 Chromium Code Reviews
 Chromium Code Reviews Issue 314953006:
  Implement LookupIterator designed to replace LookupResult  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 314953006:
  Implement LookupIterator designed to replace LookupResult  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/lookup.cc | 
| diff --git a/src/lookup.cc b/src/lookup.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..1365018e4801cd475ca2169fd3d516d96fe6024d | 
| --- /dev/null | 
| +++ b/src/lookup.cc | 
| @@ -0,0 +1,226 @@ | 
| +// 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() { | 
| + ASSERT(IsFound()); | 
| + | 
| + State old_state = state_; | 
| + state_ = NOT_FOUND; | 
| + has_property_ = false; | 
| + | 
| + if (old_state == ACCESS_CHECK) { | 
| + if (holder_map_->has_named_interceptor()) { | 
| 
Igor Sheludko
2014/06/10 16:15:07
I think "check_interceptor() && " is missing here.
 
Toon Verwaest
2014/06/10 18:59:29
Done.
 | 
| + state_ = INTERCEPTOR; | 
| + } else { | 
| + LookupOwnRealNamedProperty(); | 
| + } | 
| + if (IsFound()) return; | 
| + } else if (old_state == INTERCEPTOR) { | 
| + LookupOwnRealNamedProperty(); | 
| + if (IsFound()) return; | 
| + } | 
| + | 
| + // The prototype chain beyond a JSProxy has no meaning for lookup. | 
| + // Its trap should be used instead. | 
| + ASSERT(!holder_map_->IsJSProxyMap()); | 
| + | 
| + if (NextHolder()) ContinueLookup(); | 
| +} | 
| + | 
| + | 
| +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::ContinueLookup() { | 
| + ASSERT(!IsFound()); | 
| + do { | 
| + LookupInHolder(); | 
| + } while (!IsFound() && NextHolder()); | 
| +} | 
| + | 
| + | 
| +void LookupIterator::LookupInHolder() { | 
| + if (holder_map_->IsJSProxyMap()) { | 
| + state_ = JSPROXY; | 
| + } else if (check_access_check() && holder_map_->is_access_check_needed()) { | 
| + state_ = ACCESS_CHECK; | 
| + } else if (check_interceptor() && holder_map_->has_named_interceptor()) { | 
| + state_ = INTERCEPTOR; | 
| + } else { | 
| + LookupOwnRealNamedProperty(); | 
| + } | 
| +} | 
| + | 
| + | 
| +void LookupIterator::LookupOwnRealNamedProperty() { | 
| + 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; | 
| +} | 
| + | 
| + | 
| +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; | 
| + } | 
| + | 
| + has_property_ = true; | 
| + FetchDetails(); | 
| + | 
| + // Holes in dictionary cells are absent values unless marked as read-only. | 
| + if (property_encoding_ == DICTIONARY && | 
| + GetHolder()->IsGlobalObject() && | 
| + !property_details_.IsReadOnly() && | 
| + FetchValue()->IsTheHole()) { | 
| + has_property_ = false; | 
| + return false; | 
| 
Igor Sheludko
2014/06/10 16:15:07
"GlobalObject with property_details_.IsDeleted()"
 | 
| + } | 
| + | 
| + 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(); | 
| + } | 
| + return true; | 
| +} | 
| + | 
| + | 
| +Handle<Object> LookupIterator::FetchValue() const { | 
| + ASSERT(has_property_); | 
| + 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; | 
| +} | 
| + | 
| + | 
| +void LookupIterator::FetchDetails() { | 
| + ASSERT(has_property_); | 
| + property_details_ = property_encoding_ == DICTIONARY | 
| + ? GetHolder()->property_dictionary()->DetailsAt(number_) | 
| + : holder_map_->instance_descriptors()->GetDetails(number_); | 
| +} | 
| + | 
| + | 
| +} } // namespace v8::internal |