Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index c015fe12e992694cf7a494a1ab4fc30f397c3ec1..fa34e6238609c1eef32e323eba83e9c89fd08d9a 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -629,7 +629,6 @@ MaybeObject* Object::GetProperty(Object* receiver, |
recvr, name, attributes); |
} |
case MAP_TRANSITION: |
- case ELEMENTS_TRANSITION: |
case CONSTANT_TRANSITION: |
case NULL_DESCRIPTOR: |
break; |
@@ -1552,10 +1551,7 @@ 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. |
- 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 can_insert_transition = descriptor_index == DescriptorArray::kNotFound; |
bool allow_map_transition = |
can_insert_transition && |
(isolate->context()->global_context()->object_function()->map() != map()); |
@@ -1601,7 +1597,9 @@ 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. |
- map()->set_instance_descriptors(old_descriptors); |
+ if (allow_map_transition) { |
+ map()->set_instance_descriptors(old_descriptors); |
+ } |
new_map->SetBackPointer(map()); |
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
set_map(new_map); |
@@ -2128,7 +2126,6 @@ MaybeObject* JSObject::SetPropertyViaPrototypes( |
case MAP_TRANSITION: |
case CONSTANT_TRANSITION: |
case NULL_DESCRIPTOR: |
- case ELEMENTS_TRANSITION: |
break; |
} |
} |
@@ -2198,9 +2195,8 @@ 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, &dummy)); |
+ MaybeNull(current_map->LookupElementsTransitionMap(kind)); |
if (maybe_transitioned_map.is_null()) break; |
if (ContainsMap(candidates, maybe_transitioned_map) && |
(packed || !IsFastPackedElementsKind(kind))) { |
@@ -2214,207 +2210,68 @@ Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { |
} |
-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; |
+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; |
} |
- return NULL; |
+ current_map = next_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; |
+ ASSERT(current_map->elements_kind() == to_kind); |
+ return current_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; |
+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; |
} |
} |
- |
- // 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; |
+ return NULL; |
} |
-String* Map::elements_transition_sentinel_name() { |
- return GetHeap()->empty_symbol(); |
-} |
+MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) { |
+ ASSERT(elements_transition_map() == NULL); |
+ ASSERT(GetSequenceIndexFromFastElementsKind(elements_kind()) == |
+ (GetSequenceIndexFromFastElementsKind(next_kind) - 1)); |
+ Map* next_map; |
+ MaybeObject* maybe_next_map = |
+ this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED); |
+ if (!maybe_next_map->To(&next_map)) return maybe_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; |
+ next_map->set_elements_kind(next_kind); |
+ next_map->SetBackPointer(this); |
+ this->set_elements_transition_map(next_map); |
+ return next_map; |
} |
-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); |
+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* current_map = 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); |
- } |
+ for (; index <= to_index; ++index) { |
+ ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index); |
+ MaybeObject* maybe_next_map = |
+ current_map->CreateNextElementsTransition(next_kind); |
+ if (!maybe_next_map->To(¤t_map)) return maybe_next_map; |
} |
- 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; |
-} |
- |
-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; |
+ ASSERT(current_map->elements_kind() == to_kind); |
+ return current_map; |
} |
@@ -2427,58 +2284,60 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, |
} |
-MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { |
- Map* current_map = map(); |
- ElementsKind from_kind = current_map->elements_kind(); |
+// 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; |
+} |
- if (from_kind == to_kind) return current_map; |
- // 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(); |
+MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { |
+ Map* start_map = map(); |
+ ElementsKind from_kind = start_map->elements_kind(); |
- // 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; |
+ if (from_kind == to_kind) { |
+ return start_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; |
- } |
+ 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; |
} |
- Map* new_map = NULL; |
+ EnsureMayContainTransitions(start_map); |
+ Map* closest_map = FindClosestElementsTransition(start_map, to_kind); |
- // 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; |
+ if (closest_map->elements_kind() == to_kind) { |
+ return closest_map; |
} |
- 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; |
+ return AddMissingElementsTransitions(closest_map, to_kind); |
} |
@@ -3015,7 +2874,6 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, |
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
} |
case NULL_DESCRIPTOR: |
- case ELEMENTS_TRANSITION: |
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
case HANDLER: |
UNREACHABLE(); |
@@ -3113,9 +2971,7 @@ 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(); |
@@ -3406,7 +3262,6 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
case CONSTANT_TRANSITION: |
case NULL_DESCRIPTOR: |
case INTERCEPTOR: |
- case ELEMENTS_TRANSITION: |
break; |
case HANDLER: |
case NORMAL: |
@@ -4192,7 +4047,8 @@ MaybeObject* JSObject::PreventExtensions() { |
// Do a map transition, other objects with this map may still |
// be extensible. |
Map* new_map; |
- { MaybeObject* maybe = map()->CopyDropTransitions(); |
+ { MaybeObject* maybe = |
+ map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); |
if (!maybe->To<Map>(&new_map)) return maybe; |
} |
new_map->set_is_extensible(false); |
@@ -4972,7 +4828,8 @@ MaybeObject* Map::CopyDropDescriptors() { |
JSFunction* ctor = JSFunction::cast(constructor()); |
Object* descriptors; |
{ MaybeObject* maybe_descriptors = |
- ctor->initial_map()->instance_descriptors()->RemoveTransitions(); |
+ ctor->initial_map()->instance_descriptors()->RemoveTransitions( |
+ DescriptorArray::MAY_BE_SHARED); |
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
} |
Map::cast(result)->set_instance_descriptors( |
@@ -5025,14 +4882,15 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, |
} |
-MaybeObject* Map::CopyDropTransitions() { |
+MaybeObject* Map::CopyDropTransitions( |
+ DescriptorArray::SharedMode shared_mode) { |
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(); |
+ instance_descriptors()->RemoveTransitions(shared_mode); |
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
} |
cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
@@ -5098,11 +4956,13 @@ class IntrusiveMapTransitionIterator { |
void Start() { |
ASSERT(!IsIterating()); |
- if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0); |
+ if (descriptor_array_->MayContainTransitions()) |
+ *DescriptorArrayHeader() = Smi::FromInt(0); |
} |
bool IsIterating() { |
- return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi(); |
+ return descriptor_array_->MayContainTransitions() && |
+ (*DescriptorArrayHeader())->IsSmi(); |
} |
Map* Next() { |
@@ -5120,7 +4980,6 @@ 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)); |
@@ -5154,15 +5013,18 @@ 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); |
} |
@@ -5851,23 +5713,30 @@ bool FixedArray::IsEqualTo(FixedArray* other) { |
#endif |
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { |
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, |
+ SharedMode shared_mode) { |
Heap* heap = Isolate::Current()->heap(); |
+ // Do not use DescriptorArray::cast on incomplete object. |
+ FixedArray* result; |
if (number_of_descriptors == 0) { |
- 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; |
+ 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)); |
} |
- // Do not use DescriptorArray::cast on incomplete object. |
- FixedArray* result = FixedArray::cast(array); |
- |
result->set(kBitField3StorageIndex, Smi::FromInt(0)); |
- result->set(kEnumerationIndexIndex, |
- Smi::FromInt(PropertyDetails::kInitialIndex)); |
+ result->set(kTransitionsIndex, Smi::FromInt(0)); |
return result; |
} |
@@ -5969,7 +5838,9 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, |
} |
DescriptorArray* new_descriptors; |
- { MaybeObject* maybe_result = Allocate(new_size); |
+ { MaybeObject* maybe_result = Allocate(new_size, remove_transitions |
+ ? MAY_BE_SHARED |
+ : CANNOT_BE_SHARED); |
danno
2012/06/06 09:25:12
nit: strange formatting. Put the *_SHARED value in
|
if (!maybe_result->To(&new_descriptors)) return maybe_result; |
} |
@@ -5986,6 +5857,10 @@ 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, |
@@ -6009,6 +5884,8 @@ 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()); |
@@ -6018,14 +5895,15 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, |
} |
-MaybeObject* DescriptorArray::RemoveTransitions() { |
+MaybeObject* DescriptorArray::RemoveTransitions(SharedMode shared_mode) { |
// 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); |
+ { MaybeObject* maybe_result = Allocate(new_number_of_descriptors, |
+ shared_mode); |
if (!maybe_result->To(&new_descriptors)) return maybe_result; |
} |
@@ -6109,42 +5987,37 @@ 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 - 1; |
- continue; |
- } |
- if (mid_hash < hash) { |
+ if (mid_hash >= hash) { |
+ high = mid; |
+ } else { |
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(String* name, int len) { |
+int DescriptorArray::LinearSearch(SearchMode mode, String* name, int len) { |
uint32_t hash = name->Hash(); |
for (int number = 0; number < len; number++) { |
String* entry = GetKey(number); |
- if ((entry->Hash() == hash) && |
- name->Equals(entry) && |
- !IsNullDescriptor(number)) { |
+ if (mode == EXPECT_SORTED && entry->Hash() > hash) break; |
+ if (name->Equals(entry) && !IsNullDescriptor(number)) { |
return number; |
} |
} |
@@ -7428,20 +7301,6 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
case CONSTANT_TRANSITION: |
ClearBackPointer(heap, d->GetValue(i), &keep_entry); |
break; |
- case ELEMENTS_TRANSITION: { |
- Object* object = d->GetValue(i); |
- if (object->IsMap()) { |
- ClearBackPointer(heap, object, &keep_entry); |
- } else { |
- FixedArray* array = FixedArray::cast(object); |
- for (int j = 0; j < array->length(); ++j) { |
- if (ClearBackPointer(heap, array->get(j), &keep_entry)) { |
- array->set_undefined(j); |
- } |
- } |
- } |
- break; |
- } |
case CALLBACKS: { |
Object* object = d->GetValue(i); |
if (object->IsAccessorPair()) { |
@@ -7601,7 +7460,8 @@ 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(); |
+ MaybeObject* maybe_new_map = |
+ initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); |
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
new_map->set_prototype(value); |
MaybeObject* maybe_object = |
@@ -7631,7 +7491,8 @@ 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(); |
+ { MaybeObject* maybe_new_map = |
+ map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); |
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
} |
Heap* heap = new_map->GetHeap(); |
@@ -8498,7 +8359,6 @@ 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"; |
} |
@@ -8889,7 +8749,8 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, |
Object* new_map = map->GetPrototypeTransition(value); |
if (new_map == NULL) { |
- { MaybeObject* maybe_new_map = map->CopyDropTransitions(); |
+ { MaybeObject* maybe_new_map = |
+ map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); |
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
} |
@@ -11170,7 +11031,6 @@ 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); |
@@ -12620,7 +12480,8 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( |
// Allocate the instance descriptor. |
DescriptorArray* descriptors; |
{ MaybeObject* maybe_descriptors = |
- DescriptorArray::Allocate(instance_descriptor_length); |
+ DescriptorArray::Allocate(instance_descriptor_length, |
+ DescriptorArray::MAY_BE_SHARED); |
if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) { |
return maybe_descriptors; |
} |