Ensure that all descriptors have a valid enumeration index, and replace NextEnumIndex...
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 Jul 2012 14:26:42 +0000 (14:26 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 Jul 2012 14:26:42 +0000 (14:26 +0000)
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

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

18 files changed:
src/arm/full-codegen-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/bootstrapper.cc
src/factory.cc
src/heap.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ic.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/property.h
src/transitions-inl.h
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/macro-assembler-x64.cc

index 72cd832..aadff7a 100644 (file)
@@ -1142,7 +1142,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   // 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.
index fc5590b..a7457bf 100644 (file)
@@ -5360,7 +5360,7 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
   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));
index 7d5a241..84e866e 100644 (file)
@@ -3723,7 +3723,7 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* 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.
-  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.
index 4238a12..54eb9b8 100644 (file)
@@ -390,25 +390,32 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
 
   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 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
       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 @@ Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
 
   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 @@ Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
       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 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     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 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
       FieldDescriptor field(heap->last_index_symbol(),
                             JSRegExp::kLastIndexFieldIndex,
                             writable,
-                            enum_index++);
-      descriptors->Set(4, &field, witness);
+                            index + 1);
+      descriptors->Set(index, &field, witness);
     }
-    descriptors->SetNextEnumerationIndex(enum_index);
     descriptors->Sort(witness);
 
     initial_map->set_inobject_properties(5);
@@ -1138,17 +1158,26 @@ 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);
+    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 @@ bool Genesis::InstallNatives() {
     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);
 
index e7c612b..a4dfa90 100644 (file)
@@ -892,7 +892,7 @@ MUST_USE_RESULT static inline MaybeObject* DoCopyInsert(
     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 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
   // 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<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
     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 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
 
   // Sort the result before returning.
   result->Sort(witness);
+  ASSERT(result->NextEnumerationIndex() == next_enum);
   return result;
 }
 
index 911dc45..8e724eb 100644 (file)
@@ -3883,11 +3883,9 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
       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
index 1a9aea2..2867d5e 100644 (file)
@@ -1092,7 +1092,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   // 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.
index b307512..dd58cd2 100644 (file)
@@ -5293,7 +5293,7 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
   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);
index f9cde12..237bfd9 100644 (file)
@@ -2901,7 +2901,7 @@ void MacroAssembler::CheckEnumCache(Label* 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.
-  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.
index bee29f0..d75b3e9 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1518,8 +1518,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
 
       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 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
 
       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) {
index 757ccb5..fbb0183 100644 (file)
@@ -2095,6 +2095,7 @@ void DescriptorArray::Set(int descriptor_number,
                           const WhitenessWitness&) {
   // Range check.
   ASSERT(descriptor_number < number_of_descriptors());
+  ASSERT(desc->GetDetails().index() > 0);
 
   NoIncrementalWriteBarrierSet(this,
                                ToKeyIndex(descriptor_number),
index abaaa2f..295830e 100644 (file)
@@ -1546,7 +1546,7 @@ MaybeObject* JSObject::AddFastProperty(String* name,
   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 @@ MaybeObject* JSObject::AddFastProperty(String* name,
     }
   }
 
-  // Only allow map transition if the object isn't the global object and there
-  // is not a transition for the name, or there's a transition for the name but
-  // it's unrelated to properties.
-  int descriptor_index = old_descriptors->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 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
     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 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name,
   }
 
   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 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
 
       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 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
 
       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 @@ static MaybeObject* CreateFreshAccessor(JSObject* obj,
 
   // 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 @@ static bool TransitionToSameAccessor(Object* map,
                                      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 @@ static MaybeObject* NewCallbackTransition(JSObject* obj,
 
   // 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 @@ MaybeObject* DescriptorArray::Allocate(int number_of_descriptors,
     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 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
   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 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
     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 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
 
   // 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;
+    descriptor->SetEnumerationIndex(NextEnumerationIndex());
   }
-  new_descriptors->SetNextEnumerationIndex(enumeration_index);
 
   // Copy the descriptors, inserting or replacing a descriptor.
   int to_index = 0;
@@ -5939,6 +5928,11 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
 
   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 @@ MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
           new_descriptors->CopyFrom(i, this, i, witness);
       if (copy_result->IsFailure()) return copy_result;
     }
+    new_descriptors->SetLastAdded(LastAdded());
   }
-  new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
+
   return new_descriptors;
 }
 
@@ -5976,6 +5971,8 @@ MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
 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 @@ void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
       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 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
                                      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 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
                           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 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
                               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 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
   obj->set_properties(FixedArray::cast(fields));
   ASSERT(obj->IsJSObject());
 
-  descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
   // Check that it really works.
   ASSERT(obj->HasFastProperties());
 
index e03c2b2..b7d9da3 100644 (file)
@@ -2476,37 +2476,44 @@ class DescriptorArray: public FixedArray {
 
   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 @@ class DescriptorArray: public FixedArray {
   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 @@ class Dictionary: public HashTable<Shape, Key> {
 
   // Accessors for next enumeration index.
   void SetNextEnumerationIndex(int index) {
+    ASSERT(index != 0);
     this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
   }
 
index 7200280..f783dc2 100644 (file)
@@ -92,7 +92,7 @@ class Descriptor BASE_EMBEDDED {
              Object* value,
              PropertyAttributes attributes,
              PropertyType type,
-             int index = 0)
+             int index)
       : key_(key),
         value_(value),
         details_(attributes, type, index) { }
@@ -106,7 +106,7 @@ class FieldDescriptor: public Descriptor {
   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 @@ class ConstantFunctionDescriptor: public Descriptor {
   ConstantFunctionDescriptor(String* key,
                              JSFunction* function,
                              PropertyAttributes attributes,
-                             int index = 0)
+                             int index)
       : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
 };
 
@@ -126,7 +126,7 @@ class CallbacksDescriptor:  public Descriptor {
   CallbacksDescriptor(String* key,
                       Object* foreign,
                       PropertyAttributes attributes,
-                      int index = 0)
+                      int index)
       : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
 };
 
index 517fdc8..16496dd 100644 (file)
@@ -177,8 +177,7 @@ Map* TransitionArray::GetTargetMap(int transition_number) {
 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);
 }
index 050c0d6..1259160 100644 (file)
@@ -1109,7 +1109,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   // 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.
index 6bec93a..33c175a 100644 (file)
@@ -5005,7 +5005,7 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
   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);
index 4c46dfc..4b8ca8f 100644 (file)
@@ -4473,7 +4473,7 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* 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.
-  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.