Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 4c72aa9d6c5e60723e931762a8b20804fd6e30b2..b44f11eda7ee38c00f51b336a4b8f95ac02b8618 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -2423,7 +2423,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index, |
ElementsKind from_kind = root_map->elements_kind(); |
ElementsKind to_kind = old_map->elements_kind(); |
+ // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. |
if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && |
+ to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && |
!(IsTransitionableFastElementsKind(from_kind) && |
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { |
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, |
@@ -3559,51 +3561,38 @@ int AccessorInfo::AppendUnique(Handle<Object> descriptors, |
} |
-static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { |
- DCHECK(!map.is_null()); |
+static bool ContainsMap(MapHandleList* maps, Map* map) { |
+ DCHECK_NOT_NULL(map); |
for (int i = 0; i < maps->length(); ++i) { |
- if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; |
+ if (!maps->at(i).is_null() && *maps->at(i) == map) return true; |
} |
return false; |
} |
-template <class T> |
-static Handle<T> MaybeNull(T* p) { |
- if (p == NULL) return Handle<T>::null(); |
- return Handle<T>(p); |
-} |
- |
- |
-Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { |
- ElementsKind kind = elements_kind(); |
- Handle<Map> transitioned_map = Handle<Map>::null(); |
- Handle<Map> current_map(this); |
+Handle<Map> Map::FindTransitionedMap(Handle<Map> map, |
+ MapHandleList* candidates) { |
+ ElementsKind kind = map->elements_kind(); |
bool packed = IsFastPackedElementsKind(kind); |
+ |
+ Map* transition = nullptr; |
if (IsTransitionableFastElementsKind(kind)) { |
- while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { |
- kind = GetNextMoreGeneralFastElementsKind(kind, false); |
- Handle<Map> maybe_transitioned_map = |
- MaybeNull(current_map->LookupElementsTransitionMap(kind)); |
- if (maybe_transitioned_map.is_null()) break; |
- if (ContainsMap(candidates, maybe_transitioned_map) && |
- (packed || !IsFastPackedElementsKind(kind))) { |
- transitioned_map = maybe_transitioned_map; |
- if (!IsFastPackedElementsKind(kind)) packed = false; |
+ for (Map* current = map->ElementsTransitionMap(); |
+ current != nullptr && current->has_fast_elements(); |
+ current = current->ElementsTransitionMap()) { |
+ if (ContainsMap(candidates, current) && |
+ (packed || !IsFastPackedElementsKind(current->elements_kind()))) { |
+ transition = current; |
+ packed = packed && IsFastPackedElementsKind(current->elements_kind()); |
} |
- current_map = maybe_transitioned_map; |
} |
} |
- return transitioned_map; |
+ return transition == nullptr ? Handle<Map>() : handle(transition); |
} |
static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
Map* current_map = map; |
- int target_kind = |
- IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind) |
- ? to_kind |
- : TERMINAL_FAST_ELEMENTS_KIND; |
// Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data |
// allows to change elements from arbitrary kind to any ExternalArray |
@@ -3619,20 +3608,14 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
} |
ElementsKind kind = map->elements_kind(); |
- while (kind != target_kind) { |
- kind = GetNextTransitionElementsKind(kind); |
+ while (kind != to_kind) { |
Map* next_map = current_map->ElementsTransitionMap(); |
- if (next_map == NULL) return current_map; |
+ if (next_map == nullptr) return current_map; |
+ kind = next_map->elements_kind(); |
current_map = next_map; |
} |
- Map* next_map = current_map->ElementsTransitionMap(); |
- if (to_kind != kind && next_map != NULL) { |
- DCHECK(to_kind == DICTIONARY_ELEMENTS); |
- if (next_map->elements_kind() == to_kind) return next_map; |
- } |
- |
- DCHECK(current_map->elements_kind() == target_kind); |
+ DCHECK_EQ(to_kind, current_map->elements_kind()); |
return current_map; |
} |
@@ -3640,7 +3623,7 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { |
Map* to_map = FindClosestElementsTransition(this, to_kind); |
if (to_map->elements_kind() == to_kind) return to_map; |
- return NULL; |
+ return nullptr; |
} |
@@ -3681,9 +3664,11 @@ static Handle<Map> AddMissingElementsTransitions(Handle<Map> map, |
flag = OMIT_TRANSITION; |
} else { |
flag = INSERT_TRANSITION; |
- while (kind != to_kind && !IsTerminalElementsKind(kind)) { |
- kind = GetNextTransitionElementsKind(kind); |
- current_map = Map::CopyAsElementsKind(current_map, kind, flag); |
+ if (IsFastElementsKind(kind)) { |
+ while (kind != to_kind && !IsTerminalElementsKind(kind)) { |
+ kind = GetNextTransitionElementsKind(kind); |
+ current_map = Map::CopyAsElementsKind(current_map, kind, flag); |
+ } |
} |
} |
@@ -3705,16 +3690,28 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map, |
Isolate* isolate = map->GetIsolate(); |
Context* native_context = isolate->context()->native_context(); |
- Object* maybe_array_maps = map->is_strong() |
- ? native_context->js_array_strong_maps() |
- : native_context->js_array_maps(); |
- if (maybe_array_maps->IsFixedArray()) { |
- DisallowHeapAllocation no_gc; |
- FixedArray* array_maps = FixedArray::cast(maybe_array_maps); |
- if (array_maps->get(from_kind) == *map) { |
- Object* maybe_transitioned_map = array_maps->get(to_kind); |
- if (maybe_transitioned_map->IsMap()) { |
- return handle(Map::cast(maybe_transitioned_map)); |
+ if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { |
+ if (*map == native_context->fast_aliased_arguments_map()) { |
+ DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); |
+ return handle(native_context->slow_aliased_arguments_map()); |
+ } |
+ } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { |
+ if (*map == native_context->slow_aliased_arguments_map()) { |
+ DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); |
+ return handle(native_context->fast_aliased_arguments_map()); |
+ } |
+ } else { |
+ Object* maybe_array_maps = map->is_strong() |
+ ? native_context->js_array_strong_maps() |
+ : native_context->js_array_maps(); |
+ if (maybe_array_maps->IsFixedArray()) { |
+ DisallowHeapAllocation no_gc; |
+ FixedArray* array_maps = FixedArray::cast(maybe_array_maps); |
+ if (array_maps->get(from_kind) == *map) { |
+ Object* maybe_transitioned_map = array_maps->get(to_kind); |
+ if (maybe_transitioned_map->IsMap()) { |
+ return handle(Map::cast(maybe_transitioned_map)); |
+ } |
} |
} |
} |
@@ -3723,8 +3720,8 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map, |
bool allow_store_transition = IsTransitionElementsKind(from_kind); |
// Only store fast element maps in ascending generality. |
if (IsFastElementsKind(to_kind)) { |
- allow_store_transition &= |
- IsTransitionableFastElementsKind(from_kind) && |
+ allow_store_transition = |
+ allow_store_transition && IsTransitionableFastElementsKind(from_kind) && |
IsMoreGeneralElementsKindTransition(from_kind, to_kind); |
} |
@@ -4817,15 +4814,15 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
dictionary = CopyFastElementsToDictionary(array, length, dictionary); |
// Switch to using the dictionary as the backing storage for elements. |
+ ElementsKind target_kind = |
+ is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS; |
+ Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); |
+ // Set the new map first to satify the elements type assert in set_elements(). |
+ JSObject::MigrateToMap(object, new_map); |
+ |
if (is_arguments) { |
FixedArray::cast(object->elements())->set(1, *dictionary); |
} else { |
- // Set the new map first to satify the elements type assert in |
- // set_elements(). |
- Handle<Map> new_map = |
- JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS); |
- |
- JSObject::MigrateToMap(object, new_map); |
object->set_elements(*dictionary); |
} |
@@ -4839,8 +4836,7 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
} |
#endif |
- DCHECK(object->HasDictionaryElements() || |
- object->HasDictionaryArgumentsElements()); |
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
return dictionary; |
} |
@@ -5337,7 +5333,8 @@ bool JSObject::ReferencesObject(Object* obj) { |
if (ReferencesObjectFromElements(elements, kind, obj)) return true; |
break; |
} |
- case SLOPPY_ARGUMENTS_ELEMENTS: { |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { |
FixedArray* parameter_map = FixedArray::cast(elements()); |
// Check the mapped parameters. |
int length = parameter_map->length(); |
@@ -5435,8 +5432,7 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) { |
// If there are fast elements we normalize. |
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
- DCHECK(object->HasDictionaryElements() || |
- object->HasDictionaryArgumentsElements()); |
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
// Make sure that we never go back to fast case. |
dictionary->set_requires_slow_elements(); |
@@ -5864,7 +5860,8 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( |
} |
break; |
} |
- case SLOPPY_ARGUMENTS_ELEMENTS: |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
UNIMPLEMENTED(); |
break; |
@@ -6281,7 +6278,8 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object, |
return; |
} |
break; |
- case SLOPPY_ARGUMENTS_ELEMENTS: { |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { |
// Ascertain whether we have read-only properties or an existing |
// getter/setter pair in an arguments elements dictionary backing |
// store. |
@@ -6347,8 +6345,7 @@ void JSObject::SetElementCallback(Handle<JSObject> object, |
// Normalize elements to make this operation simple. |
bool had_dictionary_elements = object->HasDictionaryElements(); |
Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
- DCHECK(object->HasDictionaryElements() || |
- object->HasDictionaryArgumentsElements()); |
+ DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements()); |
// Update the dictionary with the new ACCESSOR_CONSTANT property. |
dictionary = SeededNumberDictionary::Set(dictionary, index, structure, |
details); |
@@ -7130,7 +7127,8 @@ Handle<Map> Map::PrepareForDataElement(Handle<Map> map, Handle<Object> value) { |
case FAST_ELEMENTS: |
case FAST_HOLEY_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
- case SLOPPY_ARGUMENTS_ELEMENTS: |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
case EXTERNAL_##TYPE##_ELEMENTS: \ |
case TYPE##_ELEMENTS: |
@@ -12300,30 +12298,6 @@ void JSObject::EnsureCanContainElements(Handle<JSObject> object, |
} |
-bool JSObject::HasFastArgumentsElements() { |
- Heap* heap = GetHeap(); |
- if (!elements()->IsFixedArray()) return false; |
- FixedArray* elements = FixedArray::cast(this->elements()); |
- if (elements->map() != heap->sloppy_arguments_elements_map()) { |
- return false; |
- } |
- FixedArray* arguments = FixedArray::cast(elements->get(1)); |
- return !arguments->IsDictionary(); |
-} |
- |
- |
-bool JSObject::HasDictionaryArgumentsElements() { |
- Heap* heap = GetHeap(); |
- if (!elements()->IsFixedArray()) return false; |
- FixedArray* elements = FixedArray::cast(this->elements()); |
- if (elements->map() != heap->sloppy_arguments_elements_map()) { |
- return false; |
- } |
- FixedArray* arguments = FixedArray::cast(elements->get(1)); |
- return arguments->IsDictionary(); |
-} |
- |
- |
ElementsAccessor* JSObject::GetElementsAccessor() { |
return ElementsAccessor::ForKind(GetElementsKind()); |
} |
@@ -12390,7 +12364,9 @@ bool JSObject::WouldConvertToSlowElements(uint32_t index) { |
static ElementsKind BestFittingFastElementsKind(JSObject* object) { |
- if (object->HasSloppyArgumentsElements()) return SLOPPY_ARGUMENTS_ELEMENTS; |
+ if (object->HasSloppyArgumentsElements()) { |
+ return FAST_SLOPPY_ARGUMENTS_ELEMENTS; |
+ } |
DCHECK(object->HasDictionaryElements()); |
SeededNumberDictionary* dictionary = object->element_dictionary(); |
ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
@@ -12457,49 +12433,34 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, |
ElementsKind kind = object->GetElementsKind(); |
FixedArrayBase* elements = object->elements(); |
+ ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; |
if (IsSloppyArgumentsElements(kind)) { |
elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); |
+ dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; |
} |
if (attributes != NONE) { |
- kind = DICTIONARY_ELEMENTS; |
+ kind = dictionary_kind; |
} else if (elements->IsSeededNumberDictionary()) { |
kind = ShouldConvertToFastElements(*object, |
SeededNumberDictionary::cast(elements), |
index, &new_capacity) |
? BestFittingFastElementsKind(*object) |
- : DICTIONARY_ELEMENTS; // Overwrite in case of arguments. |
+ : dictionary_kind; // Overwrite in case of arguments. |
} else if (ShouldConvertToSlowElements( |
*object, static_cast<uint32_t>(elements->length()), index, |
&new_capacity)) { |
- kind = DICTIONARY_ELEMENTS; |
+ kind = dictionary_kind; |
} |
- if (kind == DICTIONARY_ELEMENTS && object->HasSloppyArgumentsElements()) { |
- // TODO(verwaest): Distinguish fast/slow sloppy elements in ElementsKind. |
- Handle<SeededNumberDictionary> dictionary = |
- elements->IsSeededNumberDictionary() |
- ? handle(SeededNumberDictionary::cast(elements)) |
- : NormalizeElements(object); |
- PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
- Handle<SeededNumberDictionary> new_dictionary = |
- SeededNumberDictionary::AddNumberEntry(dictionary, index, value, |
- details); |
- if (attributes != NONE) new_dictionary->set_requires_slow_elements(); |
- if (*dictionary != *new_dictionary) { |
- FixedArray::cast(object->elements())->set(1, *new_dictionary); |
- } |
- } else { |
- ElementsKind to = value->OptimalElementsKind(); |
- if (IsHoleyElementsKind(kind) || !object->IsJSArray() || |
- index > old_length) { |
- to = GetHoleyElementsKind(to); |
- kind = GetHoleyElementsKind(kind); |
- } |
- to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind; |
- ElementsAccessor* accessor = ElementsAccessor::ForKind(to); |
- accessor->Add(object, index, value, attributes, new_capacity); |
+ ElementsKind to = value->OptimalElementsKind(); |
+ if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { |
+ to = GetHoleyElementsKind(to); |
+ kind = GetHoleyElementsKind(kind); |
} |
+ to = IsMoreGeneralElementsKindTransition(kind, to) ? to : kind; |
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(to); |
+ accessor->Add(object, index, value, attributes, new_capacity); |
uint32_t new_length = old_length; |
Handle<Object> new_length_handle; |
@@ -12758,7 +12719,8 @@ void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); |
FixedArray* backing_store = NULL; |
switch (GetElementsKind()) { |
- case SLOPPY_ARGUMENTS_ELEMENTS: |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
backing_store_base = |
FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
backing_store = FixedArray::cast(backing_store_base); |
@@ -13255,7 +13217,8 @@ int JSObject::GetOwnElementKeys(FixedArray* storage, |
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); |
break; |
} |
- case SLOPPY_ARGUMENTS_ELEMENTS: { |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { |
FixedArray* parameter_map = FixedArray::cast(elements()); |
int mapped_length = parameter_map->length() - 2; |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |