diff -r 9308d52205a0 -r bab29bcec7fe src/Array.cpp --- a/src/Array.cpp Sun Sep 16 19:02:23 2012 -0700 +++ b/src/Array.cpp Sun Sep 16 21:34:10 2012 -0700 @@ -18,6 +18,7 @@ */ #include #include "Array.h" +#include "FixedArray.h" #include "Heap.h" #include "Zone.h" #include "Structures.h" @@ -58,37 +59,60 @@ return map; } -static inline size_t -SizeFor(Type *type, unsigned elements) -{ - if (type->contained()->isTraceable()) - return sizeof(Array) + elements * sizeof(ke::Object *); - if (type->contained()->isInt32()) - return sizeof(Array) + elements * sizeof(int); - if (type->contained()->primitive() == PrimitiveType_Char) - return sizeof(Array) + elements * sizeof(char); - assert(type->contained()->isFloat()); - return elements * sizeof(float); -} - Array * Array::NewRaw(Zone *zone, Handle map, unsigned nelements, Heap::Tenure tenure) { - if (nelements > (INT_MAX / SizeFor(map->type(), 1))) { + if (nelements > (INT_MAX / SizeForElement(map->type()))) { zone->reportError(Message_ArraySizeTooBig); return NULL; } - size_t elementBytes = SizeFor(map->type(), nelements); - size_t bytes = sizeof(Array) + elementBytes; + size_t bytes = sizeof(Array); + if (map->type()->hasInlineElements()) + bytes += SizeForElement(map->type()) * nelements; + Local array(zone, Array::cast(zone->allocate(map, bytes, tenure))); if (!array) return NULL; - array->nelements_ = nelements; - array->elements_ = (Array *)array + 1; - memset(array->vec(), 0, elementBytes); + array->length_ = 0; + array->elements_ = NULL; + + if (map->type()->hasInlineElements()) { + // This must be a fixed array containing no traceables. + assert(nelements > 0); + assert(map->type()->isFixedLength()); + assert(!map->type()->contained()->isTraceable()); + + // Compute an interior |elements_| pointer, such that if elements_ + // is accessed like a FixedArray, we reach the appropriate vector. + array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements(); + array->length_ = nelements; + memset(array->bytes(), 0, SizeForElement(map->type()) * nelements); + return array; + } + // If there is nothing to allocate, we don't bother creating elements yet. + if (!nelements) + return array; + + if (!map->type()->contained()->isTraceable()) { + size_t nbytes = SizeForElement(map->type()) * nelements; + Local elements(zone, ByteArray::New(zone, nbytes, tenure)); + if (!elements) + return NULL; + + array->updateLengthAndElements(zone, nelements, elements); + return array; + } + + Local elements(zone, FixedArray::New(zone, nelements, tenure)); + if (!elements) + return NULL; + + array->updateLengthAndElements(zone, nelements, elements); + + // If this is an array of structs, we're required to allocate those structs now. if (map->type()->contained()->isStruct()) { Local childMap(zone, StructMap::cast(map->type()->contained()->newMap())); Local child(zone); @@ -97,7 +121,7 @@ if (!child) return NULL; - array->writeObject(zone, i, child); + elements->set(zone, i, child); } } @@ -211,15 +235,15 @@ } Array * -Array::NewExternal(Zone *zone, Handle map, uint32 nelements, void *buffer, +Array::NewExternal(Zone *zone, Handle map, void *buffer, unsigned length, Heap::Tenure tenure) { Local array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure))); if (!array) return NULL; - array->nelements_ = nelements; - array->elements_ = buffer; + array->length_ = length; + array->elements_ = Address(buffer) - ByteArray::offsetToElements(); return array; }