// 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(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->GetIndexForKey(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(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(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(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_