Revision: 10218
Author: [email protected]
Date: Fri Dec 9 00:50:19 2011
Log: Support Smi->Double->HeapObject transitions in constructed Arrays.
Also several bugs with Smi/double elements handling and make Ensure*
routines more flexible.
BUG=none
TEST=test/mjsunit/array-construct-transition.js
Review URL: http://codereview.chromium.org/8820014
http://code.google.com/p/v8/source/detail?r=10218
Added:
/branches/bleeding_edge/test/mjsunit/array-construct-transition.js
Modified:
/branches/bleeding_edge/src/arm/builtins-arm.cc
/branches/bleeding_edge/src/builtins.cc
/branches/bleeding_edge/src/elements.cc
/branches/bleeding_edge/src/elements.h
/branches/bleeding_edge/src/factory.cc
/branches/bleeding_edge/src/factory.h
/branches/bleeding_edge/src/ia32/builtins-ia32.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/builtins-x64.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/array-construct-transition.js Fri
Dec 9 00:50:19 2011
@@ -0,0 +1,39 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays
+
+support_smi_only_arrays = %HasFastSmiOnlyElements([1,2,3,4,5,6,7,8,9,10]);
+
+if (support_smi_only_arrays) {
+ var a = new Array(0, 1, 2);
+ assertTrue(%HasFastSmiOnlyElements(a));
+ var b = new Array(0.5, 1.2, 2.3);
+ assertTrue(%HasFastDoubleElements(b));
+ var c = new Array(0.5, 1.2, new Object());
+ assertTrue(%HasFastElements(c));
+}
=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc Thu Oct 27 04:11:59 2011
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc Fri Dec 9 00:50:19 2011
@@ -394,13 +394,18 @@
// r5: elements_array_end (untagged)
// sp[0]: last argument
Label loop, entry;
+ __ mov(r7, sp);
__ jmp(&entry);
__ bind(&loop);
- __ ldr(r2, MemOperand(sp, kPointerSize, PostIndex));
+ __ ldr(r2, MemOperand(r7, kPointerSize, PostIndex));
+ if (FLAG_smi_only_arrays) {
+ __ JumpIfNotSmi(r2, call_generic_code);
+ }
__ str(r2, MemOperand(r5, -kPointerSize, PreIndex));
__ bind(&entry);
__ cmp(r4, r5);
__ b(lt, &loop);
+ __ mov(sp, r7);
// Remove caller arguments and receiver from the stack, setup return
value and
// return.
=======================================
--- /branches/bleeding_edge/src/builtins.cc Tue Nov 15 04:34:55 2011
+++ /branches/bleeding_edge/src/builtins.cc Fri Dec 9 00:50:19 2011
@@ -232,31 +232,58 @@
if (args.length() == 1) {
return array->Initialize(JSArray::kPreallocatedArrayElements);
}
-
- // Take the arguments as elements.
- int number_of_elements = args.length() - 1;
- Smi* len = Smi::FromInt(number_of_elements);
- Object* obj;
- { MaybeObject* maybe_obj =
heap->AllocateFixedArrayWithHoles(len->value());
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
// Set length and elements on the array.
+ int number_of_elements = args.length() - 1;
MaybeObject* maybe_object =
- array->EnsureCanContainElements(FixedArray::cast(obj));
+ array->EnsureCanContainElements(&args, 1, number_of_elements,
+ ALLOW_CONVERTED_DOUBLE_ELEMENTS);
if (maybe_object->IsFailure()) return maybe_object;
- AssertNoAllocation no_gc;
- FixedArray* elms = FixedArray::cast(obj);
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ // Allocate an appropriately typed elements array.
+ MaybeObject* maybe_elms;
+ ElementsKind elements_kind = array->GetElementsKind();
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
+ number_of_elements);
+ } else {
+ maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
+ }
+ FixedArrayBase* elms;
+ if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms;
+
// Fill in the content
- for (int index = 0; index < number_of_elements; index++) {
- elms->set(index, args[index+1], mode);
+ switch (array->GetElementsKind()) {
+ case FAST_SMI_ONLY_ELEMENTS: {
+ FixedArray* smi_elms = FixedArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ smi_elms->set(index, args[index+1], SKIP_WRITE_BARRIER);
+ }
+ break;
+ }
+ case FAST_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ FixedArray* object_elms = FixedArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ object_elms->set(index, args[index+1], mode);
+ }
+ break;
+ }
+ case FAST_DOUBLE_ELEMENTS: {
+ FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ double_elms->set(index, args[index+1]->Number());
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
}
- array->set_elements(FixedArray::cast(obj));
- array->set_length(len);
-
+ array->set_elements(elms);
+ array->set_length(Smi::FromInt(number_of_elements));
return array;
}
@@ -424,7 +451,8 @@
MaybeObject* maybe_array = array->EnsureCanContainElements(
args,
first_added_arg,
- args_length - first_added_arg);
+ args_length - first_added_arg,
+ DONT_ALLOW_DOUBLE_ELEMENTS);
if (maybe_array->IsFailure()) return maybe_array;
return array->elements();
}
@@ -627,7 +655,8 @@
ASSERT(to_add <= (Smi::kMaxValue - len));
MaybeObject* maybe_object =
- array->EnsureCanContainElements(&args, 1, to_add);
+ array->EnsureCanContainElements(&args, 1, to_add,
+ DONT_ALLOW_DOUBLE_ELEMENTS);
if (maybe_object->IsFailure()) return maybe_object;
if (new_length > elms->length()) {
@@ -758,7 +787,8 @@
FixedArray* result_elms = FixedArray::cast(result);
MaybeObject* maybe_object =
- result_array->EnsureCanContainElements(result_elms);
+ result_array->EnsureCanContainElements(result_elms,
+ DONT_ALLOW_DOUBLE_ELEMENTS);
if (maybe_object->IsFailure()) return maybe_object;
AssertNoAllocation no_gc;
@@ -1022,7 +1052,7 @@
for (int i = 0; i < n_arguments; i++) {
JSArray* array = JSArray::cast(args[i]);
if (!array->HasFastSmiOnlyElements()) {
- result_array->EnsureCanContainNonSmiElements();
+ result_array->EnsureCanContainHeapObjectElements();
break;
}
}
=======================================
--- /branches/bleeding_edge/src/elements.cc Fri Nov 18 03:08:46 2011
+++ /branches/bleeding_edge/src/elements.cc Fri Dec 9 00:50:19 2011
@@ -133,6 +133,22 @@
static MaybeObject* SetLength(BackingStoreClass* backing_store,
JSObject* obj,
Object* length);
+
+ virtual MaybeObject* SetCapacityAndLength(JSArray* array,
+ int capacity,
+ int length) {
+ return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
+ array,
+ capacity,
+ length);
+ }
+
+ static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
+ int capacity,
+ int length) {
+ UNIMPLEMENTED();
+ return obj;
+ }
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
@@ -375,11 +391,6 @@
}
return heap->true_value();
}
-
- protected:
- friend class FastElementsAccessor<FastObjectElementsAccessor,
- FixedArray,
- kPointerSize>;
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
@@ -392,6 +403,11 @@
length,
set_capacity_mode);
}
+
+ protected:
+ friend class FastElementsAccessor<FastObjectElementsAccessor,
+ FixedArray,
+ kPointerSize>;
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
@@ -405,18 +421,18 @@
: public FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize> {
+ static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
+ uint32_t capacity,
+ uint32_t length) {
+ return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
+ }
+
protected:
friend class ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray>;
friend class FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize>;
-
- static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
- uint32_t capacity,
- uint32_t length) {
- return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
- }
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
=======================================
--- /branches/bleeding_edge/src/elements.h Tue Nov 8 03:59:56 2011
+++ /branches/bleeding_edge/src/elements.h Fri Dec 9 00:50:19 2011
@@ -44,11 +44,24 @@
JSObject* holder,
Object* receiver) = 0;
- // Modifies the length data property as specified for JSArrays and
resizes
- // the underlying backing store accordingly.
+ // Modifies the length data property as specified for JSArrays and
resizes the
+ // underlying backing store accordingly. The method honors the semantics
of
+ // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e.
array that
+ // have non-deletable elements can only be shrunk to the size of highest
+ // element that is non-deletable.
virtual MaybeObject* SetLength(JSObject* holder,
Object* new_length) = 0;
+ // Modifies both the length and capacity of a JSArray, resizing the
underlying
+ // backing store as necessary. This method does NOT honor the semantics
of
+ // EcmaScript 5.1 15.4.5.2, arrays can be shrunk beyond non-deletable
+ // elements. This method should only be called for array expansion OR by
+ // runtime JavaScript code that use InternalArrays and don't care about
+ // EcmaScript 5.1 semantics.
+ virtual MaybeObject* SetCapacityAndLength(JSArray* array,
+ int capacity,
+ int length) = 0;
+
virtual MaybeObject* Delete(JSObject* holder,
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
=======================================
--- /branches/bleeding_edge/src/factory.cc Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/factory.cc Fri Dec 9 00:50:19 2011
@@ -926,28 +926,48 @@
}
-Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArray>
elements,
+Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArrayBase>
elements,
PretenureFlag pretenure) {
Handle<JSArray> result =
Handle<JSArray>::cast(NewJSObject(isolate()->array_function(),
pretenure));
+ result->set_length(Smi::FromInt(0));
SetContent(result, elements);
return result;
}
+
+
+void Factory::SetElementsCapacityAndLength(Handle<JSArray> array,
+ int capacity,
+ int length) {
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ accessor->SetCapacityAndLength(*array, capacity, length));
+}
void Factory::SetContent(Handle<JSArray> array,
- Handle<FixedArray> elements) {
+ Handle<FixedArrayBase> elements) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
array->SetContent(*elements));
}
-void Factory::EnsureCanContainNonSmiElements(Handle<JSArray> array) {
+void Factory::EnsureCanContainHeapObjectElements(Handle<JSArray> array) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
- array->EnsureCanContainNonSmiElements());
+ array->EnsureCanContainHeapObjectElements());
+}
+
+
+void Factory::EnsureCanContainElements(Handle<JSArray> array,
+ Handle<FixedArrayBase> elements,
+ EnsureElementsMode mode) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ array->EnsureCanContainElements(*elements, mode));
}
=======================================
--- /branches/bleeding_edge/src/factory.h Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/factory.h Fri Dec 9 00:50:19 2011
@@ -259,12 +259,19 @@
PretenureFlag pretenure = NOT_TENURED);
Handle<JSArray> NewJSArrayWithElements(
- Handle<FixedArray> elements,
+ Handle<FixedArrayBase> elements,
PretenureFlag pretenure = NOT_TENURED);
- void SetContent(Handle<JSArray> array, Handle<FixedArray> elements);
-
- void EnsureCanContainNonSmiElements(Handle<JSArray> array);
+ void SetElementsCapacityAndLength(Handle<JSArray> array,
+ int capacity,
+ int length);
+
+ void SetContent(Handle<JSArray> array, Handle<FixedArrayBase> elements);
+
+ void EnsureCanContainHeapObjectElements(Handle<JSArray> array);
+ void EnsureCanContainElements(Handle<JSArray> array,
+ Handle<FixedArrayBase> elements,
+ EnsureElementsMode mode);
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object>
prototype);
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Tue Nov 8 06:39:37
2011
+++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Fri Dec 9 00:50:19
2011
@@ -1238,37 +1238,42 @@
false,
&prepare_generic_code_call);
__ IncrementCounter(counters->array_function_native(), 1);
- __ mov(eax, ebx);
- __ pop(ebx);
- if (construct_call) {
- __ pop(edi);
- }
- __ push(eax);
- // eax: JSArray
+ __ push(ebx);
+ __ mov(ebx, Operand(esp, kPointerSize));
// ebx: argc
// edx: elements_array_end (untagged)
// esp[0]: JSArray
- // esp[4]: return address
- // esp[8]: last argument
+ // esp[4]: argc
+ // esp[8]: constructor (only if construct_call)
+ // esp[12]: return address
+ // esp[16]: last argument
// Location of the last argument
- __ lea(edi, Operand(esp, 2 * kPointerSize));
+ int last_arg_offset = (construct_call ? 4 : 3) * kPointerSize;
+ __ lea(edi, Operand(esp, last_arg_offset));
// Location of the first array element (Parameter fill_with_holes to
- // AllocateJSArrayis false, so the FixedArray is returned in ecx).
+ // AllocateJSArray is false, so the FixedArray is returned in ecx).
__ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
+ Label has_non_smi_element;
+
// ebx: argc
// edx: location of the first array element
// edi: location of the last argument
// esp[0]: JSArray
- // esp[4]: return address
- // esp[8]: last argument
+ // esp[4]: argc
+ // esp[8]: constructor (only if construct_call)
+ // esp[12]: return address
+ // esp[16]: last argument
Label loop, entry;
__ mov(ecx, ebx);
__ jmp(&entry);
__ bind(&loop);
__ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
+ if (FLAG_smi_only_arrays) {
+ __ JumpIfNotSmi(eax, &has_non_smi_element);
+ }
__ mov(Operand(edx, 0), eax);
__ add(edx, Immediate(kPointerSize));
__ bind(&entry);
@@ -1278,13 +1283,20 @@
// Remove caller arguments from the stack and return.
// ebx: argc
// esp[0]: JSArray
- // esp[4]: return address
- // esp[8]: last argument
+ // esp[4]: argc
+ // esp[8]: constructor (only if construct_call)
+ // esp[12]: return address
+ // esp[16]: last argument
+ __ mov(ecx, Operand(esp, last_arg_offset - kPointerSize));
__ pop(eax);
- __ pop(ecx);
- __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
- __ push(ecx);
- __ ret(0);
+ __ pop(ebx);
+ __ lea(esp, Operand(esp, ebx, times_pointer_size,
+ last_arg_offset - kPointerSize));
+ __ jmp(ecx);
+
+ __ bind(&has_non_smi_element);
+ // Throw away the array that's only been partially constructed.
+ __ pop(eax);
// Restore argc and constructor before running the generic code.
__ bind(&prepare_generic_code_call);
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Wed Dec 7 00:43:18 2011
+++ /branches/bleeding_edge/src/objects-inl.h Fri Dec 9 00:50:19 2011
@@ -1183,6 +1183,22 @@
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
+Object** FixedArray::GetFirstElementAddress() {
+ return reinterpret_cast<Object**>(FIELD_ADDR(this,
OffsetOfElementAt(0)));
+}
+
+
+bool FixedArray::ContainsOnlySmisOrHoles() {
+ Object* the_hole = GetHeap()->the_hole_value();
+ Object** current = GetFirstElementAddress();
+ for (int i = 0; i < length(); ++i) {
+ Object* candidate = *current++;
+ if (!candidate->IsSmi() && candidate != the_hole) return false;
+ }
+ return true;
+}
+
+
FixedArrayBase* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
return static_cast<FixedArrayBase*>(array);
@@ -1211,38 +1227,66 @@
}
-MaybeObject* JSObject::EnsureCanContainNonSmiElements() {
+MaybeObject* JSObject::EnsureCanContainHeapObjectElements() {
#if DEBUG
ValidateSmiOnlyElements();
#endif
- if ((map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS)) {
- Object* obj;
- MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- set_map(Map::cast(obj));
+ if ((map()->elements_kind() != FAST_ELEMENTS)) {
+ return TransitionElementsKind(FAST_ELEMENTS);
}
return this;
}
MaybeObject* JSObject::EnsureCanContainElements(Object** objects,
- uint32_t count) {
- if (map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) {
- for (uint32_t i = 0; i < count; ++i) {
- Object* current = *objects++;
- if (!current->IsSmi() && current != GetHeap()->the_hole_value()) {
- return EnsureCanContainNonSmiElements();
+ uint32_t count,
+ EnsureElementsMode mode) {
+ ElementsKind current_kind = map()->elements_kind();
+ ElementsKind target_kind = current_kind;
+ ASSERT(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
+ if (current_kind == FAST_ELEMENTS) return this;
+
+ Heap* heap = GetHeap();
+ Object* the_hole = heap->the_hole_value();
+ Object* heap_number_map = heap->heap_number_map();
+ for (uint32_t i = 0; i < count; ++i) {
+ Object* current = *objects++;
+ if (!current->IsSmi() && current != the_hole) {
+ if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS &&
+ HeapObject::cast(current)->map() == heap_number_map) {
+ target_kind = FAST_DOUBLE_ELEMENTS;
+ } else {
+ target_kind = FAST_ELEMENTS;
+ break;
}
}
}
+
+ if (target_kind != current_kind) {
+ return TransitionElementsKind(target_kind);
+ }
return this;
}
-MaybeObject* JSObject::EnsureCanContainElements(FixedArray* elements) {
- Object** objects = reinterpret_cast<Object**>(
- FIELD_ADDR(elements, elements->OffsetOfElementAt(0)));
- return EnsureCanContainElements(objects, elements->length());
+MaybeObject* JSObject::EnsureCanContainElements(FixedArrayBase* elements,
+ EnsureElementsMode mode) {
+ if (elements->map() != GetHeap()->fixed_double_array_map()) {
+ ASSERT(elements->map() == GetHeap()->fixed_array_map() ||
+ elements->map() == GetHeap()->fixed_cow_array_map());
+ if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
+ mode = DONT_ALLOW_DOUBLE_ELEMENTS;
+ }
+ Object** objects =
FixedArray::cast(elements)->GetFirstElementAddress();
+ return EnsureCanContainElements(objects, elements->length(), mode);
+ }
+
+ ASSERT(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
+ if (GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) {
+ return TransitionElementsKind(FAST_DOUBLE_ELEMENTS);
+ }
+
+ return this;
}
@@ -4120,7 +4164,8 @@
(map == GetHeap()->fixed_array_map() ||
map == GetHeap()->fixed_cow_array_map())) ||
(kind == FAST_DOUBLE_ELEMENTS &&
- fixed_array->IsFixedDoubleArray()) ||
+ (fixed_array->IsFixedDoubleArray() ||
+ fixed_array == GetHeap()->empty_fixed_array())) ||
(kind == DICTIONARY_ELEMENTS &&
fixed_array->IsFixedArray() &&
fixed_array->IsDictionary()) ||
@@ -4579,11 +4624,18 @@
}
-MaybeObject* JSArray::SetContent(FixedArray* storage) {
- MaybeObject* maybe_object = EnsureCanContainElements(storage);
- if (maybe_object->IsFailure()) return maybe_object;
- set_length(Smi::FromInt(storage->length()));
+MaybeObject* JSArray::SetContent(FixedArrayBase* storage) {
+ MaybeObject* maybe_result = EnsureCanContainElements(
+ storage, ALLOW_COPIED_DOUBLE_ELEMENTS);
+ if (maybe_result->IsFailure()) return maybe_result;
+ ASSERT((storage->map() == GetHeap()->fixed_double_array_map() &&
+ GetElementsKind() == FAST_DOUBLE_ELEMENTS) ||
+ ((storage->map() != GetHeap()->fixed_double_array_map()) &&
+ ((GetElementsKind() == FAST_ELEMENTS) ||
+ (GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
+ FixedArray::cast(storage)->ContainsOnlySmisOrHoles()))));
set_elements(storage);
+ set_length(Smi::FromInt(storage->length()));
return this;
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Wed Dec 7 00:43:18 2011
+++ /branches/bleeding_edge/src/objects.cc Fri Dec 9 00:50:19 2011
@@ -8133,17 +8133,17 @@
FixedArray* destination,
WriteBarrierMode mode) {
int count = source->length();
+ int copy_size = Min(count, destination->length());
if (mode == SKIP_WRITE_BARRIER ||
!Page::FromAddress(destination->address())->IsFlagSet(
MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
- ASSERT(count <= destination->length());
Address to = destination->address() + FixedArray::kHeaderSize;
Address from = source->address() + FixedArray::kHeaderSize;
memcpy(reinterpret_cast<void*>(to),
reinterpret_cast<void*>(from),
- kPointerSize * count);
+ kPointerSize * copy_size);
} else {
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < copy_size; ++i) {
destination->set(i, source->get(i), mode);
}
}
@@ -8153,11 +8153,14 @@
static void CopySlowElementsToFast(NumberDictionary* source,
FixedArray* destination,
WriteBarrierMode mode) {
+ int destination_length = destination->length();
for (int i = 0; i < source->Capacity(); ++i) {
Object* key = source->KeyAt(i);
if (key->IsNumber()) {
uint32_t entry = static_cast<uint32_t>(key->Number());
- destination->set(entry, source->ValueAt(i), mode);
+ if (entry < static_cast<uint32_t>(destination_length)) {
+ destination->set(entry, source->ValueAt(i), mode);
+ }
}
}
}
@@ -8368,14 +8371,8 @@
void JSArray::Expand(int required_size) {
- Handle<JSArray> self(this);
- Handle<FixedArray> old_backing(FixedArray::cast(elements()));
- int old_size = old_backing->length();
- int new_size = required_size > old_size ? required_size : old_size;
- Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
- // Can't use this any more now because we may have had a GC!
- for (int i = 0; i < old_size; i++) new_backing->set(i,
old_backing->get(i));
- GetIsolate()->factory()->SetContent(self, new_backing);
+ GetIsolate()->factory()->SetElementsCapacityAndLength(
+ Handle<JSArray>(this), required_size, Smi::cast(length())->value());
}
@@ -8529,13 +8526,14 @@
MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
uint32_t first_arg,
- uint32_t arg_count) {
+ uint32_t arg_count,
+ EnsureElementsMode mode) {
// Elements in |Arguments| are ordered backwards (because they're on the
// stack), but the method that's called here iterates over them in
forward
// direction.
return EnsureCanContainElements(
args->arguments() - first_arg - (arg_count - 1),
- arg_count);
+ arg_count, mode);
}
@@ -9487,31 +9485,45 @@
FixedArrayBase* elms = FixedArrayBase::cast(elements());
uint32_t capacity = static_cast<uint32_t>(elms->length());
uint32_t length = capacity;
+
if (IsJSArray()) {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
- }
- if (from_kind == FAST_SMI_ONLY_ELEMENTS) {
- if (to_kind == FAST_DOUBLE_ELEMENTS) {
- MaybeObject* maybe_result =
- SetFastDoubleElementsCapacityAndLength(capacity, length);
- if (maybe_result->IsFailure()) return maybe_result;
- return this;
- } else if (to_kind == FAST_ELEMENTS) {
- MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
- Map* new_map;
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- if (FLAG_trace_elements_transitions) {
- PrintElementsTransition(stdout, from_kind, elms, FAST_ELEMENTS,
elms);
- }
- set_map(new_map);
- return this;
- }
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind ==
FAST_ELEMENTS) {
+ Object* raw_length = JSArray::cast(this)->length();
+ if (raw_length->IsUndefined()) {
+ // If length is undefined, then JSArray is being initialized and has
no
+ // elements, assume a length of zero.
+ length = 0;
+ } else {
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
+ }
+ }
+
+ if ((from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) ||
+ (length == 0)) {
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind);
+ Map* new_map;
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
+ }
+ set_map(new_map);
+ return this;
+ }
+
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
+ to_kind == FAST_DOUBLE_ELEMENTS) {
+ MaybeObject* maybe_result =
+ SetFastDoubleElementsCapacityAndLength(capacity, length);
+ if (maybe_result->IsFailure()) return maybe_result;
+ return this;
+ }
+
+ if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
capacity, length, kDontAllowSmiOnlyElements);
if (maybe_result->IsFailure()) return maybe_result;
return this;
}
+
// This method should never be called for any other case than the ones
// handled above.
UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Dec 8 08:07:07 2011
+++ /branches/bleeding_edge/src/objects.h Fri Dec 9 00:50:19 2011
@@ -1322,6 +1322,13 @@
};
+enum EnsureElementsMode {
+ DONT_ALLOW_DOUBLE_ELEMENTS,
+ ALLOW_COPIED_DOUBLE_ELEMENTS,
+ ALLOW_CONVERTED_DOUBLE_ELEMENTS
+};
+
+
// JSReceiver includes types on which properties can be defined, i.e.,
// JSObject and JSProxy.
class JSReceiver: public HeapObject {
@@ -1615,16 +1622,19 @@
inline void ValidateSmiOnlyElements();
- // Makes sure that this object can contain non-smi Object as elements.
- inline MaybeObject* EnsureCanContainNonSmiElements();
+ // Makes sure that this object can contain HeapObject as elements.
+ inline MaybeObject* EnsureCanContainHeapObjectElements();
// Makes sure that this object can contain the specified elements.
inline MaybeObject* EnsureCanContainElements(Object** elements,
- uint32_t count);
- inline MaybeObject* EnsureCanContainElements(FixedArray* elements);
+ uint32_t count,
+ EnsureElementsMode mode);
+ inline MaybeObject* EnsureCanContainElements(FixedArrayBase* elements,
+ EnsureElementsMode mode);
MaybeObject* EnsureCanContainElements(Arguments* arguments,
uint32_t first_arg,
- uint32_t arg_count);
+ uint32_t arg_count,
+ EnsureElementsMode mode);
// Do we want to keep the elements in fast case when increasing the
// capacity?
@@ -2124,6 +2134,9 @@
// Gives access to raw memory which stores the array's data.
inline Object** data_start();
+ inline Object** GetFirstElementAddress();
+ inline bool ContainsOnlySmisOrHoles();
+
// Copy operations.
MUST_USE_RESULT inline MaybeObject* Copy();
MUST_USE_RESULT MaybeObject* CopySize(int new_length);
@@ -7386,7 +7399,7 @@
MUST_USE_RESULT MaybeObject* Initialize(int capacity);
// Set the content of the array to the content of storage.
- inline MaybeObject* SetContent(FixedArray* storage);
+ inline MaybeObject* SetContent(FixedArrayBase* storage);
// Casting.
static inline JSArray* cast(Object* obj);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Dec 7 08:15:18 2011
+++ /branches/bleeding_edge/src/runtime.cc Fri Dec 9 00:50:19 2011
@@ -6296,7 +6296,7 @@
int part_count = indices.length();
Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
- MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
+ MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
if (maybe_result->IsFailure()) return maybe_result;
result->set_length(Smi::FromInt(part_count));
@@ -6672,7 +6672,7 @@
// This assumption is used by the slice encoding in one or two smis.
ASSERT(Smi::kMaxValue >= String::kMaxLength);
- MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
+ MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
if (maybe_result->IsFailure()) return maybe_result;
int special_length = special->length();
@@ -9318,7 +9318,7 @@
CONVERT_ARG_CHECKED(JSArray, output, 1);
MaybeObject* maybe_result_array =
- output->EnsureCanContainNonSmiElements();
+ output->EnsureCanContainHeapObjectElements();
if (maybe_result_array->IsFailure()) return maybe_result_array;
RUNTIME_ASSERT(output->HasFastElements());
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc Thu Oct 27 04:11:59 2011
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc Fri Dec 9 00:50:19 2011
@@ -1305,6 +1305,9 @@
__ jmp(&entry);
__ bind(&loop);
__ movq(kScratchRegister, Operand(r9, rcx, times_pointer_size, 0));
+ if (FLAG_smi_only_arrays) {
+ __ JumpIfNotSmi(kScratchRegister, call_generic_code);
+ }
__ movq(Operand(rdx, 0), kScratchRegister);
__ addq(rdx, Immediate(kPointerSize));
__ bind(&entry);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev