diff -r bbb498ccb4ac -r 26e3035cdffc src/Array.cpp --- a/src/Array.cpp Sat Dec 22 23:18:57 2012 -0800 +++ b/src/Array.cpp Mon Dec 24 02:49:20 2012 -0800 @@ -62,6 +62,8 @@ Array * Array::NewRaw(Zone *zone, Handle map, unsigned nelements, Heap::Tenure tenure) { + assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength()); + if (nelements > (INT_MAX / SizeForElement(map->type()))) { zone->reportError(Message_ArraySizeTooBig); return NULL; @@ -209,16 +211,21 @@ } Array * -Array::NewString(Zone *zone, Handle map, Address buffer, size_t length, Heap::Tenure tenure) +Array::NewString(Zone *zone, Handle map, char *buffer, size_t length, Heap::Tenure tenure) { assert(map->type()->isCharArray()); - Local array(zone, Array::New1D(zone, map, length, tenure)); + Local array(zone); + + if (map->type()->isFixedLength()) + array = Array::NewFixed(zone, map, tenure); + else + array = Array::New1D(zone, map, length + 1, tenure); if (!array) return NULL; - assert(array->length() >= length); - memcpy(array->chars(), buffer, length); + assert(array->length() >= length + 1); + memcpy(array->chars(), buffer, length + 1); return array; } @@ -250,3 +257,90 @@ return array; } +static bool +CopyArrayElements(Zone *zone, Handle contained, Handle dest, Handle source) +{ + if (contained->isTraceable()) { + if (contained->isStruct()) { + assert(dest->type()->contained() == contained); + assert(source->length() == dest->length()); + + Local left(zone); + Local right(zone); + for (unsigned i = 0; i < source->length(); i++) { + left = Struct::cast(dest->readObject(i)); + right = Struct::cast(source->readObject(i)); + if (!Struct::Copy(zone, left, right)) + return false; + } + } else { + assert(dest->length() == source->length()); + for (unsigned i = 0; i < source->length(); i++) + dest->writeObject(zone, i, source->readObject(i)); + } + } else { + assert(contained->pod() == dest->type()->contained()->pod()); + assert(contained->pod() == PrimitiveType_Char + ? source->length() <= dest->length() + : source->length() == dest->length()); + + assert(dest->length()); + memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type())); + } + return true; +} + +// Shallow copy an array. Fixed slots in the destination are copied from +// the source, but otherwise, references are assigned. +bool +Array::ShallowCopy(Zone *zone, Handle dest, Handle source) +{ +#if 0 + Local contained(zone, source->type()->contained()); + if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) { + assert(dest->type()->contained()->isArray()); + assert(source->length() == dest->length()); + + Local left(zone); + Local right(zone); + for (unsigned i = 0; i < source->length(); i++) { + left = Array::cast(dest->readObject(i)); + right = Array::cast(source->readObject(i)); + if (!ShallowCopy(zone, left, right)) + return false; + } + return true; + } + +#endif + assert(false); + return false; +} + +Array * +Array::DeepCopy(Zone *zone, Handle source, Heap::Tenure tenure) +{ + Local map(zone, ArrayMap::cast(source->map())); + + Local dest(zone, Array::NewRaw(zone, map, source->length(), tenure)); + if (!dest) + return NULL; + + Local contained(zone, source->type()->contained()); + if (contained->isArray()) { + assert(false); + Local sub(zone); + for (size_t i = 0; i < source->length(); i++) { + sub = Array::cast(source->readObject(i)); + sub = DeepCopy(zone, sub, tenure); + if (!sub) + return NULL; + dest->writeObject(zone, i, sub); + } + } else { + if (!CopyArrayElements(zone, contained, dest, source)) + return NULL; + } + + return dest; +}