| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_LOOKUP_INL_H_ |
| #define V8_LOOKUP_INL_H_ |
| |
| #include "src/lookup.h" |
| |
| #include "src/elements.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| |
| JSReceiver* LookupIterator::NextHolder(Map* map) { |
| DisallowHeapAllocation no_gc; |
| if (!map->prototype()->IsJSReceiver()) return NULL; |
| |
| JSReceiver* next = JSReceiver::cast(map->prototype()); |
| DCHECK(!next->map()->IsGlobalObjectMap() || |
| next->map()->is_hidden_prototype()); |
| |
| if (!check_prototype_chain() && |
| !(check_hidden() && next->map()->is_hidden_prototype()) && |
| // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even |
| // when not checking other hidden prototypes. |
| !map->IsJSGlobalProxyMap()) { |
| return NULL; |
| } |
| |
| return next; |
| } |
| |
| |
| LookupIterator::State LookupIterator::LookupInHolder(Map* const map, |
| JSReceiver* const holder) { |
| STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
| DisallowHeapAllocation no_gc; |
| if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
| return LookupNonMaskingInterceptorInHolder(map, holder); |
| } |
| switch (state_) { |
| case NOT_FOUND: |
| if (map->IsJSProxyMap()) return JSPROXY; |
| if (map->is_access_check_needed() && |
| (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) { |
| return ACCESS_CHECK; |
| } |
| // Fall through. |
| case ACCESS_CHECK: |
| if (exotic_index_state_ != ExoticIndexState::kNotExotic && |
| IsIntegerIndexedExotic(holder)) { |
| return INTEGER_INDEXED_EXOTIC; |
| } |
| if (check_interceptor() && HasInterceptor(map) && |
| !SkipInterceptor(JSObject::cast(holder))) { |
| return INTERCEPTOR; |
| } |
| // Fall through. |
| case INTERCEPTOR: |
| if (IsElement()) { |
| // TODO(verwaest): Optimize. |
| if (holder->IsStringObjectWithCharacterAt(index_)) { |
| PropertyAttributes attributes = |
| static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); |
| property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0, |
| PropertyCellType::kNoCell); |
| } else { |
| JSObject* js_object = JSObject::cast(holder); |
| if (js_object->elements() == isolate()->heap()->empty_fixed_array()) { |
| return NOT_FOUND; |
| } |
| |
| ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| FixedArrayBase* backing_store = js_object->elements(); |
| number_ = |
| accessor->GetEntryForIndex(js_object, backing_store, index_); |
| if (number_ == kMaxUInt32) return NOT_FOUND; |
| property_details_ = accessor->GetDetails(backing_store, number_); |
| } |
| } else if (!map->is_dictionary_map()) { |
| DescriptorArray* descriptors = map->instance_descriptors(); |
| int number = descriptors->SearchWithCache(*name_, map); |
| if (number == DescriptorArray::kNotFound) return NOT_FOUND; |
| number_ = static_cast<uint32_t>(number); |
| property_details_ = descriptors->GetDetails(number_); |
| } else if (map->IsGlobalObjectMap()) { |
| GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
| int number = dict->FindEntry(name_); |
| if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
| number_ = static_cast<uint32_t>(number); |
| DCHECK(dict->ValueAt(number_)->IsPropertyCell()); |
| PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
| if (cell->value()->IsTheHole()) return NOT_FOUND; |
| property_details_ = cell->property_details(); |
| } else { |
| NameDictionary* dict = JSObject::cast(holder)->property_dictionary(); |
| int number = dict->FindEntry(name_); |
| if (number == NameDictionary::kNotFound) return NOT_FOUND; |
| number_ = static_cast<uint32_t>(number); |
| property_details_ = dict->DetailsAt(number_); |
| } |
| has_property_ = true; |
| switch (property_details_.kind()) { |
| case v8::internal::kData: |
| return DATA; |
| case v8::internal::kAccessor: |
| return ACCESSOR; |
| } |
| case ACCESSOR: |
| case DATA: |
| return NOT_FOUND; |
| case INTEGER_INDEXED_EXOTIC: |
| case JSPROXY: |
| case TRANSITION: |
| UNREACHABLE(); |
| } |
| UNREACHABLE(); |
| return state_; |
| } |
| |
| |
| LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder( |
| Map* const map, JSReceiver* const holder) { |
| switch (state_) { |
| case NOT_FOUND: |
| if (check_interceptor() && HasInterceptor(map) && |
| !SkipInterceptor(JSObject::cast(holder))) { |
| return INTERCEPTOR; |
| } |
| // Fall through. |
| default: |
| return NOT_FOUND; |
| } |
| UNREACHABLE(); |
| return state_; |
| } |
| } |
| } // namespace v8::internal |
| |
| #endif // V8_LOOKUP_INL_H_ |