| 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.
|
|
|