| 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)); | 
|  |