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 |