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/lookup.h" | 5 #include "src/lookup.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/elements.h" | 9 #include "src/elements.h" |
10 #include "src/field-type.h" | 10 #include "src/field-type.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 LookupIterator it(isolate, receiver, index, configuration); | 38 LookupIterator it(isolate, receiver, index, configuration); |
39 // Here we try to avoid having to rebuild the string later | 39 // Here we try to avoid having to rebuild the string later |
40 // by storing it on the indexed LookupIterator. | 40 // by storing it on the indexed LookupIterator. |
41 it.name_ = name; | 41 it.name_ = name; |
42 return it; | 42 return it; |
43 } | 43 } |
44 | 44 |
45 return LookupIterator(receiver, name, configuration); | 45 return LookupIterator(receiver, name, configuration); |
46 } | 46 } |
47 | 47 |
48 template <bool is_element> | |
49 void LookupIterator::Start() { | |
50 DisallowHeapAllocation no_gc; | |
51 | |
52 has_property_ = false; | |
53 state_ = NOT_FOUND; | |
54 number_ = DescriptorArray::kNotFound; | |
55 holder_ = initial_holder_; | |
56 | |
57 JSReceiver* holder = *holder_; | |
58 Map* map = holder->map(); | |
59 | |
60 state_ = LookupInHolder<is_element>(map, holder); | |
61 if (IsFound()) return; | |
62 | |
63 NextInternal<is_element>(map, holder); | |
64 } | |
65 | |
66 template void LookupIterator::Start<true>(); | |
67 template void LookupIterator::Start<false>(); | |
68 | 48 |
69 void LookupIterator::Next() { | 49 void LookupIterator::Next() { |
70 DCHECK_NE(JSPROXY, state_); | 50 DCHECK_NE(JSPROXY, state_); |
71 DCHECK_NE(TRANSITION, state_); | 51 DCHECK_NE(TRANSITION, state_); |
72 DisallowHeapAllocation no_gc; | 52 DisallowHeapAllocation no_gc; |
73 has_property_ = false; | 53 has_property_ = false; |
74 | 54 |
75 JSReceiver* holder = *holder_; | 55 JSReceiver* holder = *holder_; |
76 Map* map = holder->map(); | 56 Map* map = holder->map(); |
77 | 57 |
78 if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { | 58 // Perform lookup on current holder. |
79 state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder) | 59 state_ = LookupInHolder(map, holder); |
80 : LookupInSpecialHolder<false>(map, holder); | 60 if (IsFound()) return; |
81 if (IsFound()) return; | |
82 } | |
83 | 61 |
84 IsElement() ? NextInternal<true>(map, holder) | 62 // Continue lookup if lookup on current holder failed. |
85 : NextInternal<false>(map, holder); | |
86 } | |
87 | |
88 template <bool is_element> | |
89 void LookupIterator::NextInternal(Map* map, JSReceiver* holder) { | |
90 do { | 63 do { |
91 JSReceiver* maybe_holder = NextHolder(map); | 64 JSReceiver* maybe_holder = NextHolder(map); |
92 if (maybe_holder == nullptr) { | 65 if (maybe_holder == nullptr) { |
93 if (interceptor_state_ == InterceptorState::kSkipNonMasking) { | 66 if (interceptor_state_ == InterceptorState::kSkipNonMasking) { |
94 RestartLookupForNonMaskingInterceptors<is_element>(); | 67 RestartLookupForNonMaskingInterceptors(); |
95 return; | 68 return; |
96 } | 69 } |
97 if (holder != *holder_) holder_ = handle(holder, isolate_); | 70 break; |
98 return; | |
99 } | 71 } |
100 holder = maybe_holder; | 72 holder = maybe_holder; |
101 map = holder->map(); | 73 map = holder->map(); |
102 state_ = LookupInHolder<is_element>(map, holder); | 74 state_ = LookupInHolder(map, holder); |
103 } while (!IsFound()); | 75 } while (!IsFound()); |
104 | 76 |
105 holder_ = handle(holder, isolate_); | 77 if (holder != *holder_) holder_ = handle(holder, isolate_); |
106 } | 78 } |
107 | 79 |
108 template <bool is_element> | 80 |
109 void LookupIterator::RestartInternal(InterceptorState interceptor_state) { | 81 void LookupIterator::RestartInternal(InterceptorState interceptor_state) { |
| 82 state_ = NOT_FOUND; |
110 interceptor_state_ = interceptor_state; | 83 interceptor_state_ = interceptor_state; |
111 property_details_ = PropertyDetails::Empty(); | 84 property_details_ = PropertyDetails::Empty(); |
112 Start<is_element>(); | 85 holder_ = initial_holder_; |
| 86 number_ = DescriptorArray::kNotFound; |
| 87 Next(); |
113 } | 88 } |
114 | 89 |
115 template void LookupIterator::RestartInternal<true>(InterceptorState); | |
116 template void LookupIterator::RestartInternal<false>(InterceptorState); | |
117 | 90 |
118 // static | 91 // static |
119 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( | 92 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( |
120 Isolate* isolate, Handle<Object> receiver, uint32_t index) { | 93 Isolate* isolate, Handle<Object> receiver, uint32_t index) { |
121 // Strings are the only objects with properties (only elements) directly on | 94 // Strings are the only objects with properties (only elements) directly on |
122 // the wrapper. Hence we can skip generating the wrapper for all other cases. | 95 // the wrapper. Hence we can skip generating the wrapper for all other cases. |
123 if (index != kMaxUInt32 && receiver->IsString() && | 96 if (index != kMaxUInt32 && receiver->IsString() && |
124 index < static_cast<uint32_t>(String::cast(*receiver)->length())) { | 97 index < static_cast<uint32_t>(String::cast(*receiver)->length())) { |
125 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native | 98 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native |
126 // context, ensuring that we don't leak it into JS? | 99 // context, ensuring that we don't leak it into JS? |
127 Handle<JSFunction> constructor = isolate->string_function(); | 100 Handle<JSFunction> constructor = isolate->string_function(); |
128 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); | 101 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); |
129 Handle<JSValue>::cast(result)->set_value(*receiver); | 102 Handle<JSValue>::cast(result)->set_value(*receiver); |
130 return result; | 103 return result; |
131 } | 104 } |
132 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); | 105 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); |
133 if (root->IsNull()) { | 106 if (root->IsNull()) { |
134 unsigned int magic = 0xbbbbbbbb; | 107 unsigned int magic = 0xbbbbbbbb; |
135 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); | 108 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); |
136 } | 109 } |
137 return Handle<JSReceiver>::cast(root); | 110 return Handle<JSReceiver>::cast(root); |
138 } | 111 } |
139 | 112 |
140 | 113 |
141 Handle<Map> LookupIterator::GetReceiverMap() const { | 114 Handle<Map> LookupIterator::GetReceiverMap() const { |
142 if (receiver_->IsNumber()) return factory()->heap_number_map(); | 115 if (receiver_->IsNumber()) return factory()->heap_number_map(); |
143 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); | 116 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); |
144 } | 117 } |
145 | 118 |
| 119 |
| 120 Handle<JSObject> LookupIterator::GetStoreTarget() const { |
| 121 if (receiver_->IsJSGlobalProxy()) { |
| 122 Object* prototype = JSGlobalProxy::cast(*receiver_)->map()->prototype(); |
| 123 if (!prototype->IsNull()) { |
| 124 return handle(JSGlobalObject::cast(prototype), isolate_); |
| 125 } |
| 126 } |
| 127 return Handle<JSObject>::cast(receiver_); |
| 128 } |
| 129 |
| 130 |
146 bool LookupIterator::HasAccess() const { | 131 bool LookupIterator::HasAccess() const { |
147 DCHECK_EQ(ACCESS_CHECK, state_); | 132 DCHECK_EQ(ACCESS_CHECK, state_); |
148 return isolate_->MayAccess(handle(isolate_->context()), | 133 return isolate_->MayAccess(handle(isolate_->context()), |
149 GetHolder<JSObject>()); | 134 GetHolder<JSObject>()); |
150 } | 135 } |
151 | 136 |
152 template <bool is_element> | 137 |
153 void LookupIterator::ReloadPropertyInformation() { | 138 void LookupIterator::ReloadPropertyInformation() { |
154 state_ = BEFORE_PROPERTY; | 139 state_ = BEFORE_PROPERTY; |
155 interceptor_state_ = InterceptorState::kUninitialized; | 140 interceptor_state_ = InterceptorState::kUninitialized; |
156 state_ = LookupInHolder<is_element>(holder_->map(), *holder_); | 141 state_ = LookupInHolder(holder_->map(), *holder_); |
157 DCHECK(IsFound() || !holder_->HasFastProperties()); | 142 DCHECK(IsFound() || !holder_->HasFastProperties()); |
158 } | 143 } |
159 | 144 |
160 bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { | 145 bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { |
161 DisallowHeapAllocation no_gc; | 146 DisallowHeapAllocation no_gc; |
162 | 147 |
163 Object* context = heap()->native_contexts_list(); | 148 Object* context = heap()->native_contexts_list(); |
164 while (!context->IsUndefined()) { | 149 while (!context->IsUndefined()) { |
165 Context* current_context = Context::cast(context); | 150 Context* current_context = Context::cast(context); |
166 if (current_context->get(index) == *holder_) { | 151 if (current_context->get(index) == *holder_) { |
167 return true; | 152 return true; |
168 } | 153 } |
169 context = current_context->get(Context::NEXT_CONTEXT_LINK); | 154 context = current_context->get(Context::NEXT_CONTEXT_LINK); |
170 } | 155 } |
171 return false; | 156 return false; |
172 } | 157 } |
173 | 158 |
174 void LookupIterator::InternalUpdateProtector() { | 159 void LookupIterator::UpdateProtector() { |
| 160 if (!FLAG_harmony_species) return; |
| 161 |
| 162 if (IsElement()) return; |
175 if (isolate_->bootstrapper()->IsActive()) return; | 163 if (isolate_->bootstrapper()->IsActive()) return; |
176 if (!isolate_->IsArraySpeciesLookupChainIntact()) return; | 164 if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
177 | 165 |
178 if (*name_ == heap()->constructor_string()) { | 166 if (*name_ == *isolate_->factory()->constructor_string()) { |
179 // Setting the constructor property could change an instance's @@species | 167 // Setting the constructor property could change an instance's @@species |
180 if (holder_->IsJSArray()) { | 168 if (holder_->IsJSArray()) { |
181 isolate_->CountUsage( | 169 isolate_->CountUsage( |
182 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); | 170 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); |
183 isolate_->InvalidateArraySpeciesProtector(); | 171 isolate_->InvalidateArraySpeciesProtector(); |
184 } else if (holder_->map()->is_prototype_map()) { | 172 } else if (holder_->map()->is_prototype_map()) { |
185 // Setting the constructor of Array.prototype of any realm also needs | 173 // Setting the constructor of Array.prototype of any realm also needs |
186 // to invalidate the species protector | 174 // to invalidate the species protector |
187 if (HolderIsInContextIndex(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { | 175 if (HolderIsInContextIndex(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { |
188 isolate_->CountUsage(v8::Isolate::UseCounterFeature:: | 176 isolate_->CountUsage(v8::Isolate::UseCounterFeature:: |
189 kArrayPrototypeConstructorModified); | 177 kArrayPrototypeConstructorModified); |
190 isolate_->InvalidateArraySpeciesProtector(); | 178 isolate_->InvalidateArraySpeciesProtector(); |
191 } | 179 } |
192 } | 180 } |
193 } else if (*name_ == heap()->species_symbol()) { | 181 } else if (*name_ == *isolate_->factory()->species_symbol()) { |
194 // Setting the Symbol.species property of any Array constructor invalidates | 182 // Setting the Symbol.species property of any Array constructor invalidates |
195 // the species protector | 183 // the species protector |
196 if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { | 184 if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { |
197 isolate_->CountUsage( | 185 isolate_->CountUsage( |
198 v8::Isolate::UseCounterFeature::kArraySpeciesModified); | 186 v8::Isolate::UseCounterFeature::kArraySpeciesModified); |
199 isolate_->InvalidateArraySpeciesProtector(); | 187 isolate_->InvalidateArraySpeciesProtector(); |
200 } | 188 } |
201 } | 189 } |
202 } | 190 } |
203 | 191 |
(...skipping 29 matching lines...) Expand all Loading... |
233 if (old_map.is_identical_to(new_map)) { | 221 if (old_map.is_identical_to(new_map)) { |
234 // Update the property details if the representation was None. | 222 // Update the property details if the representation was None. |
235 if (representation().IsNone()) { | 223 if (representation().IsNone()) { |
236 property_details_ = | 224 property_details_ = |
237 new_map->instance_descriptors()->GetDetails(descriptor_number()); | 225 new_map->instance_descriptors()->GetDetails(descriptor_number()); |
238 } | 226 } |
239 return; | 227 return; |
240 } | 228 } |
241 | 229 |
242 JSObject::MigrateToMap(holder, new_map); | 230 JSObject::MigrateToMap(holder, new_map); |
243 ReloadPropertyInformation<false>(); | 231 ReloadPropertyInformation(); |
244 } | 232 } |
245 | 233 |
246 | 234 |
247 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, | 235 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
248 PropertyAttributes attributes) { | 236 PropertyAttributes attributes) { |
249 DCHECK(state_ == DATA || state_ == ACCESSOR); | 237 DCHECK(state_ == DATA || state_ == ACCESSOR); |
250 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 238 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
251 Handle<JSObject> holder = GetHolder<JSObject>(); | 239 Handle<JSObject> holder = GetHolder<JSObject>(); |
252 if (IsElement()) { | 240 if (IsElement()) { |
253 DCHECK(!holder->HasFixedTypedArrayElements()); | 241 DCHECK(!holder->HasFixedTypedArrayElements()); |
254 DCHECK(attributes != NONE || !holder->HasFastElements()); | 242 DCHECK(attributes != NONE || !holder->HasFastElements()); |
255 Handle<FixedArrayBase> elements(holder->elements()); | 243 Handle<FixedArrayBase> elements(holder->elements()); |
256 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, | 244 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, |
257 attributes); | 245 attributes); |
258 ReloadPropertyInformation<true>(); | 246 } else if (!holder->HasFastProperties()) { |
| 247 PropertyDetails details(attributes, v8::internal::DATA, 0, |
| 248 PropertyCellType::kMutable); |
| 249 JSObject::SetNormalizedProperty(holder, name(), value, details); |
259 } else { | 250 } else { |
260 if (!holder->HasFastProperties()) { | 251 Handle<Map> old_map(holder->map(), isolate_); |
261 PropertyDetails details(attributes, v8::internal::DATA, 0, | 252 Handle<Map> new_map = Map::ReconfigureExistingProperty( |
262 PropertyCellType::kMutable); | 253 old_map, descriptor_number(), i::kData, attributes); |
263 JSObject::SetNormalizedProperty(holder, name(), value, details); | 254 new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value); |
264 } else { | 255 JSObject::MigrateToMap(holder, new_map); |
265 Handle<Map> old_map(holder->map(), isolate_); | |
266 Handle<Map> new_map = Map::ReconfigureExistingProperty( | |
267 old_map, descriptor_number(), i::kData, attributes); | |
268 new_map = | |
269 Map::PrepareForDataProperty(new_map, descriptor_number(), value); | |
270 JSObject::MigrateToMap(holder, new_map); | |
271 } | |
272 ReloadPropertyInformation<false>(); | |
273 } | 256 } |
274 | 257 |
| 258 ReloadPropertyInformation(); |
275 WriteDataValue(value); | 259 WriteDataValue(value); |
276 | 260 |
277 #if VERIFY_HEAP | 261 #if VERIFY_HEAP |
278 if (FLAG_verify_heap) { | 262 if (FLAG_verify_heap) { |
279 holder->JSObjectVerify(); | 263 holder->JSObjectVerify(); |
280 } | 264 } |
281 #endif | 265 #endif |
282 } | 266 } |
283 | 267 |
284 // Can only be called when the receiver is a JSObject. JSProxy has to be handled | 268 // Can only be called when the receiver is a JSObject. JSProxy has to be handled |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 Handle<Map> transition = transition_map(); | 316 Handle<Map> transition = transition_map(); |
333 bool simple_transition = transition->GetBackPointer() == receiver->map(); | 317 bool simple_transition = transition->GetBackPointer() == receiver->map(); |
334 JSObject::MigrateToMap(receiver, transition); | 318 JSObject::MigrateToMap(receiver, transition); |
335 | 319 |
336 if (simple_transition) { | 320 if (simple_transition) { |
337 int number = transition->LastAdded(); | 321 int number = transition->LastAdded(); |
338 number_ = static_cast<uint32_t>(number); | 322 number_ = static_cast<uint32_t>(number); |
339 property_details_ = transition->GetLastDescriptorDetails(); | 323 property_details_ = transition->GetLastDescriptorDetails(); |
340 state_ = DATA; | 324 state_ = DATA; |
341 } else { | 325 } else { |
342 ReloadPropertyInformation<false>(); | 326 ReloadPropertyInformation(); |
343 } | 327 } |
344 } | 328 } |
345 | 329 |
346 | 330 |
347 void LookupIterator::Delete() { | 331 void LookupIterator::Delete() { |
348 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); | 332 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); |
349 if (IsElement()) { | 333 if (IsElement()) { |
350 Handle<JSObject> object = Handle<JSObject>::cast(holder); | 334 Handle<JSObject> object = Handle<JSObject>::cast(holder); |
351 ElementsAccessor* accessor = object->GetElementsAccessor(); | 335 ElementsAccessor* accessor = object->GetElementsAccessor(); |
352 accessor->Delete(object, number_); | 336 accessor->Delete(object, number_); |
353 } else { | 337 } else { |
354 PropertyNormalizationMode mode = holder->map()->is_prototype_map() | 338 PropertyNormalizationMode mode = holder->map()->is_prototype_map() |
355 ? KEEP_INOBJECT_PROPERTIES | 339 ? KEEP_INOBJECT_PROPERTIES |
356 : CLEAR_INOBJECT_PROPERTIES; | 340 : CLEAR_INOBJECT_PROPERTIES; |
357 | 341 |
358 if (holder->HasFastProperties()) { | 342 if (holder->HasFastProperties()) { |
359 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, | 343 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, |
360 "DeletingProperty"); | 344 "DeletingProperty"); |
361 ReloadPropertyInformation<false>(); | 345 ReloadPropertyInformation(); |
362 } | 346 } |
363 // TODO(verwaest): Get rid of the name_ argument. | 347 // TODO(verwaest): Get rid of the name_ argument. |
364 JSReceiver::DeleteNormalizedProperty(holder, name_, number_); | 348 JSReceiver::DeleteNormalizedProperty(holder, name_, number_); |
365 if (holder->IsJSObject()) { | 349 if (holder->IsJSObject()) { |
366 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder)); | 350 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder)); |
367 } | 351 } |
368 } | 352 } |
369 state_ = NOT_FOUND; | 353 state_ = NOT_FOUND; |
370 } | 354 } |
371 | 355 |
372 | 356 |
373 void LookupIterator::TransitionToAccessorProperty( | 357 void LookupIterator::TransitionToAccessorProperty( |
374 AccessorComponent component, Handle<Object> accessor, | 358 AccessorComponent component, Handle<Object> accessor, |
375 PropertyAttributes attributes) { | 359 PropertyAttributes attributes) { |
376 DCHECK(!accessor->IsNull()); | 360 DCHECK(!accessor->IsNull()); |
377 // Can only be called when the receiver is a JSObject. JSProxy has to be | 361 // Can only be called when the receiver is a JSObject. JSProxy has to be |
378 // handled via a trap. Adding properties to primitive values is not | 362 // handled via a trap. Adding properties to primitive values is not |
379 // observable. | 363 // observable. |
380 Handle<JSObject> receiver = GetStoreTarget(); | 364 Handle<JSObject> receiver = GetStoreTarget(); |
381 | 365 |
382 if (!IsElement() && !receiver->map()->is_dictionary_map()) { | 366 if (!IsElement() && !receiver->map()->is_dictionary_map()) { |
383 holder_ = receiver; | 367 holder_ = receiver; |
384 Handle<Map> old_map(receiver->map(), isolate_); | 368 Handle<Map> old_map(receiver->map(), isolate_); |
385 Handle<Map> new_map = Map::TransitionToAccessorProperty( | 369 Handle<Map> new_map = Map::TransitionToAccessorProperty( |
386 old_map, name_, component, accessor, attributes); | 370 old_map, name_, component, accessor, attributes); |
387 JSObject::MigrateToMap(receiver, new_map); | 371 JSObject::MigrateToMap(receiver, new_map); |
388 | 372 |
389 ReloadPropertyInformation<false>(); | 373 ReloadPropertyInformation(); |
390 | 374 |
391 if (!new_map->is_dictionary_map()) return; | 375 if (!new_map->is_dictionary_map()) return; |
392 } | 376 } |
393 | 377 |
394 Handle<AccessorPair> pair; | 378 Handle<AccessorPair> pair; |
395 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { | 379 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { |
396 pair = Handle<AccessorPair>::cast(GetAccessors()); | 380 pair = Handle<AccessorPair>::cast(GetAccessors()); |
397 // If the component and attributes are identical, nothing has to be done. | 381 // If the component and attributes are identical, nothing has to be done. |
398 if (pair->get(component) == *accessor) { | 382 if (pair->get(component) == *accessor) { |
399 if (property_details().attributes() == attributes) return; | 383 if (property_details().attributes() == attributes) return; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 if (receiver->HasSlowArgumentsElements()) { | 423 if (receiver->HasSlowArgumentsElements()) { |
440 FixedArray* parameter_map = FixedArray::cast(receiver->elements()); | 424 FixedArray* parameter_map = FixedArray::cast(receiver->elements()); |
441 uint32_t length = parameter_map->length() - 2; | 425 uint32_t length = parameter_map->length() - 2; |
442 if (number_ < length) { | 426 if (number_ < length) { |
443 parameter_map->set(number_ + 2, heap()->the_hole_value()); | 427 parameter_map->set(number_ + 2, heap()->the_hole_value()); |
444 } | 428 } |
445 FixedArray::cast(receiver->elements())->set(1, *dictionary); | 429 FixedArray::cast(receiver->elements())->set(1, *dictionary); |
446 } else { | 430 } else { |
447 receiver->set_elements(*dictionary); | 431 receiver->set_elements(*dictionary); |
448 } | 432 } |
449 | |
450 ReloadPropertyInformation<true>(); | |
451 } else { | 433 } else { |
452 PropertyNormalizationMode mode = receiver->map()->is_prototype_map() | 434 PropertyNormalizationMode mode = receiver->map()->is_prototype_map() |
453 ? KEEP_INOBJECT_PROPERTIES | 435 ? KEEP_INOBJECT_PROPERTIES |
454 : CLEAR_INOBJECT_PROPERTIES; | 436 : CLEAR_INOBJECT_PROPERTIES; |
455 // Normalize object to make this operation simple. | 437 // Normalize object to make this operation simple. |
456 JSObject::NormalizeProperties(receiver, mode, 0, | 438 JSObject::NormalizeProperties(receiver, mode, 0, |
457 "TransitionToAccessorPair"); | 439 "TransitionToAccessorPair"); |
458 | 440 |
459 JSObject::SetNormalizedProperty(receiver, name_, pair, details); | 441 JSObject::SetNormalizedProperty(receiver, name_, pair, details); |
460 JSObject::ReoptimizeIfPrototype(receiver); | 442 JSObject::ReoptimizeIfPrototype(receiver); |
| 443 } |
461 | 444 |
462 ReloadPropertyInformation<false>(); | 445 ReloadPropertyInformation(); |
463 } | |
464 } | 446 } |
465 | 447 |
466 | 448 |
467 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { | 449 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
468 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); | 450 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
469 // Optimization that only works if configuration_ is not mutable. | 451 // Optimization that only works if configuration_ is not mutable. |
470 if (!check_prototype_chain()) return true; | 452 if (!check_prototype_chain()) return true; |
471 DisallowHeapAllocation no_gc; | 453 DisallowHeapAllocation no_gc; |
472 if (*receiver_ == *holder_) return true; | 454 if (*receiver_ == *holder_) return true; |
473 if (!receiver_->IsJSReceiver()) return false; | 455 if (!receiver_->IsJSReceiver()) return false; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 handle(JSObject::cast(*holder)->global_dictionary()); | 575 handle(JSObject::cast(*holder)->global_dictionary()); |
594 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, | 576 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, |
595 property_details_); | 577 property_details_); |
596 } else { | 578 } else { |
597 NameDictionary* property_dictionary = holder->property_dictionary(); | 579 NameDictionary* property_dictionary = holder->property_dictionary(); |
598 property_dictionary->ValueAtPut(dictionary_entry(), *value); | 580 property_dictionary->ValueAtPut(dictionary_entry(), *value); |
599 } | 581 } |
600 } | 582 } |
601 | 583 |
602 | 584 |
| 585 bool LookupIterator::HasInterceptor(Map* map) const { |
| 586 if (IsElement()) return map->has_indexed_interceptor(); |
| 587 return map->has_named_interceptor(); |
| 588 } |
| 589 |
| 590 |
603 bool LookupIterator::SkipInterceptor(JSObject* holder) { | 591 bool LookupIterator::SkipInterceptor(JSObject* holder) { |
604 auto info = GetInterceptor(holder); | 592 auto info = GetInterceptor(holder); |
605 // TODO(dcarney): check for symbol/can_intercept_symbols here as well. | 593 // TODO(dcarney): check for symbol/can_intercept_symbols here as well. |
606 if (info->non_masking()) { | 594 if (info->non_masking()) { |
607 switch (interceptor_state_) { | 595 switch (interceptor_state_) { |
608 case InterceptorState::kUninitialized: | 596 case InterceptorState::kUninitialized: |
609 interceptor_state_ = InterceptorState::kSkipNonMasking; | 597 interceptor_state_ = InterceptorState::kSkipNonMasking; |
610 // Fall through. | 598 // Fall through. |
611 case InterceptorState::kSkipNonMasking: | 599 case InterceptorState::kSkipNonMasking: |
612 return true; | 600 return true; |
613 case InterceptorState::kProcessNonMasking: | 601 case InterceptorState::kProcessNonMasking: |
614 return false; | 602 return false; |
615 } | 603 } |
616 } | 604 } |
617 return interceptor_state_ == InterceptorState::kProcessNonMasking; | 605 return interceptor_state_ == InterceptorState::kProcessNonMasking; |
618 } | 606 } |
619 | 607 |
| 608 |
620 JSReceiver* LookupIterator::NextHolder(Map* map) { | 609 JSReceiver* LookupIterator::NextHolder(Map* map) { |
621 DisallowHeapAllocation no_gc; | 610 DisallowHeapAllocation no_gc; |
622 if (map->prototype() == heap()->null_value()) return NULL; | 611 if (!map->prototype()->IsJSReceiver()) return NULL; |
623 | 612 |
624 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); | 613 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); |
625 | 614 |
626 if (!check_prototype_chain() && | 615 if (!check_prototype_chain() && |
627 !(check_hidden() && map->has_hidden_prototype()) && | 616 !(check_hidden() && map->has_hidden_prototype()) && |
628 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even | 617 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even |
629 // when not checking other hidden prototypes. | 618 // when not checking other hidden prototypes. |
630 !map->IsJSGlobalProxyMap()) { | 619 !map->IsJSGlobalProxyMap()) { |
631 return NULL; | 620 return NULL; |
632 } | 621 } |
633 | 622 |
634 return JSReceiver::cast(map->prototype()); | 623 return JSReceiver::cast(map->prototype()); |
635 } | 624 } |
636 | 625 |
637 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { | 626 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { |
638 DCHECK(!IsElement()); | 627 DCHECK(!IsElement()); |
639 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; | 628 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; |
640 | 629 |
641 Handle<String> name_string = Handle<String>::cast(name_); | 630 Handle<String> name_string = Handle<String>::cast(name_); |
642 if (name_string->length() == 0) return NOT_FOUND; | 631 if (name_string->length() == 0) return NOT_FOUND; |
643 | 632 |
644 return IsSpecialIndex(isolate_->unicode_cache(), *name_string) | 633 return IsSpecialIndex(isolate_->unicode_cache(), *name_string) |
645 ? INTEGER_INDEXED_EXOTIC | 634 ? INTEGER_INDEXED_EXOTIC |
646 : NOT_FOUND; | 635 : NOT_FOUND; |
647 } | 636 } |
648 | 637 |
649 namespace { | 638 LookupIterator::State LookupIterator::LookupInHolder(Map* const map, |
650 | 639 JSReceiver* const holder) { |
651 template <bool is_element> | |
652 bool HasInterceptor(Map* map) { | |
653 return is_element ? map->has_indexed_interceptor() | |
654 : map->has_named_interceptor(); | |
655 } | |
656 | |
657 } // namespace | |
658 | |
659 template <bool is_element> | |
660 LookupIterator::State LookupIterator::LookupInSpecialHolder( | |
661 Map* const map, JSReceiver* const holder) { | |
662 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); | 640 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
| 641 DisallowHeapAllocation no_gc; |
| 642 if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
| 643 return LookupNonMaskingInterceptorInHolder(map, holder); |
| 644 } |
663 switch (state_) { | 645 switch (state_) { |
664 case NOT_FOUND: | 646 case NOT_FOUND: |
665 if (map->IsJSProxyMap()) { | 647 if (map->IsJSProxyMap()) { |
666 if (is_element || !name_->IsPrivate()) return JSPROXY; | 648 if (IsElement() || !name_->IsPrivate()) return JSPROXY; |
667 } | 649 } |
668 if (map->is_access_check_needed()) { | 650 if (map->is_access_check_needed()) { |
669 if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; | 651 if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK; |
670 } | 652 } |
671 // Fall through. | 653 // Fall through. |
672 case ACCESS_CHECK: | 654 case ACCESS_CHECK: |
673 if (check_interceptor() && HasInterceptor<is_element>(map) && | 655 if (check_interceptor() && HasInterceptor(map) && |
674 !SkipInterceptor(JSObject::cast(holder))) { | 656 !SkipInterceptor(JSObject::cast(holder))) { |
675 if (is_element || !name_->IsPrivate()) return INTERCEPTOR; | 657 if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR; |
676 } | 658 } |
677 // Fall through. | 659 // Fall through. |
678 case INTERCEPTOR: | 660 case INTERCEPTOR: |
679 if (!is_element && map->IsJSGlobalObjectMap()) { | 661 if (IsElement()) { |
| 662 JSObject* js_object = JSObject::cast(holder); |
| 663 ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| 664 FixedArrayBase* backing_store = js_object->elements(); |
| 665 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
| 666 if (number_ == kMaxUInt32) { |
| 667 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
| 668 } |
| 669 property_details_ = accessor->GetDetails(js_object, number_); |
| 670 } else if (!map->is_dictionary_map()) { |
| 671 DescriptorArray* descriptors = map->instance_descriptors(); |
| 672 int number = descriptors->SearchWithCache(isolate_, *name_, map); |
| 673 if (number == DescriptorArray::kNotFound) return NotFound(holder); |
| 674 number_ = static_cast<uint32_t>(number); |
| 675 property_details_ = descriptors->GetDetails(number_); |
| 676 } else if (map->IsJSGlobalObjectMap()) { |
680 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); | 677 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
681 int number = dict->FindEntry(name_); | 678 int number = dict->FindEntry(name_); |
682 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; | 679 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
683 number_ = static_cast<uint32_t>(number); | 680 number_ = static_cast<uint32_t>(number); |
684 DCHECK(dict->ValueAt(number_)->IsPropertyCell()); | 681 DCHECK(dict->ValueAt(number_)->IsPropertyCell()); |
685 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); | 682 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
686 if (cell->value()->IsTheHole()) return NOT_FOUND; | 683 if (cell->value()->IsTheHole()) return NOT_FOUND; |
687 property_details_ = cell->property_details(); | 684 property_details_ = cell->property_details(); |
688 has_property_ = true; | 685 } else { |
689 switch (property_details_.kind()) { | 686 NameDictionary* dict = holder->property_dictionary(); |
690 case v8::internal::kData: | 687 int number = dict->FindEntry(name_); |
691 return DATA; | 688 if (number == NameDictionary::kNotFound) return NotFound(holder); |
692 case v8::internal::kAccessor: | 689 number_ = static_cast<uint32_t>(number); |
693 return ACCESSOR; | 690 property_details_ = dict->DetailsAt(number_); |
694 } | |
695 } | 691 } |
696 return LookupInRegularHolder<is_element>(map, holder); | 692 has_property_ = true; |
| 693 switch (property_details_.kind()) { |
| 694 case v8::internal::kData: |
| 695 return DATA; |
| 696 case v8::internal::kAccessor: |
| 697 return ACCESSOR; |
| 698 } |
697 case ACCESSOR: | 699 case ACCESSOR: |
698 case DATA: | 700 case DATA: |
699 return NOT_FOUND; | 701 return NOT_FOUND; |
700 case INTEGER_INDEXED_EXOTIC: | 702 case INTEGER_INDEXED_EXOTIC: |
701 case JSPROXY: | 703 case JSPROXY: |
702 case TRANSITION: | 704 case TRANSITION: |
703 UNREACHABLE(); | 705 UNREACHABLE(); |
704 } | 706 } |
705 UNREACHABLE(); | 707 UNREACHABLE(); |
706 return NOT_FOUND; | 708 return state_; |
707 } | 709 } |
708 | 710 |
709 template <bool is_element> | 711 |
710 LookupIterator::State LookupIterator::LookupInRegularHolder( | 712 LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder( |
711 Map* const map, JSReceiver* const holder) { | 713 Map* const map, JSReceiver* const holder) { |
712 DisallowHeapAllocation no_gc; | 714 switch (state_) { |
713 if (interceptor_state_ == InterceptorState::kProcessNonMasking) { | 715 case NOT_FOUND: |
714 return NOT_FOUND; | 716 if (check_interceptor() && HasInterceptor(map) && |
| 717 !SkipInterceptor(JSObject::cast(holder))) { |
| 718 return INTERCEPTOR; |
| 719 } |
| 720 // Fall through. |
| 721 default: |
| 722 return NOT_FOUND; |
715 } | 723 } |
716 | |
717 if (is_element) { | |
718 JSObject* js_object = JSObject::cast(holder); | |
719 ElementsAccessor* accessor = js_object->GetElementsAccessor(); | |
720 FixedArrayBase* backing_store = js_object->elements(); | |
721 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); | |
722 if (number_ == kMaxUInt32) { | |
723 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; | |
724 } | |
725 property_details_ = accessor->GetDetails(js_object, number_); | |
726 } else if (!map->is_dictionary_map()) { | |
727 DescriptorArray* descriptors = map->instance_descriptors(); | |
728 int number = descriptors->SearchWithCache(isolate_, *name_, map); | |
729 if (number == DescriptorArray::kNotFound) return NotFound(holder); | |
730 number_ = static_cast<uint32_t>(number); | |
731 property_details_ = descriptors->GetDetails(number_); | |
732 } else { | |
733 NameDictionary* dict = holder->property_dictionary(); | |
734 int number = dict->FindEntry(name_); | |
735 if (number == NameDictionary::kNotFound) return NotFound(holder); | |
736 number_ = static_cast<uint32_t>(number); | |
737 property_details_ = dict->DetailsAt(number_); | |
738 } | |
739 has_property_ = true; | |
740 switch (property_details_.kind()) { | |
741 case v8::internal::kData: | |
742 return DATA; | |
743 case v8::internal::kAccessor: | |
744 return ACCESSOR; | |
745 } | |
746 | |
747 UNREACHABLE(); | 724 UNREACHABLE(); |
748 return state_; | 725 return state_; |
749 } | 726 } |
750 | 727 |
751 } // namespace internal | 728 } // namespace internal |
752 } // namespace v8 | 729 } // namespace v8 |
OLD | NEW |