diff --git a/src/api.cc b/src/api.cc index 5c8a3142ae..52d75aad3b 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3310,22 +3310,12 @@ void PrepareExternalArrayElements(i::Handle object, i::Handle array = isolate->factory()->NewExternalArray(length, array_type, data); - // If the object already has external elements, create a new, unique - // map if the element type is now changing, because assumptions about - // generated code based on the receiver's map will be invalid. - i::Handle elements(object->elements()); - bool cant_reuse_map = - elements->map()->IsUndefined() || - !elements->map()->has_external_array_elements() || - elements->map() != isolate->heap()->MapForExternalArrayType(array_type); - if (cant_reuse_map) { - i::Handle external_array_map = - isolate->factory()->GetElementsTransitionMap( - i::Handle(object->map()), - GetElementsKindFromExternalArrayType(array_type), - object->HasFastProperties()); - object->set_map(*external_array_map); - } + i::Handle external_array_map = + isolate->factory()->GetElementsTransitionMap( + object, + GetElementsKindFromExternalArrayType(array_type)); + + object->set_map(*external_array_map); object->set_elements(*array); } diff --git a/src/factory.cc b/src/factory.cc index 97289266e3..7f34004f4f 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -455,23 +455,11 @@ Handle Factory::CopyMapDropTransitions(Handle src) { } -Handle Factory::GetFastElementsMap(Handle src) { - CALL_HEAP_FUNCTION(isolate(), src->GetFastElementsMap(), Map); -} - - -Handle Factory::GetSlowElementsMap(Handle src) { - CALL_HEAP_FUNCTION(isolate(), src->GetSlowElementsMap(), Map); -} - - Handle Factory::GetElementsTransitionMap( - Handle src, - ElementsKind elements_kind, - bool safe_to_add_transition) { + Handle src, + ElementsKind elements_kind) { CALL_HEAP_FUNCTION(isolate(), - src->GetElementsTransitionMap(elements_kind, - safe_to_add_transition), + src->GetElementsTransitionMap(elements_kind), Map); } diff --git a/src/factory.h b/src/factory.h index 71ae750b38..510b00abff 100644 --- a/src/factory.h +++ b/src/factory.h @@ -215,13 +215,8 @@ class Factory { Handle CopyMapDropTransitions(Handle map); - Handle GetFastElementsMap(Handle map); - - Handle GetSlowElementsMap(Handle map); - - Handle GetElementsTransitionMap(Handle map, - ElementsKind elements_kind, - bool safe_to_add_transition); + Handle GetElementsTransitionMap(Handle object, + ElementsKind elements_kind); Handle CopyFixedArray(Handle array); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 4cbcafebe7..30b395ee63 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -3951,14 +3951,14 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, bool is_store) { ASSERT(expr->IsMonomorphic()); Handle map = expr->GetMonomorphicReceiverType(); + AddInstruction(new(zone()) HCheckNonSmi(object)); + HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); if (!map->has_fast_elements() && !map->has_fast_double_elements() && !map->has_external_array_elements()) { return is_store ? BuildStoreKeyedGeneric(object, key, val) : BuildLoadKeyedGeneric(object, key); } - AddInstruction(new(zone()) HCheckNonSmi(object)); - HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); bool fast_double_elements = map->has_fast_double_elements(); if (is_store && map->has_fast_elements()) { diff --git a/src/objects-inl.h b/src/objects-inl.h index b8f3bd5422..295b8597d0 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1428,7 +1428,7 @@ void JSObject::initialize_elements() { MaybeObject* JSObject::ResetElements() { Object* obj; - { MaybeObject* maybe_obj = map()->GetFastElementsMap(); + { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } set_map(Map::cast(obj)); @@ -3242,45 +3242,6 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) { } -MaybeObject* Map::GetFastElementsMap() { - if (has_fast_elements()) return this; - Object* obj; - { MaybeObject* maybe_obj = CopyDropTransitions(); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - Map* new_map = Map::cast(obj); - new_map->set_elements_kind(FAST_ELEMENTS); - isolate()->counters()->map_to_fast_elements()->Increment(); - return new_map; -} - - -MaybeObject* Map::GetFastDoubleElementsMap() { - if (has_fast_double_elements()) return this; - Object* obj; - { MaybeObject* maybe_obj = CopyDropTransitions(); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - Map* new_map = Map::cast(obj); - new_map->set_elements_kind(FAST_DOUBLE_ELEMENTS); - isolate()->counters()->map_to_fast_double_elements()->Increment(); - return new_map; -} - - -MaybeObject* Map::GetSlowElementsMap() { - if (!has_fast_elements() && !has_fast_double_elements()) return this; - Object* obj; - { MaybeObject* maybe_obj = CopyDropTransitions(); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - Map* new_map = Map::cast(obj); - new_map->set_elements_kind(DICTIONARY_ELEMENTS); - isolate()->counters()->map_to_slow_elements()->Increment(); - return new_map; -} - - DescriptorArray* Map::instance_descriptors() { Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset); if (object->IsSmi()) { diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 0398572f90..d7fd5d6b06 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -256,6 +256,9 @@ void JSObject::PrintProperties(FILE* out) { descs->GetCallbacksObject(i)->ShortPrint(out); PrintF(out, " (callback)\n"); break; + case ELEMENTS_TRANSITION: + PrintF(out, " (elements transition)\n"); + break; case MAP_TRANSITION: PrintF(out, " (map transition)\n"); break; diff --git a/src/objects.cc b/src/objects.cc index 41b4fd4dbc..89d8c42e0a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1999,17 +1999,32 @@ void Map::LookupInDescriptors(JSObject* holder, } -MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind, - bool safe_to_add_transition) { - Heap* current_heap = heap(); - DescriptorArray* descriptors = instance_descriptors(); +MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) { + Heap* current_heap = GetHeap(); + Map* current_map = map(); + DescriptorArray* descriptors = current_map->instance_descriptors(); String* elements_transition_sentinel_name = current_heap->empty_symbol(); + if (current_map->elements_kind() == elements_kind) return current_map; + + // Only objects with FastProperties can have DescriptorArrays and can track + // element-related maps. Also don't add descriptors to maps that are shared. + bool safe_to_add_transition = HasFastProperties() && + !current_map->IsUndefined() && + !current_map->is_shared(); + + // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects + // with elements that switch back and forth between dictionary and fast + // element mode. + if ((current_map->elements_kind() == DICTIONARY_ELEMENTS && + elements_kind == FAST_ELEMENTS)) { + safe_to_add_transition = false; + } + if (safe_to_add_transition) { // It's only safe to manipulate the descriptor array if it would be // safe to add a transition. - ASSERT(!is_shared()); // no transitions can be added to shared maps. // Check if the elements transition already exists. DescriptorLookupCache* cache = current_heap->isolate()->descriptor_lookup_cache(); @@ -2037,13 +2052,12 @@ MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind, // No transition to an existing map for the given ElementsKind. Make a new // one. Object* obj; - { MaybeObject* maybe_map = CopyDropTransitions(); + { MaybeObject* maybe_map = current_map->CopyDropTransitions(); if (!maybe_map->ToObject(&obj)) return maybe_map; } Map* new_map = Map::cast(obj); new_map->set_elements_kind(elements_kind); - GetIsolate()->counters()->map_to_external_array_elements()->Increment(); // Only remember the map transition if the object's map is NOT equal to the // global object_function's map and there is not an already existing @@ -2065,7 +2079,7 @@ MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind, return maybe_new_descriptors; } descriptors = DescriptorArray::cast(new_descriptors); - set_instance_descriptors(descriptors); + current_map->set_instance_descriptors(descriptors); } return new_map; @@ -2973,7 +2987,7 @@ MaybeObject* JSObject::NormalizeElements() { // Set the new map first to satify the elements type assert in // set_elements(). Object* new_map; - MaybeObject* maybe = map()->GetSlowElementsMap(); + MaybeObject* maybe = GetElementsTransitionMap(DICTIONARY_ELEMENTS); if (!maybe->ToObject(&new_map)) return maybe; set_map(Map::cast(new_map)); set_elements(dictionary); @@ -7281,7 +7295,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, Map* new_map = NULL; if (elements()->map() != heap->non_strict_arguments_elements_map()) { Object* object; - MaybeObject* maybe = map()->GetFastElementsMap(); + MaybeObject* maybe = GetElementsTransitionMap(FAST_ELEMENTS); if (!maybe->ToObject(&object)) return maybe; new_map = Map::cast(object); } @@ -7384,7 +7398,8 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( } FixedDoubleArray* elems = FixedDoubleArray::cast(obj); - { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap(); + { MaybeObject* maybe_obj = + GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); @@ -10141,7 +10156,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { // Convert to fast elements. Object* obj; - { MaybeObject* maybe_obj = map()->GetFastElementsMap(); + { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); diff --git a/src/objects.h b/src/objects.h index d9c7a82276..7efddfaa8f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1860,6 +1860,11 @@ class JSObject: public JSReceiver { Object* value, PropertyAttributes attributes); + // Returns a new map with all transitions dropped from the object's current + // map and the ElementsKind set. + MUST_USE_RESULT MaybeObject* GetElementsTransitionMap( + ElementsKind elements_kind); + // Converts a descriptor of any other type to a real field, // backed by the properties array. Descriptors of visible // types, such as CONSTANT_FUNCTION, keep their enumeration order. @@ -4138,27 +4143,6 @@ class Map: public HeapObject { // instance descriptors. MUST_USE_RESULT MaybeObject* CopyDropTransitions(); - // Returns this map if it already has elements that are fast, otherwise - // returns a copy of the map, with all transitions dropped from the - // descriptors and the ElementsKind set to FAST_ELEMENTS. - MUST_USE_RESULT inline MaybeObject* GetFastElementsMap(); - - // Returns this map if it already has fast elements that are doubles, - // otherwise returns a copy of the map, with all transitions dropped from the - // descriptors and the ElementsKind set to FAST_DOUBLE_ELEMENTS. - MUST_USE_RESULT inline MaybeObject* GetFastDoubleElementsMap(); - - // Returns this map if already has dictionary elements, otherwise returns a - // copy of the map, with all transitions dropped from the descriptors and the - // ElementsKind set to DICTIONARY_ELEMENTS. - MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap(); - - // Returns a new map with all transitions dropped from the descriptors and the - // ElementsKind set. - MUST_USE_RESULT MaybeObject* GetElementsTransitionMap( - ElementsKind elements_kind, - bool safe_to_add_transition); - // Returns the property index for name (only valid for FAST MODE). int PropertyIndexFor(String* name); diff --git a/src/runtime.cc b/src/runtime.cc index 37f5b85ae6..7463952a9f 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -9414,9 +9414,11 @@ class ArrayConcatVisitor { isolate_->factory()->NewNumber(static_cast(index_offset_)); Handle map; if (fast_elements_) { - map = isolate_->factory()->GetFastElementsMap(Handle(array->map())); + map = isolate_->factory()->GetElementsTransitionMap(array, + FAST_ELEMENTS); } else { - map = isolate_->factory()->GetSlowElementsMap(Handle(array->map())); + map = isolate_->factory()->GetElementsTransitionMap(array, + DICTIONARY_ELEMENTS); } array->set_map(*map); array->set_length(*length); @@ -9907,15 +9909,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { CONVERT_CHECKED(JSArray, to, args[1]); FixedArrayBase* new_elements = from->elements(); MaybeObject* maybe_new_map; + ElementsKind elements_kind; if (new_elements->map() == isolate->heap()->fixed_array_map() || new_elements->map() == isolate->heap()->fixed_cow_array_map()) { - maybe_new_map = to->map()->GetFastElementsMap(); + elements_kind = FAST_ELEMENTS; } else if (new_elements->map() == isolate->heap()->fixed_double_array_map()) { - maybe_new_map = to->map()->GetFastDoubleElementsMap(); + elements_kind = FAST_DOUBLE_ELEMENTS; } else { - maybe_new_map = to->map()->GetSlowElementsMap(); + elements_kind = DICTIONARY_ELEMENTS; } + maybe_new_map = to->GetElementsTransitionMap(elements_kind); Object* new_map; if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; to->set_map(Map::cast(new_map)); diff --git a/src/v8-counters.h b/src/v8-counters.h index 2de830300d..5755989826 100644 --- a/src/v8-counters.h +++ b/src/v8-counters.h @@ -126,10 +126,6 @@ namespace internal { V8.GCCompactorCausedByWeakHandles) \ SC(gc_last_resort_from_js, V8.GCLastResortFromJS) \ SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \ - SC(map_to_fast_elements, V8.MapToFastElements) \ - SC(map_to_fast_double_elements, V8.MapToFastDoubleElements) \ - SC(map_to_slow_elements, V8.MapToSlowElements) \ - SC(map_to_external_array_elements, V8.MapToExternalArrayElements) \ /* How is the generic keyed-load stub used? */ \ SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \ SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \