Swapped transition array and descriptor array.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Aug 2012 08:43:16 +0000 (08:43 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 13 Aug 2012 08:43:16 +0000 (08:43 +0000)
Now a map points to a transition array which contains the descriptor array. The descriptor array is now immutable. The next step is to share the descriptor array with all back-pointed maps as long as there is a single line of extension. Maps that require a descriptor array but don't need transitions will still need a pseudo-empty transition array to contain the descriptor array.

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

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

17 files changed:
src/arm/macro-assembler-arm.cc
src/bootstrapper.cc
src/factory.cc
src/heap.cc
src/ia32/macro-assembler-ia32.cc
src/mark-compact.cc
src/mark-compact.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/profile-generator.cc
src/runtime.cc
src/transitions-inl.h
src/transitions.cc
src/transitions.h
src/x64/macro-assembler-x64.cc
test/cctest/test-alloc.cc

index 54fb337240ff5739571c1d9ba81350238851db41..cc7bcdb3be7d75923cc9de9344c5253a1db8a37d 100644 (file)
@@ -3691,15 +3691,16 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors,
                                              Register scratch) {
-  ldr(descriptors,
-      FieldMemOperand(map, Map::kInstanceDescriptorsOrBackPointerOffset));
+  Register temp = descriptors;
+  ldr(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset));
 
   Label ok, fail;
-  CheckMap(descriptors,
+  CheckMap(temp,
            scratch,
            isolate()->factory()->fixed_array_map(),
            &fail,
            DONT_DO_SMI_CHECK);
+  ldr(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
   jmp(&ok);
   bind(&fail);
   mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
@@ -3712,9 +3713,6 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
   // Preload a couple of values used in the loop.
   Register  empty_fixed_array_value = r6;
   LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
-  Register empty_descriptor_array_value = r7;
-  LoadRoot(empty_descriptor_array_value,
-           Heap::kEmptyDescriptorArrayRootIndex);
   mov(r1, r0);
   bind(&next);
 
@@ -3728,7 +3726,7 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
   // check for an enum cache.  Leave the map in r2 for the subsequent
   // prototype load.
   ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
-  ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBackPointerOffset));
+  ldr(r3, FieldMemOperand(r2, Map::kTransitionsOrBackPointerOffset));
 
   CheckMap(r3,
            r7,
@@ -3736,6 +3734,11 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
            call_runtime,
            DONT_DO_SMI_CHECK);
 
+  LoadRoot(r7, Heap::kEmptyDescriptorArrayRootIndex);
+  ldr(r3, FieldMemOperand(r3, TransitionArray::kDescriptorsOffset));
+  cmp(r3, r7);
+  b(eq, call_runtime);
+
   // Check that there is an enum cache in the non-empty instance
   // descriptors (r3).  This is the case if the next enumeration
   // index field does not contain a smi.
index 4300e73293f7e0d62baa9950e6faf1afc8b6d254..b09db461065997142ec61f6994b29f1430a225a4 100644 (file)
@@ -399,7 +399,7 @@ void Genesis::SetFunctionInstanceDescriptor(
   }
   PropertyAttributes attribs = static_cast<PropertyAttributes>(
       DONT_ENUM | DONT_DELETE | READ_ONLY);
-  map->set_instance_descriptors(*descriptors);
+  Map::SetDescriptors(map, descriptors);
 
   {  // Add length.
     CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
@@ -540,7 +540,7 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
   }
   PropertyAttributes attribs = static_cast<PropertyAttributes>(
       DONT_ENUM | DONT_DELETE);
-  map->set_instance_descriptors(*descriptors);
+  Map::SetDescriptors(map, descriptors);
 
   {  // Add length.
     CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
@@ -868,13 +868,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     // is 1.
     array_function->shared()->set_length(1);
 
+    Handle<Map> initial_map(array_function->initial_map());
     Handle<DescriptorArray> array_descriptors(factory->NewDescriptorArray(1));
     DescriptorArray::WhitenessWitness witness(*array_descriptors);
 
     Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
     PropertyAttributes attribs = static_cast<PropertyAttributes>(
         DONT_ENUM | DONT_DELETE);
-    array_function->initial_map()->set_instance_descriptors(*array_descriptors);
+    Map::SetDescriptors(initial_map, array_descriptors);
 
     {  // Add length.
       CallbacksDescriptor d(*factory->length_symbol(), *array_length, attribs);
@@ -922,7 +923,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
         factory->NewForeign(&Accessors::StringLength));
     PropertyAttributes attribs = static_cast<PropertyAttributes>(
         DONT_ENUM | DONT_DELETE | READ_ONLY);
-    string_map->set_instance_descriptors(*string_descriptors);
+    Map::SetDescriptors(string_map, string_descriptors);
 
     {  // Add length.
       CallbacksDescriptor d(*factory->length_symbol(), *string_length, attribs);
@@ -958,7 +959,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
         static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
     Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
     DescriptorArray::WhitenessWitness witness(*descriptors);
-    initial_map->set_instance_descriptors(*descriptors);
+    Map::SetDescriptors(initial_map, descriptors);
 
     {
       // ECMA-262, section 15.10.7.1.
@@ -1142,7 +1143,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     // Create the descriptor array for the arguments object.
     Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
     DescriptorArray::WhitenessWitness witness(*descriptors);
-    map->set_instance_descriptors(*descriptors);
+    Map::SetDescriptors(map, descriptors);
 
     {  // length
       FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
@@ -1528,7 +1529,7 @@ bool Genesis::InstallNatives() {
         factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName));
     PropertyAttributes attribs =
         static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
-    script_map->set_instance_descriptors(*script_descriptors);
+    Map::SetDescriptors(script_map, script_descriptors);
 
     {
       CallbacksDescriptor d(
@@ -1653,14 +1654,14 @@ bool Genesis::InstallNatives() {
     // elements in InternalArrays can be set to non-Smi values without going
     // 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()->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_map = array_function->initial_map()->Copy();
     Map* new_map;
     if (!maybe_map->To(&new_map)) return false;
     new_map->set_elements_kind(FAST_HOLEY_ELEMENTS);
     array_function->set_initial_map(new_map);
 
     // Make "length" magic on instances.
+    Handle<Map> initial_map(array_function->initial_map());
     Handle<DescriptorArray> array_descriptors(factory()->NewDescriptorArray(1));
     DescriptorArray::WhitenessWitness witness(*array_descriptors);
 
@@ -1668,7 +1669,7 @@ bool Genesis::InstallNatives() {
         &Accessors::ArrayLength));
     PropertyAttributes attribs = static_cast<PropertyAttributes>(
         DONT_ENUM | DONT_DELETE);
-    array_function->initial_map()->set_instance_descriptors(*array_descriptors);
+    Map::SetDescriptors(initial_map, array_descriptors);
 
     {  // Add length.
       CallbacksDescriptor d(
@@ -1763,7 +1764,7 @@ bool Genesis::InstallNatives() {
     Handle<DescriptorArray> reresult_descriptors =
         factory()->NewDescriptorArray(3);
     DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
-    initial_map->set_instance_descriptors(*reresult_descriptors);
+    Map::SetDescriptors(initial_map, reresult_descriptors);
 
     {
       JSFunction* array_function = global_context()->array_function();
index a4a2be24fa82a5aa8886e6cc606b4a84d6447f71..913b75601551593eb93bf5f61a5b4e9567dd4b07 100644 (file)
@@ -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,7 +496,7 @@ Handle<Map> Factory::CopyMap(Handle<Map> src,
 
 
 Handle<Map> Factory::CopyMap(Handle<Map> src) {
-  CALL_HEAP_FUNCTION(isolate(), src->Copy(DescriptorArray::MAY_BE_SHARED), Map);
+  CALL_HEAP_FUNCTION(isolate(), src->Copy(), Map);
 }
 
 
index 8cc1dea87ea5567a12deb3443342758ea756ded9..8fc025338625aaed00cee4c5101c799296a24d84 100644 (file)
@@ -3730,8 +3730,7 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
   // constructors.
   Map* new_map;
   ASSERT(object_function->has_initial_map());
-  MaybeObject* maybe_map =
-      object_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
+  MaybeObject* maybe_map = object_function->initial_map()->Copy();
   if (!maybe_map->To(&new_map)) return maybe_map;
 
   Object* prototype;
@@ -3875,8 +3874,7 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
       fun->shared()->ForbidInlineConstructor();
     } else {
       DescriptorArray* descriptors;
-      MaybeObject* maybe_descriptors =
-          DescriptorArray::Allocate(count, DescriptorArray::MAY_BE_SHARED);
+      MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
       if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
 
       DescriptorArray::WhitenessWitness witness(descriptors);
@@ -3895,7 +3893,8 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
       if (HasDuplicates(descriptors)) {
         fun->shared()->ForbidInlineConstructor();
       } else {
-        map->InitializeDescriptors(descriptors);
+        MaybeObject* maybe_failure = map->InitializeDescriptors(descriptors);
+        if (maybe_failure->IsFailure()) return maybe_failure;
         map->set_pre_allocated_property_fields(count);
         map->set_unused_property_fields(in_object_properties - count);
       }
index de3e2ce6d2a98db80cf77018abba3a92b803bbd1..7d621a34fd972d767ab7f154fb1f994f8c153f76 100644 (file)
@@ -2519,14 +2519,15 @@ void MacroAssembler::Abort(const char* msg) {
 
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
-  mov(descriptors, FieldOperand(map,
-                                Map::kInstanceDescriptorsOrBackPointerOffset));
+  Register temp = descriptors;
+  mov(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset));
 
   Label ok, fail;
-  CheckMap(descriptors,
+  CheckMap(temp,
            isolate()->factory()->fixed_array_map(),
            &fail,
            DONT_DO_SMI_CHECK);
+  mov(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
   jmp(&ok);
   bind(&fail);
   mov(descriptors, isolate()->factory()->empty_descriptor_array());
@@ -2893,12 +2894,16 @@ void MacroAssembler::CheckEnumCache(Label* call_runtime) {
   // check for an enum cache.  Leave the map in ebx for the subsequent
   // prototype load.
   mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
-  mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBackPointerOffset));
+  mov(edx, FieldOperand(ebx, Map::kTransitionsOrBackPointerOffset));
   CheckMap(edx,
            isolate()->factory()->fixed_array_map(),
            call_runtime,
            DONT_DO_SMI_CHECK);
 
+  mov(edx, FieldOperand(edx, TransitionArray::kDescriptorsOffset));
+  cmp(edx, isolate()->factory()->empty_descriptor_array());
+  j(equal, call_runtime);
+
   // Check that there is an enum cache in the non-empty instance
   // descriptors (edx).  This is the case if the next enumeration
   // index field does not contain a smi.
index 26b01ae010f31a0c8402e7e4ed5b560a4ce3c0af..b3a0bf7df1efc88a031db73a1c40fb7cfe830751 100644 (file)
@@ -1906,28 +1906,26 @@ template void Marker<MarkCompactCollector>::MarkMapContents(Map* map);
 template <class T>
 void Marker<T>::MarkMapContents(Map* map) {
   // Make sure that the back pointer stored either in the map itself or inside
-  // its prototype transitions array is marked. Treat pointers in the descriptor
-  // array as weak and also mark that array to prevent visiting it later.
+  // its transitions array is marked. Treat pointers in the transitions array as
+  // weak and also mark that array to prevent visiting it later.
   base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer()));
 
-  Object** descriptor_array_slot =
-      HeapObject::RawField(map, Map::kInstanceDescriptorsOrBackPointerOffset);
-  Object* descriptor_array = *descriptor_array_slot;
-  if (descriptor_array->IsDescriptorArray()) {
-    MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(descriptor_array));
+  Object** transitions_slot =
+      HeapObject::RawField(map, Map::kTransitionsOrBackPointerOffset);
+  Object* transitions = *transitions_slot;
+  if (transitions->IsTransitionArray()) {
+    MarkTransitionArray(reinterpret_cast<TransitionArray*>(transitions));
   } else {
     // Already marked by marking map->GetBackPointer().
-    ASSERT(descriptor_array->IsMap() || descriptor_array->IsUndefined());
+    ASSERT(transitions->IsMap() || transitions->IsUndefined());
   }
 
-  // Mark the Object* fields of the Map. Since the descriptor array has been
-  // marked already, it is fine that one of these fields contains a pointer
-  // to it. But make sure to skip back pointer.
-  STATIC_ASSERT(Map::kPointerFieldsEndOffset ==
-                Map::kBitField3Offset + kPointerSize);
+  // Mark the Object* fields of the Map. Since the transitions array has been
+  // marked already, it is fine that one of these fields contains a pointer to
+  // it.
   Object** start_slot =
       HeapObject::RawField(map, Map::kPointerFieldsBeginOffset);
-  Object** end_slot = HeapObject::RawField(map, Map::kBitField3Offset);
+  Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset);
   for (Object** slot = start_slot; slot < end_slot; slot++) {
     Object* obj = *slot;
     if (!obj->NonFailureIsHeapObject()) continue;
@@ -1937,78 +1935,16 @@ void Marker<T>::MarkMapContents(Map* map) {
 }
 
 
-template <class T>
-void Marker<T>::MarkDescriptorArray(DescriptorArray* descriptors) {
-  // Empty descriptor array is marked as a root before any maps are marked.
-  ASSERT(descriptors != descriptors->GetHeap()->empty_descriptor_array());
-
-  if (!base_marker()->MarkObjectWithoutPush(descriptors)) return;
-  Object** descriptor_start = descriptors->data_start();
-
-  // Since the descriptor array itself is not pushed for scanning, all fields
-  // that point to objects manually have to be pushed, marked, and their slots
-  // recorded.
-  if (descriptors->HasEnumCache()) {
-    Object** enum_cache_slot = descriptors->GetEnumCacheSlot();
-    Object* enum_cache = *enum_cache_slot;
-    base_marker()->MarkObjectAndPush(
-        reinterpret_cast<HeapObject*>(enum_cache));
-    mark_compact_collector()->RecordSlot(descriptor_start,
-                                         enum_cache_slot,
-                                         enum_cache);
-  }
-
-  if (descriptors->HasTransitionArray()) {
-    Object** transitions_slot = descriptors->GetTransitionsSlot();
-    Object* transitions = *transitions_slot;
-    mark_compact_collector()->RecordSlot(descriptor_start,
-                                         transitions_slot,
-                                         transitions);
-    MarkTransitionArray(reinterpret_cast<TransitionArray*>(transitions));
-  }
-
-  // If the descriptor contains a transition (value is a Map), we don't mark the
-  // value as live. It might be removed by ClearNonLiveTransitions later.
-  for (int i = 0; i < descriptors->number_of_descriptors(); ++i) {
-    Object** key_slot = descriptors->GetKeySlot(i);
-    Object* key = *key_slot;
-    if (key->IsHeapObject()) {
-      base_marker()->MarkObjectAndPush(HeapObject::cast(key));
-      mark_compact_collector()->RecordSlot(descriptor_start, key_slot, key);
-    }
-
-    Object** value_slot = descriptors->GetValueSlot(i);
-    if (!(*value_slot)->IsHeapObject()) continue;
-    HeapObject* value = HeapObject::cast(*value_slot);
-
-    mark_compact_collector()->RecordSlot(descriptor_start,
-                                         value_slot,
-                                         value);
-
-    PropertyDetails details(descriptors->GetDetails(i));
-
-    switch (details.type()) {
-      case NORMAL:
-      case FIELD:
-      case CONSTANT_FUNCTION:
-      case HANDLER:
-      case INTERCEPTOR:
-      case CALLBACKS:
-        base_marker()->MarkObjectAndPush(value);
-        break;
-      case TRANSITION:
-      case NONEXISTENT:
-        UNREACHABLE();
-        break;
-    }
-  }
-}
-
 template <class T>
 void Marker<T>::MarkTransitionArray(TransitionArray* transitions) {
   if (!base_marker()->MarkObjectWithoutPush(transitions)) return;
   Object** transitions_start = transitions->data_start();
 
+  DescriptorArray* descriptors = transitions->descriptors();
+  base_marker()->MarkObjectAndPush(descriptors);
+  mark_compact_collector()->RecordSlot(
+      transitions_start, transitions->GetDescriptorsSlot(), descriptors);
+
   if (transitions->HasPrototypeTransitions()) {
     // Mark prototype transitions array but don't push it into marking stack.
     // This will make references from it weak. We will clean dead prototype
index f4915519aa0c7e15f579bc52fd6f06a5404c9c0d..015438062983bde156c388c4973c2ae4aaf3a004 100644 (file)
@@ -394,7 +394,6 @@ template<class BaseMarker> class Marker {
   // Mark pointers in a Map and its DescriptorArray together, possibly
   // treating transitions or back pointers weak.
   void MarkMapContents(Map* map);
-  void MarkDescriptorArray(DescriptorArray* descriptors);
   void MarkTransitionArray(TransitionArray* transitions);
 
  private:
index 3bffe241f6e8624daad0aa70a19210477b39020d..68358ef8f85f3dac074e8bd3fcb511f42557bc9d 100644 (file)
@@ -1887,30 +1887,6 @@ bool DescriptorArray::IsEmpty() {
 }
 
 
-bool DescriptorArray::MayContainTransitions() {
-  return !IsEmpty();
-}
-
-
-bool DescriptorArray::HasTransitionArray() {
-  return MayContainTransitions() && !get(kTransitionsIndex)->IsSmi();
-}
-
-
-Object* DescriptorArray::back_pointer_storage() {
-  return READ_FIELD(this, kBackPointerStorageOffset);
-}
-
-
-void DescriptorArray::set_back_pointer_storage(Object* value,
-                                               WriteBarrierMode mode) {
-  ASSERT(length() > kBackPointerStorageIndex);
-  Heap* heap = GetHeap();
-  WRITE_FIELD(this, kBackPointerStorageOffset, value);
-  CONDITIONAL_WRITE_BARRIER(heap, this, kBackPointerStorageOffset, value, mode);
-}
-
-
 void DescriptorArray::NoIncrementalWriteBarrierSwap(FixedArray* array,
                                                     int first,
                                                     int second) {
@@ -2000,27 +1976,6 @@ int DescriptorArray::SearchWithCache(String* name) {
 }
 
 
-TransitionArray* DescriptorArray::transitions() {
-  ASSERT(MayContainTransitions());
-  Object* array = get(kTransitionsIndex);
-  return TransitionArray::cast(array);
-}
-
-
-void DescriptorArray::ClearTransitions() {
-  WRITE_FIELD(this, kTransitionsOffset, Smi::FromInt(0));
-}
-
-
-void DescriptorArray::set_transitions(TransitionArray* transitions_array,
-                                      WriteBarrierMode mode) {
-  Heap* heap = GetHeap();
-  WRITE_FIELD(this, kTransitionsOffset, transitions_array);
-  CONDITIONAL_WRITE_BARRIER(
-      heap, this, kTransitionsOffset, transitions_array, mode);
-}
-
-
 Object** DescriptorArray::GetKeySlot(int descriptor_number) {
   ASSERT(descriptor_number < number_of_descriptors());
   return HeapObject::RawField(
@@ -3470,43 +3425,36 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
 
 
 DescriptorArray* Map::instance_descriptors() {
-  Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
-  if (!object->IsDescriptorArray()) {
-    ASSERT(object->IsMap() || object->IsUndefined());
-    return GetHeap()->empty_descriptor_array();
-  } else {
-    return DescriptorArray::cast(object);
-  }
+  if (!HasTransitionArray()) return GetHeap()->empty_descriptor_array();
+  return transitions()->descriptors();
 }
 
 
-void Map::set_instance_descriptors(DescriptorArray* value,
-                                   WriteBarrierMode mode) {
-  Heap* heap = GetHeap();
-
-  if (value == heap->empty_descriptor_array()) {
-    ClearDescriptorArray(heap, mode);
-    return;
-  }
+// If the descriptor is using the empty transition array, install a new empty
+// transition array that will have place for an element transition.
+static MaybeObject* EnsureHasTransitionArray(Map* map) {
+  if (map->HasTransitionArray()) return map;
 
-  Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
+  TransitionArray* transitions;
+  MaybeObject* maybe_transitions = TransitionArray::Allocate(0);
+  if (!maybe_transitions->To(&transitions)) return maybe_transitions;
+  map->set_transitions(transitions);
+  return transitions;
+}
 
-  if (object->IsDescriptorArray()) {
-    value->set_back_pointer_storage(
-        DescriptorArray::cast(object)->back_pointer_storage());
-  } else {
-    ASSERT(object->IsMap() || object->IsUndefined());
-    value->set_back_pointer_storage(object);
-  }
 
+MaybeObject* Map::SetDescriptors(DescriptorArray* value,
+                                 WriteBarrierMode mode) {
   ASSERT(!is_shared());
-  WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
-  CONDITIONAL_WRITE_BARRIER(
-      heap, this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
+  MaybeObject* maybe_failure = EnsureHasTransitionArray(this);
+  if (maybe_failure->IsFailure()) return maybe_failure;
+
+  transitions()->set_descriptors(value, mode);
+  return this;
 }
 
 
-void Map::InitializeDescriptors(DescriptorArray* descriptors) {
+MaybeObject* Map::InitializeDescriptors(DescriptorArray* descriptors) {
   int len = descriptors->number_of_descriptors();
   ASSERT(len <= DescriptorArray::kMaxNumberOfDescriptors);
   SLOW_ASSERT(descriptors->IsSortedNoDuplicates());
@@ -3526,36 +3474,37 @@ void Map::InitializeDescriptors(DescriptorArray* descriptors) {
   }
 #endif
 
-  set_instance_descriptors(descriptors);
+  MaybeObject* maybe_failure = SetDescriptors(descriptors);
+  if (maybe_failure->IsFailure()) return maybe_failure;
 
   for (int i = 0; i < len; ++i) {
     if (descriptors->GetDetails(i).index() == len) {
       SetLastAdded(i);
-      break;
+      return this;
     }
   }
 
-  ASSERT((len == 0 && LastAdded() == kNoneAdded) ||
-         len == descriptors->GetDetails(LastAdded()).index());
+  ASSERT(len == 0 && LastAdded() == kNoneAdded);
+  return this;
 }
 
 
 SMI_ACCESSORS(Map, bit_field3, kBitField3Offset)
 
 
-void Map::ClearDescriptorArray(Heap* heap, WriteBarrierMode mode) {
+void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) {
   Object* back_pointer = GetBackPointer();
 #ifdef DEBUG
-  Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
-  if (object->IsDescriptorArray()) {
+  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
+  if (object->IsTransitionArray()) {
     ZapTransitions();
   } else {
     ASSERT(object->IsMap() || object->IsUndefined());
   }
 #endif
-  WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, back_pointer);
+  WRITE_FIELD(this, kTransitionsOrBackPointerOffset, back_pointer);
   CONDITIONAL_WRITE_BARRIER(
-      heap, this, kInstanceDescriptorsOrBackPointerOffset, back_pointer, mode);
+      heap, this, kTransitionsOrBackPointerOffset, back_pointer, mode);
 }
 
 
@@ -3569,9 +3518,9 @@ void Map::AppendDescriptor(Descriptor* desc,
 
 
 Object* Map::GetBackPointer() {
-  Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
+  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
   if (object->IsDescriptorArray()) {
-    return DescriptorArray::cast(object)->back_pointer_storage();
+    return TransitionArray::cast(object)->back_pointer_storage();
   } else {
     ASSERT(object->IsMap() || object->IsUndefined());
     return object;
@@ -3585,7 +3534,8 @@ bool Map::HasElementsTransition() {
 
 
 bool Map::HasTransitionArray() {
-  return instance_descriptors()->HasTransitionArray();
+  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
+  return object->IsTransitionArray();
 }
 
 
@@ -3613,35 +3563,6 @@ void Map::SetTransition(int transition_index, Map* target) {
 }
 
 
-// If the map is using the empty descriptor array, install a new empty
-// descriptor array that will contain an elements transition.
-static MaybeObject* AllowTransitions(Map* map) {
-  if (map->instance_descriptors()->MayContainTransitions()) return map;
-  DescriptorArray* descriptors;
-  MaybeObject* maybe_descriptors =
-      DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED);
-  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
-  map->set_instance_descriptors(descriptors);
-  return descriptors;
-}
-
-
-// If the descriptor is using the empty transition array, install a new empty
-// transition array that will have place for an element transition.
-static MaybeObject* EnsureHasTransitionArray(Map* map) {
-  if (map->HasTransitionArray()) return map;
-
-  AllowTransitions(map);
-
-  TransitionArray* transitions;
-  MaybeObject* maybe_transitions = TransitionArray::Allocate(0);
-  if (!maybe_transitions->To(&transitions)) return maybe_transitions;
-  MaybeObject* added_transitions = map->set_transitions(transitions);
-  if (added_transitions->IsFailure()) return added_transitions;
-  return transitions;
-}
-
-
 MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) {
   MaybeObject* allow_elements = EnsureHasTransitionArray(this);
   if (allow_elements->IsFailure()) return allow_elements;
@@ -3679,40 +3600,32 @@ bool Map::HasPrototypeTransitions() {
 
 
 TransitionArray* Map::transitions() {
-  return instance_descriptors()->transitions();
-}
-
-
-void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) {
-#ifdef DEBUG
-  ZapTransitions();
-#endif
-  DescriptorArray* descriptors = instance_descriptors();
-  if (descriptors->number_of_descriptors() == 0) {
-    ClearDescriptorArray(heap, mode);
-  } else {
-    descriptors->ClearTransitions();
-  }
+  ASSERT(HasTransitionArray());
+  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
+  return TransitionArray::cast(object);
 }
 
 
-MaybeObject* Map::set_transitions(TransitionArray* transitions_array) {
-  MaybeObject* allow_transitions = AllowTransitions(this);
-  if (allow_transitions->IsFailure()) return allow_transitions;
+void Map::set_transitions(TransitionArray* transition_array,
+                          WriteBarrierMode mode) {
+  transition_array->set_descriptors(instance_descriptors());
+  transition_array->set_back_pointer_storage(GetBackPointer());
 #ifdef DEBUG
   if (HasTransitionArray()) {
-    ASSERT(transitions() != transitions_array);
+    ASSERT(transitions() != transition_array);
     ZapTransitions();
   }
 #endif
-  instance_descriptors()->set_transitions(transitions_array);
-  return this;
+
+  WRITE_FIELD(this, kTransitionsOrBackPointerOffset, transition_array);
+  CONDITIONAL_WRITE_BARRIER(
+      GetHeap(), this, kTransitionsOrBackPointerOffset, transition_array, mode);
 }
 
 
 void Map::init_back_pointer(Object* undefined) {
   ASSERT(undefined->IsUndefined());
-  WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, undefined);
+  WRITE_FIELD(this, kTransitionsOrBackPointerOffset, undefined);
 }
 
 
@@ -3720,13 +3633,13 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
   ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
   ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
          (value->IsMap() && GetBackPointer()->IsUndefined()));
-  Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
-  if (object->IsDescriptorArray()) {
-    DescriptorArray::cast(object)->set_back_pointer_storage(value);
+  Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
+  if (object->IsTransitionArray()) {
+    TransitionArray::cast(object)->set_back_pointer_storage(value);
   } else {
-    WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
+    WRITE_FIELD(this, kTransitionsOrBackPointerOffset, value);
     CONDITIONAL_WRITE_BARRIER(
-        GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
+        GetHeap(), this, kTransitionsOrBackPointerOffset, value, mode);
   }
 }
 
@@ -3734,10 +3647,8 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
 // Can either be Smi (no transitions), normal transition array, or a transition
 // array with the header overwritten as a Smi (thus iterating).
 TransitionArray* Map::unchecked_transition_array() {
-  ASSERT(HasTransitionArray());
-  Object* object = *HeapObject::RawField(instance_descriptors(),
-                                         DescriptorArray::kTransitionsOffset);
-  ASSERT(!object->IsSmi());
+  Object* object = *HeapObject::RawField(this,
+                                         Map::kTransitionsOrBackPointerOffset);
   TransitionArray* transition_array = static_cast<TransitionArray*>(object);
   return transition_array;
 }
index 749a35297c9a390bc33d6eab7d51bddf21faf9a4..1067691335b9727e37aa6b1b9bdd4d54dc058c45 100644 (file)
@@ -2192,7 +2192,7 @@ void Map::CopyAppendCallbackDescriptors(Handle<Map> map,
   // After this point the GC is not allowed to run anymore until the map is in a
   // consistent state again, i.e., all the descriptors are appended and the
   // descriptor array is trimmed to the right size.
-  map->set_instance_descriptors(*result);
+  Map::SetDescriptors(map, result);
 
   // Fill in new callback descriptors.  Process the callbacks from
   // back to front so that the last callback with a given name takes
@@ -2211,7 +2211,7 @@ void Map::CopyAppendCallbackDescriptors(Handle<Map> map,
   int new_number_of_descriptors = map->NumberOfSetDescriptors();
   // Reinstall the original descriptor array if no new elements were added.
   if (new_number_of_descriptors == descriptor_count) {
-    map->set_instance_descriptors(*array);
+    Map::SetDescriptors(map, array);
     return;
   }
 
@@ -4141,7 +4141,7 @@ MaybeObject* JSObject::PreventExtensions() {
   // Do a map transition, other objects with this map may still
   // be extensible.
   Map* new_map;
-  MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED);
+  MaybeObject* maybe = map()->Copy();
   if (!maybe->To(&new_map)) return maybe;
 
   new_map->set_is_extensible(false);
@@ -4178,6 +4178,13 @@ bool JSReceiver::IsSimpleEnum() {
 }
 
 
+void Map::SetDescriptors(Handle<Map> map,
+                         Handle<DescriptorArray> descriptors) {
+  Isolate* isolate = map->GetIsolate();
+  CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors));
+}
+
+
 int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
   int result = 0;
   DescriptorArray* descs = instance_descriptors();
@@ -4918,7 +4925,8 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
   } else {
     ASSERT(descriptors->GetDetails(last_added).index() ==
            descriptors->number_of_descriptors());
-    result->set_instance_descriptors(descriptors);
+    MaybeObject* maybe_failure = result->SetDescriptors(descriptors);
+    if (maybe_failure->IsFailure()) return maybe_failure;
     result->SetLastAdded(last_added);
   }
 
@@ -4927,9 +4935,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
     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;
-
+    set_transitions(transitions);
     result->SetBackPointer(this);
   }
 
@@ -4940,7 +4946,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
 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);
+  MaybeObject* maybe_new_map = Copy();
   if (!maybe_new_map->To(&new_map)) return maybe_new_map;
   new_map->set_elements_kind(kind);
 
@@ -4972,25 +4978,17 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
   // array describing these properties.
   ASSERT(constructor()->IsJSFunction());
   JSFunction* ctor = JSFunction::cast(constructor());
-  Map* initial_map = ctor->initial_map();
-  DescriptorArray* initial_descriptors = initial_map->instance_descriptors();
-  DescriptorArray* descriptors;
-  MaybeObject* maybe_descriptors =
-      initial_descriptors->Copy(DescriptorArray::MAY_BE_SHARED);
-  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
+  Map* map = ctor->initial_map();
+  DescriptorArray* descriptors = map->instance_descriptors();
 
-  int last_added = initial_map->LastAdded();
+  int last_added = map->LastAdded();
 
   return CopyReplaceDescriptors(descriptors, NULL, last_added, OMIT_TRANSITION);
 }
 
 
-MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
-  DescriptorArray* source_descriptors = instance_descriptors();
-  DescriptorArray* descriptors;
-  MaybeObject* maybe_descriptors = source_descriptors->Copy(shared_mode);
-  if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
-
+MaybeObject* Map::Copy() {
+  DescriptorArray* descriptors = instance_descriptors();
   int last_added = LastAdded();
 
   return CopyReplaceDescriptors(descriptors, NULL, last_added, OMIT_TRANSITION);
@@ -5017,8 +5015,7 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
   int new_size = old_size + 1;
 
   DescriptorArray* new_descriptors;
-  MaybeObject* maybe_descriptors =
-      DescriptorArray::Allocate(new_size, DescriptorArray::MAY_BE_SHARED);
+  MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size);
   if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
 
   FixedArray::WhitenessWitness witness(new_descriptors);
@@ -5079,8 +5076,7 @@ MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor,
   ASSERT(key == descriptors->GetKey(insertion_index));
 
   DescriptorArray* new_descriptors;
-  MaybeObject* maybe_descriptors =
-      DescriptorArray::Allocate(size, DescriptorArray::MAY_BE_SHARED);
+  MaybeObject* maybe_descriptors = DescriptorArray::Allocate(size);
   if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
 
   FixedArray::WhitenessWitness witness(new_descriptors);
@@ -5301,26 +5297,28 @@ class TraversableMap : public Map {
   // If we have an unvisited child map, return that one and advance. If we have
   // none, return NULL and reset any destroyed FixedArray maps.
   TraversableMap* ChildIteratorNext() {
-    if (HasTransitionArray()) {
-      TransitionArray* transition_array = unchecked_transition_array();
-
-      if (transition_array->HasPrototypeTransitions()) {
-        HeapObject* proto_transitions =
-            transition_array->UncheckedPrototypeTransitions();
-        IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
-        if (proto_iterator.IsIterating()) {
-          Map* next = proto_iterator.Next();
-          if (next != NULL) return static_cast<TraversableMap*>(next);
-        }
-      }
+    TransitionArray* transition_array = unchecked_transition_array();
+    if (!transition_array->map()->IsSmi() &&
+        !transition_array->IsTransitionArray()) {
+      return NULL;
+    }
 
-      IntrusiveMapTransitionIterator transition_iterator(transition_array);
-      if (transition_iterator.IsIterating()) {
-        Map* next = transition_iterator.Next();
+    if (transition_array->HasPrototypeTransitions()) {
+      HeapObject* proto_transitions =
+          transition_array->UncheckedPrototypeTransitions();
+      IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
+      if (proto_iterator.IsIterating()) {
+        Map* next = proto_iterator.Next();
         if (next != NULL) return static_cast<TraversableMap*>(next);
       }
     }
 
+    IntrusiveMapTransitionIterator transition_iterator(transition_array);
+    if (transition_iterator.IsIterating()) {
+      Map* next = transition_iterator.Next();
+      if (next != NULL) return static_cast<TraversableMap*>(next);
+    }
+
     return NULL;
   }
 };
@@ -5870,21 +5868,17 @@ 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 && shared_mode == MAY_BE_SHARED) {
-    return heap->empty_descriptor_array();
-  }
+  if (number_of_descriptors == 0) return heap->empty_descriptor_array();
   // Allocate the array of keys.
   MaybeObject* maybe_array =
       heap->AllocateFixedArray(LengthFor(number_of_descriptors));
   if (!maybe_array->To(&result)) return maybe_array;
 
   result->set(kEnumCacheIndex, Smi::FromInt(0));
-  result->set(kTransitionsIndex, Smi::FromInt(0));
   return result;
 }
 
@@ -5921,25 +5915,6 @@ void DescriptorArray::CopyFrom(int dst_index,
 }
 
 
-MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
-  // Allocate the new descriptor array.
-  int number_of_descriptors = this->number_of_descriptors();
-  DescriptorArray* new_descriptors;
-  MaybeObject* maybe_result = Allocate(number_of_descriptors, shared_mode);
-  if (!maybe_result->To(&new_descriptors)) return maybe_result;
-
-  // Copy the content.
-  if (number_of_descriptors > 0) {
-    FixedArray::WhitenessWitness witness(new_descriptors);
-    for (int i = 0; i < number_of_descriptors; i++) {
-      new_descriptors->CopyFrom(i, this, i, witness);
-    }
-  }
-
-  return new_descriptors;
-}
-
-
 // We need the whiteness witness since sort will reshuffle the entries in the
 // descriptor array. If the descriptor array were to be black, the shuffling
 // would move a slot that was already recorded as pointing into an evacuation
@@ -7292,7 +7267,8 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
   // the transition array from the map.
   if (transition_index == 0 &&
       !t->HasElementsTransition() &&
-      !t->HasPrototypeTransitions()) {
+      !t->HasPrototypeTransitions() &&
+      t->descriptors()->IsEmpty()) {
     return ClearTransitions(heap);
   }
 
@@ -7534,8 +7510,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()->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_new_map = initial_map()->Copy();
     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);
@@ -7564,7 +7539,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()->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_new_map = map()->Copy();
     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
     Heap* heap = new_map->GetHeap();
@@ -8859,7 +8834,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
 
   Map* new_map = map->GetPrototypeTransition(value);
   if (new_map == NULL) {
-    MaybeObject* maybe_new_map = map->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_new_map = map->Copy();
     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
     MaybeObject* maybe_new_cache =
@@ -12594,8 +12569,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(&descriptors)) {
     return maybe_descriptors;
   }
@@ -12667,8 +12641,9 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
 
   descriptors->Sort(witness);
 
+  MaybeObject* maybe_failure = new_map->InitializeDescriptors(descriptors);
+  if (maybe_failure->IsFailure()) return maybe_failure;
   new_map->set_unused_property_fields(unused_property_fields);
-  new_map->InitializeDescriptors(descriptors);
 
   // Transform the object.
   obj->set_map(new_map);
index 0b3143aba5f32cdf778d8c2f060445dd3688c68d..b7f3132e761a85a8e37f574c2a379ea93c1db096 100644 (file)
@@ -84,6 +84,7 @@
 //           - Context
 //           - JSFunctionResultCache
 //           - ScopeInfo
+//           - TransitionArray
 //         - FixedDoubleArray
 //         - ExternalArray
 //           - ExternalPixelArray
@@ -2459,32 +2460,21 @@ class FixedDoubleArray: public FixedArrayBase {
 
 // DescriptorArrays are fixed arrays used to hold instance descriptors.
 // The format of the these objects is:
-// 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).
-//   [0]: storage for bit_field3 for Map owning this object (Smi)
-//   [1]: point to a fixed array with (value, detail) pairs.
-//   [2]: next enumeration index (Smi), or pointer to small fixed array:
-//          [0]: next enumeration index (Smi)
-//          [1]: pointer to fixed array with enum cache
-//   [3]: first key
+//   [0]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
+//          [0]: pointer to fixed array with enum cache
+//          [1]: either Smi(0) or pointer to fixed array with indices
+//   [1]: first key
 //   [length() - kDescriptorSize]: last key
-//
 class DescriptorArray: public FixedArray {
  public:
   // Returns true for both shared empty_descriptor_array and for smis, which the
   // map uses to encode additional bit fields when the descriptor array is not
   // yet used.
   inline bool IsEmpty();
-  inline bool MayContainTransitions();
-  inline bool HasTransitionArray();
-
-  DECL_ACCESSORS(transitions, TransitionArray)
-  inline void ClearTransitions();
 
   // Returns the number of descriptors in the array.
   int number_of_descriptors() {
-    ASSERT(MayContainTransitions() || IsEmpty());
+    ASSERT(length() >= kFirstIndex || IsEmpty());
     int len = length();
     return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kDescriptorSize;
   }
@@ -2508,13 +2498,6 @@ class DescriptorArray: public FixedArray {
                                 kEnumCacheOffset);
   }
 
-  Object** GetTransitionsSlot() {
-    return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
-                                kTransitionsOffset);
-  }
-
-  DECL_ACCESSORS(back_pointer_storage, Object)
-
   // Initialize or change the enum cache,
   // using the supplied storage for the small "bridge".
   void SetEnumCache(FixedArray* bridge_storage,
@@ -2552,17 +2535,6 @@ class DescriptorArray: public FixedArray {
                 int src_index,
                 const WhitenessWitness&);
 
-  // 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* Copy(SharedMode shared_mode);
-
   // Sort the instance descriptors by the hash codes of their keys.
   void Sort(const WhitenessWitness&);
 
@@ -2578,8 +2550,7 @@ class DescriptorArray: public FixedArray {
 
   // 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);
@@ -2587,10 +2558,8 @@ class DescriptorArray: public FixedArray {
   // Constant for denoting key was not found.
   static const int kNotFound = -1;
 
-  static const int kBackPointerStorageIndex = 0;
-  static const int kEnumCacheIndex = 1;
-  static const int kTransitionsIndex = 2;
-  static const int kFirstIndex = 3;
+  static const int kEnumCacheIndex = 0;
+  static const int kFirstIndex = 1;
 
   // The length of the "bridge" to the enum cache.
   static const int kEnumCacheBridgeLength = 2;
@@ -2598,11 +2567,8 @@ class DescriptorArray: public FixedArray {
   static const int kEnumCacheBridgeIndicesCacheIndex = 1;
 
   // Layout description.
-  static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
-  static const int kEnumCacheOffset = kBackPointerStorageOffset +
-                                      kPointerSize;
-  static const int kTransitionsOffset = kEnumCacheOffset + kPointerSize;
-  static const int kFirstOffset = kTransitionsOffset + kPointerSize;
+  static const int kEnumCacheOffset = FixedArray::kHeaderSize;
+  static const int kFirstOffset = kEnumCacheOffset + kPointerSize;
 
   // Layout description for the bridge array.
   static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize;
@@ -4821,11 +4787,9 @@ class Map: public HeapObject {
   inline Map* elements_transition_map();
   MUST_USE_RESULT inline MaybeObject* set_elements_transition_map(
       Map* transitioned_map);
-  inline TransitionArray* transitions();
   inline void SetTransition(int index, Map* target);
   MUST_USE_RESULT inline MaybeObject* AddTransition(String* key, Map* target);
-  MUST_USE_RESULT inline MaybeObject* set_transitions(
-      TransitionArray* transitions);
+  DECL_ACCESSORS(transitions, TransitionArray)
   inline void ClearTransitions(Heap* heap,
                                WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
 
@@ -4862,12 +4826,14 @@ class Map: public HeapObject {
   inline JSFunction* unchecked_constructor();
 
   // [instance descriptors]: describes the object.
-  DECL_ACCESSORS(instance_descriptors, DescriptorArray)
-  inline void InitializeDescriptors(DescriptorArray* descriptors);
-
-  // Should only be called to clear a descriptor array that was only used to
-  // store transitions and does not contain any live transitions anymore.
-  inline void ClearDescriptorArray(Heap* heap, WriteBarrierMode mode);
+  inline DescriptorArray* instance_descriptors();
+  MUST_USE_RESULT inline MaybeObject* SetDescriptors(
+      DescriptorArray* descriptors,
+      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+  static void SetDescriptors(Handle<Map> map,
+                             Handle<DescriptorArray> descriptors);
+  MUST_USE_RESULT inline MaybeObject* InitializeDescriptors(
+      DescriptorArray* descriptors);
 
   // [stub cache]: contains stubs compiled for this map.
   DECL_ACCESSORS(code_cache, Object)
@@ -4973,7 +4939,7 @@ class Map: public HeapObject {
 
   // Returns a copy of the map, with all transitions dropped from the
   // instance descriptors.
-  MUST_USE_RESULT MaybeObject* Copy(DescriptorArray::SharedMode shared_mode);
+  MUST_USE_RESULT MaybeObject* Copy();
 
   // Returns the property index for name (only valid for FAST MODE).
   int PropertyIndexFor(String* name);
@@ -5095,14 +5061,14 @@ class Map: public HeapObject {
   static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
   static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;
   static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
-  // Storage for instance descriptors is overloaded to also contain additional
-  // map flags when unused (bit_field3). When the map has instance descriptors,
-  // the flags are transferred to the instance descriptor array and accessed
-  // through an extra indirection.
-  static const int kInstanceDescriptorsOrBackPointerOffset =
+  // Storage for the transition array is overloaded to directly contain a back
+  // pointer if unused. When the map has transitions, the back pointer is
+  // transferred to the transition array and accessed through an extra
+  // indirection.
+  static const int kTransitionsOrBackPointerOffset =
       kConstructorOffset + kPointerSize;
   static const int kCodeCacheOffset =
-      kInstanceDescriptorsOrBackPointerOffset + kPointerSize;
+      kTransitionsOrBackPointerOffset + kPointerSize;
   static const int kBitField3Offset = kCodeCacheOffset + kPointerSize;
   static const int kPadStart = kBitField3Offset + kPointerSize;
   static const int kSize = MAP_POINTER_ALIGN(kPadStart);
index 9a91ad670ab56658efc0939c0ea060d1a480a47a..1a4139642c9e1a6a65edf12fc0d4a2b8fa627884 100644 (file)
@@ -2009,9 +2009,10 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        Map::kConstructorOffset);
   if (!map->instance_descriptors()->IsEmpty()) {
     TagObject(map->instance_descriptors(), "(map descriptors)");
+    // TODO(verwaest): Check what to do here.
     SetInternalReference(map, entry,
                          "descriptors", map->instance_descriptors(),
-                         Map::kInstanceDescriptorsOrBackPointerOffset);
+                         Map::kTransitionsOrBackPointerOffset);
   }
   SetInternalReference(map, entry,
                        "code_cache", map->code_cache(),
index 16d2c76f22c863a7b564e340882e6e29ae31799a..146607def5edb2814ca921b4149269b49bf7f89f 100644 (file)
@@ -1294,7 +1294,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
   if (needs_access_checks) {
     // Copy map so it won't interfere constructor's initial map.
     Map* new_map;
-    MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_new_map = old_map->Copy();
     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
     new_map->set_is_access_check_needed(false);
@@ -1311,7 +1311,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
   if (!old_map->is_access_check_needed()) {
     // Copy map so it won't interfere constructor's initial map.
     Map* new_map;
-    MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
+    MaybeObject* maybe_new_map = old_map->Copy();
     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
 
     new_map->set_is_access_check_needed(true);
index 6716c717abdc323bb5a8b1d150af9181b1ddb539..0fb5fbeac2c1eee8732663217ff2e4b58cb62478 100644 (file)
@@ -82,6 +82,40 @@ void TransitionArray::set_elements_transition(Map* transition_map,
 }
 
 
+DescriptorArray* TransitionArray::descriptors() {
+  return DescriptorArray::cast(get(kDescriptorsIndex));
+}
+
+
+void TransitionArray::set_descriptors(DescriptorArray* descriptors,
+                                      WriteBarrierMode mode) {
+  Heap* heap = GetHeap();
+  WRITE_FIELD(this, kDescriptorsOffset, descriptors);
+  CONDITIONAL_WRITE_BARRIER(
+      heap, this, kDescriptorsOffset, descriptors, mode);
+}
+
+
+Object** TransitionArray::GetDescriptorsSlot() {
+  return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
+                              kDescriptorsOffset);
+}
+
+
+Object* TransitionArray::back_pointer_storage() {
+  return get(kBackPointerStorageIndex);
+}
+
+
+void TransitionArray::set_back_pointer_storage(Object* back_pointer,
+                                               WriteBarrierMode mode) {
+  Heap* heap = GetHeap();
+  WRITE_FIELD(this, kBackPointerStorageOffset, back_pointer);
+  CONDITIONAL_WRITE_BARRIER(
+      heap, this, kBackPointerStorageOffset, back_pointer, mode);
+}
+
+
 bool TransitionArray::HasPrototypeTransitions() {
   Object* prototype_transitions = get(kPrototypeTransitionsIndex);
   return prototype_transitions != Smi::FromInt(0);
@@ -95,9 +129,8 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
 
 
 HeapObject* TransitionArray::UncheckedPrototypeTransitions() {
-  Object* prototype_transitions = get(kPrototypeTransitionsIndex);
-  if (prototype_transitions == Smi::FromInt(0)) return NULL;
-  return reinterpret_cast<HeapObject*>(prototype_transitions);
+  ASSERT(HasPrototypeTransitions());
+  return reinterpret_cast<HeapObject*>(get(kPrototypeTransitionsIndex));
 }
 
 
index 5dda18eddf8559a09ae7aa8e1cef5a8d1204720a..6f8b2fec5a9583a3785587c12f0a46ee5a3ab645 100644 (file)
@@ -39,10 +39,9 @@ MaybeObject* TransitionArray::Allocate(int number_of_transitions) {
   Heap* heap = Isolate::Current()->heap();
   // Use FixedArray to not use DescriptorArray::cast on incomplete object.
   FixedArray* array;
-  { MaybeObject* maybe_array =
-        heap->AllocateFixedArray(ToKeyIndex(number_of_transitions));
-    if (!maybe_array->To(&array)) return maybe_array;
-  }
+  MaybeObject* maybe_array =
+      heap->AllocateFixedArray(ToKeyIndex(number_of_transitions));
+  if (!maybe_array->To(&array)) return maybe_array;
 
   array->set(kElementsTransitionIndex, Smi::FromInt(0));
   array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
index 57f32535a5a01ebd938ca80513e4ddfe86fa3ea2..d0d761b5de367de35a60bb7694398f007a400120 100644 (file)
@@ -41,8 +41,11 @@ namespace internal {
 // TransitionArrays are fixed arrays used to hold map transitions for property,
 // constant, and element changes.
 // The format of the these objects is:
-// [0] Elements transition
-// [1] First transition
+// [0] Descriptor array
+// [1] Undefined or back pointer map
+// [2] Smi(0) or elements transition map
+// [3] Smi(0) or fixed array of prototype transitions
+// [4] First transition
 // [length() - kTransitionSize] Last transition
 class TransitionArray: public FixedArray {
  public:
@@ -63,6 +66,16 @@ class TransitionArray: public FixedArray {
   inline bool HasElementsTransition();
   inline void ClearElementsTransition();
 
+  inline DescriptorArray* descriptors();
+  inline void set_descriptors(DescriptorArray* descriptors,
+                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+  inline Object** GetDescriptorsSlot();
+
+  inline Object* back_pointer_storage();
+  inline void set_back_pointer_storage(
+      Object* back_pointer,
+      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
   inline FixedArray* GetPrototypeTransitions();
   inline void SetPrototypeTransitions(
       FixedArray* prototype_transitions,
@@ -106,15 +119,20 @@ class TransitionArray: public FixedArray {
   // Constant for denoting key was not found.
   static const int kNotFound = -1;
 
-  static const int kElementsTransitionIndex = 0;
-  static const int kPrototypeTransitionsIndex = 1;
-  static const int kFirstIndex = 2;
+  static const int kDescriptorsIndex = 0;
+  static const int kBackPointerStorageIndex = 1;
+  static const int kElementsTransitionIndex = 2;
+  static const int kPrototypeTransitionsIndex = 3;
+  static const int kFirstIndex = 4;
 
   // Layout transition array header.
-  static const int kElementsTransitionOffset = FixedArray::kHeaderSize;
+  static const int kDescriptorsOffset = FixedArray::kHeaderSize;
+  static const int kBackPointerStorageOffset = kDescriptorsOffset +
+                                               kPointerSize;
+  static const int kElementsTransitionOffset = kBackPointerStorageOffset +
+                                               kPointerSize;
   static const int kPrototypeTransitionsOffset = kElementsTransitionOffset +
                                                  kPointerSize;
-  static const int kFirstOffset = kPrototypeTransitionsOffset + kPointerSize;
 
   // Layout of map transition.
   static const int kTransitionKey = 0;
index 9ec16a1f197db9ad1773313b1a2a4532c6cfe6d9..2e554b166b902a18bba4c5da45e3dc11236d87f6 100644 (file)
@@ -2860,14 +2860,15 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
 
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
-  movq(descriptors, FieldOperand(map,
-                                 Map::kInstanceDescriptorsOrBackPointerOffset));
+  Register temp = descriptors;
+  movq(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset));
 
   Label ok, fail;
-  CheckMap(descriptors,
+  CheckMap(temp,
            isolate()->factory()->fixed_array_map(),
            &fail,
            DONT_DO_SMI_CHECK);
+  movq(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
   jmp(&ok);
   bind(&fail);
   Move(descriptors, isolate()->factory()->empty_descriptor_array());
@@ -4471,13 +4472,17 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
   // check for an enum cache.  Leave the map in rbx for the subsequent
   // prototype load.
   movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
-  movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBackPointerOffset));
+  movq(rdx, FieldOperand(rbx, Map::kTransitionsOrBackPointerOffset));
 
   CheckMap(rdx,
            isolate()->factory()->fixed_array_map(),
            call_runtime,
            DONT_DO_SMI_CHECK);
 
+  movq(rdx, FieldOperand(rdx, TransitionArray::kDescriptorsOffset));
+  cmpq(rdx, empty_descriptor_array_value);
+  j(equal, call_runtime);
+
   // Check that there is an enum cache in the non-empty instance
   // descriptors (rdx).  This is the case if the next enumeration
   // index field does not contain a smi.
index f64ed1af199727c91af0d946bbeac6d9e3b08e08..50e60da27177f4faa6bbe8d07a68af43c59d9b24 100644 (file)
@@ -158,7 +158,7 @@ TEST(StressJS) {
   Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(1);
 
   v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors);
-  map->set_instance_descriptors(*new_descriptors);
+  v8::internal::Map::SetDescriptors(map, new_descriptors);
 
   CallbacksDescriptor d(*name,
                         *foreign,