| // 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_OBJECTS_LOOKUP_INL_H_ |
| #define V8_OBJECTS_LOOKUP_INL_H_ |
| |
| #include "src/objects/lookup.h" |
| |
| #include "src/handles/handles-inl.h" |
| #include "src/heap/factory-inl.h" |
| #include "src/objects/api-callbacks.h" |
| #include "src/objects/map-inl.h" |
| #include "src/objects/name-inl.h" |
| #include "src/objects/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
| Handle<Name> name, Configuration configuration) |
| : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver), |
| configuration) {} |
| |
| LookupIterator::LookupIterator(Handle<Object> receiver, Handle<Name> name, |
| Handle<JSReceiver> holder, |
| Configuration configuration) |
| : LookupIterator(holder->GetIsolate(), receiver, name, holder, |
| configuration) {} |
| |
| LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
| Handle<Name> name, Handle<JSReceiver> holder, |
| Configuration configuration) |
| : configuration_(ComputeConfiguration(isolate, configuration, name)), |
| interceptor_state_(InterceptorState::kUninitialized), |
| property_details_(PropertyDetails::Empty()), |
| isolate_(isolate), |
| name_(isolate_->factory()->InternalizeName(name)), |
| receiver_(receiver), |
| initial_holder_(holder), |
| // kMaxUInt32 isn't a valid index. |
| index_(kMaxUInt32), |
| number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) { |
| #ifdef DEBUG |
| uint32_t index; // Assert that the name is not an array index. |
| DCHECK(!name->AsArrayIndex(&index)); |
| #endif // DEBUG |
| Start<false>(); |
| } |
| |
| LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, |
| uint32_t index, Configuration configuration) |
| : LookupIterator(isolate, receiver, index, |
| GetRoot(isolate, receiver, index), configuration) {} |
| |
| LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate, |
| Handle<Object> receiver, |
| Handle<Name> name, |
| Handle<JSReceiver> holder, |
| Configuration configuration) { |
| uint32_t index; |
| if (name->AsArrayIndex(&index)) { |
| LookupIterator it = |
| LookupIterator(isolate, receiver, index, holder, configuration); |
| it.name_ = name; |
| return it; |
| } |
| return LookupIterator(isolate, receiver, name, holder, configuration); |
| } |
| |
| LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate, |
| Handle<Object> receiver, |
| Handle<Name> name, |
| Configuration configuration) { |
| uint32_t index; |
| if (name->AsArrayIndex(&index)) { |
| LookupIterator it = LookupIterator(isolate, receiver, index, configuration); |
| it.name_ = name; |
| return it; |
| } |
| return LookupIterator(isolate, receiver, name, configuration); |
| } |
| |
| Handle<Name> LookupIterator::GetName() { |
| if (name_.is_null()) { |
| DCHECK(IsElement()); |
| name_ = factory()->Uint32ToString(index_); |
| } |
| return name_; |
| } |
| |
| bool LookupIterator::is_dictionary_holder() const { |
| return !holder_->HasFastProperties(isolate_); |
| } |
| |
| Handle<Map> LookupIterator::transition_map() const { |
| DCHECK_EQ(TRANSITION, state_); |
| return Handle<Map>::cast(transition_); |
| } |
| |
| Handle<PropertyCell> LookupIterator::transition_cell() const { |
| DCHECK_EQ(TRANSITION, state_); |
| return Handle<PropertyCell>::cast(transition_); |
| } |
| |
| template <class T> |
| Handle<T> LookupIterator::GetHolder() const { |
| DCHECK(IsFound()); |
| return Handle<T>::cast(holder_); |
| } |
| |
| bool LookupIterator::ExtendingNonExtensible(Handle<JSReceiver> receiver) { |
| DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); |
| return !receiver->map(isolate_).is_extensible() && |
| (IsElement() || !name_->IsPrivate(isolate_)); |
| } |
| |
| bool LookupIterator::IsCacheableTransition() { |
| DCHECK_EQ(TRANSITION, state_); |
| return transition_->IsPropertyCell(isolate_) || |
| (transition_map()->is_dictionary_map() && |
| !GetStoreTarget<JSReceiver>()->HasFastProperties(isolate_)) || |
| transition_map()->GetBackPointer(isolate_).IsMap(isolate_); |
| } |
| |
| void LookupIterator::UpdateProtector() { |
| if (IsElement()) return; |
| // This list must be kept in sync with |
| // CodeStubAssembler::CheckForAssociatedProtector! |
| ReadOnlyRoots roots(isolate_); |
| if (*name_ == roots.is_concat_spreadable_symbol() || |
| *name_ == roots.constructor_string() || *name_ == roots.next_string() || |
| *name_ == roots.species_symbol() || *name_ == roots.iterator_symbol() || |
| *name_ == roots.resolve_string() || *name_ == roots.then_string()) { |
| InternalUpdateProtector(); |
| } |
| } |
| |
| int LookupIterator::descriptor_number() const { |
| DCHECK(!IsElement()); |
| DCHECK(has_property_); |
| DCHECK(holder_->HasFastProperties(isolate_)); |
| return number_; |
| } |
| |
| int LookupIterator::dictionary_entry() const { |
| DCHECK(!IsElement()); |
| DCHECK(has_property_); |
| DCHECK(!holder_->HasFastProperties(isolate_)); |
| return number_; |
| } |
| |
| // static |
| LookupIterator::Configuration LookupIterator::ComputeConfiguration( |
| Isolate* isolate, Configuration configuration, Handle<Name> name) { |
| return name->IsPrivate(isolate) ? OWN_SKIP_INTERCEPTOR : configuration; |
| } |
| |
| // static |
| Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate, |
| Handle<Object> receiver, |
| uint32_t index) { |
| if (receiver->IsJSReceiver(isolate)) |
| return Handle<JSReceiver>::cast(receiver); |
| return GetRootForNonJSReceiver(isolate, receiver, index); |
| } |
| |
| template <class T> |
| Handle<T> LookupIterator::GetStoreTarget() const { |
| DCHECK(receiver_->IsJSReceiver(isolate_)); |
| if (receiver_->IsJSGlobalProxy(isolate_)) { |
| HeapObject prototype = |
| JSGlobalProxy::cast(*receiver_).map(isolate_).prototype(isolate_); |
| if (prototype.IsJSGlobalObject(isolate_)) { |
| return handle(JSGlobalObject::cast(prototype), isolate_); |
| } |
| } |
| return Handle<T>::cast(receiver_); |
| } |
| |
| // static |
| template <bool is_element> |
| InterceptorInfo LookupIterator::GetInterceptor(Isolate* isolate, |
| JSObject holder) { |
| return is_element ? holder.GetIndexedInterceptor(isolate) |
| : holder.GetNamedInterceptor(isolate); |
| } |
| |
| inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const { |
| DCHECK_EQ(INTERCEPTOR, state_); |
| JSObject holder = JSObject::cast(*holder_); |
| InterceptorInfo result = IsElement() |
| ? GetInterceptor<true>(isolate_, holder) |
| : GetInterceptor<false>(isolate_, holder); |
| return handle(result, isolate_); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_OBJECTS_LOOKUP_INL_H_ |