| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 30fea91d796b99db864bc8e07f3d2534d9218259..5c3897572955d5c2f736c427f26987c7115d0da5 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1095,7 +1095,7 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
|
| }
|
| switch (map()->instance_type()) {
|
| case MAP_TYPE:
|
| - accumulator->Add("<Map>");
|
| + accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
|
| break;
|
| case FIXED_ARRAY_TYPE:
|
| accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
|
| @@ -2161,13 +2161,135 @@ static MaybeObject* AddElementsTransitionMapToDescriptor(
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) {
|
| +// Returns the contents of |map|'s descriptor array for the given string
|
| +// (which might be NULL). |safe_to_add_transition| is set to false and NULL
|
| +// is returned if adding transitions is not allowed.
|
| +static Object* GetDescriptorContents(Map* map,
|
| + String* sentinel_name,
|
| + bool* safe_to_add_transition) {
|
| + // Get the cached index for the descriptors lookup, or find and cache it.
|
| + DescriptorArray* descriptors = map->instance_descriptors();
|
| + DescriptorLookupCache* cache = map->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 {
|
| + *safe_to_add_transition = false;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +// Returns the map that |original_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.
|
| +static Map* LookupElementsTransitionMap(Map* original_map,
|
| + ElementsKind elements_kind,
|
| + String* sentinel_name,
|
| + bool* safe_to_add_transition) {
|
| + // Special case: indirect SMI->FAST transition (cf. comment in
|
| + // AddElementsTransition()).
|
| + if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
|
| + elements_kind == FAST_ELEMENTS) {
|
| + Map* double_map = LookupElementsTransitionMap(
|
| + original_map,
|
| + FAST_DOUBLE_ELEMENTS,
|
| + sentinel_name,
|
| + safe_to_add_transition);
|
| + if (double_map == NULL) return double_map;
|
| + return LookupElementsTransitionMap(double_map,
|
| + FAST_ELEMENTS,
|
| + sentinel_name,
|
| + safe_to_add_transition);
|
| + }
|
| + Object* descriptor_contents = GetDescriptorContents(
|
| + original_map, sentinel_name, safe_to_add_transition);
|
| + if (descriptor_contents != NULL) {
|
| + Map* maybe_transition_map =
|
| + GetElementsTransitionMapFromDescriptor(descriptor_contents,
|
| + elements_kind);
|
| + ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
|
| + return maybe_transition_map;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +// Adds an entry to |original_map|'s descriptor array for a transition to
|
| +// |transitioned_map| when its elements_kind is changed to |elements_kind|,
|
| +// using |sentinel_name| as key for the entry.
|
| +static MaybeObject* AddElementsTransition(Map* original_map,
|
| + ElementsKind elements_kind,
|
| + Map* transitioned_map,
|
| + String* sentinel_name) {
|
| + // The map transition graph should be a tree, therefore the transition
|
| + // from SMI to FAST elements is not done directly, but by going through
|
| + // DOUBLE elements first.
|
| + if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
|
| + elements_kind == FAST_ELEMENTS) {
|
| + bool safe_to_add = true;
|
| + Map* double_map = LookupElementsTransitionMap(
|
| + original_map, FAST_DOUBLE_ELEMENTS, sentinel_name, &safe_to_add);
|
| + // This method is only called when safe_to_add_transition has been found
|
| + // to be true earlier.
|
| + ASSERT(safe_to_add);
|
| +
|
| + if (double_map == NULL) {
|
| + MaybeObject* maybe_map = original_map->CopyDropTransitions();
|
| + if (!maybe_map->To(&double_map)) return maybe_map;
|
| + double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
|
| + MaybeObject* maybe_double_transition = AddElementsTransition(
|
| + original_map, FAST_DOUBLE_ELEMENTS, double_map, sentinel_name);
|
| + if (maybe_double_transition->IsFailure()) return maybe_double_transition;
|
| + }
|
| + return AddElementsTransition(
|
| + double_map, FAST_ELEMENTS, transitioned_map, sentinel_name);
|
| + }
|
| +
|
| + DescriptorArray* descriptors = original_map->instance_descriptors();
|
| + bool safe_to_add_transition = true;
|
| + Object* descriptor_contents = GetDescriptorContents(
|
| + original_map, 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(sentinel_name, new_contents);
|
| + Object* new_descriptors;
|
| + MaybeObject* maybe_new_descriptors =
|
| + descriptors->CopyInsert(&desc, KEEP_TRANSITIONS);
|
| + if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
|
| + return maybe_new_descriptors;
|
| + }
|
| + descriptors = DescriptorArray::cast(new_descriptors);
|
| + original_map->set_instance_descriptors(descriptors);
|
| + return original_map;
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
|
| Heap* current_heap = GetHeap();
|
| Map* current_map = map();
|
| - DescriptorArray* descriptors = current_map->instance_descriptors();
|
| + ElementsKind from_kind = current_map->elements_kind();
|
| String* elements_transition_sentinel_name = current_heap->empty_symbol();
|
|
|
| - if (current_map->elements_kind() == elements_kind) return current_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.
|
| @@ -2175,58 +2297,33 @@ MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) {
|
| !current_map->IsUndefined() &&
|
| !current_map->is_shared();
|
|
|
| - // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects
|
| + // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
|
| // with elements that switch back and forth between dictionary and fast
|
| // element mode.
|
| - if ((current_map->elements_kind() == DICTIONARY_ELEMENTS &&
|
| - elements_kind == FAST_ELEMENTS)) {
|
| + if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
|
| safe_to_add_transition = false;
|
| }
|
|
|
| - Object* descriptor_contents = NULL;
|
| if (safe_to_add_transition) {
|
| // It's only safe to manipulate the descriptor array if it would be
|
| // safe to add a transition.
|
| -
|
| - // Check if the elements transition already exists.
|
| - DescriptorLookupCache* cache =
|
| - current_heap->isolate()->descriptor_lookup_cache();
|
| - int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
|
| - if (index == DescriptorLookupCache::kAbsent) {
|
| - index = descriptors->Search(elements_transition_sentinel_name);
|
| - cache->Update(descriptors,
|
| - elements_transition_sentinel_name,
|
| - index);
|
| - }
|
| -
|
| - // If the transition already exists, check the type. If there is a match,
|
| - // return it.
|
| - if (index != DescriptorArray::kNotFound) {
|
| - PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
|
| - if (details.type() == ELEMENTS_TRANSITION) {
|
| - descriptor_contents = descriptors->GetValue(index);
|
| - Map* maybe_transition_map =
|
| - GetElementsTransitionMapFromDescriptor(descriptor_contents,
|
| - elements_kind);
|
| - if (maybe_transition_map != NULL) {
|
| - ASSERT(maybe_transition_map->IsMap());
|
| - return maybe_transition_map;
|
| - }
|
| - } else {
|
| - safe_to_add_transition = false;
|
| - }
|
| + Map* maybe_transition_map = LookupElementsTransitionMap(
|
| + current_map, to_kind, elements_transition_sentinel_name,
|
| + &safe_to_add_transition);
|
| + if (maybe_transition_map != NULL) {
|
| + return maybe_transition_map;
|
| }
|
| }
|
|
|
| + Map* new_map = NULL;
|
| +
|
| // No transition to an existing map for the given ElementsKind. Make a new
|
| // one.
|
| - Object* obj;
|
| { MaybeObject* maybe_map = current_map->CopyDropTransitions();
|
| - if (!maybe_map->ToObject(&obj)) return maybe_map;
|
| + if (!maybe_map->To(&new_map)) return maybe_map;
|
| }
|
| - Map* new_map = Map::cast(obj);
|
|
|
| - new_map->set_elements_kind(elements_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
|
| @@ -2235,26 +2332,10 @@ MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) {
|
| (GetIsolate()->context()->global_context()->object_function()->map() !=
|
| map());
|
| if (allow_map_transition) {
|
| - MaybeObject* maybe_new_contents =
|
| - AddElementsTransitionMapToDescriptor(descriptor_contents, new_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 = descriptors->CopyInsert(
|
| - &desc,
|
| - KEEP_TRANSITIONS);
|
| - if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
|
| - return maybe_new_descriptors;
|
| - }
|
| - descriptors = DescriptorArray::cast(new_descriptors);
|
| - current_map->set_instance_descriptors(descriptors);
|
| + MaybeObject* maybe_transition = AddElementsTransition(
|
| + current_map, to_kind, new_map, elements_transition_sentinel_name);
|
| + if (maybe_transition->IsFailure()) return maybe_transition;
|
| }
|
| -
|
| return new_map;
|
| }
|
|
|
| @@ -6709,7 +6790,7 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
|
| } else {
|
| ASSERT(object->IsFixedArray());
|
| ASSERT(details.type() == ELEMENTS_TRANSITION);
|
| - FixedArray* array = reinterpret_cast<FixedArray*>(contents->get(i));
|
| + FixedArray* array = reinterpret_cast<FixedArray*>(object);
|
| bool reachable_map_found = false;
|
| for (int j = 0; j < array->length(); ++j) {
|
| Map* target = reinterpret_cast<Map*>(array->get(j));
|
| @@ -6723,7 +6804,7 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
|
| // Getter prototype() is read-only, set_prototype() has side
|
| // effects.
|
| *RawField(target, Map::kPrototypeOffset) = real_prototype;
|
| - } else {
|
| + } else if (target->IsMap()) {
|
| reachable_map_found = true;
|
| }
|
| }
|
|
|