Revision: 12042
Author:   [email protected]
Date:     Wed Jul 11 07:26:42 2012
Log: Ensure that all descriptors have a valid enumeration index, and replace NextEnumIndex with LastAdded.

The LastAdded points to the descriptor that was last added to the array. From the descriptor we can deduce the NextEnumerationIndex. This allows us to quickly find the property that we are transitioning to, which is necessary for transition-intensive code, eg JSON parsing.

Review URL: https://chromiumcodereview.appspot.com/10695120
http://code.google.com/p/v8/source/detail?r=12042

Modified:
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/property.h
 /branches/bleeding_edge/src/transitions-inl.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Jul 10 06:31:36 2012 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Jul 11 07:26:42 2012
@@ -1142,7 +1142,7 @@
   // We got a map in register r0. Get the enumeration cache from it.
   __ bind(&use_cache);
   __ LoadInstanceDescriptors(r0, r1, r2);
- __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
+  __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kLastAddedOffset));
__ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));

   // Set up the four remaining stack slots.
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Jul 10 06:31:36 2012 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Jul 11 07:26:42 2012
@@ -5360,7 +5360,7 @@
   Register scratch = ToRegister(instr->scratch());
   __ LoadInstanceDescriptors(map, result, scratch);
   __ ldr(result,
- FieldMemOperand(result, DescriptorArray::kEnumerationIndexOffset));
+         FieldMemOperand(result, DescriptorArray::kLastAddedOffset));
   __ ldr(result,
          FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
   __ cmp(result, Operand(0));
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jul 10 06:31:36 2012 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Jul 11 07:26:42 2012
@@ -3723,7 +3723,7 @@
   // 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.
-  ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
+  ldr(r3, FieldMemOperand(r3, DescriptorArray::kLastAddedOffset));
   JumpIfSmi(r3, call_runtime);

   // For all objects but the receiver, check that the cache is empty.
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Jul  5 06:54:20 2012
+++ /branches/bleeding_edge/src/bootstrapper.cc Wed Jul 11 07:26:42 2012
@@ -390,25 +390,32 @@

   DescriptorArray::WhitenessWitness witness(*descriptors);

+  int index = 0;
+
   {  // Add length.
     Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionLength));
-    CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs);
-    descriptors->Set(0, &d, witness);
+ CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add name.
     Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionName));
-    CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs);
-    descriptors->Set(1, &d, witness);
+ CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add arguments.
Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionArguments));
-    CallbacksDescriptor d(*factory()->arguments_symbol(), *f, attribs);
-    descriptors->Set(2, &d, witness);
+    CallbacksDescriptor d(
+        *factory()->arguments_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add caller.
     Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionCaller));
-    CallbacksDescriptor d(*factory()->caller_symbol(), *f, attribs);
-    descriptors->Set(3, &d, witness);
+ CallbacksDescriptor d(*factory()->caller_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   if (prototypeMode != DONT_ADD_PROTOTYPE) {
     // Add prototype.
@@ -416,9 +423,11 @@
       attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
     }
Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionPrototype));
-    CallbacksDescriptor d(*factory()->prototype_symbol(), *f, attribs);
-    descriptors->Set(4, &d, witness);
-  }
+    CallbacksDescriptor d(
+        *factory()->prototype_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+  }
+
   descriptors->Sort(witness);
   return descriptors;
 }
@@ -533,25 +542,32 @@

   DescriptorArray::WhitenessWitness witness(*descriptors);

+  int index = 0;
   {  // Add length.
     Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionLength));
-    CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs);
-    descriptors->Set(0, &d, witness);
+ CallbacksDescriptor d(*factory()->length_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add name.
     Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionName));
-    CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs);
-    descriptors->Set(1, &d, witness);
+ CallbacksDescriptor d(*factory()->name_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add arguments.
     Handle<AccessorPair> arguments(factory()->NewAccessorPair());
- CallbacksDescriptor d(*factory()->arguments_symbol(), *arguments, attribs);
-    descriptors->Set(2, &d, witness);
+    CallbacksDescriptor d(
+        *factory()->arguments_symbol(), *arguments, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }
   {  // Add caller.
     Handle<AccessorPair> caller(factory()->NewAccessorPair());
-    CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs);
-    descriptors->Set(3, &d, witness);
+    CallbacksDescriptor d(
+        *factory()->caller_symbol(), *caller, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
+    ++index;
   }

   if (prototypeMode != DONT_ADD_PROTOTYPE) {
@@ -560,8 +576,9 @@
       attribs = static_cast<PropertyAttributes>(attribs | READ_ONLY);
     }
Handle<Foreign> f(factory()->NewForeign(&Accessors::FunctionPrototype));
-    CallbacksDescriptor d(*factory()->prototype_symbol(), *f, attribs);
-    descriptors->Set(4, &d, witness);
+    CallbacksDescriptor d(
+        *factory()->prototype_symbol(), *f, attribs, index + 1);
+    descriptors->Set(index, &d, witness);
   }

   descriptors->Sort(witness);
@@ -950,38 +967,42 @@
     DescriptorArray::WhitenessWitness witness(*descriptors);
     PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
-    int enum_index = 0;
+    int index = 0;
     {
       // ECMA-262, section 15.10.7.1.
       FieldDescriptor field(heap->source_symbol(),
                             JSRegExp::kSourceFieldIndex,
                             final,
-                            enum_index++);
-      descriptors->Set(0, &field, witness);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
+      ++index;
     }
     {
       // ECMA-262, section 15.10.7.2.
       FieldDescriptor field(heap->global_symbol(),
                             JSRegExp::kGlobalFieldIndex,
                             final,
-                            enum_index++);
-      descriptors->Set(1, &field, witness);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
+      ++index;
     }
     {
       // ECMA-262, section 15.10.7.3.
       FieldDescriptor field(heap->ignore_case_symbol(),
                             JSRegExp::kIgnoreCaseFieldIndex,
                             final,
-                            enum_index++);
-      descriptors->Set(2, &field, witness);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
+      ++index;
     }
     {
       // ECMA-262, section 15.10.7.4.
       FieldDescriptor field(heap->multiline_symbol(),
                             JSRegExp::kMultilineFieldIndex,
                             final,
-                            enum_index++);
-      descriptors->Set(3, &field, witness);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
+      ++index;
     }
     {
       // ECMA-262, section 15.10.7.5.
@@ -990,10 +1011,9 @@
       FieldDescriptor field(heap->last_index_symbol(),
                             JSRegExp::kLastIndexFieldIndex,
                             writable,
-                            enum_index++);
-      descriptors->Set(4, &field, witness);
-    }
-    descriptors->SetNextEnumerationIndex(enum_index);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
+    }
     descriptors->Sort(witness);

     initial_map->set_inobject_properties(5);
@@ -1138,17 +1158,26 @@
     // Create the descriptor array for the arguments object.
     Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
     DescriptorArray::WhitenessWitness witness(*descriptors);
+    int index = 0;
     {  // length
-      FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
-      descriptors->Set(0, &d, witness);
+ FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM, index + 1);
+      descriptors->Set(index, &d, witness);
+      ++index;
     }
     {  // callee
- CallbacksDescriptor d(*factory->callee_symbol(), *callee, attributes);
-      descriptors->Set(1, &d, witness);
+      CallbacksDescriptor d(*factory->callee_symbol(),
+                            *callee,
+                            attributes,
+                            index + 1);
+      descriptors->Set(index, &d, witness);
+      ++index;
     }
     {  // caller
- CallbacksDescriptor d(*factory->caller_symbol(), *caller, attributes);
-      descriptors->Set(2, &d, witness);
+      CallbacksDescriptor d(*factory->caller_symbol(),
+                            *caller,
+                            attributes,
+                            index + 1);
+      descriptors->Set(index, &d, witness);
     }
     descriptors->Sort(witness);

@@ -1741,26 +1770,27 @@
     JSFunction* array_function = global_context()->array_function();
     Handle<DescriptorArray> array_descriptors(
         array_function->initial_map()->instance_descriptors());
- int index = array_descriptors->SearchWithCache(heap()->length_symbol());
+    int old = array_descriptors->SearchWithCache(heap()->length_symbol());
     MaybeObject* copy_result =
- reresult_descriptors->CopyFrom(0, *array_descriptors, index, witness); + reresult_descriptors->CopyFrom(0, *array_descriptors, old, witness);
     if (copy_result->IsFailure()) return false;

-    int enum_index = 0;
+    int index = 1;
     {
       FieldDescriptor index_field(heap()->index_symbol(),
                                   JSRegExpResult::kIndexIndex,
                                   NONE,
-                                  enum_index++);
-      reresult_descriptors->Set(1, &index_field, witness);
+                                  index + 1);
+      reresult_descriptors->Set(index, &index_field, witness);
+      ++index;
     }

     {
       FieldDescriptor input_field(heap()->input_symbol(),
                                   JSRegExpResult::kInputIndex,
                                   NONE,
-                                  enum_index++);
-      reresult_descriptors->Set(2, &input_field, witness);
+                                  index + 1);
+      reresult_descriptors->Set(index, &input_field, witness);
     }
     reresult_descriptors->Sort(witness);

=======================================
--- /branches/bleeding_edge/src/factory.cc      Mon Jul  9 01:59:03 2012
+++ /branches/bleeding_edge/src/factory.cc      Wed Jul 11 07:26:42 2012
@@ -892,7 +892,7 @@
     String* key,
     Object* value,
     PropertyAttributes attributes) {
-  CallbacksDescriptor desc(key, value, attributes);
+  CallbacksDescriptor desc(key, value, attributes, 0);
   MaybeObject* obj = array->CopyInsert(&desc);
   return obj;
 }
@@ -936,6 +936,8 @@
   // Fill in new callback descriptors.  Process the callbacks from
   // back to front so that the last callback with a given name takes
   // precedence over previously added callbacks with that name.
+  int added_descriptor_count = descriptor_count;
+  int next_enum = array->NextEnumerationIndex();
   for (int i = nof_callbacks - 1; i >= 0; i--) {
     Handle<AccessorInfo> entry =
         Handle<AccessorInfo>(AccessorInfo::cast(callbacks.get(i)));
@@ -943,19 +945,26 @@
     Handle<String> key =
         SymbolFromString(Handle<String>(String::cast(entry->name())));
     // Check if a descriptor with this name already exists before writing.
-    if (LinearSearch(*result, EXPECT_UNSORTED, *key, descriptor_count) ==
+ if (LinearSearch(*result, EXPECT_UNSORTED, *key, added_descriptor_count) ==
         DescriptorArray::kNotFound) {
-      CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
-      result->Set(descriptor_count, &desc, witness);
-      descriptor_count++;
+      CallbacksDescriptor desc(*key,
+                               *entry,
+                               entry->property_attributes(),
+                               next_enum++);
+      result->Set(added_descriptor_count, &desc, witness);
+      added_descriptor_count++;
     }
   }
+
+  // Return the old descriptor array if there were no new elements.
+  if (added_descriptor_count == descriptor_count) return array;

   // If duplicates were detected, allocate a result of the right size
   // and transfer the elements.
-  if (descriptor_count < result->length()) {
- Handle<DescriptorArray> new_result = NewDescriptorArray(descriptor_count);
-    for (int i = 0; i < descriptor_count; i++) {
+  if (added_descriptor_count < result->length()) {
+    Handle<DescriptorArray> new_result =
+        NewDescriptorArray(added_descriptor_count);
+    for (int i = 0; i < added_descriptor_count; i++) {
       DescriptorArray::CopyFrom(new_result, i, result, i, witness);
     }
     result = new_result;
@@ -963,6 +972,7 @@

   // Sort the result before returning.
   result->Sort(witness);
+  ASSERT(result->NextEnumerationIndex() == next_enum);
   return result;
 }

=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Jul 10 06:31:36 2012
+++ /branches/bleeding_edge/src/heap.cc Wed Jul 11 07:26:42 2012
@@ -3883,11 +3883,9 @@
       for (int i = 0; i < count; i++) {
         String* name = fun->shared()->GetThisPropertyAssignmentName(i);
         ASSERT(name->IsSymbol());
-        FieldDescriptor field(name, i, NONE);
-        field.SetEnumerationIndex(i);
+        FieldDescriptor field(name, i, NONE, i + 1);
         descriptors->Set(i, &field, witness);
       }
-      descriptors->SetNextEnumerationIndex(count);
       descriptors->SortUnchecked(witness);

// The descriptors may contain duplicates because the compiler does not
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Jun 26 06:56:48 2012 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Jul 11 07:26:42 2012
@@ -1092,7 +1092,7 @@
   // We got a map in register eax. Get the enumeration cache from it.
   __ bind(&use_cache);
   __ LoadInstanceDescriptors(eax, ecx);
-  __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
+  __ mov(ecx, FieldOperand(ecx, DescriptorArray::kLastAddedOffset));
__ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));

   // Set up the four remaining stack slots.
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Jul 5 06:54:20 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jul 11 07:26:42 2012
@@ -5293,7 +5293,7 @@
   Register result = ToRegister(instr->result());
   __ LoadInstanceDescriptors(map, result);
   __ mov(result,
-         FieldOperand(result, DescriptorArray::kEnumerationIndexOffset));
+         FieldOperand(result, DescriptorArray::kLastAddedOffset));
   __ mov(result,
          FieldOperand(result, FixedArray::SizeFor(instr->idx())));
   __ test(result, result);
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jul 10 06:31:36 2012 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed Jul 11 07:26:42 2012
@@ -2901,7 +2901,7 @@
   // 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.
-  mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
+  mov(edx, FieldOperand(edx, DescriptorArray::kLastAddedOffset));
   JumpIfSmi(edx, call_runtime);

   // For all objects but the receiver, check that the cache is empty.
=======================================
--- /branches/bleeding_edge/src/ic.cc   Mon Jul  9 03:28:56 2012
+++ /branches/bleeding_edge/src/ic.cc   Wed Jul 11 07:26:42 2012
@@ -1518,8 +1518,7 @@

       Handle<Map> transition(Map::cast(value));
DescriptorArray* target_descriptors = transition->instance_descriptors();
-      int descriptor = target_descriptors->SearchWithCache(*name);
-      ASSERT(descriptor != DescriptorArray::kNotFound);
+      int descriptor = target_descriptors->LastAdded();
       PropertyDetails details = target_descriptors->GetDetails(descriptor);

       if (details.type() != FIELD || details.attributes() != NONE) return;
@@ -1990,8 +1989,7 @@

       Handle<Map> transition(Map::cast(value));
DescriptorArray* target_descriptors = transition->instance_descriptors();
-      int descriptor = target_descriptors->SearchWithCache(*name);
-      ASSERT(descriptor != DescriptorArray::kNotFound);
+      int descriptor = target_descriptors->LastAdded();
       PropertyDetails details = target_descriptors->GetDetails(descriptor);

       if (details.type() == FIELD && details.attributes() == NONE) {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Tue Jul 10 06:31:36 2012
+++ /branches/bleeding_edge/src/objects-inl.h   Wed Jul 11 07:26:42 2012
@@ -2095,6 +2095,7 @@
                           const WhitenessWitness&) {
   // Range check.
   ASSERT(descriptor_number < number_of_descriptors());
+  ASSERT(desc->GetDetails().index() > 0);

   NoIncrementalWriteBarrierSet(this,
                                ToKeyIndex(descriptor_number),
=======================================
--- /branches/bleeding_edge/src/objects.cc      Tue Jul 10 06:31:36 2012
+++ /branches/bleeding_edge/src/objects.cc      Wed Jul 11 07:26:42 2012
@@ -1546,7 +1546,7 @@
   int index = map()->NextFreePropertyIndex();

   // Allocate new instance descriptors with (name, index) added
-  FieldDescriptor new_field(name, index, attributes);
+  FieldDescriptor new_field(name, index, attributes, 0);
   DescriptorArray* new_descriptors;
   { MaybeObject* maybe_new_descriptors =
         old_descriptors->CopyInsert(&new_field);
@@ -1555,18 +1555,11 @@
     }
   }

- // Only allow map transition if the object isn't the global object and there - // is not a transition for the name, or there's a transition for the name but
-  // it's unrelated to properties.
-  int descriptor_index = old_descriptors->SearchWithCache(name);
-
- // Element transitions are stored in the descriptor for property "", which is - // not a identifier and should have forced a switch to slow properties above. - bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound;
+  // Only allow map transition if the object isn't the global object.
   bool allow_map_transition =
-      can_insert_transition &&
(isolate->context()->global_context()->object_function()->map() != map());

+  ASSERT(old_descriptors->Search(name) == DescriptorArray::kNotFound);
   ASSERT(index < map()->inobject_properties() ||
          (index - map()->inobject_properties()) < properties()->length() ||
          map()->unused_property_fields() == 0);
@@ -1622,7 +1615,7 @@
     JSFunction* function,
     PropertyAttributes attributes) {
   // Allocate new instance descriptors with (name, function) added
-  ConstantFunctionDescriptor d(name, function, attributes);
+  ConstantFunctionDescriptor d(name, function, attributes, 0);
   DescriptorArray* new_descriptors;
   { MaybeObject* maybe_new_descriptors =
         map()->instance_descriptors()->CopyInsert(&d);
@@ -1865,7 +1858,7 @@
   }

   int index = map()->NextFreePropertyIndex();
-  FieldDescriptor new_field(name, index, attributes);
+  FieldDescriptor new_field(name, index, attributes, 0);
   // Make a new DescriptorArray replacing an entry with FieldDescriptor.
   Object* descriptors_unchecked;
   { MaybeObject* maybe_descriptors_unchecked =
@@ -2938,7 +2931,7 @@

       Map* transition_map = Map::cast(transition);
DescriptorArray* descriptors = transition_map->instance_descriptors();
-      int descriptor = descriptors->SearchWithCache(*name);
+      int descriptor = descriptors->LastAdded();
       PropertyDetails details = descriptors->GetDetails(descriptor);
ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);

@@ -3062,7 +3055,7 @@

       Map* transition_map = Map::cast(transition);
DescriptorArray* descriptors = transition_map->instance_descriptors();
-      int descriptor = descriptors->Search(name);
+      int descriptor = descriptors->LastAdded();
       PropertyDetails details = descriptors->GetDetails(descriptor);
ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);

@@ -4610,7 +4603,7 @@

// step 2: create a copy of the descriptors, incl. the new getter/setter pair
   Map* map1 = obj->map();
-  CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
+  CallbacksDescriptor callbacks_descr2(name, accessors2, attributes, 0);
   DescriptorArray* descriptors2;
   { MaybeObject* maybe_descriptors2 =
         map1->instance_descriptors()->CopyInsert(&callbacks_descr2);
@@ -4657,7 +4650,7 @@
                                      Object* accessor,
                                      PropertyAttributes attributes ) {
   DescriptorArray* descs = Map::cast(map)->instance_descriptors();
-  int number = descs->SearchWithCache(name);
+  int number = descs->LastAdded();
   ASSERT(number != DescriptorArray::kNotFound);
   Object* target_accessor =
AccessorPair::cast(descs->GetCallbacksObject(number))->get(component);
@@ -4681,7 +4674,7 @@

// step 2: create a copy of the descriptors, incl. the new getter/setter pair
   Map* map2 = obj->map();
-  CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
+  CallbacksDescriptor callbacks_descr3(name, accessors3, attributes, 0);
   DescriptorArray* descriptors3;
   { MaybeObject* maybe_descriptors3 =
         map2->instance_descriptors()->CopyInsert(&callbacks_descr3);
@@ -5817,8 +5810,7 @@
     if (!maybe_array->To(&result)) return maybe_array;
   }

-  result->set(kEnumerationIndexIndex,
-              Smi::FromInt(PropertyDetails::kInitialIndex));
+  result->set(kLastAddedIndex, Smi::FromInt(-1));
   result->set(kTransitionsIndex, Smi::FromInt(0));
   return result;
 }
@@ -5830,9 +5822,9 @@
   ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
   ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
   if (HasEnumCache()) {
-    FixedArray::cast(get(kEnumerationIndexIndex))->
+    FixedArray::cast(get(kLastAddedIndex))->
       set(kEnumCacheBridgeCacheIndex, new_cache);
-    FixedArray::cast(get(kEnumerationIndexIndex))->
+    FixedArray::cast(get(kLastAddedIndex))->
       set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
   } else {
     if (IsEmpty()) return;  // Do nothing for empty descriptor array.
@@ -5841,9 +5833,9 @@
     FixedArray::cast(bridge_storage)->
       set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
     NoWriteBarrierSet(FixedArray::cast(bridge_storage),
-                      kEnumCacheBridgeEnumIndex,
-                      get(kEnumerationIndexIndex));
-    set(kEnumerationIndexIndex, bridge_storage);
+                      kEnumCacheBridgeLastAdded,
+                      get(kLastAddedIndex));
+    set(kLastAddedIndex, bridge_storage);
   }
 }

@@ -5910,14 +5902,11 @@

// Set the enumeration index in the descriptors and set the enumeration index
   // in the result.
-  int enumeration_index = NextEnumerationIndex();
   if (keep_enumeration_index) {
     descriptor->SetEnumerationIndex(GetDetails(index).index());
   } else {
-    descriptor->SetEnumerationIndex(enumeration_index);
-    ++enumeration_index;
-  }
-  new_descriptors->SetNextEnumerationIndex(enumeration_index);
+    descriptor->SetEnumerationIndex(NextEnumerationIndex());
+  }

   // Copy the descriptors, inserting or replacing a descriptor.
   int to_index = 0;
@@ -5939,6 +5928,11 @@

   ASSERT(insertion_index < new_descriptors->number_of_descriptors());
   new_descriptors->Set(insertion_index, descriptor, witness);
+  if (!replacing) {
+    new_descriptors->SetLastAdded(insertion_index);
+  } else {
+    new_descriptors->SetLastAdded(LastAdded());
+  }

   ASSERT(to_index == new_descriptors->number_of_descriptors());
   SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
@@ -5964,8 +5958,9 @@
           new_descriptors->CopyFrom(i, this, i, witness);
       if (copy_result->IsFailure()) return copy_result;
     }
-  }
-  new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
+    new_descriptors->SetLastAdded(LastAdded());
+  }
+
   return new_descriptors;
 }

@@ -5976,6 +5971,8 @@
 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
   // In-place heap sort.
   int len = number_of_descriptors();
+  // Nothing to sort.
+  if (len == 0) return;

   // Bottom-up max-heap construction.
   // Index of the last node with children
@@ -6023,6 +6020,19 @@
       parent_index = child_index;
     }
   }
+
+  int last_enum_index = -1;
+  int last_added = -1;
+  for (int i = 0; i < len; ++i) {
+    int current_enum = GetDetails(i).index();
+    if (current_enum > last_enum_index) {
+      last_added = i;
+      last_enum_index = current_enum;
+    }
+  }
+  SetLastAdded(last_added);
+
+  ASSERT(LastAdded() != -1);
 }


@@ -12720,7 +12730,7 @@
                                      JSFunction::cast(value),
                                      details.attributes(),
                                      details.index());
-        descriptors->Set(next_descriptor++, &d, witness);
+        descriptors->Set(next_descriptor, &d, witness);
       } else if (type == NORMAL) {
         if (current_offset < inobject_props) {
           obj->InObjectPropertyAtPut(current_offset,
@@ -12734,7 +12744,7 @@
                           current_offset++,
                           details.attributes(),
                           details.index());
-        descriptors->Set(next_descriptor++, &d, witness);
+        descriptors->Set(next_descriptor, &d, witness);
       } else if (type == CALLBACKS) {
         if (value->IsAccessorPair()) {
           MaybeObject* maybe_copy =
@@ -12745,10 +12755,11 @@
                               value,
                               details.attributes(),
                               details.index());
-        descriptors->Set(next_descriptor++, &d, witness);
+        descriptors->Set(next_descriptor, &d, witness);
       } else {
         UNREACHABLE();
       }
+      ++next_descriptor;
     }
   }
   ASSERT(current_offset == number_of_fields);
@@ -12768,7 +12779,6 @@
   obj->set_properties(FixedArray::cast(fields));
   ASSERT(obj->IsJSObject());

-  descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
   // Check that it really works.
   ASSERT(obj->HasFastProperties());

=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Jul 10 06:31:36 2012
+++ /branches/bleeding_edge/src/objects.h       Wed Jul 11 07:26:42 2012
@@ -2476,37 +2476,44 @@

   inline int number_of_entries() { return number_of_descriptors(); }

-  int NextEnumerationIndex() {
-    if (IsEmpty()) return PropertyDetails::kInitialIndex;
-    Object* obj = get(kEnumerationIndexIndex);
+  int LastAdded() {
+    ASSERT(!IsEmpty());
+    Object* obj = get(kLastAddedIndex);
     if (obj->IsSmi()) {
       return Smi::cast(obj)->value();
     } else {
- Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeEnumIndex); + Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeLastAdded);
       return Smi::cast(index)->value();
     }
   }

-  // Set next enumeration index and flush any enum cache.
-  void SetNextEnumerationIndex(int value) {
-    if (!IsEmpty()) {
-      set(kEnumerationIndexIndex, Smi::FromInt(value));
-    }
-  }
+  int NextEnumerationIndex() {
+    if (number_of_descriptors() == 0) {
+      return PropertyDetails::kInitialIndex;
+    }
+    return GetDetails(LastAdded()).index() + 1;
+  }
+
+  // Set index of the last added descriptor and flush any enum cache.
+  void SetLastAdded(int index) {
+    ASSERT(!IsEmpty() || index > 0);
+    set(kLastAddedIndex, Smi::FromInt(index));
+  }
+
   bool HasEnumCache() {
-    return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi();
+    return !IsEmpty() && !get(kLastAddedIndex)->IsSmi();
   }

   Object* GetEnumCache() {
     ASSERT(HasEnumCache());
-    FixedArray* bridge = FixedArray::cast(get(kEnumerationIndexIndex));
+    FixedArray* bridge = FixedArray::cast(get(kLastAddedIndex));
     return bridge->get(kEnumCacheBridgeCacheIndex);
   }

   Object** GetEnumCacheSlot() {
     ASSERT(HasEnumCache());
     return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
-                                kEnumerationIndexOffset);
+                                kLastAddedOffset);
   }

   Object** GetTransitionsSlot() {
@@ -2604,27 +2611,27 @@
   static const int kNotFound = -1;

   static const int kBackPointerStorageIndex = 0;
-  static const int kEnumerationIndexIndex = 1;
+  static const int kLastAddedIndex = 1;
   static const int kTransitionsIndex = 2;
   static const int kFirstIndex = 3;

   // The length of the "bridge" to the enum cache.
   static const int kEnumCacheBridgeLength = 3;
-  static const int kEnumCacheBridgeEnumIndex = 0;
+  static const int kEnumCacheBridgeLastAdded = 0;
   static const int kEnumCacheBridgeCacheIndex = 1;
   static const int kEnumCacheBridgeIndicesCacheIndex = 2;

   // Layout description.
   static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
-  static const int kEnumerationIndexOffset = kBackPointerStorageOffset +
-                                             kPointerSize;
- static const int kTransitionsOffset = kEnumerationIndexOffset + kPointerSize;
+  static const int kLastAddedOffset = kBackPointerStorageOffset +
+                                      kPointerSize;
+  static const int kTransitionsOffset = kLastAddedOffset + kPointerSize;
   static const int kFirstOffset = kTransitionsOffset + kPointerSize;

   // Layout description for the bridge array.
-  static const int kEnumCacheBridgeEnumOffset = FixedArray::kHeaderSize;
+ static const int kEnumCacheBridgeLastAddedOffset = FixedArray::kHeaderSize;
   static const int kEnumCacheBridgeCacheOffset =
-    kEnumCacheBridgeEnumOffset + kPointerSize;
+    kEnumCacheBridgeLastAddedOffset + kPointerSize;

   // Layout of descriptor.
   static const int kDescriptorKey = 0;
@@ -3090,6 +3097,7 @@

   // Accessors for next enumeration index.
   void SetNextEnumerationIndex(int index) {
+    ASSERT(index != 0);
     this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
   }

=======================================
--- /branches/bleeding_edge/src/property.h      Fri Jul  6 01:11:10 2012
+++ /branches/bleeding_edge/src/property.h      Wed Jul 11 07:26:42 2012
@@ -92,7 +92,7 @@
              Object* value,
              PropertyAttributes attributes,
              PropertyType type,
-             int index = 0)
+             int index)
       : key_(key),
         value_(value),
         details_(attributes, type, index) { }
@@ -106,7 +106,7 @@
   FieldDescriptor(String* key,
                   int field_index,
                   PropertyAttributes attributes,
-                  int index = 0)
+                  int index)
: Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
 };

@@ -116,7 +116,7 @@
   ConstantFunctionDescriptor(String* key,
                              JSFunction* function,
                              PropertyAttributes attributes,
-                             int index = 0)
+                             int index)
       : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
 };

@@ -126,7 +126,7 @@
   CallbacksDescriptor(String* key,
                       Object* foreign,
                       PropertyAttributes attributes,
-                      int index = 0)
+                      int index)
       : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
 };

=======================================
--- /branches/bleeding_edge/src/transitions-inl.h       Tue Jul 10 00:53:00 2012
+++ /branches/bleeding_edge/src/transitions-inl.h       Wed Jul 11 07:26:42 2012
@@ -177,8 +177,7 @@
 PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
   Map* map = GetTargetMap(transition_number);
   DescriptorArray* descriptors = map->instance_descriptors();
-  String* key = GetKey(transition_number);
-  int descriptor = descriptors->SearchWithCache(key);
+  int descriptor = descriptors->LastAdded();
   ASSERT(descriptor != DescriptorArray::kNotFound);
   return descriptors->GetDetails(descriptor);
 }
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue Jun 26 06:56:48 2012 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Jul 11 07:26:42 2012
@@ -1109,7 +1109,7 @@
   // We got a map in register rax. Get the enumeration cache from it.
   __ bind(&use_cache);
   __ LoadInstanceDescriptors(rax, rcx);
- __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
+  __ movq(rcx, FieldOperand(rcx, DescriptorArray::kLastAddedOffset));
__ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));

   // Set up the four remaining stack slots.
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Jul 5 06:54:20 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Jul 11 07:26:42 2012
@@ -5005,7 +5005,7 @@
   Register result = ToRegister(instr->result());
   __ LoadInstanceDescriptors(map, result);
   __ movq(result,
-          FieldOperand(result, DescriptorArray::kEnumerationIndexOffset));
+          FieldOperand(result, DescriptorArray::kLastAddedOffset));
   __ movq(result,
           FieldOperand(result, FixedArray::SizeFor(instr->idx())));
   Condition cc = masm()->CheckSmi(result);
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jul 10 06:31:36 2012 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Jul 11 07:26:42 2012
@@ -4473,7 +4473,7 @@
   // 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.
-  movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
+  movq(rdx, FieldOperand(rdx, DescriptorArray::kLastAddedOffset));
   JumpIfSmi(rdx, call_runtime);

   // For all objects but the receiver, check that the cache is empty.

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to