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