Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index ba3fb12b81f3aa18dd7b43810f595f32595789dd..006bed382f282fe7942bc58cad05571caafff745 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -58,6 +58,10 @@ namespace internal { |
| const int kGetterIndex = 0; |
| const int kSetterIndex = 1; |
| +uint64_t FixedDoubleArray::kHoleNanInt64 = -1; |
| +uint64_t FixedDoubleArray:: kCanonoicalNonHoleNanLower32 = 0x7FF00000; |
|
Mads Ager (chromium)
2011/06/06 07:58:23
remove space after '::'
Can't you use the V8_UINT
danno
2011/06/08 12:09:43
This macro only works with x64 builds. It reports
|
| +uint64_t FixedDoubleArray::kCanonoicalNonHoleNanInt64 = |
| + kCanonoicalNonHoleNanLower32 << 32; |
| MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, |
| Object* value) { |
| @@ -3033,14 +3037,23 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
| { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
| if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| } |
| - uint32_t length = IsJSArray() ? |
| - static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
| - static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| - if (index < length) { |
| + int length = IsJSArray() |
| + ? Smi::cast(JSArray::cast(this)->length())->value() |
| + : FixedArray::cast(elements())->length(); |
| + if (index < static_cast<uint32_t>(length)) { |
| FixedArray::cast(elements())->set_the_hole(index); |
| } |
| break; |
| } |
| + case FAST_DOUBLE_ELEMENTS: { |
| + int length = IsJSArray() |
| + ? Smi::cast(JSArray::cast(this)->length())->value() |
| + : FixedArray::cast(elements())->length(); |
| + if (index < static_cast<uint32_t>(length)) { |
| + FixedDoubleArray::cast(elements())->set_the_hole(index); |
| + } |
| + break; |
| + } |
| case EXTERNAL_PIXEL_ELEMENTS: |
| case EXTERNAL_BYTE_ELEMENTS: |
| case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| @@ -6909,10 +6922,10 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
| } |
| Map* new_map = Map::cast(obj); |
| - AssertNoAllocation no_gc; |
| - WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| switch (GetElementsKind()) { |
| case FAST_ELEMENTS: { |
| + AssertNoAllocation no_gc; |
| + WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| FixedArray* old_elements = FixedArray::cast(elements()); |
| uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| // Fill out the new array with this content and array holes. |
| @@ -6921,7 +6934,28 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
| } |
| break; |
| } |
| + case FAST_DOUBLE_ELEMENTS: { |
| + FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); |
| + uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| + // Fill out the new array with this content and array holes. |
| + for (uint32_t i = 0; i < old_length; i++) { |
| + if (!old_elements->is_the_hole(i)) { |
| + Object* obj; |
| + // Objects must be allocated in the old object space, since the |
| + // overall number of HeapNumbers needed for the conversion might |
| + // exceed the capacity of new space, and we would fail repeatedly |
| + // trying to convert the FixedDoubleArray. |
| + MaybeObject* maybe_value_object = |
| + GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); |
| + if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; |
| + elems->set(i, obj, UPDATE_WRITE_BARRIER); |
|
Mads Ager (chromium)
2011/06/06 07:58:23
Why not use the WriteBarrierMode of the new elemen
danno
2011/06/08 12:09:43
It doesn't really make sense to use GetWriteBarrie
|
| + } |
| + } |
| + break; |
| + } |
| case DICTIONARY_ELEMENTS: { |
| + AssertNoAllocation no_gc; |
| + WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| for (int i = 0; i < dictionary->Capacity(); i++) { |
| Object* key = dictionary->KeyAt(i); |
| @@ -6948,6 +6982,57 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
| } |
| +MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
| + int capacity, |
| + int length) { |
| + Heap* heap = GetHeap(); |
| + // We should never end in here with a pixel or external array. |
| + ASSERT(!HasExternalArrayElements()); |
| + |
| + Object* obj; |
| + { MaybeObject* maybe_obj = heap->AllocateFixedDoubleArray(capacity); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + FixedDoubleArray* elems = FixedDoubleArray::cast(obj); |
| + |
| + { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap(); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + Map* new_map = Map::cast(obj); |
| + |
| + AssertNoAllocation no_gc; |
| + switch (GetElementsKind()) { |
| + case FAST_ELEMENTS: { |
| + FixedArray* old_elements = FixedArray::cast(elements()); |
| + elems->Initialize(old_elements); |
| + break; |
| + } |
| + case FAST_DOUBLE_ELEMENTS: { |
| + FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); |
| + elems->Initialize(old_elements); |
| + break; |
| + } |
| + case DICTIONARY_ELEMENTS: { |
| + NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| + elems->Initialize(dictionary); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + |
| + set_map(new_map); |
| + set_elements(elems); |
| + |
| + if (IsJSArray()) { |
| + JSArray::cast(this)->set_length(Smi::FromInt(length)); |
| + } |
| + |
| + return this; |
| +} |
| + |
| + |
| MaybeObject* JSObject::SetSlowElements(Object* len) { |
| // We should never end in here with a pixel or external array. |
| ASSERT(!HasExternalArrayElements()); |
| @@ -7648,7 +7733,6 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
| if (found) return result; |
| } |
| - |
| // Check whether there is extra space in fixed array.. |
| if (index < elms_length) { |
| elms->set(index, value); |
| @@ -7690,6 +7774,88 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
| } |
| +MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
| + uint32_t index, |
| + Object* value, |
| + StrictModeFlag strict_mode, |
| + bool check_prototype) { |
| + ASSERT(HasFastDoubleElements()); |
| + |
| + FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| + uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
| + |
| + // If storing to an element that isn't in the array, pass the store request |
| + // up the prototype chain before storing in the receiver's elements. |
| + if (check_prototype && |
| + (index >= elms_length || elms->is_the_hole(index))) { |
| + bool found; |
| + MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
| + value, |
| + &found, |
| + strict_mode); |
| + if (found) return result; |
| + } |
| + |
| + // If the value object is not a heap number, switch to fast elements and try |
| + // again. |
| + bool value_is_smi = value->IsSmi(); |
| + if (!value_is_smi && |
|
Mads Ager (chromium)
2011/06/06 07:58:23
if (!value->IsNumber()) which covers IsSmi() and I
danno
2011/06/08 12:09:43
Done.
|
| + (HeapObject::cast(value)->map() != |
| + *(GetIsolate()->factory()->heap_number_map()))) { |
| + Object* obj; |
| + { MaybeObject* maybe_obj = |
| + SetFastElementsCapacityAndLength(elms_length, elms_length); |
|
Mads Ager (chromium)
2011/06/06 07:58:23
Should you really pass in elms_length for both her
danno
2011/06/08 12:09:43
Done.
|
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + return SetFastElement(index, value, strict_mode, check_prototype); |
| + } |
| + |
| + double double_value = value_is_smi |
| + ? static_cast<double>(Smi::cast(value)->value()) |
| + : HeapNumber::cast(value)->value(); |
| + |
| + // Check whether there is extra space in fixed array.. |
|
Mads Ager (chromium)
2011/06/06 07:58:23
.. -> .
in the fixed array?
danno
2011/06/08 12:09:43
Done.
|
| + if (index < elms_length) { |
| + elms->set(index, double_value); |
| + if (IsJSArray()) { |
| + // Update the length of the array if needed. |
| + uint32_t array_length = 0; |
| + CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
| + if (index >= array_length) { |
| + JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
| + } |
| + } |
| + return value; |
| + } |
| + |
| + // Allow gap in fast case. |
| + if ((index - elms_length) < kMaxGap) { |
| + // Try allocating extra space. |
| + int new_capacity = NewElementsCapacity(index+1); |
| + if (new_capacity <= kMaxFastElementsLength || |
| + !ShouldConvertToSlowElements(new_capacity)) { |
| + ASSERT(static_cast<uint32_t>(new_capacity) > index); |
| + Object* obj; |
| + { MaybeObject* maybe_obj = |
| + SetFastDoubleElementsCapacityAndLength(new_capacity, |
| + index + 1); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + FixedDoubleArray::cast(elements())->set(index, double_value); |
| + return value; |
| + } |
| + } |
| + |
| + // Otherwise default to slow case. |
| + Object* obj; |
| + { MaybeObject* maybe_obj = NormalizeElements(); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + ASSERT(HasDictionaryElements()); |
| + return SetElement(index, value, strict_mode, check_prototype); |
| +} |
| + |
| + |
| MaybeObject* JSObject::SetElement(uint32_t index, |
| Object* value, |
| StrictModeFlag strict_mode, |
| @@ -7739,6 +7905,8 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
| case FAST_ELEMENTS: |
| // Fast case. |
| return SetFastElement(index, value, strict_mode, check_prototype); |
| + case FAST_DOUBLE_ELEMENTS: |
| + return SetFastDoubleElement(index, value, strict_mode, check_prototype); |
| case EXTERNAL_PIXEL_ELEMENTS: { |
| ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
| return pixels->SetValue(index, value); |
| @@ -7862,24 +8030,35 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
| } else { |
| new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
| } |
| - Object* obj; |
| - { MaybeObject* maybe_obj = |
| - SetFastElementsCapacityAndLength(new_length, new_length); |
| - if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| - } |
| + if (ShouldConvertToFastDoubleElements()) { |
| + Object* obj; |
| + { MaybeObject* maybe_obj = |
| + SetFastDoubleElementsCapacityAndLength(new_length, new_length); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| #ifdef DEBUG |
| - if (FLAG_trace_normalization) { |
| - PrintF("Object elements are fast case again:\n"); |
| - Print(); |
| - } |
| + if (FLAG_trace_normalization) { |
| + PrintF("Object elements are fast double case again:\n"); |
| + Print(); |
| + } |
| +#endif |
| + } else { |
| + Object* obj; |
| + { MaybeObject* maybe_obj = |
| + SetFastElementsCapacityAndLength(new_length, new_length); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| +#ifdef DEBUG |
| + if (FLAG_trace_normalization) { |
| + PrintF("Object elements are fast case again:\n"); |
| + Print(); |
| + } |
| #endif |
| + } |
| } |
| return value; |
| } |
| - default: |
| - UNREACHABLE(); |
| - break; |
| } |
| // All possible cases have been handled above. Add a return to avoid the |
| // complaints from the compiler. |
| @@ -8022,6 +8201,16 @@ MaybeObject* JSObject::GetElementWithReceiver(Object* receiver, |
| } |
| break; |
| } |
| + case FAST_DOUBLE_ELEMENTS: { |
| + FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| + if (index < static_cast<uint32_t>(elms->length())) { |
| + if (!elms->is_the_hole(index)) { |
| + double double_value = elms->get(index); |
| + return GetHeap()->AllocateHeapNumber(double_value); |
| + } |
| + } |
| + break; |
| + } |
| case EXTERNAL_PIXEL_ELEMENTS: |
| case EXTERNAL_BYTE_ELEMENTS: |
| case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| @@ -8141,6 +8330,7 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) { |
| } |
| break; |
| } |
| + case FAST_DOUBLE_ELEMENTS: |
| case FAST_ELEMENTS: |
| case DICTIONARY_ELEMENTS: |
| UNREACHABLE(); |
| @@ -8225,6 +8415,23 @@ bool JSObject::ShouldConvertToFastElements() { |
| } |
| +bool JSObject::ShouldConvertToFastDoubleElements() { |
| + if (FLAG_unbox_double_arrays) { |
| + ASSERT(HasDictionaryElements()); |
| + NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| + for (int i = 0; i < dictionary->Capacity(); i++) { |
| + Object* key = dictionary->KeyAt(i); |
| + if (key->IsNumber()) { |
| + if (!dictionary->ValueAt(i)->IsNumber()) return false; |
| + } |
| + } |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| + |
| // Certain compilers request function template instantiation when they |
| // see the definition of the other template functions in the |
| // class. This requires us to have the template functions put |