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 |