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

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

Issue 2164573003: [turbofan] Introduce a TransitionElementsKind simplified operator. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix the runtime fallback. Created 4 years, 5 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/effect-control-linearizer.cc ('k') | src/compiler/opcodes.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 470 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 } 481 }
482 482
483 483
484 Reduction JSNativeContextSpecialization::ReduceElementAccess( 484 Reduction JSNativeContextSpecialization::ReduceElementAccess(
485 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, 485 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
486 AccessMode access_mode, LanguageMode language_mode, 486 AccessMode access_mode, LanguageMode language_mode,
487 KeyedAccessStoreMode store_mode) { 487 KeyedAccessStoreMode store_mode) {
488 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || 488 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
489 node->opcode() == IrOpcode::kJSStoreProperty); 489 node->opcode() == IrOpcode::kJSStoreProperty);
490 Node* receiver = NodeProperties::GetValueInput(node, 0); 490 Node* receiver = NodeProperties::GetValueInput(node, 0);
491 Node* context = NodeProperties::GetContextInput(node);
492 Node* effect = NodeProperties::GetEffectInput(node); 491 Node* effect = NodeProperties::GetEffectInput(node);
493 Node* control = NodeProperties::GetControlInput(node); 492 Node* control = NodeProperties::GetControlInput(node);
494 Node* frame_state = NodeProperties::FindFrameStateBefore(node); 493 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
495 494
496 // Not much we can do if deoptimization support is disabled. 495 // Not much we can do if deoptimization support is disabled.
497 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 496 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
498 497
499 // TODO(bmeurer): Add support for non-standard stores. 498 // TODO(bmeurer): Add support for non-standard stores.
500 if (store_mode != STANDARD_STORE) return NoChange(); 499 if (store_mode != STANDARD_STORE) return NoChange();
501 500
(...skipping 16 matching lines...) Expand all
518 // The final states for every polymorphic branch. We join them with 517 // The final states for every polymorphic branch. We join them with
519 // Merge+Phi+EffectPhi at the bottom. 518 // Merge+Phi+EffectPhi at the bottom.
520 ZoneVector<Node*> values(zone()); 519 ZoneVector<Node*> values(zone());
521 ZoneVector<Node*> effects(zone()); 520 ZoneVector<Node*> effects(zone());
522 ZoneVector<Node*> controls(zone()); 521 ZoneVector<Node*> controls(zone());
523 522
524 // Ensure that {receiver} is a heap object. 523 // Ensure that {receiver} is a heap object.
525 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), 524 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
526 receiver, effect, control); 525 receiver, effect, control);
527 526
528 // Load the {receiver} map. The resulting effect is the dominating effect for
529 // all (polymorphic) branches.
530 Node* receiver_map = effect =
531 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
532 receiver, effect, control);
533
534 // Generate code for the various different element access patterns. 527 // Generate code for the various different element access patterns.
535 Node* fallthrough_control = control; 528 Node* fallthrough_control = control;
536 for (size_t j = 0; j < access_infos.size(); ++j) { 529 for (size_t j = 0; j < access_infos.size(); ++j) {
537 ElementAccessInfo const& access_info = access_infos[j]; 530 ElementAccessInfo const& access_info = access_infos[j];
538 Node* this_receiver = receiver; 531 Node* this_receiver = receiver;
539 Node* this_value = value; 532 Node* this_value = value;
540 Node* this_index = index; 533 Node* this_index = index;
541 Node* this_effect; 534 Node* this_effect = effect;
542 Node* this_control; 535 Node* this_control = fallthrough_control;
536
537 // Perform possible elements kind transitions.
538 for (auto transition : access_info.transitions()) {
539 Handle<Map> const transition_source = transition.first;
540 Handle<Map> const transition_target = transition.second;
541 this_effect = graph()->NewNode(
542 simplified()->TransitionElementsKind(
543 IsSimpleMapChangeTransition(transition_source->elements_kind(),
544 transition_target->elements_kind())
545 ? ElementsTransition::kFastTransition
546 : ElementsTransition::kSlowTransition),
547 receiver, jsgraph()->HeapConstant(transition_source),
548 jsgraph()->HeapConstant(transition_target), this_effect,
549 this_control);
550 }
551
552 // Load the {receiver} map.
553 Node* receiver_map = this_effect =
554 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
555 receiver, this_effect, this_control);
543 556
544 // Perform map check on {receiver}. 557 // Perform map check on {receiver}.
545 Type* receiver_type = access_info.receiver_type(); 558 Type* receiver_type = access_info.receiver_type();
546 bool receiver_is_jsarray = true; 559 bool receiver_is_jsarray = true;
547 { 560 {
548 ZoneVector<Node*> this_controls(zone()); 561 ZoneVector<Node*> this_controls(zone());
549 ZoneVector<Node*> this_effects(zone()); 562 ZoneVector<Node*> this_effects(zone());
550 size_t num_transitions = access_info.transitions().size();
551 int num_classes = access_info.receiver_type()->NumClasses(); 563 int num_classes = access_info.receiver_type()->NumClasses();
552 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); 564 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
553 i.Advance()) { 565 i.Advance()) {
554 DCHECK_LT(0, num_classes); 566 DCHECK_LT(0, num_classes);
555 Handle<Map> map = i.Current(); 567 Handle<Map> map = i.Current();
556 Node* check = 568 Node* check =
557 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 569 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
558 receiver_map, jsgraph()->Constant(map)); 570 receiver_map, jsgraph()->Constant(map));
559 if (--num_classes == 0 && num_transitions == 0 && 571 if (--num_classes == 0 && j == access_infos.size() - 1) {
560 j == access_infos.size() - 1) {
561 // Last map check on the fallthrough control path, do a conditional 572 // Last map check on the fallthrough control path, do a conditional
562 // eager deoptimization exit here. 573 // eager deoptimization exit here.
563 // TODO(turbofan): This is ugly as hell! We should probably introduce 574 // TODO(turbofan): This is ugly as hell! We should probably introduce
564 // macro-ish operators for property access that encapsulate this whole 575 // macro-ish operators for property access that encapsulate this whole
565 // mess. 576 // mess.
566 check = graph()->NewNode(simplified()->CheckIf(), check, effect, 577 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect,
567 fallthrough_control); 578 this_control);
568 this_controls.push_back(fallthrough_control); 579 this_controls.push_back(this_control);
569 this_effects.push_back(check); 580 this_effects.push_back(check);
570 fallthrough_control = nullptr; 581 fallthrough_control = nullptr;
571 } else { 582 } else {
572 Node* branch = 583 Node* branch =
573 graph()->NewNode(common()->Branch(), check, fallthrough_control); 584 graph()->NewNode(common()->Branch(), check, fallthrough_control);
574 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 585 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
575 this_effects.push_back(effect); 586 this_effects.push_back(effect);
576 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 587 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
577 } 588 }
578 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; 589 if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
579 } 590 }
580 591
581 // Generate possible elements kind transitions.
582 for (auto transition : access_info.transitions()) {
583 DCHECK_LT(0u, num_transitions);
584 Handle<Map> transition_source = transition.first;
585 Handle<Map> transition_target = transition.second;
586 Node* transition_control;
587 Node* transition_effect = effect;
588
589 // Check if {receiver} has the specified {transition_source} map.
590 Node* check = graph()->NewNode(
591 simplified()->ReferenceEqual(Type::Any()), receiver_map,
592 jsgraph()->HeapConstant(transition_source));
593 if (--num_transitions == 0 && j == access_infos.size() - 1) {
594 transition_effect =
595 graph()->NewNode(simplified()->CheckIf(), check,
596 transition_effect, fallthrough_control);
597 transition_control = fallthrough_control;
598 fallthrough_control = nullptr;
599 } else {
600 Node* branch =
601 graph()->NewNode(common()->Branch(), check, fallthrough_control);
602 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
603 transition_control = graph()->NewNode(common()->IfTrue(), branch);
604 }
605
606 // Migrate {receiver} from {transition_source} to {transition_target}.
607 if (IsSimpleMapChangeTransition(transition_source->elements_kind(),
608 transition_target->elements_kind())) {
609 // In-place migration, just store the {transition_target} map.
610 transition_effect = graph()->NewNode(
611 simplified()->StoreField(AccessBuilder::ForMap()), receiver,
612 jsgraph()->HeapConstant(transition_target), transition_effect,
613 transition_control);
614 } else {
615 // Instance migration, let the stub deal with the {receiver}.
616 TransitionElementsKindStub stub(isolate(),
617 transition_source->elements_kind(),
618 transition_target->elements_kind());
619 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
620 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0,
621 CallDescriptor::kNeedsFrameState, node->op()->properties());
622 transition_effect = graph()->NewNode(
623 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()),
624 receiver, jsgraph()->HeapConstant(transition_target), context,
625 frame_state, transition_effect, transition_control);
626 }
627
628 this_controls.push_back(transition_control);
629 this_effects.push_back(transition_effect);
630 }
631
632 // Create single chokepoint for the control. 592 // Create single chokepoint for the control.
633 int const this_control_count = static_cast<int>(this_controls.size()); 593 int const this_control_count = static_cast<int>(this_controls.size());
634 if (this_control_count == 1) { 594 if (this_control_count == 1) {
635 this_control = this_controls.front(); 595 this_control = this_controls.front();
636 this_effect = this_effects.front(); 596 this_effect = this_effects.front();
637 } else { 597 } else {
638 this_control = 598 this_control =
639 graph()->NewNode(common()->Merge(this_control_count), 599 graph()->NewNode(common()->Merge(this_control_count),
640 this_control_count, &this_controls.front()); 600 this_control_count, &this_controls.front());
641 this_effects.push_back(this_control); 601 this_effects.push_back(this_control);
642 this_effect = 602 this_effect =
643 graph()->NewNode(common()->EffectPhi(this_control_count), 603 graph()->NewNode(common()->EffectPhi(this_control_count),
644 this_control_count + 1, &this_effects.front()); 604 this_control_count + 1, &this_effects.front());
605
606 // TODO(turbofan): The effect/control linearization will not find a
607 // FrameState after the StoreField or Call that is generated for the
608 // elements kind transition above. This is because those operators
609 // don't have the kNoWrite flag on it, even though they are not
610 // observable by JavaScript.
611 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
612 this_effect, this_control);
645 } 613 }
646
647 // TODO(turbofan): The effect/control linearization will not find a
648 // FrameState after the StoreField or Call that is generated for the
649 // elements kind transition above. This is because those operators
650 // don't have the kNoWrite flag on it, even though they are not
651 // observable by JavaScript.
652 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
653 this_effect, this_control);
654 } 614 }
655 615
656 // Certain stores need a prototype chain check because shape changes 616 // Certain stores need a prototype chain check because shape changes
657 // could allow callbacks on elements in the prototype chain that are 617 // could allow callbacks on elements in the prototype chain that are
658 // not compatible with (monomorphic) keyed stores. 618 // not compatible with (monomorphic) keyed stores.
659 Handle<JSObject> holder; 619 Handle<JSObject> holder;
660 if (access_info.holder().ToHandle(&holder)) { 620 if (access_info.holder().ToHandle(&holder)) {
661 AssumePrototypesStable(receiver_type, native_context, holder); 621 AssumePrototypesStable(receiver_type, native_context, holder);
662 } 622 }
663 623
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
1074 } 1034 }
1075 1035
1076 1036
1077 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1037 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1078 return jsgraph()->simplified(); 1038 return jsgraph()->simplified();
1079 } 1039 }
1080 1040
1081 } // namespace compiler 1041 } // namespace compiler
1082 } // namespace internal 1042 } // namespace internal
1083 } // namespace v8 1043 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/effect-control-linearizer.cc ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698