Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Revert "Promoting elements transitions to their own field."

This reverts commit 09c97a6df060a7f8de6ce24457da11d6853f1a38.
  • Loading branch information...
commit 65f63527feb02ddb4b18138da93d643725d6825c 1 parent ae5b0e1
@piscisaureus piscisaureus authored
View
2  deps/v8/src/arm/macro-assembler-arm.cc
@@ -2016,7 +2016,7 @@ void MacroAssembler::CompareMap(Register obj_map,
Map* current_map = *map;
while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
kind = GetNextMoreGeneralFastElementsKind(kind, packed);
- current_map = current_map->LookupElementsTransitionMap(kind);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
if (!current_map) break;
b(eq, early_success);
cmp(obj_map, Operand(Handle<Map>(current_map)));
View
1  deps/v8/src/ast.cc
@@ -514,6 +514,7 @@ bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
// We don't know the target.
return false;
case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
// Perhaps something interesting is up in the prototype chain...
View
6 deps/v8/src/bootstrapper.cc
@@ -1632,10 +1632,9 @@ bool Genesis::InstallNatives() {
// through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT
// transition easy to trap. Moreover, they rarely are smi-only.
MaybeObject* maybe_map =
- array_function->initial_map()->CopyDropTransitions(
- DescriptorArray::MAY_BE_SHARED);
+ array_function->initial_map()->CopyDropTransitions();
Map* new_map;
- if (!maybe_map->To(&new_map)) return false;
+ if (!maybe_map->To<Map>(&new_map)) return false;
new_map->set_elements_kind(FAST_HOLEY_ELEMENTS);
array_function->set_initial_map(new_map);
@@ -2192,6 +2191,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
break;
}
case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
// Ignore non-properties.
View
9 deps/v8/src/factory.cc
@@ -115,8 +115,7 @@ Handle<ObjectHashTable> Factory::NewObjectHashTable(int at_least_space_for) {
Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
ASSERT(0 <= number_of_descriptors);
CALL_HEAP_FUNCTION(isolate(),
- DescriptorArray::Allocate(number_of_descriptors,
- DescriptorArray::MAY_BE_SHARED),
+ DescriptorArray::Allocate(number_of_descriptors),
DescriptorArray);
}
@@ -497,9 +496,7 @@ Handle<Map> Factory::CopyMap(Handle<Map> src,
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
- CALL_HEAP_FUNCTION(isolate(),
- src->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED),
- Map);
+ CALL_HEAP_FUNCTION(isolate(), src->CopyDropTransitions(), Map);
}
@@ -942,7 +939,7 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
Handle<String> key =
SymbolFromString(Handle<String>(String::cast(entry->name())));
// Check if a descriptor with this name already exists before writing.
- if (result->LinearSearch(EXPECT_UNSORTED, *key, descriptor_count) ==
+ if (result->LinearSearch(*key, descriptor_count) ==
DescriptorArray::kNotFound) {
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
result->Set(descriptor_count, &desc, witness);
View
6 deps/v8/src/heap.cc
@@ -3671,8 +3671,7 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
Map* new_map;
ASSERT(object_function->has_initial_map());
{ MaybeObject* maybe_map =
- object_function->initial_map()->CopyDropTransitions(
- DescriptorArray::MAY_BE_SHARED);
+ object_function->initial_map()->CopyDropTransitions();
if (!maybe_map->To<Map>(&new_map)) return maybe_map;
}
Object* prototype;
@@ -3820,8 +3819,7 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
fun->shared()->ForbidInlineConstructor();
} else {
DescriptorArray* descriptors;
- { MaybeObject* maybe_descriptors_obj =
- DescriptorArray::Allocate(count, DescriptorArray::MAY_BE_SHARED);
+ { MaybeObject* maybe_descriptors_obj = DescriptorArray::Allocate(count);
if (!maybe_descriptors_obj->To<DescriptorArray>(&descriptors)) {
return maybe_descriptors_obj;
}
View
2  deps/v8/src/hydrogen-instructions.h
@@ -2104,7 +2104,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
kind = GetNextMoreGeneralFastElementsKind(kind, packed);
Map* transitioned_map =
- map->LookupElementsTransitionMap(kind);
+ map->LookupElementsTransitionMap(kind, NULL);
if (transitioned_map) {
map_set->Add(Handle<Map>(transitioned_map), zone);
}
View
2  deps/v8/src/ia32/macro-assembler-ia32.cc
@@ -566,7 +566,7 @@ void MacroAssembler::CompareMap(Register obj,
Map* current_map = *map;
while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
kind = GetNextMoreGeneralFastElementsKind(kind, packed);
- current_map = current_map->LookupElementsTransitionMap(kind);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
if (!current_map) break;
j(equal, early_success, Label::kNear);
cmp(FieldOperand(obj, HeapObject::kMapOffset),
View
2  deps/v8/src/ic.cc
@@ -1511,6 +1511,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
break;
case CONSTANT_FUNCTION:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
return;
case HANDLER:
case NULL_DESCRIPTOR:
@@ -1974,6 +1975,7 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
case CALLBACKS:
case INTERCEPTOR:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
// Always rewrite to the generic case so that we do not
// repeatedly try to rewrite.
code = (strict_mode == kStrictMode)
View
17 deps/v8/src/mark-compact.cc
@@ -1883,17 +1883,6 @@ void Marker<T>::MarkDescriptorArray(DescriptorArray* descriptors) {
enum_cache);
}
- // TODO(verwaest) Make sure we free unused transitions.
- if (descriptors->elements_transition_map() != NULL) {
- Object** transitions_slot = descriptors->GetTransitionsSlot();
- Object* transitions = *transitions_slot;
- base_marker()->MarkObjectAndPush(
- reinterpret_cast<HeapObject*>(transitions));
- mark_compact_collector()->RecordSlot(descriptor_start,
- transitions_slot,
- transitions);
- }
-
// If the descriptor contains a transition (value is a Map), we don't mark the
// value as live. It might be set to the NULL_DESCRIPTOR in
// ClearNonLiveTransitions later.
@@ -1932,6 +1921,12 @@ void Marker<T>::MarkDescriptorArray(DescriptorArray* descriptors) {
MarkAccessorPairSlot(accessors, AccessorPair::kSetterOffset);
}
break;
+ case ELEMENTS_TRANSITION:
+ // For maps with multiple elements transitions, the transition maps are
+ // stored in a FixedArray. Keep the fixed array alive but not the maps
+ // that it refers to.
+ if (value->IsFixedArray()) base_marker()->MarkObjectWithoutPush(value);
+ break;
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
View
2  deps/v8/src/mips/macro-assembler-mips.cc
@@ -3491,7 +3491,7 @@ void MacroAssembler::CompareMapAndBranch(Register obj_map,
Map* current_map = *map;
while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
kind = GetNextMoreGeneralFastElementsKind(kind, packed);
- current_map = current_map->LookupElementsTransitionMap(kind);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
if (!current_map) break;
Branch(early_success, eq, obj_map, right);
right = Operand(Handle<Map>(current_map));
View
15 deps/v8/src/objects-debug.cc
@@ -929,6 +929,21 @@ bool DescriptorArray::IsConsistentWithBackPointers(Map* current_map) {
return false;
}
break;
+ case ELEMENTS_TRANSITION: {
+ Object* object = GetValue(i);
+ if (!CheckOneBackPointer(current_map, object)) {
+ return false;
+ }
+ if (object->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(object);
+ for (int i = 0; i < array->length(); ++i) {
+ if (!CheckOneBackPointer(current_map, array->get(i))) {
+ return false;
+ }
+ }
+ }
+ break;
+ }
case CALLBACKS: {
Object* object = GetValue(i);
if (object->IsAccessorPair()) {
View
63 deps/v8/src/objects-inl.h
@@ -1876,14 +1876,9 @@ Object** FixedArray::data_start() {
bool DescriptorArray::IsEmpty() {
ASSERT(this->IsSmi() ||
- this->MayContainTransitions() ||
+ this->length() > kFirstIndex ||
this == HEAP->empty_descriptor_array());
- return this->IsSmi() || length() < kFirstIndex;
-}
-
-
-bool DescriptorArray::MayContainTransitions() {
- return length() >= kTransitionsIndex;
+ return this->IsSmi() || length() <= kFirstIndex;
}
@@ -1893,7 +1888,7 @@ int DescriptorArray::bit_field3_storage() {
}
void DescriptorArray::set_bit_field3_storage(int value) {
- ASSERT(this->MayContainTransitions());
+ ASSERT(!IsEmpty());
WRITE_FIELD(this, kBitField3StorageOffset, Smi::FromInt(value));
}
@@ -1917,7 +1912,7 @@ int DescriptorArray::Search(String* name) {
// Fast case: do linear search for small arrays.
const int kMaxElementsForLinearSearch = 8;
if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) {
- return LinearSearch(EXPECT_SORTED, name, nof);
+ return LinearSearch(name, nof);
}
// Slow case: perform binary search.
@@ -1935,30 +1930,6 @@ int DescriptorArray::SearchWithCache(String* name) {
}
-Map* DescriptorArray::elements_transition_map() {
- if (!this->MayContainTransitions()) {
- return NULL;
- }
- Object* transition_map = get(kTransitionsIndex);
- if (transition_map == Smi::FromInt(0)) {
- return NULL;
- } else {
- return Map::cast(transition_map);
- }
-}
-
-
-void DescriptorArray::set_elements_transition_map(
- Map* transition_map, WriteBarrierMode mode) {
- ASSERT(this->length() > kTransitionsIndex);
- Heap* heap = GetHeap();
- WRITE_FIELD(this, kTransitionsOffset, transition_map);
- CONDITIONAL_WRITE_BARRIER(
- heap, this, kTransitionsOffset, transition_map, mode);
- ASSERT(DescriptorArray::cast(this));
-}
-
-
Object** DescriptorArray::GetKeySlot(int descriptor_number) {
ASSERT(descriptor_number < number_of_descriptors());
return HeapObject::RawField(
@@ -2044,6 +2015,7 @@ bool DescriptorArray::IsTransitionOnly(int descriptor_number) {
switch (GetType(descriptor_number)) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
return true;
case CALLBACKS: {
Object* value = GetValue(descriptor_number);
@@ -3499,16 +3471,6 @@ Object* Map::GetBackPointer() {
}
-Map* Map::elements_transition_map() {
- return instance_descriptors()->elements_transition_map();
-}
-
-
-void Map::set_elements_transition_map(Map* transitioned_map) {
- return instance_descriptors()->set_elements_transition_map(transitioned_map);
-}
-
-
void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
Heap* heap = GetHeap();
ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
@@ -4161,12 +4123,15 @@ MaybeObject* JSFunction::set_initial_map_and_cache_transitions(
maps->set(kind, current_map);
for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
i < kFastElementsKindCount; ++i) {
- Map* new_map;
- ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
- MaybeObject* maybe_new_map =
- current_map->CreateNextElementsTransition(next_kind);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- maps->set(next_kind, new_map);
+ ElementsKind transitioned_kind = GetFastElementsKindFromSequenceIndex(i);
+ MaybeObject* maybe_new_map = current_map->CopyDropTransitions();
+ Map* new_map = NULL;
+ if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
+ new_map->set_elements_kind(transitioned_kind);
+ maybe_new_map = current_map->AddElementsTransition(transitioned_kind,
+ new_map);
+ if (maybe_new_map->IsFailure()) return maybe_new_map;
+ maps->set(transitioned_kind, new_map);
current_map = new_map;
}
global_context->set_js_array_maps(maps);
View
22 deps/v8/src/objects-printer.cc
@@ -273,6 +273,25 @@ void JSObject::PrintProperties(FILE* out) {
descs->GetCallbacksObject(i)->ShortPrint(out);
PrintF(out, " (callback)\n");
break;
+ case ELEMENTS_TRANSITION: {
+ PrintF(out, "(elements transition to ");
+ Object* descriptor_contents = descs->GetValue(i);
+ if (descriptor_contents->IsMap()) {
+ Map* map = Map::cast(descriptor_contents);
+ PrintElementsKind(out, map->elements_kind());
+ } else {
+ FixedArray* map_array = FixedArray::cast(descriptor_contents);
+ for (int i = 0; i < map_array->length(); ++i) {
+ Map* map = Map::cast(map_array->get(i));
+ if (i != 0) {
+ PrintF(out, ", ");
+ }
+ PrintElementsKind(out, map->elements_kind());
+ }
+ }
+ PrintF(out, ")\n");
+ break;
+ }
case MAP_TRANSITION:
PrintF(out, "(map transition)\n");
break;
@@ -419,9 +438,6 @@ void JSObject::JSObjectPrint(FILE* out) {
PrintF(out,
"]\n - prototype = %p\n",
reinterpret_cast<void*>(GetPrototype()));
- PrintF(out,
- " - elements transition to = %p\n",
- reinterpret_cast<void*>(map()->elements_transition_map()));
PrintF(out, " {\n");
PrintProperties(out);
PrintElements(out);
View
480 deps/v8/src/objects.cc
@@ -639,6 +639,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
recvr, name, attributes);
}
case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
break;
@@ -1562,7 +1563,10 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// Element transitions are stored in the descriptor for property "", which is
// not a identifier and should have forced a switch to slow properties above.
- bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound;
+ ASSERT(descriptor_index == DescriptorArray::kNotFound ||
+ old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
+ bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
+ old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
bool allow_map_transition =
can_insert_transition &&
(isolate->context()->global_context()->object_function()->map() != map());
@@ -1608,9 +1612,7 @@ MaybeObject* JSObject::AddFastProperty(String* name,
}
// We have now allocated all the necessary objects.
// All the changes can be applied at once, so they are atomic.
- if (allow_map_transition) {
- map()->set_instance_descriptors(old_descriptors);
- }
+ map()->set_instance_descriptors(old_descriptors);
new_map->SetBackPointer(map());
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
set_map(new_map);
@@ -2155,6 +2157,7 @@ MaybeObject* JSObject::SetPropertyViaPrototypes(
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
+ case ELEMENTS_TRANSITION:
break;
}
}
@@ -2225,8 +2228,9 @@ Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
if (IsTransitionableFastElementsKind(kind)) {
while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
kind = GetNextMoreGeneralFastElementsKind(kind, false);
+ bool dummy = true;
Handle<Map> maybe_transitioned_map =
- MaybeNull(current_map->LookupElementsTransitionMap(kind));
+ MaybeNull(current_map->LookupElementsTransitionMap(kind, &dummy));
if (maybe_transitioned_map.is_null()) break;
if (ContainsMap(candidates, maybe_transitioned_map) &&
(packed || !IsFastPackedElementsKind(kind))) {
@@ -2240,68 +2244,207 @@ Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
}
-static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
- Map* current_map = map;
- int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
- int to_index = GetSequenceIndexFromFastElementsKind(to_kind);
- for (; index < to_index; ++index) {
- Map* next_map = current_map->elements_transition_map();
- if (next_map == NULL) {
- return current_map;
+static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
+ ElementsKind elements_kind) {
+ if (descriptor_contents->IsMap()) {
+ Map* map = Map::cast(descriptor_contents);
+ if (map->elements_kind() == elements_kind) {
+ return map;
}
- current_map = next_map;
+ return NULL;
}
- ASSERT(current_map->elements_kind() == to_kind);
- return current_map;
+
+ FixedArray* map_array = FixedArray::cast(descriptor_contents);
+ for (int i = 0; i < map_array->length(); ++i) {
+ Object* current = map_array->get(i);
+ // Skip undefined slots, they are sentinels for reclaimed maps.
+ if (!current->IsUndefined()) {
+ Map* current_map = Map::cast(map_array->get(i));
+ if (current_map->elements_kind() == elements_kind) {
+ return current_map;
+ }
+ }
+ }
+
+ return NULL;
}
-Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
- if (this->instance_descriptors()->MayContainTransitions() &&
- IsMoreGeneralElementsKindTransition(this->elements_kind(), to_kind)) {
- Map* to_map = FindClosestElementsTransition(this, to_kind);
- if (to_map->elements_kind() == to_kind) {
- return to_map;
+static MaybeObject* AddElementsTransitionMapToDescriptor(
+ Object* descriptor_contents,
+ Map* new_map) {
+ // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
+ // simply add the map.
+ if (descriptor_contents == NULL) {
+ return new_map;
+ }
+
+ // There was already a map in the descriptor, create a 2-element FixedArray
+ // to contain the existing map plus the new one.
+ FixedArray* new_array;
+ Heap* heap = new_map->GetHeap();
+ if (descriptor_contents->IsMap()) {
+ // Must tenure, DescriptorArray expects no new-space objects.
+ MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
+ if (!maybe_new_array->To<FixedArray>(&new_array)) {
+ return maybe_new_array;
+ }
+ new_array->set(0, descriptor_contents);
+ new_array->set(1, new_map);
+ return new_array;
+ }
+
+ // The descriptor already contained a list of maps for different ElementKinds
+ // of ELEMENTS_TRANSITION, first check the existing array for an undefined
+ // slot, and if that's not available, create a FixedArray to hold the existing
+ // maps plus the new one and fill it in.
+ FixedArray* array = FixedArray::cast(descriptor_contents);
+ for (int i = 0; i < array->length(); ++i) {
+ if (array->get(i)->IsUndefined()) {
+ array->set(i, new_map);
+ return array;
}
}
- return NULL;
+
+ // Must tenure, DescriptorArray expects no new-space objects.
+ MaybeObject* maybe_new_array =
+ heap->AllocateFixedArray(array->length() + 1, TENURED);
+ if (!maybe_new_array->To<FixedArray>(&new_array)) {
+ return maybe_new_array;
+ }
+ int i = 0;
+ while (i < array->length()) {
+ new_array->set(i, array->get(i));
+ ++i;
+ }
+ new_array->set(i, new_map);
+ return new_array;
}
-MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
- ASSERT(elements_transition_map() == NULL);
- ASSERT(GetSequenceIndexFromFastElementsKind(elements_kind()) ==
- (GetSequenceIndexFromFastElementsKind(next_kind) - 1));
+String* Map::elements_transition_sentinel_name() {
+ return GetHeap()->empty_symbol();
+}
- Map* next_map;
- MaybeObject* maybe_next_map =
- this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED);
- if (!maybe_next_map->To(&next_map)) return maybe_next_map;
- next_map->set_elements_kind(next_kind);
- next_map->SetBackPointer(this);
- this->set_elements_transition_map(next_map);
- return next_map;
+Object* Map::GetDescriptorContents(String* sentinel_name,
+ bool* safe_to_add_transition) {
+ // Get the cached index for the descriptors lookup, or find and cache it.
+ DescriptorArray* descriptors = instance_descriptors();
+ DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
+ int index = cache->Lookup(descriptors, sentinel_name);
+ if (index == DescriptorLookupCache::kAbsent) {
+ index = descriptors->Search(sentinel_name);
+ cache->Update(descriptors, sentinel_name, index);
+ }
+ // If the transition already exists, return its descriptor.
+ if (index != DescriptorArray::kNotFound) {
+ PropertyDetails details = descriptors->GetDetails(index);
+ if (details.type() == ELEMENTS_TRANSITION) {
+ return descriptors->GetValue(index);
+ } else {
+ if (safe_to_add_transition != NULL) {
+ *safe_to_add_transition = false;
+ }
+ }
+ }
+ return NULL;
}
-static MaybeObject* AddMissingElementsTransitions(Map* map,
- ElementsKind to_kind) {
- int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()) + 1;
- int to_index = GetSequenceIndexFromFastElementsKind(to_kind);
- ASSERT(index <= to_index);
+Map* Map::LookupElementsTransitionMap(ElementsKind to_kind,
+ bool* safe_to_add_transition) {
+ ElementsKind from_kind = elements_kind();
+ if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
+ if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
+ if (safe_to_add_transition) *safe_to_add_transition = false;
+ return NULL;
+ }
+ ElementsKind transitioned_from_kind =
+ GetNextMoreGeneralFastElementsKind(from_kind, false);
- Map* current_map = map;
- for (; index <= to_index; ++index) {
- ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index);
- MaybeObject* maybe_next_map =
- current_map->CreateNextElementsTransition(next_kind);
- if (!maybe_next_map->To(&current_map)) return maybe_next_map;
+ // If the transition is a single step in the transition sequence, fall
+ // through to looking it up and returning it. If it requires several steps,
+ // divide and conquer.
+ if (transitioned_from_kind != to_kind) {
+ // If the transition is several steps in the lattice, divide and conquer.
+ Map* from_map = LookupElementsTransitionMap(transitioned_from_kind,
+ safe_to_add_transition);
+ if (from_map == NULL) return NULL;
+ return from_map->LookupElementsTransitionMap(to_kind,
+ safe_to_add_transition);
+ }
+ }
+ Object* descriptor_contents = GetDescriptorContents(
+ elements_transition_sentinel_name(), safe_to_add_transition);
+ if (descriptor_contents != NULL) {
+ Map* maybe_transition_map =
+ GetElementsTransitionMapFromDescriptor(descriptor_contents,
+ to_kind);
+ ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
+ return maybe_transition_map;
}
+ return NULL;
+}
- ASSERT(current_map->elements_kind() == to_kind);
- return current_map;
+
+MaybeObject* Map::AddElementsTransition(ElementsKind to_kind,
+ Map* transitioned_map) {
+ ElementsKind from_kind = elements_kind();
+ if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
+ ASSERT(IsMoreGeneralElementsKindTransition(from_kind, to_kind));
+ ElementsKind transitioned_from_kind =
+ GetNextMoreGeneralFastElementsKind(from_kind, false);
+ // The map transitions graph should be a tree, therefore transitions to
+ // ElementsKind that are not adjacent in the ElementsKind sequence are not
+ // done directly, but instead by going through intermediate ElementsKinds
+ // first.
+ if (to_kind != transitioned_from_kind) {
+ bool safe_to_add = true;
+ Map* intermediate_map = LookupElementsTransitionMap(
+ transitioned_from_kind, &safe_to_add);
+ // This method is only called when safe_to_add has been found to be true
+ // earlier.
+ ASSERT(safe_to_add);
+
+ if (intermediate_map == NULL) {
+ MaybeObject* maybe_map = CopyDropTransitions();
+ if (!maybe_map->To(&intermediate_map)) return maybe_map;
+ intermediate_map->set_elements_kind(transitioned_from_kind);
+ MaybeObject* maybe_transition = AddElementsTransition(
+ transitioned_from_kind, intermediate_map);
+ if (maybe_transition->IsFailure()) return maybe_transition;
+ }
+ return intermediate_map->AddElementsTransition(to_kind, transitioned_map);
+ }
+ }
+
+ bool safe_to_add_transition = true;
+ Object* descriptor_contents = GetDescriptorContents(
+ elements_transition_sentinel_name(), &safe_to_add_transition);
+ // This method is only called when safe_to_add_transition has been found
+ // to be true earlier.
+ ASSERT(safe_to_add_transition);
+ MaybeObject* maybe_new_contents =
+ AddElementsTransitionMapToDescriptor(descriptor_contents,
+ transitioned_map);
+ Object* new_contents;
+ if (!maybe_new_contents->ToObject(&new_contents)) {
+ return maybe_new_contents;
+ }
+
+ ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
+ new_contents);
+ Object* new_descriptors;
+ MaybeObject* maybe_new_descriptors =
+ instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
+ if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
+ return maybe_new_descriptors;
+ }
+ set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ transitioned_map->SetBackPointer(this);
+ return this;
}
@@ -2314,60 +2457,58 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
}
-// If the map is using the empty descriptor array, install a new empty
-// descriptor array that will contain an element transition.
-// TODO(verwaest) Goes away once the descriptor array is immutable.
-static MaybeObject* EnsureMayContainTransitions(Map* map) {
- if (map->instance_descriptors()->MayContainTransitions()) return map;
- DescriptorArray* descriptor_array;
- MaybeObject* maybe_descriptor_array =
- DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED);
- if (!maybe_descriptor_array->To(&descriptor_array)) {
- return maybe_descriptor_array;
- }
- map->set_instance_descriptors(descriptor_array);
- return map;
-}
+MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
+ Map* current_map = map();
+ ElementsKind from_kind = current_map->elements_kind();
+ if (from_kind == to_kind) return current_map;
-MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
- Map* start_map = map();
- ElementsKind from_kind = start_map->elements_kind();
+ // Only objects with FastProperties can have DescriptorArrays and can track
+ // element-related maps. Also don't add descriptors to maps that are shared.
+ bool safe_to_add_transition = HasFastProperties() &&
+ !current_map->IsUndefined() &&
+ !current_map->is_shared();
- if (from_kind == to_kind) {
- return start_map;
+ // Prevent long chains of DICTIONARY -> FAST_*_ELEMENTS maps caused by objects
+ // with elements that switch back and forth between dictionary and fast
+ // element modes.
+ if (from_kind == DICTIONARY_ELEMENTS &&
+ IsFastElementsKind(to_kind)) {
+ safe_to_add_transition = false;
}
- Context* global_context = GetIsolate()->context()->global_context();
- bool allow_store_transition =
- // Only remember the map transition if the object's map is NOT equal to
- // the global object_function's map and there is not an already existing
- // non-matching element transition.
- (global_context->object_function()->map() != map()) &&
- !start_map->IsUndefined() && !start_map->is_shared() &&
- // Only store fast element maps in ascending generality.
- IsTransitionableFastElementsKind(from_kind) &&
- IsFastElementsKind(to_kind) &&
- IsMoreGeneralElementsKindTransition(from_kind, to_kind);
-
- if (!allow_store_transition) {
- // Create a new free-floating map only if we are not allowed to store it.
- Map* new_map = NULL;
- MaybeObject* maybe_new_map =
- start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- new_map->set_elements_kind(to_kind);
- return new_map;
+ if (safe_to_add_transition) {
+ // It's only safe to manipulate the descriptor array if it would be
+ // safe to add a transition.
+ Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
+ to_kind, &safe_to_add_transition);
+ if (maybe_transition_map != NULL) {
+ return maybe_transition_map;
+ }
}
- EnsureMayContainTransitions(start_map);
- Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
+ Map* new_map = NULL;
- if (closest_map->elements_kind() == to_kind) {
- return closest_map;
+ // No transition to an existing map for the given ElementsKind. Make a new
+ // one.
+ { MaybeObject* maybe_map = current_map->CopyDropTransitions();
+ if (!maybe_map->To(&new_map)) return maybe_map;
}
- return AddMissingElementsTransitions(closest_map, to_kind);
+ new_map->set_elements_kind(to_kind);
+
+ // Only remember the map transition if the object's map is NOT equal to the
+ // global object_function's map and there is not an already existing
+ // non-matching element transition.
+ Context* global_context = GetIsolate()->context()->global_context();
+ bool allow_map_transition = safe_to_add_transition &&
+ (global_context->object_function()->map() != map());
+ if (allow_map_transition) {
+ MaybeObject* maybe_transition =
+ current_map->AddElementsTransition(to_kind, new_map);
+ if (maybe_transition->IsFailure()) return maybe_transition;
+ }
+ return new_map;
}
@@ -2907,6 +3048,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
}
case NULL_DESCRIPTOR:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case HANDLER:
UNREACHABLE();
@@ -3004,7 +3146,9 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
case CONSTANT_TRANSITION:
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
// if the value is a function.
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case HANDLER:
UNREACHABLE();
@@ -3301,6 +3445,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
case INTERCEPTOR:
+ case ELEMENTS_TRANSITION:
break;
case HANDLER:
case NORMAL:
@@ -4090,8 +4235,7 @@ MaybeObject* JSObject::PreventExtensions() {
// Do a map transition, other objects with this map may still
// be extensible.
Map* new_map;
- { MaybeObject* maybe =
- map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ { MaybeObject* maybe = map()->CopyDropTransitions();
if (!maybe->To<Map>(&new_map)) return maybe;
}
new_map->set_is_extensible(false);
@@ -4871,8 +5015,7 @@ MaybeObject* Map::CopyDropDescriptors() {
JSFunction* ctor = JSFunction::cast(constructor());
Object* descriptors;
{ MaybeObject* maybe_descriptors =
- ctor->initial_map()->instance_descriptors()->RemoveTransitions(
- DescriptorArray::MAY_BE_SHARED);
+ ctor->initial_map()->instance_descriptors()->RemoveTransitions();
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
}
Map::cast(result)->set_instance_descriptors(
@@ -4926,15 +5069,14 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
}
-MaybeObject* Map::CopyDropTransitions(
- DescriptorArray::SharedMode shared_mode) {
+MaybeObject* Map::CopyDropTransitions() {
Object* new_map;
{ MaybeObject* maybe_new_map = CopyDropDescriptors();
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
Object* descriptors;
{ MaybeObject* maybe_descriptors =
- instance_descriptors()->RemoveTransitions(shared_mode);
+ instance_descriptors()->RemoveTransitions();
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
}
cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
@@ -5003,13 +5145,11 @@ class IntrusiveMapTransitionIterator {
void Start() {
ASSERT(!IsIterating());
- if (descriptor_array_->MayContainTransitions())
- *DescriptorArrayHeader() = Smi::FromInt(0);
+ if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0);
}
bool IsIterating() {
- return descriptor_array_->MayContainTransitions() &&
- (*DescriptorArrayHeader())->IsSmi();
+ return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi();
}
Map* Next() {
@@ -5027,6 +5167,7 @@ class IntrusiveMapTransitionIterator {
switch (details.type()) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
// We definitely have a map transition.
*DescriptorArrayHeader() = Smi::FromInt(raw_index + 2);
return static_cast<Map*>(descriptor_array_->GetValue(index));
@@ -5060,18 +5201,15 @@ class IntrusiveMapTransitionIterator {
break;
}
}
- if (index == descriptor_array_->number_of_descriptors()) {
- Map* elements_transition = descriptor_array_->elements_transition_map();
- if (elements_transition != NULL) {
- *DescriptorArrayHeader() = Smi::FromInt(index + 1);
- return elements_transition;
- }
- }
*DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map();
return NULL;
}
private:
+ bool HasDescriptors() {
+ return descriptor_array_->length() > DescriptorArray::kFirstIndex;
+ }
+
Object** DescriptorArrayHeader() {
return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset);
}
@@ -5760,30 +5898,23 @@ bool FixedArray::IsEqualTo(FixedArray* other) {
#endif
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors,
- SharedMode shared_mode) {
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Heap* heap = Isolate::Current()->heap();
- // Do not use DescriptorArray::cast on incomplete object.
- FixedArray* result;
if (number_of_descriptors == 0) {
- if (shared_mode == MAY_BE_SHARED) {
- return heap->empty_descriptor_array();
- }
- { MaybeObject* maybe_array =
- heap->AllocateFixedArray(kTransitionsIndex + 1);
- if (!maybe_array->To(&result)) return maybe_array;
- }
- } else {
- // Allocate the array of keys.
- { MaybeObject* maybe_array =
- heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
- if (!maybe_array->To(&result)) return maybe_array;
- }
- result->set(kEnumerationIndexIndex,
- Smi::FromInt(PropertyDetails::kInitialIndex));
+ return heap->empty_descriptor_array();
+ }
+ // Allocate the array of keys.
+ Object* array;
+ { MaybeObject* maybe_array =
+ heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
+ if (!maybe_array->ToObject(&array)) return maybe_array;
}
+ // Do not use DescriptorArray::cast on incomplete object.
+ FixedArray* result = FixedArray::cast(array);
+
result->set(kBitField3StorageIndex, Smi::FromInt(0));
- result->set(kTransitionsIndex, Smi::FromInt(0));
+ result->set(kEnumerationIndexIndex,
+ Smi::FromInt(PropertyDetails::kInitialIndex));
return result;
}
@@ -5885,8 +6016,7 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
DescriptorArray* new_descriptors;
- { SharedMode mode = remove_transitions ? MAY_BE_SHARED : CANNOT_BE_SHARED;
- MaybeObject* maybe_result = Allocate(new_size, mode);
+ { MaybeObject* maybe_result = Allocate(new_size);
if (!maybe_result->To(&new_descriptors)) return maybe_result;
}
@@ -5903,10 +6033,6 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
++enumeration_index;
}
}
- Map* old_elements_transition = elements_transition_map();
- if ((!remove_transitions) && (old_elements_transition != NULL)) {
- new_descriptors->set_elements_transition_map(old_elements_transition);
- }
new_descriptors->SetNextEnumerationIndex(enumeration_index);
// Copy the descriptors, filtering out transitions and null descriptors,
@@ -5930,8 +6056,6 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
}
if (insertion_index < 0) insertion_index = to_index++;
-
- ASSERT(insertion_index < new_descriptors->number_of_descriptors());
new_descriptors->Set(insertion_index, descriptor, witness);
ASSERT(to_index == new_descriptors->number_of_descriptors());
@@ -5941,15 +6065,14 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
-MaybeObject* DescriptorArray::RemoveTransitions(SharedMode shared_mode) {
+MaybeObject* DescriptorArray::RemoveTransitions() {
// Allocate the new descriptor array.
int new_number_of_descriptors = 0;
for (int i = 0; i < number_of_descriptors(); i++) {
if (IsProperty(i)) new_number_of_descriptors++;
}
DescriptorArray* new_descriptors;
- { MaybeObject* maybe_result = Allocate(new_number_of_descriptors,
- shared_mode);
+ { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
if (!maybe_result->To(&new_descriptors)) return maybe_result;
}
@@ -6034,37 +6157,42 @@ void DescriptorArray::Sort(const WhitenessWitness& witness) {
int DescriptorArray::BinarySearch(String* name, int low, int high) {
uint32_t hash = name->Hash();
- int limit = high;
-
- ASSERT(low <= high);
- while (low != high) {
+ while (low <= high) {
int mid = (low + high) / 2;
String* mid_name = GetKey(mid);
uint32_t mid_hash = mid_name->Hash();
- if (mid_hash >= hash) {
- high = mid;
- } else {
+ if (mid_hash > hash) {
+ high = mid - 1;
+ continue;
+ }
+ if (mid_hash < hash) {
low = mid + 1;
+ continue;
}
+ // Found an element with the same hash-code.
+ ASSERT(hash == mid_hash);
+ // There might be more, so we find the first one and
+ // check them all to see if we have a match.
+ if (name == mid_name && !IsNullDescriptor(mid)) return mid;
+ while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
+ for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
+ if (GetKey(mid)->Equals(name) && !IsNullDescriptor(mid)) return mid;
+ }
+ break;
}
-
- for (; low <= limit && GetKey(low)->Hash() == hash; ++low) {
- if (GetKey(low)->Equals(name) && !IsNullDescriptor(low))
- return low;
- }
-
return kNotFound;
}
-int DescriptorArray::LinearSearch(SearchMode mode, String* name, int len) {
+int DescriptorArray::LinearSearch(String* name, int len) {
uint32_t hash = name->Hash();
for (int number = 0; number < len; number++) {
String* entry = GetKey(number);
- if (mode == EXPECT_SORTED && entry->Hash() > hash) break;
- if (name->Equals(entry) && !IsNullDescriptor(number)) {
+ if ((entry->Hash() == hash) &&
+ name->Equals(entry) &&
+ !IsNullDescriptor(number)) {
return number;
}
}
@@ -7343,6 +7471,25 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
case CONSTANT_TRANSITION:
keep_entry = !ClearBackPointer(heap, d->GetValue(i));
break;
+ case ELEMENTS_TRANSITION: {
+ Object* object = d->GetValue(i);
+ if (object->IsMap()) {
+ keep_entry = !ClearBackPointer(heap, object);
+ } else {
+ FixedArray* array = FixedArray::cast(object);
+ for (int j = 0; j < array->length(); ++j) {
+ Object* target = array->get(j);
+ if (target->IsMap()) {
+ if (ClearBackPointer(heap, target)) {
+ array->set_undefined(j);
+ } else {
+ keep_entry = true;
+ }
+ }
+ }
+ }
+ break;
+ }
case CALLBACKS: {
Object* object = d->GetValue(i);
if (object->IsAccessorPair()) {
@@ -7531,8 +7678,7 @@ MaybeObject* JSObject::OptimizeAsPrototype() {
Map* new_map =
proto_map->GetPrototypeTransition(heap->the_hole_value());
if (new_map == NULL) {
- MaybeObject* maybe_new_map =
- proto_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ MaybeObject* maybe_new_map = proto_map->CopyDropTransitions();
if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
new_map->set_used_for_prototype(true);
MaybeObject* ok =
@@ -7565,8 +7711,7 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
// If the function has allocated the initial map
// replace it with a copy containing the new prototype.
Map* new_map;
- MaybeObject* maybe_new_map =
- initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_prototype(value);
MaybeObject* maybe_object =
@@ -7596,8 +7741,7 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
// Remove map transitions because they point to maps with a
// different prototype.
Map* new_map;
- { MaybeObject* maybe_new_map =
- map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
}
Heap* heap = new_map->GetHeap();
@@ -8471,6 +8615,7 @@ const char* Code::PropertyType2String(PropertyType type) {
case HANDLER: return "HANDLER";
case INTERCEPTOR: return "INTERCEPTOR";
case MAP_TRANSITION: return "MAP_TRANSITION";
+ case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
@@ -8865,9 +9010,8 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
Map* new_map = map->GetPrototypeTransition(value);
if (new_map == NULL) {
- { MaybeObject* maybe_new_map =
- map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ { MaybeObject* maybe_new_map = map->CopyDropTransitions();
+ if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
}
{ MaybeObject* maybe_new_cache =
@@ -11159,6 +11303,7 @@ bool StringDictionary::ContainsTransition(int entry) {
switch (DetailsAt(entry).type()) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
return true;
case CALLBACKS: {
Object* value = ValueAt(entry);
@@ -12608,8 +12753,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
// Allocate the instance descriptor.
DescriptorArray* descriptors;
{ MaybeObject* maybe_descriptors =
- DescriptorArray::Allocate(instance_descriptor_length,
- DescriptorArray::MAY_BE_SHARED);
+ DescriptorArray::Allocate(instance_descriptor_length);
if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
return maybe_descriptors;
}
View
69 deps/v8/src/objects.h
@@ -170,14 +170,6 @@ enum CreationFlag {
};
-// Indicates whether the search function should expect a sorted or an unsorted
-// array as input.
-enum SearchMode {
- EXPECT_SORTED,
- EXPECT_UNSORTED
-};
-
-
// Instance size sentinel for objects of variable size.
const int kVariableSizeSentinel = 0;
@@ -2435,15 +2427,10 @@ class DescriptorArray: public FixedArray {
// map uses to encode additional bit fields when the descriptor array is not
// yet used.
inline bool IsEmpty();
- inline bool MayContainTransitions();
-
- DECL_ACCESSORS(elements_transition_map, Map)
// Returns the number of descriptors in the array.
int number_of_descriptors() {
- ASSERT(length() > kFirstIndex ||
- length() == kTransitionsIndex ||
- IsEmpty());
+ ASSERT(length() > kFirstIndex || IsEmpty());
int len = length();
return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kDescriptorSize;
}
@@ -2481,12 +2468,6 @@ class DescriptorArray: public FixedArray {
kEnumerationIndexOffset);
}
- Object** GetTransitionsSlot() {
- ASSERT(elements_transition_map() != NULL);
- return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
- kTransitionsOffset);
- }
-
// TODO(1399): It should be possible to make room for bit_field3 in the map
// without overloading the instance descriptors field in the map
// (and storing it in the DescriptorArray when the map has one).
@@ -2563,16 +2544,9 @@ class DescriptorArray: public FixedArray {
MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor,
TransitionFlag transition_flag);
- // Indicates whether the search function should expect a sorted or an unsorted
- // descriptor array as input.
- enum SharedMode {
- MAY_BE_SHARED,
- CANNOT_BE_SHARED
- };
-
// Return a copy of the array with all transitions and null descriptors
// removed. Return a Failure object in case of an allocation failure.
- MUST_USE_RESULT MaybeObject* RemoveTransitions(SharedMode shared_mode);
+ MUST_USE_RESULT MaybeObject* RemoveTransitions();
// Sort the instance descriptors by the hash codes of their keys.
// Does not check for duplicates.
@@ -2600,13 +2574,12 @@ class DescriptorArray: public FixedArray {
// Perform a linear search in the instance descriptors represented
// by this fixed array. len is the number of descriptor indices that are
- // valid.
- int LinearSearch(SearchMode mode, String* name, int len);
+ // valid. Does not require the descriptors to be sorted.
+ int LinearSearch(String* name, int len);
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors,
- SharedMode shared_mode);
+ MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors);
// Casting.
static inline DescriptorArray* cast(Object* obj);
@@ -2615,9 +2588,8 @@ class DescriptorArray: public FixedArray {
static const int kNotFound = -1;
static const int kBitField3StorageIndex = 0;
- static const int kTransitionsIndex = 1;
- static const int kEnumerationIndexIndex = 2;
- static const int kFirstIndex = 3;
+ static const int kEnumerationIndexIndex = 1;
+ static const int kFirstIndex = 2;
// The length of the "bridge" to the enum cache.
static const int kEnumCacheBridgeLength = 3;
@@ -2627,8 +2599,8 @@ class DescriptorArray: public FixedArray {
// Layout description.
static const int kBitField3StorageOffset = FixedArray::kHeaderSize;
- static const int kTransitionsOffset = kBitField3StorageOffset + kPointerSize;
- static const int kEnumerationIndexOffset = kTransitionsOffset + kPointerSize;
+ static const int kEnumerationIndexOffset = kBitField3StorageOffset +
+ kPointerSize;
static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize;
// Layout description for the bridge array.
@@ -4734,9 +4706,6 @@ class Map: public HeapObject {
static bool IsValidElementsTransition(ElementsKind from_kind,
ElementsKind to_kind);
- inline Map* elements_transition_map();
- inline void set_elements_transition_map(Map* transitioned_map);
-
// Tells whether the map is attached to SharedFunctionInfo
// (for inobject slack tracking).
inline void set_attached_to_shared_function_info(bool value);
@@ -4840,8 +4809,7 @@ class Map: public HeapObject {
// Returns a copy of the map, with all transitions dropped from the
// instance descriptors.
- MUST_USE_RESULT MaybeObject* CopyDropTransitions(
- DescriptorArray::SharedMode shared_mode);
+ MUST_USE_RESULT MaybeObject* CopyDropTransitions();
// Returns the property index for name (only valid for FAST MODE).
int PropertyIndexFor(String* name);
@@ -4894,15 +4862,23 @@ class Map: public HeapObject {
// The "shared" flags of both this map and |other| are ignored.
bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
+ // Returns the contents of this map's descriptor array for the given string.
+ // May return NULL. |safe_to_add_transition| is set to false and NULL
+ // is returned if adding transitions is not allowed.
+ Object* GetDescriptorContents(String* sentinel_name,
+ bool* safe_to_add_transitions);
+
// Returns the map that this map transitions to if its elements_kind
// is changed to |elements_kind|, or NULL if no such map is cached yet.
// |safe_to_add_transitions| is set to false if adding transitions is not
// allowed.
- Map* LookupElementsTransitionMap(ElementsKind elements_kind);
+ Map* LookupElementsTransitionMap(ElementsKind elements_kind,
+ bool* safe_to_add_transition);
- // Adds a new transitions for changing the elements kind to |elements_kind|.
- MUST_USE_RESULT MaybeObject* CreateNextElementsTransition(
- ElementsKind elements_kind);
+ // Adds an entry to this map's descriptor array for a transition to
+ // |transitioned_map| when its elements_kind is changed to |elements_kind|.
+ MUST_USE_RESULT MaybeObject* AddElementsTransition(
+ ElementsKind elements_kind, Map* transitioned_map);
// Returns the transitioned map for this map with the most generic
// elements_kind that's found in |candidates|, or null handle if no match is
@@ -5049,6 +5025,7 @@ class Map: public HeapObject {
kSize> BodyDescriptor;
private:
+ String* elements_transition_sentinel_name();
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
};
View
1  deps/v8/src/profile-generator.cc
@@ -2219,6 +2219,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
case HANDLER: // only in lookup results, not in descriptors
case INTERCEPTOR: // only in lookup results, not in descriptors
case MAP_TRANSITION: // we do not care about transitions here...
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR: // ... and not about "holes"
break;
View
5 deps/v8/src/property-details.h
@@ -63,8 +63,9 @@ enum PropertyType {
INTERCEPTOR = 5, // only in lookup results, not in descriptors
// All properties before MAP_TRANSITION are real.
MAP_TRANSITION = 6, // only in fast mode
- CONSTANT_TRANSITION = 7, // only in fast mode
- NULL_DESCRIPTOR = 8, // only in fast mode
+ ELEMENTS_TRANSITION = 7,
+ CONSTANT_TRANSITION = 8, // only in fast mode
+ NULL_DESCRIPTOR = 9, // only in fast mode
// There are no IC stubs for NULL_DESCRIPTORS. Therefore,
// NULL_DESCRIPTOR can be used as the type flag for IC stubs for
// nonexistent properties.
View
7 deps/v8/src/property.cc
@@ -61,6 +61,12 @@ void LookupResult::Print(FILE* out) {
GetTransitionMap()->Print(out);
PrintF(out, "\n");
break;
+ case ELEMENTS_TRANSITION:
+ PrintF(out, " -type = elements transition\n");
+ PrintF(out, " -map:\n");
+ GetTransitionMap()->Print(out);
+ PrintF(out, "\n");
+ break;
case CONSTANT_FUNCTION:
PrintF(out, " -type = constant function\n");
PrintF(out, " -function:\n");
@@ -112,6 +118,7 @@ bool Descriptor::ContainsTransition() {
switch (details_.type()) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
return true;
case CALLBACKS: {
if (!value_->IsAccessorPair()) return false;
View
10 deps/v8/src/property.h
@@ -111,6 +111,14 @@ class MapTransitionDescriptor: public Descriptor {
: Descriptor(key, map, attributes, MAP_TRANSITION) { }
};
+class ElementsTransitionDescriptor: public Descriptor {
+ public:
+ ElementsTransitionDescriptor(String* key,
+ Object* map_or_array)
+ : Descriptor(key, map_or_array, PropertyDetails(NONE,
+ ELEMENTS_TRANSITION)) { }
+};
+
// Marks a field name in a map so that adding the field is guaranteed
// to create a FIELD descriptor in the new map. Used after adding
// a constant function the first time, creating a CONSTANT_FUNCTION
@@ -172,6 +180,7 @@ bool IsPropertyDescriptor(T* desc) {
AccessorPair::cast(callback_object)->ContainsAccessor());
}
case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return false;
@@ -302,6 +311,7 @@ class LookupResult BASE_EMBEDDED {
Map* GetTransitionMap() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
ASSERT(type() == MAP_TRANSITION ||
+ type() == ELEMENTS_TRANSITION ||
type() == CONSTANT_TRANSITION);
return Map::cast(GetValue());
}
View
7 deps/v8/src/runtime.cc
@@ -1236,8 +1236,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
if (needs_access_checks) {
// Copy map so it won't interfere constructor's initial map.
Object* new_map;
- { MaybeObject* maybe_new_map =
- old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
@@ -1255,8 +1254,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
if (!old_map->is_access_check_needed()) {
// Copy map so it won't interfere constructor's initial map.
Object* new_map;
- { MaybeObject* maybe_new_map =
- old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+ { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
@@ -10289,6 +10287,7 @@ static MaybeObject* DebugLookupResultValue(Heap* heap,
}
case INTERCEPTOR:
case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return heap->undefined_value();
View
2  deps/v8/src/x64/macro-assembler-x64.cc
@@ -2760,7 +2760,7 @@ void MacroAssembler::CompareMap(Register obj,
Map* current_map = *map;
while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
kind = GetNextMoreGeneralFastElementsKind(kind, packed);
- current_map = current_map->LookupElementsTransitionMap(kind);
+ current_map = current_map->LookupElementsTransitionMap(kind, NULL);
if (!current_map) break;
j(equal, early_success, Label::kNear);
Cmp(FieldOperand(obj, HeapObject::kMapOffset),
Please sign in to comment.
Something went wrong with that request. Please try again.