Commit 948a973d authored by jkummerow's avatar jkummerow Committed by Commit bot

Revert of Simplify and compact transitions storage (patchset #4 id:80001 of...

Revert of Simplify and compact transitions storage (patchset #4 id:80001 of https://codereview.chromium.org/980573002/)

Reason for revert:
x64 test failures

Original issue's description:
> Simplify and compact transitions storage
>
> Simple transitions are now stored in a map's "transitions" field (as a WeakCell wrapping the target map); full TransitionArrays are used when that's not sufficient.
> To encapsulate these storage format implementation details, functions for manipulating and querying transitions have been refactored to be static functions on the TransitionArray class, and take maps as inputs.
>
> Committed: https://crrev.com/45fbef7f2252fce10634931cb103ccc1fc95ae6a
> Cr-Commit-Position: refs/heads/master@{#27029}

TBR=verwaest@chromium.org,ulan@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/982143002

Cr-Commit-Position: refs/heads/master@{#27030}
parent 45fbef7f
...@@ -1286,12 +1286,12 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { ...@@ -1286,12 +1286,12 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
Object* raw_transitions = map->raw_transitions(); if (map->HasTransitionArray()) {
if (TransitionArray::IsFullTransitionArray(raw_transitions)) { TransitionArray* transitions = map->transitions();
TransitionArray* transitions = TransitionArray::cast(raw_transitions);
int transitions_entry = GetEntry(transitions)->index(); int transitions_entry = GetEntry(transitions)->index();
if (FLAG_collect_maps && map->CanTransition()) { if (FLAG_collect_maps && map->CanTransition()) {
if (!transitions->IsSimpleTransition()) {
if (transitions->HasPrototypeTransitions()) { if (transitions->HasPrototypeTransitions()) {
FixedArray* prototype_transitions = FixedArray* prototype_transitions =
transitions->GetPrototypeTransitions(); transitions->GetPrototypeTransitions();
...@@ -1303,14 +1303,11 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { ...@@ -1303,14 +1303,11 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
// TODO(alph): transitions keys are strong links. // TODO(alph): transitions keys are strong links.
MarkAsWeakContainer(transitions); MarkAsWeakContainer(transitions);
} }
}
TagObject(transitions, "(transition array)"); TagObject(transitions, "(transition array)");
SetInternalReference(map, entry, "transitions", transitions, SetInternalReference(map, entry, "transitions", transitions,
Map::kTransitionsOffset); Map::kTransitionsOffset);
} else if (TransitionArray::IsSimpleTransition(raw_transitions)) {
TagObject(raw_transitions, "(transition)");
SetInternalReference(map, entry, "transition", raw_transitions,
Map::kTransitionsOffset);
} }
DescriptorArray* descriptors = map->instance_descriptors(); DescriptorArray* descriptors = map->instance_descriptors();
TagObject(descriptors, "(map descriptors)"); TagObject(descriptors, "(map descriptors)");
......
...@@ -2476,7 +2476,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type, ...@@ -2476,7 +2476,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
map->set_dependent_code(DependentCode::cast(empty_fixed_array()), map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
map->set_weak_cell_cache(Smi::FromInt(0)); map->set_weak_cell_cache(Smi::FromInt(0));
map->set_raw_transitions(Smi::FromInt(0)); map->init_transitions(undefined_value());
map->set_unused_property_fields(0); map->set_unused_property_fields(0);
map->set_instance_descriptors(empty_descriptor_array()); map->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
...@@ -2610,7 +2610,7 @@ bool Heap::CreateInitialMaps() { ...@@ -2610,7 +2610,7 @@ bool Heap::CreateInitialMaps() {
// Fix the instance_descriptors for the existing maps. // Fix the instance_descriptors for the existing maps.
meta_map()->set_code_cache(empty_fixed_array()); meta_map()->set_code_cache(empty_fixed_array());
meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
meta_map()->set_raw_transitions(Smi::FromInt(0)); meta_map()->init_transitions(undefined_value());
meta_map()->set_instance_descriptors(empty_descriptor_array()); meta_map()->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout()); meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
...@@ -2619,7 +2619,7 @@ bool Heap::CreateInitialMaps() { ...@@ -2619,7 +2619,7 @@ bool Heap::CreateInitialMaps() {
fixed_array_map()->set_code_cache(empty_fixed_array()); fixed_array_map()->set_code_cache(empty_fixed_array());
fixed_array_map()->set_dependent_code( fixed_array_map()->set_dependent_code(
DependentCode::cast(empty_fixed_array())); DependentCode::cast(empty_fixed_array()));
fixed_array_map()->set_raw_transitions(Smi::FromInt(0)); fixed_array_map()->init_transitions(undefined_value());
fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
fixed_array_map()->set_layout_descriptor( fixed_array_map()->set_layout_descriptor(
...@@ -2628,7 +2628,7 @@ bool Heap::CreateInitialMaps() { ...@@ -2628,7 +2628,7 @@ bool Heap::CreateInitialMaps() {
undefined_map()->set_code_cache(empty_fixed_array()); undefined_map()->set_code_cache(empty_fixed_array());
undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
undefined_map()->set_raw_transitions(Smi::FromInt(0)); undefined_map()->init_transitions(undefined_value());
undefined_map()->set_instance_descriptors(empty_descriptor_array()); undefined_map()->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
undefined_map()->set_layout_descriptor( undefined_map()->set_layout_descriptor(
...@@ -2637,7 +2637,7 @@ bool Heap::CreateInitialMaps() { ...@@ -2637,7 +2637,7 @@ bool Heap::CreateInitialMaps() {
null_map()->set_code_cache(empty_fixed_array()); null_map()->set_code_cache(empty_fixed_array());
null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
null_map()->set_raw_transitions(Smi::FromInt(0)); null_map()->init_transitions(undefined_value());
null_map()->set_instance_descriptors(empty_descriptor_array()); null_map()->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout()); null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
...@@ -2646,7 +2646,7 @@ bool Heap::CreateInitialMaps() { ...@@ -2646,7 +2646,7 @@ bool Heap::CreateInitialMaps() {
constant_pool_array_map()->set_code_cache(empty_fixed_array()); constant_pool_array_map()->set_code_cache(empty_fixed_array());
constant_pool_array_map()->set_dependent_code( constant_pool_array_map()->set_dependent_code(
DependentCode::cast(empty_fixed_array())); DependentCode::cast(empty_fixed_array()));
constant_pool_array_map()->set_raw_transitions(Smi::FromInt(0)); constant_pool_array_map()->init_transitions(undefined_value());
constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array()); constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
constant_pool_array_map()->set_layout_descriptor( constant_pool_array_map()->set_layout_descriptor(
......
...@@ -1470,9 +1470,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker< ...@@ -1470,9 +1470,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
fixed_array_size); fixed_array_size);
} }
if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) { if (map_obj->HasTransitionArray()) {
int fixed_array_size = int fixed_array_size = map_obj->transitions()->Size();
TransitionArray::cast(map_obj->raw_transitions())->Size();
heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE, heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
fixed_array_size); fixed_array_size);
} }
...@@ -2347,12 +2346,10 @@ void MarkCompactCollector::ClearNonLiveReferences() { ...@@ -2347,12 +2346,10 @@ void MarkCompactCollector::ClearNonLiveReferences() {
void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
FixedArray* prototype_transitions = int number_of_transitions = map->NumberOfProtoTransitions();
TransitionArray::GetPrototypeTransitions(map); FixedArray* prototype_transitions = map->GetPrototypeTransitions();
int number_of_transitions =
TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
const int header = TransitionArray::kProtoTransitionHeaderSize; const int header = Map::kProtoTransitionHeaderSize;
int new_number_of_transitions = 0; int new_number_of_transitions = 0;
for (int i = 0; i < number_of_transitions; i++) { for (int i = 0; i < number_of_transitions; i++) {
Object* cached_map = prototype_transitions->get(header + i); Object* cached_map = prototype_transitions->get(header + i);
...@@ -2366,8 +2363,7 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { ...@@ -2366,8 +2363,7 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
} }
if (new_number_of_transitions != number_of_transitions) { if (new_number_of_transitions != number_of_transitions) {
TransitionArray::SetNumberOfPrototypeTransitions(prototype_transitions, map->SetNumberOfProtoTransitions(new_number_of_transitions);
new_number_of_transitions);
} }
// Fill slots that became free with undefined value. // Fill slots that became free with undefined value.
...@@ -2388,7 +2384,7 @@ void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map, ...@@ -2388,7 +2384,7 @@ void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
bool current_is_alive = map_mark.Get(); bool current_is_alive = map_mark.Get();
bool parent_is_alive = Marking::MarkBitFrom(parent).Get(); bool parent_is_alive = Marking::MarkBitFrom(parent).Get();
if (!current_is_alive && parent_is_alive) { if (!current_is_alive && parent_is_alive) {
ClearMapTransitions(parent, map); ClearMapTransitions(parent);
} }
} }
...@@ -2402,43 +2398,28 @@ bool MarkCompactCollector::ClearMapBackPointer(Map* target) { ...@@ -2402,43 +2398,28 @@ bool MarkCompactCollector::ClearMapBackPointer(Map* target) {
} }
void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) { void MarkCompactCollector::ClearMapTransitions(Map* map) {
Object* transitions = map->raw_transitions(); // If there are no transitions to be cleared, return.
int num_transitions = TransitionArray::NumberOfTransitions(transitions); // TODO(verwaest) Should be an assert, otherwise back pointers are not
// properly cleared.
if (!map->HasTransitionArray()) return;
int number_of_own_descriptors = map->NumberOfOwnDescriptors(); TransitionArray* t = map->transitions();
DescriptorArray* descriptors = map->instance_descriptors();
// A previously existing simple transition (stored in a WeakCell) may have
// been cleared. Clear the useless cell pointer, and take ownership
// of the descriptor array.
if (transitions->IsWeakCell() && WeakCell::cast(transitions)->cleared()) {
map->set_raw_transitions(Smi::FromInt(0));
}
if (num_transitions == 0 &&
descriptors == dead_transition->instance_descriptors() &&
number_of_own_descriptors > 0) {
TrimDescriptorArray(map, descriptors, number_of_own_descriptors);
DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
map->set_owns_descriptors(true);
return;
}
int transition_index = 0; int transition_index = 0;
DescriptorArray* descriptors = map->instance_descriptors();
bool descriptors_owner_died = false; bool descriptors_owner_died = false;
// Compact all live descriptors to the left. // Compact all live descriptors to the left.
for (int i = 0; i < num_transitions; ++i) { for (int i = 0; i < t->number_of_transitions(); ++i) {
Map* target = TransitionArray::GetTarget(transitions, i); Map* target = t->GetTarget(i);
if (ClearMapBackPointer(target)) { if (ClearMapBackPointer(target)) {
if (target->instance_descriptors() == descriptors) { if (target->instance_descriptors() == descriptors) {
descriptors_owner_died = true; descriptors_owner_died = true;
} }
} else { } else {
if (i != transition_index) { if (i != transition_index) {
DCHECK(TransitionArray::IsFullTransitionArray(transitions));
TransitionArray* t = TransitionArray::cast(transitions);
Name* key = t->GetKey(i); Name* key = t->GetKey(i);
t->SetKey(transition_index, key); t->SetKey(transition_index, key);
Object** key_slot = t->GetKeySlot(transition_index); Object** key_slot = t->GetKeySlot(transition_index);
...@@ -2453,7 +2434,9 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) { ...@@ -2453,7 +2434,9 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
// If there are no transitions to be cleared, return. // If there are no transitions to be cleared, return.
// TODO(verwaest) Should be an assert, otherwise back pointers are not // TODO(verwaest) Should be an assert, otherwise back pointers are not
// properly cleared. // properly cleared.
if (transition_index == num_transitions) return; if (transition_index == t->number_of_transitions()) return;
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
if (descriptors_owner_died) { if (descriptors_owner_died) {
if (number_of_own_descriptors > 0) { if (number_of_own_descriptors > 0) {
...@@ -2469,17 +2452,14 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) { ...@@ -2469,17 +2452,14 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
// such that number_of_transitions() == 0. If this assumption changes, // such that number_of_transitions() == 0. If this assumption changes,
// TransitionArray::Insert() will need to deal with the case that a transition // TransitionArray::Insert() will need to deal with the case that a transition
// array disappeared during GC. // array disappeared during GC.
int trim = TransitionArray::Capacity(transitions) - transition_index; int trim = t->number_of_transitions_storage() - transition_index;
if (trim > 0) { if (trim > 0) {
// Non-full-TransitionArray cases can never reach this point.
DCHECK(TransitionArray::IsFullTransitionArray(transitions));
TransitionArray* t = TransitionArray::cast(transitions);
heap_->RightTrimFixedArray<Heap::FROM_GC>( heap_->RightTrimFixedArray<Heap::FROM_GC>(
t, trim * TransitionArray::kTransitionSize); t, t->IsSimpleTransition() ? trim
: trim * TransitionArray::kTransitionSize);
t->SetNumberOfTransitions(transition_index); t->SetNumberOfTransitions(transition_index);
// The map still has a full transition array.
DCHECK(TransitionArray::IsFullTransitionArray(map->raw_transitions()));
} }
DCHECK(map->HasTransitionArray());
} }
...@@ -4191,7 +4171,7 @@ void MarkCompactCollector::SweepSpaces() { ...@@ -4191,7 +4171,7 @@ void MarkCompactCollector::SweepSpaces() {
EvacuateNewSpaceAndCandidates(); EvacuateNewSpaceAndCandidates();
// ClearNonLiveReferences depends on precise sweeping of map space to // ClearNonLiveTransitions depends on precise sweeping of map space to
// detect whether unmarked map became dead in this collection or in one // detect whether unmarked map became dead in this collection or in one
// of the previous ones. // of the previous ones.
{ {
......
...@@ -808,7 +808,7 @@ class MarkCompactCollector { ...@@ -808,7 +808,7 @@ class MarkCompactCollector {
void ClearNonLiveReferences(); void ClearNonLiveReferences();
void ClearNonLivePrototypeTransitions(Map* map); void ClearNonLivePrototypeTransitions(Map* map);
void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark); void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark);
void ClearMapTransitions(Map* map, Map* dead_transition); void ClearMapTransitions(Map* map);
bool ClearMapBackPointer(Map* map); bool ClearMapBackPointer(Map* map);
void TrimDescriptorArray(Map* map, DescriptorArray* descriptors, void TrimDescriptorArray(Map* map, DescriptorArray* descriptors,
int number_of_own_descriptors); int number_of_own_descriptors);
......
...@@ -584,13 +584,18 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map, ...@@ -584,13 +584,18 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map,
template <typename StaticVisitor> template <typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap, void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap,
Map* map) { Map* map) {
Object* raw_transitions = map->raw_transitions(); // Make sure that the back pointer stored either in the map itself or
if (TransitionArray::IsSimpleTransition(raw_transitions)) { // inside its transitions array is marked. Skip recording the back
StaticVisitor::VisitPointer( // pointer slot since map space is not compacted.
heap, HeapObject::RawField(map, Map::kTransitionsOffset)); StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer()));
}
if (TransitionArray::IsFullTransitionArray(raw_transitions)) { // Treat pointers in the transitions array as weak and also mark that
MarkTransitionArray(heap, TransitionArray::cast(raw_transitions)); // array to prevent visiting it later. Skip recording the transition
// array slot, since it will be implicitly recorded when the pointer
// fields of this map are visited.
if (map->HasTransitionArray()) {
TransitionArray* transitions = map->transitions();
MarkTransitionArray(heap, transitions);
} }
// Since descriptor arrays are potentially shared, ensure that only the // Since descriptor arrays are potentially shared, ensure that only the
...@@ -626,18 +631,20 @@ void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray( ...@@ -626,18 +631,20 @@ void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray(
Heap* heap, TransitionArray* transitions) { Heap* heap, TransitionArray* transitions) {
if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return; if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
// Simple transitions do not have keys nor prototype transitions.
if (transitions->IsSimpleTransition()) return;
if (transitions->HasPrototypeTransitions()) { if (transitions->HasPrototypeTransitions()) {
// Mark prototype transitions array but do not push it onto marking // Mark prototype transitions array but do not push it onto marking
// stack, this will make references from it weak. We will clean dead // stack, this will make references from it weak. We will clean dead
// prototype transitions in ClearNonLiveReferences. // prototype transitions in ClearNonLiveTransitions.
Object** slot = transitions->GetPrototypeTransitionsSlot(); Object** slot = transitions->GetPrototypeTransitionsSlot();
HeapObject* obj = HeapObject::cast(*slot); HeapObject* obj = HeapObject::cast(*slot);
heap->mark_compact_collector()->RecordSlot(slot, slot, obj); heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
StaticVisitor::MarkObjectWithoutPush(heap, obj); StaticVisitor::MarkObjectWithoutPush(heap, obj);
} }
int num_transitions = TransitionArray::NumberOfTransitions(transitions); for (int i = 0; i < transitions->number_of_transitions(); ++i) {
for (int i = 0; i < num_transitions; ++i) {
StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i)); StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
} }
} }
......
...@@ -2553,11 +2553,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2553,11 +2553,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
number_ = number; number_ = number;
} }
void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) { void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
Map* target = int transition_index = map->SearchTransition(kData, name, attributes);
TransitionArray::SearchTransition(map, kData, name, attributes); if (transition_index == TransitionArray::kNotFound) return NotFound();
if (target == NULL) return NotFound();
lookup_type_ = TRANSITION_TYPE; lookup_type_ = TRANSITION_TYPE;
transition_ = handle(target); transition_ = handle(map->GetTransition(transition_index));
number_ = transition_->LastAdded(); number_ = transition_->LastAdded();
details_ = transition_->instance_descriptors()->GetDetails(number_); details_ = transition_->instance_descriptors()->GetDetails(number_);
} }
......
...@@ -359,19 +359,19 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { ...@@ -359,19 +359,19 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
bool follow_expected = false; bool follow_expected = false;
Handle<Map> target; Handle<Map> target;
if (seq_one_byte) { if (seq_one_byte) {
key = TransitionArray::ExpectedTransitionKey(map); key = Map::ExpectedTransitionKey(map);
follow_expected = !key.is_null() && ParseJsonString(key); follow_expected = !key.is_null() && ParseJsonString(key);
} }
// If the expected transition hits, follow it. // If the expected transition hits, follow it.
if (follow_expected) { if (follow_expected) {
target = TransitionArray::ExpectedTransitionTarget(map); target = Map::ExpectedTransitionTarget(map);
} else { } else {
// If the expected transition failed, parse an internalized string and // If the expected transition failed, parse an internalized string and
// try to find a matching transition. // try to find a matching transition.
key = ParseJsonInternalizedString(); key = ParseJsonInternalizedString();
if (key.is_null()) return ReportUnexpectedCharacter(); if (key.is_null()) return ReportUnexpectedCharacter();
target = TransitionArray::FindTransitionToField(map, key); target = Map::FindTransitionToField(map, key);
// If a transition was found, follow it and continue. // If a transition was found, follow it and continue.
transitioning = !target.is_null(); transitioning = !target.is_null();
} }
......
...@@ -320,8 +320,10 @@ void Map::MapVerify() { ...@@ -320,8 +320,10 @@ void Map::MapVerify() {
VerifyHeapPointer(prototype()); VerifyHeapPointer(prototype());
VerifyHeapPointer(instance_descriptors()); VerifyHeapPointer(instance_descriptors());
SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates()); SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates());
SLOW_DCHECK(TransitionArray::IsSortedNoDuplicates(this)); if (HasTransitionArray()) {
SLOW_DCHECK(TransitionArray::IsConsistentWithBackPointers(this)); SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
}
// TODO(ishell): turn it back to SLOW_DCHECK. // TODO(ishell): turn it back to SLOW_DCHECK.
CHECK(!FLAG_unbox_double_fields || CHECK(!FLAG_unbox_double_fields ||
layout_descriptor()->IsConsistentWithMap(this)); layout_descriptor()->IsConsistentWithMap(this));
...@@ -342,6 +344,7 @@ void Map::VerifyOmittedMapChecks() { ...@@ -342,6 +344,7 @@ void Map::VerifyOmittedMapChecks() {
if (!FLAG_omit_map_checks_for_leaf_maps) return; if (!FLAG_omit_map_checks_for_leaf_maps) return;
if (!is_stable() || if (!is_stable() ||
is_deprecated() || is_deprecated() ||
HasTransitionArray() ||
is_dictionary_map()) { is_dictionary_map()) {
CHECK_EQ(0, dependent_code()->number_of_entries( CHECK_EQ(0, dependent_code()->number_of_entries(
DependentCode::kPrototypeCheckGroup)); DependentCode::kPrototypeCheckGroup));
...@@ -1205,28 +1208,14 @@ bool TransitionArray::IsSortedNoDuplicates(int valid_entries) { ...@@ -1205,28 +1208,14 @@ bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
} }
// static
bool TransitionArray::IsSortedNoDuplicates(Map* map) {
Object* raw_transitions = map->raw_transitions();
if (IsFullTransitionArray(raw_transitions)) {
return TransitionArray::cast(raw_transitions)->IsSortedNoDuplicates();
}
// Simple and non-existent transitions are always sorted.
return true;
}
static bool CheckOneBackPointer(Map* current_map, Object* target) { static bool CheckOneBackPointer(Map* current_map, Object* target) {
return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map; return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map;
} }
// static bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) {
bool TransitionArray::IsConsistentWithBackPointers(Map* map) { for (int i = 0; i < number_of_transitions(); ++i) {
Object* transitions = map->raw_transitions(); if (!CheckOneBackPointer(current_map, GetTarget(i))) return false;
for (int i = 0; i < TransitionArray::NumberOfTransitions(transitions); ++i) {
Map* target = TransitionArray::GetTarget(transitions, i);
if (!CheckOneBackPointer(map, target)) return false;
} }
return true; return true;
} }
......
...@@ -1877,6 +1877,41 @@ void JSObject::initialize_elements() { ...@@ -1877,6 +1877,41 @@ void JSObject::initialize_elements() {
} }
Handle<String> Map::ExpectedTransitionKey(Handle<Map> map) {
DisallowHeapAllocation no_gc;
if (!map->HasTransitionArray()) return Handle<String>::null();
TransitionArray* transitions = map->transitions();
if (!transitions->IsSimpleTransition()) return Handle<String>::null();
int transition = TransitionArray::kSimpleTransitionIndex;
PropertyDetails details = transitions->GetTargetDetails(transition);
Name* name = transitions->GetKey(transition);
if (details.type() != DATA) return Handle<String>::null();
if (details.attributes() != NONE) return Handle<String>::null();
if (!name->IsString()) return Handle<String>::null();
return Handle<String>(String::cast(name));
}
Handle<Map> Map::ExpectedTransitionTarget(Handle<Map> map) {
DCHECK(!ExpectedTransitionKey(map).is_null());
return Handle<Map>(map->transitions()->GetTarget(
TransitionArray::kSimpleTransitionIndex));
}
Handle<Map> Map::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
DisallowHeapAllocation no_allocation;
if (!map->HasTransitionArray()) return Handle<Map>::null();
TransitionArray* transitions = map->transitions();
int transition = transitions->Search(kData, *key, NONE);
if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
PropertyDetails details = transitions->GetTargetDetails(transition);
if (details.type() != DATA) return Handle<Map>::null();
DCHECK_EQ(NONE, details.attributes());
return Handle<Map>(transitions->GetTarget(transition));
}
ACCESSORS(Oddball, to_string, String, kToStringOffset) ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset) ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
...@@ -5220,6 +5255,22 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) { ...@@ -5220,6 +5255,22 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
} }
// If the descriptor is using the empty transition array, install a new empty
// transition array that will have place for an element transition.
static void EnsureHasTransitionArray(Handle<Map> map) {
Handle<TransitionArray> transitions;
if (!map->HasTransitionArray()) {
transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
transitions->set_back_pointer_storage(map->GetBackPointer());
} else if (!map->transitions()->IsFullTransitionArray()) {
transitions = TransitionArray::ExtendToFullTransitionArray(map);
} else {
return;
}
map->set_transitions(*transitions);
}
LayoutDescriptor* Map::layout_descriptor_gc_safe() { LayoutDescriptor* Map::layout_descriptor_gc_safe() {
Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset); Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
return LayoutDescriptor::cast_gc_safe(layout_desc); return LayoutDescriptor::cast_gc_safe(layout_desc);
...@@ -5322,13 +5373,127 @@ Object* Map::GetBackPointer() { ...@@ -5322,13 +5373,127 @@ Object* Map::GetBackPointer() {
} }
Map* Map::ElementsTransitionMap() { bool Map::HasElementsTransition() {
return TransitionArray::SearchSpecial( return HasTransitionArray() && transitions()->HasElementsTransition();
this, GetHeap()->elements_transition_symbol());
} }
ACCESSORS(Map, raw_transitions, Object, kTransitionsOffset) bool Map::HasTransitionArray() const {
Object* object = READ_FIELD(this, kTransitionsOffset);
return object->IsTransitionArray();
}
Map* Map::elements_transition_map() {
int index =
transitions()->SearchSpecial(GetHeap()->elements_transition_symbol());
return transitions()->GetTarget(index);
}
bool Map::CanHaveMoreTransitions() {
if (!HasTransitionArray()) return true;
return transitions()->number_of_transitions() <
TransitionArray::kMaxNumberOfTransitions;
}
Map* Map::GetTransition(int transition_index) {
return transitions()->GetTarget(transition_index);
}
int Map::SearchSpecialTransition(Symbol* name) {
if (HasTransitionArray()) {
return transitions()->SearchSpecial(name);
}
return TransitionArray::kNotFound;
}
int Map::SearchTransition(PropertyKind kind, Name* name,
PropertyAttributes attributes) {
if (HasTransitionArray()) {
return transitions()->Search(kind, name, attributes);
}
return TransitionArray::kNotFound;
}
FixedArray* Map::GetPrototypeTransitions() {
if (!HasTransitionArray()) return GetHeap()->empty_fixed_array();
if (!transitions()->HasPrototypeTransitions()) {
return GetHeap()->empty_fixed_array();
}
return transitions()->GetPrototypeTransitions();
}
void Map::SetPrototypeTransitions(
Handle<Map> map, Handle<FixedArray> proto_transitions) {
EnsureHasTransitionArray(map);
int old_number_of_transitions = map->NumberOfProtoTransitions();
if (Heap::ShouldZapGarbage() && map->HasPrototypeTransitions()) {
DCHECK(map->GetPrototypeTransitions() != *proto_transitions);
map->ZapPrototypeTransitions();
}
map->transitions()->SetPrototypeTransitions(*proto_transitions);
map->SetNumberOfProtoTransitions(old_number_of_transitions);
}
bool Map::HasPrototypeTransitions() {
return HasTransitionArray() && transitions()->HasPrototypeTransitions();
}
TransitionArray* Map::transitions() const {
DCHECK(HasTransitionArray());
Object* object = READ_FIELD(this, kTransitionsOffset);
return TransitionArray::cast(object);
}
void Map::set_transitions(TransitionArray* transition_array,
WriteBarrierMode mode) {
// Transition arrays are not shared. When one is replaced, it should not
// keep referenced objects alive, so we zap it.
// When there is another reference to the array somewhere (e.g. a handle),
// not zapping turns from a waste of memory into a source of crashes.
if (HasTransitionArray()) {
#ifdef DEBUG
for (int i = 0; i < transitions()->number_of_transitions(); i++) {
Map* target = transitions()->GetTarget(i);
if (target->instance_descriptors() == instance_descriptors()) {
Name* key = transitions()->GetKey(i);
int new_target_index;
if (TransitionArray::IsSpecialTransition(key)) {
new_target_index = transition_array->SearchSpecial(Symbol::cast(key));
} else {
PropertyDetails details =
TransitionArray::GetTargetDetails(key, target);
new_target_index = transition_array->Search(details.kind(), key,
details.attributes());
}
DCHECK_NE(TransitionArray::kNotFound, new_target_index);
DCHECK_EQ(target, transition_array->GetTarget(new_target_index));
}
}
#endif
DCHECK(transitions() != transition_array);
ZapTransitions();
}
WRITE_FIELD(this, kTransitionsOffset, transition_array);
CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTransitionsOffset,
transition_array, mode);
}
void Map::init_transitions(Object* undefined) {
DCHECK(undefined->IsUndefined());
WRITE_FIELD(this, kTransitionsOffset, undefined);
}
void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
...@@ -5347,7 +5512,6 @@ ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset) ...@@ -5347,7 +5512,6 @@ ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset)
ACCESSORS(Map, constructor_or_backpointer, Object, ACCESSORS(Map, constructor_or_backpointer, Object,
kConstructorOrBackPointerOffset) kConstructorOrBackPointerOffset)
Object* Map::GetConstructor() const { Object* Map::GetConstructor() const {
Object* maybe_constructor = constructor_or_backpointer(); Object* maybe_constructor = constructor_or_backpointer();
// Follow any back pointers. // Follow any back pointers.
...@@ -5357,15 +5521,12 @@ Object* Map::GetConstructor() const { ...@@ -5357,15 +5521,12 @@ Object* Map::GetConstructor() const {
} }
return maybe_constructor; return maybe_constructor;
} }
void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) { void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) {
// Never overwrite a back pointer with a constructor. // Never overwrite a back pointer with a constructor.
DCHECK(!constructor_or_backpointer()->IsMap()); DCHECK(!constructor_or_backpointer()->IsMap());
set_constructor_or_backpointer(constructor, mode); set_constructor_or_backpointer(constructor, mode);
} }
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset) ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset) ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset)
......
...@@ -432,9 +432,8 @@ void Map::MapPrint(std::ostream& os) { // NOLINT ...@@ -432,9 +432,8 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
if (FLAG_unbox_double_fields) { if (FLAG_unbox_double_fields) {
os << "\n - layout descriptor: " << Brief(layout_descriptor()); os << "\n - layout descriptor: " << Brief(layout_descriptor());
} }
if (TransitionArray::NumberOfTransitions(raw_transitions()) > 0) { if (HasTransitionArray()) {
os << "\n - transitions: "; os << "\n - transitions: " << Brief(transitions());
TransitionArray::PrintTransitions(os, raw_transitions());
} }
os << "\n - prototype: " << Brief(prototype()); os << "\n - prototype: " << Brief(prototype());
os << "\n - constructor: " << Brief(GetConstructor()); os << "\n - constructor: " << Brief(GetConstructor());
...@@ -1139,20 +1138,19 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT ...@@ -1139,20 +1138,19 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT
void TransitionArray::Print() { void TransitionArray::Print() {
OFStream os(stdout); OFStream os(stdout);
TransitionArray::PrintTransitions(os, this); this->PrintTransitions(os);
os << std::flush; os << std::flush;
} }
void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions, void TransitionArray::PrintTransitions(std::ostream& os,
bool print_header) { // NOLINT bool print_header) { // NOLINT
int num_transitions = NumberOfTransitions(transitions);
if (print_header) { if (print_header) {
os << "Transition array " << num_transitions << "\n"; os << "Transition array " << number_of_transitions() << "\n";
} }
for (int i = 0; i < num_transitions; i++) { for (int i = 0; i < number_of_transitions(); i++) {
Name* key = GetKey(transitions, i); Name* key = GetKey(i);
Map* target = GetTarget(transitions, i); Map* target = GetTarget(i);
os << " "; os << " ";
#ifdef OBJECT_PRINT #ifdef OBJECT_PRINT
key->NamePrint(os); key->NamePrint(os);
...@@ -1160,17 +1158,16 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions, ...@@ -1160,17 +1158,16 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
key->ShortPrint(os); key->ShortPrint(os);
#endif #endif
os << ": "; os << ": ";
Heap* heap = key->GetHeap(); if (key == GetHeap()->nonextensible_symbol()) {
if (key == heap->nonextensible_symbol()) {
os << " (transition to non-extensible)"; os << " (transition to non-extensible)";
} else if (key == heap->sealed_symbol()) { } else if (key == GetHeap()->sealed_symbol()) {
os << " (transition to sealed)"; os << " (transition to sealed)";
} else if (key == heap->frozen_symbol()) { } else if (key == GetHeap()->frozen_symbol()) {
os << " (transition to frozen)"; os << " (transition to frozen)";
} else if (key == heap->elements_transition_symbol()) { } else if (key == GetHeap()->elements_transition_symbol()) {
os << " (transition to " << ElementsKindToString(target->elements_kind()) os << " (transition to " << ElementsKindToString(target->elements_kind())
<< ")"; << ")";
} else if (key == heap->observed_symbol()) { } else if (key == GetHeap()->observed_symbol()) {
os << " (transition to Object.observe)"; os << " (transition to Object.observe)";
} else { } else {
PropertyDetails details = GetTargetDetails(key, target); PropertyDetails details = GetTargetDetails(key, target);
...@@ -1180,9 +1177,7 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions, ...@@ -1180,9 +1177,7 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
} }
os << (details.kind() == kData ? "data" : "accessor"); os << (details.kind() == kData ? "data" : "accessor");
if (details.location() == kDescriptor) { if (details.location() == kDescriptor) {
Object* value = os << " " << Brief(GetTargetValue(i));
target->instance_descriptors()->GetValue(target->LastAdded());
os << " " << Brief(value);
} }
os << "), attrs: " << details.attributes(); os << "), attrs: " << details.attributes();
} }
...@@ -1192,7 +1187,8 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions, ...@@ -1192,7 +1187,8 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
void JSObject::PrintTransitions(std::ostream& os) { // NOLINT void JSObject::PrintTransitions(std::ostream& os) { // NOLINT
TransitionArray::PrintTransitions(os, map()->raw_transitions()); if (!map()->HasTransitionArray()) return;
map()->transitions()->PrintTransitions(os, false);
} }
#endif // defined(DEBUG) || defined(OBJECT_PRINT) #endif // defined(DEBUG) || defined(OBJECT_PRINT)
} } // namespace v8::internal } } // namespace v8::internal
This diff is collapsed.
...@@ -5869,11 +5869,26 @@ class Map: public HeapObject { ...@@ -5869,11 +5869,26 @@ class Map: public HeapObject {
// map with DICTIONARY_ELEMENTS was found in the prototype chain. // map with DICTIONARY_ELEMENTS was found in the prototype chain.
bool DictionaryElementsInPrototypeChainOnly(); bool DictionaryElementsInPrototypeChainOnly();
inline Map* ElementsTransitionMap(); inline bool HasTransitionArray() const;
inline bool HasElementsTransition();
inline Map* elements_transition_map();
inline Map* GetTransition(int transition_index);
inline int SearchSpecialTransition(Symbol* name);
inline int SearchTransition(PropertyKind kind, Name* name,
PropertyAttributes attributes);
inline FixedArrayBase* GetInitialElements(); inline FixedArrayBase* GetInitialElements();
DECL_ACCESSORS(raw_transitions, Object) DECL_ACCESSORS(transitions, TransitionArray)
inline void init_transitions(Object* undefined);
static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
// Try to follow an existing transition to a field with attributes NONE. The
// return value indicates whether the transition was successful.
static inline Handle<Map> FindTransitionToField(Handle<Map> map,
Handle<Name> key);
Map* FindRootMap(); Map* FindRootMap();
Map* FindFieldOwner(int descriptor); Map* FindFieldOwner(int descriptor);
...@@ -5947,8 +5962,6 @@ class Map: public HeapObject { ...@@ -5947,8 +5962,6 @@ class Map: public HeapObject {
inline Object* GetConstructor() const; inline Object* GetConstructor() const;
inline void SetConstructor(Object* constructor, inline void SetConstructor(Object* constructor,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// [back pointer]: points back to the parent map from which a transition
// leads to this map. The field overlaps with the constructor (see above).
inline Object* GetBackPointer(); inline Object* GetBackPointer();
inline void SetBackPointer(Object* value, inline void SetBackPointer(Object* value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
...@@ -5981,8 +5994,38 @@ class Map: public HeapObject { ...@@ -5981,8 +5994,38 @@ class Map: public HeapObject {
// [weak cell cache]: cache that stores a weak cell pointing to this map. // [weak cell cache]: cache that stores a weak cell pointing to this map.
DECL_ACCESSORS(weak_cell_cache, Object) DECL_ACCESSORS(weak_cell_cache, Object)
// [prototype transitions]: cache of prototype transitions.
// Prototype transition is a transition that happens
// when we change object's prototype to a new one.
// Cache format:
// 0: finger - index of the first free cell in the cache
// 1 + i: target map
inline FixedArray* GetPrototypeTransitions();
inline bool HasPrototypeTransitions();
static const int kProtoTransitionNumberOfEntriesOffset = 0;
static const int kProtoTransitionHeaderSize = 1;
inline int NumberOfProtoTransitions() {
FixedArray* cache = GetPrototypeTransitions();
if (cache->length() == 0) return 0;
return
Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value();
}
inline void SetNumberOfProtoTransitions(int value) {
FixedArray* cache = GetPrototypeTransitions();
DCHECK(cache->length() != 0);
cache->set(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value));
}
inline PropertyDetails GetLastDescriptorDetails(); inline PropertyDetails GetLastDescriptorDetails();
// The size of transition arrays are limited so they do not end up in large
// object space. Otherwise ClearNonLiveTransitions would leak memory while
// applying in-place right trimming.
inline bool CanHaveMoreTransitions();
int LastAdded() { int LastAdded() {
int number_of_own_descriptors = NumberOfOwnDescriptors(); int number_of_own_descriptors = NumberOfOwnDescriptors();
DCHECK(number_of_own_descriptors > 0); DCHECK(number_of_own_descriptors > 0);
...@@ -6150,6 +6193,11 @@ class Map: public HeapObject { ...@@ -6150,6 +6193,11 @@ class Map: public HeapObject {
// Removes a code object from the code cache at the given index. // Removes a code object from the code cache at the given index.
void RemoveFromCodeCache(Name* name, Code* code, int index); void RemoveFromCodeCache(Name* name, Code* code, int index);
// Set all map transitions from this map to dead maps to null. Also clear
// back pointers in transition targets so that we do not process this map
// again while following back pointers.
void ClearNonLiveTransitions(Heap* heap);
// Computes a hash value for this map, to be used in HashTables and such. // Computes a hash value for this map, to be used in HashTables and such.
int Hash(); int Hash();
...@@ -6215,6 +6263,18 @@ class Map: public HeapObject { ...@@ -6215,6 +6263,18 @@ class Map: public HeapObject {
inline int visitor_id(); inline int visitor_id();
inline void set_visitor_id(int visitor_id); inline void set_visitor_id(int visitor_id);
typedef void (*TraverseCallback)(Map* map, void* data);
void TraverseTransitionTree(TraverseCallback callback, void* data);
// When you set the prototype of an object using the __proto__ accessor you
// need a new map for the object (the prototype is stored in the map). In
// order not to multiply maps unnecessarily we store these as transitions in
// the original map. That way we can transition to the same map if the same
// prototype is set, rather than creating a new map every time. The
// transitions are in the form of a map where the keys are prototype objects
// and the values are the maps they transition to.
static const int kMaxCachedPrototypeTransitions = 256;
static Handle<Map> TransitionToPrototype(Handle<Map> map, static Handle<Map> TransitionToPrototype(Handle<Map> map,
Handle<Object> prototype, Handle<Object> prototype,
PrototypeOptimizationMode mode); PrototypeOptimizationMode mode);
...@@ -6228,10 +6288,6 @@ class Map: public HeapObject { ...@@ -6228,10 +6288,6 @@ class Map: public HeapObject {
static const int kPrototypeOffset = kBitField3Offset + kPointerSize; static const int kPrototypeOffset = kBitField3Offset + kPointerSize;
static const int kConstructorOrBackPointerOffset = static const int kConstructorOrBackPointerOffset =
kPrototypeOffset + kPointerSize; kPrototypeOffset + kPointerSize;
// When there is only one transition, it is stored directly in this field;
// otherwise a transition array is used.
// For prototype maps, this slot is used to store a pointer to the prototype
// object using this map.
static const int kTransitionsOffset = static const int kTransitionsOffset =
kConstructorOrBackPointerOffset + kPointerSize; kConstructorOrBackPointerOffset + kPointerSize;
static const int kDescriptorsOffset = kTransitionsOffset + kPointerSize; static const int kDescriptorsOffset = kTransitionsOffset + kPointerSize;
...@@ -6374,6 +6430,15 @@ class Map: public HeapObject { ...@@ -6374,6 +6430,15 @@ class Map: public HeapObject {
static Handle<Map> TransitionElementsToSlow(Handle<Map> object, static Handle<Map> TransitionElementsToSlow(Handle<Map> object,
ElementsKind to_kind); ElementsKind to_kind);
// Zaps the contents of backing data structures. Note that the
// heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects
// holding weak references when incremental marking is used, because it also
// iterates over objects that are otherwise unreachable.
// In general we only want to call these functions in release mode when
// heap verification is turned on.
void ZapPrototypeTransitions();
void ZapTransitions();
void DeprecateTransitionTree(); void DeprecateTransitionTree();
bool DeprecateTarget(PropertyKind kind, Name* key, bool DeprecateTarget(PropertyKind kind, Name* key,
PropertyAttributes attributes, PropertyAttributes attributes,
...@@ -6402,6 +6467,16 @@ class Map: public HeapObject { ...@@ -6402,6 +6467,16 @@ class Map: public HeapObject {
HeapType* old_field_type, HeapType* old_field_type,
HeapType* new_field_type); HeapType* new_field_type);
static inline void SetPrototypeTransitions(
Handle<Map> map,
Handle<FixedArray> prototype_transitions);
static Handle<Map> GetPrototypeTransition(Handle<Map> map,
Handle<Object> prototype);
static Handle<Map> PutPrototypeTransition(Handle<Map> map,
Handle<Object> prototype,
Handle<Map> target_map);
static const int kFastPropertiesSoftLimit = 12; static const int kFastPropertiesSoftLimit = 12;
static const int kMaxFastProperties = 128; static const int kMaxFastProperties = 128;
......
...@@ -11,19 +11,55 @@ namespace v8 { ...@@ -11,19 +11,55 @@ namespace v8 {
namespace internal { namespace internal {
#define FIELD_ADDR(p, offset) \
(reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
#define WRITE_FIELD(p, offset, value) \
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode) \
if (mode == UPDATE_WRITE_BARRIER) { \
heap->incremental_marking()->RecordWrite( \
object, HeapObject::RawField(object, offset), value); \
if (heap->InNewSpace(value)) { \
heap->RecordWrite(object->address(), offset); \
} \
}
TransitionArray* TransitionArray::cast(Object* object) { TransitionArray* TransitionArray::cast(Object* object) {
DCHECK(object->IsTransitionArray()); DCHECK(object->IsTransitionArray());
return reinterpret_cast<TransitionArray*>(object); return reinterpret_cast<TransitionArray*>(object);
} }
bool TransitionArray::HasElementsTransition() {
return SearchSpecial(GetHeap()->elements_transition_symbol()) != kNotFound;
}
Object* TransitionArray::back_pointer_storage() {
return get(kBackPointerStorageIndex);
}
void TransitionArray::set_back_pointer_storage(Object* back_pointer,
WriteBarrierMode mode) {
Heap* heap = GetHeap();
WRITE_FIELD(this, kBackPointerStorageOffset, back_pointer);
CONDITIONAL_WRITE_BARRIER(
heap, this, kBackPointerStorageOffset, back_pointer, mode);
}
bool TransitionArray::HasPrototypeTransitions() { bool TransitionArray::HasPrototypeTransitions() {
return get(kPrototypeTransitionsIndex) != Smi::FromInt(0); return IsFullTransitionArray() &&
get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
} }
FixedArray* TransitionArray::GetPrototypeTransitions() { FixedArray* TransitionArray::GetPrototypeTransitions() {
DCHECK(HasPrototypeTransitions()); // Callers must check first. DCHECK(IsFullTransitionArray());
Object* prototype_transitions = get(kPrototypeTransitionsIndex); Object* prototype_transitions = get(kPrototypeTransitionsIndex);
return FixedArray::cast(prototype_transitions); return FixedArray::cast(prototype_transitions);
} }
...@@ -31,68 +67,88 @@ FixedArray* TransitionArray::GetPrototypeTransitions() { ...@@ -31,68 +67,88 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
void TransitionArray::SetPrototypeTransitions(FixedArray* transitions, void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
WriteBarrierMode mode) { WriteBarrierMode mode) {
DCHECK(IsFullTransitionArray());
DCHECK(transitions->IsFixedArray()); DCHECK(transitions->IsFixedArray());
set(kPrototypeTransitionsIndex, transitions, mode); Heap* heap = GetHeap();
WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions);
CONDITIONAL_WRITE_BARRIER(
heap, this, kPrototypeTransitionsOffset, transitions, mode);
} }
Object** TransitionArray::GetPrototypeTransitionsSlot() { Object** TransitionArray::GetPrototypeTransitionsSlot() {
return RawFieldOfElementAt(kPrototypeTransitionsIndex); return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
kPrototypeTransitionsOffset);
} }
Object** TransitionArray::GetKeySlot(int transition_number) { Object** TransitionArray::GetKeySlot(int transition_number) {
DCHECK(!IsSimpleTransition());
DCHECK(transition_number < number_of_transitions()); DCHECK(transition_number < number_of_transitions());
return RawFieldOfElementAt(ToKeyIndex(transition_number)); return RawFieldOfElementAt(ToKeyIndex(transition_number));
} }
Name* TransitionArray::GetKey(int transition_number) { Name* TransitionArray::GetKey(int transition_number) {
if (IsSimpleTransition()) {
Map* target = GetTarget(kSimpleTransitionIndex);
int descriptor = target->LastAdded();
Name* key = target->instance_descriptors()->GetKey(descriptor);
return key;
}
DCHECK(transition_number < number_of_transitions()); DCHECK(transition_number < number_of_transitions());
return Name::cast(get(ToKeyIndex(transition_number))); return Name::cast(get(ToKeyIndex(transition_number)));
} }
Name* TransitionArray::GetKey(Object* raw_transitions, int transition_number) {
if (IsSimpleTransition(raw_transitions)) {
DCHECK(transition_number == 0);
return GetSimpleTransitionKey(GetSimpleTransition(raw_transitions));
}
DCHECK(IsFullTransitionArray(raw_transitions));
return TransitionArray::cast(raw_transitions)->GetKey(transition_number);
}
void TransitionArray::SetKey(int transition_number, Name* key) { void TransitionArray::SetKey(int transition_number, Name* key) {
DCHECK(!IsSimpleTransition());
DCHECK(transition_number < number_of_transitions()); DCHECK(transition_number < number_of_transitions());
set(ToKeyIndex(transition_number), key); set(ToKeyIndex(transition_number), key);
} }
Map* TransitionArray::GetTarget(int transition_number) { Map* TransitionArray::GetTarget(int transition_number) {
if (IsSimpleTransition()) {
DCHECK(transition_number == kSimpleTransitionIndex);
return Map::cast(get(kSimpleTransitionTarget));
}
DCHECK(transition_number < number_of_transitions()); DCHECK(transition_number < number_of_transitions());
return Map::cast(get(ToTargetIndex(transition_number))); return Map::cast(get(ToTargetIndex(transition_number)));
} }
Map* TransitionArray::GetTarget(Object* raw_transitions, void TransitionArray::SetTarget(int transition_number, Map* value) {
int transition_number) { if (IsSimpleTransition()) {
if (IsSimpleTransition(raw_transitions)) { DCHECK(transition_number == kSimpleTransitionIndex);
DCHECK(transition_number == 0); return set(kSimpleTransitionTarget, value);
return GetSimpleTransition(raw_transitions);
} }
DCHECK(IsFullTransitionArray(raw_transitions)); DCHECK(transition_number < number_of_transitions());
return TransitionArray::cast(raw_transitions)->GetTarget(transition_number); set(ToTargetIndex(transition_number), value);
} }
void TransitionArray::SetTarget(int transition_number, Map* value) { PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
DCHECK(transition_number < number_of_transitions()); Map* map = GetTarget(transition_number);
set(ToTargetIndex(transition_number), value); return map->GetLastDescriptorDetails();
}
Object* TransitionArray::GetTargetValue(int transition_number) {
Map* map = GetTarget(transition_number);
return map->instance_descriptors()->GetValue(map->LastAdded());
} }
int TransitionArray::SearchName(Name* name, int* out_insertion_index) { int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
if (IsSimpleTransition()) {
Name* key = GetKey(kSimpleTransitionIndex);
if (key->Equals(name)) return kSimpleTransitionIndex;
if (out_insertion_index != NULL) {
*out_insertion_index = key->Hash() > name->Hash() ? 0 : 1;
}
return kNotFound;
}
return internal::Search<ALL_ENTRIES>(this, name, 0, out_insertion_index); return internal::Search<ALL_ENTRIES>(this, name, 0, out_insertion_index);
} }
...@@ -169,10 +225,19 @@ void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number, ...@@ -169,10 +225,19 @@ void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number,
void TransitionArray::SetNumberOfTransitions(int number_of_transitions) { void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
DCHECK(number_of_transitions <= Capacity(this)); if (IsFullTransitionArray()) {
set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); DCHECK(number_of_transitions <= number_of_transitions_storage());
WRITE_FIELD(this, kTransitionLengthOffset,
Smi::FromInt(number_of_transitions));
}
} }
#undef FIELD_ADDR
#undef WRITE_FIELD
#undef CONDITIONAL_WRITE_BARRIER
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_TRANSITIONS_INL_H_ #endif // V8_TRANSITIONS_INL_H_
This diff is collapsed.
This diff is collapsed.
...@@ -2141,12 +2141,6 @@ TEST(InstanceOfStubWriteBarrier) { ...@@ -2141,12 +2141,6 @@ TEST(InstanceOfStubWriteBarrier) {
} }
static int NumberOfProtoTransitions(Map* map) {
return TransitionArray::NumberOfPrototypeTransitions(
TransitionArray::GetPrototypeTransitions(map));
}
TEST(PrototypeTransitionClearing) { TEST(PrototypeTransitionClearing) {
if (FLAG_never_compact) return; if (FLAG_never_compact) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
...@@ -2159,7 +2153,7 @@ TEST(PrototypeTransitionClearing) { ...@@ -2159,7 +2153,7 @@ TEST(PrototypeTransitionClearing) {
v8::Utils::OpenHandle( v8::Utils::OpenHandle(
*v8::Handle<v8::Object>::Cast( *v8::Handle<v8::Object>::Cast(
CcTest::global()->Get(v8_str("base")))); CcTest::global()->Get(v8_str("base"))));
int initialTransitions = NumberOfProtoTransitions(baseObject->map()); int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
CompileRun( CompileRun(
"var live = [];" "var live = [];"
...@@ -2172,17 +2166,16 @@ TEST(PrototypeTransitionClearing) { ...@@ -2172,17 +2166,16 @@ TEST(PrototypeTransitionClearing) {
// Verify that only dead prototype transitions are cleared. // Verify that only dead prototype transitions are cleared.
CHECK_EQ(initialTransitions + 10, CHECK_EQ(initialTransitions + 10,
NumberOfProtoTransitions(baseObject->map())); baseObject->map()->NumberOfProtoTransitions());
CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
const int transitions = 10 - 3; const int transitions = 10 - 3;
CHECK_EQ(initialTransitions + transitions, CHECK_EQ(initialTransitions + transitions,
NumberOfProtoTransitions(baseObject->map())); baseObject->map()->NumberOfProtoTransitions());
// Verify that prototype transitions array was compacted. // Verify that prototype transitions array was compacted.
FixedArray* trans = FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
TransitionArray::GetPrototypeTransitions(baseObject->map());
for (int i = initialTransitions; i < initialTransitions + transitions; i++) { for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
int j = TransitionArray::kProtoTransitionHeaderSize + i; int j = Map::kProtoTransitionHeaderSize + i;
CHECK(trans->get(j)->IsMap()); CHECK(trans->get(j)->IsMap());
} }
...@@ -2200,7 +2193,7 @@ TEST(PrototypeTransitionClearing) { ...@@ -2200,7 +2193,7 @@ TEST(PrototypeTransitionClearing) {
i::FLAG_always_compact = true; i::FLAG_always_compact = true;
Handle<Map> map(baseObject->map()); Handle<Map> map(baseObject->map());
CHECK(!space->LastPage()->Contains( CHECK(!space->LastPage()->Contains(
TransitionArray::GetPrototypeTransitions(*map)->address())); map->GetPrototypeTransitions()->address()));
CHECK(space->LastPage()->Contains(prototype->address())); CHECK(space->LastPage()->Contains(prototype->address()));
} }
...@@ -2883,7 +2876,7 @@ TEST(OptimizedAllocationArrayLiterals) { ...@@ -2883,7 +2876,7 @@ TEST(OptimizedAllocationArrayLiterals) {
static int CountMapTransitions(Map* map) { static int CountMapTransitions(Map* map) {
return TransitionArray::NumberOfTransitions(map->raw_transitions()); return map->transitions()->number_of_transitions();
} }
...@@ -3062,7 +3055,7 @@ TEST(TransitionArraySimpleToFull) { ...@@ -3062,7 +3055,7 @@ TEST(TransitionArraySimpleToFull) {
CompileRun("o = new F;" CompileRun("o = new F;"
"root = new F"); "root = new F");
root = GetByName("root"); root = GetByName("root");
DCHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions())); DCHECK(root->map()->transitions()->IsSimpleTransition());
AddPropertyTo(2, root, "happy"); AddPropertyTo(2, root, "happy");
// Count number of live transitions after marking. Note that one transition // Count number of live transitions after marking. Note that one transition
......
...@@ -342,10 +342,9 @@ class Expectations { ...@@ -342,10 +342,9 @@ class Expectations {
SetDataField(property_index, attributes, representation, heap_type); SetDataField(property_index, attributes, representation, heap_type);
Handle<String> name = MakeName("prop", property_index); Handle<String> name = MakeName("prop", property_index);
Map* target = int t = map->SearchTransition(kData, *name, attributes);
TransitionArray::SearchTransition(*map, kData, *name, attributes); CHECK_NE(TransitionArray::kNotFound, t);
CHECK(target != NULL); return handle(map->GetTransition(t));
return handle(target);
} }
Handle<Map> AddAccessorConstant(Handle<Map> map, Handle<Map> AddAccessorConstant(Handle<Map> map,
...@@ -1478,10 +1477,9 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { ...@@ -1478,10 +1477,9 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
} }
Handle<String> name = MakeName("prop", i); Handle<String> name = MakeName("prop", i);
Map* target = int t = map2->SearchTransition(kData, *name, NONE);
TransitionArray::SearchTransition(*map2, kData, *name, NONE); CHECK_NE(TransitionArray::kNotFound, t);
CHECK(target != NULL); map2 = handle(map2->GetTransition(t));
map2 = handle(target);
} }
map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE, map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE,
...@@ -1501,12 +1499,12 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { ...@@ -1501,12 +1499,12 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
// Fill in transition tree of |map2| so that it can't have more transitions. // Fill in transition tree of |map2| so that it can't have more transitions.
for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) { for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) {
CHECK(TransitionArray::CanHaveMoreTransitions(map2)); CHECK(map2->CanHaveMoreTransitions());
Handle<String> name = MakeName("foo", i); Handle<String> name = MakeName("foo", i);
Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(), Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(),
INSERT_TRANSITION).ToHandleChecked(); INSERT_TRANSITION).ToHandleChecked();
} }
CHECK(!TransitionArray::CanHaveMoreTransitions(map2)); CHECK(!map2->CanHaveMoreTransitions());
// Try to update |map|, since there is no place for propX transition at |map2| // Try to update |map|, since there is no place for propX transition at |map2|
// |map| should become "copy-generalized". // |map| should become "copy-generalized".
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment