Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index c37a4a8b2086be48e881634f36f36acf034cc56c..57882a4d20a0f8f3a64c9919c39d94c86f64df30 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -487,20 +487,11 @@ MaybeObject* JSObject::SetNormalizedProperty(String* name, |
set_properties(StringDictionary::cast(dict)); |
return value; |
} |
- |
- PropertyDetails original_details = property_dictionary()->DetailsAt(entry); |
- int enumeration_index; |
- // Preserve the enumeration index unless the property was deleted. |
- if (original_details.IsDeleted()) { |
- enumeration_index = property_dictionary()->NextEnumerationIndex(); |
- property_dictionary()->SetNextEnumerationIndex(enumeration_index + 1); |
- } else { |
- enumeration_index = original_details.dictionary_index(); |
- ASSERT(enumeration_index > 0); |
- } |
- |
+ // Preserve enumeration index. |
details = PropertyDetails( |
- details.attributes(), details.type(), enumeration_index); |
+ details.attributes(), |
+ details.type(), |
+ property_dictionary()->DetailsAt(entry).dictionary_index()); |
if (IsGlobalObject()) { |
JSGlobalPropertyCell* cell = |
@@ -651,9 +642,11 @@ MaybeObject* Object::GetProperty(Object* receiver, |
receiver, result->GetCallbackObject(), name); |
case HANDLER: |
return result->proxy()->GetPropertyWithHandler(receiver, name); |
- case INTERCEPTOR: |
+ case INTERCEPTOR: { |
+ JSObject* recvr = JSObject::cast(receiver); |
return result->holder()->GetPropertyWithInterceptor( |
- receiver, name, attributes); |
+ recvr, name, attributes); |
+ } |
case TRANSITION: |
case NONEXISTENT: |
UNREACHABLE(); |
@@ -1539,9 +1532,8 @@ MaybeObject* JSObject::AddFastProperty(String* name, |
PropertyAttributes attributes, |
StoreFromKeyed store_mode) { |
ASSERT(!IsJSGlobalProxy()); |
- ASSERT(DescriptorArray::kNotFound == |
- map()->instance_descriptors()->Search( |
- name, map()->NumberOfOwnDescriptors())); |
+ ASSERT(map()->instance_descriptors()->Search(name) == |
+ DescriptorArray::kNotFound); |
// Normalize the object if the name is an actual string (not the |
// hidden symbols) and is not a real identifier. |
@@ -1690,7 +1682,7 @@ MaybeObject* JSObject::AddProperty(String* name, |
} |
if (HasFastProperties()) { |
// Ensure the descriptor array does not get too big. |
- if (map_of_this->NumberOfOwnDescriptors() < |
+ if (map_of_this->instance_descriptors()->number_of_descriptors() < |
DescriptorArray::kMaxNumberOfDescriptors) { |
if (value->IsJSFunction()) { |
return AddConstantFunctionProperty(name, |
@@ -1761,36 +1753,8 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition( |
Object* new_value, |
PropertyAttributes attributes) { |
Map* old_map = map(); |
- Map* old_target = old_map->GetTransition(transition_index); |
Object* result; |
- // To sever a transition to a map with which the descriptors are shared, the |
- // larger map (more descriptors) needs to store its own descriptors array. |
- // Both sides of the severed chain need to have their own descriptors pointer |
- // to store distinct descriptor arrays. |
- |
- // If the old_target did not yet store its own descriptors, the new |
- // descriptors pointer is created for the old_target by temporarily clearing |
- // the back pointer and setting its descriptor array. The ownership of the |
- // descriptor array is returned to the smaller maps by installing a reduced |
- // copy of the descriptor array in the old_map. |
- |
- // This phase is executed before creating the new map since it requires |
- // allocation that may fail. |
- if (!old_target->StoresOwnDescriptors()) { |
- DescriptorArray* old_descriptors = old_map->instance_descriptors(); |
- |
- old_target->SetBackPointer(GetHeap()->undefined_value()); |
- MaybeObject* maybe_failure = old_target->SetDescriptors(old_descriptors); |
- // Reset the backpointer before returning failure, otherwise the map ends up |
- // with an undefined backpointer and no descriptors, losing its own |
- // descriptors. Setting the backpointer always succeeds. |
- old_target->SetBackPointer(old_map); |
- if (maybe_failure->IsFailure()) return maybe_failure; |
- |
- old_map->set_owns_descriptors(true); |
- } |
- |
MaybeObject* maybe_result = |
ConvertDescriptorToField(name, new_value, attributes); |
if (!maybe_result->To(&result)) return maybe_result; |
@@ -1799,60 +1763,13 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition( |
// This method should only be used to convert existing transitions. Objects |
// with the map of "new Object()" cannot have transitions in the first place. |
- Map* new_map = map(); |
- ASSERT(new_map != GetIsolate()->empty_object_map()); |
+ ASSERT(map() != GetIsolate()->empty_object_map()); |
// TODO(verwaest): From here on we lose existing map transitions, causing |
// invalid back pointers. This will change once we can store multiple |
// transitions with the same key. |
- |
- if (old_map->owns_descriptors()) { |
- // If the old map owns its own descriptors, transfer ownership to the |
- // new_map and install its descriptors in the old_map. Since the old_map |
- // stores the descriptors for the new_map, remove the transition array of |
- // the new_map that is only in place to store the descriptors. |
- old_map->transitions()->descriptors_pointer()->set_value( |
- new_map->instance_descriptors()); |
- new_map->ClearTransitions(GetHeap()); |
- old_map->set_owns_descriptors(false); |
- Map* map; |
- JSGlobalPropertyCell* pointer = |
- old_map->transitions()->descriptors_pointer(); |
- for (Object* current = old_map; |
- !current->IsUndefined(); |
- current = map->GetBackPointer()) { |
- map = Map::cast(current); |
- if (!map->HasTransitionArray()) break; |
- TransitionArray* transitions = map->transitions(); |
- if (transitions->descriptors_pointer() != pointer) break; |
- map->SetEnumLength(Map::kInvalidEnumCache); |
- } |
- } else if (old_target->instance_descriptors() == |
- old_map->instance_descriptors()) { |
- // Since the conversion above generated a new fast map with an additional |
- // property which can be shared as well, install this descriptor pointer |
- // along the entire chain of smaller maps; and remove the transition array |
- // that is only in place to hold the descriptor array in the new map. |
- Map* map; |
- JSGlobalPropertyCell* new_pointer = |
- new_map->transitions()->descriptors_pointer(); |
- JSGlobalPropertyCell* old_pointer = |
- old_map->transitions()->descriptors_pointer(); |
- for (Object* current = old_map; |
- !current->IsUndefined(); |
- current = map->GetBackPointer()) { |
- map = Map::cast(current); |
- if (!map->HasTransitionArray()) break; |
- TransitionArray* transitions = map->transitions(); |
- if (transitions->descriptors_pointer() != old_pointer) break; |
- map->SetEnumLength(Map::kInvalidEnumCache); |
- transitions->set_descriptors_pointer(new_pointer); |
- } |
- new_map->ClearTransitions(GetHeap()); |
- } |
- |
- old_map->SetTransition(transition_index, new_map); |
- new_map->SetBackPointer(old_map); |
+ old_map->SetTransition(transition_index, map()); |
+ map()->SetBackPointer(old_map); |
return result; |
} |
@@ -2176,13 +2093,11 @@ enum RightTrimMode { FROM_GC, FROM_MUTATOR }; |
static void ZapEndOfFixedArray(Address new_end, int to_trim) { |
// If we are doing a big trim in old space then we zap the space. |
Object** zap = reinterpret_cast<Object**>(new_end); |
- zap++; // Header of filler must be at least one word so skip that. |
for (int i = 1; i < to_trim; i++) { |
*zap++ = Smi::FromInt(0); |
} |
} |
- |
template<RightTrimMode trim_mode> |
static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { |
ASSERT(elms->map() != HEAP->fixed_cow_array_map()); |
@@ -2223,31 +2138,13 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { |
} |
-void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
- Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
- if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
- int number_of_descriptors = descriptors->number_of_descriptors(); |
- Isolate* isolate = map->GetIsolate(); |
- Handle<DescriptorArray> new_descriptors = |
- isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); |
- DescriptorArray::WhitenessWitness witness(*new_descriptors); |
- |
- for (int i = 0; i < number_of_descriptors; ++i) { |
- new_descriptors->CopyFrom(i, *descriptors, i, witness); |
- } |
- |
- Map::SetDescriptors(map, new_descriptors); |
-} |
- |
- |
-void Map::AppendCallbackDescriptors(Handle<Map> map, |
- Handle<Object> descriptors) { |
+void Map::CopyAppendCallbackDescriptors(Handle<Map> map, |
+ Handle<Object> descriptors) { |
Isolate* isolate = map->GetIsolate(); |
Handle<DescriptorArray> array(map->instance_descriptors()); |
- NeanderArray callbacks(descriptors); |
+ v8::NeanderArray callbacks(descriptors); |
int nof_callbacks = callbacks.length(); |
- |
- ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); |
+ int descriptor_count = array->number_of_descriptors(); |
// Ensure the keys are symbols before writing them into the instance |
// descriptor. Since it may cause a GC, it has to be done before we |
@@ -2260,7 +2157,23 @@ void Map::AppendCallbackDescriptors(Handle<Map> map, |
entry->set_name(*key); |
} |
- int nof = map->NumberOfOwnDescriptors(); |
+ Handle<DescriptorArray> result = |
+ isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); |
+ |
+ // Ensure that marking will not progress and change color of objects. |
+ DescriptorArray::WhitenessWitness witness(*result); |
+ |
+ // Copy the descriptors from the array. |
+ if (0 < descriptor_count) { |
+ for (int i = 0; i < descriptor_count; i++) { |
+ result->CopyFrom(i, *array, i, witness); |
+ } |
+ } |
+ |
+ // After this point the GC is not allowed to run anymore until the map is in a |
+ // consistent state again, i.e., all the descriptors are appended and the |
+ // descriptor array is trimmed to the right size. |
+ Map::SetDescriptors(map, result); |
// Fill in new callback descriptors. Process the callbacks from |
// back to front so that the last callback with a given name takes |
@@ -2269,14 +2182,26 @@ void Map::AppendCallbackDescriptors(Handle<Map> map, |
AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); |
String* key = String::cast(entry->name()); |
// Check if a descriptor with this name already exists before writing. |
- if (array->Search(key, nof) == DescriptorArray::kNotFound) { |
+ if (LinearSearch(*result, key, map->NumberOfOwnDescriptors()) == |
+ DescriptorArray::kNotFound) { |
CallbacksDescriptor desc(key, entry, entry->property_attributes()); |
- array->Append(&desc); |
- nof += 1; |
+ map->AppendDescriptor(&desc, witness); |
} |
} |
- map->SetNumberOfOwnDescriptors(nof); |
+ int new_number_of_descriptors = map->NumberOfOwnDescriptors(); |
+ // Reinstall the original descriptor array if no new elements were added. |
+ if (new_number_of_descriptors == descriptor_count) { |
+ Map::SetDescriptors(map, array); |
+ return; |
+ } |
+ |
+ // If duplicates were detected, trim the descriptor array to the right size. |
+ int new_array_size = DescriptorArray::LengthFor(new_number_of_descriptors); |
+ if (new_array_size < result->length()) { |
+ RightTrimFixedArray<FROM_MUTATOR>( |
+ isolate->heap(), *result, result->length() - new_array_size); |
+ } |
} |
@@ -3339,19 +3264,19 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
Map* map_of_this = map(); |
// Allocate new content. |
- int real_size = map_of_this->NumberOfOwnDescriptors(); |
- int property_count = real_size; |
+ int property_count = map_of_this->NumberOfDescribedProperties(); |
if (expected_additional_properties > 0) { |
property_count += expected_additional_properties; |
} else { |
property_count += 2; // Make space for two more properties. |
} |
StringDictionary* dictionary; |
- MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); |
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
+ { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); |
+ if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
+ } |
DescriptorArray* descs = map_of_this->instance_descriptors(); |
- for (int i = 0; i < real_size; i++) { |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
PropertyDetails details = descs->GetDetails(i); |
switch (details.type()) { |
case CONSTANT_FUNCTION: { |
@@ -3396,7 +3321,8 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
Heap* current_heap = GetHeap(); |
// Copy the next enumeration index from instance descriptor. |
- dictionary->SetNextEnumerationIndex(real_size + 1); |
+ int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); |
+ dictionary->SetNextEnumerationIndex(index); |
Map* new_map; |
MaybeObject* maybe_map = |
@@ -3742,11 +3668,10 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable( |
DescriptorArray* descriptors = this->map()->instance_descriptors(); |
if (descriptors->number_of_descriptors() > 0) { |
int sorted_index = descriptors->GetSortedKeyIndex(0); |
- if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && |
- sorted_index < map()->NumberOfOwnDescriptors()) { |
+ if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { |
ASSERT(descriptors->GetType(sorted_index) == FIELD); |
- inline_value = |
- this->FastPropertyAt(descriptors->GetFieldIndex(sorted_index)); |
+ inline_value = this->FastPropertyAt( |
+ descriptors->GetFieldIndex(sorted_index)); |
} else { |
inline_value = GetHeap()->undefined_value(); |
} |
@@ -3811,8 +3736,7 @@ MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) { |
DescriptorArray* descriptors = this->map()->instance_descriptors(); |
if (descriptors->number_of_descriptors() > 0) { |
int sorted_index = descriptors->GetSortedKeyIndex(0); |
- if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && |
- sorted_index < map()->NumberOfOwnDescriptors()) { |
+ if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { |
ASSERT(descriptors->GetType(sorted_index) == FIELD); |
this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), |
value); |
@@ -4254,15 +4178,14 @@ void Map::SetDescriptors(Handle<Map> map, |
} |
-int Map::NumberOfDescribedProperties(DescriptorFlag which, |
- PropertyAttributes filter) { |
+int Map::NumberOfDescribedProperties(PropertyAttributes filter) { |
int result = 0; |
DescriptorArray* descs = instance_descriptors(); |
- int limit = which == ALL_DESCRIPTORS |
- ? descs->number_of_descriptors() |
- : NumberOfOwnDescriptors(); |
- for (int i = 0; i < limit; i++) { |
- if ((descs->GetDetails(i).attributes() & filter) == 0) result++; |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
+ PropertyDetails details = descs->GetDetails(i); |
+ if ((details.attributes() & filter) == 0) { |
+ result++; |
+ } |
} |
return result; |
} |
@@ -4270,8 +4193,7 @@ int Map::NumberOfDescribedProperties(DescriptorFlag which, |
int Map::PropertyIndexFor(String* name) { |
DescriptorArray* descs = instance_descriptors(); |
- int limit = NumberOfOwnDescriptors(); |
- for (int i = 0; i < limit; i++) { |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); |
} |
return -1; |
@@ -4280,9 +4202,8 @@ int Map::PropertyIndexFor(String* name) { |
int Map::NextFreePropertyIndex() { |
int max_index = -1; |
- int number_of_own_descriptors = NumberOfOwnDescriptors(); |
DescriptorArray* descs = instance_descriptors(); |
- for (int i = 0; i < number_of_own_descriptors; i++) { |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
if (descs->GetType(i) == FIELD) { |
int current_index = descs->GetFieldIndex(i); |
if (current_index > max_index) max_index = current_index; |
@@ -4294,9 +4215,8 @@ int Map::NextFreePropertyIndex() { |
AccessorDescriptor* Map::FindAccessor(String* name) { |
DescriptorArray* descs = instance_descriptors(); |
- int number_of_own_descriptors = NumberOfOwnDescriptors(); |
- for (int i = 0; i < number_of_own_descriptors; i++) { |
- if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
+ if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { |
return descs->GetCallbacks(i); |
} |
} |
@@ -4720,10 +4640,9 @@ MaybeObject* JSObject::DefineFastAccessor(String* name, |
if (result.IsFound()) { |
Map* target = result.GetTransitionTarget(); |
- ASSERT(target->NumberOfOwnDescriptors() == |
- map()->NumberOfOwnDescriptors()); |
- // This works since descriptors are sorted in order of addition. |
- ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name); |
+ ASSERT(target->instance_descriptors()->number_of_descriptors() == |
+ map()->instance_descriptors()->number_of_descriptors()); |
+ ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name); |
return TryAccessorTransition( |
this, target, descriptor_number, component, accessor, attributes); |
} |
@@ -4906,9 +4825,8 @@ Object* JSObject::LookupAccessor(String* name, AccessorComponent component) { |
Object* JSObject::SlowReverseLookup(Object* value) { |
if (HasFastProperties()) { |
- int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); |
DescriptorArray* descs = map()->instance_descriptors(); |
- for (int i = 0; i < number_of_own_descriptors; i++) { |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
if (descs->GetType(i) == FIELD) { |
if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { |
return descs->GetKey(i); |
@@ -4937,11 +4855,8 @@ MaybeObject* Map::RawCopy(int instance_size) { |
result->set_bit_field(bit_field()); |
result->set_bit_field2(bit_field2()); |
result->set_bit_field3(bit_field3()); |
- int new_bit_field3 = bit_field3(); |
- new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); |
- new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); |
- new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); |
- result->set_bit_field3(new_bit_field3); |
+ result->SetNumberOfOwnDescriptors(0); |
+ result->SetEnumLength(kInvalidEnumCache); |
return result; |
} |
@@ -4991,82 +4906,14 @@ MaybeObject* Map::CopyDropDescriptors() { |
} |
-MaybeObject* Map::ShareDescriptor(Descriptor* descriptor) { |
- // Sanity check. This path is only to be taken if the map owns its descriptor |
- // array, implying that its NumberOfOwnDescriptors equals the number of |
- // descriptors in the descriptor array. |
- ASSERT(NumberOfOwnDescriptors() == |
- instance_descriptors()->number_of_descriptors()); |
- Map* result; |
- MaybeObject* maybe_result = CopyDropDescriptors(); |
- if (!maybe_result->To(&result)) return maybe_result; |
- |
- String* name = descriptor->GetKey(); |
- |
- TransitionArray* transitions; |
- MaybeObject* maybe_transitions = |
- AddTransition(name, result, SIMPLE_TRANSITION); |
- if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
- |
- DescriptorArray* descriptors = instance_descriptors(); |
- int old_size = descriptors->number_of_descriptors(); |
- |
- DescriptorArray* new_descriptors; |
- |
- if (descriptors->NumberOfSlackDescriptors() > 0) { |
- new_descriptors = descriptors; |
- new_descriptors->Append(descriptor); |
- } else { |
- // Descriptor arrays grow by 50%. |
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate( |
- old_size, old_size < 4 ? 1 : old_size / 2); |
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- |
- DescriptorArray::WhitenessWitness witness(new_descriptors); |
- |
- // Copy the descriptors, inserting a descriptor. |
- for (int i = 0; i < old_size; ++i) { |
- new_descriptors->CopyFrom(i, descriptors, i, witness); |
- } |
- |
- new_descriptors->Append(descriptor, witness); |
- |
- // If the source descriptors had an enum cache we copy it. This ensures that |
- // the maps to which we push the new descriptor array back can rely on a |
- // cache always being available once it is set. If the map has more |
- // enumerated descriptors than available in the original cache, the cache |
- // will be lazily replaced by the extended cache when needed. |
- if (descriptors->HasEnumCache()) { |
- new_descriptors->CopyEnumCacheFrom(descriptors); |
- } |
- } |
- |
- transitions->set_descriptors(new_descriptors); |
- |
- set_transitions(transitions); |
- result->SetBackPointer(this); |
- set_owns_descriptors(false); |
- |
- result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors()); |
- ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); |
- |
- return result; |
-} |
- |
- |
MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
String* name, |
- TransitionFlag flag, |
- int descriptor_index) { |
- ASSERT(descriptors->IsSortedNoDuplicates()); |
- |
+ TransitionFlag flag) { |
Map* result; |
MaybeObject* maybe_result = CopyDropDescriptors(); |
if (!maybe_result->To(&result)) return maybe_result; |
- // Unless we are creating a map with no descriptors and no back pointer, we |
- // insert the descriptor array locally. |
- if (!descriptors->IsEmpty()) { |
+ if (descriptors->number_of_descriptors() != 0) { |
MaybeObject* maybe_failure = result->SetDescriptors(descriptors); |
if (maybe_failure->IsFailure()) return maybe_failure; |
result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); |
@@ -5074,30 +4921,9 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { |
TransitionArray* transitions; |
- SimpleTransitionFlag simple_flag = |
- (descriptor_index == descriptors->number_of_descriptors() - 1) |
- ? SIMPLE_TRANSITION |
- : FULL_TRANSITION; |
- MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); |
+ MaybeObject* maybe_transitions = AddTransition(name, result); |
if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
- if (descriptors->IsEmpty()) { |
- if (owns_descriptors()) { |
- // If the copied map has no added fields, and the parent map owns its |
- // descriptors, those descriptors have to be empty. In that case, |
- // transfer ownership of the descriptors to the new child. |
- ASSERT(instance_descriptors()->IsEmpty()); |
- set_owns_descriptors(false); |
- } else { |
- // If the parent did not own its own descriptors, it may share a larger |
- // descriptors array already. In that case, force a split by setting |
- // the descriptor array of the new map to the empty descriptor array. |
- MaybeObject* maybe_failure = |
- result->SetDescriptors(GetHeap()->empty_descriptor_array()); |
- if (maybe_failure->IsFailure()) return maybe_failure; |
- } |
- } |
- |
set_transitions(transitions); |
result->SetBackPointer(this); |
} |
@@ -5107,6 +4933,12 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { |
+ // Create a new free-floating map only if we are not allowed to store it. |
+ Map* new_map = NULL; |
+ MaybeObject* maybe_new_map = Copy(); |
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
+ new_map->set_elements_kind(kind); |
+ |
if (flag == INSERT_TRANSITION) { |
ASSERT(!HasElementsTransition() || |
((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || |
@@ -5117,49 +4949,10 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { |
ASSERT(!IsFastElementsKind(kind) || |
IsMoreGeneralElementsKindTransition(elements_kind(), kind)); |
ASSERT(kind != elements_kind()); |
- } |
- |
- if (flag == INSERT_TRANSITION && owns_descriptors()) { |
- // In case the map owned its own descriptors, share the descriptors and |
- // transfer ownership to the new map. |
- Map* new_map; |
- MaybeObject* maybe_new_map = CopyDropDescriptors(); |
- if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
MaybeObject* added_elements = set_elements_transition_map(new_map); |
if (added_elements->IsFailure()) return added_elements; |
- new_map->set_elements_kind(kind); |
- new_map->SetBackPointer(this); |
- new_map->SetNumberOfOwnDescriptors(NumberOfOwnDescriptors()); |
- set_owns_descriptors(false); |
- return new_map; |
- } |
- |
- // In case the map did not own its own descriptors, a split is forced by |
- // copying the map; creating a new descriptor array cell. |
- // Create a new free-floating map only if we are not allowed to store it. |
- Map* new_map; |
- MaybeObject* maybe_new_map = Copy(); |
- if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
- ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors()); |
- new_map->set_elements_kind(kind); |
- |
- if (flag == INSERT_TRANSITION) { |
- // Map::Copy does not store the descriptor array in case it is empty, since |
- // it does not insert a back pointer; implicitly indicating that its |
- // descriptor array is empty. Since in this case we do want to insert a back |
- // pointer, we have to manually set the empty descriptor array to force a |
- // split. |
- if (!new_map->StoresOwnDescriptors()) { |
- ASSERT(new_map->NumberOfOwnDescriptors() == 0); |
- MaybeObject* maybe_failure = |
- new_map->SetDescriptors(GetHeap()->empty_descriptor_array()); |
- if (maybe_failure->IsFailure()) return maybe_failure; |
- } |
- MaybeObject* added_elements = set_elements_transition_map(new_map); |
- if (added_elements->IsFailure()) return added_elements; |
- |
new_map->SetBackPointer(this); |
} |
@@ -5177,25 +4970,13 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { |
Map* map = ctor->initial_map(); |
DescriptorArray* descriptors = map->instance_descriptors(); |
- int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
- DescriptorArray* new_descriptors; |
- MaybeObject* maybe_descriptors = |
- descriptors->CopyUpTo(number_of_own_descriptors); |
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- |
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); |
+ return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); |
} |
MaybeObject* Map::Copy() { |
DescriptorArray* descriptors = instance_descriptors(); |
- DescriptorArray* new_descriptors; |
- int number_of_own_descriptors = NumberOfOwnDescriptors(); |
- MaybeObject* maybe_descriptors = |
- descriptors->CopyUpTo(number_of_own_descriptors); |
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- |
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); |
+ return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); |
} |
@@ -5207,39 +4988,28 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, |
MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
if (maybe_failure->IsFailure()) return maybe_failure; |
- int old_size = NumberOfOwnDescriptors(); |
- int new_size = old_size + 1; |
- descriptor->SetEnumerationIndex(new_size); |
+ String* key = descriptor->GetKey(); |
+ ASSERT(descriptors->Search(key) == DescriptorArray::kNotFound); |
- if (flag == INSERT_TRANSITION && |
- owns_descriptors() && |
- CanHaveMoreTransitions()) { |
- return ShareDescriptor(descriptor); |
- } |
+ int old_size = descriptors->number_of_descriptors(); |
+ int new_size = old_size + 1; |
DescriptorArray* new_descriptors; |
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); |
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); |
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- DescriptorArray::WhitenessWitness witness(new_descriptors); |
+ FixedArray::WhitenessWitness witness(new_descriptors); |
// Copy the descriptors, inserting a descriptor. |
for (int i = 0; i < old_size; ++i) { |
new_descriptors->CopyFrom(i, descriptors, i, witness); |
} |
- if (old_size != descriptors->number_of_descriptors()) { |
- new_descriptors->SetNumberOfDescriptors(new_size); |
- new_descriptors->Set(old_size, descriptor, witness); |
- new_descriptors->Sort(); |
- } else { |
- new_descriptors->Append(descriptor, witness); |
- } |
+ new_descriptors->Append(descriptor, witness, old_size); |
- String* key = descriptor->GetKey(); |
- int insertion_index = new_descriptors->number_of_descriptors() - 1; |
+ SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
- return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); |
+ return CopyReplaceDescriptors(new_descriptors, key, flag); |
} |
@@ -5252,7 +5022,7 @@ MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, |
if (maybe_result->IsFailure()) return maybe_result; |
// We replace the key if it is already present. |
- int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this); |
+ int index = old_descriptors->SearchWithCache(descriptor->GetKey()); |
if (index != DescriptorArray::kNotFound) { |
return CopyReplaceDescriptor(descriptor, index, flag); |
} |
@@ -5260,62 +5030,41 @@ MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, |
} |
-MaybeObject* DescriptorArray::CopyUpTo(int enumeration_index) { |
- if (enumeration_index == 0) return GetHeap()->empty_descriptor_array(); |
- |
- int size = enumeration_index; |
- |
- DescriptorArray* descriptors; |
- MaybeObject* maybe_descriptors = Allocate(size); |
- if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; |
- DescriptorArray::WhitenessWitness witness(descriptors); |
- |
- for (int i = 0; i < size; ++i) { |
- descriptors->CopyFrom(i, this, i, witness); |
- } |
- |
- if (number_of_descriptors() != enumeration_index) descriptors->Sort(); |
- |
- return descriptors; |
-} |
- |
- |
MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, |
int insertion_index, |
TransitionFlag flag) { |
+ DescriptorArray* descriptors = instance_descriptors(); |
+ int size = descriptors->number_of_descriptors(); |
+ ASSERT(0 <= insertion_index && insertion_index < size); |
+ |
// Ensure the key is a symbol. |
MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
if (maybe_failure->IsFailure()) return maybe_failure; |
- DescriptorArray* descriptors = instance_descriptors(); |
- |
String* key = descriptor->GetKey(); |
ASSERT(key == descriptors->GetKey(insertion_index)); |
- int new_size = NumberOfOwnDescriptors(); |
- ASSERT(0 <= insertion_index && insertion_index < new_size); |
- |
- PropertyDetails details = descriptors->GetDetails(insertion_index); |
- ASSERT_LE(details.descriptor_index(), new_size); |
- descriptor->SetEnumerationIndex(details.descriptor_index()); |
- |
DescriptorArray* new_descriptors; |
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); |
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(size); |
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- DescriptorArray::WhitenessWitness witness(new_descriptors); |
- for (int i = 0; i < new_size; ++i) { |
- if (i == insertion_index) { |
- new_descriptors->Set(i, descriptor, witness); |
- } else { |
- new_descriptors->CopyFrom(i, descriptors, i, witness); |
- } |
+ FixedArray::WhitenessWitness witness(new_descriptors); |
+ |
+ // Copy the descriptors, replacing a descriptor. |
+ for (int index = 0; index < size; ++index) { |
+ if (index == insertion_index) continue; |
+ new_descriptors->CopyFrom(index, descriptors, index, witness); |
} |
- // Re-sort if descriptors were removed. |
- if (new_size != descriptors->length()) new_descriptors->Sort(); |
+ PropertyDetails original_details = descriptors->GetDetails(insertion_index); |
+ descriptor->SetEnumerationIndex(original_details.descriptor_index()); |
+ descriptor->SetSortedKey(original_details.pointer()); |
+ |
+ new_descriptors->Set(insertion_index, descriptor, witness); |
+ |
+ SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
- return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); |
+ return CopyReplaceDescriptors(new_descriptors, key, flag); |
} |
@@ -6090,40 +5839,33 @@ bool FixedArray::IsEqualTo(FixedArray* other) { |
#endif |
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { |
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { |
Heap* heap = Isolate::Current()->heap(); |
// Do not use DescriptorArray::cast on incomplete object. |
- int size = number_of_descriptors + slack; |
- if (size == 0) return heap->empty_descriptor_array(); |
FixedArray* result; |
+ if (number_of_descriptors == 0) return heap->empty_descriptor_array(); |
// Allocate the array of keys. |
- MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size)); |
+ MaybeObject* maybe_array = |
+ heap->AllocateFixedArray(LengthFor(number_of_descriptors)); |
if (!maybe_array->To(&result)) return maybe_array; |
- result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); |
result->set(kEnumCacheIndex, Smi::FromInt(0)); |
return result; |
} |
-void DescriptorArray::ClearEnumCache() { |
- set(kEnumCacheIndex, Smi::FromInt(0)); |
-} |
- |
- |
void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
FixedArray* new_cache, |
Object* new_index_cache) { |
ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
if (HasEnumCache()) { |
- ASSERT(new_cache->length() > GetEnumCache()->length()); |
FixedArray::cast(get(kEnumCacheIndex))-> |
set(kEnumCacheBridgeCacheIndex, new_cache); |
FixedArray::cast(get(kEnumCacheIndex))-> |
set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
} else { |
- ASSERT(!IsEmpty()); |
+ if (IsEmpty()) return; // Do nothing for empty descriptor array. |
FixedArray::cast(bridge_storage)-> |
set(kEnumCacheBridgeCacheIndex, new_cache); |
FixedArray::cast(bridge_storage)-> |
@@ -6199,7 +5941,6 @@ void DescriptorArray::Sort() { |
parent_index = child_index; |
} |
} |
- ASSERT(IsSortedNoDuplicates()); |
} |
@@ -7390,6 +7131,7 @@ void StringHasher::AddSurrogatePairNoIndex(uc32 c) { |
uint32_t StringHasher::GetHashField() { |
+ ASSERT(is_valid()); |
if (length_ <= String::kMaxHashCalcLength) { |
if (is_array_index()) { |
return MakeArrayIndexHash(array_index(), length_); |
@@ -7446,58 +7188,15 @@ void String::PrintOn(FILE* file) { |
// Clear a possible back pointer in case the transition leads to a dead map. |
// Return true in case a back pointer has been cleared and false otherwise. |
-static bool ClearBackPointer(Heap* heap, Map* target) { |
- if (Marking::MarkBitFrom(target).Get()) return false; |
- target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); |
+static bool ClearBackPointer(Heap* heap, Object* target) { |
+ ASSERT(target->IsMap()); |
+ Map* map = Map::cast(target); |
+ if (Marking::MarkBitFrom(map).Get()) return false; |
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); |
return true; |
} |
-static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) { |
- int live_enum = map->EnumLength(); |
- if (live_enum == Map::kInvalidEnumCache) { |
- live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
- } |
- if (live_enum == 0) return descriptors->ClearEnumCache(); |
- |
- FixedArray* enum_cache = descriptors->GetEnumCache(); |
- |
- int to_trim = enum_cache->length() - live_enum; |
- if (to_trim <= 0) return; |
- RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim); |
- |
- if (!descriptors->HasEnumIndicesCache()) return; |
- FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache(); |
- RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim); |
-} |
- |
- |
-static void TrimDescriptorArray(Heap* heap, |
- Map* map, |
- DescriptorArray* descriptors, |
- int number_of_own_descriptors) { |
- int number_of_descriptors = descriptors->number_of_descriptors(); |
- int to_trim = number_of_descriptors - number_of_own_descriptors; |
- if (to_trim <= 0) return; |
- |
- // Maximally keep 50% of unused descriptors. |
- int keep = Min(to_trim, number_of_own_descriptors / 2); |
- for (int i = number_of_own_descriptors; |
- i < number_of_own_descriptors + keep; |
- ++i) { |
- descriptors->EraseDescriptor(heap, i); |
- } |
- |
- if (to_trim > keep) { |
- RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim - keep); |
- } |
- descriptors->SetNumberOfDescriptors(number_of_own_descriptors); |
- |
- if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors); |
- descriptors->Sort(); |
-} |
- |
- |
// TODO(mstarzinger): This method should be moved into MarkCompactCollector, |
// because it cannot be called from outside the GC and we already have methods |
// depending on the transitions layout in the GC anyways. |
@@ -7512,21 +7211,9 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
int transition_index = 0; |
- DescriptorArray* descriptors = t->descriptors(); |
- bool descriptors_owner_died = false; |
- |
// Compact all live descriptors to the left. |
for (int i = 0; i < t->number_of_transitions(); ++i) { |
- Map* target = t->GetTarget(i); |
- if (ClearBackPointer(heap, target)) { |
- ASSERT(!Marking::IsGrey(Marking::MarkBitFrom(target))); |
- DescriptorArray* target_descriptors = target->instance_descriptors(); |
- if ((target_descriptors->number_of_descriptors() == 0 && |
- target->NumberOfOwnDescriptors() > 0) || |
- target_descriptors == descriptors) { |
- descriptors_owner_died = true; |
- } |
- } else { |
+ if (!ClearBackPointer(heap, t->GetTarget(i))) { |
if (i != transition_index) { |
String* key = t->GetKey(i); |
t->SetKey(transition_index, key); |
@@ -7541,9 +7228,6 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
if (t->HasElementsTransition() && |
ClearBackPointer(heap, t->elements_transition())) { |
- if (t->elements_transition()->instance_descriptors() == descriptors) { |
- descriptors_owner_died = true; |
- } |
t->ClearElementsTransition(); |
} else { |
// If there are no transitions to be cleared, return. |
@@ -7552,32 +7236,19 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
if (transition_index == t->number_of_transitions()) return; |
} |
- int number_of_own_descriptors = NumberOfOwnDescriptors(); |
- |
- if (descriptors_owner_died) { |
- if (number_of_own_descriptors > 0) { |
- TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors); |
- ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); |
- } else { |
- t->set_descriptors(heap->empty_descriptor_array()); |
- } |
- set_owns_descriptors(true); |
- } |
- |
// If the final transition array does not contain any live transitions, remove |
// the transition array from the map. |
if (transition_index == 0 && |
!t->HasElementsTransition() && |
!t->HasPrototypeTransitions() && |
- number_of_own_descriptors == 0) { |
- ASSERT(owns_descriptors()); |
+ t->descriptors()->IsEmpty()) { |
return ClearTransitions(heap); |
} |
int trim = t->number_of_transitions() - transition_index; |
if (trim > 0) { |
- RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition() |
- ? trim : trim * TransitionArray::kTransitionSize); |
+ RightTrimFixedArray<FROM_GC>( |
+ heap, t, trim * TransitionArray::kTransitionSize); |
} |
} |
@@ -10524,7 +10195,7 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() { |
MaybeObject* JSObject::GetPropertyPostInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
// Check local property in holder, ignore interceptor. |
@@ -10542,7 +10213,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor( |
MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
// Check local property in holder, ignore interceptor. |
@@ -10556,13 +10227,13 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
MaybeObject* JSObject::GetPropertyWithInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
Isolate* isolate = GetIsolate(); |
InterceptorInfo* interceptor = GetNamedInterceptor(); |
HandleScope scope(isolate); |
- Handle<Object> receiver_handle(receiver); |
+ Handle<JSReceiver> receiver_handle(receiver); |
Handle<JSObject> holder_handle(this); |
Handle<String> name_handle(name); |
@@ -10694,16 +10365,9 @@ bool JSObject::HasRealNamedCallbackProperty(String* key) { |
int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { |
- if (HasFastProperties()) { |
- Map* map = this->map(); |
- if (filter == NONE) return map->NumberOfOwnDescriptors(); |
- if (filter == DONT_ENUM) { |
- int result = map->EnumLength(); |
- if (result != Map::kInvalidEnumCache) return result; |
- } |
- return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter); |
- } |
- return property_dictionary()->NumberOfElementsFilterAttributes(filter); |
+ return HasFastProperties() ? |
+ map()->NumberOfDescribedProperties(filter) : |
+ property_dictionary()->NumberOfElementsFilterAttributes(filter); |
} |
@@ -10826,10 +10490,9 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { |
void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { |
ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); |
if (HasFastProperties()) { |
- int real_size = map()->NumberOfOwnDescriptors(); |
DescriptorArray* descs = map()->instance_descriptors(); |
- ASSERT(storage->length() >= index + real_size); |
- for (int i = 0; i < real_size; i++) { |
+ ASSERT(storage->length() >= index + descs->number_of_descriptors()); |
+ for (int i = 0; i < descs->number_of_descriptors(); i++) { |
storage->set(index + i, descs->GetKey(i)); |
} |
} else { |
@@ -12532,8 +12195,8 @@ MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { |
int pos = 0; |
for (int i = 0; i < capacity; i++) { |
if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { |
- int index = DetailsAt(i).dictionary_index(); |
- enumeration_order->set(pos++, Smi::FromInt(index)); |
+ enumeration_order->set( |
+ pos++, Smi::FromInt(DetailsAt(i).dictionary_index())); |
} |
} |
@@ -12662,8 +12325,7 @@ MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key, |
uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); |
// Insert element at empty or deleted entry |
if (!details.IsDeleted() && |
- details.dictionary_index() == 0 && |
- Shape::kIsEnumerable) { |
+ details.dictionary_index() == 0 && Shape::kIsEnumerable) { |
// Assign an enumeration index to the property and update |
// SetNextEnumerationIndex. |
int index = NextEnumerationIndex(); |
@@ -12969,7 +12631,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( |
return maybe_descriptors; |
} |
- DescriptorArray::WhitenessWitness witness(descriptors); |
+ FixedArray::WhitenessWitness witness(descriptors); |
int number_of_allocated_fields = |
number_of_fields + unused_property_fields - inobject_props; |