2014-06-11 09:59:14 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "src/v8.h"
|
|
|
|
|
|
|
|
#include "src/bootstrapper.h"
|
|
|
|
#include "src/lookup.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
|
|
|
|
void LookupIterator::Next() {
|
|
|
|
has_property_ = false;
|
|
|
|
do {
|
2014-06-11 18:02:38 +00:00
|
|
|
state_ = LookupInHolder();
|
2014-06-11 09:59:14 +00:00
|
|
|
} while (!IsFound() && NextHolder());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-11 18:02:38 +00:00
|
|
|
Handle<JSReceiver> LookupIterator::GetRoot() const {
|
2014-06-11 09:59:14 +00:00
|
|
|
Handle<Object> receiver = GetReceiver();
|
|
|
|
if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
|
2014-07-14 10:54:24 +00:00
|
|
|
Handle<Object> root =
|
|
|
|
handle(receiver->GetRootMap(isolate_)->prototype(), isolate_);
|
|
|
|
CHECK(!root->IsNull());
|
|
|
|
return Handle<JSReceiver>::cast(root);
|
2014-06-11 09:59:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Map> LookupIterator::GetReceiverMap() const {
|
|
|
|
Handle<Object> receiver = GetReceiver();
|
|
|
|
if (receiver->IsNumber()) return isolate_->factory()->heap_number_map();
|
|
|
|
return handle(Handle<HeapObject>::cast(receiver)->map());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool LookupIterator::NextHolder() {
|
|
|
|
if (holder_map_->prototype()->IsNull()) return false;
|
|
|
|
|
|
|
|
Handle<JSReceiver> next(JSReceiver::cast(holder_map_->prototype()));
|
|
|
|
|
|
|
|
if (!check_derived() &&
|
2014-06-12 15:08:33 +00:00
|
|
|
!(check_hidden() &&
|
|
|
|
// TODO(verwaest): Check if this is actually necessary currently. If it
|
|
|
|
// is, this should be handled by setting is_hidden_prototype on the
|
|
|
|
// global object behind the proxy.
|
|
|
|
(holder_map_->IsJSGlobalProxyMap() ||
|
|
|
|
next->map()->is_hidden_prototype()))) {
|
2014-06-11 09:59:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
holder_map_ = handle(next->map());
|
|
|
|
maybe_holder_ = next;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-11 18:02:38 +00:00
|
|
|
LookupIterator::State LookupIterator::LookupInHolder() {
|
|
|
|
switch (state_) {
|
2014-06-11 09:59:14 +00:00
|
|
|
case NOT_FOUND:
|
|
|
|
if (holder_map_->IsJSProxyMap()) {
|
2014-06-11 18:02:38 +00:00
|
|
|
return JSPROXY;
|
2014-06-11 09:59:14 +00:00
|
|
|
}
|
|
|
|
if (check_access_check() && holder_map_->is_access_check_needed()) {
|
2014-06-11 18:02:38 +00:00
|
|
|
return ACCESS_CHECK;
|
2014-06-11 09:59:14 +00:00
|
|
|
}
|
2014-06-11 18:02:38 +00:00
|
|
|
// Fall through.
|
2014-06-11 09:59:14 +00:00
|
|
|
case ACCESS_CHECK:
|
|
|
|
if (check_interceptor() && holder_map_->has_named_interceptor()) {
|
2014-06-11 18:02:38 +00:00
|
|
|
return INTERCEPTOR;
|
2014-06-11 09:59:14 +00:00
|
|
|
}
|
2014-06-11 18:02:38 +00:00
|
|
|
// Fall through.
|
2014-06-11 09:59:14 +00:00
|
|
|
case INTERCEPTOR:
|
|
|
|
if (holder_map_->is_dictionary_map()) {
|
|
|
|
property_encoding_ = DICTIONARY;
|
|
|
|
} else {
|
|
|
|
DescriptorArray* descriptors = holder_map_->instance_descriptors();
|
|
|
|
number_ = descriptors->SearchWithCache(*name_, *holder_map_);
|
2014-06-11 18:02:38 +00:00
|
|
|
if (number_ == DescriptorArray::kNotFound) return NOT_FOUND;
|
2014-06-11 09:59:14 +00:00
|
|
|
property_encoding_ = DESCRIPTOR;
|
|
|
|
}
|
2014-06-11 18:02:38 +00:00
|
|
|
return PROPERTY;
|
2014-06-11 09:59:14 +00:00
|
|
|
case PROPERTY:
|
2014-06-11 18:02:38 +00:00
|
|
|
return NOT_FOUND;
|
2014-06-11 09:59:14 +00:00
|
|
|
case JSPROXY:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2014-06-11 18:02:38 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return state_;
|
2014-06-11 09:59:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool LookupIterator::IsBootstrapping() const {
|
|
|
|
return isolate_->bootstrapper()->IsActive();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool LookupIterator::HasAccess(v8::AccessType access_type) const {
|
|
|
|
ASSERT_EQ(ACCESS_CHECK, state_);
|
|
|
|
ASSERT(is_guaranteed_to_have_holder());
|
|
|
|
return isolate_->MayNamedAccess(GetHolder(), name_, access_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool LookupIterator::HasProperty() {
|
|
|
|
ASSERT_EQ(PROPERTY, state_);
|
|
|
|
ASSERT(is_guaranteed_to_have_holder());
|
|
|
|
|
|
|
|
if (property_encoding_ == DICTIONARY) {
|
|
|
|
Handle<JSObject> holder = GetHolder();
|
|
|
|
number_ = holder->property_dictionary()->FindEntry(name_);
|
|
|
|
if (number_ == NameDictionary::kNotFound) return false;
|
|
|
|
|
|
|
|
property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_);
|
|
|
|
// Holes in dictionary cells are absent values unless marked as read-only.
|
|
|
|
if (holder->IsGlobalObject() &&
|
|
|
|
(property_details_.IsDeleted() ||
|
|
|
|
(!property_details_.IsReadOnly() && FetchValue()->IsTheHole()))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
property_details_ = holder_map_->instance_descriptors()->GetDetails(
|
|
|
|
number_);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (property_details_.type()) {
|
|
|
|
case v8::internal::FIELD:
|
|
|
|
case v8::internal::NORMAL:
|
|
|
|
case v8::internal::CONSTANT:
|
2014-06-11 18:02:38 +00:00
|
|
|
property_kind_ = DATA;
|
2014-06-11 09:59:14 +00:00
|
|
|
break;
|
|
|
|
case v8::internal::CALLBACKS:
|
2014-06-11 18:02:38 +00:00
|
|
|
property_kind_ = ACCESSOR;
|
2014-06-11 09:59:14 +00:00
|
|
|
break;
|
|
|
|
case v8::internal::HANDLER:
|
|
|
|
case v8::internal::NONEXISTENT:
|
|
|
|
case v8::internal::INTERCEPTOR:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
has_property_ = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> LookupIterator::FetchValue() const {
|
|
|
|
Object* result = NULL;
|
|
|
|
switch (property_encoding_) {
|
|
|
|
case DICTIONARY:
|
|
|
|
result = GetHolder()->property_dictionary()->ValueAt(number_);
|
|
|
|
if (GetHolder()->IsGlobalObject()) {
|
|
|
|
result = PropertyCell::cast(result)->value();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DESCRIPTOR:
|
|
|
|
if (property_details_.type() == v8::internal::FIELD) {
|
|
|
|
FieldIndex field_index = FieldIndex::ForDescriptor(
|
|
|
|
*holder_map_, number_);
|
|
|
|
return JSObject::FastPropertyAt(
|
|
|
|
GetHolder(), property_details_.representation(), field_index);
|
|
|
|
}
|
|
|
|
result = holder_map_->instance_descriptors()->GetValue(number_);
|
|
|
|
}
|
|
|
|
return handle(result, isolate_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> LookupIterator::GetAccessors() const {
|
|
|
|
ASSERT(has_property_);
|
2014-06-11 18:02:38 +00:00
|
|
|
ASSERT_EQ(ACCESSOR, property_kind_);
|
2014-06-11 09:59:14 +00:00
|
|
|
return FetchValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> LookupIterator::GetDataValue() const {
|
|
|
|
ASSERT(has_property_);
|
2014-06-11 18:02:38 +00:00
|
|
|
ASSERT_EQ(DATA, property_kind_);
|
2014-06-11 09:59:14 +00:00
|
|
|
Handle<Object> value = FetchValue();
|
|
|
|
if (value->IsTheHole()) {
|
|
|
|
ASSERT(property_details_.IsReadOnly());
|
|
|
|
return factory()->undefined_value();
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|