Index: src/objects.cc |
=================================================================== |
--- src/objects.cc (revision 474) |
+++ src/objects.cc (working copy) |
@@ -964,21 +964,7 @@ |
return AddSlowProperty(name, value, attributes); |
} |
- // Replace a CONSTANT_TRANSITION flag with a transition. |
- // Do this by removing it, and the standard code for adding a map transition |
- // will then run. |
DescriptorArray* old_descriptors = map()->instance_descriptors(); |
- int old_name_index = old_descriptors->Search(name); |
- bool constant_transition = false; // Only used in assertions. |
- if (old_name_index != DescriptorArray::kNotFound && CONSTANT_TRANSITION == |
- PropertyDetails(old_descriptors->GetDetails(old_name_index)).type()) { |
- constant_transition = true; |
- Object* r = old_descriptors->CopyRemove(name); |
- if (r->IsFailure()) return r; |
- old_descriptors = DescriptorArray::cast(r); |
- old_name_index = DescriptorArray::kNotFound; |
- } |
- |
// Compute the new index for new field. |
int index = map()->NextFreePropertyIndex(); |
@@ -993,64 +979,43 @@ |
bool allow_map_transition = |
!old_descriptors->Contains(name) && |
(Top::context()->global_context()->object_function()->map() != map()); |
- ASSERT(allow_map_transition || !constant_transition); |
- if (map()->unused_property_fields() > 0) { |
- ASSERT(index < properties()->length()); |
- // Allocate a new map for the object. |
- Object* r = map()->Copy(); |
+ ASSERT(index < properties()->length() || |
+ map()->unused_property_fields() == 0); |
+ // Allocate a new map for the object. |
+ Object* r = map()->Copy(); |
+ if (r->IsFailure()) return r; |
+ Map* new_map = Map::cast(r); |
+ if (allow_map_transition) { |
+ // Allocate new instance descriptors for the old map with map transition. |
+ MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
+ Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); |
if (r->IsFailure()) return r; |
- Map* new_map = Map::cast(r); |
- if (allow_map_transition) { |
- // Allocate new instance descriptors for the old map with map transition. |
- MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
- Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); |
- if (r->IsFailure()) return r; |
- old_descriptors = DescriptorArray::cast(r); |
- } |
- // We have now allocated all the necessary objects. |
- // All the changes can be applied at once, so they are atomic. |
- map()->set_instance_descriptors(old_descriptors); |
- new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
- new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
- set_map(new_map); |
- properties()->set(index, value); |
- } else { |
- ASSERT(map()->unused_property_fields() == 0); |
+ old_descriptors = DescriptorArray::cast(r); |
+ } |
+ |
+ if (map()->unused_property_fields() == 0) { |
if (properties()->length() > kMaxFastProperties) { |
Object* obj = NormalizeProperties(); |
if (obj->IsFailure()) return obj; |
return AddSlowProperty(name, value, attributes); |
} |
- |
- static const int kExtraFields = 3; |
// Make room for the new value |
Object* values = |
- properties()->CopySize(properties()->length() + kExtraFields); |
+ properties()->CopySize(properties()->length() + kFieldsAdded); |
if (values->IsFailure()) return values; |
- FixedArray::cast(values)->set(index, value); |
- |
- // Allocate a new map for the object. |
- Object* r = map()->Copy(); |
- if (r->IsFailure()) return r; |
- Map* new_map = Map::cast(r); |
- |
- if (allow_map_transition) { |
- MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
- // Allocate new instance descriptors for the old map with map transition. |
- Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); |
- if (r->IsFailure()) return r; |
- old_descriptors = DescriptorArray::cast(r); |
- } |
- // We have now allocated all the necessary objects. |
- // All changes can be done at once, atomically. |
- map()->set_instance_descriptors(old_descriptors); |
- new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
- new_map->set_unused_property_fields(kExtraFields - 1); |
- set_map(new_map); |
set_properties(FixedArray::cast(values)); |
+ new_map->set_unused_property_fields(kFieldsAdded - 1); |
+ } else { |
+ new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
} |
+ // We have now allocated all the necessary objects. |
+ // All the changes can be applied at once, so they are atomic. |
+ map()->set_instance_descriptors(old_descriptors); |
+ new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
+ set_map(new_map); |
+ properties()->set(index, value); |
return value; |
} |
@@ -1104,74 +1069,6 @@ |
} |
-Object* JSObject::ReplaceConstantFunctionProperty(String* name, |
- Object* value) { |
- // There are two situations to handle here: |
- // 1: Replace a constant function with another function. |
- // 2: Replace a constant function with an object. |
- if (value->IsJSFunction()) { |
- JSFunction* function = JSFunction::cast(value); |
- |
- Object* new_map = map()->CopyDropTransitions(); |
- if (new_map->IsFailure()) return new_map; |
- set_map(Map::cast(new_map)); |
- |
- // Replace the function entry |
- int index = map()->instance_descriptors()->Search(name); |
- ASSERT(index != DescriptorArray::kNotFound); |
- map()->instance_descriptors()->ReplaceConstantFunction(index, function); |
- } else { |
- // Allocate new instance descriptors with updated property index. |
- int index = map()->NextFreePropertyIndex(); |
- Object* new_descriptors = |
- map()->instance_descriptors()->CopyReplace(name, index, NONE); |
- if (new_descriptors->IsFailure()) return new_descriptors; |
- |
- if (map()->unused_property_fields() > 0) { |
- ASSERT(index < properties()->length()); |
- |
- // Allocate a new map for the object. |
- Object* new_map = map()->Copy(); |
- if (new_map->IsFailure()) return new_map; |
- |
- Map::cast(new_map)-> |
- set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
- Map::cast(new_map)-> |
- set_unused_property_fields(map()->unused_property_fields()-1); |
- set_map(Map::cast(new_map)); |
- properties()->set(index, value); |
- } else { |
- ASSERT(map()->unused_property_fields() == 0); |
- static const int kFastNofProperties = 20; |
- if (properties()->length() > kFastNofProperties) { |
- Object* obj = NormalizeProperties(); |
- if (obj->IsFailure()) return obj; |
- return SetProperty(name, value, NONE); |
- } |
- |
- static const int kExtraFields = 5; |
- // Make room for the more properties. |
- Object* values = |
- properties()->CopySize(properties()->length() + kExtraFields); |
- if (values->IsFailure()) return values; |
- FixedArray::cast(values)->set(index, value); |
- |
- // Allocate a new map for the object. |
- Object* new_map = map()->Copy(); |
- if (new_map->IsFailure()) return new_map; |
- |
- Map::cast(new_map)-> |
- set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
- Map::cast(new_map)-> |
- set_unused_property_fields(kExtraFields - 1); |
- set_map(Map::cast(new_map)); |
- set_properties(FixedArray::cast(values)); |
- } |
- } |
- return value; |
-} |
- |
- |
// Add property in slow mode |
Object* JSObject::AddSlowProperty(String* name, |
Object* value, |
@@ -1223,6 +1120,103 @@ |
} |
+Object* JSObject::ReplaceSlowProperty(String* name, |
+ Object* value, |
+ PropertyAttributes attributes) { |
+ Dictionary* dictionary = property_dictionary(); |
+ PropertyDetails old_details = |
+ dictionary->DetailsAt(dictionary->FindStringEntry(name)); |
+ int new_index = old_details.index(); |
+ if (old_details.IsTransition()) new_index = 0; |
+ |
+ PropertyDetails new_details(attributes, NORMAL, old_details.index()); |
+ Object* result = |
+ property_dictionary()->SetOrAddStringEntry(name, value, new_details); |
+ if (result->IsFailure()) return result; |
+ if (property_dictionary() != result) { |
+ set_properties(Dictionary::cast(result)); |
+ } |
+ return value; |
+} |
+ |
+Object* JSObject::ConvertDescriptorToFieldAndMapTransition( |
+ String* name, |
+ Object* new_value, |
+ PropertyAttributes attributes) { |
+ Map* old_map = map(); |
+ Object* result = ConvertDescriptorToField(name, new_value, attributes); |
+ if (result->IsFailure()) return result; |
+ // If we get to this point we have succeeded - do not return failure |
+ // after this point. Later stuff is optional. |
+ if (!HasFastProperties()) { |
+ return result; |
+ } |
+ // Do not add transitions to the map of "new Object()". |
+ if (map() == Top::context()->global_context()->object_function()->map()) { |
+ return result; |
+ } |
+ |
+ MapTransitionDescriptor transition(name, |
+ map(), |
+ attributes); |
+ Object* new_descriptors = |
+ old_map->instance_descriptors()-> |
+ CopyInsert(&transition, KEEP_TRANSITIONS); |
+ if (new_descriptors->IsFailure()) return result; // Yes, return _result_. |
+ old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
+ return result; |
+} |
+ |
+ |
+Object* JSObject::ConvertDescriptorToField(String* name, |
+ Object* new_value, |
+ PropertyAttributes attributes) { |
+ if (map()->unused_property_fields() == 0 && |
+ properties()->length() > kMaxFastProperties) { |
+ Object* obj = NormalizeProperties(); |
+ if (obj->IsFailure()) return obj; |
+ return ReplaceSlowProperty(name, new_value, attributes); |
+ } |
+ |
+ int index = map()->NextFreePropertyIndex(); |
+ FieldDescriptor new_field(name, index, attributes); |
+ // Make a new DescriptorArray replacing an entry with FieldDescriptor. |
+ Object* descriptors_unchecked = map()->instance_descriptors()-> |
+ CopyInsert(&new_field, REMOVE_TRANSITIONS); |
+ if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; |
+ DescriptorArray* new_descriptors = |
+ DescriptorArray::cast(descriptors_unchecked); |
+ |
+ // Make a new map for the object. |
+ Object* new_map_unchecked = map()->Copy(); |
+ if (new_map_unchecked->IsFailure()) return new_map_unchecked; |
+ Map* new_map = Map::cast(new_map_unchecked); |
+ new_map->set_instance_descriptors(new_descriptors); |
+ |
+ // Make new properties array if necessary. |
+ FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. |
+ int new_unused_property_fields = map()->unused_property_fields() - 1; |
+ if (map()->unused_property_fields() == 0) { |
+ new_unused_property_fields = kFieldsAdded - 1; |
+ Object* new_properties_unchecked = |
+ properties()->CopySize(properties()->length() + kFieldsAdded); |
+ if (new_properties_unchecked->IsFailure()) return new_properties_unchecked; |
+ new_properties = FixedArray::cast(new_properties_unchecked); |
+ } |
+ |
+ // Update pointers to commit changes. |
+ // Object points to the new map. |
+ new_map->set_unused_property_fields(new_unused_property_fields); |
+ set_map(new_map); |
+ if (new_properties) { |
+ set_properties(FixedArray::cast(new_properties)); |
+ } |
+ properties()->set(index, new_value); |
+ return new_value; |
+} |
+ |
+ |
+ |
Object* JSObject::SetPropertyWithInterceptor(String* name, |
Object* value, |
PropertyAttributes attributes) { |
@@ -1528,13 +1522,12 @@ |
return AddFastPropertyUsingMap(result->GetTransitionMap(), |
name, |
value); |
- } else { |
- return AddFastProperty(name, value, attributes); |
} |
+ return ConvertDescriptorToField(name, value, attributes); |
case CONSTANT_FUNCTION: |
if (value == result->GetConstantFunction()) return value; |
// Only replace the function if necessary. |
- return ReplaceConstantFunctionProperty(name, value); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
case CALLBACKS: |
return SetPropertyWithCallback(result->GetCallbackObject(), |
name, |
@@ -1545,10 +1538,9 @@ |
case CONSTANT_TRANSITION: |
// Replace with a MAP_TRANSITION to a new map with a FIELD, even |
// if the value is a function. |
- // AddProperty has been extended to do this, in this case. |
- return AddFastProperty(name, value, attributes); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
case NULL_DESCRIPTOR: |
- UNREACHABLE(); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
default: |
UNREACHABLE(); |
} |
@@ -1580,33 +1572,14 @@ |
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
return SetPropertyWithFailedAccessCheck(result, name, value); |
} |
- /* |
- REMOVED FROM CLONE |
- if (result->IsNotFound() || !result->IsProperty()) { |
- // We could not find a local property so let's check whether there is an |
- // accessor that wants to handle the property. |
- LookupResult accessor_result; |
- LookupCallbackSetterInPrototypes(name, &accessor_result); |
- if (accessor_result.IsValid()) { |
- return SetPropertyWithCallback(accessor_result.GetCallbackObject(), |
- name, |
- value, |
- accessor_result.holder()); |
- } |
- } |
- */ |
+ // Check for accessor in prototype chain removed here in clone. |
if (result->IsNotFound()) { |
return AddProperty(name, value, attributes); |
} |
if (!result->IsLoaded()) { |
return SetLazyProperty(result, name, value, attributes); |
} |
- /* |
- REMOVED FROM CLONE |
- if (result->IsReadOnly() && result->IsProperty()) return value; |
- */ |
- // This is a real property that is not read-only, or it is a |
- // transition or null descriptor and there are no setters in the prototypes. |
+ // Check of IsReadOnly removed from here in clone. |
switch (result->type()) { |
case NORMAL: |
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); |
@@ -1621,12 +1594,12 @@ |
name, |
value); |
} else { |
- return AddFastProperty(name, value, attributes); |
+ return ConvertDescriptorToField(name, value, attributes); |
} |
case CONSTANT_FUNCTION: |
if (value == result->GetConstantFunction()) return value; |
// Only replace the function if necessary. |
- return ReplaceConstantFunctionProperty(name, value); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
case CALLBACKS: |
return SetPropertyWithCallback(result->GetCallbackObject(), |
name, |
@@ -1637,10 +1610,9 @@ |
case CONSTANT_TRANSITION: |
// Replace with a MAP_TRANSITION to a new map with a FIELD, even |
// if the value is a function. |
- // AddProperty has been extended to do this, in this case. |
- return AddFastProperty(name, value, attributes); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
case NULL_DESCRIPTOR: |
- UNREACHABLE(); |
+ return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
default: |
UNREACHABLE(); |
} |
@@ -2663,14 +2635,6 @@ |
} |
-void DescriptorArray::ReplaceConstantFunction(int descriptor_number, |
- JSFunction* value) { |
- ASSERT(!Heap::InNewSpace(value)); |
- FixedArray* content_array = GetContentArray(); |
- fast_set(content_array, ToValueIndex(descriptor_number), value); |
-} |
- |
- |
Object* DescriptorArray::CopyInsert(Descriptor* descriptor, |
TransitionFlag transition_flag) { |
// Transitions are only kept when inserting another transition. |
@@ -2771,69 +2735,6 @@ |
} |
-Object* DescriptorArray::CopyReplace(String* name, |
- int index, |
- PropertyAttributes attributes) { |
- // Allocate the new descriptor array. |
- Object* result = DescriptorArray::Allocate(number_of_descriptors()); |
- if (result->IsFailure()) return result; |
- |
- // Make sure only symbols are added to the instance descriptor. |
- if (!name->IsSymbol()) { |
- Object* result = Heap::LookupSymbol(name); |
- if (result->IsFailure()) return result; |
- name = String::cast(result); |
- } |
- |
- DescriptorWriter w(DescriptorArray::cast(result)); |
- for (DescriptorReader r(this); !r.eos(); r.advance()) { |
- if (r.Equals(name)) { |
- FieldDescriptor d(name, index, attributes); |
- d.SetEnumerationIndex(r.GetDetails().index()); |
- w.Write(&d); |
- } else { |
- w.WriteFrom(&r); |
- } |
- } |
- |
- // Copy the next enumeration index. |
- DescriptorArray::cast(result)-> |
- SetNextEnumerationIndex(NextEnumerationIndex()); |
- |
- ASSERT(w.eos()); |
- return result; |
-} |
- |
- |
-Object* DescriptorArray::CopyRemove(String* name) { |
- if (!name->IsSymbol()) { |
- Object* result = Heap::LookupSymbol(name); |
- if (result->IsFailure()) return result; |
- name = String::cast(result); |
- } |
- ASSERT(name->IsSymbol()); |
- Object* result = Allocate(number_of_descriptors() - 1); |
- if (result->IsFailure()) return result; |
- DescriptorArray* new_descriptors = DescriptorArray::cast(result); |
- |
- // Set the enumeration index in the descriptors and set the enumeration index |
- // in the result. |
- new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); |
- // Write the old content and the descriptor information |
- DescriptorWriter w(new_descriptors); |
- DescriptorReader r(this); |
- while (!r.eos()) { |
- if (r.GetKey() != name) { // Both are symbols; object identity suffices. |
- w.WriteFrom(&r); |
- } |
- r.advance(); |
- } |
- ASSERT(w.eos()); |
- |
- return new_descriptors; |
-} |
- |
- |
Object* DescriptorArray::RemoveTransitions() { |
// Remove all transitions. Return a copy of the array with all transitions |
// removed, or a Failure object if the new array could not be allocated. |