| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 4c72aa9d6c5e60723e931762a8b20804fd6e30b2..e6c556ddeca0a17cd7a4d14964d6caf63574984c 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -3559,51 +3559,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 +3606,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 +3621,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 +3662,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 +3688,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));
|
| + }
|
| }
|
| }
|
| }
|
| @@ -4817,15 +4812,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 +4834,7 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements(
|
| }
|
| #endif
|
|
|
| - DCHECK(object->HasDictionaryElements() ||
|
| - object->HasDictionaryArgumentsElements());
|
| + DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
|
| return dictionary;
|
| }
|
|
|
| @@ -5337,7 +5331,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 +5430,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 +5858,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 +6276,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 +6343,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 +7125,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 +12296,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 +12362,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 +12431,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 +12717,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 +13215,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));
|
|
|