OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
8 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
9 #include "src/lookup.h" | 9 #include "src/lookup.h" |
10 #include "src/lookup-inl.h" | 10 #include "src/lookup-inl.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 | 15 |
16 void LookupIterator::Next() { | 16 void LookupIterator::Next() { |
17 DCHECK_NE(JSPROXY, state_); | 17 DCHECK_NE(JSPROXY, state_); |
18 DCHECK_NE(TRANSITION, state_); | 18 DCHECK_NE(TRANSITION, state_); |
19 DisallowHeapAllocation no_gc; | 19 DisallowHeapAllocation no_gc; |
20 has_property_ = false; | 20 has_property_ = false; |
21 | 21 |
22 JSReceiver* holder = | 22 JSReceiver* holder = *holder_; |
23 maybe_holder_.is_null() ? NULL : *maybe_holder_.ToHandleChecked(); | |
24 Map* map = *holder_map_; | 23 Map* map = *holder_map_; |
25 | 24 |
26 // Perform lookup on current holder. | 25 // Perform lookup on current holder. |
27 state_ = LookupInHolder(map, holder); | 26 state_ = LookupInHolder(map, holder); |
28 if (IsFound()) return; | 27 if (IsFound()) return; |
29 | 28 |
30 // Continue lookup if lookup on current holder failed. | 29 // Continue lookup if lookup on current holder failed. |
31 do { | 30 do { |
32 JSReceiver* maybe_holder = NextHolder(map); | 31 JSReceiver* maybe_holder = NextHolder(map); |
33 if (maybe_holder == NULL) break; | 32 if (maybe_holder == NULL) break; |
34 holder = maybe_holder; | 33 holder = maybe_holder; |
35 map = holder->map(); | 34 map = holder->map(); |
36 state_ = LookupInHolder(map, holder); | 35 state_ = LookupInHolder(map, holder); |
37 } while (!IsFound()); | 36 } while (!IsFound()); |
38 | 37 |
39 if (holder == NULL) return; | 38 if (holder != *holder_) { |
40 | 39 holder_ = handle(holder, isolate_); |
41 maybe_holder_ = handle(holder, isolate_); | 40 holder_map_ = handle(map, isolate_); |
42 holder_map_ = handle(map, isolate_); | 41 } |
43 } | 42 } |
44 | 43 |
45 | 44 |
46 Handle<JSReceiver> LookupIterator::GetRoot() const { | 45 Handle<JSReceiver> LookupIterator::GetRoot() const { |
47 Handle<Object> receiver = GetReceiver(); | 46 if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_); |
48 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); | |
49 Handle<Object> root = | 47 Handle<Object> root = |
50 handle(receiver->GetRootMap(isolate_)->prototype(), isolate_); | 48 handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_); |
51 CHECK(!root->IsNull()); | 49 CHECK(!root->IsNull()); |
52 return Handle<JSReceiver>::cast(root); | 50 return Handle<JSReceiver>::cast(root); |
53 } | 51 } |
54 | 52 |
55 | 53 |
56 Handle<Map> LookupIterator::GetReceiverMap() const { | 54 Handle<Map> LookupIterator::GetReceiverMap() const { |
57 Handle<Object> receiver = GetReceiver(); | 55 if (receiver_->IsNumber()) return isolate_->factory()->heap_number_map(); |
58 if (receiver->IsNumber()) return isolate_->factory()->heap_number_map(); | 56 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); |
59 return handle(Handle<HeapObject>::cast(receiver)->map(), isolate_); | |
60 } | 57 } |
61 | 58 |
62 | 59 |
63 Handle<JSObject> LookupIterator::GetStoreTarget() const { | 60 Handle<JSObject> LookupIterator::GetStoreTarget() const { |
64 Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); | 61 if (receiver_->IsJSGlobalProxy()) { |
65 | 62 PrototypeIterator iter(isolate(), receiver_); |
66 if (receiver->IsJSGlobalProxy()) { | 63 if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_); |
67 PrototypeIterator iter(isolate(), receiver); | |
68 if (iter.IsAtEnd()) return receiver; | |
69 return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); | 64 return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); |
70 } | 65 } |
71 return receiver; | 66 return Handle<JSObject>::cast(receiver_); |
72 } | 67 } |
73 | 68 |
74 | 69 |
75 bool LookupIterator::IsBootstrapping() const { | 70 bool LookupIterator::IsBootstrapping() const { |
76 return isolate_->bootstrapper()->IsActive(); | 71 return isolate_->bootstrapper()->IsActive(); |
77 } | 72 } |
78 | 73 |
79 | 74 |
80 bool LookupIterator::HasAccess(v8::AccessType access_type) const { | 75 bool LookupIterator::HasAccess(v8::AccessType access_type) const { |
81 DCHECK_EQ(ACCESS_CHECK, state_); | 76 DCHECK_EQ(ACCESS_CHECK, state_); |
82 DCHECK(is_guaranteed_to_have_holder()); | |
83 return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type); | 77 return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type); |
84 } | 78 } |
85 | 79 |
86 | 80 |
87 void LookupIterator::ReloadPropertyInformation() { | 81 void LookupIterator::ReloadPropertyInformation() { |
88 state_ = BEFORE_PROPERTY; | 82 state_ = BEFORE_PROPERTY; |
89 state_ = LookupInHolder(*holder_map_, *maybe_holder_.ToHandleChecked()); | 83 state_ = LookupInHolder(*holder_map_, *holder_); |
90 DCHECK(IsFound() || holder_map_->is_dictionary_map()); | 84 DCHECK(IsFound() || holder_map_->is_dictionary_map()); |
91 } | 85 } |
92 | 86 |
93 | 87 |
94 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { | 88 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
95 DCHECK(state_ == DATA || state_ == ACCESSOR); | 89 DCHECK(state_ == DATA || state_ == ACCESSOR); |
96 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 90 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
97 if (holder_map_->is_dictionary_map()) return; | 91 if (holder_map_->is_dictionary_map()) return; |
98 holder_map_ = | 92 holder_map_ = |
99 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); | 93 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 transition_map_ = Map::TransitionToDataProperty( | 135 transition_map_ = Map::TransitionToDataProperty( |
142 handle(receiver->map(), isolate_), name_, value, attributes, store_mode); | 136 handle(receiver->map(), isolate_), name_, value, attributes, store_mode); |
143 state_ = TRANSITION; | 137 state_ = TRANSITION; |
144 } | 138 } |
145 | 139 |
146 | 140 |
147 void LookupIterator::ApplyTransitionToDataProperty() { | 141 void LookupIterator::ApplyTransitionToDataProperty() { |
148 DCHECK_EQ(TRANSITION, state_); | 142 DCHECK_EQ(TRANSITION, state_); |
149 | 143 |
150 Handle<JSObject> receiver = GetStoreTarget(); | 144 Handle<JSObject> receiver = GetStoreTarget(); |
151 maybe_holder_ = receiver; | 145 holder_ = receiver; |
152 holder_map_ = transition_map_; | 146 holder_map_ = transition_map_; |
153 JSObject::MigrateToMap(receiver, holder_map_); | 147 JSObject::MigrateToMap(receiver, holder_map_); |
154 ReloadPropertyInformation(); | 148 ReloadPropertyInformation(); |
155 } | 149 } |
156 | 150 |
157 | 151 |
158 void LookupIterator::TransitionToAccessorProperty( | 152 void LookupIterator::TransitionToAccessorProperty( |
159 AccessorComponent component, Handle<Object> accessor, | 153 AccessorComponent component, Handle<Object> accessor, |
160 PropertyAttributes attributes) { | 154 PropertyAttributes attributes) { |
161 DCHECK(!accessor->IsNull()); | 155 DCHECK(!accessor->IsNull()); |
162 // Can only be called when the receiver is a JSObject. JSProxy has to be | 156 // Can only be called when the receiver is a JSObject. JSProxy has to be |
163 // handled via a trap. Adding properties to primitive values is not | 157 // handled via a trap. Adding properties to primitive values is not |
164 // observable. | 158 // observable. |
165 Handle<JSObject> receiver = GetStoreTarget(); | 159 Handle<JSObject> receiver = GetStoreTarget(); |
166 maybe_holder_ = receiver; | 160 holder_ = receiver; |
167 holder_map_ = | 161 holder_map_ = |
168 Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_), | 162 Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_), |
169 name_, component, accessor, attributes); | 163 name_, component, accessor, attributes); |
170 JSObject::MigrateToMap(receiver, holder_map_); | 164 JSObject::MigrateToMap(receiver, holder_map_); |
171 | 165 |
172 ReloadPropertyInformation(); | 166 ReloadPropertyInformation(); |
173 | 167 |
174 if (!holder_map_->is_dictionary_map()) return; | 168 if (!holder_map_->is_dictionary_map()) return; |
175 | 169 |
176 // We have to deoptimize since accesses to data properties may have been | 170 // We have to deoptimize since accesses to data properties may have been |
(...skipping 24 matching lines...) Expand all Loading... |
201 holder_map_ = handle(receiver->map(), isolate_); | 195 holder_map_ = handle(receiver->map(), isolate_); |
202 ReloadPropertyInformation(); | 196 ReloadPropertyInformation(); |
203 } | 197 } |
204 | 198 |
205 | 199 |
206 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { | 200 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
207 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); | 201 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
208 // Optimization that only works if configuration_ is not mutable. | 202 // Optimization that only works if configuration_ is not mutable. |
209 if (!check_prototype_chain()) return true; | 203 if (!check_prototype_chain()) return true; |
210 DisallowHeapAllocation no_gc; | 204 DisallowHeapAllocation no_gc; |
211 Handle<Object> receiver = GetReceiver(); | 205 if (!receiver_->IsJSReceiver()) return false; |
212 if (!receiver->IsJSReceiver()) return false; | 206 Object* current = *receiver_; |
213 Object* current = *receiver; | 207 JSReceiver* holder = *holder_; |
214 JSReceiver* holder = *maybe_holder_.ToHandleChecked(); | |
215 // JSProxy do not occur as hidden prototypes. | 208 // JSProxy do not occur as hidden prototypes. |
216 if (current->IsJSProxy()) { | 209 if (current->IsJSProxy()) { |
217 return JSReceiver::cast(current) == holder; | 210 return JSReceiver::cast(current) == holder; |
218 } | 211 } |
219 PrototypeIterator iter(isolate(), current, | 212 PrototypeIterator iter(isolate(), current, |
220 PrototypeIterator::START_AT_RECEIVER); | 213 PrototypeIterator::START_AT_RECEIVER); |
221 do { | 214 do { |
222 if (JSReceiver::cast(iter.GetCurrent()) == holder) return true; | 215 if (JSReceiver::cast(iter.GetCurrent()) == holder) return true; |
223 DCHECK(!current->IsJSProxy()); | 216 DCHECK(!current->IsJSProxy()); |
224 iter.Advance(); | 217 iter.Advance(); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 | 283 |
291 | 284 |
292 Handle<Object> LookupIterator::GetDataValue() const { | 285 Handle<Object> LookupIterator::GetDataValue() const { |
293 DCHECK_EQ(DATA, state_); | 286 DCHECK_EQ(DATA, state_); |
294 Handle<Object> value = FetchValue(); | 287 Handle<Object> value = FetchValue(); |
295 return value; | 288 return value; |
296 } | 289 } |
297 | 290 |
298 | 291 |
299 void LookupIterator::WriteDataValue(Handle<Object> value) { | 292 void LookupIterator::WriteDataValue(Handle<Object> value) { |
300 DCHECK(is_guaranteed_to_have_holder()); | |
301 DCHECK_EQ(DATA, state_); | 293 DCHECK_EQ(DATA, state_); |
302 Handle<JSObject> holder = GetHolder<JSObject>(); | 294 Handle<JSObject> holder = GetHolder<JSObject>(); |
303 if (holder_map_->is_dictionary_map()) { | 295 if (holder_map_->is_dictionary_map()) { |
304 NameDictionary* property_dictionary = holder->property_dictionary(); | 296 NameDictionary* property_dictionary = holder->property_dictionary(); |
305 if (holder->IsGlobalObject()) { | 297 if (holder->IsGlobalObject()) { |
306 Handle<PropertyCell> cell( | 298 Handle<PropertyCell> cell( |
307 PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry()))); | 299 PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry()))); |
308 PropertyCell::SetValueInferType(cell, value); | 300 PropertyCell::SetValueInferType(cell, value); |
309 } else { | 301 } else { |
310 property_dictionary->ValueAtPut(dictionary_entry(), *value); | 302 property_dictionary->ValueAtPut(dictionary_entry(), *value); |
311 } | 303 } |
312 } else if (property_details_.type() == v8::internal::FIELD) { | 304 } else if (property_details_.type() == v8::internal::FIELD) { |
313 holder->WriteToField(descriptor_number(), *value); | 305 holder->WriteToField(descriptor_number(), *value); |
314 } else { | 306 } else { |
315 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); | 307 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); |
316 } | 308 } |
317 } | 309 } |
318 | 310 |
319 | 311 |
320 void LookupIterator::InternalizeName() { | 312 void LookupIterator::InternalizeName() { |
321 if (name_->IsUniqueName()) return; | 313 if (name_->IsUniqueName()) return; |
322 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); | 314 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); |
323 } | 315 } |
324 } } // namespace v8::internal | 316 } } // namespace v8::internal |
OLD | NEW |