From 75407ae2b78806edc45108278a8eda78d3e2fbf1 Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 10 Jul 2012 07:53:00 +0000 Subject: [PATCH] Moving prototype transitions into the header of the transition array. Review URL: https://chromiumcodereview.appspot.com/10692026 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12022 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/heap.cc | 8 ++-- src/mark-compact.cc | 49 ++++++++++------------ src/objects-debug.cc | 3 +- src/objects-inl.h | 104 ++++++++++++++++++++++++----------------------- src/objects.cc | 62 +++++++++++++--------------- src/objects.h | 26 ++++++------ src/profile-generator.cc | 10 ----- src/transitions-inl.h | 38 ++++++++++++++++- src/transitions.cc | 5 +++ src/transitions.h | 36 +++++++++++----- test/cctest/test-heap.cc | 5 ++- 11 files changed, 192 insertions(+), 154 deletions(-) diff --git a/src/heap.cc b/src/heap.cc index 5c3a386..1b4ec81 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2082,7 +2082,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, map->set_pre_allocated_property_fields(0); map->init_instance_descriptors(); map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); - map->init_prototype_transitions(undefined_value()); + map->init_back_pointer(undefined_value()); map->set_unused_property_fields(0); map->set_bit_field(0); map->set_bit_field2(1 << Map::kIsExtensible); @@ -2221,15 +2221,15 @@ bool Heap::CreateInitialMaps() { // Fix the instance_descriptors for the existing maps. meta_map()->init_instance_descriptors(); meta_map()->set_code_cache(empty_fixed_array()); - meta_map()->init_prototype_transitions(undefined_value()); + meta_map()->init_back_pointer(undefined_value()); fixed_array_map()->init_instance_descriptors(); fixed_array_map()->set_code_cache(empty_fixed_array()); - fixed_array_map()->init_prototype_transitions(undefined_value()); + fixed_array_map()->init_back_pointer(undefined_value()); oddball_map()->init_instance_descriptors(); oddball_map()->set_code_cache(empty_fixed_array()); - oddball_map()->init_prototype_transitions(undefined_value()); + oddball_map()->init_back_pointer(undefined_value()); // Fix prototype object for existing maps. meta_map()->set_prototype(null_value()); diff --git a/src/mark-compact.cc b/src/mark-compact.cc index a9d0c16..e75dc49 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -1823,24 +1823,6 @@ template void Marker::MarkMapContents(Map* map); template void Marker::MarkMapContents(Map* map) { - // Mark prototype transitions array but don't push it into marking stack. - // This will make references from it weak. We will clean dead prototype - // transitions in ClearNonLiveTransitions. - Object** proto_trans_slot = - HeapObject::RawField(map, Map::kPrototypeTransitionsOrBackPointerOffset); - HeapObject* prototype_transitions = HeapObject::cast(*proto_trans_slot); - if (prototype_transitions->IsFixedArray()) { - mark_compact_collector()->RecordSlot(proto_trans_slot, - proto_trans_slot, - prototype_transitions); - MarkBit mark = Marking::MarkBitFrom(prototype_transitions); - if (!mark.Get()) { - mark.Set(); - MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(), - prototype_transitions->Size()); - } - } - // Make sure that the back pointer stored either in the map itself or inside // its prototype transitions array is marked. Treat pointers in the descriptor // array as weak and also mark that array to prevent visiting it later. @@ -1855,13 +1837,12 @@ void Marker::MarkMapContents(Map* map) { // Mark the Object* fields of the Map. Since the descriptor array has been // marked already, it is fine that one of these fields contains a pointer - // to it. But make sure to skip back pointer and prototype transitions. + // to it. But make sure to skip back pointer. STATIC_ASSERT(Map::kPointerFieldsEndOffset == - Map::kPrototypeTransitionsOrBackPointerOffset + kPointerSize); - Object** start_slot = HeapObject::RawField( - map, Map::kPointerFieldsBeginOffset); - Object** end_slot = HeapObject::RawField( - map, Map::kPrototypeTransitionsOrBackPointerOffset); + Map::kBackPointerOffset + kPointerSize); + Object** start_slot = + HeapObject::RawField(map, Map::kPointerFieldsBeginOffset); + Object** end_slot = HeapObject::RawField(map, Map::kBackPointerOffset); for (Object** slot = start_slot; slot < end_slot; slot++) { Object* obj = *slot; if (!obj->NonFailureIsHeapObject()) continue; @@ -1952,9 +1933,21 @@ void Marker::MarkTransitionArray(TransitionArray* transitions) { Object** transitions_start = transitions->data_start(); if (transitions->HasElementsTransition()) { - mark_compact_collector()->RecordSlot(transitions_start, - transitions->GetElementsSlot(), - transitions->elements_transition()); + mark_compact_collector()->RecordSlot( + transitions_start, + transitions->GetElementsTransitionSlot(), + transitions->elements_transition()); + } + + if (transitions->HasPrototypeTransitions()) { + // Mark prototype transitions array but don't push it into marking stack. + // This will make references from it weak. We will clean dead prototype + // transitions in ClearNonLiveTransitions. + Object** proto_trans_slot = transitions->GetPrototypeTransitionsSlot(); + HeapObject* prototype_transitions = HeapObject::cast(*proto_trans_slot); + base_marker()->MarkObjectWithoutPush(prototype_transitions); + mark_compact_collector()->RecordSlot( + transitions_start, proto_trans_slot, prototype_transitions); } for (int i = 0; i < transitions->number_of_transitions(); ++i) { @@ -2545,7 +2538,7 @@ void MarkCompactCollector::ClearNonLiveTransitions() { void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { int number_of_transitions = map->NumberOfProtoTransitions(); - FixedArray* prototype_transitions = map->prototype_transitions(); + FixedArray* prototype_transitions = map->GetPrototypeTransitions(); int new_number_of_transitions = 0; const int header = Map::kProtoTransitionHeaderSize; diff --git a/src/objects-debug.cc b/src/objects-debug.cc index fde1814..e40fe51 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -1006,7 +1006,6 @@ void NormalizedMapCache::NormalizedMapCacheVerify() { void Map::ZapTransitions() { TransitionArray* transition_array = transitions(); - if (transition_array == NULL) return; MemsetPointer(transition_array->data_start(), GetHeap()->the_hole_value(), transition_array->length()); @@ -1014,7 +1013,7 @@ void Map::ZapTransitions() { void Map::ZapPrototypeTransitions() { - FixedArray* proto_transitions = prototype_transitions(); + FixedArray* proto_transitions = GetPrototypeTransitions(); MemsetPointer(proto_transitions->data_start(), GetHeap()->the_hole_value(), proto_transitions->length()); diff --git a/src/objects-inl.h b/src/objects-inl.h index 55a7a42..06c3405 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3524,12 +3524,7 @@ void Map::set_bit_field3(int value) { Object* Map::GetBackPointer() { - Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); - if (object->IsFixedArray()) { - return FixedArray::cast(object)->get(kProtoTransitionBackPointerOffset); - } else { - return object; - } + return READ_FIELD(this, kBackPointerOffset); } @@ -3567,9 +3562,9 @@ static MaybeObject* AllowTransitions(Map* map) { } -// If the descriptor does not have a transition array, install a new -// transition array that has room for an element transition. -static MaybeObject* AllowElementsTransition(Map* map) { +// If the descriptor is using the empty transition array, install a new empty +// transition array that will have place for an element transition. +static MaybeObject* EnsureHasTransitionArray(Map* map) { if (map->HasTransitionArray()) return map; AllowTransitions(map); @@ -3584,13 +3579,41 @@ static MaybeObject* AllowElementsTransition(Map* map) { MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) { - MaybeObject* allow_elements = AllowElementsTransition(this); + MaybeObject* allow_elements = EnsureHasTransitionArray(this); if (allow_elements->IsFailure()) return allow_elements; transitions()->set_elements_transition(transitioned_map); return this; } +FixedArray* Map::GetPrototypeTransitions() { + if (!HasTransitionArray()) return GetHeap()->empty_fixed_array(); + if (!transitions()->HasPrototypeTransitions()) { + return GetHeap()->empty_fixed_array(); + } + return transitions()->GetPrototypeTransitions(); +} + + +MaybeObject* Map::SetPrototypeTransitions(FixedArray* proto_transitions) { + MaybeObject* allow_prototype = EnsureHasTransitionArray(this); + if (allow_prototype->IsFailure()) return allow_prototype; +#ifdef DEBUG + if (HasPrototypeTransitions()) { + ASSERT(GetPrototypeTransitions() != proto_transitions); + ZapPrototypeTransitions(); + } +#endif + transitions()->SetPrototypeTransitions(proto_transitions); + return this; +} + + +bool Map::HasPrototypeTransitions() { + return HasTransitionArray() && transitions()->HasPrototypeTransitions(); +} + + TransitionArray* Map::transitions() { return instance_descriptors()->transitions(); } @@ -3623,57 +3646,38 @@ MaybeObject* Map::set_transitions(TransitionArray* transitions_array) { } +void Map::init_back_pointer(Object* undefined) { + ASSERT(undefined->IsUndefined()); + WRITE_FIELD(this, kBackPointerOffset, undefined); +} + + void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { Heap* heap = GetHeap(); ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE); ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) || (value->IsMap() && GetBackPointer()->IsUndefined())); - Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); - if (object->IsFixedArray()) { - FixedArray::cast(object)->set( - kProtoTransitionBackPointerOffset, value, mode); - } else { - WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value); - CONDITIONAL_WRITE_BARRIER( - heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode); - } -} - - -FixedArray* Map::prototype_transitions() { - Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); - if (object->IsFixedArray()) { - return FixedArray::cast(object); - } else { - return GetHeap()->empty_fixed_array(); - } + WRITE_FIELD(this, kBackPointerOffset, value); + CONDITIONAL_WRITE_BARRIER(heap, this, kBackPointerOffset, value, mode); } -void Map::set_prototype_transitions(FixedArray* value, WriteBarrierMode mode) { - Heap* heap = GetHeap(); - ASSERT(value != heap->empty_fixed_array()); - value->set(kProtoTransitionBackPointerOffset, GetBackPointer()); -#ifdef DEBUG - if (value != prototype_transitions()) { - ZapPrototypeTransitions(); - } -#endif - WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value); - CONDITIONAL_WRITE_BARRIER( - heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode); -} - - -void Map::init_prototype_transitions(Object* undefined) { - ASSERT(undefined->IsUndefined()); - WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, undefined); +// Can either be Smi (no transitions), normal transition array, or a transition +// array with the header overwritten as a Smi (thus iterating). +TransitionArray* Map::unchecked_transition_array() { + ASSERT(HasTransitionArray()); + Object* object = *HeapObject::RawField(instance_descriptors(), + DescriptorArray::kTransitionsOffset); + ASSERT(!object->IsSmi()); + TransitionArray* transition_array = static_cast(object); + return transition_array; } -HeapObject* Map::unchecked_prototype_transitions() { - Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); - return reinterpret_cast(object); +HeapObject* Map::UncheckedPrototypeTransitions() { + ASSERT(HasTransitionArray()); + ASSERT(unchecked_transition_array()->HasPrototypeTransitions()); + return unchecked_transition_array()->UncheckedPrototypeTransitions(); } diff --git a/src/objects.cc b/src/objects.cc index 244e22b..9861988 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -5147,11 +5147,11 @@ class IntrusivePrototypeTransitionIterator { void Start() { ASSERT(!IsIterating()); - if (HasTransitions()) *Header() = Smi::FromInt(0); + *Header() = Smi::FromInt(0); } bool IsIterating() { - return HasTransitions() && (*Header())->IsSmi(); + return (*Header())->IsSmi(); } Map* Next() { @@ -5166,23 +5166,17 @@ class IntrusivePrototypeTransitionIterator { } private: - bool HasTransitions() { - return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray(); - } - Object** Header() { return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset); } int NumberOfTransitions() { - ASSERT(HasTransitions()); FixedArray* proto_trans = reinterpret_cast(proto_trans_); Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); return Smi::cast(num)->value(); } Map* GetTransition(int transitionNumber) { - ASSERT(HasTransitions()); FixedArray* proto_trans = reinterpret_cast(proto_trans_); return Map::cast(proto_trans->get(IndexFor(transitionNumber))); } @@ -5232,42 +5226,41 @@ class TraversableMap : public Map { return old_parent; } - // Can either be Smi (no instance descriptors), or a descriptor array with the - // header overwritten as a Smi (thus iterating). - TransitionArray* MutatedTransitions() { - Object* object = *HeapObject::RawField(instance_descriptors(), - DescriptorArray::kTransitionsOffset); - TransitionArray* transition_array = static_cast(object); - return transition_array; - } - // Start iterating over this map's children, possibly destroying a FixedArray // map (see explanation above). void ChildIteratorStart() { if (HasTransitionArray()) { + if (HasPrototypeTransitions()) { + IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start(); + } + IntrusiveMapTransitionIterator(transitions()).Start(); } - IntrusivePrototypeTransitionIterator( - unchecked_prototype_transitions()).Start(); } // If we have an unvisited child map, return that one and advance. If we have // none, return NULL and reset any destroyed FixedArray maps. TraversableMap* ChildIteratorNext() { - IntrusivePrototypeTransitionIterator - proto_iterator(unchecked_prototype_transitions()); - if (proto_iterator.IsIterating()) { - Map* next = proto_iterator.Next(); - if (next != NULL) return static_cast(next); - } if (HasTransitionArray()) { - IntrusiveMapTransitionIterator - transitions_iterator(MutatedTransitions()); - if (transitions_iterator.IsIterating()) { - Map* next = transitions_iterator.Next(); + TransitionArray* transition_array = unchecked_transition_array(); + + if (transition_array->HasPrototypeTransitions()) { + HeapObject* proto_transitions = + transition_array->UncheckedPrototypeTransitions(); + IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions); + if (proto_iterator.IsIterating()) { + Map* next = proto_iterator.Next(); + if (next != NULL) return static_cast(next); + } + } + + IntrusiveMapTransitionIterator transition_iterator(transition_array); + if (transition_iterator.IsIterating()) { + Map* next = transition_iterator.Next(); if (next != NULL) return static_cast(next); } } + return NULL; } }; @@ -7417,7 +7410,9 @@ void Map::ClearNonLiveTransitions(Heap* heap) { // If the final transition array does not contain any live transitions, remove // the transition array from the map. - if (transition_index == 0 && !t->HasElementsTransition()) { + if (transition_index == 0 && + !t->HasElementsTransition() && + !t->HasPrototypeTransitions()) { return ClearTransitions(); } @@ -8835,7 +8830,7 @@ MaybeObject* JSArray::SetElementsLength(Object* len) { Map* Map::GetPrototypeTransition(Object* prototype) { - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); int number_of_transitions = NumberOfProtoTransitions(); const int proto_offset = kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; @@ -8857,7 +8852,7 @@ MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { // Don't cache prototype transition if this map is shared. if (is_shared() || !FLAG_cache_prototype_transitions) return this; - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); const int step = kProtoTransitionElementsPerEntry; const int header = kProtoTransitionHeaderSize; @@ -8880,7 +8875,8 @@ MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { new_cache->set(i + header, cache->get(i + header)); } cache = new_cache; - set_prototype_transitions(cache); + MaybeObject* set_result = SetPrototypeTransitions(cache); + if (set_result->IsFailure()) return set_result; } int last = transitions - 1; diff --git a/src/objects.h b/src/objects.h index b697605..d7cd80f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4864,6 +4864,7 @@ class Map: public HeapObject { inline Object* GetBackPointer(); inline void SetBackPointer(Object* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline void init_back_pointer(Object* undefined); // [prototype transitions]: cache of prototype transitions. // Prototype transition is a transition that happens @@ -4873,27 +4874,29 @@ class Map: public HeapObject { // 1: back pointer that overlaps with prototype transitions field. // 2 + 2 * i: prototype // 3 + 2 * i: target map - DECL_ACCESSORS(prototype_transitions, FixedArray) + inline FixedArray* GetPrototypeTransitions(); + MUST_USE_RESULT inline MaybeObject* SetPrototypeTransitions( + FixedArray* prototype_transitions); + inline bool HasPrototypeTransitions(); - inline void init_prototype_transitions(Object* undefined); - inline HeapObject* unchecked_prototype_transitions(); + inline HeapObject* UncheckedPrototypeTransitions(); + inline TransitionArray* unchecked_transition_array(); - static const int kProtoTransitionHeaderSize = 2; + static const int kProtoTransitionHeaderSize = 1; static const int kProtoTransitionNumberOfEntriesOffset = 0; - static const int kProtoTransitionBackPointerOffset = 1; static const int kProtoTransitionElementsPerEntry = 2; static const int kProtoTransitionPrototypeOffset = 0; static const int kProtoTransitionMapOffset = 1; inline int NumberOfProtoTransitions() { - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); if (cache->length() == 0) return 0; return Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value(); } inline void SetNumberOfProtoTransitions(int value) { - FixedArray* cache = prototype_transitions(); + FixedArray* cache = GetPrototypeTransitions(); ASSERT(cache->length() != 0); cache->set_unchecked(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value)); @@ -5053,17 +5056,14 @@ class Map: public HeapObject { kConstructorOffset + kPointerSize; static const int kCodeCacheOffset = kInstanceDescriptorsOrBitField3Offset + kPointerSize; - static const int kPrototypeTransitionsOrBackPointerOffset = - kCodeCacheOffset + kPointerSize; - static const int kPadStart = - kPrototypeTransitionsOrBackPointerOffset + kPointerSize; + static const int kBackPointerOffset = kCodeCacheOffset + kPointerSize; + static const int kPadStart = kBackPointerOffset + kPointerSize; static const int kSize = MAP_POINTER_ALIGN(kPadStart); // Layout of pointer fields. Heap iteration code relies on them // being continuously allocated. static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset; - static const int kPointerFieldsEndOffset = - kPrototypeTransitionsOrBackPointerOffset + kPointerSize; + static const int kPointerFieldsEndOffset = kBackPointerOffset + kPointerSize; // Byte offsets within kInstanceSizesOffset. static const int kInstanceSizeOffset = kInstanceSizesOffset + 0; diff --git a/src/profile-generator.cc b/src/profile-generator.cc index ea93006..d06b62c 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -2013,16 +2013,6 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { "descriptors", map->instance_descriptors(), Map::kInstanceDescriptorsOrBitField3Offset); } - if (map->unchecked_prototype_transitions()->IsFixedArray()) { - TagObject(map->prototype_transitions(), "(prototype transitions)"); - SetInternalReference(map, entry, - "prototype_transitions", map->prototype_transitions(), - Map::kPrototypeTransitionsOrBackPointerOffset); - } else { - SetInternalReference(map, entry, - "back_pointer", map->GetBackPointer(), - Map::kPrototypeTransitionsOrBackPointerOffset); - } SetInternalReference(map, entry, "code_cache", map->code_cache(), Map::kCodeCacheOffset); diff --git a/src/transitions-inl.h b/src/transitions-inl.h index 9061883..517fdc8 100644 --- a/src/transitions-inl.h +++ b/src/transitions-inl.h @@ -82,6 +82,42 @@ void TransitionArray::set_elements_transition(Map* transition_map, } +bool TransitionArray::HasPrototypeTransitions() { + Object* prototype_transitions = get(kPrototypeTransitionsIndex); + return prototype_transitions != Smi::FromInt(0); +} + + +FixedArray* TransitionArray::GetPrototypeTransitions() { + Object* prototype_transitions = get(kPrototypeTransitionsIndex); + return FixedArray::cast(prototype_transitions); +} + + +HeapObject* TransitionArray::UncheckedPrototypeTransitions() { + Object* prototype_transitions = get(kPrototypeTransitionsIndex); + if (prototype_transitions == Smi::FromInt(0)) return NULL; + return reinterpret_cast(prototype_transitions); +} + + +void TransitionArray::SetPrototypeTransitions(FixedArray* transitions, + WriteBarrierMode mode) { + ASSERT(this != NULL); + ASSERT(transitions->IsFixedArray()); + Heap* heap = GetHeap(); + WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions); + CONDITIONAL_WRITE_BARRIER( + heap, this, kPrototypeTransitionsOffset, transitions, mode); +} + + +Object** TransitionArray::GetPrototypeTransitionsSlot() { + return HeapObject::RawField(reinterpret_cast(this), + kPrototypeTransitionsOffset); +} + + Object** TransitionArray::GetKeySlot(int transition_number) { ASSERT(transition_number < number_of_transitions()); return HeapObject::RawField( @@ -148,7 +184,7 @@ PropertyDetails TransitionArray::GetTargetDetails(int transition_number) { } -Object** TransitionArray::GetElementsSlot() { +Object** TransitionArray::GetElementsTransitionSlot() { return HeapObject::RawField(reinterpret_cast(this), kElementsTransitionOffset); } diff --git a/src/transitions.cc b/src/transitions.cc index 033f224..1e965cd 100644 --- a/src/transitions.cc +++ b/src/transitions.cc @@ -45,6 +45,7 @@ MaybeObject* TransitionArray::Allocate(int number_of_transitions) { } array->set(kElementsTransitionIndex, Smi::FromInt(0)); + array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); return array; } @@ -98,6 +99,10 @@ MaybeObject* TransitionArray::CopyInsert(String* name, Object* value) { result->set_elements_transition(elements_transition()); } + if (HasPrototypeTransitions()) { + result->SetPrototypeTransitions(GetPrototypeTransitions()); + } + FixedArray::WhitenessWitness witness(result); if (insertion_index != kNotFound) { diff --git a/src/transitions.h b/src/transitions.h index 5abdf99..a4b5b27 100644 --- a/src/transitions.h +++ b/src/transitions.h @@ -46,22 +46,33 @@ namespace internal { // [length() - kTransitionSize] Last transition class TransitionArray: public FixedArray { public: - inline Map* elements_transition(); - inline void set_elements_transition( - Map* value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline void ClearElementsTransition(); - inline bool HasElementsTransition(); // Accessors for fetching instance transition at transition number. inline String* GetKey(int transition_number); - inline Object** GetKeySlot(int transition_number); inline void SetKey(int transition_number, String* value); + inline Object** GetKeySlot(int transition_number); + inline Object* GetValue(int transition_number); - inline Object** GetValueSlot(int transition_number); inline void SetValue(int transition_number, Object* value); + inline Object** GetValueSlot(int transition_number); + inline Map* GetTargetMap(int transition_number); inline PropertyDetails GetTargetDetails(int transition_number); - inline Object** GetElementsSlot(); + + inline Map* elements_transition(); + inline void set_elements_transition( + Map* value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Object** GetElementsTransitionSlot(); + inline bool HasElementsTransition(); + inline void ClearElementsTransition(); + + inline FixedArray* GetPrototypeTransitions(); + inline void SetPrototypeTransitions( + FixedArray* prototype_transitions, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Object** GetPrototypeTransitionsSlot(); + inline bool HasPrototypeTransitions(); + inline HeapObject* UncheckedPrototypeTransitions(); // Returns the number of transitions in the array. int number_of_transitions() { @@ -99,11 +110,14 @@ class TransitionArray: public FixedArray { static const int kNotFound = -1; static const int kElementsTransitionIndex = 0; - static const int kFirstIndex = 1; + static const int kPrototypeTransitionsIndex = 1; + static const int kFirstIndex = 2; // Layout transition array header. static const int kElementsTransitionOffset = FixedArray::kHeaderSize; - static const int kFirstOffset = kElementsTransitionOffset + kPointerSize; + static const int kPrototypeTransitionsOffset = kElementsTransitionOffset + + kPointerSize; + static const int kFirstOffset = kPrototypeTransitionsOffset + kPointerSize; // Layout of map transition. static const int kTransitionKey = 0; diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 211a20c..8ba7f40 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -1587,7 +1587,7 @@ TEST(PrototypeTransitionClearing) { CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions()); // Verify that prototype transitions array was compacted. - FixedArray* trans = baseObject->map()->prototype_transitions(); + FixedArray* trans = baseObject->map()->GetPrototypeTransitions(); for (int i = 0; i < transitions; i++) { int j = Map::kProtoTransitionHeaderSize + i * Map::kProtoTransitionElementsPerEntry; @@ -1608,7 +1608,8 @@ TEST(PrototypeTransitionClearing) { // clearing correctly records slots in prototype transition array. i::FLAG_always_compact = true; Handle map(baseObject->map()); - CHECK(!space->LastPage()->Contains(map->prototype_transitions()->address())); + CHECK(!space->LastPage()->Contains( + map->GetPrototypeTransitions()->address())); CHECK(space->LastPage()->Contains(prototype->address())); baseObject->SetPrototype(*prototype, false)->ToObjectChecked(); CHECK(map->GetPrototypeTransition(*prototype)->IsMap()); -- 2.7.4