Chromium Code Reviews| Index: src/lookup.cc |
| diff --git a/src/lookup.cc b/src/lookup.cc |
| index c3cf013c68f60cf102c7063035353a0f98d92db2..da6fca0bf9e77d27063aa4a02da98bcfdad19eb8 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 && !representation().IsNone()) { |
| + 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); |
|
Toon Verwaest
2017/02/09 16:06:09
Enum? Is this fast enough? I think WriteDataValue
Igor Sheludko
2017/02/09 17:08:13
See comment in Object::SetDataProperty().
|
| #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,12 @@ 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|. |
| + if (DEBUG_BOOL && !initializing_store && |
| + property_details_.constness() == kConst) { |
| + DCHECK(IsConstFieldValueEqualTo(*value)); |
| + } |
| JSObject::cast(*holder)->WriteToField(descriptor_number(), |
| property_details_, *value); |
| } else { |