• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/bootstrapper.h"
8 #include "src/lookup.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 
Next()14 void LookupIterator::Next() {
15   has_property_ = false;
16   do {
17     state_ = LookupInHolder();
18   } while (!IsFound() && NextHolder());
19 }
20 
21 
GetRoot() const22 Handle<JSReceiver> LookupIterator::GetRoot() const {
23   Handle<Object> receiver = GetReceiver();
24   if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
25   Context* native_context = isolate_->context()->native_context();
26   JSFunction* function;
27   if (receiver->IsNumber()) {
28     function = native_context->number_function();
29   } else if (receiver->IsString()) {
30     function = native_context->string_function();
31   } else if (receiver->IsSymbol()) {
32     function = native_context->symbol_function();
33   } else if (receiver->IsBoolean()) {
34     function = native_context->boolean_function();
35   } else {
36     UNREACHABLE();
37     function = NULL;
38   }
39   return handle(JSReceiver::cast(function->instance_prototype()));
40 }
41 
42 
GetReceiverMap() const43 Handle<Map> LookupIterator::GetReceiverMap() const {
44   Handle<Object> receiver = GetReceiver();
45   if (receiver->IsNumber()) return isolate_->factory()->heap_number_map();
46   return handle(Handle<HeapObject>::cast(receiver)->map());
47 }
48 
49 
NextHolder()50 bool LookupIterator::NextHolder() {
51   if (holder_map_->prototype()->IsNull()) return false;
52 
53   Handle<JSReceiver> next(JSReceiver::cast(holder_map_->prototype()));
54 
55   if (!check_derived() &&
56       !(check_hidden() &&
57          // TODO(verwaest): Check if this is actually necessary currently. If it
58          // is, this should be handled by setting is_hidden_prototype on the
59          // global object behind the proxy.
60         (holder_map_->IsJSGlobalProxyMap() ||
61          next->map()->is_hidden_prototype()))) {
62     return false;
63   }
64 
65   holder_map_ = handle(next->map());
66   maybe_holder_ = next;
67   return true;
68 }
69 
70 
LookupInHolder()71 LookupIterator::State LookupIterator::LookupInHolder() {
72   switch (state_) {
73     case NOT_FOUND:
74       if (holder_map_->IsJSProxyMap()) {
75         return JSPROXY;
76       }
77       if (check_access_check() && holder_map_->is_access_check_needed()) {
78         return ACCESS_CHECK;
79       }
80       // Fall through.
81     case ACCESS_CHECK:
82       if (check_interceptor() && holder_map_->has_named_interceptor()) {
83         return INTERCEPTOR;
84       }
85       // Fall through.
86     case INTERCEPTOR:
87       if (holder_map_->is_dictionary_map()) {
88         property_encoding_ = DICTIONARY;
89       } else {
90         DescriptorArray* descriptors = holder_map_->instance_descriptors();
91         number_ = descriptors->SearchWithCache(*name_, *holder_map_);
92         if (number_ == DescriptorArray::kNotFound) return NOT_FOUND;
93         property_encoding_ = DESCRIPTOR;
94       }
95       return PROPERTY;
96     case PROPERTY:
97       return NOT_FOUND;
98     case JSPROXY:
99       UNREACHABLE();
100   }
101   UNREACHABLE();
102   return state_;
103 }
104 
105 
IsBootstrapping() const106 bool LookupIterator::IsBootstrapping() const {
107   return isolate_->bootstrapper()->IsActive();
108 }
109 
110 
HasAccess(v8::AccessType access_type) const111 bool LookupIterator::HasAccess(v8::AccessType access_type) const {
112   ASSERT_EQ(ACCESS_CHECK, state_);
113   ASSERT(is_guaranteed_to_have_holder());
114   return isolate_->MayNamedAccess(GetHolder(), name_, access_type);
115 }
116 
117 
HasProperty()118 bool LookupIterator::HasProperty() {
119   ASSERT_EQ(PROPERTY, state_);
120   ASSERT(is_guaranteed_to_have_holder());
121 
122   if (property_encoding_ == DICTIONARY) {
123     Handle<JSObject> holder = GetHolder();
124     number_ = holder->property_dictionary()->FindEntry(name_);
125     if (number_ == NameDictionary::kNotFound) return false;
126 
127     property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_);
128     // Holes in dictionary cells are absent values unless marked as read-only.
129     if (holder->IsGlobalObject() &&
130         (property_details_.IsDeleted() ||
131          (!property_details_.IsReadOnly() && FetchValue()->IsTheHole()))) {
132       return false;
133     }
134   } else {
135     property_details_ = holder_map_->instance_descriptors()->GetDetails(
136         number_);
137   }
138 
139   switch (property_details_.type()) {
140     case v8::internal::FIELD:
141     case v8::internal::NORMAL:
142     case v8::internal::CONSTANT:
143       property_kind_ = DATA;
144       break;
145     case v8::internal::CALLBACKS:
146       property_kind_ = ACCESSOR;
147       break;
148     case v8::internal::HANDLER:
149     case v8::internal::NONEXISTENT:
150     case v8::internal::INTERCEPTOR:
151       UNREACHABLE();
152   }
153 
154   has_property_ = true;
155   return true;
156 }
157 
158 
FetchValue() const159 Handle<Object> LookupIterator::FetchValue() const {
160   Object* result = NULL;
161   switch (property_encoding_) {
162     case DICTIONARY:
163       result = GetHolder()->property_dictionary()->ValueAt(number_);
164       if (GetHolder()->IsGlobalObject()) {
165         result = PropertyCell::cast(result)->value();
166       }
167       break;
168     case DESCRIPTOR:
169       if (property_details_.type() == v8::internal::FIELD) {
170         FieldIndex field_index = FieldIndex::ForDescriptor(
171             *holder_map_, number_);
172         return JSObject::FastPropertyAt(
173             GetHolder(), property_details_.representation(), field_index);
174       }
175       result = holder_map_->instance_descriptors()->GetValue(number_);
176   }
177   return handle(result, isolate_);
178 }
179 
180 
GetAccessors() const181 Handle<Object> LookupIterator::GetAccessors() const {
182   ASSERT(has_property_);
183   ASSERT_EQ(ACCESSOR, property_kind_);
184   return FetchValue();
185 }
186 
187 
GetDataValue() const188 Handle<Object> LookupIterator::GetDataValue() const {
189   ASSERT(has_property_);
190   ASSERT_EQ(DATA, property_kind_);
191   Handle<Object> value = FetchValue();
192   if (value->IsTheHole()) {
193     ASSERT(property_details_.IsReadOnly());
194     return factory()->undefined_value();
195   }
196   return value;
197 }
198 
199 
200 } }  // namespace v8::internal
201