Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 10971cfb7c53c8695f620f49129373c1f489e882..fe2b6bafdda913a2625fb6e9e04d4e49009ca16b 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1812,7 +1812,8 @@ static bool IsIdentifier(UnicodeCache* cache, Name* name) { |
MaybeObject* JSObject::AddFastProperty(Name* name, |
Object* value, |
PropertyAttributes attributes, |
- StoreFromKeyed store_mode) { |
+ StoreFromKeyed store_mode, |
+ ValueType value_type) { |
ASSERT(!IsJSGlobalProxy()); |
ASSERT(DescriptorArray::kNotFound == |
map()->instance_descriptors()->Search( |
@@ -1838,8 +1839,8 @@ MaybeObject* JSObject::AddFastProperty(Name* name, |
int index = map()->NextFreePropertyIndex(); |
// Allocate new instance descriptors with (name, index) added |
- Representation representation = IsJSContextExtensionObject() |
- ? Representation::Tagged() : value->OptimalRepresentation(); |
+ if (IsJSContextExtensionObject()) value_type = FORCE_TAGGED; |
+ Representation representation = value->OptimalRepresentation(value_type); |
FieldDescriptor new_field(name, index, attributes, representation); |
@@ -1956,7 +1957,8 @@ MaybeObject* JSObject::AddProperty(Name* name, |
PropertyAttributes attributes, |
StrictModeFlag strict_mode, |
JSReceiver::StoreFromKeyed store_mode, |
- ExtensibilityCheck extensibility_check) { |
+ ExtensibilityCheck extensibility_check, |
+ ValueType value_type) { |
ASSERT(!IsJSGlobalProxy()); |
Map* map_of_this = map(); |
Heap* heap = GetHeap(); |
@@ -1983,7 +1985,8 @@ MaybeObject* JSObject::AddProperty(Name* name, |
JSFunction::cast(value), |
attributes); |
} else { |
- result = AddFastProperty(name, value, attributes, store_mode); |
+ result = AddFastProperty( |
+ name, value, attributes, store_mode, value_type); |
} |
} else { |
// Normalize the object to prevent very large instance descriptors. |
@@ -2267,7 +2270,7 @@ bool Map::InstancesNeedRewriting(Map* target, |
int limit = NumberOfOwnDescriptors(); |
for (int i = 0; i < limit; i++) { |
if (new_desc->GetDetails(i).representation().IsDouble() && |
- old_desc->GetDetails(i).representation().IsSmi()) { |
+ !old_desc->GetDetails(i).representation().IsDouble()) { |
return true; |
} |
} |
@@ -2338,8 +2341,9 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) { |
? old_descriptors->GetValue(i) |
: RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); |
if (FLAG_track_double_fields && |
- old_details.representation().IsSmi() && |
+ !old_details.representation().IsDouble() && |
details.representation().IsDouble()) { |
+ if (old_details.representation().IsNone()) value = Smi::FromInt(0); |
// 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 |
@@ -2392,7 +2396,7 @@ MaybeObject* JSObject::GeneralizeFieldRepresentation( |
MaybeObject* maybe_new_map = |
map()->GeneralizeRepresentation(modify_index, new_representation); |
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
- ASSERT(map() != new_map || new_map->FindRootMap()->is_deprecated()); |
+ if (map() == new_map) return this; |
return MigrateToMap(new_map); |
} |
@@ -2569,10 +2573,21 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, |
Representation old_representation = |
old_descriptors->GetDetails(modify_index).representation(); |
- if (old_representation.IsNone()) { |
- UNREACHABLE(); |
+ // It's fine to transition from None to anything but double without any |
+ // modification to the object, because the default uninitialized value for |
+ // representation None can be overwritten by both smi and tagged values. |
+ // Doubles, however, would require a box allocation. |
+ if (old_representation.IsNone() && |
+ !new_representation.IsNone() && |
+ !new_representation.IsDouble()) { |
+ if (FLAG_trace_generalization) { |
+ PrintF("initializing representation %i: %p -> %s\n", |
+ modify_index, |
+ static_cast<void*>(this), |
+ new_representation.Mnemonic()); |
+ } |
old_descriptors->SetRepresentation(modify_index, new_representation); |
- return this; |
+ return old_map; |
} |
int descriptors = old_map->NumberOfOwnDescriptors(); |
@@ -2598,7 +2613,7 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, |
updated_descriptors->GetDetails(modify_index).representation(); |
if (new_representation.fits_into(updated_representation)) { |
if (FLAG_trace_generalization && |
- !(modify_index == 0 && new_representation.IsSmi())) { |
+ !(modify_index == 0 && new_representation.IsNone())) { |
PropertyDetails old_details = old_descriptors->GetDetails(modify_index); |
PrintF("migrating to existing map %p(%s) -> %p(%s)\n", |
static_cast<void*>(this), |
@@ -2636,7 +2651,7 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, |
old_descriptors->GetKey(descriptor), new_descriptors); |
if (FLAG_trace_generalization && |
- !(modify_index == 0 && new_representation.IsSmi())) { |
+ !(modify_index == 0 && new_representation.IsNone())) { |
PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n", |
modify_index, |
static_cast<void*>(this), |
@@ -3928,10 +3943,12 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( |
Handle<JSObject> object, |
Handle<Name> key, |
Handle<Object> value, |
- PropertyAttributes attributes) { |
+ PropertyAttributes attributes, |
+ ValueType value_type) { |
CALL_HEAP_FUNCTION( |
object->GetIsolate(), |
- object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes), |
+ object->SetLocalPropertyIgnoreAttributes( |
+ *key, *value, attributes, value_type), |
Object); |
} |
@@ -3939,7 +3956,8 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( |
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
Name* name_raw, |
Object* value_raw, |
- PropertyAttributes attributes) { |
+ PropertyAttributes attributes, |
+ ValueType value_type) { |
// Make sure that the top context does not change when doing callbacks or |
// interceptor calls. |
AssertNoContextChange ncc; |
@@ -3965,13 +3983,16 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( |
name_raw, |
value_raw, |
- attributes); |
+ attributes, |
+ value_type); |
} |
// Check for accessor in prototype chain removed here in clone. |
if (!lookup.IsFound()) { |
// Neither properties nor transitions found. |
- return AddProperty(name_raw, value_raw, attributes, kNonStrictMode); |
+ return AddProperty( |
+ name_raw, value_raw, attributes, kNonStrictMode, |
+ MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK, value_type); |
} |
// From this point on everything needs to be handlified. |
@@ -3998,9 +4019,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
} |
case FIELD: { |
Representation representation = lookup.representation(); |
- if (!value->FitsRepresentation(representation)) { |
+ Representation value_representation = |
+ value->OptimalRepresentation(value_type); |
+ if (!value_representation.fits_into(representation)) { |
MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation( |
- lookup.GetDescriptorIndex(), value->OptimalRepresentation()); |
+ lookup.GetDescriptorIndex(), value_representation); |
if (maybe_failure->IsFailure()) return maybe_failure; |
DescriptorArray* desc = self->map()->instance_descriptors(); |
int descriptor = lookup.GetDescriptorIndex(); |
@@ -4041,9 +4064,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
if (details.type() == FIELD) { |
if (attributes == details.attributes()) { |
Representation representation = details.representation(); |
- if (!value->FitsRepresentation(representation)) { |
+ Representation value_representation = |
+ value->OptimalRepresentation(value_type); |
+ if (!value_representation.fits_into(representation)) { |
MaybeObject* maybe_map = transition_map->GeneralizeRepresentation( |
- descriptor, value->OptimalRepresentation()); |
+ descriptor, value_representation); |
if (!maybe_map->To(&transition_map)) return maybe_map; |
Object* back = transition_map->GetBackPointer(); |
if (back->IsMap()) { |