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

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2196653002: [turbofan] Introduce a dedicated CheckMaps simplified operator. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@TurboFan_JSNativeContextSpecialization_NonElementKeyedAccess
Patch Set: Created 4 years, 4 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/compiler/js-native-context-specialization.h ('k') | src/compiler/js-typed-lowering.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 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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/compiler/js-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 136 }
137 137
138 // Ensure that {index} matches the specified {name} (if {index} is given). 138 // Ensure that {index} matches the specified {name} (if {index} is given).
139 if (index != nullptr) { 139 if (index != nullptr) {
140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), 140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
141 index, jsgraph()->HeapConstant(name)); 141 index, jsgraph()->HeapConstant(name));
142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); 142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
143 } 143 }
144 144
145 // Check for the monomorphic cases. 145 // Check for the monomorphic cases.
146 if (access_infos.size() == 1 && 146 if (access_infos.size() == 1) {
147 HasOnlyStringMaps(access_infos[0].receiver_maps())) { 147 PropertyAccessInfo access_info = access_infos.front();
148 // Monormorphic string access (ignoring the fact that there are multiple 148 if (HasOnlyStringMaps(access_info.receiver_maps())) {
149 // String maps). 149 // Monormorphic string access (ignoring the fact that there are multiple
150 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver, 150 // String maps).
151 effect, control); 151 receiver = effect = graph()->NewNode(simplified()->CheckString(),
152 receiver, effect, control);
153 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) {
154 // Monomorphic number access (we also deal with Smis here).
155 receiver = effect = graph()->NewNode(simplified()->CheckNumber(),
156 receiver, effect, control);
157 } else {
158 // Monomorphic property access.
159 effect = BuildCheckTaggedPointer(receiver, effect, control);
160 effect = BuildCheckMaps(receiver, effect, control,
161 access_info.receiver_maps());
162 }
152 163
153 // Generate the actual property access. 164 // Generate the actual property access.
154 ValueEffectControl continuation = 165 ValueEffectControl continuation =
155 BuildPropertyAccess(receiver, value, effect, control, name, 166 BuildPropertyAccess(receiver, value, effect, control, name,
156 native_context, access_infos[0], access_mode); 167 native_context, access_info, access_mode);
157 value = continuation.value(); 168 value = continuation.value();
158 effect = continuation.effect(); 169 effect = continuation.effect();
159 control = continuation.control(); 170 control = continuation.control();
160 } else if (access_infos.size() == 1 &&
161 HasOnlyNumberMaps(access_infos[0].receiver_maps())) {
162 // Monomorphic number access (we also deal with Smis here).
163 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), receiver,
164 effect, control);
165
166 // Generate the actual property access.
167 ValueEffectControl continuation =
168 BuildPropertyAccess(receiver, value, effect, control, name,
169 native_context, access_infos[0], access_mode);
170 value = continuation.value();
171 effect = continuation.effect();
172 control = continuation.control();
173 } else { 171 } else {
174 // The final states for every polymorphic branch. We join them with 172 // The final states for every polymorphic branch. We join them with
175 // Merge+Phi+EffectPhi at the bottom. 173 // Merge+Phi+EffectPhi at the bottom.
176 ZoneVector<Node*> values(zone()); 174 ZoneVector<Node*> values(zone());
177 ZoneVector<Node*> effects(zone()); 175 ZoneVector<Node*> effects(zone());
178 ZoneVector<Node*> controls(zone()); 176 ZoneVector<Node*> controls(zone());
179 177
180 // Check if {receiver} may be a number. 178 // Check if {receiver} may be a number.
181 bool receiverissmi_possible = false; 179 bool receiverissmi_possible = false;
182 for (PropertyAccessInfo const& access_info : access_infos) { 180 for (PropertyAccessInfo const& access_info : access_infos) {
183 if (HasNumberMaps(access_info.receiver_maps())) { 181 if (HasNumberMaps(access_info.receiver_maps())) {
184 receiverissmi_possible = true; 182 receiverissmi_possible = true;
185 break; 183 break;
186 } 184 }
187 } 185 }
188 186
189 // Ensure that {receiver} is a heap object. 187 // Ensure that {receiver} is a heap object.
190 Node* receiverissmi_control = nullptr; 188 Node* receiverissmi_control = nullptr;
191 Node* receiverissmi_effect = effect; 189 Node* receiverissmi_effect = effect;
192 if (receiverissmi_possible) { 190 if (receiverissmi_possible) {
193 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 191 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
194 Node* branch = graph()->NewNode(common()->Branch(), check, control); 192 Node* branch = graph()->NewNode(common()->Branch(), check, control);
195 control = graph()->NewNode(common()->IfFalse(), branch); 193 control = graph()->NewNode(common()->IfFalse(), branch);
196 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); 194 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
197 receiverissmi_effect = effect; 195 receiverissmi_effect = effect;
198 } else { 196 } else {
199 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), 197 effect = BuildCheckTaggedPointer(receiver, effect, control);
200 receiver, effect, control);
201 } 198 }
202 199
203 // Load the {receiver} map. The resulting effect is the dominating effect 200 // Load the {receiver} map. The resulting effect is the dominating effect
204 // for all (polymorphic) branches. 201 // for all (polymorphic) branches.
205 Node* receiver_map = effect = 202 Node* receiver_map = effect =
206 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 203 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
207 receiver, effect, control); 204 receiver, effect, control);
208 205
209 // Generate code for the various different property access patterns. 206 // Generate code for the various different property access patterns.
210 Node* fallthrough_control = control; 207 Node* fallthrough_control = control;
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 &access_infos)) { 424 &access_infos)) {
428 return NoChange(); 425 return NoChange();
429 } 426 }
430 427
431 // Nothing to do if we have no non-deprecated maps. 428 // Nothing to do if we have no non-deprecated maps.
432 if (access_infos.empty()) { 429 if (access_infos.empty()) {
433 return ReduceSoftDeoptimize( 430 return ReduceSoftDeoptimize(
434 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); 431 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
435 } 432 }
436 433
437 // The final states for every polymorphic branch. We join them with 434 // Ensure that {receiver} is a heap object.
438 // Merge+Phi+EffectPhi at the bottom. 435 effect = BuildCheckTaggedPointer(receiver, effect, control);
439 ZoneVector<Node*> values(zone());
440 ZoneVector<Node*> effects(zone());
441 ZoneVector<Node*> controls(zone());
442 436
443 // Ensure that {receiver} is a heap object. 437 // Check for the monomorphic case.
444 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), 438 if (access_infos.size() == 1) {
445 receiver, effect, control); 439 ElementAccessInfo access_info = access_infos.front();
446
447 // Generate code for the various different element access patterns.
448 Node* fallthrough_control = control;
449 for (size_t j = 0; j < access_infos.size(); ++j) {
450 ElementAccessInfo const& access_info = access_infos[j];
451 Node* this_receiver = receiver;
452 Node* this_value = value;
453 Node* this_index = index;
454 Node* this_effect = effect;
455 Node* this_control = fallthrough_control;
456 440
457 // Perform possible elements kind transitions. 441 // Perform possible elements kind transitions.
458 for (auto transition : access_info.transitions()) { 442 for (auto transition : access_info.transitions()) {
459 Handle<Map> const transition_source = transition.first; 443 Handle<Map> const transition_source = transition.first;
460 Handle<Map> const transition_target = transition.second; 444 Handle<Map> const transition_target = transition.second;
461 this_effect = graph()->NewNode( 445 effect = graph()->NewNode(
462 simplified()->TransitionElementsKind( 446 simplified()->TransitionElementsKind(
463 IsSimpleMapChangeTransition(transition_source->elements_kind(), 447 IsSimpleMapChangeTransition(transition_source->elements_kind(),
464 transition_target->elements_kind()) 448 transition_target->elements_kind())
465 ? ElementsTransition::kFastTransition 449 ? ElementsTransition::kFastTransition
466 : ElementsTransition::kSlowTransition), 450 : ElementsTransition::kSlowTransition),
467 receiver, jsgraph()->HeapConstant(transition_source), 451 receiver, jsgraph()->HeapConstant(transition_source),
468 jsgraph()->HeapConstant(transition_target), this_effect, 452 jsgraph()->HeapConstant(transition_target), effect, control);
469 this_control);
470 } 453 }
471 454
472 // Load the {receiver} map. 455 // TODO(turbofan): The effect/control linearization will not find a
473 Node* receiver_map = this_effect = 456 // FrameState after the StoreField or Call that is generated for the
474 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 457 // elements kind transition above. This is because those operators
475 receiver, this_effect, this_control); 458 // don't have the kNoWrite flag on it, even though they are not
459 // observable by JavaScript.
460 effect =
461 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
476 462
477 // Perform map check on {receiver}. 463 // Perform map check on the {receiver}.
478 MapList const& receiver_maps = access_info.receiver_maps(); 464 effect =
479 { 465 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
480 ZoneVector<Node*> this_controls(zone()); 466
481 ZoneVector<Node*> this_effects(zone()); 467 // Access the actual element.
482 size_t num_classes = receiver_maps.size(); 468 ValueEffectControl continuation =
483 for (Handle<Map> map : receiver_maps) { 469 BuildElementAccess(receiver, index, value, effect, control,
484 DCHECK_LT(0u, num_classes); 470 native_context, access_info, access_mode);
485 Node* check = 471 value = continuation.value();
486 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 472 effect = continuation.effect();
487 receiver_map, jsgraph()->Constant(map)); 473 control = continuation.control();
488 if (--num_classes == 0 && j == access_infos.size() - 1) { 474 } else {
489 // Last map check on the fallthrough control path, do a conditional 475 // The final states for every polymorphic branch. We join them with
490 // eager deoptimization exit here. 476 // Merge+Phi+EffectPhi at the bottom.
491 // TODO(turbofan): This is ugly as hell! We should probably introduce 477 ZoneVector<Node*> values(zone());
492 // macro-ish operators for property access that encapsulate this whole 478 ZoneVector<Node*> effects(zone());
493 // mess. 479 ZoneVector<Node*> controls(zone());
494 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, 480
495 this_control); 481 // Generate code for the various different element access patterns.
496 this_controls.push_back(this_control); 482 Node* fallthrough_control = control;
497 this_effects.push_back(check); 483 for (size_t j = 0; j < access_infos.size(); ++j) {
498 fallthrough_control = nullptr; 484 ElementAccessInfo const& access_info = access_infos[j];
485 Node* this_receiver = receiver;
486 Node* this_value = value;
487 Node* this_index = index;
488 Node* this_effect = effect;
489 Node* this_control = fallthrough_control;
490
491 // Perform possible elements kind transitions.
492 for (auto transition : access_info.transitions()) {
493 Handle<Map> const transition_source = transition.first;
494 Handle<Map> const transition_target = transition.second;
495 this_effect = graph()->NewNode(
496 simplified()->TransitionElementsKind(
497 IsSimpleMapChangeTransition(transition_source->elements_kind(),
498 transition_target->elements_kind())
499 ? ElementsTransition::kFastTransition
500 : ElementsTransition::kSlowTransition),
501 receiver, jsgraph()->HeapConstant(transition_source),
502 jsgraph()->HeapConstant(transition_target), this_effect,
503 this_control);
504 }
505
506 // Load the {receiver} map.
507 Node* receiver_map = this_effect =
508 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
509 receiver, this_effect, this_control);
510
511 // Perform map check(s) on {receiver}.
512 MapList const& receiver_maps = access_info.receiver_maps();
513 {
514 ZoneVector<Node*> this_controls(zone());
515 ZoneVector<Node*> this_effects(zone());
516 size_t num_classes = receiver_maps.size();
517 for (Handle<Map> map : receiver_maps) {
518 DCHECK_LT(0u, num_classes);
519 Node* check =
520 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
521 receiver_map, jsgraph()->Constant(map));
522 if (--num_classes == 0 && j == access_infos.size() - 1) {
523 // Last map check on the fallthrough control path, do a conditional
524 // eager deoptimization exit here.
525 // TODO(turbofan): This is ugly as hell! We should probably
526 // introduce macro-ish operators for property access that
527 // encapsulate this whole mess.
528 check = graph()->NewNode(simplified()->CheckIf(), check,
529 this_effect, this_control);
530 this_controls.push_back(this_control);
531 this_effects.push_back(check);
532 fallthrough_control = nullptr;
533 } else {
534 Node* branch = graph()->NewNode(common()->Branch(), check,
535 fallthrough_control);
536 this_controls.push_back(
537 graph()->NewNode(common()->IfTrue(), branch));
538 this_effects.push_back(effect);
539 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
540 }
541 }
542
543 // Create single chokepoint for the control.
epertoso 2016/07/29 09:34:08 nit: do you mean checkpoint?
Benedikt Meurer 2016/07/29 09:37:48 Yes.
544 int const this_control_count = static_cast<int>(this_controls.size());
545 if (this_control_count == 1) {
546 this_control = this_controls.front();
547 this_effect = this_effects.front();
499 } else { 548 } else {
500 Node* branch = 549 this_control =
501 graph()->NewNode(common()->Branch(), check, fallthrough_control); 550 graph()->NewNode(common()->Merge(this_control_count),
502 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 551 this_control_count, &this_controls.front());
503 this_effects.push_back(effect); 552 this_effects.push_back(this_control);
504 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 553 this_effect =
554 graph()->NewNode(common()->EffectPhi(this_control_count),
555 this_control_count + 1, &this_effects.front());
556
557 // TODO(turbofan): The effect/control linearization will not find a
558 // FrameState after the StoreField or Call that is generated for the
559 // elements kind transition above. This is because those operators
560 // don't have the kNoWrite flag on it, even though they are not
561 // observable by JavaScript.
562 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
563 this_effect, this_control);
505 } 564 }
506 } 565 }
507 566
508 // Create single chokepoint for the control. 567 // Certain stores need a prototype chain check because shape changes
509 int const this_control_count = static_cast<int>(this_controls.size()); 568 // could allow callbacks on elements in the prototype chain that are
510 if (this_control_count == 1) { 569 // not compatible with (monomorphic) keyed stores.
511 this_control = this_controls.front(); 570 Handle<JSObject> holder;
512 this_effect = this_effects.front(); 571 if (access_info.holder().ToHandle(&holder)) {
513 } else { 572 AssumePrototypesStable(receiver_maps, native_context, holder);
514 this_control = 573 }
515 graph()->NewNode(common()->Merge(this_control_count),
516 this_control_count, &this_controls.front());
517 this_effects.push_back(this_control);
518 this_effect =
519 graph()->NewNode(common()->EffectPhi(this_control_count),
520 this_control_count + 1, &this_effects.front());
521 574
522 // TODO(turbofan): The effect/control linearization will not find a 575 // Access the actual element.
523 // FrameState after the StoreField or Call that is generated for the 576 ValueEffectControl continuation = BuildElementAccess(
524 // elements kind transition above. This is because those operators 577 this_receiver, this_index, this_value, this_effect, this_control,
525 // don't have the kNoWrite flag on it, even though they are not 578 native_context, access_info, access_mode);
526 // observable by JavaScript. 579 values.push_back(continuation.value());
527 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, 580 effects.push_back(continuation.effect());
528 this_effect, this_control); 581 controls.push_back(continuation.control());
529 }
530 } 582 }
531 583
532 // Certain stores need a prototype chain check because shape changes 584 DCHECK_NULL(fallthrough_control);
533 // could allow callbacks on elements in the prototype chain that are 585
534 // not compatible with (monomorphic) keyed stores. 586 // Generate the final merge point for all (polymorphic) branches.
535 Handle<JSObject> holder; 587 int const control_count = static_cast<int>(controls.size());
536 if (access_info.holder().ToHandle(&holder)) { 588 if (control_count == 0) {
537 AssumePrototypesStable(receiver_maps, native_context, holder); 589 value = effect = control = jsgraph()->Dead();
590 } else if (control_count == 1) {
591 value = values.front();
592 effect = effects.front();
593 control = controls.front();
594 } else {
595 control = graph()->NewNode(common()->Merge(control_count), control_count,
596 &controls.front());
597 values.push_back(control);
598 value = graph()->NewNode(
599 common()->Phi(MachineRepresentation::kTagged, control_count),
600 control_count + 1, &values.front());
601 effects.push_back(control);
602 effect = graph()->NewNode(common()->EffectPhi(control_count),
603 control_count + 1, &effects.front());
538 } 604 }
539
540 // Access the actual element.
541 ValueEffectControl continuation = BuildElementAccess(
542 this_receiver, this_index, this_value, this_effect, this_control,
543 native_context, access_info, access_mode);
544 values.push_back(continuation.value());
545 effects.push_back(continuation.effect());
546 controls.push_back(continuation.control());
547 } 605 }
548 606
549 DCHECK_NULL(fallthrough_control);
550
551 // Generate the final merge point for all (polymorphic) branches.
552 int const control_count = static_cast<int>(controls.size());
553 if (control_count == 0) {
554 value = effect = control = jsgraph()->Dead();
555 } else if (control_count == 1) {
556 value = values.front();
557 effect = effects.front();
558 control = controls.front();
559 } else {
560 control = graph()->NewNode(common()->Merge(control_count), control_count,
561 &controls.front());
562 values.push_back(control);
563 value = graph()->NewNode(
564 common()->Phi(MachineRepresentation::kTagged, control_count),
565 control_count + 1, &values.front());
566 effects.push_back(control);
567 effect = graph()->NewNode(common()->EffectPhi(control_count),
568 control_count + 1, &effects.front());
569 }
570 ReplaceWithValue(node, value, effect, control); 607 ReplaceWithValue(node, value, effect, control);
571 return Replace(value); 608 return Replace(value);
572 } 609 }
573 610
574 template <typename KeyedICNexus> 611 template <typename KeyedICNexus>
575 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( 612 Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
576 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, 613 Node* node, Node* index, Node* value, KeyedICNexus const& nexus,
577 AccessMode access_mode, LanguageMode language_mode, 614 AccessMode access_mode, LanguageMode language_mode,
578 KeyedAccessStoreMode store_mode) { 615 KeyedAccessStoreMode store_mode) {
579 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || 616 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 field_access.machine_type = MachineType::Float64(); 822 field_access.machine_type = MachineType::Float64();
786 } 823 }
787 } else { 824 } else {
788 // Unboxed double field, we store directly to the field. 825 // Unboxed double field, we store directly to the field.
789 field_access.machine_type = MachineType::Float64(); 826 field_access.machine_type = MachineType::Float64();
790 } 827 }
791 } else if (field_type->Is(Type::TaggedSigned())) { 828 } else if (field_type->Is(Type::TaggedSigned())) {
792 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), 829 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(),
793 value, effect, control); 830 value, effect, control);
794 } else if (field_type->Is(Type::TaggedPointer())) { 831 } else if (field_type->Is(Type::TaggedPointer())) {
832 // Ensure that {value} is a HeapObject.
795 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), 833 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
796 value, effect, control); 834 value, effect, control);
797 if (field_type->NumClasses() == 1) { 835 if (field_type->NumClasses() == 1) {
798 // Emit a map check for the value. 836 // Emit a map check for the value.
799 Node* value_map = effect = 837 Node* field_map =
800 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 838 jsgraph()->Constant(field_type->Classes().Current());
801 value, effect, control); 839 effect = graph()->NewNode(simplified()->CheckMaps(1), value,
802 Node* check = graph()->NewNode( 840 field_map, effect, control);
803 simplified()->ReferenceEqual(Type::Internal()), value_map,
804 jsgraph()->Constant(field_type->Classes().Current()));
805 effect =
806 graph()->NewNode(simplified()->CheckIf(), check, effect, control);
807 } else { 841 } else {
808 DCHECK_EQ(0, field_type->NumClasses()); 842 DCHECK_EQ(0, field_type->NumClasses());
809 } 843 }
810 } else { 844 } else {
811 DCHECK(field_type->Is(Type::Tagged())); 845 DCHECK(field_type->Is(Type::Tagged()));
812 } 846 }
813 Handle<Map> transition_map; 847 Handle<Map> transition_map;
814 if (access_info.transition_map().ToHandle(&transition_map)) { 848 if (access_info.transition_map().ToHandle(&transition_map)) {
815 effect = graph()->NewNode( 849 effect = graph()->NewNode(
816 common()->BeginRegion(RegionObservability::kObservable), effect); 850 common()->BeginRegion(RegionObservability::kObservable), effect);
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 // Make sure we do not store signalling NaNs into double arrays. 994 // Make sure we do not store signalling NaNs into double arrays.
961 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 995 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
962 } 996 }
963 effect = graph()->NewNode(simplified()->StoreElement(element_access), 997 effect = graph()->NewNode(simplified()->StoreElement(element_access),
964 elements, index, value, effect, control); 998 elements, index, value, effect, control);
965 } 999 }
966 1000
967 return ValueEffectControl(value, effect, control); 1001 return ValueEffectControl(value, effect, control);
968 } 1002 }
969 1003
1004 Node* JSNativeContextSpecialization::BuildCheckMaps(
1005 Node* receiver, Node* effect, Node* control,
1006 std::vector<Handle<Map>> const& maps) {
1007 HeapObjectMatcher m(receiver);
1008 if (m.HasValue()) {
1009 Handle<Map> receiver_map(m.Value()->map(), isolate());
1010 if (receiver_map->is_stable()) {
1011 for (Handle<Map> map : maps) {
1012 if (map.is_identical_to(receiver_map)) {
1013 dependencies()->AssumeMapStable(receiver_map);
1014 return effect;
1015 }
1016 }
1017 }
1018 }
1019 int const map_input_count = static_cast<int>(maps.size());
1020 int const input_count = 1 + map_input_count + 1 + 1;
1021 Node** inputs = zone()->NewArray<Node*>(input_count);
1022 inputs[0] = receiver;
1023 for (int i = 0; i < map_input_count; ++i) {
1024 inputs[1 + i] = jsgraph()->HeapConstant(maps[i]);
1025 }
1026 inputs[input_count - 2] = effect;
1027 inputs[input_count - 1] = control;
1028 return graph()->NewNode(simplified()->CheckMaps(map_input_count), input_count,
1029 inputs);
1030 }
1031
1032 Node* JSNativeContextSpecialization::BuildCheckTaggedPointer(Node* receiver,
1033 Node* effect,
1034 Node* control) {
1035 switch (receiver->opcode()) {
1036 case IrOpcode::kHeapConstant:
1037 case IrOpcode::kJSCreate:
1038 case IrOpcode::kJSCreateArguments:
1039 case IrOpcode::kJSCreateArray:
1040 case IrOpcode::kJSCreateClosure:
1041 case IrOpcode::kJSCreateIterResultObject:
1042 case IrOpcode::kJSCreateLiteralArray:
1043 case IrOpcode::kJSCreateLiteralObject:
1044 case IrOpcode::kJSCreateLiteralRegExp:
1045 case IrOpcode::kJSConvertReceiver:
1046 case IrOpcode::kJSToName:
1047 case IrOpcode::kJSToString:
1048 case IrOpcode::kJSToObject:
1049 case IrOpcode::kJSTypeOf: {
1050 return effect;
1051 }
1052 default: {
1053 return graph()->NewNode(simplified()->CheckTaggedPointer(), receiver,
1054 effect, control);
1055 }
1056 }
1057 }
1058
970 void JSNativeContextSpecialization::AssumePrototypesStable( 1059 void JSNativeContextSpecialization::AssumePrototypesStable(
971 std::vector<Handle<Map>> const& receiver_maps, 1060 std::vector<Handle<Map>> const& receiver_maps,
972 Handle<Context> native_context, Handle<JSObject> holder) { 1061 Handle<Context> native_context, Handle<JSObject> holder) {
973 // Determine actual holder and perform prototype chain checks. 1062 // Determine actual holder and perform prototype chain checks.
974 for (auto map : receiver_maps) { 1063 for (auto map : receiver_maps) {
975 // Perform the implicit ToObject for primitives here. 1064 // Perform the implicit ToObject for primitives here.
976 // Implemented according to ES6 section 7.3.2 GetV (V, P). 1065 // Implemented according to ES6 section 7.3.2 GetV (V, P).
977 Handle<JSFunction> constructor; 1066 Handle<JSFunction> constructor;
978 if (Map::GetConstructorFunction(map, native_context) 1067 if (Map::GetConstructorFunction(map, native_context)
979 .ToHandle(&constructor)) { 1068 .ToHandle(&constructor)) {
(...skipping 24 matching lines...) Expand all
1004 } 1093 }
1005 } 1094 }
1006 } 1095 }
1007 return true; 1096 return true;
1008 } 1097 }
1009 return false; 1098 return false;
1010 } 1099 }
1011 1100
1012 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, 1101 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver,
1013 Node* effect) { 1102 Node* effect) {
1014 NodeMatcher m(receiver); 1103 HeapObjectMatcher m(receiver);
1015 if (m.IsJSCreate()) { 1104 if (m.HasValue()) {
1105 Handle<Map> receiver_map(m.Value()->map(), isolate());
1106 if (receiver_map->is_stable()) return receiver_map;
1107 } else if (m.IsJSCreate()) {
1016 HeapObjectMatcher mtarget(m.InputAt(0)); 1108 HeapObjectMatcher mtarget(m.InputAt(0));
1017 HeapObjectMatcher mnewtarget(m.InputAt(1)); 1109 HeapObjectMatcher mnewtarget(m.InputAt(1));
1018 if (mtarget.HasValue() && mnewtarget.HasValue()) { 1110 if (mtarget.HasValue() && mnewtarget.HasValue()) {
1019 Handle<JSFunction> constructor = 1111 Handle<JSFunction> constructor =
1020 Handle<JSFunction>::cast(mtarget.Value()); 1112 Handle<JSFunction>::cast(mtarget.Value());
1021 if (constructor->has_initial_map()) { 1113 if (constructor->has_initial_map()) {
1022 Handle<Map> initial_map(constructor->initial_map(), isolate()); 1114 Handle<Map> initial_map(constructor->initial_map(), isolate());
1023 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) { 1115 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
1024 // Walk up the {effect} chain to see if the {receiver} is the 1116 // Walk up the {effect} chain to see if the {receiver} is the
1025 // dominating effect and there's no other observable write in 1117 // dominating effect and there's no other observable write in
1026 // between. 1118 // between.
1027 while (true) { 1119 while (true) {
1028 if (receiver == effect) return initial_map; 1120 if (receiver == effect) return initial_map;
1029 if (!effect->op()->HasProperty(Operator::kNoWrite) || 1121 if (!effect->op()->HasProperty(Operator::kNoWrite) ||
1030 effect->op()->EffectInputCount() != 1) { 1122 effect->op()->EffectInputCount() != 1) {
1031 break; 1123 break;
1032 } 1124 }
1033 effect = NodeProperties::GetEffectInput(effect); 1125 effect = NodeProperties::GetEffectInput(effect);
1034 } 1126 }
1035 } 1127 }
1036 } 1128 }
1037 } 1129 }
1038 } 1130 }
1131 // TODO(turbofan): Go hunting for CheckMaps(receiver) in the effect chain?
1039 return MaybeHandle<Map>(); 1132 return MaybeHandle<Map>();
1040 } 1133 }
1041 1134
1042 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( 1135 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
1043 Node* receiver) { 1136 Node* receiver) {
1044 HeapObjectMatcher m(receiver); 1137 HeapObjectMatcher m(receiver);
1045 if (m.HasValue()) { 1138 if (m.HasValue()) {
1046 return handle(m.Value()->map()->FindRootMap(), isolate()); 1139 return handle(m.Value()->map()->FindRootMap(), isolate());
1047 } else if (m.IsJSCreate()) { 1140 } else if (m.IsJSCreate()) {
1048 HeapObjectMatcher mtarget(m.InputAt(0)); 1141 HeapObjectMatcher mtarget(m.InputAt(0));
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 } 1193 }
1101 1194
1102 1195
1103 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1196 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1104 return jsgraph()->simplified(); 1197 return jsgraph()->simplified();
1105 } 1198 }
1106 1199
1107 } // namespace compiler 1200 } // namespace compiler
1108 } // namespace internal 1201 } // namespace internal
1109 } // namespace v8 1202 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/js-typed-lowering.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698