From: verwaest@chromium.org Date: Wed, 11 Jul 2012 14:26:42 +0000 (+0000) Subject: Ensure that all descriptors have a valid enumeration index, and replace NextEnumIndex... X-Git-Tag: upstream/4.7.83~16366 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b008d99b11f4dc9e2b30dfe7edbde289fd05bf2e;p=platform%2Fupstream%2Fv8.git 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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12042 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 72cd8328c..aadff7ada 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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. diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index fc5590bff..a7457bf5d 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -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)); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 7d5a241f4..84e866e3b 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -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. diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 4238a12d2..54eb9b8a8 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -390,25 +390,32 @@ Handle Genesis::ComputeFunctionInstanceDescriptor( DescriptorArray::WhitenessWitness witness(*descriptors); + int index = 0; + { // Add length. Handle 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 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 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 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 Genesis::ComputeFunctionInstanceDescriptor( attribs = static_cast(attribs & ~READ_ONLY); } Handle 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 Genesis::ComputeStrictFunctionInstanceDescriptor( DescriptorArray::WhitenessWitness witness(*descriptors); + int index = 0; { // Add length. Handle 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 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 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 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 Genesis::ComputeStrictFunctionInstanceDescriptor( attribs = static_cast(attribs | READ_ONLY); } Handle 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 inner_global, DescriptorArray::WhitenessWitness witness(*descriptors); PropertyAttributes final = static_cast(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 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 inner_global, // Create the descriptor array for the arguments object. Handle 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 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); diff --git a/src/factory.cc b/src/factory.cc index e7c612b92..a4dfa907d 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -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 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 entry = Handle(AccessorInfo::cast(callbacks.get(i))); @@ -943,19 +945,26 @@ Handle Factory::CopyAppendCallbackDescriptors( Handle key = SymbolFromString(Handle(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 new_result = NewDescriptorArray(descriptor_count); - for (int i = 0; i < descriptor_count; i++) { + if (added_descriptor_count < result->length()) { + Handle 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 Factory::CopyAppendCallbackDescriptors( // Sort the result before returning. result->Sort(witness); + ASSERT(result->NextEnumerationIndex() == next_enum); return result; } diff --git a/src/heap.cc b/src/heap.cc index 911dc4595..8e724ebb6 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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 diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 1a9aea241..2867d5ec7 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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. diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index b307512d6..dd58cd236 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -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); diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index f9cde1270..237bfd949 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -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. diff --git a/src/ic.cc b/src/ic.cc index bee29f0b8..d75b3e979 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -1518,8 +1518,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, Handle 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 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) { diff --git a/src/objects-inl.h b/src/objects-inl.h index 757ccb5af..fbb018381 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -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), diff --git a/src/objects.cc b/src/objects.cc index abaaa2f37..295830e10 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -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()); diff --git a/src/objects.h b/src/objects.h index e03c2b2d3..b7d9da3ff 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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(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 { // Accessors for next enumeration index. void SetNextEnumerationIndex(int index) { + ASSERT(index != 0); this->set(kNextEnumerationIndexIndex, Smi::FromInt(index)); } diff --git a/src/property.h b/src/property.h index 720028008..f783dc2e9 100644 --- a/src/property.h +++ b/src/property.h @@ -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) {} }; diff --git a/src/transitions-inl.h b/src/transitions-inl.h index 517fdc806..16496ddd2 100644 --- a/src/transitions-inl.h +++ b/src/transitions-inl.h @@ -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); } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 050c0d657..1259160c5 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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. diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 6bec93af5..33c175aeb 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -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); diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 4c46dfcbb..4b8ca8f99 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -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.