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

Side by Side Diff: src/compiler/ast-graph-builder.cc

Issue 949743002: [turbofan] Variable liveness analysis for deopt (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Test tweaks Created 5 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
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/compiler/ast-graph-builder.h" 5 #include "src/compiler/ast-graph-builder.h"
6 6
7 #include "src/compiler.h" 7 #include "src/compiler.h"
8 #include "src/compiler/ast-loop-assignment-analyzer.h" 8 #include "src/compiler/ast-loop-assignment-analyzer.h"
9 #include "src/compiler/control-builders.h" 9 #include "src/compiler/control-builders.h"
10 #include "src/compiler/linkage.h" 10 #include "src/compiler/linkage.h"
11 #include "src/compiler/liveness-analyzer.h"
11 #include "src/compiler/machine-operator.h" 12 #include "src/compiler/machine-operator.h"
12 #include "src/compiler/node-matchers.h" 13 #include "src/compiler/node-matchers.h"
13 #include "src/compiler/node-properties.h" 14 #include "src/compiler/node-properties.h"
14 #include "src/compiler/operator-properties.h" 15 #include "src/compiler/operator-properties.h"
15 #include "src/full-codegen.h" 16 #include "src/full-codegen.h"
16 #include "src/parser.h" 17 #include "src/parser.h"
17 #include "src/scopes.h" 18 #include "src/scopes.h"
18 19
19 namespace v8 { 20 namespace v8 {
20 namespace internal { 21 namespace internal {
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 jsgraph_(jsgraph), 387 jsgraph_(jsgraph),
387 environment_(nullptr), 388 environment_(nullptr),
388 ast_context_(nullptr), 389 ast_context_(nullptr),
389 globals_(0, local_zone), 390 globals_(0, local_zone),
390 execution_control_(nullptr), 391 execution_control_(nullptr),
391 execution_context_(nullptr), 392 execution_context_(nullptr),
392 try_nesting_level_(0), 393 try_nesting_level_(0),
393 input_buffer_size_(0), 394 input_buffer_size_(0),
394 input_buffer_(nullptr), 395 input_buffer_(nullptr),
395 exit_control_(nullptr), 396 exit_control_(nullptr),
396 loop_assignment_analysis_(loop) { 397 loop_assignment_analysis_(loop),
398 liveness_analyzer_(new (local_zone) LivenessAnalyzer(
399 static_cast<size_t>(info->scope()->num_stack_slots()), local_zone)) {
397 InitializeAstVisitor(info->isolate(), local_zone); 400 InitializeAstVisitor(info->isolate(), local_zone);
398 } 401 }
399 402
400 403
401 Node* AstGraphBuilder::GetFunctionClosure() { 404 Node* AstGraphBuilder::GetFunctionClosure() {
402 if (!function_closure_.is_set()) { 405 if (!function_closure_.is_set()) {
403 const Operator* op = 406 const Operator* op =
404 common()->Parameter(Linkage::kJSFunctionCallClosureParamIndex); 407 common()->Parameter(Linkage::kJSFunctionCallClosureParamIndex);
405 Node* node = NewNode(op, graph()->start()); 408 Node* node = NewNode(op, graph()->start());
406 function_closure_.set(node); 409 function_closure_.set(node);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 520
518 // Emit tracing call if requested to do so. 521 // Emit tracing call if requested to do so.
519 if (FLAG_trace) { 522 if (FLAG_trace) {
520 // TODO(mstarzinger): Only traces implicit return. 523 // TODO(mstarzinger): Only traces implicit return.
521 Node* return_value = jsgraph()->UndefinedConstant(); 524 Node* return_value = jsgraph()->UndefinedConstant();
522 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); 525 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
523 } 526 }
524 527
525 // Return 'undefined' in case we can fall off the end. 528 // Return 'undefined' in case we can fall off the end.
526 BuildReturn(jsgraph()->UndefinedConstant()); 529 BuildReturn(jsgraph()->UndefinedConstant());
530
531 // Finish the basic structure of the graph.
532 environment()->UpdateControlDependency(exit_control());
533 graph()->SetEnd(NewNode(common()->End()));
Michael Starzinger 2015/03/01 21:00:56 This duplicates the end node, please don't do this
Jarin 2015/03/16 21:30:12 Great catch, bad rebase. Done.
534
535 // Compute local variable liveness information and use it to relax
536 // frame states.
537 RelaxFrameStatesWithLiveness();
Michael Starzinger 2015/03/01 21:00:56 Rather move this call into CreateGraph() a few lin
Jarin 2015/03/16 21:30:12 Done.
527 } 538 }
528 539
529 540
541 void AstGraphBuilder::RelaxFrameStatesWithLiveness() {
542 if (!FLAG_analyze_environment_liveness) return;
543
544 FrameStateRelaxer relaxer(jsgraph(), jsgraph()->UndefinedConstant(),
545 liveness_analyzer()->local_count(), local_zone());
546 Variable* arguments = info()->scope()->arguments();
547 if (arguments != nullptr && arguments->IsStackAllocated()) {
548 relaxer.Blacklist(arguments->index());
titzer 2015/02/27 21:09:55 Maybe "MarkPermanentlyLive(int index)" as a better
Jarin 2015/03/16 21:30:12 Done.
549 }
550 liveness_analyzer()->Run(&relaxer);
551 if (FLAG_trace_environment_liveness) {
552 OFStream os(stdout);
553 liveness_analyzer()->Print(os);
554 }
555 }
556
557
530 // Left-hand side can only be a property, a global or a variable slot. 558 // Left-hand side can only be a property, a global or a variable slot.
531 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 559 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
532 560
533 561
534 // Determine the left-hand side kind of an assignment. 562 // Determine the left-hand side kind of an assignment.
535 static LhsKind DetermineLhsKind(Expression* expr) { 563 static LhsKind DetermineLhsKind(Expression* expr) {
536 Property* property = expr->AsProperty(); 564 Property* property = expr->AsProperty();
537 DCHECK(expr->IsValidReferenceExpression()); 565 DCHECK(expr->IsValidReferenceExpression());
538 LhsKind lhs_kind = 566 LhsKind lhs_kind =
539 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName()) 567 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName())
540 ? NAMED_PROPERTY 568 ? NAMED_PROPERTY
541 : KEYED_PROPERTY; 569 : KEYED_PROPERTY;
542 return lhs_kind; 570 return lhs_kind;
543 } 571 }
544 572
545 573
546 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, 574 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
547 Scope* scope, 575 Scope* scope,
548 Node* control_dependency) 576 Node* control_dependency)
549 : builder_(builder), 577 : builder_(builder),
550 parameters_count_(scope->num_parameters() + 1), 578 parameters_count_(scope->num_parameters() + 1),
551 locals_count_(scope->num_stack_slots()), 579 locals_count_(scope->num_stack_slots()),
580 liveness_block_(builder_->liveness_analyzer()->New()),
552 values_(builder_->local_zone()), 581 values_(builder_->local_zone()),
553 contexts_(builder_->local_zone()), 582 contexts_(builder_->local_zone()),
554 control_dependency_(control_dependency), 583 control_dependency_(control_dependency),
555 effect_dependency_(control_dependency), 584 effect_dependency_(control_dependency),
556 parameters_node_(nullptr), 585 parameters_node_(nullptr),
557 locals_node_(nullptr), 586 locals_node_(nullptr),
558 stack_node_(nullptr) { 587 stack_node_(nullptr) {
559 DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); 588 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
560 589
561 // Bind the receiver variable. 590 // Bind the receiver variable.
562 Node* receiver = builder->graph()->NewNode(common()->Parameter(0), 591 Node* receiver = builder->graph()->NewNode(common()->Parameter(0),
563 builder->graph()->start()); 592 builder->graph()->start());
564 values()->push_back(receiver); 593 values()->push_back(receiver);
565 594
566 // Bind all parameter variables. The parameter indices are shifted by 1 595 // Bind all parameter variables. The parameter indices are shifted by 1
567 // (receiver is parameter index -1 but environment index 0). 596 // (receiver is parameter index -1 but environment index 0).
568 for (int i = 0; i < scope->num_parameters(); ++i) { 597 for (int i = 0; i < scope->num_parameters(); ++i) {
569 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1), 598 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1),
570 builder->graph()->start()); 599 builder->graph()->start());
571 values()->push_back(parameter); 600 values()->push_back(parameter);
572 } 601 }
573 602
574 // Bind all local variables to undefined. 603 // Bind all local variables to undefined.
575 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); 604 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
576 values()->insert(values()->end(), locals_count(), undefined_constant); 605 values()->insert(values()->end(), locals_count(), undefined_constant);
577 } 606 }
578 607
579 608
580 AstGraphBuilder::Environment::Environment( 609 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
581 const AstGraphBuilder::Environment* copy)
582 : builder_(copy->builder_), 610 : builder_(copy->builder_),
583 parameters_count_(copy->parameters_count_), 611 parameters_count_(copy->parameters_count_),
584 locals_count_(copy->locals_count_), 612 locals_count_(copy->locals_count_),
585 values_(copy->zone()), 613 values_(copy->zone()),
586 contexts_(copy->zone()), 614 contexts_(copy->zone()),
587 control_dependency_(copy->control_dependency_), 615 control_dependency_(copy->control_dependency_),
588 effect_dependency_(copy->effect_dependency_), 616 effect_dependency_(copy->effect_dependency_),
589 parameters_node_(copy->parameters_node_), 617 parameters_node_(copy->parameters_node_),
590 locals_node_(copy->locals_node_), 618 locals_node_(copy->locals_node_),
591 stack_node_(copy->stack_node_) { 619 stack_node_(copy->stack_node_) {
592 const size_t kStackEstimate = 7; // optimum from experimentation! 620 const size_t kStackEstimate = 7; // optimum from experimentation!
593 values_.reserve(copy->values_.size() + kStackEstimate); 621 values_.reserve(copy->values_.size() + kStackEstimate);
594 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); 622 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
595 contexts_.reserve(copy->contexts_.size()); 623 contexts_.reserve(copy->contexts_.size());
596 contexts_.insert(contexts_.begin(), copy->contexts_.begin(), 624 contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
597 copy->contexts_.end()); 625 copy->contexts_.end());
626
627 if (FLAG_analyze_environment_liveness) {
628 // Split the liveness blocks.
629 copy->liveness_block_ =
630 builder_->liveness_analyzer()->New(copy->liveness_block());
631 liveness_block_ =
632 builder_->liveness_analyzer()->New(copy->liveness_block());
633 }
598 } 634 }
599 635
600 636
637 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
638 DCHECK(variable->IsStackAllocated());
639 if (variable->IsParameter()) {
640 values()->at(variable->index() + 1) = node;
641 } else {
642 DCHECK(variable->IsStackLocal());
643 values()->at(variable->index() + parameters_count_) = node;
644 if (FLAG_analyze_environment_liveness) {
645 liveness_block()->Bind(variable->index());
646 }
647 }
648 }
649
650
651 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
652 DCHECK(variable->IsStackAllocated());
653 if (variable->IsParameter()) {
654 return values()->at(variable->index() + 1);
655 } else {
656 DCHECK(variable->IsStackLocal());
657 if (FLAG_analyze_environment_liveness) {
658 liveness_block()->Lookup(variable->index());
659 }
660 return values()->at(variable->index() + parameters_count_);
661 }
662 }
663
664
665 void AstGraphBuilder::Environment::MakeAllLocalsLive() {
titzer 2015/02/27 21:09:55 Make -> Mark?
Jarin 2015/03/16 21:30:12 Done.
666 if (FLAG_analyze_environment_liveness) {
667 for (int i = 0; i < locals_count_; i++) {
668 liveness_block()->Lookup(i);
669 }
670 }
671 }
672
673
674 AstGraphBuilder::Environment* AstGraphBuilder::Environment::Snapshot() {
Michael Starzinger 2015/03/02 10:56:34 nit: How about s/Snapshot/CopyAndShareLiveness/ he
Jarin 2015/03/16 21:30:12 Done.
675 Environment* env = new (zone()) Environment(this);
676 if (FLAG_analyze_environment_liveness) {
677 env->liveness_block_ = liveness_block();
678 }
679 return env;
680 }
681
682
601 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, 683 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
602 int offset, int count) { 684 int offset, int count) {
603 bool should_update = false; 685 bool should_update = false;
604 Node** env_values = (count == 0) ? NULL : &values()->at(offset); 686 Node** env_values = (count == 0) ? NULL : &values()->at(offset);
605 if (*state_values == NULL || (*state_values)->InputCount() != count) { 687 if (*state_values == NULL || (*state_values)->InputCount() != count) {
606 should_update = true; 688 should_update = true;
607 } else { 689 } else {
608 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); 690 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
609 for (int i = 0; i < count; i++) { 691 for (int i = 0; i < count; i++) {
610 if ((*state_values)->InputAt(i) != env_values[i]) { 692 if ((*state_values)->InputAt(i) != env_values[i]) {
(...skipping 11 matching lines...) Expand all
622 704
623 Node* AstGraphBuilder::Environment::Checkpoint( 705 Node* AstGraphBuilder::Environment::Checkpoint(
624 BailoutId ast_id, OutputFrameStateCombine combine) { 706 BailoutId ast_id, OutputFrameStateCombine combine) {
625 UpdateStateValues(&parameters_node_, 0, parameters_count()); 707 UpdateStateValues(&parameters_node_, 0, parameters_count());
626 UpdateStateValues(&locals_node_, parameters_count(), locals_count()); 708 UpdateStateValues(&locals_node_, parameters_count(), locals_count());
627 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), 709 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
628 stack_height()); 710 stack_height());
629 711
630 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine); 712 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
631 713
632 return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_, 714 Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
633 builder()->current_context(), 715 stack_node_, builder()->current_context(),
634 builder()->jsgraph()->UndefinedConstant()); 716 builder()->jsgraph()->UndefinedConstant());
717 if (FLAG_analyze_environment_liveness) {
718 liveness_block()->Checkpoint(result);
719 }
720 return result;
635 } 721 }
636 722
637 723
638 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, 724 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
639 Expression::Context kind) 725 Expression::Context kind)
640 : kind_(kind), owner_(own), outer_(own->ast_context()) { 726 : kind_(kind), owner_(own), outer_(own->ast_context()) {
641 owner()->set_ast_context(this); // Push. 727 owner()->set_ast_context(this); // Push.
642 #ifdef DEBUG 728 #ifdef DEBUG
643 original_height_ = environment()->stack_height(); 729 original_height_ = environment()->stack_height();
644 #endif 730 #endif
(...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after
1284 1370
1285 // TODO(mstarzinger): Remove bailout once everything works. 1371 // TODO(mstarzinger): Remove bailout once everything works.
1286 if (!FLAG_turbo_exceptions) SetStackOverflow(); 1372 if (!FLAG_turbo_exceptions) SetStackOverflow();
1287 } 1373 }
1288 1374
1289 1375
1290 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 1376 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1291 // TODO(turbofan): Do we really need a separate reloc-info for this? 1377 // TODO(turbofan): Do we really need a separate reloc-info for this?
1292 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); 1378 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
1293 PrepareFrameState(node, stmt->DebugBreakId()); 1379 PrepareFrameState(node, stmt->DebugBreakId());
1380 environment()->MakeAllLocalsLive();
1294 } 1381 }
1295 1382
1296 1383
1297 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 1384 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1298 Node* context = current_context(); 1385 Node* context = current_context();
1299 1386
1300 // Build a new shared function info if we cannot find one in the baseline 1387 // Build a new shared function info if we cannot find one in the baseline
1301 // code. We also have a stack overflow if the recursive compilation did. 1388 // code. We also have a stack overflow if the recursive compilation did.
1302 expr->InitializeSharedInfo(handle(info()->shared_info()->code())); 1389 expr->InitializeSharedInfo(handle(info()->shared_info()->code()));
1303 Handle<SharedFunctionInfo> shared_info = expr->shared_info(); 1390 Handle<SharedFunctionInfo> shared_info = expr->shared_info();
(...skipping 1748 matching lines...) Expand 10 before | Expand all | Expand 10 after
3052 DCHECK(contexts_.size() <= other->contexts_.size()); 3139 DCHECK(contexts_.size() <= other->contexts_.size());
3053 3140
3054 // Nothing to do if the other environment is dead. 3141 // Nothing to do if the other environment is dead.
3055 if (other->IsMarkedAsUnreachable()) return; 3142 if (other->IsMarkedAsUnreachable()) return;
3056 3143
3057 // Resurrect a dead environment by copying the contents of the other one and 3144 // Resurrect a dead environment by copying the contents of the other one and
3058 // placing a singleton merge as the new control dependency. 3145 // placing a singleton merge as the new control dependency.
3059 if (this->IsMarkedAsUnreachable()) { 3146 if (this->IsMarkedAsUnreachable()) {
3060 Node* other_control = other->control_dependency_; 3147 Node* other_control = other->control_dependency_;
3061 Node* inputs[] = {other_control}; 3148 Node* inputs[] = {other_control};
3149 liveness_block_ = other->liveness_block_;
3062 control_dependency_ = 3150 control_dependency_ =
3063 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); 3151 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
3064 effect_dependency_ = other->effect_dependency_; 3152 effect_dependency_ = other->effect_dependency_;
3065 values_ = other->values_; 3153 values_ = other->values_;
3066 // TODO(titzer): make context stack heights match. 3154 // TODO(titzer): make context stack heights match.
3067 size_t min = std::min(contexts_.size(), other->contexts_.size()); 3155 size_t min = std::min(contexts_.size(), other->contexts_.size());
3068 contexts_ = other->contexts_; 3156 contexts_ = other->contexts_;
3069 contexts_.resize(min, nullptr); 3157 contexts_.resize(min, nullptr);
3070 return; 3158 return;
3071 } 3159 }
3072 3160
3161 // Record the merge for the local variable liveness calculation.
3162 // Unfortunately, we have to mirror the logic in the MergeControl method:
3163 // connect before merge or loop, or create a new merge otherwise.
3164 if (FLAG_analyze_environment_liveness) {
3165 if (GetControlDependency()->opcode() != IrOpcode::kLoop &&
3166 GetControlDependency()->opcode() != IrOpcode::kMerge) {
3167 liveness_block_ = builder_->liveness_analyzer()->New(liveness_block());
3168 }
3169 liveness_block()->AddPredecessor(other->liveness_block());
3170 }
3171
3073 // Create a merge of the control dependencies of both environments and update 3172 // Create a merge of the control dependencies of both environments and update
3074 // the current environment's control dependency accordingly. 3173 // the current environment's control dependency accordingly.
3075 Node* control = builder_->MergeControl(this->GetControlDependency(), 3174 Node* control = builder_->MergeControl(this->GetControlDependency(),
3076 other->GetControlDependency()); 3175 other->GetControlDependency());
3077 UpdateControlDependency(control); 3176 UpdateControlDependency(control);
3078 3177
3079 // Create a merge of the effect dependencies of both environments and update 3178 // Create a merge of the effect dependencies of both environments and update
3080 // the current environment's effect dependency accordingly. 3179 // the current environment's effect dependency accordingly.
3081 Node* effect = builder_->MergeEffect(this->GetEffectDependency(), 3180 Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
3082 other->GetEffectDependency(), control); 3181 other->GetEffectDependency(), control);
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
3233 // Phi does not exist yet, introduce one. 3332 // Phi does not exist yet, introduce one.
3234 value = NewPhi(inputs, value, control); 3333 value = NewPhi(inputs, value, control);
3235 value->ReplaceInput(inputs - 1, other); 3334 value->ReplaceInput(inputs - 1, other);
3236 } 3335 }
3237 return value; 3336 return value;
3238 } 3337 }
3239 3338
3240 } // namespace compiler 3339 } // namespace compiler
3241 } // namespace internal 3340 } // namespace internal
3242 } // namespace v8 3341 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698