Grouping all map creation code.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Jul 2012 13:50:19 +0000 (13:50 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 17 Jul 2012 13:50:19 +0000 (13:50 +0000)
- Now tunnel all descriptor changes through methods on the map
- Renamed CopyDropTransitions to regular Copy since we always "drop transitions" on copy anyway.
- Merged and moved elements transition map creation.

Review URL: https://chromiumcodereview.appspot.com/10780031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12105 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/api.cc
src/bootstrapper.cc
src/factory.cc
src/factory.h
src/handles.cc
src/heap.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime.cc

index 72dfc64..6abe3c6 100644 (file)
@@ -3234,7 +3234,7 @@ void v8::Object::TurnOnAccessCheck() {
   i::Deoptimizer::DeoptimizeGlobalObject(*obj);
 
   i::Handle<i::Map> new_map =
-      isolate->factory()->CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
+      isolate->factory()->CopyMap(i::Handle<i::Map>(obj->map()));
   new_map->set_is_access_check_needed(true);
   obj->set_map(*new_map);
 }
index 3d54187..726670a 100644 (file)
@@ -317,7 +317,7 @@ static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
   // object.__proto__ = proto;
   Factory* factory = object->GetIsolate()->factory();
   Handle<Map> old_to_map = Handle<Map>(object->map());
-  Handle<Map> new_to_map = factory->CopyMapDropTransitions(old_to_map);
+  Handle<Map> new_to_map = factory->CopyMap(old_to_map);
   new_to_map->set_prototype(*proto);
   object->set_map(*new_to_map);
 }
@@ -999,7 +999,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
 
     // RegExp prototype object is itself a RegExp.
-    Handle<Map> proto_map = factory->CopyMapDropTransitions(initial_map);
+    Handle<Map> proto_map = factory->CopyMap(initial_map);
     proto_map->set_prototype(global_context()->initial_object_prototype());
     Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
     proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
@@ -1101,7 +1101,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     elements->set(1, *array);
 
     Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
-    Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
+    Handle<Map> new_map = factory->CopyMap(old_map);
     new_map->set_pre_allocated_property_fields(2);
     Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
     // Set elements kind after allocating the object because
@@ -1630,8 +1630,7 @@ 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()->Copy(DescriptorArray::MAY_BE_SHARED);
     Map* new_map;
     if (!maybe_map->To(&new_map)) return false;
     new_map->set_elements_kind(FAST_HOLEY_ELEMENTS);
@@ -2247,7 +2246,7 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
 
   // Transfer the prototype (new map is needed).
   Handle<Map> old_to_map = Handle<Map>(to->map());
-  Handle<Map> new_to_map = factory->CopyMapDropTransitions(old_to_map);
+  Handle<Map> new_to_map = factory->CopyMap(old_to_map);
   new_to_map->set_prototype(from->map()->prototype());
   to->set_map(*new_to_map);
 }
index 679bb44..8340b46 100644 (file)
@@ -496,10 +496,8 @@ 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);
+Handle<Map> Factory::CopyMap(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(isolate(), src->Copy(DescriptorArray::MAY_BE_SHARED), Map);
 }
 
 
index f170700..3b7ead5 100644 (file)
@@ -227,8 +227,7 @@ class Factory {
   // Copy the map adding more inobject properties if possible without
   // overflowing the instance size.
   Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
-
-  Handle<Map> CopyMapDropTransitions(Handle<Map> map);
+  Handle<Map> CopyMap(Handle<Map> map);
 
   Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
                                        ElementsKind elements_kind);
index e98e843..7ccfe08 100644 (file)
@@ -165,7 +165,7 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
   func->shared()->set_expected_nof_properties(nof);
   if (func->has_initial_map()) {
     Handle<Map> new_initial_map =
-        func->GetIsolate()->factory()->CopyMapDropTransitions(
+        func->GetIsolate()->factory()->CopyMap(
             Handle<Map>(func->initial_map()));
     new_initial_map->set_unused_property_fields(nof);
     func->set_initial_map(*new_initial_map);
index f1cd6a6..c3bbe12 100644 (file)
@@ -3709,23 +3709,21 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
   // constructors.
   Map* new_map;
   ASSERT(object_function->has_initial_map());
-  { MaybeObject* maybe_map =
-        object_function->initial_map()->CopyDropTransitions(
-            DescriptorArray::MAY_BE_SHARED);
-    if (!maybe_map->To<Map>(&new_map)) return maybe_map;
-  }
+  MaybeObject* maybe_map =
+      object_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
+  if (!maybe_map->To(&new_map)) return maybe_map;
+
   Object* prototype;
-  MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
-    if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
-  }
+  MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
+  if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
+
   // When creating the prototype for the function we must set its
   // constructor to the function.
-  Object* result;
-  { MaybeObject* maybe_result =
-        JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
-            constructor_symbol(), function, DONT_ENUM);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
+  MaybeObject* maybe_failure =
+      JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
+          constructor_symbol(), function, DONT_ENUM);
+  if (maybe_failure->IsFailure()) return maybe_failure;
+
   return prototype;
 }
 
index 6dd2a99..feca271 100644 (file)
@@ -3653,12 +3653,12 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
   ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
          (value->IsMap() && GetBackPointer()->IsUndefined()));
   Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
-  if (object->IsMap()) {
+  if (object->IsDescriptorArray()) {
+    DescriptorArray::cast(object)->set_back_pointer_storage(value);
+  } else {
     WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
     CONDITIONAL_WRITE_BARRIER(
         GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
-  } else {
-    DescriptorArray::cast(object)->set_back_pointer_storage(value);
   }
 }
 
@@ -4301,7 +4301,7 @@ MaybeObject* JSFunction::set_initial_map_and_cache_transitions(
       Map* new_map;
       ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
       MaybeObject* maybe_new_map =
-          current_map->CreateNextElementsTransition(next_kind);
+          current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
       if (!maybe_new_map->To(&new_map)) return maybe_new_map;
       maps->set(next_kind, new_map);
       current_map = new_map;
index 05f23d7..4f99d59 100644 (file)
@@ -513,9 +513,9 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
         // from the DontDelete cell without checking if it contains
         // the hole value.
         Map* new_map;
-        MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
-          if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-        }
+        MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
+        if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
         set_map(new_map);
       }
       JSGlobalPropertyCell* cell =
@@ -1544,57 +1544,42 @@ MaybeObject* JSObject::AddFastProperty(String* name,
     return AddSlowProperty(name, value, attributes);
   }
 
-  DescriptorArray* old_descriptors = map()->instance_descriptors();
   // Compute the new index for new field.
   int index = map()->NextFreePropertyIndex();
 
   // Allocate new instance descriptors with (name, index) added
   FieldDescriptor new_field(name, index, attributes, 0);
 
-  DescriptorArray* new_descriptors;
-  MaybeObject* maybe_new_descriptors = old_descriptors->CopyAdd(&new_field);
-  if (!maybe_new_descriptors->To(&new_descriptors)) {
-    return maybe_new_descriptors;
-  }
-
-  // Only allow map transition if the object isn't the global object.
-  bool allow_map_transition = isolate->empty_object_map() != map();
-
   ASSERT(index < map()->inobject_properties() ||
          (index - map()->inobject_properties()) < properties()->length() ||
          map()->unused_property_fields() == 0);
 
-  // Allocate a new map for the object.
-  Map* new_map;
-  MaybeObject* maybe_r = map()->CopyReplaceDescriptors(new_descriptors);
-  if (!maybe_r->To(&new_map)) return maybe_r;
-
-  TransitionArray* new_transitions = NULL;
-  if (allow_map_transition) {
-    MaybeObject* maybe_transitions = map()->AddTransition(name, new_map);
-    if (!maybe_transitions->To(&new_transitions)) return maybe_transitions;
-  }
+  FixedArray* values = NULL;
 
   if (map()->unused_property_fields() == 0) {
     // Make room for the new value
-    FixedArray* values;
     MaybeObject* maybe_values =
         properties()->CopySize(properties()->length() + kFieldsAdded);
     if (!maybe_values->To(&values)) return maybe_values;
+  }
 
+  // Only allow map transition if the object isn't the global object.
+  TransitionFlag flag = isolate->empty_object_map() != map()
+      ? INSERT_TRANSITION
+      : OMIT_TRANSITION;
+
+  Map* new_map;
+  MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
+  if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
+  if (map()->unused_property_fields() == 0) {
+    ASSERT(values != NULL);
     set_properties(values);
     new_map->set_unused_property_fields(kFieldsAdded - 1);
   } else {
     new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
   }
 
-  // Apply all changes at once, so they are atomic.
-  if (allow_map_transition) {
-    MaybeObject* transition_added = map()->set_transitions(new_transitions);
-    if (transition_added->IsFailure()) return transition_added;
-  }
-
-  new_map->SetBackPointer(map());
   set_map(new_map);
   return FastPropertyAtPut(index, value);
 }
@@ -1607,48 +1592,24 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
   // Allocate new instance descriptors with (name, function) added
   ConstantFunctionDescriptor d(name, function, attributes, 0);
 
-  DescriptorArray* new_descriptors;
-  MaybeObject* maybe_new_descriptors =
-      map()->instance_descriptors()->CopyAdd(&d);
-  if (!maybe_new_descriptors->To(&new_descriptors)) {
-    return maybe_new_descriptors;
-  }
+  Heap* heap = GetHeap();
+  TransitionFlag flag =
+      // Do not add transitions to the empty object map (map of "new Object()"),
+      // nor to global objects.
+      (map() == heap->isolate()->empty_object_map() || IsGlobalObject() ||
+      // Don't add transitions to special properties with non-trivial
+      // attributes.
+      // TODO(verwaest): Once we support attribute changes, these transitions
+      // should be kept as well.
+       attributes != NONE)
+      ? OMIT_TRANSITION
+      : INSERT_TRANSITION;
 
-  // Allocate a new map for the object.
   Map* new_map;
-  MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors);
+  MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
   if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
-  Map* old_map = map();
-
-  Heap* heap = GetHeap();
-  // Do not add transitions to the empty object map (map of "new Object()"), nor
-  // to global objects.
-  if (old_map == heap->isolate()->empty_object_map() || IsGlobalObject()) {
-    set_map(new_map);
-    return function;
-  }
-
-  // Don't add transitions to special properties with non-trivial attributes.
-  // TODO(verwaest): Once we support attribute changes, these transitions should
-  // be kept as well.
-  if (attributes != NONE) {
-    set_map(new_map);
-    return function;
-  }
-
-  // Add a constant transition to the old map, so future assignments to this
-  // property on other objects of the same type will create a normal field, not
-  // a constant function.
-  TransitionArray* transitions;
-  MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map);
-  if (!maybe_transitions->To(&transitions)) return maybe_transitions;
-
-  MaybeObject* transition_added = old_map->set_transitions(transitions);
-  if (transition_added->IsFailure()) return transition_added;
-
   set_map(new_map);
-  new_map->SetBackPointer(old_map);
   return function;
 }
 
@@ -1819,15 +1780,10 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name,
   int index = map()->NextFreePropertyIndex();
   FieldDescriptor new_field(name, index, attributes, 0);
 
-  // Make a new DescriptorArray replacing an entry with FieldDescriptor.
-  DescriptorArray* new_descriptors;
-  MaybeObject* maybe_descriptors =
-      map()->instance_descriptors()->CopyInsert(&new_field);
-  if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
-
   // Make a new map for the object.
   Map* new_map;
-  MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors);
+  MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field,
+                                                           OMIT_TRANSITION);
   if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
   // Make new properties array if necessary.
@@ -2220,33 +2176,6 @@ Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
 }
 
 
-MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
-    ASSERT(!HasElementsTransition() ||
-        ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
-          IsExternalArrayElementsKind(
-              elements_transition_map()->elements_kind())) &&
-         (next_kind == DICTIONARY_ELEMENTS ||
-          IsExternalArrayElementsKind(next_kind))));
-    ASSERT(!IsFastElementsKind(next_kind) ||
-           IsMoreGeneralElementsKindTransition(elements_kind(), next_kind));
-    ASSERT(next_kind != elements_kind());
-
-    Map* next_map;
-    { MaybeObject* maybe_next_map =
-          this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED);
-      if (!maybe_next_map->To(&next_map)) return maybe_next_map;
-    }
-
-    { MaybeObject* added_elements = this->set_elements_transition_map(next_map);
-      if (added_elements->IsFailure()) return added_elements;
-    }
-
-    next_map->set_elements_kind(next_kind);
-    next_map->SetBackPointer(this);
-    return next_map;
-}
-
-
 static MaybeObject* AddMissingElementsTransitions(Map* map,
                                                   ElementsKind to_kind) {
   ASSERT(IsFastElementsKind(map->elements_kind()));
@@ -2260,18 +2189,18 @@ static MaybeObject* AddMissingElementsTransitions(Map* map,
   Map* current_map = map;
 
   for (; index < to_index; ++index) {
-      ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
-      MaybeObject* maybe_next_map =
-          current_map->CreateNextElementsTransition(next_kind);
-      if (!maybe_next_map->To(&current_map)) return maybe_next_map;
+    ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
+    MaybeObject* maybe_next_map =
+        current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
+    if (!maybe_next_map->To(&current_map)) return maybe_next_map;
   }
 
   // In case we are exiting the fast elements kind system, just add the map in
   // the end.
   if (!IsFastElementsKind(to_kind)) {
-      MaybeObject* maybe_next_map =
-          current_map->CreateNextElementsTransition(to_kind);
-      if (!maybe_next_map->To(&current_map)) return maybe_next_map;
+    MaybeObject* maybe_next_map =
+        current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
+    if (!maybe_next_map->To(&current_map)) return maybe_next_map;
   }
 
   ASSERT(current_map->elements_kind() == to_kind);
@@ -2312,13 +2241,7 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind 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;
+    return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
   }
 
   Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
@@ -4062,10 +3985,9 @@ 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);
-    if (!maybe->To<Map>(&new_map)) return maybe;
-  }
+  MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED);
+  if (!maybe->To(&new_map)) return maybe;
+
   new_map->set_is_extensible(false);
   set_map(new_map);
   ASSERT(!map()->is_extensible());
@@ -4529,40 +4451,6 @@ static MaybeObject* TryAccessorTransition(JSObject* self,
 }
 
 
-static MaybeObject* NewCallbackTransition(JSObject* obj,
-                                          String* name,
-                                          AccessorComponent component,
-                                          Object* accessor,
-                                          PropertyAttributes attributes,
-                                          AccessorPair* new_accessors) {
-  // step 1: create a copy of the descriptors, incl. the new getter/setter pair
-  Map* old_map = obj->map();
-  CallbacksDescriptor new_accessors_desc(name, new_accessors, attributes);
-  DescriptorArray* descriptors;
-  MaybeObject* maybe_descriptors =
-      old_map->instance_descriptors()->CopyInsert(&new_accessors_desc);
-  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
-
-  // step 2: create a new map with the new descriptors
-  Map* new_map;
-  MaybeObject* maybe_new_map = old_map->CopyReplaceDescriptors(descriptors);
-  if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-
-  // step 3: add a new transition to the new map
-  TransitionArray* transitions;
-  MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map);
-  if (!maybe_transitions->To(&transitions)) return maybe_transitions;
-
-  // step 4: everything went well so far, so we make our changes visible
-  MaybeObject* transition_added = old_map->set_transitions(transitions);
-  if (transition_added->IsFailure()) return transition_added;
-
-  new_map->SetBackPointer(old_map);
-  obj->set_map(new_map);
-  return obj;
-}
-
-
 MaybeObject* JSObject::DefineFastAccessor(String* name,
                                           AccessorComponent component,
                                           Object* accessor,
@@ -4613,12 +4501,15 @@ MaybeObject* JSObject::DefineFastAccessor(String* name,
   if (!maybe_accessors->To(&accessors)) return maybe_accessors;
   accessors->set(component, accessor);
 
-  return NewCallbackTransition(this,
-                               name,
-                               component,
-                               accessor,
-                               attributes,
-                               accessors);
+  CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
+
+  Map* new_map;
+  MaybeObject* maybe_new_map =
+      map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
+  if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
+  set_map(new_map);
+  return this;
 }
 
 
@@ -4826,9 +4717,8 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
 
 MaybeObject* Map::CopyDropDescriptors() {
   Map* result;
-  { MaybeObject* maybe_result = RawCopy(instance_size());
-    if (!maybe_result->To(&result)) return maybe_result;
-  }
+  MaybeObject* maybe_result = RawCopy(instance_size());
+  if (!maybe_result->To(&result)) return maybe_result;
 
   // Please note instance_type and instance_size are set when allocated.
   result->set_inobject_properties(inobject_properties());
@@ -4841,16 +4731,58 @@ MaybeObject* Map::CopyDropDescriptors() {
 }
 
 
-MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors) {
+MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
+                                         String* name,
+                                         TransitionFlag flag) {
   Map* result;
-  MaybeObject* maybe_result = CopyDropDescriptors();
-    if (!maybe_result->To(&result)) return maybe_result;
-  }
+  MaybeObject* maybe_result = CopyDropDescriptors();
+  if (!maybe_result->To(&result)) return maybe_result;
+
   result->set_instance_descriptors(descriptors);
+
+  if (flag == INSERT_TRANSITION) {
+    TransitionArray* transitions;
+    MaybeObject* maybe_transitions = AddTransition(name, result);
+    if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+
+    MaybeObject* maybe_set = set_transitions(transitions);
+    if (maybe_set->IsFailure()) return maybe_set;
+
+    result->SetBackPointer(this);
+  }
+
   return result;
 }
 
 
+MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
+  // Create a new free-floating map only if we are not allowed to store it.
+  Map* new_map = NULL;
+  MaybeObject* maybe_new_map = Copy(DescriptorArray::MAY_BE_SHARED);
+  if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+  new_map->set_elements_kind(kind);
+
+  if (flag == INSERT_TRANSITION) {
+    ASSERT(!HasElementsTransition() ||
+        ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
+          IsExternalArrayElementsKind(
+              elements_transition_map()->elements_kind())) &&
+         (kind == DICTIONARY_ELEMENTS ||
+          IsExternalArrayElementsKind(kind))));
+    ASSERT(!IsFastElementsKind(kind) ||
+           IsMoreGeneralElementsKindTransition(elements_kind(), kind));
+    ASSERT(kind != elements_kind());
+
+    MaybeObject* added_elements = set_elements_transition_map(new_map);
+    if (added_elements->IsFailure()) return added_elements;
+
+    new_map->SetBackPointer(this);
+  }
+
+  return new_map;
+}
+
+
 MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
   if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
 
@@ -4859,21 +4791,67 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
   ASSERT(constructor()->IsJSFunction());
   JSFunction* ctor = JSFunction::cast(constructor());
   DescriptorArray* descriptors;
-  MaybeObject* maybe_descriptors =
-        ctor->initial_map()->instance_descriptors()->Copy(
-            DescriptorArray::MAY_BE_SHARED);
-    if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
-  }
-  return CopyReplaceDescriptors(descriptors);
+  MaybeObject* maybe_descriptors =
+      ctor->initial_map()->instance_descriptors()->Copy(
+          DescriptorArray::MAY_BE_SHARED);
+  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
+  return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
 }
 
 
-MaybeObject* Map::CopyDropTransitions(DescriptorArray::SharedMode shared_mode) {
+MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
   DescriptorArray* descriptors;
-  { MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
-    if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+  MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
+  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
+  return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
+}
+
+
+MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
+                                    TransitionFlag flag) {
+  DescriptorArray* descriptors;
+  MaybeObject* maybe_descriptors = instance_descriptors()->CopyAdd(descriptor);
+  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
+  return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
+}
+
+
+MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
+                                       TransitionFlag flag) {
+  DescriptorArray* old_descriptors = instance_descriptors();
+
+  // Ensure the key is a symbol.
+  MaybeObject* maybe_result = descriptor->KeyToSymbol();
+  if (maybe_result->IsFailure()) return maybe_result;
+
+  DescriptorArray* descriptors;
+  MaybeObject* maybe_descriptors;
+
+  // We replace the key if it is already present.
+  int index = old_descriptors->SearchWithCache(descriptor->GetKey());
+  if (index == DescriptorArray::kNotFound) {
+    maybe_descriptors = old_descriptors->CopyAdd(descriptor);
+  } else {
+    maybe_descriptors = old_descriptors->CopyReplace(descriptor, index);
   }
-  return CopyReplaceDescriptors(descriptors);
+  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
+  return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
+}
+
+
+MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor,
+                                        int index,
+                                        TransitionFlag flag) {
+  DescriptorArray* descriptors;
+  MaybeObject* maybe_descriptors =
+      instance_descriptors()->CopyReplace(descriptor, index);
+  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+
+  return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
 }
 
 
@@ -4885,6 +4863,7 @@ void Map::UpdateCodeCache(Handle<Map> map,
                           map->UpdateCodeCache(*name, *code));
 }
 
+
 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
   ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache());
 
@@ -5738,18 +5717,6 @@ MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor,
 }
 
 
-MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
-  // Ensure the key is a symbol.
-  MaybeObject* maybe_result = descriptor->KeyToSymbol();
-  if (maybe_result->IsFailure()) return maybe_result;
-
-  // We replace the key if it is already present.
-  int index = SearchWithCache(descriptor->GetKey());
-  if (index == kNotFound) return CopyAdd(descriptor);
-  return CopyReplace(descriptor, index);
-}
-
-
 MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) {
   // Ensure the key is a symbol.
   MaybeObject* maybe_result = descriptor->KeyToSymbol();
@@ -7466,11 +7433,10 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
     // replace it with a copy containing the new prototype.
     Map* new_map;
     MaybeObject* maybe_new_map =
-        initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
+        initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
     new_map->set_prototype(value);
-    MaybeObject* maybe_object =
-        set_initial_map_and_cache_transitions(new_map);
+    MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map);
     if (maybe_object->IsFailure()) return maybe_object;
   } else {
     // Put the value in the initial map field until an initial map is
@@ -7496,10 +7462,9 @@ 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);
-      if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-    }
+    MaybeObject* maybe_new_map = map()->Copy(DescriptorArray::MAY_BE_SHARED);
+    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
     Heap* heap = new_map->GetHeap();
     set_map(new_map);
     new_map->set_constructor(value);
@@ -8791,15 +8756,12 @@ 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->Copy(DescriptorArray::MAY_BE_SHARED);
+    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
-    { MaybeObject* maybe_new_cache =
-          map->PutPrototypeTransition(value, new_map);
-      if (maybe_new_cache->IsFailure()) return maybe_new_cache;
-    }
+    MaybeObject* maybe_new_cache =
+        map->PutPrototypeTransition(value, new_map);
+    if (maybe_new_cache->IsFailure()) return maybe_new_cache;
 
     new_map->set_prototype(value);
   }
@@ -12576,7 +12538,8 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
   descriptors->Sort(witness);
   // Allocate new map.
   Map* new_map;
-  MaybeObject* maybe_new_map = obj->map()->CopyReplaceDescriptors(descriptors);
+  MaybeObject* maybe_new_map =
+      obj->map()->CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
   if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
   new_map->set_unused_property_fields(unused_property_fields);
index 4f06283..6349c02 100644 (file)
@@ -178,6 +178,13 @@ enum SearchMode {
 };
 
 
+// Indicates whether transitions can be added to a source map or not.
+enum TransitionFlag {
+  INSERT_TRANSITION,
+  OMIT_TRANSITION
+};
+
+
 // Instance size sentinel for objects of variable size.
 const int kVariableSizeSentinel = 0;
 
@@ -2555,14 +2562,13 @@ class DescriptorArray: public FixedArray {
                 int src_index,
                 const WhitenessWitness&);
 
-  // Copy the descriptor array, insert a new descriptor and optionally
-  // remove map transitions.  If the descriptor is already present, it is
-  // replaced.  If a replaced descriptor is a real property (not a transition
-  // or null), its enumeration index is kept as is.
-  // If adding a real property, map transitions must be removed.  If adding
-  // a transition, they must not be removed.  All null descriptors are removed.
-  MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor);
+  // Copy the descriptor array, inserting new descriptor. Its enumeration index
+  // is automatically set to the size of the descriptor array to which it was
+  // added first.
   MUST_USE_RESULT MaybeObject* CopyAdd(Descriptor* descriptor);
+
+  // Copy the descriptor array, replacing a descriptor. Its enumeration index is
+  // kept.
   MUST_USE_RESULT MaybeObject* CopyReplace(Descriptor* descriptor,
                                            int insertion_index);
 
@@ -4917,15 +4923,23 @@ class Map: public HeapObject {
   MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors();
   MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
   MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors(
-      DescriptorArray* descriptors);
+      DescriptorArray* descriptors, String* name, TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor,
+                                                 TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor,
+                                                    TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor(Descriptor* descriptor,
+                                                     int index,
+                                                     TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
+                                                  TransitionFlag flag);
 
   MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
                                               NormalizedMapSharingMode sharing);
 
   // 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* Copy(DescriptorArray::SharedMode shared_mode);
 
   // Returns the property index for name (only valid for FAST MODE).
   int PropertyIndexFor(String* name);
@@ -4984,10 +4998,6 @@ class Map: public HeapObject {
   // allowed.
   Map* LookupElementsTransitionMap(ElementsKind elements_kind);
 
-  // Adds a new transitions for changing the elements kind to |elements_kind|.
-  MUST_USE_RESULT MaybeObject* CreateNextElementsTransition(
-      ElementsKind elements_kind);
-
   // 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
   // found at all.
index f672534..54bb61a 100644 (file)
@@ -1293,14 +1293,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
   bool needs_access_checks = old_map->is_access_check_needed();
   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);
-      if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
-    }
+    Map* new_map;
+    MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
+    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
-    Map::cast(new_map)->set_is_access_check_needed(false);
-    object->set_map(Map::cast(new_map));
+    new_map->set_is_access_check_needed(false);
+    object->set_map(new_map);
   }
   return isolate->heap()->ToBoolean(needs_access_checks);
 }
@@ -1312,14 +1310,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
   Map* old_map = object->map();
   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);
-      if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
-    }
+    Map* new_map;
+    MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
+    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
-    Map::cast(new_map)->set_is_access_check_needed(true);
-    object->set_map(Map::cast(new_map));
+    new_map->set_is_access_check_needed(true);
+    object->set_map(new_map);
   }
   return isolate->heap()->undefined_value();
 }
@@ -2172,25 +2168,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
   if (function->HasFastProperties()) {
     // Construct a new field descriptor with updated attributes.
     DescriptorArray* instance_desc = function->map()->instance_descriptors();
+
     int index = instance_desc->Search(name);
     ASSERT(index != DescriptorArray::kNotFound);
     PropertyDetails details = instance_desc->GetDetails(index);
+
     CallbacksDescriptor new_desc(name,
         instance_desc->GetValue(index),
         static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
         details.index());
-    // Construct a new field descriptors array containing the new descriptor.
-    DescriptorArray* new_descriptors;
-    { MaybeObject* maybe_descriptors =
-          instance_desc->CopyReplace(&new_desc, index);
-      if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
-    }
+
     // Create a new map featuring the new field descriptors array.
     Map* new_map;
-    { MaybeObject* maybe_map =
-          function->map()->CopyReplaceDescriptors(new_descriptors);
-      if (!maybe_map->To(&new_map)) return maybe_map;
-    }
+    MaybeObject* maybe_map =
+        function->map()->CopyReplaceDescriptor(
+            &new_desc, index, OMIT_TRANSITION);
+    if (!maybe_map->To(&new_map)) return maybe_map;
+
     function->set_map(new_map);
   } else {  // Dictionary properties.
     // Directly manipulate the property details.
@@ -7829,8 +7823,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
           isolate->heap()->non_strict_arguments_elements_map());
 
       Handle<Map> old_map(result->map());
-      Handle<Map> new_map =
-          isolate->factory()->CopyMapDropTransitions(old_map);
+      Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
       new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
 
       result->set_map(*new_map);