| 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/isolate-inl.h" | 10 #include "src/isolate-inl.h" |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { | 391 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
| 392 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); | 392 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
| 393 return InternalHolderIsReceiverOrHiddenPrototype(); | 393 return InternalHolderIsReceiverOrHiddenPrototype(); |
| 394 } | 394 } |
| 395 | 395 |
| 396 bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const { | 396 bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const { |
| 397 // Optimization that only works if configuration_ is not mutable. | 397 // Optimization that only works if configuration_ is not mutable. |
| 398 if (!check_prototype_chain()) return true; | 398 if (!check_prototype_chain()) return true; |
| 399 DisallowHeapAllocation no_gc; | 399 DisallowHeapAllocation no_gc; |
| 400 if (!receiver_->IsJSReceiver()) return false; | 400 if (!receiver_->IsJSReceiver()) return false; |
| 401 Object* current = *receiver_; | 401 JSReceiver* current = JSReceiver::cast(*receiver_); |
| 402 JSReceiver* holder = *holder_; | 402 JSReceiver* holder = *holder_; |
| 403 if (current == holder) return true; |
| 404 if (!holder->map()->is_hidden_prototype()) return false; |
| 403 // JSProxy do not occur as hidden prototypes. | 405 // JSProxy do not occur as hidden prototypes. |
| 404 if (current->IsJSProxy()) { | 406 if (current->IsJSProxy()) return false; |
| 405 return JSReceiver::cast(current) == holder; | 407 PrototypeIterator iter(isolate(), current); |
| 408 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
| 409 if (iter.GetCurrent<JSReceiver>() == holder) return true; |
| 410 iter.Advance(); |
| 406 } | 411 } |
| 407 PrototypeIterator iter(isolate(), current, | |
| 408 PrototypeIterator::START_AT_RECEIVER); | |
| 409 do { | |
| 410 if (iter.GetCurrent<JSReceiver>() == holder) return true; | |
| 411 DCHECK(!current->IsJSProxy()); | |
| 412 iter.Advance(); | |
| 413 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); | |
| 414 return false; | 412 return false; |
| 415 } | 413 } |
| 416 | 414 |
| 417 | 415 |
| 418 Handle<Object> LookupIterator::FetchValue() const { | 416 Handle<Object> LookupIterator::FetchValue() const { |
| 419 Object* result = NULL; | 417 Object* result = NULL; |
| 420 if (IsElement()) { | 418 if (IsElement()) { |
| 421 Handle<JSObject> holder = GetHolder<JSObject>(); | 419 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 422 // TODO(verwaest): Optimize. | |
| 423 if (holder->IsStringObjectWithCharacterAt(index_)) { | |
| 424 Handle<JSValue> js_value = Handle<JSValue>::cast(holder); | |
| 425 Handle<String> string(String::cast(js_value->value())); | |
| 426 return factory()->LookupSingleCharacterStringFromCode( | |
| 427 String::Flatten(string)->Get(index_)); | |
| 428 } | |
| 429 | |
| 430 ElementsAccessor* accessor = holder->GetElementsAccessor(); | 420 ElementsAccessor* accessor = holder->GetElementsAccessor(); |
| 431 return accessor->Get(handle(holder->elements()), number_); | 421 return accessor->Get(holder, number_); |
| 432 } else if (holder_map_->IsJSGlobalObjectMap()) { | 422 } else if (holder_map_->IsJSGlobalObjectMap()) { |
| 433 Handle<JSObject> holder = GetHolder<JSObject>(); | 423 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 434 result = holder->global_dictionary()->ValueAt(number_); | 424 result = holder->global_dictionary()->ValueAt(number_); |
| 435 DCHECK(result->IsPropertyCell()); | 425 DCHECK(result->IsPropertyCell()); |
| 436 result = PropertyCell::cast(result)->value(); | 426 result = PropertyCell::cast(result)->value(); |
| 437 } else if (holder_map_->is_dictionary_map()) { | 427 } else if (holder_map_->is_dictionary_map()) { |
| 438 result = holder_->property_dictionary()->ValueAt(number_); | 428 result = holder_->property_dictionary()->ValueAt(number_); |
| 439 } else if (property_details_.type() == v8::internal::DATA) { | 429 } else if (property_details_.type() == v8::internal::DATA) { |
| 440 Handle<JSObject> holder = GetHolder<JSObject>(); | 430 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 441 FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_); | 431 FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 return value; | 498 return value; |
| 509 } | 499 } |
| 510 | 500 |
| 511 | 501 |
| 512 void LookupIterator::WriteDataValue(Handle<Object> value) { | 502 void LookupIterator::WriteDataValue(Handle<Object> value) { |
| 513 DCHECK_EQ(DATA, state_); | 503 DCHECK_EQ(DATA, state_); |
| 514 Handle<JSReceiver> holder = GetHolder<JSReceiver>(); | 504 Handle<JSReceiver> holder = GetHolder<JSReceiver>(); |
| 515 if (IsElement()) { | 505 if (IsElement()) { |
| 516 Handle<JSObject> object = Handle<JSObject>::cast(holder); | 506 Handle<JSObject> object = Handle<JSObject>::cast(holder); |
| 517 ElementsAccessor* accessor = object->GetElementsAccessor(); | 507 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 518 accessor->Set(object->elements(), number_, *value); | 508 accessor->Set(object, number_, *value); |
| 519 } else if (holder->IsJSGlobalObject()) { | 509 } else if (holder->IsJSGlobalObject()) { |
| 520 Handle<GlobalDictionary> property_dictionary = | 510 Handle<GlobalDictionary> property_dictionary = |
| 521 handle(JSObject::cast(*holder)->global_dictionary()); | 511 handle(JSObject::cast(*holder)->global_dictionary()); |
| 522 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, | 512 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, |
| 523 property_details_); | 513 property_details_); |
| 524 } else if (holder_map_->is_dictionary_map()) { | 514 } else if (holder_map_->is_dictionary_map()) { |
| 525 NameDictionary* property_dictionary = holder->property_dictionary(); | 515 NameDictionary* property_dictionary = holder->property_dictionary(); |
| 526 property_dictionary->ValueAtPut(dictionary_entry(), *value); | 516 property_dictionary->ValueAtPut(dictionary_entry(), *value); |
| 527 } else if (property_details_.type() == v8::internal::DATA) { | 517 } else if (property_details_.type() == v8::internal::DATA) { |
| 528 JSObject::cast(*holder)->WriteToField(descriptor_number(), *value); | 518 JSObject::cast(*holder)->WriteToField(descriptor_number(), *value); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 if (map->IsJSProxyMap()) { | 608 if (map->IsJSProxyMap()) { |
| 619 // Do not leak private property names. | 609 // Do not leak private property names. |
| 620 if (IsElement() || !name_->IsPrivate()) return JSPROXY; | 610 if (IsElement() || !name_->IsPrivate()) return JSPROXY; |
| 621 } | 611 } |
| 622 if (map->is_access_check_needed() && | 612 if (map->is_access_check_needed() && |
| 623 (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) { | 613 (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) { |
| 624 return ACCESS_CHECK; | 614 return ACCESS_CHECK; |
| 625 } | 615 } |
| 626 // Fall through. | 616 // Fall through. |
| 627 case ACCESS_CHECK: | 617 case ACCESS_CHECK: |
| 628 if (exotic_index_state_ != ExoticIndexState::kNotExotic && | |
| 629 holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) { | |
| 630 return INTEGER_INDEXED_EXOTIC; | |
| 631 } | |
| 632 if (check_interceptor() && HasInterceptor(map) && | 618 if (check_interceptor() && HasInterceptor(map) && |
| 633 !SkipInterceptor(JSObject::cast(holder))) { | 619 !SkipInterceptor(JSObject::cast(holder))) { |
| 634 // Do not leak private property names. | 620 // Do not leak private property names. |
| 635 if (!name_.is_null() && name_->IsPrivate()) return NOT_FOUND; | 621 if (!name_.is_null() && name_->IsPrivate()) return NOT_FOUND; |
| 636 return INTERCEPTOR; | 622 return INTERCEPTOR; |
| 637 } | 623 } |
| 638 // Fall through. | 624 // Fall through. |
| 639 case INTERCEPTOR: | 625 case INTERCEPTOR: |
| 640 if (IsElement()) { | 626 if (IsElement()) { |
| 641 // TODO(verwaest): Optimize. | 627 JSObject* js_object = JSObject::cast(holder); |
| 642 if (holder->IsStringObjectWithCharacterAt(index_)) { | 628 ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| 643 PropertyAttributes attributes = | 629 FixedArrayBase* backing_store = js_object->elements(); |
| 644 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); | 630 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
| 645 property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0, | 631 if (number_ == kMaxUInt32) { |
| 646 PropertyCellType::kNoCell); | 632 if (*receiver_ == Object::cast(holder) && holder->IsJSTypedArray()) { |
| 647 } else { | 633 return INTEGER_INDEXED_EXOTIC; |
| 648 JSObject* js_object = JSObject::cast(holder); | |
| 649 if (js_object->elements() == isolate()->heap()->empty_fixed_array()) { | |
| 650 return NOT_FOUND; | |
| 651 } | 634 } |
| 652 | 635 return NOT_FOUND; |
| 653 ElementsAccessor* accessor = js_object->GetElementsAccessor(); | |
| 654 FixedArrayBase* backing_store = js_object->elements(); | |
| 655 number_ = | |
| 656 accessor->GetEntryForIndex(js_object, backing_store, index_); | |
| 657 if (number_ == kMaxUInt32) return NOT_FOUND; | |
| 658 property_details_ = accessor->GetDetails(backing_store, number_); | |
| 659 } | 636 } |
| 637 property_details_ = accessor->GetDetails(js_object, number_); |
| 638 } else if (exotic_index_state_ != ExoticIndexState::kNotExotic && |
| 639 holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) { |
| 640 return INTEGER_INDEXED_EXOTIC; |
| 660 } else if (!map->is_dictionary_map()) { | 641 } else if (!map->is_dictionary_map()) { |
| 661 DescriptorArray* descriptors = map->instance_descriptors(); | 642 DescriptorArray* descriptors = map->instance_descriptors(); |
| 662 int number = descriptors->SearchWithCache(*name_, map); | 643 int number = descriptors->SearchWithCache(*name_, map); |
| 663 if (number == DescriptorArray::kNotFound) return NOT_FOUND; | 644 if (number == DescriptorArray::kNotFound) return NOT_FOUND; |
| 664 number_ = static_cast<uint32_t>(number); | 645 number_ = static_cast<uint32_t>(number); |
| 665 property_details_ = descriptors->GetDetails(number_); | 646 property_details_ = descriptors->GetDetails(number_); |
| 666 } else if (map->IsJSGlobalObjectMap()) { | 647 } else if (map->IsJSGlobalObjectMap()) { |
| 667 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); | 648 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
| 668 int number = dict->FindEntry(name_); | 649 int number = dict->FindEntry(name_); |
| 669 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; | 650 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 // Fall through. | 691 // Fall through. |
| 711 default: | 692 default: |
| 712 return NOT_FOUND; | 693 return NOT_FOUND; |
| 713 } | 694 } |
| 714 UNREACHABLE(); | 695 UNREACHABLE(); |
| 715 return state_; | 696 return state_; |
| 716 } | 697 } |
| 717 | 698 |
| 718 } // namespace internal | 699 } // namespace internal |
| 719 } // namespace v8 | 700 } // namespace v8 |
| OLD | NEW |