Support admin.inc again.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of SourcePawn.
7 * SourcePawn is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * SourcePawn. If not, see http://www.gnu.org/licenses/.
21 #include "FixedArray.h"
24 #include "Structures.h"
30 ArrayMap::New(Zone *zone, Handle<ArrayType> type)
32 Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
36 Local<ArrayMap> map(zone, ArrayMap::cast(obj));
42 ArrayMap::Attach(Zone *zone, Handle<ArrayType> type)
45 return ArrayMap::cast(type->newMap());
47 Local<ArrayMap> map(zone, ArrayMap::New(zone, type));
51 // Ensure the inner type has an ArrayMap if needed.
52 if (type->contained()->isArray()) {
53 Local<ArrayType> contained(zone, ArrayType::cast(type->contained()));
54 if (!ArrayMap::Attach(zone, contained))
63 Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
65 assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
67 if (nelements > (INT_MAX / SizeForElement(map->type()))) {
68 zone->reportError(Message_ArraySizeTooBig);
72 size_t bytes = sizeof(Array);
73 if (map->type()->hasInlineElements())
74 bytes += SizeForElement(map->type()) * nelements;
76 Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
81 array->elements_ = NULL;
83 if (map->type()->hasInlineElements()) {
84 // This must be a fixed array containing no traceables.
85 assert(nelements > 0);
86 assert(map->type()->isFixedLength());
87 assert(!map->type()->contained()->isTraceable());
89 // Compute an interior |elements_| pointer, such that if elements_
90 // is accessed like a FixedArray, we reach the appropriate vector.
91 array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
92 array->length_ = nelements;
93 memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
97 // If there is nothing to allocate, we don't bother creating elements yet.
101 if (!map->type()->contained()->isTraceable()) {
102 size_t nbytes = SizeForElement(map->type()) * nelements;
103 Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
107 array->updateLengthAndElements(zone, nelements, elements);
111 Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
115 array->updateLengthAndElements(zone, nelements, elements);
117 // If this is an array of structs, we're required to allocate those structs now.
118 if (map->type()->contained()->isStruct()) {
119 Local<StructType> childType(zone, StructType::cast(map->type()->contained()));
120 Local<StructMap> childMap(zone, childType->newMap());
121 Local<Struct> child(zone);
122 for (unsigned i = 0; i < nelements; i++) {
123 child = Struct::New(zone, childMap, tenure);
127 elements->set(zone, i, child);
135 ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
136 unsigned level, Heap::Tenure tenure)
138 Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
142 if (map->type()->contained()->isArray()) {
143 Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
144 Local<ArrayMap> childMap(zone, childType->newMap());
145 Local<Array> child(zone);
147 for (unsigned i = 0; i < unsigned(dims[level]); i++) {
148 child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
152 array->writeObject(zone, i, child);
160 Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
162 for (size_t i = 0; i < map->type()->levels(); i++) {
164 zone->reportError(Message_InvalidDimensionSize, dims[i], i);
169 return ConstructSizedArray(zone, map, dims, 0, tenure);
173 ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
175 unsigned length = map->type()->fixedLength();
176 Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
180 if (map->type()->contained()->isArray()) {
181 Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
182 Local<ArrayMap> childMap(zone, childType->newMap());
183 Local<Array> child(zone);
185 if (childMap->type()->isFixedLength()) {
186 for (unsigned i = 0; i < length; i++) {
187 child = ConstructFixedArray(zone, childMap, tenure);
191 array->writeObject(zone, i, child);
194 for (unsigned i = 0; i < length; i++) {
195 child = Array::NewRaw(zone, childMap, 0, tenure);
199 array->writeObject(zone, i, child);
208 Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
210 return ConstructFixedArray(zone, map, tenure);
214 Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
216 assert(map->type()->isCharArray());
218 Local<Array> array(zone);
220 if (map->type()->isFixedLength())
221 array = Array::NewFixed(zone, map, tenure);
223 array = Array::New1D(zone, map, length + 1, tenure);
227 assert(array->length() >= length + 1);
228 memcpy(array->chars(), buffer, length + 1);
233 Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
235 assert(map->type()->levels());
236 return Array::NewRaw(zone, map, elements, tenure);
240 Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
242 assert(!map->type()->isFixedLength());
244 return Array::NewRaw(zone, map, 0, tenure);
248 Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
251 Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
255 array->length_ = length;
256 array->elements_ = Address(buffer) - ByteArray::offsetToElements();
261 CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
263 if (contained->isTraceable()) {
264 if (contained->isStruct()) {
265 assert(dest->type()->contained() == contained);
266 assert(source->length() == dest->length());
268 Local<Struct> left(zone);
269 Local<Struct> right(zone);
270 for (unsigned i = 0; i < source->length(); i++) {
271 left = Struct::cast(dest->readObject(i));
272 right = Struct::cast(source->readObject(i));
273 if (!Struct::Copy(zone, left, right))
276 } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
277 assert(ArrayType::cast(source->type())->fixedLength() ==
278 ArrayType::cast(contained)->fixedLength());
280 Local<Array> left(zone);
281 Local<Array> right(zone);
282 for (unsigned i = 0; i < source->length(); i++) {
283 left = Array::cast(dest->readObject(i));
284 right = Array::cast(source->readObject(i));
285 if (!Array::ShallowCopy(zone, left, right))
289 assert(dest->length() == source->length());
290 for (unsigned i = 0; i < source->length(); i++)
291 dest->writeObject(zone, i, source->readObject(i));
294 assert(contained->pod() == dest->type()->contained()->pod());
295 assert(contained->pod() == PrimitiveType_Char
296 ? source->length() <= dest->length()
297 : source->length() == dest->length());
299 assert(dest->length());
300 memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
305 // Shallow copy an array. Fixed slots in the destination are copied from
306 // the source, but otherwise, references are assigned.
308 Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
310 Local<Type> contained(zone, dest->type()->contained());
312 return CopyArrayElements(zone, contained, dest, source);
316 Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
318 Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
320 Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
324 Local<Type> contained(zone, source->type()->contained());
325 if (contained->isArray()) {
327 Local<Array> sub(zone);
328 for (size_t i = 0; i < source->length(); i++) {
329 sub = Array::cast(source->readObject(i));
330 sub = DeepCopy(zone, sub, tenure);
333 dest->writeObject(zone, i, sub);
336 if (!CopyArrayElements(zone, contained, dest, source))