OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/lookup.h" | 5 #include "src/lookup.h" |
6 | 6 |
7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
8 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
9 #include "src/elements.h" | 9 #include "src/elements.h" |
10 #include "src/field-type.h" | 10 #include "src/field-type.h" |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 Handle<PropertyCell> cell( | 230 Handle<PropertyCell> cell( |
231 PropertyCell::cast(dictionary->ValueAt(dictionary_entry()))); | 231 PropertyCell::cast(dictionary->ValueAt(dictionary_entry()))); |
232 DCHECK(!cell->IsTheHole(isolate_)); | 232 DCHECK(!cell->IsTheHole(isolate_)); |
233 property_details_ = cell->property_details(); | 233 property_details_ = cell->property_details(); |
234 PropertyCell::PrepareForValue(dictionary, dictionary_entry(), value, | 234 PropertyCell::PrepareForValue(dictionary, dictionary_entry(), value, |
235 property_details_); | 235 property_details_); |
236 return; | 236 return; |
237 } | 237 } |
238 if (!holder->HasFastProperties()) return; | 238 if (!holder->HasFastProperties()) return; |
239 | 239 |
| 240 PropertyConstness new_constness = kConst; |
| 241 if (FLAG_track_constant_fields) { |
| 242 if (constness() == kConst) { |
| 243 DCHECK_EQ(kData, property_details_.kind()); |
| 244 // Check that current value matches new value otherwise we should make |
| 245 // the property mutable. |
| 246 if (!IsConstFieldValueEqualTo(*value)) new_constness = kMutable; |
| 247 } |
| 248 } else { |
| 249 new_constness = kMutable; |
| 250 } |
| 251 |
240 Handle<Map> old_map(holder->map(), isolate_); | 252 Handle<Map> old_map(holder->map(), isolate_); |
241 Handle<Map> new_map = | 253 Handle<Map> new_map = Map::PrepareForDataProperty( |
242 Map::PrepareForDataProperty(old_map, descriptor_number(), value); | 254 old_map, descriptor_number(), new_constness, value); |
243 | 255 |
244 if (old_map.is_identical_to(new_map)) { | 256 if (old_map.is_identical_to(new_map)) { |
245 // Update the property details if the representation was None. | 257 // Update the property details if the representation was None. |
246 if (representation().IsNone()) { | 258 if (representation().IsNone()) { |
247 property_details_ = | 259 property_details_ = |
248 new_map->instance_descriptors()->GetDetails(descriptor_number()); | 260 new_map->instance_descriptors()->GetDetails(descriptor_number()); |
249 } | 261 } |
250 return; | 262 return; |
251 } | 263 } |
252 | 264 |
(...skipping 11 matching lines...) Expand all Loading... |
264 DCHECK(!holder->HasFixedTypedArrayElements()); | 276 DCHECK(!holder->HasFixedTypedArrayElements()); |
265 DCHECK(attributes != NONE || !holder->HasFastElements()); | 277 DCHECK(attributes != NONE || !holder->HasFastElements()); |
266 Handle<FixedArrayBase> elements(holder->elements()); | 278 Handle<FixedArrayBase> elements(holder->elements()); |
267 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, | 279 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, |
268 attributes); | 280 attributes); |
269 ReloadPropertyInformation<true>(); | 281 ReloadPropertyInformation<true>(); |
270 } else if (holder->HasFastProperties()) { | 282 } else if (holder->HasFastProperties()) { |
271 Handle<Map> old_map(holder->map(), isolate_); | 283 Handle<Map> old_map(holder->map(), isolate_); |
272 Handle<Map> new_map = Map::ReconfigureExistingProperty( | 284 Handle<Map> new_map = Map::ReconfigureExistingProperty( |
273 old_map, descriptor_number(), i::kData, attributes); | 285 old_map, descriptor_number(), i::kData, attributes); |
274 new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value); | 286 // Force mutable to avoid changing constant value by reconfiguring |
| 287 // kData -> kAccessor -> kData. |
| 288 new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), |
| 289 kMutable, value); |
275 JSObject::MigrateToMap(holder, new_map); | 290 JSObject::MigrateToMap(holder, new_map); |
276 ReloadPropertyInformation<false>(); | 291 ReloadPropertyInformation<false>(); |
277 } else { | 292 } else { |
278 PropertyDetails details(kData, attributes, 0, PropertyCellType::kMutable); | 293 PropertyDetails details(kData, attributes, 0, PropertyCellType::kMutable); |
279 if (holder->IsJSGlobalObject()) { | 294 if (holder->IsJSGlobalObject()) { |
280 Handle<GlobalDictionary> dictionary(holder->global_dictionary()); | 295 Handle<GlobalDictionary> dictionary(holder->global_dictionary()); |
281 | 296 |
282 Handle<PropertyCell> cell = PropertyCell::PrepareForValue( | 297 Handle<PropertyCell> cell = PropertyCell::PrepareForValue( |
283 dictionary, dictionary_entry(), value, details); | 298 dictionary, dictionary_entry(), value, details); |
284 cell->set_value(*value); | 299 cell->set_value(*value); |
285 property_details_ = cell->property_details(); | 300 property_details_ = cell->property_details(); |
286 } else { | 301 } else { |
287 Handle<NameDictionary> dictionary(holder->property_dictionary()); | 302 Handle<NameDictionary> dictionary(holder->property_dictionary()); |
288 PropertyDetails original_details = | 303 PropertyDetails original_details = |
289 dictionary->DetailsAt(dictionary_entry()); | 304 dictionary->DetailsAt(dictionary_entry()); |
290 int enumeration_index = original_details.dictionary_index(); | 305 int enumeration_index = original_details.dictionary_index(); |
291 DCHECK(enumeration_index > 0); | 306 DCHECK(enumeration_index > 0); |
292 details = details.set_index(enumeration_index); | 307 details = details.set_index(enumeration_index); |
293 dictionary->SetEntry(dictionary_entry(), name(), value, details); | 308 dictionary->SetEntry(dictionary_entry(), name(), value, details); |
294 property_details_ = details; | 309 property_details_ = details; |
295 } | 310 } |
296 state_ = DATA; | 311 state_ = DATA; |
297 } | 312 } |
298 | 313 |
299 WriteDataValue(value); | 314 WriteDataValue(value, true); |
300 | 315 |
301 #if VERIFY_HEAP | 316 #if VERIFY_HEAP |
302 if (FLAG_verify_heap) { | 317 if (FLAG_verify_heap) { |
303 holder->JSObjectVerify(); | 318 holder->JSObjectVerify(); |
304 } | 319 } |
305 #endif | 320 #endif |
306 } | 321 } |
307 | 322 |
308 // Can only be called when the receiver is a JSObject. JSProxy has to be handled | 323 // Can only be called when the receiver is a JSObject. JSProxy has to be handled |
309 // via a trap. Adding properties to primitive values is not observable. | 324 // via a trap. Adding properties to primitive values is not observable. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 has_property_ = true; | 368 has_property_ = true; |
354 } else { | 369 } else { |
355 // Don't set enumeration index (it will be set during value store). | 370 // Don't set enumeration index (it will be set during value store). |
356 property_details_ = | 371 property_details_ = |
357 PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell); | 372 PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell); |
358 transition_ = map; | 373 transition_ = map; |
359 } | 374 } |
360 return; | 375 return; |
361 } | 376 } |
362 | 377 |
363 Handle<Map> transition = | 378 Handle<Map> transition = Map::TransitionToDataProperty( |
364 Map::TransitionToDataProperty(map, name_, value, attributes, store_mode); | 379 map, name_, value, attributes, kDefaultFieldConstness, store_mode); |
365 state_ = TRANSITION; | 380 state_ = TRANSITION; |
366 transition_ = transition; | 381 transition_ = transition; |
367 | 382 |
368 if (transition->is_dictionary_map()) { | 383 if (transition->is_dictionary_map()) { |
369 // Don't set enumeration index (it will be set during value store). | 384 // Don't set enumeration index (it will be set during value store). |
370 property_details_ = | 385 property_details_ = |
371 PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell); | 386 PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell); |
372 } else { | 387 } else { |
373 property_details_ = transition->GetLastDescriptorDetails(); | 388 property_details_ = transition->GetLastDescriptorDetails(); |
374 has_property_ = true; | 389 has_property_ = true; |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 Handle<JSObject> holder = GetHolder<JSObject>(); | 611 Handle<JSObject> holder = GetHolder<JSObject>(); |
597 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); | 612 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); |
598 return JSObject::FastPropertyAt(holder, property_details_.representation(), | 613 return JSObject::FastPropertyAt(holder, property_details_.representation(), |
599 field_index); | 614 field_index); |
600 } else { | 615 } else { |
601 result = holder_->map()->instance_descriptors()->GetValue(number_); | 616 result = holder_->map()->instance_descriptors()->GetValue(number_); |
602 } | 617 } |
603 return handle(result, isolate_); | 618 return handle(result, isolate_); |
604 } | 619 } |
605 | 620 |
| 621 bool LookupIterator::IsConstFieldValueEqualTo(Object* value) const { |
| 622 DCHECK(!IsElement()); |
| 623 DCHECK(holder_->HasFastProperties()); |
| 624 DCHECK_EQ(kField, property_details_.location()); |
| 625 DCHECK_EQ(kConst, property_details_.constness()); |
| 626 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 627 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); |
| 628 if (property_details_.representation().IsDouble()) { |
| 629 if (!value->IsNumber()) return false; |
| 630 uint64_t bits; |
| 631 if (holder->IsUnboxedDoubleField(field_index)) { |
| 632 bits = holder->RawFastDoublePropertyAsBitsAt(field_index); |
| 633 } else { |
| 634 Object* current_value = holder->RawFastPropertyAt(field_index); |
| 635 DCHECK(current_value->IsMutableHeapNumber()); |
| 636 bits = HeapNumber::cast(current_value)->value_as_bits(); |
| 637 } |
| 638 // Use bit representation of double to to check for hole double, since |
| 639 // manipulating the signaling NaN used for the hole in C++, e.g. with |
| 640 // bit_cast or value(), will change its value on ia32 (the x87 stack is |
| 641 // used to return values and stores to the stack silently clear the |
| 642 // signalling bit). |
| 643 if (bits == kHoleNanInt64) { |
| 644 // Uninitialized double field. |
| 645 return true; |
| 646 } |
| 647 return bit_cast<double>(bits) == value->Number(); |
| 648 } else { |
| 649 Object* current_value = holder->RawFastPropertyAt(field_index); |
| 650 return current_value->IsUninitialized(isolate()) || current_value == value; |
| 651 } |
| 652 } |
| 653 |
606 int LookupIterator::GetFieldDescriptorIndex() const { | 654 int LookupIterator::GetFieldDescriptorIndex() const { |
607 DCHECK(has_property_); | 655 DCHECK(has_property_); |
608 DCHECK(holder_->HasFastProperties()); | 656 DCHECK(holder_->HasFastProperties()); |
609 DCHECK_EQ(kField, property_details_.location()); | 657 DCHECK_EQ(kField, property_details_.location()); |
610 DCHECK_EQ(kData, property_details_.kind()); | 658 DCHECK_EQ(kData, property_details_.kind()); |
611 return descriptor_number(); | 659 return descriptor_number(); |
612 } | 660 } |
613 | 661 |
614 int LookupIterator::GetAccessorIndex() const { | 662 int LookupIterator::GetAccessorIndex() const { |
615 DCHECK(has_property_); | 663 DCHECK(has_property_); |
616 DCHECK(holder_->HasFastProperties()); | 664 DCHECK(holder_->HasFastProperties()); |
617 DCHECK_EQ(kDescriptor, property_details_.location()); | 665 DCHECK_EQ(kDescriptor, property_details_.location()); |
618 DCHECK_EQ(kAccessor, property_details_.kind()); | 666 DCHECK_EQ(kAccessor, property_details_.kind()); |
619 return descriptor_number(); | 667 return descriptor_number(); |
620 } | 668 } |
621 | 669 |
622 | 670 |
623 int LookupIterator::GetConstantIndex() const { | 671 int LookupIterator::GetConstantIndex() const { |
624 DCHECK(has_property_); | 672 DCHECK(has_property_); |
625 DCHECK(holder_->HasFastProperties()); | 673 DCHECK(holder_->HasFastProperties()); |
626 DCHECK_EQ(kDescriptor, property_details_.location()); | 674 DCHECK_EQ(kDescriptor, property_details_.location()); |
627 DCHECK_EQ(kData, property_details_.kind()); | 675 DCHECK_EQ(kData, property_details_.kind()); |
| 676 DCHECK(!FLAG_track_constant_fields); |
628 DCHECK(!IsElement()); | 677 DCHECK(!IsElement()); |
629 return descriptor_number(); | 678 return descriptor_number(); |
630 } | 679 } |
631 | 680 |
632 | 681 |
633 FieldIndex LookupIterator::GetFieldIndex() const { | 682 FieldIndex LookupIterator::GetFieldIndex() const { |
634 DCHECK(has_property_); | 683 DCHECK(has_property_); |
635 DCHECK(holder_->HasFastProperties()); | 684 DCHECK(holder_->HasFastProperties()); |
636 DCHECK_EQ(kField, property_details_.location()); | 685 DCHECK_EQ(kField, property_details_.location()); |
637 DCHECK(!IsElement()); | 686 DCHECK(!IsElement()); |
(...skipping 28 matching lines...) Expand all Loading... |
666 return FetchValue(); | 715 return FetchValue(); |
667 } | 716 } |
668 | 717 |
669 | 718 |
670 Handle<Object> LookupIterator::GetDataValue() const { | 719 Handle<Object> LookupIterator::GetDataValue() const { |
671 DCHECK_EQ(DATA, state_); | 720 DCHECK_EQ(DATA, state_); |
672 Handle<Object> value = FetchValue(); | 721 Handle<Object> value = FetchValue(); |
673 return value; | 722 return value; |
674 } | 723 } |
675 | 724 |
676 | 725 void LookupIterator::WriteDataValue(Handle<Object> value, |
677 void LookupIterator::WriteDataValue(Handle<Object> value) { | 726 bool initializing_store) { |
678 DCHECK_EQ(DATA, state_); | 727 DCHECK_EQ(DATA, state_); |
679 Handle<JSReceiver> holder = GetHolder<JSReceiver>(); | 728 Handle<JSReceiver> holder = GetHolder<JSReceiver>(); |
680 if (IsElement()) { | 729 if (IsElement()) { |
681 Handle<JSObject> object = Handle<JSObject>::cast(holder); | 730 Handle<JSObject> object = Handle<JSObject>::cast(holder); |
682 ElementsAccessor* accessor = object->GetElementsAccessor(); | 731 ElementsAccessor* accessor = object->GetElementsAccessor(); |
683 accessor->Set(object, number_, *value); | 732 accessor->Set(object, number_, *value); |
684 } else if (holder->HasFastProperties()) { | 733 } else if (holder->HasFastProperties()) { |
685 if (property_details_.location() == kField) { | 734 if (property_details_.location() == kField) { |
| 735 // Check that in case of kConst field the existing value is equal to |
| 736 // |value|. |
| 737 DCHECK_IMPLIES( |
| 738 !initializing_store && property_details_.constness() == kConst, |
| 739 IsConstFieldValueEqualTo(*value)); |
686 JSObject::cast(*holder)->WriteToField(descriptor_number(), | 740 JSObject::cast(*holder)->WriteToField(descriptor_number(), |
687 property_details_, *value); | 741 property_details_, *value); |
688 } else { | 742 } else { |
689 DCHECK_EQ(kDescriptor, property_details_.location()); | 743 DCHECK_EQ(kDescriptor, property_details_.location()); |
690 DCHECK_EQ(kConst, property_details_.constness()); | 744 DCHECK_EQ(kConst, property_details_.constness()); |
691 } | 745 } |
692 } else if (holder->IsJSGlobalObject()) { | 746 } else if (holder->IsJSGlobalObject()) { |
693 GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary(); | 747 GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary(); |
694 Object* cell = dictionary->ValueAt(dictionary_entry()); | 748 Object* cell = dictionary->ValueAt(dictionary_entry()); |
695 DCHECK(cell->IsPropertyCell()); | 749 DCHECK(cell->IsPropertyCell()); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 | 927 |
874 // We have found a cached property! Modify the iterator accordingly. | 928 // We have found a cached property! Modify the iterator accordingly. |
875 name_ = maybe_name.ToHandleChecked(); | 929 name_ = maybe_name.ToHandleChecked(); |
876 Restart(); | 930 Restart(); |
877 CHECK_EQ(state(), LookupIterator::DATA); | 931 CHECK_EQ(state(), LookupIterator::DATA); |
878 return true; | 932 return true; |
879 } | 933 } |
880 | 934 |
881 } // namespace internal | 935 } // namespace internal |
882 } // namespace v8 | 936 } // namespace v8 |
OLD | NEW |