| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index cd86a43988d98e2f3cab15831d2e6144f28ae886..a4729534e32d26086d4884d3412f1efcde10a418 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1975,31 +1975,6 @@ static Handle<Object> NewStorageFor(Isolate* isolate,
|
| }
|
|
|
|
|
| -void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object,
|
| - Handle<Map> new_map,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - int field_index,
|
| - Representation representation) {
|
| - Isolate* isolate = object->GetIsolate();
|
| -
|
| - // This method is used to transition to a field. If we are transitioning to a
|
| - // double field, allocate new storage.
|
| - Handle<Object> storage = NewStorageFor(isolate, value, representation);
|
| -
|
| - if (object->map()->unused_property_fields() == 0) {
|
| - int new_unused = new_map->unused_property_fields();
|
| - Handle<FixedArray> properties(object->properties());
|
| - Handle<FixedArray> values = isolate->factory()->CopySizeFixedArray(
|
| - properties, properties->length() + new_unused + 1);
|
| - object->set_properties(*values);
|
| - }
|
| -
|
| - object->set_map(*new_map);
|
| - object->FastPropertyAtPut(field_index, *storage);
|
| -}
|
| -
|
| -
|
| static MaybeObject* CopyAddFieldDescriptor(Map* map,
|
| Name* name,
|
| int index,
|
| @@ -2064,7 +2039,16 @@ void JSObject::AddFastProperty(Handle<JSObject> object,
|
| Handle<Map> new_map = CopyAddFieldDescriptor(
|
| handle(object->map()), name, index, attributes, representation, flag);
|
|
|
| - AddFastPropertyUsingMap(object, new_map, name, value, index, representation);
|
| + JSObject::MigrateToMap(object, new_map);
|
| +
|
| + if (representation.IsDouble()) {
|
| + // Nothing more to be done.
|
| + if (value->IsUninitialized()) return;
|
| + HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(index));
|
| + box->set_value(value->Number());
|
| + } else {
|
| + object->FastPropertyAtPut(index, *value);
|
| + }
|
| }
|
|
|
|
|
| @@ -2108,7 +2092,7 @@ void JSObject::AddConstantProperty(Handle<JSObject> object,
|
| Handle<Map> new_map = CopyAddConstantDescriptor(
|
| handle(object->map()), name, constant, attributes, flag);
|
|
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| }
|
|
|
|
|
| @@ -2418,9 +2402,14 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
|
|
|
| Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
|
| Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
|
| - int descriptors = new_map->NumberOfOwnDescriptors();
|
| + int old_nof = old_map->NumberOfOwnDescriptors();
|
| + int new_nof = new_map->NumberOfOwnDescriptors();
|
| +
|
| + // This method only supports generalizing instances to at least the same
|
| + // number of properties.
|
| + ASSERT(old_nof <= new_nof);
|
|
|
| - for (int i = 0; i < descriptors; i++) {
|
| + for (int i = 0; i < old_nof; i++) {
|
| PropertyDetails details = new_descriptors->GetDetails(i);
|
| if (details.type() != FIELD) continue;
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| @@ -2447,6 +2436,17 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
|
| array->set(target_index, *value);
|
| }
|
|
|
| + for (int i = old_nof; i < new_nof; i++) {
|
| + PropertyDetails details = new_descriptors->GetDetails(i);
|
| + if (details.type() != FIELD) continue;
|
| + if (details.representation().IsDouble()) {
|
| + int target_index = new_descriptors->GetFieldIndex(i) - inobject;
|
| + if (target_index < 0) target_index += total_size;
|
| + Handle<Object> box = isolate->factory()->NewHeapNumber(0);
|
| + array->set(target_index, *box);
|
| + }
|
| + }
|
| +
|
| // From here on we cannot fail and we shouldn't GC anymore.
|
| DisallowHeapAllocation no_allocation;
|
|
|
| @@ -3859,16 +3859,7 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
|
| }
|
| map = MapAsElementsKind(map, to_kind);
|
| }
|
| - int total_size =
|
| - map->NumberOfOwnDescriptors() + map->unused_property_fields();
|
| - int out_of_object = total_size - map->inobject_properties();
|
| - if (out_of_object != object->properties()->length()) {
|
| - Isolate* isolate = object->GetIsolate();
|
| - Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray(
|
| - handle(object->properties()), out_of_object);
|
| - object->set_properties(*new_properties);
|
| - }
|
| - object->set_map(*map);
|
| + JSObject::MigrateToMap(object, map);
|
| }
|
|
|
|
|
| @@ -3924,29 +3915,31 @@ Handle<Object> JSObject::SetPropertyUsingTransition(
|
| // Keep the target CONSTANT if the same value is stored.
|
| // TODO(verwaest): Also support keeping the placeholder
|
| // (value->IsUninitialized) as constant.
|
| - if (details.type() == CONSTANT &&
|
| - descriptors->GetValue(descriptor) == *value) {
|
| - object->set_map(*transition_map);
|
| - return value;
|
| - }
|
| -
|
| - Representation representation = details.representation();
|
| -
|
| - if (!value->FitsRepresentation(representation) ||
|
| - details.type() == CONSTANT) {
|
| + if (!value->FitsRepresentation(details.representation()) ||
|
| + (details.type() == CONSTANT &&
|
| + descriptors->GetValue(descriptor) != *value)) {
|
| transition_map = Map::GeneralizeRepresentation(transition_map,
|
| descriptor, value->OptimalRepresentation(), FORCE_FIELD);
|
| - Object* back = transition_map->GetBackPointer();
|
| - if (back->IsMap()) {
|
| - MigrateToMap(object, handle(Map::cast(back)));
|
| - }
|
| - descriptors = transition_map->instance_descriptors();
|
| - representation = descriptors->GetDetails(descriptor).representation();
|
| }
|
|
|
| + JSObject::MigrateToMap(object, transition_map);
|
| +
|
| + // Reload.
|
| + descriptors = transition_map->instance_descriptors();
|
| + details = descriptors->GetDetails(descriptor);
|
| +
|
| + if (details.type() != FIELD) return value;
|
| +
|
| int field_index = descriptors->GetFieldIndex(descriptor);
|
| - AddFastPropertyUsingMap(
|
| - object, transition_map, name, value, field_index, representation);
|
| + if (details.representation().IsDouble()) {
|
| + // Nothing more to be done.
|
| + if (value->IsUninitialized()) return value;
|
| + HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(field_index));
|
| + box->set_value(value->Number());
|
| + } else {
|
| + object->FastPropertyAtPut(field_index, *value);
|
| + }
|
| +
|
| return value;
|
| }
|
|
|
| @@ -4768,6 +4761,7 @@ MaybeObject* JSObject::NormalizeElements() {
|
| MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
|
| DICTIONARY_ELEMENTS);
|
| if (!maybe->To(&new_map)) return maybe;
|
| + // TODO(verwaest): Replace by MigrateToMap.
|
| set_map(new_map);
|
| set_elements(dictionary);
|
| }
|
| @@ -5496,7 +5490,7 @@ Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
|
| Handle<Map> new_map = Map::Copy(handle(object->map()));
|
|
|
| new_map->set_is_extensible(false);
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| ASSERT(!object->map()->is_extensible());
|
|
|
| if (object->map()->is_observed()) {
|
| @@ -5589,11 +5583,11 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
| Handle<Map> old_map(object->map());
|
| old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result);
|
| if (result.IsTransition()) {
|
| - Map* transition_map = result.GetTransitionTarget();
|
| + Handle<Map> transition_map(result.GetTransitionTarget());
|
| ASSERT(transition_map->has_dictionary_elements());
|
| ASSERT(transition_map->is_frozen());
|
| ASSERT(!transition_map->is_extensible());
|
| - object->set_map(transition_map);
|
| + JSObject::MigrateToMap(object, transition_map);
|
| } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
|
| // Create a new descriptor array with fully-frozen properties
|
| int num_descriptors = old_map->NumberOfOwnDescriptors();
|
| @@ -5606,7 +5600,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
| new_map->freeze();
|
| new_map->set_is_extensible(false);
|
| new_map->set_elements_kind(DICTIONARY_ELEMENTS);
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| } else {
|
| // Slow path: need to normalize properties for safety
|
| NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| @@ -5617,7 +5611,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
| new_map->freeze();
|
| new_map->set_is_extensible(false);
|
| new_map->set_elements_kind(DICTIONARY_ELEMENTS);
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
|
|
| // Freeze dictionary-mode properties
|
| FreezeDictionary(object->property_dictionary());
|
| @@ -5661,7 +5655,7 @@ void JSObject::SetObserved(Handle<JSObject> object) {
|
| new_map = Map::Copy(handle(object->map()));
|
| new_map->set_is_observed();
|
| }
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| }
|
|
|
|
|
| @@ -6391,11 +6385,11 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
| }
|
|
|
|
|
| -static bool TryAccessorTransition(JSObject* self,
|
| - Map* transitioned_map,
|
| +static bool TryAccessorTransition(Handle<JSObject> self,
|
| + Handle<Map> transitioned_map,
|
| int target_descriptor,
|
| AccessorComponent component,
|
| - Object* accessor,
|
| + Handle<Object> accessor,
|
| PropertyAttributes attributes) {
|
| DescriptorArray* descs = transitioned_map->instance_descriptors();
|
| PropertyDetails details = descs->GetDetails(target_descriptor);
|
| @@ -6409,8 +6403,8 @@ static bool TryAccessorTransition(JSObject* self,
|
| PropertyAttributes target_attributes = details.attributes();
|
|
|
| // Reuse transition if adding same accessor with same attributes.
|
| - if (target_accessor == accessor && target_attributes == attributes) {
|
| - self->set_map(transitioned_map);
|
| + if (target_accessor == *accessor && target_attributes == attributes) {
|
| + JSObject::MigrateToMap(self, transitioned_map);
|
| return true;
|
| }
|
|
|
| @@ -6472,14 +6466,14 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
|
| object->map()->LookupTransition(*object, *name, &result);
|
|
|
| if (result.IsFound()) {
|
| - Map* target = result.GetTransitionTarget();
|
| + Handle<Map> target(result.GetTransitionTarget());
|
| ASSERT(target->NumberOfOwnDescriptors() ==
|
| object->map()->NumberOfOwnDescriptors());
|
| // This works since descriptors are sorted in order of addition.
|
| ASSERT(object->map()->instance_descriptors()->
|
| GetKey(descriptor_number) == *name);
|
| - return TryAccessorTransition(*object, target, descriptor_number,
|
| - component, *accessor, attributes);
|
| + return TryAccessorTransition(object, target, descriptor_number,
|
| + component, accessor, attributes);
|
| }
|
| } else {
|
| // If not, lookup a transition.
|
| @@ -6487,12 +6481,12 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
|
|
|
| // If there is a transition, try to follow it.
|
| if (result.IsFound()) {
|
| - Map* target = result.GetTransitionTarget();
|
| + Handle<Map> target(result.GetTransitionTarget());
|
| int descriptor_number = target->LastAdded();
|
| ASSERT(target->instance_descriptors()->GetKey(descriptor_number)
|
| ->Equals(*name));
|
| - return TryAccessorTransition(*object, target, descriptor_number,
|
| - component, *accessor, attributes);
|
| + return TryAccessorTransition(object, target, descriptor_number,
|
| + component, accessor, attributes);
|
| }
|
| }
|
|
|
| @@ -6505,7 +6499,7 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
|
| accessors->set(component, *accessor);
|
| Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()),
|
| name, accessors, attributes);
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| return true;
|
| }
|
|
|
| @@ -9789,7 +9783,7 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
|
| // different prototype.
|
| Handle<Map> new_map = Map::Copy(handle(function->map()));
|
|
|
| - function->set_map(*new_map);
|
| + JSObject::MigrateToMap(function, new_map);
|
| new_map->set_constructor(*value);
|
| new_map->set_non_instance_prototype(true);
|
| Isolate* isolate = new_map->GetIsolate();
|
| @@ -11863,7 +11857,7 @@ Handle<Object> JSObject::SetPrototype(Handle<JSObject> object,
|
| new_map->set_prototype(*value);
|
| }
|
| ASSERT(new_map->prototype() == *value);
|
| - real_receiver->set_map(*new_map);
|
| + JSObject::MigrateToMap(real_receiver, new_map);
|
|
|
| if (!dictionary_elements_in_chain &&
|
| new_map->DictionaryElementsInPrototypeChainOnly()) {
|
| @@ -12204,7 +12198,7 @@ Handle<Object> JSObject::SetFastElement(Handle<JSObject> object,
|
|
|
| UpdateAllocationSite(object, kind);
|
| Handle<Map> new_map = GetElementsTransitionMap(object, kind);
|
| - object->set_map(*new_map);
|
| + JSObject::MigrateToMap(object, new_map);
|
| ASSERT(IsFastObjectElementsKind(object->GetElementsKind()));
|
| }
|
| // Increase backing store capacity if that's been decided previously.
|
| @@ -12893,6 +12887,7 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
|
| MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
|
| Map* new_map;
|
| if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
| + // TODO(verwaest): Replace by MigrateToMap.
|
| set_map(new_map);
|
| if (FLAG_trace_elements_transitions) {
|
| FixedArrayBase* elms = FixedArrayBase::cast(elements());
|
|
|