| 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 {
|
|
|