Index: src/lookup.cc |
diff --git a/src/lookup.cc b/src/lookup.cc |
index c3cf013c68f60cf102c7063035353a0f98d92db2..b78016142bf9f6a2932a97ae86e9770a1052b9ae 100644 |
--- a/src/lookup.cc |
+++ b/src/lookup.cc |
@@ -237,9 +237,21 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
} |
if (!holder->HasFastProperties()) return; |
+ PropertyConstness new_constness = kConst; |
+ if (FLAG_track_constant_fields) { |
+ if (constness() == kConst) { |
+ DCHECK_EQ(kData, property_details_.kind()); |
+ // Check that current value matches new value otherwise we should make |
+ // the property mutable. |
+ if (!IsConstFieldValueEqualTo(*value)) new_constness = kMutable; |
+ } |
+ } else { |
+ new_constness = kMutable; |
+ } |
+ |
Handle<Map> old_map(holder->map(), isolate_); |
- Handle<Map> new_map = |
- Map::PrepareForDataProperty(old_map, descriptor_number(), value); |
+ Handle<Map> new_map = Map::PrepareForDataProperty( |
+ old_map, descriptor_number(), new_constness, value); |
if (old_map.is_identical_to(new_map)) { |
// Update the property details if the representation was None. |
@@ -271,7 +283,10 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
Handle<Map> old_map(holder->map(), isolate_); |
Handle<Map> new_map = Map::ReconfigureExistingProperty( |
old_map, descriptor_number(), i::kData, attributes); |
- new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value); |
+ // Force mutable to avoid changing constant value by reconfiguring |
+ // kData -> kAccessor -> kData. |
+ new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), |
+ kMutable, value); |
JSObject::MigrateToMap(holder, new_map); |
ReloadPropertyInformation<false>(); |
} else { |
@@ -296,7 +311,7 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
state_ = DATA; |
} |
- WriteDataValue(value); |
+ WriteDataValue(value, true); |
#if VERIFY_HEAP |
if (FLAG_verify_heap) { |
@@ -360,8 +375,8 @@ void LookupIterator::PrepareTransitionToDataProperty( |
return; |
} |
- Handle<Map> transition = |
- Map::TransitionToDataProperty(map, name_, value, attributes, store_mode); |
+ Handle<Map> transition = Map::TransitionToDataProperty( |
+ map, name_, value, attributes, kDefaultFieldConstness, store_mode); |
state_ = TRANSITION; |
transition_ = transition; |
@@ -603,6 +618,39 @@ Handle<Object> LookupIterator::FetchValue() const { |
return handle(result, isolate_); |
} |
+bool LookupIterator::IsConstFieldValueEqualTo(Object* value) const { |
+ DCHECK(!IsElement()); |
+ DCHECK(holder_->HasFastProperties()); |
+ DCHECK_EQ(kField, property_details_.location()); |
+ DCHECK_EQ(kConst, property_details_.constness()); |
+ Handle<JSObject> holder = GetHolder<JSObject>(); |
+ FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); |
+ if (property_details_.representation().IsDouble()) { |
+ if (!value->IsNumber()) return false; |
+ uint64_t bits; |
+ if (holder->IsUnboxedDoubleField(field_index)) { |
+ bits = holder->RawFastDoublePropertyAsBitsAt(field_index); |
+ } else { |
+ Object* current_value = holder->RawFastPropertyAt(field_index); |
+ DCHECK(current_value->IsMutableHeapNumber()); |
+ bits = HeapNumber::cast(current_value)->value_as_bits(); |
+ } |
+ // Use bit representation of double to to check for hole double, since |
+ // manipulating the signaling NaN used for the hole in C++, e.g. with |
+ // bit_cast or value(), will change its value on ia32 (the x87 stack is |
+ // used to return values and stores to the stack silently clear the |
+ // signalling bit). |
+ if (bits == kHoleNanInt64) { |
+ // Uninitialized double field. |
+ return true; |
+ } |
+ return bit_cast<double>(bits) == value->Number(); |
+ } else { |
+ Object* current_value = holder->RawFastPropertyAt(field_index); |
+ return current_value->IsUninitialized(isolate()) || current_value == value; |
+ } |
+} |
+ |
int LookupIterator::GetFieldDescriptorIndex() const { |
DCHECK(has_property_); |
DCHECK(holder_->HasFastProperties()); |
@@ -625,6 +673,7 @@ int LookupIterator::GetConstantIndex() const { |
DCHECK(holder_->HasFastProperties()); |
DCHECK_EQ(kDescriptor, property_details_.location()); |
DCHECK_EQ(kData, property_details_.kind()); |
+ DCHECK(!FLAG_track_constant_fields); |
DCHECK(!IsElement()); |
return descriptor_number(); |
} |
@@ -673,8 +722,8 @@ Handle<Object> LookupIterator::GetDataValue() const { |
return value; |
} |
- |
-void LookupIterator::WriteDataValue(Handle<Object> value) { |
+void LookupIterator::WriteDataValue(Handle<Object> value, |
+ bool initializing_store) { |
DCHECK_EQ(DATA, state_); |
Handle<JSReceiver> holder = GetHolder<JSReceiver>(); |
if (IsElement()) { |
@@ -683,6 +732,11 @@ void LookupIterator::WriteDataValue(Handle<Object> value) { |
accessor->Set(object, number_, *value); |
} else if (holder->HasFastProperties()) { |
if (property_details_.location() == kField) { |
+ // Check that in case of kConst field the existing value is equal to |
+ // |value|. |
+ DCHECK_IMPLIES( |
+ !initializing_store && property_details_.constness() == kConst, |
+ IsConstFieldValueEqualTo(*value)); |
JSObject::cast(*holder)->WriteToField(descriptor_number(), |
property_details_, *value); |
} else { |