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 3541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3552 Handle<FixedArray> array, | 3552 Handle<FixedArray> array, |
3553 int valid_descriptors) { | 3553 int valid_descriptors) { |
3554 NeanderArray callbacks(descriptors); | 3554 NeanderArray callbacks(descriptors); |
3555 DCHECK(array->length() >= callbacks.length() + valid_descriptors); | 3555 DCHECK(array->length() >= callbacks.length() + valid_descriptors); |
3556 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks, | 3556 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks, |
3557 array, | 3557 array, |
3558 valid_descriptors); | 3558 valid_descriptors); |
3559 } | 3559 } |
3560 | 3560 |
3561 | 3561 |
3562 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { | 3562 static bool ContainsMap(MapHandleList* maps, Map* map) { |
3563 DCHECK(!map.is_null()); | 3563 DCHECK_NOT_NULL(map); |
3564 for (int i = 0; i < maps->length(); ++i) { | 3564 for (int i = 0; i < maps->length(); ++i) { |
3565 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; | 3565 if (!maps->at(i).is_null() && *maps->at(i) == map) return true; |
3566 } | 3566 } |
3567 return false; | 3567 return false; |
3568 } | 3568 } |
3569 | 3569 |
3570 | 3570 |
3571 template <class T> | 3571 Handle<Map> Map::FindTransitionedMap(Handle<Map> map, |
3572 static Handle<T> MaybeNull(T* p) { | 3572 MapHandleList* candidates) { |
3573 if (p == NULL) return Handle<T>::null(); | 3573 ElementsKind kind = map->elements_kind(); |
3574 return Handle<T>(p); | 3574 bool packed = IsFastPackedElementsKind(kind); |
3575 } | |
3576 | 3575 |
3577 | 3576 Map* transition = nullptr; |
3578 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { | |
3579 ElementsKind kind = elements_kind(); | |
3580 Handle<Map> transitioned_map = Handle<Map>::null(); | |
3581 Handle<Map> current_map(this); | |
3582 bool packed = IsFastPackedElementsKind(kind); | |
3583 if (IsTransitionableFastElementsKind(kind)) { | 3577 if (IsTransitionableFastElementsKind(kind)) { |
3584 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { | 3578 for (Map* current = map->ElementsTransitionMap(); |
3585 kind = GetNextMoreGeneralFastElementsKind(kind, false); | 3579 current != nullptr && current->has_fast_elements(); |
3586 Handle<Map> maybe_transitioned_map = | 3580 current = current->ElementsTransitionMap()) { |
3587 MaybeNull(current_map->LookupElementsTransitionMap(kind)); | 3581 if (ContainsMap(candidates, current) && |
3588 if (maybe_transitioned_map.is_null()) break; | 3582 (packed || !IsFastPackedElementsKind(current->elements_kind()))) { |
3589 if (ContainsMap(candidates, maybe_transitioned_map) && | 3583 transition = current; |
3590 (packed || !IsFastPackedElementsKind(kind))) { | 3584 packed = packed && IsFastPackedElementsKind(current->elements_kind()); |
3591 transitioned_map = maybe_transitioned_map; | |
3592 if (!IsFastPackedElementsKind(kind)) packed = false; | |
3593 } | 3585 } |
3594 current_map = maybe_transitioned_map; | |
3595 } | 3586 } |
3596 } | 3587 } |
3597 return transitioned_map; | 3588 return transition == nullptr ? Handle<Map>() : handle(transition); |
3598 } | 3589 } |
3599 | 3590 |
3600 | 3591 |
3601 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { | 3592 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
3602 Map* current_map = map; | 3593 Map* current_map = map; |
3603 int target_kind = | |
3604 IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind) | |
3605 ? to_kind | |
3606 : TERMINAL_FAST_ELEMENTS_KIND; | |
3607 | 3594 |
3608 // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data | 3595 // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data |
3609 // allows to change elements from arbitrary kind to any ExternalArray | 3596 // allows to change elements from arbitrary kind to any ExternalArray |
3610 // elements kind. Satisfy its requirements, checking whether we already | 3597 // elements kind. Satisfy its requirements, checking whether we already |
3611 // have the cached transition. | 3598 // have the cached transition. |
3612 if (IsExternalArrayElementsKind(to_kind) && | 3599 if (IsExternalArrayElementsKind(to_kind) && |
3613 !IsFixedTypedArrayElementsKind(map->elements_kind())) { | 3600 !IsFixedTypedArrayElementsKind(map->elements_kind())) { |
3614 Map* next_map = map->ElementsTransitionMap(); | 3601 Map* next_map = map->ElementsTransitionMap(); |
3615 if (next_map != NULL && next_map->elements_kind() == to_kind) { | 3602 if (next_map != NULL && next_map->elements_kind() == to_kind) { |
3616 return next_map; | 3603 return next_map; |
3617 } | 3604 } |
3618 return map; | 3605 return map; |
3619 } | 3606 } |
3620 | 3607 |
3621 ElementsKind kind = map->elements_kind(); | 3608 ElementsKind kind = map->elements_kind(); |
3622 while (kind != target_kind) { | 3609 while (kind != to_kind) { |
3623 kind = GetNextTransitionElementsKind(kind); | |
3624 Map* next_map = current_map->ElementsTransitionMap(); | 3610 Map* next_map = current_map->ElementsTransitionMap(); |
3625 if (next_map == NULL) return current_map; | 3611 if (next_map == nullptr) return current_map; |
3612 kind = next_map->elements_kind(); | |
3626 current_map = next_map; | 3613 current_map = next_map; |
3627 } | 3614 } |
3628 | 3615 |
3629 Map* next_map = current_map->ElementsTransitionMap(); | 3616 DCHECK_EQ(to_kind, current_map->elements_kind()); |
3630 if (to_kind != kind && next_map != NULL) { | |
3631 DCHECK(to_kind == DICTIONARY_ELEMENTS); | |
3632 if (next_map->elements_kind() == to_kind) return next_map; | |
3633 } | |
3634 | |
3635 DCHECK(current_map->elements_kind() == target_kind); | |
3636 return current_map; | 3617 return current_map; |
3637 } | 3618 } |
3638 | 3619 |
3639 | 3620 |
3640 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { | 3621 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { |
3641 Map* to_map = FindClosestElementsTransition(this, to_kind); | 3622 Map* to_map = FindClosestElementsTransition(this, to_kind); |
3642 if (to_map->elements_kind() == to_kind) return to_map; | 3623 if (to_map->elements_kind() == to_kind) return to_map; |
3643 return NULL; | 3624 return nullptr; |
3644 } | 3625 } |
3645 | 3626 |
3646 | 3627 |
3647 bool Map::IsMapInArrayPrototypeChain() { | 3628 bool Map::IsMapInArrayPrototypeChain() { |
3648 Isolate* isolate = GetIsolate(); | 3629 Isolate* isolate = GetIsolate(); |
3649 if (isolate->initial_array_prototype()->map() == this) { | 3630 if (isolate->initial_array_prototype()->map() == this) { |
3650 return true; | 3631 return true; |
3651 } | 3632 } |
3652 | 3633 |
3653 if (isolate->initial_object_prototype()->map() == this) { | 3634 if (isolate->initial_object_prototype()->map() == this) { |
(...skipping 20 matching lines...) Expand all Loading... | |
3674 DCHECK(IsTransitionElementsKind(map->elements_kind())); | 3655 DCHECK(IsTransitionElementsKind(map->elements_kind())); |
3675 | 3656 |
3676 Handle<Map> current_map = map; | 3657 Handle<Map> current_map = map; |
3677 | 3658 |
3678 ElementsKind kind = map->elements_kind(); | 3659 ElementsKind kind = map->elements_kind(); |
3679 TransitionFlag flag; | 3660 TransitionFlag flag; |
3680 if (map->is_prototype_map()) { | 3661 if (map->is_prototype_map()) { |
3681 flag = OMIT_TRANSITION; | 3662 flag = OMIT_TRANSITION; |
3682 } else { | 3663 } else { |
3683 flag = INSERT_TRANSITION; | 3664 flag = INSERT_TRANSITION; |
3684 while (kind != to_kind && !IsTerminalElementsKind(kind)) { | 3665 if (IsFastElementsKind(kind)) { |
3685 kind = GetNextTransitionElementsKind(kind); | 3666 while (kind != to_kind && !IsTerminalElementsKind(kind)) { |
3686 current_map = Map::CopyAsElementsKind(current_map, kind, flag); | 3667 kind = GetNextTransitionElementsKind(kind); |
3668 current_map = Map::CopyAsElementsKind(current_map, kind, flag); | |
3669 } | |
3687 } | 3670 } |
3688 } | 3671 } |
3689 | 3672 |
3690 // In case we are exiting the fast elements kind system, just add the map in | 3673 // In case we are exiting the fast elements kind system, just add the map in |
3691 // the end. | 3674 // the end. |
3692 if (kind != to_kind) { | 3675 if (kind != to_kind) { |
3693 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); | 3676 current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); |
3694 } | 3677 } |
3695 | 3678 |
3696 DCHECK(current_map->elements_kind() == to_kind); | 3679 DCHECK(current_map->elements_kind() == to_kind); |
3697 return current_map; | 3680 return current_map; |
3698 } | 3681 } |
3699 | 3682 |
3700 | 3683 |
3701 Handle<Map> Map::TransitionElementsTo(Handle<Map> map, | 3684 Handle<Map> Map::TransitionElementsTo(Handle<Map> map, |
3702 ElementsKind to_kind) { | 3685 ElementsKind to_kind) { |
3703 ElementsKind from_kind = map->elements_kind(); | 3686 ElementsKind from_kind = map->elements_kind(); |
3704 if (from_kind == to_kind) return map; | 3687 if (from_kind == to_kind) return map; |
3705 | 3688 |
3706 Isolate* isolate = map->GetIsolate(); | 3689 Isolate* isolate = map->GetIsolate(); |
3707 Context* native_context = isolate->context()->native_context(); | 3690 Context* native_context = isolate->context()->native_context(); |
3708 Object* maybe_array_maps = map->is_strong() | 3691 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { |
3709 ? native_context->js_array_strong_maps() | 3692 if (*map == native_context->fast_aliased_arguments_map()) { |
3710 : native_context->js_array_maps(); | 3693 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); |
3711 if (maybe_array_maps->IsFixedArray()) { | 3694 return handle(native_context->slow_aliased_arguments_map()); |
3712 DisallowHeapAllocation no_gc; | 3695 } |
3713 FixedArray* array_maps = FixedArray::cast(maybe_array_maps); | 3696 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { |
3714 if (array_maps->get(from_kind) == *map) { | 3697 if (*map == native_context->slow_aliased_arguments_map()) { |
3715 Object* maybe_transitioned_map = array_maps->get(to_kind); | 3698 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); |
3716 if (maybe_transitioned_map->IsMap()) { | 3699 return handle(native_context->fast_aliased_arguments_map()); |
3717 return handle(Map::cast(maybe_transitioned_map)); | 3700 } |
3701 } else { | |
3702 Object* maybe_array_maps = map->is_strong() | |
3703 ? native_context->js_array_strong_maps() | |
3704 : native_context->js_array_maps(); | |
3705 if (maybe_array_maps->IsFixedArray()) { | |
3706 DisallowHeapAllocation no_gc; | |
3707 FixedArray* array_maps = FixedArray::cast(maybe_array_maps); | |
3708 if (array_maps->get(from_kind) == *map) { | |
3709 Object* maybe_transitioned_map = array_maps->get(to_kind); | |
3710 if (maybe_transitioned_map->IsMap()) { | |
3711 return handle(Map::cast(maybe_transitioned_map)); | |
3712 } | |
3718 } | 3713 } |
3719 } | 3714 } |
3720 } | 3715 } |
3721 | 3716 |
3722 DCHECK(!map->IsUndefined()); | 3717 DCHECK(!map->IsUndefined()); |
3723 bool allow_store_transition = IsTransitionElementsKind(from_kind); | 3718 bool allow_store_transition = IsTransitionElementsKind(from_kind); |
3724 // Only store fast element maps in ascending generality. | 3719 // Only store fast element maps in ascending generality. |
3725 if (IsFastElementsKind(to_kind)) { | 3720 if (IsFastElementsKind(to_kind)) { |
3726 allow_store_transition &= | 3721 allow_store_transition &= |
Igor Sheludko
2015/07/02 13:28:42
allow_store_transition = allow_store_transition &&
Toon Verwaest
2015/07/02 13:49:02
Done.
| |
3727 IsTransitionableFastElementsKind(from_kind) && | 3722 IsTransitionableFastElementsKind(from_kind) && |
3728 IsMoreGeneralElementsKindTransition(from_kind, to_kind); | 3723 IsMoreGeneralElementsKindTransition(from_kind, to_kind); |
3729 } | 3724 } |
3730 | 3725 |
3731 if (!allow_store_transition) { | 3726 if (!allow_store_transition) { |
3732 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); | 3727 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); |
3733 } | 3728 } |
3734 | 3729 |
3735 return Map::AsElementsKind(map, to_kind); | 3730 return Map::AsElementsKind(map, to_kind); |
3736 } | 3731 } |
(...skipping 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4810 : array->length(); | 4805 : array->length(); |
4811 int old_capacity = 0; | 4806 int old_capacity = 0; |
4812 int used_elements = 0; | 4807 int used_elements = 0; |
4813 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); | 4808 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
4814 Handle<SeededNumberDictionary> dictionary = | 4809 Handle<SeededNumberDictionary> dictionary = |
4815 SeededNumberDictionary::New(isolate, used_elements); | 4810 SeededNumberDictionary::New(isolate, used_elements); |
4816 | 4811 |
4817 dictionary = CopyFastElementsToDictionary(array, length, dictionary); | 4812 dictionary = CopyFastElementsToDictionary(array, length, dictionary); |
4818 | 4813 |
4819 // Switch to using the dictionary as the backing storage for elements. | 4814 // Switch to using the dictionary as the backing storage for elements. |
4815 ElementsKind target_kind = | |
4816 is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS; | |
4817 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); | |
4818 // Set the new map first to satify the elements type assert in set_elements(). | |
4819 JSObject::MigrateToMap(object, new_map); | |
4820 | |
4820 if (is_arguments) { | 4821 if (is_arguments) { |
4821 FixedArray::cast(object->elements())->set(1, *dictionary); | 4822 FixedArray::cast(object->elements())->set(1, *dictionary); |
4822 } else { | 4823 } else { |
4823 // Set the new map first to satify the elements type assert in | |
4824 // set_elements(). | |
4825 Handle<Map> new_map = | |
4826 JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS); | |
4827 | |
4828 JSObject::MigrateToMap(object, new_map); | |
4829 object->set_elements(*dictionary); | 4824 object->set_elements(*dictionary); |
4830 } | 4825 } |
4831 | 4826 |
4832 isolate->counters()->elements_to_dictionary()->Increment(); | 4827 isolate->counters()->elements_to_dictionary()->Increment(); |
4833 | 4828 |
4834 #ifdef DEBUG | 4829 #ifdef DEBUG |
4835 if (FLAG_trace_normalization) { | 4830 if (FLAG_trace_normalization) { |
4836 OFStream os(stdout); | 4831 OFStream os(stdout); |
4837 os << "Object elements have been normalized:\n"; | 4832 os << "Object elements have been normalized:\n"; |
4838 object->Print(os); | 4833 object->Print(os); |
4839 } | 4834 } |
4840 #endif | 4835 #endif |
4841 | 4836 |
4842 DCHECK(object->HasDictionaryElements() || | 4837 DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
4843 object->HasDictionaryArgumentsElements()); | |
4844 return dictionary; | 4838 return dictionary; |
4845 } | 4839 } |
4846 | 4840 |
4847 | 4841 |
4848 static Smi* GenerateIdentityHash(Isolate* isolate) { | 4842 static Smi* GenerateIdentityHash(Isolate* isolate) { |
4849 int hash_value; | 4843 int hash_value; |
4850 int attempts = 0; | 4844 int attempts = 0; |
4851 do { | 4845 do { |
4852 // Generate a random 32-bit hash value but limit range to fit | 4846 // Generate a random 32-bit hash value but limit range to fit |
4853 // within a smi. | 4847 // within a smi. |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5330 case FAST_SMI_ELEMENTS: | 5324 case FAST_SMI_ELEMENTS: |
5331 case FAST_HOLEY_SMI_ELEMENTS: | 5325 case FAST_HOLEY_SMI_ELEMENTS: |
5332 break; | 5326 break; |
5333 case FAST_ELEMENTS: | 5327 case FAST_ELEMENTS: |
5334 case FAST_HOLEY_ELEMENTS: | 5328 case FAST_HOLEY_ELEMENTS: |
5335 case DICTIONARY_ELEMENTS: { | 5329 case DICTIONARY_ELEMENTS: { |
5336 FixedArray* elements = FixedArray::cast(this->elements()); | 5330 FixedArray* elements = FixedArray::cast(this->elements()); |
5337 if (ReferencesObjectFromElements(elements, kind, obj)) return true; | 5331 if (ReferencesObjectFromElements(elements, kind, obj)) return true; |
5338 break; | 5332 break; |
5339 } | 5333 } |
5340 case SLOPPY_ARGUMENTS_ELEMENTS: { | 5334 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
5335 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { | |
5341 FixedArray* parameter_map = FixedArray::cast(elements()); | 5336 FixedArray* parameter_map = FixedArray::cast(elements()); |
5342 // Check the mapped parameters. | 5337 // Check the mapped parameters. |
5343 int length = parameter_map->length(); | 5338 int length = parameter_map->length(); |
5344 for (int i = 2; i < length; ++i) { | 5339 for (int i = 2; i < length; ++i) { |
5345 Object* value = parameter_map->get(i); | 5340 Object* value = parameter_map->get(i); |
5346 if (!value->IsTheHole() && value == obj) return true; | 5341 if (!value->IsTheHole() && value == obj) return true; |
5347 } | 5342 } |
5348 // Check the arguments. | 5343 // Check the arguments. |
5349 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 5344 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
5350 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : | 5345 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5428 // It's not possible to seal objects with external array elements | 5423 // It's not possible to seal objects with external array elements |
5429 if (object->HasExternalArrayElements() || | 5424 if (object->HasExternalArrayElements() || |
5430 object->HasFixedTypedArrayElements()) { | 5425 object->HasFixedTypedArrayElements()) { |
5431 THROW_NEW_ERROR( | 5426 THROW_NEW_ERROR( |
5432 isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), | 5427 isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), |
5433 Object); | 5428 Object); |
5434 } | 5429 } |
5435 | 5430 |
5436 // If there are fast elements we normalize. | 5431 // If there are fast elements we normalize. |
5437 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); | 5432 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
5438 DCHECK(object->HasDictionaryElements() || | 5433 DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
5439 object->HasDictionaryArgumentsElements()); | |
5440 | 5434 |
5441 // Make sure that we never go back to fast case. | 5435 // Make sure that we never go back to fast case. |
5442 dictionary->set_requires_slow_elements(); | 5436 dictionary->set_requires_slow_elements(); |
5443 | 5437 |
5444 // Do a map transition, other objects with this map may still | 5438 // Do a map transition, other objects with this map may still |
5445 // be extensible. | 5439 // be extensible. |
5446 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. | 5440 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. |
5447 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); | 5441 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); |
5448 | 5442 |
5449 new_map->set_is_extensible(false); | 5443 new_map->set_is_extensible(false); |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5857 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), | 5851 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)), |
5858 JSObject); | 5852 JSObject); |
5859 if (copying) { | 5853 if (copying) { |
5860 element_dictionary->ValueAtPut(i, *result); | 5854 element_dictionary->ValueAtPut(i, *result); |
5861 } | 5855 } |
5862 } | 5856 } |
5863 } | 5857 } |
5864 } | 5858 } |
5865 break; | 5859 break; |
5866 } | 5860 } |
5867 case SLOPPY_ARGUMENTS_ELEMENTS: | 5861 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
5862 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | |
5868 UNIMPLEMENTED(); | 5863 UNIMPLEMENTED(); |
5869 break; | 5864 break; |
5870 | 5865 |
5871 | 5866 |
5872 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 5867 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
5873 case EXTERNAL_##TYPE##_ELEMENTS: \ | 5868 case EXTERNAL_##TYPE##_ELEMENTS: \ |
5874 case TYPE##_ELEMENTS: \ | 5869 case TYPE##_ELEMENTS: \ |
5875 | 5870 |
5876 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 5871 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
5877 #undef TYPED_ARRAY_CASE | 5872 #undef TYPED_ARRAY_CASE |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6274 | 6269 |
6275 case DICTIONARY_ELEMENTS: | 6270 case DICTIONARY_ELEMENTS: |
6276 if (UpdateGetterSetterInDictionary(object->element_dictionary(), | 6271 if (UpdateGetterSetterInDictionary(object->element_dictionary(), |
6277 index, | 6272 index, |
6278 *getter, | 6273 *getter, |
6279 *setter, | 6274 *setter, |
6280 attributes)) { | 6275 attributes)) { |
6281 return; | 6276 return; |
6282 } | 6277 } |
6283 break; | 6278 break; |
6284 case SLOPPY_ARGUMENTS_ELEMENTS: { | 6279 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
6280 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { | |
6285 // Ascertain whether we have read-only properties or an existing | 6281 // Ascertain whether we have read-only properties or an existing |
6286 // getter/setter pair in an arguments elements dictionary backing | 6282 // getter/setter pair in an arguments elements dictionary backing |
6287 // store. | 6283 // store. |
6288 FixedArray* parameter_map = FixedArray::cast(object->elements()); | 6284 FixedArray* parameter_map = FixedArray::cast(object->elements()); |
6289 uint32_t length = parameter_map->length(); | 6285 uint32_t length = parameter_map->length(); |
6290 Object* probe = | 6286 Object* probe = |
6291 index < (length - 2) ? parameter_map->get(index + 2) : NULL; | 6287 index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
6292 if (probe == NULL || probe->IsTheHole()) { | 6288 if (probe == NULL || probe->IsTheHole()) { |
6293 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 6289 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
6294 if (arguments->IsDictionary()) { | 6290 if (arguments->IsDictionary()) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6340 uint32_t index, | 6336 uint32_t index, |
6341 Handle<Object> structure, | 6337 Handle<Object> structure, |
6342 PropertyAttributes attributes) { | 6338 PropertyAttributes attributes) { |
6343 Heap* heap = object->GetHeap(); | 6339 Heap* heap = object->GetHeap(); |
6344 PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0, | 6340 PropertyDetails details = PropertyDetails(attributes, ACCESSOR_CONSTANT, 0, |
6345 PropertyCellType::kNoCell); | 6341 PropertyCellType::kNoCell); |
6346 | 6342 |
6347 // Normalize elements to make this operation simple. | 6343 // Normalize elements to make this operation simple. |
6348 bool had_dictionary_elements = object->HasDictionaryElements(); | 6344 bool had_dictionary_elements = object->HasDictionaryElements(); |
6349 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); | 6345 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
6350 DCHECK(object->HasDictionaryElements() || | 6346 DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
6351 object->HasDictionaryArgumentsElements()); | |
6352 // Update the dictionary with the new ACCESSOR_CONSTANT property. | 6347 // Update the dictionary with the new ACCESSOR_CONSTANT property. |
6353 dictionary = SeededNumberDictionary::Set(dictionary, index, structure, | 6348 dictionary = SeededNumberDictionary::Set(dictionary, index, structure, |
6354 details); | 6349 details); |
6355 dictionary->set_requires_slow_elements(); | 6350 dictionary->set_requires_slow_elements(); |
6356 | 6351 |
6357 // Update the dictionary backing store on the object. | 6352 // Update the dictionary backing store on the object. |
6358 if (object->elements()->map() == heap->sloppy_arguments_elements_map()) { | 6353 if (object->elements()->map() == heap->sloppy_arguments_elements_map()) { |
6359 // Also delete any parameter alias. | 6354 // Also delete any parameter alias. |
6360 // | 6355 // |
6361 // TODO(kmillikin): when deleting the last parameter alias we could | 6356 // TODO(kmillikin): when deleting the last parameter alias we could |
(...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7123 | 7118 |
7124 case FAST_DOUBLE_ELEMENTS: | 7119 case FAST_DOUBLE_ELEMENTS: |
7125 case FAST_HOLEY_DOUBLE_ELEMENTS: | 7120 case FAST_HOLEY_DOUBLE_ELEMENTS: |
7126 if (value->IsNumber()) return map; | 7121 if (value->IsNumber()) return map; |
7127 kind = FAST_ELEMENTS; | 7122 kind = FAST_ELEMENTS; |
7128 break; | 7123 break; |
7129 | 7124 |
7130 case FAST_ELEMENTS: | 7125 case FAST_ELEMENTS: |
7131 case FAST_HOLEY_ELEMENTS: | 7126 case FAST_HOLEY_ELEMENTS: |
7132 case DICTIONARY_ELEMENTS: | 7127 case DICTIONARY_ELEMENTS: |
7133 case SLOPPY_ARGUMENTS_ELEMENTS: | 7128 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
7129 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | |
7134 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 7130 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
7135 case EXTERNAL_##TYPE##_ELEMENTS: \ | 7131 case EXTERNAL_##TYPE##_ELEMENTS: \ |
7136 case TYPE##_ELEMENTS: | 7132 case TYPE##_ELEMENTS: |
7137 | 7133 |
7138 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 7134 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
7139 #undef TYPED_ARRAY_CASE | 7135 #undef TYPED_ARRAY_CASE |
7140 return map; | 7136 return map; |
7141 } | 7137 } |
7142 | 7138 |
7143 if (holey) kind = GetHoleyElementsKind(kind); | 7139 if (holey) kind = GetHoleyElementsKind(kind); |
(...skipping 5149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12293 uint32_t arg_count, | 12289 uint32_t arg_count, |
12294 EnsureElementsMode mode) { | 12290 EnsureElementsMode mode) { |
12295 // Elements in |Arguments| are ordered backwards (because they're on the | 12291 // Elements in |Arguments| are ordered backwards (because they're on the |
12296 // stack), but the method that's called here iterates over them in forward | 12292 // stack), but the method that's called here iterates over them in forward |
12297 // direction. | 12293 // direction. |
12298 return EnsureCanContainElements( | 12294 return EnsureCanContainElements( |
12299 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); | 12295 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); |
12300 } | 12296 } |
12301 | 12297 |
12302 | 12298 |
12303 bool JSObject::HasFastArgumentsElements() { | |
12304 Heap* heap = GetHeap(); | |
12305 if (!elements()->IsFixedArray()) return false; | |
12306 FixedArray* elements = FixedArray::cast(this->elements()); | |
12307 if (elements->map() != heap->sloppy_arguments_elements_map()) { | |
12308 return false; | |
12309 } | |
12310 FixedArray* arguments = FixedArray::cast(elements->get(1)); | |
12311 return !arguments->IsDictionary(); | |
12312 } | |
12313 | |
12314 | |
12315 bool JSObject::HasDictionaryArgumentsElements() { | |
12316 Heap* heap = GetHeap(); | |
12317 if (!elements()->IsFixedArray()) return false; | |
12318 FixedArray* elements = FixedArray::cast(this->elements()); | |
12319 if (elements->map() != heap->sloppy_arguments_elements_map()) { | |
12320 return false; | |
12321 } | |
12322 FixedArray* arguments = FixedArray::cast(elements->get(1)); | |
12323 return arguments->IsDictionary(); | |
12324 } | |
12325 | |
12326 | |
12327 ElementsAccessor* JSObject::GetElementsAccessor() { | 12299 ElementsAccessor* JSObject::GetElementsAccessor() { |
12328 return ElementsAccessor::ForKind(GetElementsKind()); | 12300 return ElementsAccessor::ForKind(GetElementsKind()); |
12329 } | 12301 } |
12330 | 12302 |
12331 | 12303 |
12332 void JSObject::ValidateElements(Handle<JSObject> object) { | 12304 void JSObject::ValidateElements(Handle<JSObject> object) { |
12333 #ifdef ENABLE_SLOW_DCHECKS | 12305 #ifdef ENABLE_SLOW_DCHECKS |
12334 if (FLAG_enable_slow_asserts) { | 12306 if (FLAG_enable_slow_asserts) { |
12335 ElementsAccessor* accessor = object->GetElementsAccessor(); | 12307 ElementsAccessor* accessor = object->GetElementsAccessor(); |
12336 accessor->Validate(object); | 12308 accessor->Validate(object); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12383 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); | 12355 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); |
12384 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12356 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
12385 uint32_t new_capacity; | 12357 uint32_t new_capacity; |
12386 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); | 12358 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); |
12387 } | 12359 } |
12388 return false; | 12360 return false; |
12389 } | 12361 } |
12390 | 12362 |
12391 | 12363 |
12392 static ElementsKind BestFittingFastElementsKind(JSObject* object) { | 12364 static ElementsKind BestFittingFastElementsKind(JSObject* object) { |
12393 if (object->HasSloppyArgumentsElements()) return SLOPPY_ARGUMENTS_ELEMENTS; | 12365 if (object->HasSloppyArgumentsElements()) { |
12366 return FAST_SLOPPY_ARGUMENTS_ELEMENTS; | |
12367 } | |
12394 DCHECK(object->HasDictionaryElements()); | 12368 DCHECK(object->HasDictionaryElements()); |
12395 SeededNumberDictionary* dictionary = object->element_dictionary(); | 12369 SeededNumberDictionary* dictionary = object->element_dictionary(); |
12396 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; | 12370 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
12397 for (int i = 0; i < dictionary->Capacity(); i++) { | 12371 for (int i = 0; i < dictionary->Capacity(); i++) { |
12398 Object* key = dictionary->KeyAt(i); | 12372 Object* key = dictionary->KeyAt(i); |
12399 if (key->IsNumber()) { | 12373 if (key->IsNumber()) { |
12400 Object* value = dictionary->ValueAt(i); | 12374 Object* value = dictionary->ValueAt(i); |
12401 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; | 12375 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; |
12402 if (!value->IsSmi()) { | 12376 if (!value->IsSmi()) { |
12403 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; | 12377 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12450 Handle<Object> old_length_handle; | 12424 Handle<Object> old_length_handle; |
12451 if (object->IsJSArray()) { | 12425 if (object->IsJSArray()) { |
12452 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); | 12426 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); |
12453 if (object->map()->is_observed()) { | 12427 if (object->map()->is_observed()) { |
12454 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); | 12428 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); |
12455 } | 12429 } |
12456 } | 12430 } |
12457 | 12431 |
12458 ElementsKind kind = object->GetElementsKind(); | 12432 ElementsKind kind = object->GetElementsKind(); |
12459 FixedArrayBase* elements = object->elements(); | 12433 FixedArrayBase* elements = object->elements(); |
12434 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; | |
12460 if (IsSloppyArgumentsElements(kind)) { | 12435 if (IsSloppyArgumentsElements(kind)) { |
12461 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); | 12436 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); |
12437 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; | |
12462 } | 12438 } |
12463 | 12439 |
12464 if (attributes != NONE) { | 12440 if (attributes != NONE) { |
12465 kind = DICTIONARY_ELEMENTS; | 12441 kind = dictionary_kind; |
12466 } else if (elements->IsSeededNumberDictionary()) { | 12442 } else if (elements->IsSeededNumberDictionary()) { |
12467 kind = ShouldConvertToFastElements(*object, | 12443 kind = ShouldConvertToFastElements(*object, |
12468 SeededNumberDictionary::cast(elements), | 12444 SeededNumberDictionary::cast(elements), |
12469 index, &new_capacity) | 12445 index, &new_capacity) |
12470 ? BestFittingFastElementsKind(*object) | 12446 ? BestFittingFastElementsKind(*object) |
12471 : DICTIONARY_ELEMENTS; // Overwrite in case of arguments. | 12447 : dictionary_kind; // Overwrite in case of arguments. |
12472 } else if (ShouldConvertToSlowElements( | 12448 } else if (ShouldConvertToSlowElements( |
12473 *object, static_cast<uint32_t>(elements->length()), index, | 12449 *object, static_cast<uint32_t>(elements->length()), index, |
12474 &new_capacity)) { | 12450 &new_capacity)) { |
12475 kind = DICTIONARY_ELEMENTS; | 12451 kind = dictionary_kind; |
12476 } | 12452 } |
12477 | 12453 |
12478 if (kind == DICTIONARY_ELEMENTS && object->HasSloppyArgumentsElements()) { | 12454 ElementsKind to = value->OptimalElementsKind(); |
12479 // TODO(verwaest): Distinguish fast/slow sloppy elements in ElementsKind. | 12455 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { |
12480 Handle<SeededNumberDictionary> dictionary = | 12456 to = GetHoleyElementsKind(to); |
12481 elements->IsSeededNumberDictionary() | 12457 kind = GetHoleyElementsKind(kind); |
12482 ? handle(SeededNumberDictionary::cast(elements)) | |
12483 : NormalizeElements(object); | |
12484 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | |
12485 Handle<SeededNumberDictionary> new_dictionary = | |
12486 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, | |
12487 details); | |
12488 if (attributes != NONE) new_dictionary->set_requires_slow_elements(); | |
12489 if (*dictionary != *new_dictionary) { | |
12490 FixedArray::cast(object->elements())->set(1, *new_dictionary); | |
12491 } | |
12492 } else { | |
12493 ElementsKind to = value->OptimalElementsKind(); | |
12494 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || | |
12495 index > old_length) { | |
12496 to = GetHoleyElementsKind(to); | |
12497 kind = GetHoleyElementsKind(kind); | |
12498 } | |
12499 to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind; | |
12500 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); | |
12501 accessor->Add(object, index, value, attributes, new_capacity); | |
12502 } | 12458 } |
12459 to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind; | |
12460 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); | |
12461 accessor->Add(object, index, value, attributes, new_capacity); | |
12503 | 12462 |
12504 uint32_t new_length = old_length; | 12463 uint32_t new_length = old_length; |
12505 Handle<Object> new_length_handle; | 12464 Handle<Object> new_length_handle; |
12506 if (object->IsJSArray() && index >= old_length) { | 12465 if (object->IsJSArray() && index >= old_length) { |
12507 new_length = index + 1; | 12466 new_length = index + 1; |
12508 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); | 12467 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); |
12509 JSArray::cast(*object)->set_length(*new_length_handle); | 12468 JSArray::cast(*object)->set_length(*new_length_handle); |
12510 } | 12469 } |
12511 | 12470 |
12512 if (!old_length_handle.is_null() && new_length != old_length) { | 12471 if (!old_length_handle.is_null() && new_length != old_length) { |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12751 } | 12710 } |
12752 | 12711 |
12753 | 12712 |
12754 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 12713 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
12755 *capacity = 0; | 12714 *capacity = 0; |
12756 *used = 0; | 12715 *used = 0; |
12757 | 12716 |
12758 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); | 12717 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); |
12759 FixedArray* backing_store = NULL; | 12718 FixedArray* backing_store = NULL; |
12760 switch (GetElementsKind()) { | 12719 switch (GetElementsKind()) { |
12761 case SLOPPY_ARGUMENTS_ELEMENTS: | 12720 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
12721 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: | |
12762 backing_store_base = | 12722 backing_store_base = |
12763 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); | 12723 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
12764 backing_store = FixedArray::cast(backing_store_base); | 12724 backing_store = FixedArray::cast(backing_store_base); |
12765 if (backing_store->IsDictionary()) { | 12725 if (backing_store->IsDictionary()) { |
12766 SeededNumberDictionary* dictionary = | 12726 SeededNumberDictionary* dictionary = |
12767 SeededNumberDictionary::cast(backing_store); | 12727 SeededNumberDictionary::cast(backing_store); |
12768 *capacity = dictionary->Capacity(); | 12728 *capacity = dictionary->Capacity(); |
12769 *used = dictionary->NumberOfElements(); | 12729 *used = dictionary->NumberOfElements(); |
12770 break; | 12730 break; |
12771 } | 12731 } |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13248 } | 13208 } |
13249 | 13209 |
13250 case DICTIONARY_ELEMENTS: { | 13210 case DICTIONARY_ELEMENTS: { |
13251 if (storage != NULL) { | 13211 if (storage != NULL) { |
13252 element_dictionary()->CopyKeysTo(storage, filter, | 13212 element_dictionary()->CopyKeysTo(storage, filter, |
13253 SeededNumberDictionary::SORTED); | 13213 SeededNumberDictionary::SORTED); |
13254 } | 13214 } |
13255 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); | 13215 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); |
13256 break; | 13216 break; |
13257 } | 13217 } |
13258 case SLOPPY_ARGUMENTS_ELEMENTS: { | 13218 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
13219 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { | |
13259 FixedArray* parameter_map = FixedArray::cast(elements()); | 13220 FixedArray* parameter_map = FixedArray::cast(elements()); |
13260 int mapped_length = parameter_map->length() - 2; | 13221 int mapped_length = parameter_map->length() - 2; |
13261 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 13222 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
13262 if (arguments->IsDictionary()) { | 13223 if (arguments->IsDictionary()) { |
13263 // Copy the keys from arguments first, because Dictionary::CopyKeysTo | 13224 // Copy the keys from arguments first, because Dictionary::CopyKeysTo |
13264 // will insert in storage starting at index 0. | 13225 // will insert in storage starting at index 0. |
13265 SeededNumberDictionary* dictionary = | 13226 SeededNumberDictionary* dictionary = |
13266 SeededNumberDictionary::cast(arguments); | 13227 SeededNumberDictionary::cast(arguments); |
13267 if (storage != NULL) { | 13228 if (storage != NULL) { |
13268 dictionary->CopyKeysTo(storage, filter, | 13229 dictionary->CopyKeysTo(storage, filter, |
(...skipping 2881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
16150 Handle<Object> new_value) { | 16111 Handle<Object> new_value) { |
16151 if (cell->value() != *new_value) { | 16112 if (cell->value() != *new_value) { |
16152 cell->set_value(*new_value); | 16113 cell->set_value(*new_value); |
16153 Isolate* isolate = cell->GetIsolate(); | 16114 Isolate* isolate = cell->GetIsolate(); |
16154 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16115 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16155 isolate, DependentCode::kPropertyCellChangedGroup); | 16116 isolate, DependentCode::kPropertyCellChangedGroup); |
16156 } | 16117 } |
16157 } | 16118 } |
16158 } // namespace internal | 16119 } // namespace internal |
16159 } // namespace v8 | 16120 } // namespace v8 |
OLD | NEW |