From e53471dbaa21d6a063de63e0662bf5b0f707bbeb Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Wed, 31 Jul 2013 17:08:50 +0000 Subject: [PATCH] Remove elements transitions from the transition array. This is preparatory work for reordering the transition tree. Since elements transitions will be at the root of the transition tree, runtime access to them is slow since we have to walk the transition tree backwards first. Hence remove the optimization that promoted them to a special field, requiring a pointer (mostly NULL) in every non-simple transition array. R=titzer@chromium.org Review URL: https://chromiumcodereview.appspot.com/21228002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15993 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 2 +- src/heap.cc | 5 +++++ src/heap.h | 3 ++- src/objects-debug.cc | 4 ---- src/objects-inl.h | 15 ++++++++++----- src/objects.cc | 22 ++++------------------ src/transitions-inl.h | 24 +---------------------- src/transitions.cc | 5 ----- src/transitions.h | 44 +++++++++++++++++++++++-------------------- 9 files changed, 47 insertions(+), 77 deletions(-) diff --git a/include/v8.h b/include/v8.h index 6b18153833..a4eae968d3 100644 --- a/include/v8.h +++ b/include/v8.h @@ -5429,7 +5429,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 134; + static const int kEmptyStringRootIndex = 135; static const int kNodeClassIdOffset = 1 * kApiPointerSize; static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3; diff --git a/src/heap.cc b/src/heap.cc index 777661570a..c2a2707602 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3202,6 +3202,11 @@ bool Heap::CreateInitialObjects() { } set_frozen_symbol(Symbol::cast(obj)); + { MaybeObject* maybe_obj = AllocateSymbol(); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_elements_transition_symbol(Symbol::cast(obj)); + { MaybeObject* maybe_obj = SeededNumberDictionary::Allocate(this, 0, TENURED); if (!maybe_obj->ToObject(&obj)) return false; } diff --git a/src/heap.h b/src/heap.h index fbe0531014..de6f55bfaf 100644 --- a/src/heap.h +++ b/src/heap.h @@ -178,7 +178,7 @@ namespace internal { V(Smi, last_script_id, LastScriptId) \ V(Script, empty_script, EmptyScript) \ V(Smi, real_stack_limit, RealStackLimit) \ - V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames) \ + V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames) \ V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \ V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \ V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \ @@ -186,6 +186,7 @@ namespace internal { V(JSObject, observation_state, ObservationState) \ V(Map, external_map, ExternalMap) \ V(Symbol, frozen_symbol, FrozenSymbol) \ + V(Symbol, elements_transition_symbol, ElementsTransitionSymbol) \ V(SeededNumberDictionary, empty_slow_element_dictionary, \ EmptySlowElementDictionary) \ V(Symbol, observed_symbol, ObservedSymbol) \ diff --git a/src/objects-debug.cc b/src/objects-debug.cc index cb5f2b7900..395f95ca7e 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -1162,10 +1162,6 @@ static bool CheckOneBackPointer(Map* current_map, Object* target) { bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) { - if (HasElementsTransition() && - !CheckOneBackPointer(current_map, elements_transition())) { - return false; - } for (int i = 0; i < number_of_transitions(); ++i) { if (!CheckOneBackPointer(current_map, GetTarget(i))) return false; } diff --git a/src/objects-inl.h b/src/objects-inl.h index 3c70569241..128dc6be28 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4269,7 +4269,8 @@ bool Map::HasTransitionArray() { Map* Map::elements_transition_map() { - return transitions()->elements_transition(); + int index = transitions()->Search(GetHeap()->elements_transition_symbol()); + return transitions()->GetTarget(index); } @@ -4300,10 +4301,14 @@ Map* Map::GetTransition(int transition_index) { MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) { - MaybeObject* allow_elements = EnsureHasTransitionArray(this); - if (allow_elements->IsFailure()) return allow_elements; - transitions()->set_elements_transition(transitioned_map); - return this; + TransitionArray* transitions; + MaybeObject* maybe_transitions = AddTransition( + GetHeap()->elements_transition_symbol(), + transitioned_map, + FULL_TRANSITION); + if (!maybe_transitions->To(&transitions)) return maybe_transitions; + set_transitions(transitions); + return transitions; } diff --git a/src/objects.cc b/src/objects.cc index 1fdd478b7f..2e9badbb2a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -7023,12 +7023,6 @@ class IntrusiveMapTransitionIterator { return transition_array_->GetTarget(index); } - if (index == number_of_transitions && - transition_array_->HasElementsTransition()) { - Map* elements_transition = transition_array_->elements_transition(); - *TransitionArrayHeader() = Smi::FromInt(index + 1); - return elements_transition; - } *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map(); return NULL; } @@ -9145,18 +9139,10 @@ void Map::ClearNonLiveTransitions(Heap* heap) { } } - if (t->HasElementsTransition() && - ClearBackPointer(heap, t->elements_transition())) { - if (t->elements_transition()->instance_descriptors() == descriptors) { - descriptors_owner_died = true; - } - t->ClearElementsTransition(); - } else { - // If there are no transitions to be cleared, return. - // TODO(verwaest) Should be an assert, otherwise back pointers are not - // properly cleared. - if (transition_index == t->number_of_transitions()) return; - } + // If there are no transitions to be cleared, return. + // TODO(verwaest) Should be an assert, otherwise back pointers are not + // properly cleared. + if (transition_index == t->number_of_transitions()) return; int number_of_own_descriptors = NumberOfOwnDescriptors(); diff --git a/src/transitions-inl.h b/src/transitions-inl.h index 45b6457245..c4825fcf73 100644 --- a/src/transitions-inl.h +++ b/src/transitions-inl.h @@ -57,30 +57,8 @@ TransitionArray* TransitionArray::cast(Object* object) { } -Map* TransitionArray::elements_transition() { - Object* transition_map = get(kElementsTransitionIndex); - return Map::cast(transition_map); -} - - -void TransitionArray::ClearElementsTransition() { - WRITE_FIELD(this, kElementsTransitionOffset, Smi::FromInt(0)); -} - - bool TransitionArray::HasElementsTransition() { - return IsFullTransitionArray() && - get(kElementsTransitionIndex) != Smi::FromInt(0); -} - - -void TransitionArray::set_elements_transition(Map* transition_map, - WriteBarrierMode mode) { - ASSERT(IsFullTransitionArray()); - Heap* heap = GetHeap(); - WRITE_FIELD(this, kElementsTransitionOffset, transition_map); - CONDITIONAL_WRITE_BARRIER( - heap, this, kElementsTransitionOffset, transition_map, mode); + return Search(GetHeap()->elements_transition_symbol()) != kNotFound; } diff --git a/src/transitions.cc b/src/transitions.cc index df53178dd3..086edcb994 100644 --- a/src/transitions.cc +++ b/src/transitions.cc @@ -50,7 +50,6 @@ MaybeObject* TransitionArray::Allocate(int number_of_transitions) { FixedArray* array; MaybeObject* maybe_array = AllocateRaw(ToKeyIndex(number_of_transitions)); if (!maybe_array->To(&array)) return maybe_array; - array->set(kElementsTransitionIndex, Smi::FromInt(0)); array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); return array; } @@ -120,10 +119,6 @@ MaybeObject* TransitionArray::CopyInsert(Name* name, Map* target) { maybe_array = TransitionArray::Allocate(new_size); if (!maybe_array->To(&result)) return maybe_array; - if (HasElementsTransition()) { - result->set_elements_transition(elements_transition()); - } - if (HasPrototypeTransitions()) { result->SetPrototypeTransitions(GetPrototypeTransitions()); } diff --git a/src/transitions.h b/src/transitions.h index 7abef47346..fde1279895 100644 --- a/src/transitions.h +++ b/src/transitions.h @@ -41,10 +41,10 @@ namespace internal { // TransitionArrays are fixed arrays used to hold map transitions for property, // constant, and element changes. They can either be simple transition arrays // that store a single property transition, or a full transition array that has -// space for elements transitions, prototype transitions and multiple property -// transitons. The details related to property transitions are accessed in the -// descriptor array of the target map. In the case of a simple transition, the -// key is also read from the descriptor array of the target map. +// prototype transitions and multiple property transitons. The details related +// to property transitions are accessed in the descriptor array of the target +// map. In the case of a simple transition, the key is also read from the +// descriptor array of the target map. // // The simple format of the these objects is: // [0] Undefined or back pointer map @@ -52,9 +52,8 @@ namespace internal { // // The full format is: // [0] Undefined or back pointer map -// [1] Smi(0) or elements transition map -// [2] Smi(0) or fixed array of prototype transitions -// [3] First transition +// [1] Smi(0) or fixed array of prototype transitions +// [2] First transition // [length() - kTransitionSize] Last transition class TransitionArray: public FixedArray { public: @@ -73,12 +72,7 @@ class TransitionArray: public FixedArray { inline PropertyDetails GetTargetDetails(int transition_number); - inline Map* elements_transition(); - inline void set_elements_transition( - Map* target, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline bool HasElementsTransition(); - inline void ClearElementsTransition(); inline Object* back_pointer_storage(); inline void set_back_pointer_storage( @@ -127,8 +121,21 @@ class TransitionArray: public FixedArray { // Allocates a TransitionArray. MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions); - bool IsSimpleTransition() { return length() == kSimpleTransitionSize; } - bool IsFullTransitionArray() { return length() >= kFirstIndex; } + bool IsSimpleTransition() { + return length() == kSimpleTransitionSize && + get(kSimpleTransitionTarget)->IsHeapObject() && + // The IntrusivePrototypeTransitionIterator may have set the map of the + // prototype transitions array to a smi. In that case, there are + // prototype transitions, hence this transition array is a full + // transition array. + HeapObject::cast(get(kSimpleTransitionTarget))->map()->IsMap() && + get(kSimpleTransitionTarget)->IsMap(); + } + + bool IsFullTransitionArray() { + return length() > kFirstIndex || + (length() == kFirstIndex && !IsSimpleTransition()); + } // Casting. static inline TransitionArray* cast(Object* obj); @@ -139,9 +146,8 @@ class TransitionArray: public FixedArray { static const int kBackPointerStorageIndex = 0; // Layout for full transition arrays. - static const int kElementsTransitionIndex = 1; - static const int kPrototypeTransitionsIndex = 2; - static const int kFirstIndex = 3; + static const int kPrototypeTransitionsIndex = 1; + static const int kFirstIndex = 2; // Layout for simple transition arrays. static const int kSimpleTransitionTarget = 1; @@ -152,9 +158,7 @@ class TransitionArray: public FixedArray { static const int kBackPointerStorageOffset = FixedArray::kHeaderSize; // Layout for the full transition array header. - static const int kElementsTransitionOffset = kBackPointerStorageOffset + - kPointerSize; - static const int kPrototypeTransitionsOffset = kElementsTransitionOffset + + static const int kPrototypeTransitionsOffset = kBackPointerStorageOffset + kPointerSize; // Layout of map transition entries in full transition arrays.