From: verwaest@chromium.org Date: Wed, 31 Jul 2013 17:08:50 +0000 (+0000) Subject: Remove elements transitions from the transition array. X-Git-Tag: upstream/4.7.83~13104 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e53471dbaa21d6a063de63e0662bf5b0f707bbeb;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/include/v8.h b/include/v8.h index 6b1815383..a4eae968d 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 777661570..c2a270760 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 fbe053101..de6f55bfa 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 cb5f2b790..395f95ca7 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 3c7056924..128dc6be2 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 1fdd478b7..2e9badbb2 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 45b645724..c4825fcf7 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 df53178dd..086edcb99 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 7abef4734..fde127989 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.