OLD | NEW |
---|---|
(Empty) | |
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 void LookupIterator::Next() { | |
14 ASSERT(IsFound()); | |
15 | |
16 State old_state = state_; | |
17 state_ = NOT_FOUND; | |
18 has_property_ = false; | |
19 | |
20 if (old_state == ACCESS_CHECK) { | |
21 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.
| |
22 state_ = INTERCEPTOR; | |
23 } else { | |
24 LookupOwnRealNamedProperty(); | |
25 } | |
26 if (IsFound()) return; | |
27 } else if (old_state == INTERCEPTOR) { | |
28 LookupOwnRealNamedProperty(); | |
29 if (IsFound()) return; | |
30 } | |
31 | |
32 // The prototype chain beyond a JSProxy has no meaning for lookup. | |
33 // Its trap should be used instead. | |
34 ASSERT(!holder_map_->IsJSProxyMap()); | |
35 | |
36 if (NextHolder()) ContinueLookup(); | |
37 } | |
38 | |
39 | |
40 Handle<JSReceiver> LookupIterator::GetOrigin() const { | |
41 Handle<Object> receiver = GetReceiver(); | |
42 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); | |
43 Context* native_context = isolate_->context()->native_context(); | |
44 JSFunction* function; | |
45 if (receiver->IsNumber()) { | |
46 function = native_context->number_function(); | |
47 } else if (receiver->IsString()) { | |
48 function = native_context->string_function(); | |
49 } else if (receiver->IsSymbol()) { | |
50 function = native_context->symbol_function(); | |
51 } else if (receiver->IsBoolean()) { | |
52 function = native_context->boolean_function(); | |
53 } else { | |
54 UNREACHABLE(); | |
55 function = NULL; | |
56 } | |
57 return handle(JSReceiver::cast(function->instance_prototype())); | |
58 } | |
59 | |
60 | |
61 Handle<Map> LookupIterator::GetReceiverMap() const { | |
62 Handle<Object> receiver = GetReceiver(); | |
63 if (receiver->IsNumber()) return isolate_->factory()->heap_number_map(); | |
64 return handle(Handle<HeapObject>::cast(receiver)->map()); | |
65 } | |
66 | |
67 | |
68 bool LookupIterator::NextHolder() { | |
69 if (holder_map_->prototype()->IsNull()) return false; | |
70 | |
71 Handle<JSReceiver> next(JSReceiver::cast(holder_map_->prototype())); | |
72 | |
73 if (!check_derived() && | |
74 // TODO(verwaest): Check if this is actually necessary currently. If it | |
75 // is, this should be handled by setting is_hidden_prototype on the | |
76 // global object behind the proxy. | |
77 !holder_map_->IsJSGlobalProxyMap() && | |
78 !next->map()->is_hidden_prototype()) { | |
79 return false; | |
80 } | |
81 | |
82 holder_map_ = handle(next->map()); | |
83 maybe_holder_ = next; | |
84 return true; | |
85 } | |
86 | |
87 | |
88 void LookupIterator::ContinueLookup() { | |
89 ASSERT(!IsFound()); | |
90 do { | |
91 LookupInHolder(); | |
92 } while (!IsFound() && NextHolder()); | |
93 } | |
94 | |
95 | |
96 void LookupIterator::LookupInHolder() { | |
97 if (holder_map_->IsJSProxyMap()) { | |
98 state_ = JSPROXY; | |
99 } else if (check_access_check() && holder_map_->is_access_check_needed()) { | |
100 state_ = ACCESS_CHECK; | |
101 } else if (check_interceptor() && holder_map_->has_named_interceptor()) { | |
102 state_ = INTERCEPTOR; | |
103 } else { | |
104 LookupOwnRealNamedProperty(); | |
105 } | |
106 } | |
107 | |
108 | |
109 void LookupIterator::LookupOwnRealNamedProperty() { | |
110 if (holder_map_->is_dictionary_map()) { | |
111 property_encoding_ = DICTIONARY; | |
112 } else { | |
113 DescriptorArray* descriptors = holder_map_->instance_descriptors(); | |
114 number_ = descriptors->SearchWithCache(*name_, *holder_map_); | |
115 if (number_ == DescriptorArray::kNotFound) return; | |
116 property_encoding_ = DESCRIPTOR; | |
117 } | |
118 state_ = PROPERTY; | |
119 } | |
120 | |
121 | |
122 bool LookupIterator::IsBootstrapping() const { | |
123 return isolate_->bootstrapper()->IsActive(); | |
124 } | |
125 | |
126 | |
127 bool LookupIterator::HasAccess(v8::AccessType access_type) const { | |
128 ASSERT_EQ(ACCESS_CHECK, state_); | |
129 ASSERT(is_guaranteed_to_have_holder()); | |
130 return isolate_->MayNamedAccess(GetHolder(), name_, access_type); | |
131 } | |
132 | |
133 | |
134 bool LookupIterator::HasProperty() { | |
135 ASSERT_EQ(PROPERTY, state_); | |
136 ASSERT(is_guaranteed_to_have_holder()); | |
137 | |
138 if (property_encoding_ == DICTIONARY) { | |
139 Handle<JSObject> holder = GetHolder(); | |
140 number_ = holder->property_dictionary()->FindEntry(name_); | |
141 if (number_ == NameDictionary::kNotFound) return false; | |
142 } | |
143 | |
144 has_property_ = true; | |
145 FetchDetails(); | |
146 | |
147 // Holes in dictionary cells are absent values unless marked as read-only. | |
148 if (property_encoding_ == DICTIONARY && | |
149 GetHolder()->IsGlobalObject() && | |
150 !property_details_.IsReadOnly() && | |
151 FetchValue()->IsTheHole()) { | |
152 has_property_ = false; | |
153 return false; | |
Igor Sheludko
2014/06/10 16:15:07
"GlobalObject with property_details_.IsDeleted()"
| |
154 } | |
155 | |
156 switch (property_details_.type()) { | |
157 case v8::internal::FIELD: | |
158 case v8::internal::NORMAL: | |
159 case v8::internal::CONSTANT: | |
160 property_type_ = DATA; | |
161 break; | |
162 case v8::internal::CALLBACKS: | |
163 property_type_ = ACCESSORS; | |
164 break; | |
165 case v8::internal::HANDLER: | |
166 case v8::internal::NONEXISTENT: | |
167 case v8::internal::INTERCEPTOR: | |
168 UNREACHABLE(); | |
169 } | |
170 return true; | |
171 } | |
172 | |
173 | |
174 Handle<Object> LookupIterator::FetchValue() const { | |
175 ASSERT(has_property_); | |
176 Object* result = NULL; | |
177 switch (property_encoding_) { | |
178 case DICTIONARY: | |
179 result = GetHolder()->property_dictionary()->ValueAt(number_); | |
180 if (GetHolder()->IsGlobalObject()) { | |
181 result = PropertyCell::cast(result)->value(); | |
182 } | |
183 break; | |
184 case DESCRIPTOR: | |
185 if (property_details_.type() == v8::internal::FIELD) { | |
186 FieldIndex field_index = FieldIndex::ForDescriptor( | |
187 *holder_map_, number_); | |
188 return JSObject::FastPropertyAt( | |
189 GetHolder(), property_details_.representation(), field_index); | |
190 } | |
191 result = holder_map_->instance_descriptors()->GetValue(number_); | |
192 } | |
193 return handle(result, isolate_); | |
194 } | |
195 | |
196 | |
197 Handle<Object> LookupIterator::GetAccessors() const { | |
198 ASSERT(has_property_); | |
199 ASSERT_EQ(ACCESSORS, property_type_); | |
200 return FetchValue(); | |
201 } | |
202 | |
203 | |
204 Handle<Object> LookupIterator::GetDataValue() const { | |
205 ASSERT(has_property_); | |
206 ASSERT_EQ(DATA, property_type_); | |
207 Handle<Object> value = FetchValue(); | |
208 if (value->IsTheHole()) { | |
209 ASSERT_EQ(DICTIONARY, property_encoding_); | |
210 ASSERT(GetHolder()->IsGlobalObject()); | |
211 ASSERT(property_details_.IsReadOnly()); | |
212 return factory()->undefined_value(); | |
213 } | |
214 return value; | |
215 } | |
216 | |
217 | |
218 void LookupIterator::FetchDetails() { | |
219 ASSERT(has_property_); | |
220 property_details_ = property_encoding_ == DICTIONARY | |
221 ? GetHolder()->property_dictionary()->DetailsAt(number_) | |
222 : holder_map_->instance_descriptors()->GetDetails(number_); | |
223 } | |
224 | |
225 | |
226 } } // namespace v8::internal | |
OLD | NEW |