| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 3fa1a4098f4b870748e13419feecd42be112f015..e63a582f9fe7b6c19e7499af93ba1fadf372df9c 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -815,11 +815,14 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
| value = result->holder()->GetNormalizedProperty(result);
|
| ASSERT(!value->IsTheHole() || result->IsReadOnly());
|
| return value->IsTheHole() ? heap->undefined_value() : value;
|
| - case FIELD:
|
| - value = result->holder()->FastPropertyAt(
|
| + case FIELD: {
|
| + MaybeObject* maybe_result = result->holder()->FastPropertyAt(
|
| + result->representation(),
|
| result->GetFieldIndex().field_index());
|
| + if (!maybe_result->To(&value)) return maybe_result;
|
| ASSERT(!value->IsTheHole() || result->IsReadOnly());
|
| return value->IsTheHole() ? heap->undefined_value() : value;
|
| + }
|
| case CONSTANT_FUNCTION:
|
| return result->GetConstantFunction();
|
| case CALLBACKS:
|
| @@ -1711,7 +1714,15 @@ String* JSReceiver::constructor_name() {
|
| MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
|
| Name* name,
|
| Object* value,
|
| - int field_index) {
|
| + int field_index,
|
| + Representation representation) {
|
| + // This method is used to transition to a field. If we are transitioning to a
|
| + // double field, allocate new storage.
|
| + Object* storage;
|
| + MaybeObject* maybe_storage =
|
| + value->AllocateNewStorageFor(GetHeap(), representation);
|
| + if (!maybe_storage->To(&storage)) return maybe_storage;
|
| +
|
| if (map()->unused_property_fields() == 0) {
|
| int new_unused = new_map->unused_property_fields();
|
| FixedArray* values;
|
| @@ -1721,8 +1732,11 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
|
|
|
| set_properties(values);
|
| }
|
| +
|
| set_map(new_map);
|
| - return FastPropertyAtPut(field_index, value);
|
| +
|
| + FastPropertyAtPut(field_index, storage);
|
| + return value;
|
| }
|
|
|
|
|
| @@ -1774,8 +1788,8 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
|
| int index = map()->NextFreePropertyIndex();
|
|
|
| // Allocate new instance descriptors with (name, index) added
|
| - FieldDescriptor new_field(
|
| - name, index, attributes, value->OptimalRepresentation(), 0);
|
| + Representation representation = value->OptimalRepresentation();
|
| + FieldDescriptor new_field(name, index, attributes, representation, 0);
|
|
|
| ASSERT(index < map()->inobject_properties() ||
|
| (index - map()->inobject_properties()) < properties()->length() ||
|
| @@ -1783,6 +1797,7 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
|
|
|
| FixedArray* values = NULL;
|
|
|
| + // TODO(verwaest): Merge with AddFastPropertyUsingMap.
|
| if (map()->unused_property_fields() == 0) {
|
| // Make room for the new value
|
| MaybeObject* maybe_values =
|
| @@ -1792,10 +1807,17 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
|
|
|
| TransitionFlag flag = INSERT_TRANSITION;
|
|
|
| + Heap* heap = isolate->heap();
|
| +
|
| Map* new_map;
|
| MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
|
| if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
|
|
| + Object* storage;
|
| + MaybeObject* maybe_storage =
|
| + value->AllocateNewStorageFor(heap, representation);
|
| + if (!maybe_storage->To(&storage)) return maybe_storage;
|
| +
|
| if (map()->unused_property_fields() == 0) {
|
| ASSERT(values != NULL);
|
| set_properties(values);
|
| @@ -1805,7 +1827,9 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
|
| }
|
|
|
| set_map(new_map);
|
| - return FastPropertyAtPut(index, value);
|
| +
|
| + FastPropertyAtPut(index, storage);
|
| + return value;
|
| }
|
|
|
|
|
| @@ -2071,9 +2095,9 @@ MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
|
| return ReplaceSlowProperty(name, new_value, attributes);
|
| }
|
|
|
| + Representation representation = new_value->OptimalRepresentation();
|
| int index = map()->NextFreePropertyIndex();
|
| - FieldDescriptor new_field(
|
| - name, index, attributes, new_value->OptimalRepresentation(), 0);
|
| + FieldDescriptor new_field(name, index, attributes, representation, 0);
|
|
|
| // Make a new map for the object.
|
| Map* new_map;
|
| @@ -2091,6 +2115,12 @@ MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
|
| if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties;
|
| }
|
|
|
| + Heap* heap = GetHeap();
|
| + Object* storage;
|
| + MaybeObject* maybe_storage =
|
| + new_value->AllocateNewStorageFor(heap, representation);
|
| + if (!maybe_storage->To(&storage)) return maybe_storage;
|
| +
|
| // Update pointers to commit changes.
|
| // Object points to the new map.
|
| new_map->set_unused_property_fields(new_unused_property_fields);
|
| @@ -2098,7 +2128,8 @@ MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
|
| if (new_properties != NULL) {
|
| set_properties(new_properties);
|
| }
|
| - return FastPropertyAtPut(index, new_value);
|
| + FastPropertyAtPut(index, new_value);
|
| + return new_value;
|
| }
|
|
|
|
|
| @@ -2166,13 +2197,28 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
|
| }
|
|
|
|
|
| -bool Map::InstancesNeedRewriting(int target_number_of_fields,
|
| +bool Map::InstancesNeedRewriting(Map* target,
|
| + int target_number_of_fields,
|
| int target_inobject,
|
| int target_unused) {
|
| // If fields were added (or removed), rewrite the instance.
|
| int number_of_fields = NumberOfFields();
|
| ASSERT(target_number_of_fields >= number_of_fields);
|
| if (target_number_of_fields != number_of_fields) return true;
|
| +
|
| + if (FLAG_track_double_fields) {
|
| + // If smi descriptors were replaced by double descriptors, rewrite.
|
| + DescriptorArray* old_desc = instance_descriptors();
|
| + DescriptorArray* new_desc = target->instance_descriptors();
|
| + int limit = NumberOfOwnDescriptors();
|
| + for (int i = 0; i < limit; i++) {
|
| + if (new_desc->GetDetails(i).representation().IsDouble() &&
|
| + old_desc->GetDetails(i).representation().IsSmi()) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| +
|
| // If no fields were added, and no inobject properties were removed, setting
|
| // the map is sufficient.
|
| if (target_inobject == inobject_properties()) return false;
|
| @@ -2212,7 +2258,8 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
|
| int unused = new_map->unused_property_fields();
|
|
|
| // Nothing to do if no functions were converted to fields.
|
| - if (!old_map->InstancesNeedRewriting(number_of_fields, inobject, unused)) {
|
| + if (!old_map->InstancesNeedRewriting(
|
| + new_map, number_of_fields, inobject, unused)) {
|
| set_map(new_map);
|
| return this;
|
| }
|
| @@ -2235,7 +2282,21 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
|
| old_details.type() == FIELD);
|
| Object* value = old_details.type() == CONSTANT_FUNCTION
|
| ? old_descriptors->GetValue(i)
|
| - : FastPropertyAt(old_descriptors->GetFieldIndex(i));
|
| + : RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
|
| + if (FLAG_track_double_fields &&
|
| + old_details.representation().IsSmi() &&
|
| + details.representation().IsDouble()) {
|
| + // Objects must be allocated in the old object space, since the
|
| + // overall number of HeapNumbers needed for the conversion might
|
| + // exceed the capacity of new space, and we would fail repeatedly
|
| + // trying to migrate the instance.
|
| + MaybeObject* maybe_storage =
|
| + value->AllocateNewStorageFor(heap, details.representation(), TENURED);
|
| + if (!maybe_storage->To(&value)) return maybe_storage;
|
| + }
|
| + ASSERT(!(FLAG_track_double_fields &&
|
| + details.representation().IsDouble() &&
|
| + value->IsSmi()));
|
| int target_index = new_descriptors->GetFieldIndex(i) - inobject;
|
| if (target_index < 0) target_index += total_size;
|
| array->set(target_index, value);
|
| @@ -2300,6 +2361,10 @@ MaybeObject* Map::CopyGeneralizeAllRepresentations() {
|
|
|
| new_map->instance_descriptors()->InitializeRepresentations(
|
| Representation::Tagged());
|
| + if (FLAG_trace_generalization) {
|
| + PrintF("failed generalization %p -> %p\n",
|
| + static_cast<void*>(this), static_cast<void*>(new_map));
|
| + }
|
| return new_map;
|
| }
|
|
|
| @@ -2465,7 +2530,13 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
| verbatim, valid, descriptors, old_descriptors)) {
|
| Representation updated_representation =
|
| updated_descriptors->GetDetails(modify_index).representation();
|
| - if (new_representation.fits_into(updated_representation)) return updated;
|
| + if (new_representation.fits_into(updated_representation)) {
|
| + if (FLAG_trace_generalization) {
|
| + PrintF("migrating to existing map %p -> %p\n",
|
| + static_cast<void*>(this), static_cast<void*>(updated));
|
| + }
|
| + return updated;
|
| + }
|
| }
|
|
|
| DescriptorArray* new_descriptors;
|
| @@ -2490,6 +2561,13 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
| split_map->DeprecateTarget(
|
| old_descriptors->GetKey(descriptor), new_descriptors);
|
|
|
| + if (FLAG_trace_generalization) {
|
| + PrintF("migrating to new map %p -> %p (%i steps)\n",
|
| + static_cast<void*>(this),
|
| + static_cast<void*>(new_descriptors),
|
| + descriptors - descriptor);
|
| + }
|
| +
|
| Map* new_map = split_map;
|
| // Add missing transitions.
|
| for (; descriptor < descriptors; descriptor++) {
|
| @@ -3032,7 +3110,7 @@ void JSObject::LocalLookupRealNamedProperty(Name* name, LookupResult* result) {
|
| // occur as fields.
|
| if (result->IsField() &&
|
| result->IsReadOnly() &&
|
| - FastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
|
| + RawFastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
|
| result->DisallowCaching();
|
| }
|
| return;
|
| @@ -3465,14 +3543,19 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
|
| }
|
|
|
|
|
| -void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) {
|
| +void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
|
| CALL_HEAP_FUNCTION_VOID(
|
| object->GetIsolate(),
|
| - object->TransitionToMap(*map));
|
| + object->AllocateStorageForMap(*map));
|
| }
|
|
|
|
|
| void JSObject::MigrateInstance(Handle<JSObject> object) {
|
| + if (FLAG_trace_migration) {
|
| + PrintF("migrating instance %p (%p)\n",
|
| + static_cast<void*>(*object),
|
| + static_cast<void*>(object->map()));
|
| + }
|
| CALL_HEAP_FUNCTION_VOID(
|
| object->GetIsolate(),
|
| object->MigrateInstance());
|
| @@ -3481,10 +3564,10 @@ void JSObject::MigrateInstance(Handle<JSObject> object) {
|
|
|
| Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map,
|
| int modify_index,
|
| - Representation new_representation) {
|
| + Representation representation) {
|
| CALL_HEAP_FUNCTION(
|
| map->GetIsolate(),
|
| - map->GeneralizeRepresentation(modify_index, new_representation),
|
| + map->GeneralizeRepresentation(modify_index, representation),
|
| Map);
|
| }
|
|
|
| @@ -3584,9 +3667,21 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
| lookup->holder()->GeneralizeFieldRepresentation(
|
| lookup->GetDescriptorIndex(), value->OptimalRepresentation());
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
| + DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
|
| + int descriptor = lookup->GetDescriptorIndex();
|
| + representation = desc->GetDetails(descriptor).representation();
|
| + }
|
| + if (FLAG_track_double_fields && representation.IsDouble()) {
|
| + HeapNumber* storage =
|
| + HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
|
| + lookup->GetFieldIndex().field_index()));
|
| + storage->set_value(value->Number());
|
| + result = *value;
|
| + break;
|
| }
|
| - result = lookup->holder()->FastPropertyAtPut(
|
| + lookup->holder()->FastPropertyAtPut(
|
| lookup->GetFieldIndex().field_index(), *value);
|
| + result = *value;
|
| break;
|
| }
|
| case CONSTANT_FUNCTION:
|
| @@ -3615,7 +3710,8 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
|
|
| if (details.type() == FIELD) {
|
| if (attributes == details.attributes()) {
|
| - if (!value->FitsRepresentation(details.representation())) {
|
| + Representation representation = details.representation();
|
| + if (!value->FitsRepresentation(representation)) {
|
| MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
| descriptor, value->OptimalRepresentation());
|
| if (!maybe_map->To(&transition_map)) return maybe_map;
|
| @@ -3625,10 +3721,13 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
| lookup->holder()->MigrateToMap(Map::cast(back));
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
| }
|
| + DescriptorArray* desc = transition_map->instance_descriptors();
|
| + int descriptor = transition_map->LastAdded();
|
| + representation = desc->GetDetails(descriptor).representation();
|
| }
|
| int field_index = descriptors->GetFieldIndex(descriptor);
|
| result = lookup->holder()->AddFastPropertyUsingMap(
|
| - transition_map, *name, *value, field_index);
|
| + transition_map, *name, *value, field_index, representation);
|
| } else {
|
| result = lookup->holder()->ConvertDescriptorToField(
|
| *name, *value, attributes);
|
| @@ -3769,9 +3868,20 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
| MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation(
|
| lookup.GetDescriptorIndex(), value->OptimalRepresentation());
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
| + DescriptorArray* desc = self->map()->instance_descriptors();
|
| + int descriptor = lookup.GetDescriptorIndex();
|
| + representation = desc->GetDetails(descriptor).representation();
|
| + }
|
| + if (FLAG_track_double_fields && representation.IsDouble()) {
|
| + HeapNumber* storage =
|
| + HeapNumber::cast(self->RawFastPropertyAt(
|
| + lookup.GetFieldIndex().field_index()));
|
| + storage->set_value(value->Number());
|
| + result = *value;
|
| + break;
|
| }
|
| - result = self->FastPropertyAtPut(
|
| - lookup.GetFieldIndex().field_index(), *value);
|
| + self->FastPropertyAtPut(lookup.GetFieldIndex().field_index(), *value);
|
| + result = *value;
|
| break;
|
| }
|
| case CONSTANT_FUNCTION:
|
| @@ -3796,7 +3906,8 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
|
|
| if (details.type() == FIELD) {
|
| if (attributes == details.attributes()) {
|
| - if (!value->FitsRepresentation(details.representation())) {
|
| + Representation representation = details.representation();
|
| + if (!value->FitsRepresentation(representation)) {
|
| MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
| descriptor, value->OptimalRepresentation());
|
| if (!maybe_map->To(&transition_map)) return maybe_map;
|
| @@ -3805,10 +3916,13 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
| MaybeObject* maybe_failure = self->MigrateToMap(Map::cast(back));
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
| }
|
| + DescriptorArray* desc = transition_map->instance_descriptors();
|
| + int descriptor = transition_map->LastAdded();
|
| + representation = desc->GetDetails(descriptor).representation();
|
| }
|
| int field_index = descriptors->GetFieldIndex(descriptor);
|
| result = self->AddFastPropertyUsingMap(
|
| - transition_map, *name, *value, field_index);
|
| + transition_map, *name, *value, field_index, representation);
|
| } else {
|
| result = self->ConvertDescriptorToField(*name, *value, attributes);
|
| }
|
| @@ -4233,7 +4347,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
|
| NORMAL,
|
| Representation::None(),
|
| details.descriptor_index());
|
| - Object* value = FastPropertyAt(descs->GetFieldIndex(i));
|
| + Object* value = RawFastPropertyAt(descs->GetFieldIndex(i));
|
| MaybeObject* maybe_dictionary =
|
| dictionary->Add(descs->GetKey(i), value, d);
|
| if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
|
| @@ -4614,8 +4728,10 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable(
|
| if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
|
| sorted_index < map()->NumberOfOwnDescriptors()) {
|
| ASSERT(descriptors->GetType(sorted_index) == FIELD);
|
| - inline_value =
|
| - this->FastPropertyAt(descriptors->GetFieldIndex(sorted_index));
|
| + MaybeObject* maybe_value = this->FastPropertyAt(
|
| + descriptors->GetDetails(sorted_index).representation(),
|
| + descriptors->GetFieldIndex(sorted_index));
|
| + if (!maybe_value->To(&inline_value)) return maybe_value;
|
| } else {
|
| inline_value = GetHeap()->undefined_value();
|
| }
|
| @@ -4684,8 +4800,7 @@ MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) {
|
| if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
|
| sorted_index < map()->NumberOfOwnDescriptors()) {
|
| ASSERT(descriptors->GetType(sorted_index) == FIELD);
|
| - this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index),
|
| - value);
|
| + FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value);
|
| return this;
|
| }
|
| }
|
| @@ -5161,6 +5276,11 @@ MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) {
|
| StackLimitCheck check(isolate);
|
| if (check.HasOverflowed()) return isolate->StackOverflow();
|
|
|
| + if (map()->is_deprecated()) {
|
| + MaybeObject* maybe_failure = MigrateInstance();
|
| + if (maybe_failure->IsFailure()) return maybe_failure;
|
| + }
|
| +
|
| Heap* heap = isolate->heap();
|
| Object* result;
|
| { MaybeObject* maybe_result = heap->CopyJSObject(this);
|
| @@ -5170,27 +5290,24 @@ MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) {
|
|
|
| // Deep copy local properties.
|
| if (copy->HasFastProperties()) {
|
| - FixedArray* properties = copy->properties();
|
| - for (int i = 0; i < properties->length(); i++) {
|
| - Object* value = properties->get(i);
|
| - if (value->IsJSObject()) {
|
| - JSObject* js_object = JSObject::cast(value);
|
| - { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| - properties->set(i, result);
|
| - }
|
| - }
|
| - int nof = copy->map()->inobject_properties();
|
| - for (int i = 0; i < nof; i++) {
|
| - Object* value = copy->InObjectPropertyAt(i);
|
| + DescriptorArray* descriptors = copy->map()->instance_descriptors();
|
| + int limit = copy->map()->NumberOfOwnDescriptors();
|
| + for (int i = 0; i < limit; i++) {
|
| + PropertyDetails details = descriptors->GetDetails(i);
|
| + if (details.type() != FIELD) continue;
|
| + int index = descriptors->GetFieldIndex(i);
|
| + Object* value = RawFastPropertyAt(index);
|
| if (value->IsJSObject()) {
|
| JSObject* js_object = JSObject::cast(value);
|
| - { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| - copy->InObjectPropertyAtPut(i, result);
|
| + MaybeObject* maybe_copy = js_object->DeepCopy(isolate);
|
| + if (!maybe_copy->To(&value)) return maybe_copy;
|
| + } else {
|
| + Representation representation = details.representation();
|
| + MaybeObject* maybe_storage =
|
| + value->AllocateNewStorageFor(heap, representation);
|
| + if (!maybe_storage->To(&value)) return maybe_storage;
|
| }
|
| + copy->FastPropertyAtPut(index, value);
|
| }
|
| } else {
|
| { MaybeObject* maybe_result =
|
| @@ -6018,7 +6135,14 @@ Object* JSObject::SlowReverseLookup(Object* value) {
|
| DescriptorArray* descs = map()->instance_descriptors();
|
| for (int i = 0; i < number_of_own_descriptors; i++) {
|
| if (descs->GetType(i) == FIELD) {
|
| - if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
|
| + Object* property = RawFastPropertyAt(descs->GetFieldIndex(i));
|
| + if (FLAG_track_double_fields &&
|
| + descs->GetDetails(i).representation().IsDouble()) {
|
| + ASSERT(property->IsHeapNumber());
|
| + if (value->IsNumber() && property->Number() == value->Number()) {
|
| + return descs->GetKey(i);
|
| + }
|
| + } else if (property == value) {
|
| return descs->GetKey(i);
|
| }
|
| } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
|
| @@ -6048,6 +6172,7 @@ MaybeObject* Map::RawCopy(int instance_size) {
|
| 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);
|
| + new_bit_field3 = Deprecated::update(new_bit_field3, false);
|
| result->set_bit_field3(new_bit_field3);
|
| return result;
|
| }
|
|
|