Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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.