Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: src/lookup.cc

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

Powered by Google App Engine
This is Rietveld 408576698