Chromium Code Reviews| Index: src/lookup.cc |
| diff --git a/src/lookup.cc b/src/lookup.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..17a8ed0ed718c0b3d032f24334929a48511c4cd0 |
| --- /dev/null |
| +++ b/src/lookup.cc |
| @@ -0,0 +1,202 @@ |
| +// 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 { |
| + LookupInHolder(); |
| + } while (!IsFound() && NextHolder()); |
| +} |
| + |
| + |
| +Handle<JSReceiver> LookupIterator::GetOrigin() const { |
| + Handle<Object> receiver = GetReceiver(); |
| + if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); |
| + Context* native_context = isolate_->context()->native_context(); |
| + JSFunction* function; |
| + if (receiver->IsNumber()) { |
| + function = native_context->number_function(); |
| + } else if (receiver->IsString()) { |
| + function = native_context->string_function(); |
| + } else if (receiver->IsSymbol()) { |
| + function = native_context->symbol_function(); |
| + } else if (receiver->IsBoolean()) { |
| + function = native_context->boolean_function(); |
| + } else { |
| + UNREACHABLE(); |
| + function = NULL; |
| + } |
| + return handle(JSReceiver::cast(function->instance_prototype())); |
| +} |
| + |
| + |
| +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() && |
| + // 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()) { |
| + return false; |
| + } |
| + |
| + holder_map_ = handle(next->map()); |
| + maybe_holder_ = next; |
| + return true; |
| +} |
| + |
| + |
| +void LookupIterator::LookupInHolder() { |
| + State old_state = state_; |
| + state_ = NOT_FOUND; |
|
rossberg
2014/06/11 15:37:00
Might be clearer to not pre-default this. There ar
Toon Verwaest
2014/06/11 17:32:18
Done.
|
| + switch (old_state) { |
| + case NOT_FOUND: |
| + if (holder_map_->IsJSProxyMap()) { |
| + state_ = JSPROXY; |
| + return; |
| + } |
| + if (check_access_check() && holder_map_->is_access_check_needed()) { |
| + state_ = ACCESS_CHECK; |
| + return; |
| + } |
|
rossberg
2014/06/11 15:37:00
Put a fall-through comment here and below.
Toon Verwaest
2014/06/11 17:32:18
Done.
|
| + case ACCESS_CHECK: |
| + if (check_interceptor() && holder_map_->has_named_interceptor()) { |
| + state_ = INTERCEPTOR; |
| + return; |
| + } |
| + case INTERCEPTOR: |
| + if (holder_map_->is_dictionary_map()) { |
| + property_encoding_ = DICTIONARY; |
| + } else { |
| + DescriptorArray* descriptors = holder_map_->instance_descriptors(); |
| + number_ = descriptors->SearchWithCache(*name_, *holder_map_); |
| + if (number_ == DescriptorArray::kNotFound) return; |
| + property_encoding_ = DESCRIPTOR; |
| + } |
| + state_ = PROPERTY; |
| + case PROPERTY: |
| + return; |
| + case JSPROXY: |
| + UNREACHABLE(); |
| + } |
| +} |
| + |
| + |
| +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: |
| + property_type_ = DATA; |
| + break; |
| + case v8::internal::CALLBACKS: |
| + property_type_ = ACCESSORS; |
| + 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_); |
| + ASSERT_EQ(ACCESSORS, property_type_); |
| + return FetchValue(); |
| +} |
| + |
| + |
| +Handle<Object> LookupIterator::GetDataValue() const { |
| + ASSERT(has_property_); |
| + ASSERT_EQ(DATA, property_type_); |
| + Handle<Object> value = FetchValue(); |
| + if (value->IsTheHole()) { |
| + ASSERT_EQ(DICTIONARY, property_encoding_); |
| + ASSERT(GetHolder()->IsGlobalObject()); |
| + ASSERT(property_details_.IsReadOnly()); |
| + return factory()->undefined_value(); |
| + } |
| + return value; |
| +} |
| + |
| + |
| +} } // namespace v8::internal |