blob: 2339606a45a9e3742f4e0a8f43f111b980a7894f [file] [log] [blame]
// 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/internal-index.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, kInvalidIndex, receiver,
configuration) {}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name,
Handle<Object> lookup_start_object,
Configuration configuration)
: LookupIterator(isolate, receiver, name, kInvalidIndex,
lookup_start_object, configuration) {}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
size_t index, Configuration configuration)
: LookupIterator(isolate, receiver, Handle<Name>(), index, receiver,
configuration) {
DCHECK_NE(index, kInvalidIndex);
}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
size_t index, Handle<Object> lookup_start_object,
Configuration configuration)
: LookupIterator(isolate, receiver, Handle<Name>(), index,
lookup_start_object, configuration) {
DCHECK_NE(index, kInvalidIndex);
}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key, Configuration configuration)
: LookupIterator(isolate, receiver, key.name(), key.index(), receiver,
configuration) {}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key,
Handle<Object> lookup_start_object,
Configuration configuration)
: LookupIterator(isolate, receiver, key.name(), key.index(),
lookup_start_object, configuration) {}
// This private constructor is the central bottleneck that all the other
// constructors use.
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, size_t index,
Handle<Object> lookup_start_object,
Configuration configuration)
: configuration_(ComputeConfiguration(isolate, configuration, name)),
isolate_(isolate),
name_(name),
receiver_(receiver),
lookup_start_object_(lookup_start_object),
index_(index) {
if (IsElement()) {
// If we're not looking at a TypedArray, we will need the key represented
// as an internalized string.
if (index_ > JSArray::kMaxArrayIndex &&
!lookup_start_object->IsJSTypedArray()) {
if (name_.is_null()) {
name_ = isolate->factory()->SizeToString(index_);
}
name_ = isolate->factory()->InternalizeName(name_);
} else if (!name_.is_null() && !name_->IsInternalizedString()) {
// Maintain the invariant that if name_ is present, it is internalized.
name_ = Handle<Name>();
}
Start<true>();
} else {
name_ = isolate->factory()->InternalizeName(name_);
#ifdef DEBUG
// Assert that the name is not an index.
// If we're not looking at the prototype chain and the lookup start object
// is not a typed array, then this means "array index", otherwise we need to
// ensure the full generality so that typed arrays are handled correctly.
if (!check_prototype_chain() && !lookup_start_object->IsJSTypedArray()) {
uint32_t index;
DCHECK(!name_->AsArrayIndex(&index));
} else {
size_t index;
DCHECK(!name_->AsIntegerIndex(&index));
}
#endif // DEBUG
Start<false>();
}
}
LookupIterator::Key::Key(Isolate* isolate, double index) {
DCHECK_EQ(index, static_cast<uint64_t>(index));
#if V8_TARGET_ARCH_32_BIT
if (index <= JSArray::kMaxArrayIndex) {
index_ = static_cast<size_t>(index);
} else {
index_ = LookupIterator::kInvalidIndex;
name_ = isolate->factory()->InternalizeString(
isolate->factory()->HeapNumberToString(
isolate->factory()->NewHeapNumber(index), index));
}
#else
index_ = static_cast<size_t>(index);
#endif
}
LookupIterator::Key::Key(Isolate* isolate, Handle<Name> name) {
if (name->AsIntegerIndex(&index_)) {
name_ = name;
} else {
index_ = LookupIterator::kInvalidIndex;
name_ = isolate->factory()->InternalizeName(name);
}
}
LookupIterator::Key::Key(Isolate* isolate, Handle<Object> valid_key) {
DCHECK(valid_key->IsName() || valid_key->IsNumber());
if (valid_key->ToIntegerIndex(&index_)) return;
if (valid_key->IsNumber()) {
// Negative or out of range -> treat as named property.
valid_key = isolate->factory()->NumberToString(valid_key);
}
DCHECK(valid_key->IsName());
name_ = Handle<Name>::cast(valid_key);
if (!name_->AsIntegerIndex(&index_)) {
index_ = LookupIterator::kInvalidIndex;
name_ = isolate->factory()->InternalizeName(name_);
}
}
Handle<Name> LookupIterator::Key::GetName(Isolate* isolate) {
if (name_.is_null()) {
DCHECK(is_element());
name_ = isolate->factory()->SizeToString(index_);
}
return name_;
}
Handle<Name> LookupIterator::name() const {
DCHECK(!IsElement(*holder_));
return name_;
}
Handle<Name> LookupIterator::GetName() {
if (name_.is_null()) {
DCHECK(IsElement());
name_ = factory()->SizeToString(index_);
}
return name_;
}
bool LookupIterator::IsElement(JSReceiver object) const {
return index_ <= JSArray::kMaxArrayIndex ||
(index_ != kInvalidIndex && object.map().has_typed_array_elements());
}
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_);
}
// static
void LookupIterator::UpdateProtector(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name) {
// 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(isolate, receiver, name);
}
}
void LookupIterator::UpdateProtector() {
if (IsElement()) return;
UpdateProtector(isolate_, receiver_, name_);
}
InternalIndex LookupIterator::descriptor_number() const {
DCHECK(!IsElement(*holder_));
DCHECK(has_property_);
DCHECK(holder_->HasFastProperties(isolate_));
return number_;
}
InternalIndex LookupIterator::dictionary_entry() const {
DCHECK(!IsElement(*holder_));
DCHECK(has_property_);
DCHECK(!holder_->HasFastProperties(isolate_));
return number_;
}
// static
LookupIterator::Configuration LookupIterator::ComputeConfiguration(
Isolate* isolate, Configuration configuration, Handle<Name> name) {
return (!name.is_null() && name->IsPrivate(isolate)) ? OWN_SKIP_INTERCEPTOR
: configuration;
}
// static
Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
Handle<Object> lookup_start_object,
size_t index) {
if (lookup_start_object->IsJSReceiver(isolate)) {
return Handle<JSReceiver>::cast(lookup_start_object);
}
return GetRootForNonJSReceiver(isolate, lookup_start_object, 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_);
}
template <bool is_element>
InterceptorInfo LookupIterator::GetInterceptor(JSObject holder) const {
if (is_element && index_ <= JSArray::kMaxArrayIndex) {
return holder.GetIndexedInterceptor(isolate_);
} else {
return holder.GetNamedInterceptor(isolate_);
}
}
inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const {
DCHECK_EQ(INTERCEPTOR, state_);
JSObject holder = JSObject::cast(*holder_);
InterceptorInfo result = IsElement(holder) ? GetInterceptor<true>(holder)
: GetInterceptor<false>(holder);
return handle(result, isolate_);
}
} // namespace internal
} // namespace v8
#endif // V8_OBJECTS_LOOKUP_INL_H_