| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 250e009b24f12c24582900bb2a4bcd89b77ab349..c9e34d587d23cdca1ed3e7fd8bb1a7861ddea4d8 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1764,23 +1764,6 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition(
|
| Map* old_target = old_map->GetTransition(transition_index);
|
| Object* result;
|
|
|
| - // To sever a transition to a map with which the descriptors are shared, the
|
| - // larger map (more descriptors) needs to store its own descriptors array.
|
| - // Both sides of the severed chain need to have their own descriptors pointer
|
| - // to store distinct descriptor arrays.
|
| -
|
| - // If the old_target did not yet store its own descriptors, the new
|
| - // descriptors pointer is created for the old_target by temporarily clearing
|
| - // the back pointer and setting its descriptor array.
|
| -
|
| - // This phase is executed before creating the new map since it requires
|
| - // allocation that may fail.
|
| - if (!old_target->StoresOwnDescriptors()) {
|
| - DescriptorArray* old_descriptors = old_map->instance_descriptors();
|
| - MaybeObject* maybe_failure = old_target->SetDescriptors(old_descriptors);
|
| - if (maybe_failure->IsFailure()) return maybe_failure;
|
| - }
|
| -
|
| MaybeObject* maybe_result =
|
| ConvertDescriptorToField(name, new_value, attributes);
|
| if (!maybe_result->To(&result)) return maybe_result;
|
| @@ -1801,8 +1784,7 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition(
|
| old_target->instance_descriptors() == old_map->instance_descriptors()) {
|
| // Since the conversion above generated a new fast map with an additional
|
| // property which can be shared as well, install this descriptor pointer
|
| - // along the entire chain of smaller maps; and remove the transition array
|
| - // that is only in place to hold the descriptor array in the new map.
|
| + // along the entire chain of smaller maps.
|
| Map* map;
|
| DescriptorArray* new_descriptors = new_map->instance_descriptors();
|
| DescriptorArray* old_descriptors = old_map->instance_descriptors();
|
| @@ -1810,14 +1792,11 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition(
|
| !current->IsUndefined();
|
| current = map->GetBackPointer()) {
|
| map = Map::cast(current);
|
| - if (!map->HasTransitionArray()) break;
|
| - TransitionArray* transitions = map->transitions();
|
| - if (transitions->descriptors() != old_descriptors) break;
|
| + if (map->instance_descriptors() != old_descriptors) break;
|
| map->SetEnumLength(Map::kInvalidEnumCache);
|
| - transitions->set_descriptors(new_descriptors);
|
| + map->set_instance_descriptors(new_descriptors);
|
| }
|
| old_map->set_owns_descriptors(false);
|
| - new_map->ClearTransitions(GetHeap());
|
| }
|
|
|
| old_map->SetTransition(transition_index, new_map);
|
| @@ -2201,7 +2180,7 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
|
| new_descriptors->CopyFrom(i, *descriptors, i, witness);
|
| }
|
|
|
| - Map::SetDescriptors(map, new_descriptors);
|
| + map->set_instance_descriptors(*new_descriptors);
|
| }
|
|
|
|
|
| @@ -4229,13 +4208,6 @@ bool JSReceiver::IsSimpleEnum() {
|
| }
|
|
|
|
|
| -void Map::SetDescriptors(Handle<Map> map,
|
| - Handle<DescriptorArray> descriptors) {
|
| - Isolate* isolate = map->GetIsolate();
|
| - CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors));
|
| -}
|
| -
|
| -
|
| int Map::NumberOfDescribedProperties(DescriptorFlag which,
|
| PropertyAttributes filter) {
|
| int result = 0;
|
| @@ -5013,37 +4985,37 @@ MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors,
|
|
|
| new_descriptors->Append(descriptor, witness);
|
|
|
| - // If the source descriptors had an enum cache we copy it. This ensures that
|
| - // the maps to which we push the new descriptor array back can rely on a
|
| - // cache always being available once it is set. If the map has more
|
| - // enumerated descriptors than available in the original cache, the cache
|
| - // will be lazily replaced by the extended cache when needed.
|
| - if (descriptors->HasEnumCache()) {
|
| - new_descriptors->CopyEnumCacheFrom(descriptors);
|
| - }
|
| + if (old_size > 0) {
|
| + // If the source descriptors had an enum cache we copy it. This ensures
|
| + // that the maps to which we push the new descriptor array back can rely
|
| + // on a cache always being available once it is set. If the map has more
|
| + // enumerated descriptors than available in the original cache, the cache
|
| + // will be lazily replaced by the extended cache when needed.
|
| + if (descriptors->HasEnumCache()) {
|
| + new_descriptors->CopyEnumCacheFrom(descriptors);
|
| + }
|
|
|
| - Map* map;
|
| - // Replace descriptors by new_descriptors in all maps that share it.
|
| - for (Object* current = GetBackPointer();
|
| - !current->IsUndefined();
|
| - current = map->GetBackPointer()) {
|
| - map = Map::cast(current);
|
| - if (!map->HasTransitionArray()) break;
|
| - TransitionArray* transitions = map->transitions();
|
| - if (transitions->descriptors() != descriptors) break;
|
| - transitions->set_descriptors(new_descriptors);
|
| - }
|
| + Map* map;
|
| + // Replace descriptors by new_descriptors in all maps that share it.
|
| + for (Object* current = GetBackPointer();
|
| + !current->IsUndefined();
|
| + current = map->GetBackPointer()) {
|
| + map = Map::cast(current);
|
| + if (map->instance_descriptors() != descriptors) break;
|
| + map->set_instance_descriptors(new_descriptors);
|
| + }
|
|
|
| - transitions->set_descriptors(new_descriptors);
|
| + set_instance_descriptors(new_descriptors);
|
| + }
|
| }
|
|
|
| - set_transitions(transitions);
|
| result->SetBackPointer(this);
|
| - set_owns_descriptors(false);
|
| -
|
| - result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors());
|
| + result->InitializeDescriptors(new_descriptors);
|
| ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1);
|
|
|
| + set_transitions(transitions);
|
| + set_owns_descriptors(false);
|
| +
|
| return result;
|
| }
|
|
|
| @@ -5058,13 +5030,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
|
| MaybeObject* maybe_result = CopyDropDescriptors();
|
| if (!maybe_result->To(&result)) return maybe_result;
|
|
|
| - // Unless we are creating a map with no descriptors and no back pointer, we
|
| - // insert the descriptor array locally.
|
| - if (!descriptors->IsEmpty()) {
|
| - MaybeObject* maybe_failure = result->SetDescriptors(descriptors);
|
| - if (maybe_failure->IsFailure()) return maybe_failure;
|
| - result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors());
|
| - }
|
| + result->InitializeDescriptors(descriptors);
|
|
|
| if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
|
| TransitionArray* transitions;
|
| @@ -5075,23 +5041,6 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
|
| MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
|
| if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
|
|
| - if (descriptors->IsEmpty()) {
|
| - if (owns_descriptors()) {
|
| - // If the copied map has no added fields, and the parent map owns its
|
| - // descriptors, those descriptors have to be empty. In that case,
|
| - // transfer ownership of the descriptors to the new child.
|
| - ASSERT(instance_descriptors()->IsEmpty());
|
| - set_owns_descriptors(false);
|
| - } else {
|
| - // If the parent did not own its own descriptors, it may share a larger
|
| - // descriptors array already. In that case, force a split by setting
|
| - // the descriptor array of the new map to the empty descriptor array.
|
| - MaybeObject* maybe_failure =
|
| - result->SetDescriptors(GetHeap()->empty_descriptor_array());
|
| - if (maybe_failure->IsFailure()) return maybe_failure;
|
| - }
|
| - }
|
| -
|
| set_transitions(transitions);
|
| result->SetBackPointer(this);
|
| }
|
| @@ -5113,7 +5062,10 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
|
| ASSERT(kind != elements_kind());
|
| }
|
|
|
| - if (flag == INSERT_TRANSITION && owns_descriptors()) {
|
| + bool insert_transition =
|
| + flag == INSERT_TRANSITION && !HasElementsTransition();
|
| +
|
| + if (insert_transition && owns_descriptors()) {
|
| // In case the map owned its own descriptors, share the descriptors and
|
| // transfer ownership to the new map.
|
| Map* new_map;
|
| @@ -5124,8 +5076,8 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
|
| if (added_elements->IsFailure()) return added_elements;
|
|
|
| new_map->set_elements_kind(kind);
|
| + new_map->InitializeDescriptors(instance_descriptors());
|
| new_map->SetBackPointer(this);
|
| - new_map->SetNumberOfOwnDescriptors(NumberOfOwnDescriptors());
|
| set_owns_descriptors(false);
|
| return new_map;
|
| }
|
| @@ -5136,24 +5088,12 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
|
| Map* new_map;
|
| MaybeObject* maybe_new_map = Copy();
|
| if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
| - ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors());
|
| +
|
| new_map->set_elements_kind(kind);
|
|
|
| - if (flag == INSERT_TRANSITION && !HasElementsTransition()) {
|
| - // Map::Copy does not store the descriptor array in case it is empty, since
|
| - // it does not insert a back pointer; implicitly indicating that its
|
| - // descriptor array is empty. Since in this case we do want to insert a back
|
| - // pointer, we have to manually set the empty descriptor array to force a
|
| - // split.
|
| - if (!new_map->StoresOwnDescriptors()) {
|
| - ASSERT(new_map->NumberOfOwnDescriptors() == 0);
|
| - MaybeObject* maybe_failure =
|
| - new_map->SetDescriptors(GetHeap()->empty_descriptor_array());
|
| - if (maybe_failure->IsFailure()) return maybe_failure;
|
| - }
|
| + if (insert_transition) {
|
| MaybeObject* added_elements = set_elements_transition_map(new_map);
|
| if (added_elements->IsFailure()) return added_elements;
|
| -
|
| new_map->SetBackPointer(this);
|
| }
|
|
|
| @@ -7467,14 +7407,8 @@ static void TrimDescriptorArray(Heap* heap,
|
|
|
| // Clear a possible back pointer in case the transition leads to a dead map.
|
| // Return true in case a back pointer has been cleared and false otherwise.
|
| -static bool ClearBackPointer(Heap* heap,
|
| - Map* target,
|
| - DescriptorArray* descriptors,
|
| - bool* descriptors_owner_died) {
|
| +static bool ClearBackPointer(Heap* heap, Map* target) {
|
| if (Marking::MarkBitFrom(target).Get()) return false;
|
| - if (target->instance_descriptors() == descriptors) {
|
| - *descriptors_owner_died = true;
|
| - }
|
| target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
|
| return true;
|
| }
|
| @@ -7494,13 +7428,18 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
|
|
|
| int transition_index = 0;
|
|
|
| - DescriptorArray* descriptors = t->descriptors();
|
| + DescriptorArray* descriptors = instance_descriptors();
|
| bool descriptors_owner_died = false;
|
|
|
| // Compact all live descriptors to the left.
|
| for (int i = 0; i < t->number_of_transitions(); ++i) {
|
| Map* target = t->GetTarget(i);
|
| - if (!ClearBackPointer(heap, target, descriptors, &descriptors_owner_died)) {
|
| + if (ClearBackPointer(heap, target)) {
|
| + if (target->instance_descriptors() == descriptors) {
|
| + descriptors_owner_died = true;
|
| + descriptors_owner_died = true;
|
| + }
|
| + } else {
|
| if (i != transition_index) {
|
| String* key = t->GetKey(i);
|
| t->SetKey(transition_index, key);
|
| @@ -7514,10 +7453,10 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
|
| }
|
|
|
| if (t->HasElementsTransition() &&
|
| - ClearBackPointer(heap,
|
| - t->elements_transition(),
|
| - descriptors,
|
| - &descriptors_owner_died)) {
|
| + 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.
|
| @@ -7533,7 +7472,7 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
|
| TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
|
| ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
|
| } else {
|
| - t->set_descriptors(heap->empty_descriptor_array());
|
| + ASSERT(descriptors == GetHeap()->empty_descriptor_array());
|
| }
|
| }
|
|
|
| @@ -13015,8 +12954,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
|
|
|
| descriptors->Sort();
|
|
|
| - MaybeObject* maybe_failure = new_map->InitializeDescriptors(descriptors);
|
| - if (maybe_failure->IsFailure()) return maybe_failure;
|
| + new_map->InitializeDescriptors(descriptors);
|
| new_map->set_unused_property_fields(unused_property_fields);
|
|
|
| // Transform the object.
|
|
|