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