From d8c7a03a3a0ad2491b43315f1bb28e9211749097 Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 17 Jul 2012 13:50:19 +0000 Subject: [PATCH] Grouping all map creation code. - Now tunnel all descriptor changes through methods on the map - Renamed CopyDropTransitions to regular Copy since we always "drop transitions" on copy anyway. - Merged and moved elements transition map creation. Review URL: https://chromiumcodereview.appspot.com/10780031 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12105 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/api.cc | 2 +- src/bootstrapper.cc | 11 +- src/factory.cc | 6 +- src/factory.h | 3 +- src/handles.cc | 2 +- src/heap.cc | 26 ++-- src/objects-inl.h | 8 +- src/objects.cc | 373 +++++++++++++++++++++++----------------------------- src/objects.h | 38 ++++-- src/runtime.cc | 45 +++---- 10 files changed, 237 insertions(+), 277 deletions(-) diff --git a/src/api.cc b/src/api.cc index 72dfc64..6abe3c6 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3234,7 +3234,7 @@ void v8::Object::TurnOnAccessCheck() { i::Deoptimizer::DeoptimizeGlobalObject(*obj); i::Handle new_map = - isolate->factory()->CopyMapDropTransitions(i::Handle(obj->map())); + isolate->factory()->CopyMap(i::Handle(obj->map())); new_map->set_is_access_check_needed(true); obj->set_map(*new_map); } diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 3d54187..726670a 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -317,7 +317,7 @@ static void SetObjectPrototype(Handle object, Handle proto) { // object.__proto__ = proto; Factory* factory = object->GetIsolate()->factory(); Handle old_to_map = Handle(object->map()); - Handle new_to_map = factory->CopyMapDropTransitions(old_to_map); + Handle new_to_map = factory->CopyMap(old_to_map); new_to_map->set_prototype(*proto); object->set_map(*new_to_map); } @@ -999,7 +999,7 @@ bool Genesis::InitializeGlobal(Handle inner_global, initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map)); // RegExp prototype object is itself a RegExp. - Handle proto_map = factory->CopyMapDropTransitions(initial_map); + Handle proto_map = factory->CopyMap(initial_map); proto_map->set_prototype(global_context()->initial_object_prototype()); Handle proto = factory->NewJSObjectFromMap(proto_map); proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, @@ -1101,7 +1101,7 @@ bool Genesis::InitializeGlobal(Handle inner_global, elements->set(1, *array); Handle old_map(global_context()->arguments_boilerplate()->map()); - Handle new_map = factory->CopyMapDropTransitions(old_map); + Handle new_map = factory->CopyMap(old_map); new_map->set_pre_allocated_property_fields(2); Handle result = factory->NewJSObjectFromMap(new_map); // Set elements kind after allocating the object because @@ -1630,8 +1630,7 @@ bool Genesis::InstallNatives() { // through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT // transition easy to trap. Moreover, they rarely are smi-only. MaybeObject* maybe_map = - array_function->initial_map()->CopyDropTransitions( - DescriptorArray::MAY_BE_SHARED); + array_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED); Map* new_map; if (!maybe_map->To(&new_map)) return false; new_map->set_elements_kind(FAST_HOLEY_ELEMENTS); @@ -2247,7 +2246,7 @@ void Genesis::TransferObject(Handle from, Handle to) { // Transfer the prototype (new map is needed). Handle old_to_map = Handle(to->map()); - Handle new_to_map = factory->CopyMapDropTransitions(old_to_map); + Handle new_to_map = factory->CopyMap(old_to_map); new_to_map->set_prototype(from->map()->prototype()); to->set_map(*new_to_map); } diff --git a/src/factory.cc b/src/factory.cc index 679bb44..8340b46 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -496,10 +496,8 @@ Handle Factory::CopyMap(Handle src, } -Handle Factory::CopyMapDropTransitions(Handle src) { - CALL_HEAP_FUNCTION(isolate(), - src->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED), - Map); +Handle Factory::CopyMap(Handle src) { + CALL_HEAP_FUNCTION(isolate(), src->Copy(DescriptorArray::MAY_BE_SHARED), Map); } diff --git a/src/factory.h b/src/factory.h index f170700..3b7ead5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -227,8 +227,7 @@ class Factory { // Copy the map adding more inobject properties if possible without // overflowing the instance size. Handle CopyMap(Handle map, int extra_inobject_props); - - Handle CopyMapDropTransitions(Handle map); + Handle CopyMap(Handle map); Handle GetElementsTransitionMap(Handle object, ElementsKind elements_kind); diff --git a/src/handles.cc b/src/handles.cc index e98e843..7ccfe08 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -165,7 +165,7 @@ void SetExpectedNofProperties(Handle func, int nof) { func->shared()->set_expected_nof_properties(nof); if (func->has_initial_map()) { Handle new_initial_map = - func->GetIsolate()->factory()->CopyMapDropTransitions( + func->GetIsolate()->factory()->CopyMap( Handle(func->initial_map())); new_initial_map->set_unused_property_fields(nof); func->set_initial_map(*new_initial_map); diff --git a/src/heap.cc b/src/heap.cc index f1cd6a6..c3bbe12 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3709,23 +3709,21 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) { // constructors. Map* new_map; ASSERT(object_function->has_initial_map()); - { MaybeObject* maybe_map = - object_function->initial_map()->CopyDropTransitions( - DescriptorArray::MAY_BE_SHARED); - if (!maybe_map->To(&new_map)) return maybe_map; - } + MaybeObject* maybe_map = + object_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_map->To(&new_map)) return maybe_map; + Object* prototype; - { MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map); - if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; - } + MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map); + if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; + // When creating the prototype for the function we must set its // constructor to the function. - Object* result; - { MaybeObject* maybe_result = - JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes( - constructor_symbol(), function, DONT_ENUM); - if (!maybe_result->ToObject(&result)) return maybe_result; - } + MaybeObject* maybe_failure = + JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes( + constructor_symbol(), function, DONT_ENUM); + if (maybe_failure->IsFailure()) return maybe_failure; + return prototype; } diff --git a/src/objects-inl.h b/src/objects-inl.h index 6dd2a99..feca271 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3653,12 +3653,12 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) || (value->IsMap() && GetBackPointer()->IsUndefined())); Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset); - if (object->IsMap()) { + if (object->IsDescriptorArray()) { + DescriptorArray::cast(object)->set_back_pointer_storage(value); + } else { WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value); CONDITIONAL_WRITE_BARRIER( GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode); - } else { - DescriptorArray::cast(object)->set_back_pointer_storage(value); } } @@ -4301,7 +4301,7 @@ MaybeObject* JSFunction::set_initial_map_and_cache_transitions( Map* new_map; ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); MaybeObject* maybe_new_map = - current_map->CreateNextElementsTransition(next_kind); + current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION); if (!maybe_new_map->To(&new_map)) return maybe_new_map; maps->set(next_kind, new_map); current_map = new_map; diff --git a/src/objects.cc b/src/objects.cc index 05f23d7..4f99d59 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -513,9 +513,9 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) { // from the DontDelete cell without checking if it contains // the hole value. Map* new_map; - { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - } + MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + set_map(new_map); } JSGlobalPropertyCell* cell = @@ -1544,57 +1544,42 @@ MaybeObject* JSObject::AddFastProperty(String* name, return AddSlowProperty(name, value, attributes); } - DescriptorArray* old_descriptors = map()->instance_descriptors(); // Compute the new index for new field. int index = map()->NextFreePropertyIndex(); // Allocate new instance descriptors with (name, index) added FieldDescriptor new_field(name, index, attributes, 0); - DescriptorArray* new_descriptors; - MaybeObject* maybe_new_descriptors = old_descriptors->CopyAdd(&new_field); - if (!maybe_new_descriptors->To(&new_descriptors)) { - return maybe_new_descriptors; - } - - // Only allow map transition if the object isn't the global object. - bool allow_map_transition = isolate->empty_object_map() != map(); - ASSERT(index < map()->inobject_properties() || (index - map()->inobject_properties()) < properties()->length() || map()->unused_property_fields() == 0); - // Allocate a new map for the object. - Map* new_map; - MaybeObject* maybe_r = map()->CopyReplaceDescriptors(new_descriptors); - if (!maybe_r->To(&new_map)) return maybe_r; - - TransitionArray* new_transitions = NULL; - if (allow_map_transition) { - MaybeObject* maybe_transitions = map()->AddTransition(name, new_map); - if (!maybe_transitions->To(&new_transitions)) return maybe_transitions; - } + FixedArray* values = NULL; if (map()->unused_property_fields() == 0) { // Make room for the new value - FixedArray* values; MaybeObject* maybe_values = properties()->CopySize(properties()->length() + kFieldsAdded); if (!maybe_values->To(&values)) return maybe_values; + } + // Only allow map transition if the object isn't the global object. + TransitionFlag flag = isolate->empty_object_map() != map() + ? INSERT_TRANSITION + : OMIT_TRANSITION; + + Map* new_map; + MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + + if (map()->unused_property_fields() == 0) { + ASSERT(values != NULL); set_properties(values); new_map->set_unused_property_fields(kFieldsAdded - 1); } else { new_map->set_unused_property_fields(map()->unused_property_fields() - 1); } - // Apply all changes at once, so they are atomic. - if (allow_map_transition) { - MaybeObject* transition_added = map()->set_transitions(new_transitions); - if (transition_added->IsFailure()) return transition_added; - } - - new_map->SetBackPointer(map()); set_map(new_map); return FastPropertyAtPut(index, value); } @@ -1607,48 +1592,24 @@ MaybeObject* JSObject::AddConstantFunctionProperty( // Allocate new instance descriptors with (name, function) added ConstantFunctionDescriptor d(name, function, attributes, 0); - DescriptorArray* new_descriptors; - MaybeObject* maybe_new_descriptors = - map()->instance_descriptors()->CopyAdd(&d); - if (!maybe_new_descriptors->To(&new_descriptors)) { - return maybe_new_descriptors; - } + Heap* heap = GetHeap(); + TransitionFlag flag = + // Do not add transitions to the empty object map (map of "new Object()"), + // nor to global objects. + (map() == heap->isolate()->empty_object_map() || IsGlobalObject() || + // Don't add transitions to special properties with non-trivial + // attributes. + // TODO(verwaest): Once we support attribute changes, these transitions + // should be kept as well. + attributes != NONE) + ? OMIT_TRANSITION + : INSERT_TRANSITION; - // Allocate a new map for the object. Map* new_map; - MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors); + MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag); if (!maybe_new_map->To(&new_map)) return maybe_new_map; - Map* old_map = map(); - - Heap* heap = GetHeap(); - // Do not add transitions to the empty object map (map of "new Object()"), nor - // to global objects. - if (old_map == heap->isolate()->empty_object_map() || IsGlobalObject()) { - set_map(new_map); - return function; - } - - // Don't add transitions to special properties with non-trivial attributes. - // TODO(verwaest): Once we support attribute changes, these transitions should - // be kept as well. - if (attributes != NONE) { - set_map(new_map); - return function; - } - - // Add a constant transition to the old map, so future assignments to this - // property on other objects of the same type will create a normal field, not - // a constant function. - TransitionArray* transitions; - MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map); - if (!maybe_transitions->To(&transitions)) return maybe_transitions; - - MaybeObject* transition_added = old_map->set_transitions(transitions); - if (transition_added->IsFailure()) return transition_added; - set_map(new_map); - new_map->SetBackPointer(old_map); return function; } @@ -1819,15 +1780,10 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name, int index = map()->NextFreePropertyIndex(); FieldDescriptor new_field(name, index, attributes, 0); - // Make a new DescriptorArray replacing an entry with FieldDescriptor. - DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = - map()->instance_descriptors()->CopyInsert(&new_field); - if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; - // Make a new map for the object. Map* new_map; - MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors); + MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, + OMIT_TRANSITION); if (!maybe_new_map->To(&new_map)) return maybe_new_map; // Make new properties array if necessary. @@ -2220,33 +2176,6 @@ Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { } -MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) { - ASSERT(!HasElementsTransition() || - ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || - IsExternalArrayElementsKind( - elements_transition_map()->elements_kind())) && - (next_kind == DICTIONARY_ELEMENTS || - IsExternalArrayElementsKind(next_kind)))); - ASSERT(!IsFastElementsKind(next_kind) || - IsMoreGeneralElementsKindTransition(elements_kind(), next_kind)); - ASSERT(next_kind != elements_kind()); - - Map* next_map; - { MaybeObject* maybe_next_map = - this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED); - if (!maybe_next_map->To(&next_map)) return maybe_next_map; - } - - { MaybeObject* added_elements = this->set_elements_transition_map(next_map); - if (added_elements->IsFailure()) return added_elements; - } - - next_map->set_elements_kind(next_kind); - next_map->SetBackPointer(this); - return next_map; -} - - static MaybeObject* AddMissingElementsTransitions(Map* map, ElementsKind to_kind) { ASSERT(IsFastElementsKind(map->elements_kind())); @@ -2260,18 +2189,18 @@ static MaybeObject* AddMissingElementsTransitions(Map* map, Map* current_map = map; for (; index < to_index; ++index) { - ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1); - MaybeObject* maybe_next_map = - current_map->CreateNextElementsTransition(next_kind); - if (!maybe_next_map->To(¤t_map)) return maybe_next_map; + ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1); + MaybeObject* maybe_next_map = + current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION); + if (!maybe_next_map->To(¤t_map)) return maybe_next_map; } // In case we are exiting the fast elements kind system, just add the map in // the end. if (!IsFastElementsKind(to_kind)) { - MaybeObject* maybe_next_map = - current_map->CreateNextElementsTransition(to_kind); - if (!maybe_next_map->To(¤t_map)) return maybe_next_map; + MaybeObject* maybe_next_map = + current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION); + if (!maybe_next_map->To(¤t_map)) return maybe_next_map; } ASSERT(current_map->elements_kind() == to_kind); @@ -2312,13 +2241,7 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { } if (!allow_store_transition) { - // Create a new free-floating map only if we are not allowed to store it. - Map* new_map = NULL; - MaybeObject* maybe_new_map = - start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - new_map->set_elements_kind(to_kind); - return new_map; + return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION); } Map* closest_map = FindClosestElementsTransition(start_map, to_kind); @@ -4062,10 +3985,9 @@ MaybeObject* JSObject::PreventExtensions() { // Do a map transition, other objects with this map may still // be extensible. Map* new_map; - { MaybeObject* maybe = - map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe->To(&new_map)) return maybe; - } + MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe->To(&new_map)) return maybe; + new_map->set_is_extensible(false); set_map(new_map); ASSERT(!map()->is_extensible()); @@ -4529,40 +4451,6 @@ static MaybeObject* TryAccessorTransition(JSObject* self, } -static MaybeObject* NewCallbackTransition(JSObject* obj, - String* name, - AccessorComponent component, - Object* accessor, - PropertyAttributes attributes, - AccessorPair* new_accessors) { - // step 1: create a copy of the descriptors, incl. the new getter/setter pair - Map* old_map = obj->map(); - CallbacksDescriptor new_accessors_desc(name, new_accessors, attributes); - DescriptorArray* descriptors; - MaybeObject* maybe_descriptors = - old_map->instance_descriptors()->CopyInsert(&new_accessors_desc); - if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; - - // step 2: create a new map with the new descriptors - Map* new_map; - MaybeObject* maybe_new_map = old_map->CopyReplaceDescriptors(descriptors); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - - // step 3: add a new transition to the new map - TransitionArray* transitions; - MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map); - if (!maybe_transitions->To(&transitions)) return maybe_transitions; - - // step 4: everything went well so far, so we make our changes visible - MaybeObject* transition_added = old_map->set_transitions(transitions); - if (transition_added->IsFailure()) return transition_added; - - new_map->SetBackPointer(old_map); - obj->set_map(new_map); - return obj; -} - - MaybeObject* JSObject::DefineFastAccessor(String* name, AccessorComponent component, Object* accessor, @@ -4613,12 +4501,15 @@ MaybeObject* JSObject::DefineFastAccessor(String* name, if (!maybe_accessors->To(&accessors)) return maybe_accessors; accessors->set(component, accessor); - return NewCallbackTransition(this, - name, - component, - accessor, - attributes, - accessors); + CallbacksDescriptor new_accessors_desc(name, accessors, attributes); + + Map* new_map; + MaybeObject* maybe_new_map = + map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + + set_map(new_map); + return this; } @@ -4826,9 +4717,8 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, MaybeObject* Map::CopyDropDescriptors() { Map* result; - { MaybeObject* maybe_result = RawCopy(instance_size()); - if (!maybe_result->To(&result)) return maybe_result; - } + MaybeObject* maybe_result = RawCopy(instance_size()); + if (!maybe_result->To(&result)) return maybe_result; // Please note instance_type and instance_size are set when allocated. result->set_inobject_properties(inobject_properties()); @@ -4841,16 +4731,58 @@ MaybeObject* Map::CopyDropDescriptors() { } -MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors) { +MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, + String* name, + TransitionFlag flag) { Map* result; - { MaybeObject* maybe_result = CopyDropDescriptors(); - if (!maybe_result->To(&result)) return maybe_result; - } + MaybeObject* maybe_result = CopyDropDescriptors(); + if (!maybe_result->To(&result)) return maybe_result; + result->set_instance_descriptors(descriptors); + + if (flag == INSERT_TRANSITION) { + TransitionArray* transitions; + MaybeObject* maybe_transitions = AddTransition(name, result); + if (!maybe_transitions->To(&transitions)) return maybe_transitions; + + MaybeObject* maybe_set = set_transitions(transitions); + if (maybe_set->IsFailure()) return maybe_set; + + result->SetBackPointer(this); + } + return result; } +MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { + // Create a new free-floating map only if we are not allowed to store it. + Map* new_map = NULL; + MaybeObject* maybe_new_map = Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + new_map->set_elements_kind(kind); + + if (flag == INSERT_TRANSITION) { + ASSERT(!HasElementsTransition() || + ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || + IsExternalArrayElementsKind( + elements_transition_map()->elements_kind())) && + (kind == DICTIONARY_ELEMENTS || + IsExternalArrayElementsKind(kind)))); + ASSERT(!IsFastElementsKind(kind) || + IsMoreGeneralElementsKindTransition(elements_kind(), kind)); + ASSERT(kind != elements_kind()); + + MaybeObject* added_elements = set_elements_transition_map(new_map); + if (added_elements->IsFailure()) return added_elements; + + new_map->SetBackPointer(this); + } + + return new_map; +} + + MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); @@ -4859,21 +4791,67 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { ASSERT(constructor()->IsJSFunction()); JSFunction* ctor = JSFunction::cast(constructor()); DescriptorArray* descriptors; - { MaybeObject* maybe_descriptors = - ctor->initial_map()->instance_descriptors()->Copy( - DescriptorArray::MAY_BE_SHARED); - if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; - } - return CopyReplaceDescriptors(descriptors); + MaybeObject* maybe_descriptors = + ctor->initial_map()->instance_descriptors()->Copy( + DescriptorArray::MAY_BE_SHARED); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); } -MaybeObject* Map::CopyDropTransitions(DescriptorArray::SharedMode shared_mode) { +MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) { DescriptorArray* descriptors; - { MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode); - if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); +} + + +MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, + TransitionFlag flag) { + DescriptorArray* descriptors; + MaybeObject* maybe_descriptors = instance_descriptors()->CopyAdd(descriptor); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag); +} + + +MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, + TransitionFlag flag) { + DescriptorArray* old_descriptors = instance_descriptors(); + + // Ensure the key is a symbol. + MaybeObject* maybe_result = descriptor->KeyToSymbol(); + if (maybe_result->IsFailure()) return maybe_result; + + DescriptorArray* descriptors; + MaybeObject* maybe_descriptors; + + // We replace the key if it is already present. + int index = old_descriptors->SearchWithCache(descriptor->GetKey()); + if (index == DescriptorArray::kNotFound) { + maybe_descriptors = old_descriptors->CopyAdd(descriptor); + } else { + maybe_descriptors = old_descriptors->CopyReplace(descriptor, index); } - return CopyReplaceDescriptors(descriptors); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag); +} + + +MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, + int index, + TransitionFlag flag) { + DescriptorArray* descriptors; + MaybeObject* maybe_descriptors = + instance_descriptors()->CopyReplace(descriptor, index); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag); } @@ -4885,6 +4863,7 @@ void Map::UpdateCodeCache(Handle map, map->UpdateCodeCache(*name, *code)); } + MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache()); @@ -5738,18 +5717,6 @@ MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor, } -MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) { - // Ensure the key is a symbol. - MaybeObject* maybe_result = descriptor->KeyToSymbol(); - if (maybe_result->IsFailure()) return maybe_result; - - // We replace the key if it is already present. - int index = SearchWithCache(descriptor->GetKey()); - if (index == kNotFound) return CopyAdd(descriptor); - return CopyReplace(descriptor, index); -} - - MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) { // Ensure the key is a symbol. MaybeObject* maybe_result = descriptor->KeyToSymbol(); @@ -7466,11 +7433,10 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) { // replace it with a copy containing the new prototype. Map* new_map; MaybeObject* maybe_new_map = - initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); + initial_map()->Copy(DescriptorArray::MAY_BE_SHARED); if (!maybe_new_map->To(&new_map)) return maybe_new_map; new_map->set_prototype(value); - MaybeObject* maybe_object = - set_initial_map_and_cache_transitions(new_map); + MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map); if (maybe_object->IsFailure()) return maybe_object; } else { // Put the value in the initial map field until an initial map is @@ -7496,10 +7462,9 @@ MaybeObject* JSFunction::SetPrototype(Object* value) { // Remove map transitions because they point to maps with a // different prototype. Map* new_map; - { MaybeObject* maybe_new_map = - map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - } + MaybeObject* maybe_new_map = map()->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + Heap* heap = new_map->GetHeap(); set_map(new_map); new_map->set_constructor(value); @@ -8791,15 +8756,12 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, Map* new_map = map->GetPrototypeTransition(value); if (new_map == NULL) { - { MaybeObject* maybe_new_map = - map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - } + MaybeObject* maybe_new_map = map->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; - { MaybeObject* maybe_new_cache = - map->PutPrototypeTransition(value, new_map); - if (maybe_new_cache->IsFailure()) return maybe_new_cache; - } + MaybeObject* maybe_new_cache = + map->PutPrototypeTransition(value, new_map); + if (maybe_new_cache->IsFailure()) return maybe_new_cache; new_map->set_prototype(value); } @@ -12576,7 +12538,8 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( descriptors->Sort(witness); // Allocate new map. Map* new_map; - MaybeObject* maybe_new_map = obj->map()->CopyReplaceDescriptors(descriptors); + MaybeObject* maybe_new_map = + obj->map()->CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); if (!maybe_new_map->To(&new_map)) return maybe_new_map; new_map->set_unused_property_fields(unused_property_fields); diff --git a/src/objects.h b/src/objects.h index 4f06283..6349c02 100644 --- a/src/objects.h +++ b/src/objects.h @@ -178,6 +178,13 @@ enum SearchMode { }; +// Indicates whether transitions can be added to a source map or not. +enum TransitionFlag { + INSERT_TRANSITION, + OMIT_TRANSITION +}; + + // Instance size sentinel for objects of variable size. const int kVariableSizeSentinel = 0; @@ -2555,14 +2562,13 @@ class DescriptorArray: public FixedArray { int src_index, const WhitenessWitness&); - // Copy the descriptor array, insert a new descriptor and optionally - // remove map transitions. If the descriptor is already present, it is - // replaced. If a replaced descriptor is a real property (not a transition - // or null), its enumeration index is kept as is. - // If adding a real property, map transitions must be removed. If adding - // a transition, they must not be removed. All null descriptors are removed. - MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor); + // Copy the descriptor array, inserting new descriptor. Its enumeration index + // is automatically set to the size of the descriptor array to which it was + // added first. MUST_USE_RESULT MaybeObject* CopyAdd(Descriptor* descriptor); + + // Copy the descriptor array, replacing a descriptor. Its enumeration index is + // kept. MUST_USE_RESULT MaybeObject* CopyReplace(Descriptor* descriptor, int insertion_index); @@ -4917,15 +4923,23 @@ class Map: public HeapObject { MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors(); MUST_USE_RESULT MaybeObject* CopyDropDescriptors(); MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors( - DescriptorArray* descriptors); + DescriptorArray* descriptors, String* name, TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor(Descriptor* descriptor, + int index, + TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind, + TransitionFlag flag); MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode, NormalizedMapSharingMode sharing); // Returns a copy of the map, with all transitions dropped from the // instance descriptors. - MUST_USE_RESULT MaybeObject* CopyDropTransitions( - DescriptorArray::SharedMode shared_mode); + MUST_USE_RESULT MaybeObject* Copy(DescriptorArray::SharedMode shared_mode); // Returns the property index for name (only valid for FAST MODE). int PropertyIndexFor(String* name); @@ -4984,10 +4998,6 @@ class Map: public HeapObject { // allowed. Map* LookupElementsTransitionMap(ElementsKind elements_kind); - // Adds a new transitions for changing the elements kind to |elements_kind|. - MUST_USE_RESULT MaybeObject* CreateNextElementsTransition( - ElementsKind elements_kind); - // Returns the transitioned map for this map with the most generic // elements_kind that's found in |candidates|, or null handle if no match is // found at all. diff --git a/src/runtime.cc b/src/runtime.cc index f672534..54bb61a 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1293,14 +1293,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) { bool needs_access_checks = old_map->is_access_check_needed(); if (needs_access_checks) { // Copy map so it won't interfere constructor's initial map. - Object* new_map; - { MaybeObject* maybe_new_map = - old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; - } + Map* new_map; + MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; - Map::cast(new_map)->set_is_access_check_needed(false); - object->set_map(Map::cast(new_map)); + new_map->set_is_access_check_needed(false); + object->set_map(new_map); } return isolate->heap()->ToBoolean(needs_access_checks); } @@ -1312,14 +1310,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) { Map* old_map = object->map(); if (!old_map->is_access_check_needed()) { // Copy map so it won't interfere constructor's initial map. - Object* new_map; - { MaybeObject* maybe_new_map = - old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); - if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; - } + Map* new_map; + MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; - Map::cast(new_map)->set_is_access_check_needed(true); - object->set_map(Map::cast(new_map)); + new_map->set_is_access_check_needed(true); + object->set_map(new_map); } return isolate->heap()->undefined_value(); } @@ -2172,25 +2168,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { if (function->HasFastProperties()) { // Construct a new field descriptor with updated attributes. DescriptorArray* instance_desc = function->map()->instance_descriptors(); + int index = instance_desc->Search(name); ASSERT(index != DescriptorArray::kNotFound); PropertyDetails details = instance_desc->GetDetails(index); + CallbacksDescriptor new_desc(name, instance_desc->GetValue(index), static_cast(details.attributes() | READ_ONLY), details.index()); - // Construct a new field descriptors array containing the new descriptor. - DescriptorArray* new_descriptors; - { MaybeObject* maybe_descriptors = - instance_desc->CopyReplace(&new_desc, index); - if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; - } + // Create a new map featuring the new field descriptors array. Map* new_map; - { MaybeObject* maybe_map = - function->map()->CopyReplaceDescriptors(new_descriptors); - if (!maybe_map->To(&new_map)) return maybe_map; - } + MaybeObject* maybe_map = + function->map()->CopyReplaceDescriptor( + &new_desc, index, OMIT_TRANSITION); + if (!maybe_map->To(&new_map)) return maybe_map; + function->set_map(new_map); } else { // Dictionary properties. // Directly manipulate the property details. @@ -7829,8 +7823,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { isolate->heap()->non_strict_arguments_elements_map()); Handle old_map(result->map()); - Handle new_map = - isolate->factory()->CopyMapDropTransitions(old_map); + Handle new_map = isolate->factory()->CopyMap(old_map); new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); result->set_map(*new_map); -- 2.7.4