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_); |
| 18 DCHECK_NE(TRANSITION, state_); |
17 DisallowHeapAllocation no_gc; | 19 DisallowHeapAllocation no_gc; |
18 has_property_ = false; | 20 has_property_ = false; |
19 | 21 |
20 JSReceiver* holder = NULL; | 22 JSReceiver* holder = |
| 23 maybe_holder_.is_null() ? NULL : *maybe_holder_.ToHandleChecked(); |
21 Map* map = *holder_map_; | 24 Map* map = *holder_map_; |
22 | 25 |
23 // Perform lookup on current holder. | 26 // Perform lookup on current holder. |
24 state_ = LookupInHolder(map); | 27 state_ = LookupInHolder(map, holder); |
| 28 if (IsFound()) return; |
25 | 29 |
26 // Continue lookup if lookup on current holder failed. | 30 // Continue lookup if lookup on current holder failed. |
27 while (!IsFound()) { | 31 do { |
28 JSReceiver* maybe_holder = NextHolder(map); | 32 JSReceiver* maybe_holder = NextHolder(map); |
29 if (maybe_holder == NULL) break; | 33 if (maybe_holder == NULL) break; |
30 holder = maybe_holder; | 34 holder = maybe_holder; |
31 map = holder->map(); | 35 map = holder->map(); |
32 state_ = LookupInHolder(map); | 36 state_ = LookupInHolder(map, holder); |
33 } | 37 } while (!IsFound()); |
34 | 38 |
35 // Either was found in the receiver, or the receiver has no prototype. | |
36 if (holder == NULL) return; | 39 if (holder == NULL) return; |
37 | 40 |
38 maybe_holder_ = handle(holder, isolate_); | 41 maybe_holder_ = handle(holder, isolate_); |
39 holder_map_ = handle(map, isolate_); | 42 holder_map_ = handle(map, isolate_); |
40 } | 43 } |
41 | 44 |
42 | 45 |
43 Handle<JSReceiver> LookupIterator::GetRoot() const { | 46 Handle<JSReceiver> LookupIterator::GetRoot() const { |
44 Handle<Object> receiver = GetReceiver(); | 47 Handle<Object> receiver = GetReceiver(); |
45 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); | 48 if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); |
(...skipping 28 matching lines...) Expand all Loading... |
74 } | 77 } |
75 | 78 |
76 | 79 |
77 bool LookupIterator::HasAccess(v8::AccessType access_type) const { | 80 bool LookupIterator::HasAccess(v8::AccessType access_type) const { |
78 DCHECK_EQ(ACCESS_CHECK, state_); | 81 DCHECK_EQ(ACCESS_CHECK, state_); |
79 DCHECK(is_guaranteed_to_have_holder()); | 82 DCHECK(is_guaranteed_to_have_holder()); |
80 return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type); | 83 return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type); |
81 } | 84 } |
82 | 85 |
83 | 86 |
84 bool LookupIterator::HasProperty() { | |
85 DCHECK_EQ(PROPERTY, state_); | |
86 DCHECK(is_guaranteed_to_have_holder()); | |
87 | |
88 if (property_encoding_ == DICTIONARY) { | |
89 Handle<JSObject> holder = GetHolder<JSObject>(); | |
90 number_ = holder->property_dictionary()->FindEntry(name_); | |
91 if (number_ == NameDictionary::kNotFound) return false; | |
92 | |
93 property_details_ = holder->property_dictionary()->DetailsAt(number_); | |
94 // Holes in dictionary cells are absent values. | |
95 if (holder->IsGlobalObject() && | |
96 (property_details_.IsDeleted() || FetchValue()->IsTheHole())) { | |
97 return false; | |
98 } | |
99 } else { | |
100 // Can't use descriptor_number() yet because has_property_ is still false. | |
101 property_details_ = | |
102 holder_map_->instance_descriptors()->GetDetails(number_); | |
103 } | |
104 | |
105 LoadPropertyKind(); | |
106 | |
107 has_property_ = true; | |
108 return true; | |
109 } | |
110 | |
111 | |
112 void LookupIterator::LoadPropertyKind() { | |
113 switch (property_details_.type()) { | |
114 case v8::internal::FIELD: | |
115 case v8::internal::NORMAL: | |
116 case v8::internal::CONSTANT: | |
117 property_kind_ = DATA; | |
118 break; | |
119 case v8::internal::CALLBACKS: | |
120 property_kind_ = ACCESSOR; | |
121 break; | |
122 } | |
123 } | |
124 | |
125 | |
126 void LookupIterator::ReloadPropertyInformation() { | 87 void LookupIterator::ReloadPropertyInformation() { |
127 state_ = BEFORE_PROPERTY; | 88 state_ = BEFORE_PROPERTY; |
128 state_ = LookupInHolder(*holder_map_); | 89 state_ = LookupInHolder(*holder_map_, *maybe_holder_.ToHandleChecked()); |
129 DCHECK(IsFound()); | 90 DCHECK(IsFound() || holder_map_->is_dictionary_map()); |
130 HasProperty(); | |
131 } | 91 } |
132 | 92 |
133 | 93 |
134 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { | 94 void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
135 DCHECK(has_property_); | 95 DCHECK(state_ == DATA || state_ == ACCESSOR); |
136 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 96 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
137 if (property_encoding_ == DICTIONARY) return; | 97 if (property_encoding_ == DICTIONARY) return; |
138 holder_map_ = | 98 holder_map_ = |
139 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); | 99 Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); |
140 JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_); | 100 JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_); |
141 ReloadPropertyInformation(); | 101 ReloadPropertyInformation(); |
142 } | 102 } |
143 | 103 |
144 | 104 |
145 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, | 105 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
146 PropertyAttributes attributes) { | 106 PropertyAttributes attributes) { |
147 DCHECK(has_property_); | 107 DCHECK(state_ == DATA || state_ == ACCESSOR); |
148 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 108 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
149 Handle<JSObject> holder = GetHolder<JSObject>(); | 109 Handle<JSObject> holder = GetHolder<JSObject>(); |
150 if (property_encoding_ != DICTIONARY) { | 110 if (property_encoding_ != DICTIONARY) { |
151 holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(), | 111 holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(), |
152 attributes); | 112 attributes); |
153 JSObject::MigrateToMap(holder, holder_map_); | 113 JSObject::MigrateToMap(holder, holder_map_); |
154 } | 114 } |
155 | 115 |
156 if (holder_map_->is_dictionary_map()) { | 116 if (holder_map_->is_dictionary_map()) { |
157 PropertyDetails details(attributes, NORMAL, 0); | 117 PropertyDetails details(attributes, NORMAL, 0); |
158 JSObject::SetNormalizedProperty(holder, name(), value, details); | 118 JSObject::SetNormalizedProperty(holder, name(), value, details); |
159 } | 119 } |
160 | 120 |
161 ReloadPropertyInformation(); | 121 ReloadPropertyInformation(); |
162 } | 122 } |
163 | 123 |
164 | 124 |
165 void LookupIterator::PrepareTransitionToDataProperty( | 125 void LookupIterator::PrepareTransitionToDataProperty( |
166 Handle<Object> value, PropertyAttributes attributes, | 126 Handle<Object> value, PropertyAttributes attributes, |
167 Object::StoreFromKeyed store_mode) { | 127 Object::StoreFromKeyed store_mode) { |
168 if (state_ == TRANSITION) return; | 128 if (state_ == TRANSITION) return; |
169 DCHECK(!has_property_ || property_kind_ != ACCESSOR); | 129 DCHECK(state_ != LookupIterator::ACCESSOR || |
170 DCHECK(!(has_property_ || state_ == JSPROXY) || | 130 GetAccessors()->IsDeclaredAccessorInfo()); |
171 !HolderIsReceiverOrHiddenPrototype()); | 131 DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype()); |
172 | 132 |
173 // Can only be called when the receiver is a JSObject. JSProxy has to be | 133 // Can only be called when the receiver is a JSObject. JSProxy has to be |
174 // handled via a trap. Adding properties to primitive values is not | 134 // handled via a trap. Adding properties to primitive values is not |
175 // observable. | 135 // observable. |
176 Handle<JSObject> receiver = GetStoreTarget(); | 136 Handle<JSObject> receiver = GetStoreTarget(); |
177 | 137 |
178 if (!name().is_identical_to(isolate()->factory()->hidden_string()) && | 138 if (!name().is_identical_to(isolate()->factory()->hidden_string()) && |
179 !receiver->map()->is_extensible()) { | 139 !receiver->map()->is_extensible()) { |
180 return; | 140 return; |
181 } | 141 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 | 177 |
218 // We have to deoptimize since accesses to data properties may have been | 178 // We have to deoptimize since accesses to data properties may have been |
219 // inlined without a corresponding map-check. | 179 // inlined without a corresponding map-check. |
220 if (holder_map_->IsGlobalObjectMap()) { | 180 if (holder_map_->IsGlobalObjectMap()) { |
221 Deoptimizer::DeoptimizeGlobalObject(*receiver); | 181 Deoptimizer::DeoptimizeGlobalObject(*receiver); |
222 } | 182 } |
223 | 183 |
224 // Install the accessor into the dictionary-mode object. | 184 // Install the accessor into the dictionary-mode object. |
225 PropertyDetails details(attributes, CALLBACKS, 0); | 185 PropertyDetails details(attributes, CALLBACKS, 0); |
226 Handle<AccessorPair> pair; | 186 Handle<AccessorPair> pair; |
227 if (IsFound() && HasProperty() && property_kind() == ACCESSOR && | 187 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { |
228 GetAccessors()->IsAccessorPair()) { | |
229 pair = Handle<AccessorPair>::cast(GetAccessors()); | 188 pair = Handle<AccessorPair>::cast(GetAccessors()); |
230 // If the component and attributes are identical, nothing has to be done. | 189 // If the component and attributes are identical, nothing has to be done. |
231 if (pair->get(component) == *accessor) { | 190 if (pair->get(component) == *accessor) { |
232 if (property_details().attributes() == attributes) return; | 191 if (property_details().attributes() == attributes) return; |
233 } else { | 192 } else { |
234 pair = AccessorPair::Copy(pair); | 193 pair = AccessorPair::Copy(pair); |
235 pair->set(component, *accessor); | 194 pair->set(component, *accessor); |
236 } | 195 } |
237 } else { | 196 } else { |
238 pair = isolate()->factory()->NewAccessorPair(); | 197 pair = isolate()->factory()->NewAccessorPair(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 | 283 |
325 Handle<PropertyCell> LookupIterator::GetPropertyCell() const { | 284 Handle<PropertyCell> LookupIterator::GetPropertyCell() const { |
326 Handle<JSObject> holder = GetHolder<JSObject>(); | 285 Handle<JSObject> holder = GetHolder<JSObject>(); |
327 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 286 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
328 Object* value = global->property_dictionary()->ValueAt(dictionary_entry()); | 287 Object* value = global->property_dictionary()->ValueAt(dictionary_entry()); |
329 return Handle<PropertyCell>(PropertyCell::cast(value)); | 288 return Handle<PropertyCell>(PropertyCell::cast(value)); |
330 } | 289 } |
331 | 290 |
332 | 291 |
333 Handle<Object> LookupIterator::GetAccessors() const { | 292 Handle<Object> LookupIterator::GetAccessors() const { |
334 DCHECK(has_property_); | 293 DCHECK_EQ(ACCESSOR, state_); |
335 DCHECK_EQ(ACCESSOR, property_kind_); | |
336 return FetchValue(); | 294 return FetchValue(); |
337 } | 295 } |
338 | 296 |
339 | 297 |
340 Handle<Object> LookupIterator::GetDataValue() const { | 298 Handle<Object> LookupIterator::GetDataValue() const { |
341 DCHECK(has_property_); | 299 DCHECK_EQ(DATA, state_); |
342 DCHECK_EQ(DATA, property_kind_); | |
343 Handle<Object> value = FetchValue(); | 300 Handle<Object> value = FetchValue(); |
344 return value; | 301 return value; |
345 } | 302 } |
346 | 303 |
347 | 304 |
348 void LookupIterator::WriteDataValue(Handle<Object> value) { | 305 void LookupIterator::WriteDataValue(Handle<Object> value) { |
349 DCHECK(is_guaranteed_to_have_holder()); | 306 DCHECK(is_guaranteed_to_have_holder()); |
350 DCHECK(has_property_); | 307 DCHECK_EQ(DATA, state_); |
351 Handle<JSObject> holder = GetHolder<JSObject>(); | 308 Handle<JSObject> holder = GetHolder<JSObject>(); |
352 if (property_encoding_ == DICTIONARY) { | 309 if (property_encoding_ == DICTIONARY) { |
353 NameDictionary* property_dictionary = holder->property_dictionary(); | 310 NameDictionary* property_dictionary = holder->property_dictionary(); |
354 if (holder->IsGlobalObject()) { | 311 if (holder->IsGlobalObject()) { |
355 Handle<PropertyCell> cell( | 312 Handle<PropertyCell> cell( |
356 PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry()))); | 313 PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry()))); |
357 PropertyCell::SetValueInferType(cell, value); | 314 PropertyCell::SetValueInferType(cell, value); |
358 } else { | 315 } else { |
359 property_dictionary->ValueAtPut(dictionary_entry(), *value); | 316 property_dictionary->ValueAtPut(dictionary_entry(), *value); |
360 } | 317 } |
361 } else if (property_details_.type() == v8::internal::FIELD) { | 318 } else if (property_details_.type() == v8::internal::FIELD) { |
362 holder->WriteToField(descriptor_number(), *value); | 319 holder->WriteToField(descriptor_number(), *value); |
363 } else { | 320 } else { |
364 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); | 321 DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); |
365 } | 322 } |
366 } | 323 } |
367 | 324 |
368 | 325 |
369 void LookupIterator::InternalizeName() { | 326 void LookupIterator::InternalizeName() { |
370 if (name_->IsUniqueName()) return; | 327 if (name_->IsUniqueName()) return; |
371 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); | 328 name_ = factory()->InternalizeString(Handle<String>::cast(name_)); |
372 } | 329 } |
373 } } // namespace v8::internal | 330 } } // namespace v8::internal |
OLD | NEW |