OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 4771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4782 if (!value->IsTheHole()) { | 4782 if (!value->IsTheHole()) { |
4783 PropertyDetails details = PropertyDetails::Empty(); | 4783 PropertyDetails details = PropertyDetails::Empty(); |
4784 dictionary = | 4784 dictionary = |
4785 SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details); | 4785 SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details); |
4786 } | 4786 } |
4787 } | 4787 } |
4788 return dictionary; | 4788 return dictionary; |
4789 } | 4789 } |
4790 | 4790 |
4791 | 4791 |
4792 Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary( | |
4793 Handle<JSObject> object, Handle<FixedArrayBase> elements) { | |
4794 DCHECK(!object->HasDictionaryElements()); | |
4795 DCHECK(!object->HasSlowArgumentsElements()); | |
4796 Isolate* isolate = object->GetIsolate(); | |
4797 // Ensure that notifications fire if the array or object prototypes are | |
4798 // normalizing. | |
4799 isolate->UpdateArrayProtectorOnNormalizeElements(object); | |
4800 int length = object->IsJSArray() | |
4801 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() | |
4802 : elements->length(); | |
4803 int used = object->GetFastElementsUsage(); | |
4804 Handle<SeededNumberDictionary> dictionary = | |
4805 SeededNumberDictionary::New(isolate, used); | |
4806 return CopyFastElementsToDictionary(elements, length, dictionary); | |
4807 } | |
4808 | |
4809 | |
4792 Handle<SeededNumberDictionary> JSObject::NormalizeElements( | 4810 Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
4793 Handle<JSObject> object) { | 4811 Handle<JSObject> object) { |
4794 DCHECK(!object->HasExternalArrayElements() && | 4812 DCHECK(!object->HasExternalArrayElements() && |
4795 !object->HasFixedTypedArrayElements()); | 4813 !object->HasFixedTypedArrayElements()); |
4796 Isolate* isolate = object->GetIsolate(); | 4814 Isolate* isolate = object->GetIsolate(); |
4797 | 4815 |
4798 // Find the backing store. | 4816 // Find the backing store. |
4799 Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements())); | 4817 Handle<FixedArrayBase> elements(object->elements(), isolate); |
4800 bool is_arguments = | 4818 bool is_arguments = object->HasSloppyArgumentsElements(); |
4801 (array->map() == isolate->heap()->sloppy_arguments_elements_map()); | |
4802 if (is_arguments) { | 4819 if (is_arguments) { |
4803 array = handle(FixedArrayBase::cast( | 4820 FixedArray* parameter_map = FixedArray::cast(*elements); |
4804 Handle<FixedArray>::cast(array)->get(1))); | 4821 elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate); |
4805 } | 4822 } |
4806 if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array); | 4823 |
4824 if (elements->IsDictionary()) { | |
4825 return Handle<SeededNumberDictionary>::cast(elements); | |
4826 } | |
4807 | 4827 |
4808 DCHECK(object->HasFastSmiOrObjectElements() || | 4828 DCHECK(object->HasFastSmiOrObjectElements() || |
4809 object->HasFastDoubleElements() || | 4829 object->HasFastDoubleElements() || |
4810 object->HasFastArgumentsElements()); | 4830 object->HasFastArgumentsElements()); |
4811 | 4831 |
4812 // Ensure that notifications fire if the array or object prototypes are | |
4813 // normalizing. | |
4814 isolate->UpdateArrayProtectorOnNormalizeElements(object); | |
4815 | |
4816 // Compute the effective length and allocate a new backing store. | |
4817 int length = object->IsJSArray() | |
4818 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() | |
4819 : array->length(); | |
4820 int old_capacity = 0; | |
4821 int used_elements = 0; | |
4822 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); | |
4823 Handle<SeededNumberDictionary> dictionary = | 4832 Handle<SeededNumberDictionary> dictionary = |
4824 SeededNumberDictionary::New(isolate, used_elements); | 4833 GetNormalizedElementDictionary(object, elements); |
4825 | |
4826 dictionary = CopyFastElementsToDictionary(array, length, dictionary); | |
4827 | 4834 |
4828 // Switch to using the dictionary as the backing storage for elements. | 4835 // Switch to using the dictionary as the backing storage for elements. |
4829 ElementsKind target_kind = | 4836 ElementsKind target_kind = |
4830 is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS; | 4837 is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS; |
4831 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); | 4838 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); |
4832 // Set the new map first to satify the elements type assert in set_elements(). | 4839 // Set the new map first to satify the elements type assert in set_elements(). |
4833 JSObject::MigrateToMap(object, new_map); | 4840 JSObject::MigrateToMap(object, new_map); |
4834 | 4841 |
4835 if (is_arguments) { | 4842 if (is_arguments) { |
4836 FixedArray::cast(object->elements())->set(1, *dictionary); | 4843 FixedArray::cast(object->elements())->set(1, *dictionary); |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5456 if (IsJSGlobalProxy()) { | 5463 if (IsJSGlobalProxy()) { |
5457 PrototypeIterator iter(GetIsolate(), this); | 5464 PrototypeIterator iter(GetIsolate(), this); |
5458 if (iter.IsAtEnd()) return false; | 5465 if (iter.IsAtEnd()) return false; |
5459 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); | 5466 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); |
5460 return JSObject::cast(iter.GetCurrent())->map()->is_extensible(); | 5467 return JSObject::cast(iter.GetCurrent())->map()->is_extensible(); |
5461 } | 5468 } |
5462 return map()->is_extensible(); | 5469 return map()->is_extensible(); |
5463 } | 5470 } |
5464 | 5471 |
5465 | 5472 |
5466 Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary( | |
5467 Handle<JSObject> object) { | |
5468 DCHECK(!object->elements()->IsDictionary()); | |
5469 Isolate* isolate = object->GetIsolate(); | |
5470 int length = object->IsJSArray() | |
5471 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() | |
5472 : object->elements()->length(); | |
5473 if (length > 0) { | |
5474 int capacity = 0; | |
5475 int used = 0; | |
5476 object->GetElementsCapacityAndUsage(&capacity, &used); | |
5477 Handle<SeededNumberDictionary> new_element_dictionary = | |
5478 SeededNumberDictionary::New(isolate, used); | |
5479 | |
5480 // Move elements to a dictionary; avoid calling NormalizeElements to avoid | |
5481 // unnecessary transitions. | |
5482 return CopyFastElementsToDictionary(handle(object->elements()), length, | |
5483 new_element_dictionary); | |
5484 } | |
5485 // No existing elements, use a pre-allocated empty backing store | |
5486 return isolate->factory()->empty_slow_element_dictionary(); | |
5487 } | |
5488 | |
5489 | |
5490 template <typename Dictionary> | 5473 template <typename Dictionary> |
5491 static void ApplyAttributesToDictionary(Dictionary* dictionary, | 5474 static void ApplyAttributesToDictionary(Dictionary* dictionary, |
5492 const PropertyAttributes attributes) { | 5475 const PropertyAttributes attributes) { |
5493 int capacity = dictionary->Capacity(); | 5476 int capacity = dictionary->Capacity(); |
5494 for (int i = 0; i < capacity; i++) { | 5477 for (int i = 0; i < capacity; i++) { |
5495 Object* k = dictionary->KeyAt(i); | 5478 Object* k = dictionary->KeyAt(i); |
5496 if (dictionary->IsKey(k) && | 5479 if (dictionary->IsKey(k) && |
5497 !(k->IsSymbol() && Symbol::cast(k)->is_private())) { | 5480 !(k->IsSymbol() && Symbol::cast(k)->is_private())) { |
5498 PropertyDetails details = dictionary->DetailsAt(i); | 5481 PropertyDetails details = dictionary->DetailsAt(i); |
5499 int attrs = attributes; | 5482 int attrs = attributes; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5537 | 5520 |
5538 // It's not possible to seal or freeze objects with external array elements | 5521 // It's not possible to seal or freeze objects with external array elements |
5539 if (object->HasExternalArrayElements() || | 5522 if (object->HasExternalArrayElements() || |
5540 object->HasFixedTypedArrayElements()) { | 5523 object->HasFixedTypedArrayElements()) { |
5541 THROW_NEW_ERROR( | 5524 THROW_NEW_ERROR( |
5542 isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), | 5525 isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), |
5543 Object); | 5526 Object); |
5544 } | 5527 } |
5545 | 5528 |
5546 Handle<SeededNumberDictionary> new_element_dictionary; | 5529 Handle<SeededNumberDictionary> new_element_dictionary; |
5547 if (!object->elements()->IsDictionary()) { | 5530 if (!object->HasDictionaryElements()) { |
5548 new_element_dictionary = GetNormalizedElementDictionary(object); | 5531 int length = |
5549 isolate->UpdateArrayProtectorOnNormalizeElements(object); | 5532 object->IsJSArray() |
5533 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() | |
5534 : object->elements()->length(); | |
5535 new_element_dictionary = | |
5536 length == 0 ? isolate->factory()->empty_slow_element_dictionary() | |
Igor Sheludko
2015/07/15 14:58:06
Probably it would be better if GetNormalizedElemen
Toon Verwaest
2015/07/15 15:07:58
It, unfortunately, cannot. The empty dictionary is
| |
5537 : GetNormalizedElementDictionary( | |
5538 object, handle(object->elements())); | |
5550 } | 5539 } |
5551 | 5540 |
5552 Handle<Symbol> transition_marker; | 5541 Handle<Symbol> transition_marker; |
5553 if (attrs == NONE) { | 5542 if (attrs == NONE) { |
5554 transition_marker = isolate->factory()->nonextensible_symbol(); | 5543 transition_marker = isolate->factory()->nonextensible_symbol(); |
5555 } else if (attrs == SEALED) { | 5544 } else if (attrs == SEALED) { |
5556 transition_marker = isolate->factory()->sealed_symbol(); | 5545 transition_marker = isolate->factory()->sealed_symbol(); |
5557 } else { | 5546 } else { |
5558 DCHECK(attrs == FROZEN); | 5547 DCHECK(attrs == FROZEN); |
5559 transition_marker = isolate->factory()->frozen_symbol(); | 5548 transition_marker = isolate->factory()->frozen_symbol(); |
(...skipping 6581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12141 *new_capacity = JSObject::NewElementsCapacity(index + 1); | 12130 *new_capacity = JSObject::NewElementsCapacity(index + 1); |
12142 DCHECK_LT(index, *new_capacity); | 12131 DCHECK_LT(index, *new_capacity); |
12143 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || | 12132 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || |
12144 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && | 12133 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && |
12145 object->GetHeap()->InNewSpace(object))) { | 12134 object->GetHeap()->InNewSpace(object))) { |
12146 return false; | 12135 return false; |
12147 } | 12136 } |
12148 // If the fast-case backing storage takes up roughly three times as | 12137 // If the fast-case backing storage takes up roughly three times as |
12149 // much space (in machine words) as a dictionary backing storage | 12138 // much space (in machine words) as a dictionary backing storage |
12150 // would, the object should have slow elements. | 12139 // would, the object should have slow elements. |
12151 int old_capacity = 0; | 12140 int used_elements = object->GetFastElementsUsage(); |
12152 int used_elements = 0; | |
12153 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); | |
12154 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * | 12141 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * |
12155 SeededNumberDictionary::kEntrySize; | 12142 SeededNumberDictionary::kEntrySize; |
12156 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; | 12143 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; |
12157 } | 12144 } |
12158 | 12145 |
12159 | 12146 |
12160 bool JSObject::WouldConvertToSlowElements(uint32_t index) { | 12147 bool JSObject::WouldConvertToSlowElements(uint32_t index) { |
12161 if (HasFastElements()) { | 12148 if (HasFastElements()) { |
12162 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); | 12149 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); |
12163 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12150 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12510 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { | 12497 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
12511 Isolate* isolate = array->GetIsolate(); | 12498 Isolate* isolate = array->GetIsolate(); |
12512 Handle<Name> length = isolate->factory()->length_string(); | 12499 Handle<Name> length = isolate->factory()->length_string(); |
12513 THROW_NEW_ERROR( | 12500 THROW_NEW_ERROR( |
12514 isolate, | 12501 isolate, |
12515 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), | 12502 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), |
12516 Object); | 12503 Object); |
12517 } | 12504 } |
12518 | 12505 |
12519 | 12506 |
12520 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 12507 template <typename BackingStore> |
12521 *capacity = 0; | 12508 static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) { |
12522 *used = 0; | 12509 int limit = object->IsJSArray() |
12510 ? Smi::cast(JSArray::cast(object)->length())->value() | |
12511 : store->length(); | |
12512 int used = 0; | |
12513 for (int i = 0; i < limit; ++i) { | |
12514 if (!store->is_the_hole(i)) ++used; | |
12515 } | |
12516 return used; | |
12517 } | |
12523 | 12518 |
12524 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); | 12519 |
12525 FixedArray* backing_store = NULL; | 12520 int JSObject::GetFastElementsUsage() { |
12521 FixedArrayBase* store = elements(); | |
12526 switch (GetElementsKind()) { | 12522 switch (GetElementsKind()) { |
12523 case FAST_SMI_ELEMENTS: | |
12524 case FAST_DOUBLE_ELEMENTS: | |
12525 case FAST_ELEMENTS: | |
12526 // Only JSArray have packed elements. | |
12527 return Smi::cast(JSArray::cast(this)->length())->value(); | |
12527 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: | 12528 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
12528 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | 12529 store = FixedArray::cast(FixedArray::cast(store)->get(1)); |
12529 backing_store_base = | 12530 // Fall through. |
12530 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); | |
12531 backing_store = FixedArray::cast(backing_store_base); | |
12532 if (backing_store->IsDictionary()) { | |
12533 SeededNumberDictionary* dictionary = | |
12534 SeededNumberDictionary::cast(backing_store); | |
12535 *capacity = dictionary->Capacity(); | |
12536 *used = dictionary->NumberOfElements(); | |
12537 break; | |
12538 } | |
12539 // Fall through. | |
12540 case FAST_SMI_ELEMENTS: | |
12541 case FAST_ELEMENTS: | |
12542 if (IsJSArray()) { | |
12543 *capacity = backing_store_base->length(); | |
12544 *used = Smi::cast(JSArray::cast(this)->length())->value(); | |
12545 break; | |
12546 } | |
12547 // Fall through if packing is not guaranteed. | |
12548 case FAST_HOLEY_SMI_ELEMENTS: | 12531 case FAST_HOLEY_SMI_ELEMENTS: |
12549 case FAST_HOLEY_ELEMENTS: | 12532 case FAST_HOLEY_ELEMENTS: |
12550 backing_store = FixedArray::cast(backing_store_base); | 12533 return FastHoleyElementsUsage(this, FixedArray::cast(store)); |
12551 *capacity = backing_store->length(); | 12534 case FAST_HOLEY_DOUBLE_ELEMENTS: |
12552 for (int i = 0; i < *capacity; ++i) { | 12535 if (elements()->length() == 0) return 0; |
12553 if (!backing_store->get(i)->IsTheHole()) ++(*used); | 12536 return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store)); |
12554 } | |
12555 break; | |
12556 case DICTIONARY_ELEMENTS: { | |
12557 SeededNumberDictionary* dictionary = element_dictionary(); | |
12558 *capacity = dictionary->Capacity(); | |
12559 *used = dictionary->NumberOfElements(); | |
12560 break; | |
12561 } | |
12562 case FAST_DOUBLE_ELEMENTS: | |
12563 if (IsJSArray()) { | |
12564 *capacity = backing_store_base->length(); | |
12565 *used = Smi::cast(JSArray::cast(this)->length())->value(); | |
12566 break; | |
12567 } | |
12568 // Fall through if packing is not guaranteed. | |
12569 case FAST_HOLEY_DOUBLE_ELEMENTS: { | |
12570 *capacity = elements()->length(); | |
12571 if (*capacity == 0) break; | |
12572 FixedDoubleArray * elms = FixedDoubleArray::cast(elements()); | |
12573 for (int i = 0; i < *capacity; i++) { | |
12574 if (!elms->is_the_hole(i)) ++(*used); | |
12575 } | |
12576 break; | |
12577 } | |
12578 | 12537 |
12538 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | |
12539 case DICTIONARY_ELEMENTS: | |
12579 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 12540 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
12580 case EXTERNAL_##TYPE##_ELEMENTS: \ | 12541 case EXTERNAL_##TYPE##_ELEMENTS: \ |
12581 case TYPE##_ELEMENTS: \ | 12542 case TYPE##_ELEMENTS: \ |
12582 | 12543 |
12583 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 12544 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
12584 #undef TYPED_ARRAY_CASE | 12545 #undef TYPED_ARRAY_CASE |
12585 { | 12546 UNREACHABLE(); |
12586 // External arrays are considered 100% used. | 12547 return 0; |
12587 FixedArrayBase* external_array = FixedArrayBase::cast(elements()); | |
12588 *capacity = external_array->length(); | |
12589 *used = external_array->length(); | |
12590 break; | |
12591 } | |
12592 } | 12548 } |
12593 } | 12549 } |
12594 | 12550 |
12595 | 12551 |
12596 // Certain compilers request function template instantiation when they | 12552 // Certain compilers request function template instantiation when they |
12597 // see the definition of the other template functions in the | 12553 // see the definition of the other template functions in the |
12598 // class. This requires us to have the template functions put | 12554 // class. This requires us to have the template functions put |
12599 // together, so even though this function belongs in objects-debug.cc, | 12555 // together, so even though this function belongs in objects-debug.cc, |
12600 // we keep it here instead to satisfy certain compilers. | 12556 // we keep it here instead to satisfy certain compilers. |
12601 #ifdef OBJECT_PRINT | 12557 #ifdef OBJECT_PRINT |
(...skipping 3321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
15923 Handle<Object> new_value) { | 15879 Handle<Object> new_value) { |
15924 if (cell->value() != *new_value) { | 15880 if (cell->value() != *new_value) { |
15925 cell->set_value(*new_value); | 15881 cell->set_value(*new_value); |
15926 Isolate* isolate = cell->GetIsolate(); | 15882 Isolate* isolate = cell->GetIsolate(); |
15927 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 15883 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
15928 isolate, DependentCode::kPropertyCellChangedGroup); | 15884 isolate, DependentCode::kPropertyCellChangedGroup); |
15929 } | 15885 } |
15930 } | 15886 } |
15931 } // namespace internal | 15887 } // namespace internal |
15932 } // namespace v8 | 15888 } // namespace v8 |
OLD | NEW |