| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index a2b35ef45dd3a814351d7d5fa82c95bbec2ec7ac..ac5b0d478ffb1594686a157277ee19d805cefed3 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1282,12 +1282,21 @@ MaybeObject* JSObject::AddFastProperty(String* name,
|
| }
|
| }
|
|
|
| - // Only allow map transition if the object's map is NOT equal to the
|
| - // global object_function's map and there is not a transition for name.
|
| + // Only allow map transition if the object isn't the global object and there
|
| + // is not a transition for the name, or there's a transition for the name but
|
| + // it's unrelated to properties.
|
| + int descriptor_index = old_descriptors->Search(name);
|
| +
|
| + // External array 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) != EXTERNAL_ARRAY_TRANSITION);
|
| + bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
|
| + old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
|
| bool allow_map_transition =
|
| - !old_descriptors->Contains(name) &&
|
| - (isolate->context()->global_context()->object_function()->
|
| - map() != map());
|
| + can_insert_transition &&
|
| + (isolate->context()->global_context()->object_function()->map() != map());
|
|
|
| ASSERT(index < map()->inobject_properties() ||
|
| (index - map()->inobject_properties()) < properties()->length() ||
|
| @@ -1819,6 +1828,77 @@ void Map::LookupInDescriptors(JSObject* holder,
|
| }
|
|
|
|
|
| +MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
|
| + bool safe_to_add_transition) {
|
| + DescriptorArray* descriptors = instance_descriptors();
|
| + String* external_array_sentinel_name = GetIsolate()->heap()->empty_symbol();
|
| +
|
| + if (safe_to_add_transition) {
|
| + // It's only safe to manipulate the descriptor array if it would be
|
| + // safe to add a transition.
|
| +
|
| + ASSERT(!is_shared()); // no transitions can be added to shared maps.
|
| + // Check if the external array transition already exists.
|
| + DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
|
| + int index = cache->Lookup(descriptors, external_array_sentinel_name);
|
| + if (index == DescriptorLookupCache::kAbsent) {
|
| + index = descriptors->Search(external_array_sentinel_name);
|
| + cache->Update(descriptors,
|
| + external_array_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() == EXTERNAL_ARRAY_TRANSITION &&
|
| + details.array_type() == array_type) {
|
| + return descriptors->GetValue(index);
|
| + } else {
|
| + safe_to_add_transition = false;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // No transition to an existing external array map. Make a new one.
|
| + Object* obj;
|
| + { MaybeObject* maybe_map = CopyDropTransitions();
|
| + if (!maybe_map->ToObject(&obj)) return maybe_map;
|
| + }
|
| + Map* new_map = Map::cast(obj);
|
| +
|
| + new_map->set_has_fast_elements(false);
|
| + new_map->set_has_external_array_elements(true);
|
| + GetIsolate()->counters()->map_to_external_array_elements()->Increment();
|
| +
|
| + // 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 external array transition.
|
| + bool allow_map_transition =
|
| + safe_to_add_transition &&
|
| + (GetIsolate()->context()->global_context()->object_function()->map() !=
|
| + map());
|
| + if (allow_map_transition) {
|
| + // Allocate new instance descriptors for the old map with map transition.
|
| + ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
|
| + Map::cast(new_map),
|
| + array_type);
|
| + 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);
|
| + set_instance_descriptors(descriptors);
|
| + }
|
| +
|
| + return new_map;
|
| +}
|
| +
|
| +
|
| void JSObject::LocalLookupRealNamedProperty(String* name,
|
| LookupResult* result) {
|
| if (IsJSGlobalProxy()) {
|
| @@ -2051,6 +2131,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
|
| return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
| }
|
| case NULL_DESCRIPTOR:
|
| + case EXTERNAL_ARRAY_TRANSITION:
|
| return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
| default:
|
| UNREACHABLE();
|
| @@ -2130,6 +2211,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
| // if the value is a function.
|
| return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
| case NULL_DESCRIPTOR:
|
| + case EXTERNAL_ARRAY_TRANSITION:
|
| return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
| default:
|
| UNREACHABLE();
|
| @@ -5484,6 +5566,7 @@ void Map::CreateBackPointers() {
|
| DescriptorArray* descriptors = instance_descriptors();
|
| for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
|
| if (descriptors->GetType(i) == MAP_TRANSITION ||
|
| + descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
|
| descriptors->GetType(i) == CONSTANT_TRANSITION) {
|
| // Get target.
|
| Map* target = Map::cast(descriptors->GetValue(i));
|
| @@ -5526,6 +5609,7 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
|
| // non-live object.
|
| PropertyDetails details(Smi::cast(contents->get(i + 1)));
|
| if (details.type() == MAP_TRANSITION ||
|
| + details.type() == EXTERNAL_ARRAY_TRANSITION ||
|
| details.type() == CONSTANT_TRANSITION) {
|
| Map* target = reinterpret_cast<Map*>(contents->get(i));
|
| ASSERT(target->IsHeapObject());
|
| @@ -6399,6 +6483,7 @@ const char* Code::PropertyType2String(PropertyType type) {
|
| case CALLBACKS: return "CALLBACKS";
|
| case INTERCEPTOR: return "INTERCEPTOR";
|
| case MAP_TRANSITION: return "MAP_TRANSITION";
|
| + case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
|
| case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
|
| case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
|
| }
|
|
|