| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index b53e9b514e78ab19fe140422a23c1fb303809fa1..654486dcef724f8594a52ed6bae681612a8a438d 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -33,6 +33,7 @@
|
| #include "codegen.h"
|
| #include "full-codegen.h"
|
| #include "hashmap.h"
|
| +#include "hydrogen-environment-liveness.h"
|
| #include "lithium-allocator.h"
|
| #include "parser.h"
|
| #include "scopeinfo.h"
|
| @@ -71,6 +72,7 @@ HBasicBlock::HBasicBlock(HGraph* graph)
|
| last_instruction_index_(-1),
|
| deleted_phis_(4, graph->zone()),
|
| parent_loop_header_(NULL),
|
| + inlined_entry_block_(NULL),
|
| is_inline_return_target_(false),
|
| is_deoptimizing_(false),
|
| dominates_loop_successors_(false),
|
| @@ -130,10 +132,13 @@ HDeoptimize* HBasicBlock::CreateDeoptimize(
|
| HDeoptimize::UseEnvironment has_uses) {
|
| ASSERT(HasEnvironment());
|
| if (has_uses == HDeoptimize::kNoUses)
|
| - return new(zone()) HDeoptimize(0, zone());
|
| + return new(zone()) HDeoptimize(0, 0, 0, zone());
|
|
|
| HEnvironment* environment = last_environment();
|
| - HDeoptimize* instr = new(zone()) HDeoptimize(environment->length(), zone());
|
| + int first_local_index = environment->first_local_index();
|
| + int first_expression_index = environment->first_expression_index();
|
| + HDeoptimize* instr = new(zone()) HDeoptimize(
|
| + environment->length(), first_local_index, first_expression_index, zone());
|
| for (int i = 0; i < environment->length(); i++) {
|
| HValue* val = environment->values()->at(i);
|
| instr->AddEnvironmentValue(val, zone());
|
| @@ -156,6 +161,9 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
|
|
|
| HSimulate* instr =
|
| new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
|
| +#ifdef DEBUG
|
| + instr->set_closure(environment->closure());
|
| +#endif
|
| // Order of pushed values: newest (top of stack) first. This allows
|
| // HSimulate::MergeInto() to easily append additional pushed values
|
| // that are older (from further down the stack).
|
| @@ -192,7 +200,7 @@ void HBasicBlock::Goto(HBasicBlock* block,
|
|
|
| if (block->IsInlineReturnTarget()) {
|
| AddInstruction(new(zone()) HLeaveInlined());
|
| - last_environment_ = last_environment()->DiscardInlined(drop_extra);
|
| + UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
|
| }
|
|
|
| if (add_simulate) AddSimulate(BailoutId::None());
|
| @@ -209,7 +217,7 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value,
|
| ASSERT(target->IsInlineReturnTarget());
|
| ASSERT(return_value != NULL);
|
| AddInstruction(new(zone()) HLeaveInlined());
|
| - last_environment_ = last_environment()->DiscardInlined(drop_extra);
|
| + UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
|
| last_environment()->Push(return_value);
|
| AddSimulate(BailoutId::None());
|
| HGoto* instr = new(zone()) HGoto(target);
|
| @@ -224,6 +232,12 @@ void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
|
| }
|
|
|
|
|
| +void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
|
| + last_environment_ = env;
|
| + graph()->update_maximum_environment_size(env->first_expression_index());
|
| +}
|
| +
|
| +
|
| void HBasicBlock::SetJoinId(BailoutId ast_id) {
|
| int length = predecessors_.length();
|
| ASSERT(length > 0);
|
| @@ -731,8 +745,7 @@ HInstruction* HGraphBuilder::IfBuilder::IfCompare(
|
| HInstruction* HGraphBuilder::IfBuilder::IfCompareMap(HValue* left,
|
| Handle<Map> map) {
|
| HCompareMap* compare =
|
| - new(zone()) HCompareMap(left, map,
|
| - first_true_block_, first_false_block_);
|
| + new(zone()) HCompareMap(left, map, first_true_block_, first_false_block_);
|
| AddCompare(compare);
|
| return compare;
|
| }
|
| @@ -811,9 +824,16 @@ void HGraphBuilder::IfBuilder::Then() {
|
| did_then_ = true;
|
| if (needs_compare_) {
|
| // Handle if's without any expressions, they jump directly to the "else"
|
| - // branch.
|
| - builder_->current_block()->GotoNoSimulate(first_false_block_);
|
| - first_true_block_ = NULL;
|
| + // branch. However, we must pretend that the "then" branch is reachable,
|
| + // so that the graph builder visits it and sees any live range extending
|
| + // constructs within it.
|
| + HConstant* constant_false = builder_->graph()->GetConstantFalse();
|
| + ToBooleanStub::Types boolean_type = ToBooleanStub::no_types();
|
| + boolean_type.Add(ToBooleanStub::BOOLEAN);
|
| + HBranch* branch =
|
| + new(zone()) HBranch(constant_false, first_true_block_,
|
| + first_false_block_, boolean_type);
|
| + builder_->current_block()->Finish(branch);
|
| }
|
| builder_->set_current_block(first_true_block_);
|
| }
|
| @@ -2103,7 +2123,8 @@ HGraph::HGraph(CompilationInfo* info)
|
| use_optimistic_licm_(false),
|
| has_soft_deoptimize_(false),
|
| depends_on_empty_array_proto_elements_(false),
|
| - type_change_checksum_(0) {
|
| + type_change_checksum_(0),
|
| + maximum_environment_size_(0) {
|
| if (info->IsStub()) {
|
| HydrogenCodeStub* stub = info->code_stub();
|
| CodeStubInterfaceDescriptor* descriptor =
|
| @@ -4431,8 +4452,8 @@ FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
|
| if (owner->ast_context()->IsTest()) {
|
| HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
|
| HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
|
| - if_true->MarkAsInlineReturnTarget();
|
| - if_false->MarkAsInlineReturnTarget();
|
| + if_true->MarkAsInlineReturnTarget(owner->current_block());
|
| + if_false->MarkAsInlineReturnTarget(owner->current_block());
|
| TestContext* outer_test_context = TestContext::cast(owner->ast_context());
|
| Expression* cond = outer_test_context->condition();
|
| TypeFeedbackOracle* outer_oracle = outer_test_context->oracle();
|
| @@ -4442,7 +4463,7 @@ FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
|
| new TestContext(owner, cond, outer_oracle, if_true, if_false);
|
| } else {
|
| function_return_ = owner->graph()->CreateBasicBlock();
|
| - function_return()->MarkAsInlineReturnTarget();
|
| + function_return()->MarkAsInlineReturnTarget(owner->current_block());
|
| }
|
| // Set this after possibly allocating a new TestContext above.
|
| call_context_ = owner->ast_context();
|
| @@ -4862,6 +4883,11 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
|
| Verify(true);
|
| #endif
|
|
|
| + if (FLAG_analyze_environment_liveness) {
|
| + EnvironmentSlotLivenessAnalyzer esla(this);
|
| + esla.AnalyzeAndTrim();
|
| + }
|
| +
|
| PropagateDeoptimizingMark();
|
| if (!CheckConstPhiUses()) {
|
| *bailout_reason = SmartArrayPointer<char>(StrDup(
|
| @@ -6553,7 +6579,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
|
| case Variable::PARAMETER:
|
| case Variable::LOCAL: {
|
| - HValue* value = environment()->Lookup(variable);
|
| + HValue* value = LookupAndMakeLive(variable);
|
| if (value == graph()->GetConstantHole()) {
|
| ASSERT(IsDeclaredVariableMode(variable->mode()) &&
|
| variable->mode() != VAR);
|
| @@ -7553,7 +7579,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
| if (var->mode() == CONST) {
|
| return Bailout("unsupported const compound assignment");
|
| }
|
| - Bind(var, Top());
|
| + BindIfLive(var, Top());
|
| break;
|
|
|
| case Variable::CONTEXT: {
|
| @@ -7782,7 +7808,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
| // permitted.
|
| CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
|
| HValue* value = Pop();
|
| - Bind(var, value);
|
| + BindIfLive(var, value);
|
| return ast_context()->ReturnValue(value);
|
| }
|
|
|
| @@ -9002,7 +9028,8 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
| function_state()->inlining_kind(),
|
| function->scope()->arguments(),
|
| arguments_values,
|
| - undefined_receiver);
|
| + undefined_receiver,
|
| + zone());
|
| function_state()->set_entry(enter_inlined);
|
| AddInstruction(enter_inlined);
|
|
|
| @@ -9081,6 +9108,8 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
| HBasicBlock* if_true = inlined_test_context()->if_true();
|
| HBasicBlock* if_false = inlined_test_context()->if_false();
|
|
|
| + HEnterInlined* entry = function_state()->entry();
|
| +
|
| // Pop the return test context from the expression context stack.
|
| ASSERT(ast_context() == inlined_test_context());
|
| ClearInlinedTestContext();
|
| @@ -9088,11 +9117,13 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
|
|
| // Forward to the real test context.
|
| if (if_true->HasPredecessor()) {
|
| + entry->RegisterReturnTarget(if_true, zone());
|
| if_true->SetJoinId(ast_id);
|
| HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
|
| if_true->Goto(true_target, function_state());
|
| }
|
| if (if_false->HasPredecessor()) {
|
| + entry->RegisterReturnTarget(if_false, zone());
|
| if_false->SetJoinId(ast_id);
|
| HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
|
| if_false->Goto(false_target, function_state());
|
| @@ -9101,6 +9132,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
| return true;
|
|
|
| } else if (function_return()->HasPredecessor()) {
|
| + function_state()->entry()->RegisterReturnTarget(function_return(), zone());
|
| function_return()->SetJoinId(ast_id);
|
| set_current_block(function_return());
|
| } else {
|
| @@ -9407,7 +9439,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
|
|
| VariableProxy* arg_two = args->at(1)->AsVariableProxy();
|
| if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
|
| - HValue* arg_two_value = environment()->Lookup(arg_two->var());
|
| + HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
|
| if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
|
|
|
| // Found pattern f.apply(receiver, arguments).
|
| @@ -10118,7 +10150,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
|
|
| case Variable::PARAMETER:
|
| case Variable::LOCAL:
|
| - Bind(var, after);
|
| + BindIfLive(var, after);
|
| break;
|
|
|
| case Variable::CONTEXT: {
|
| @@ -11201,7 +11233,7 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration(
|
| case Variable::LOCAL: {
|
| CHECK_ALIVE(VisitForValue(declaration->fun()));
|
| HValue* value = Pop();
|
| - environment()->Bind(variable, value);
|
| + BindIfLive(variable, value);
|
| break;
|
| }
|
| case Variable::CONTEXT: {
|
|
|