Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index bc49f06a20baf0980a6c5b1a62d90dda1742448d..0e8c4760dd353dd66a0adbf21138f253f56b8519 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -1983,9 +1983,6 @@ void HGraph::InsertRepresentationChanges() { |
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
: owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
owner->set_ast_context(this); // Push. |
-#ifdef DEBUG |
- original_count_ = owner->environment()->total_count(); |
-#endif |
} |
@@ -1994,101 +1991,6 @@ AstContext::~AstContext() { |
} |
-EffectContext::~EffectContext() { |
- ASSERT(owner()->HasStackOverflow() || |
- !owner()->subgraph()->HasExit() || |
- owner()->environment()->total_count() == original_count_); |
-} |
- |
- |
-ValueContext::~ValueContext() { |
- ASSERT(owner()->HasStackOverflow() || |
- !owner()->subgraph()->HasExit() || |
- owner()->environment()->total_count() == original_count_ + 1); |
-} |
- |
- |
-void EffectContext::ReturnValue(HValue* value) { |
- // The value is simply ignored. |
-} |
- |
- |
-void ValueContext::ReturnValue(HValue* value) { |
- // The value is tracked in the bailout environment, and communicated |
- // through the environment as the result of the expression. |
- owner()->Push(value); |
-} |
- |
- |
-void TestContext::ReturnValue(HValue* value) { |
- BuildBranch(value); |
-} |
- |
- |
-void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
- owner()->AddInstruction(instr); |
- if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
-} |
- |
- |
-void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
- owner()->AddInstruction(instr); |
- owner()->Push(instr); |
- if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
-} |
- |
- |
-void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
- HGraphBuilder* builder = owner(); |
- builder->AddInstruction(instr); |
- // We expect a simulate after every expression with side effects, though |
- // this one isn't actually needed (and wouldn't work if it were targeted). |
- if (instr->HasSideEffects()) { |
- builder->Push(instr); |
- builder->AddSimulate(ast_id); |
- builder->Pop(); |
- } |
- BuildBranch(instr); |
-} |
- |
- |
-void TestContext::BuildBranch(HValue* value) { |
- HGraphBuilder* builder = owner(); |
- HBasicBlock* materialize_true = builder->graph()->CreateBasicBlock(); |
- HBasicBlock* materialize_false = builder->graph()->CreateBasicBlock(); |
- HBranch* branch = new HBranch(materialize_true, materialize_false, value); |
- builder->CurrentBlock()->Finish(branch); |
- |
- HBasicBlock* true_block = if_true(); |
- HValue* true_value = invert_true() |
- ? builder->graph()->GetConstantFalse() |
- : builder->graph()->GetConstantTrue(); |
- materialize_true->set_inverted(invert_true()); |
- true_block->set_deopt_predecessor(materialize_true); |
- |
- if (true_block->IsInlineReturnTarget()) { |
- materialize_true->AddLeaveInlined(true_value, true_block); |
- } else { |
- materialize_true->last_environment()->Push(true_value); |
- materialize_true->Goto(true_block); |
- } |
- |
- HBasicBlock* false_block = if_false(); |
- HValue* false_value = invert_false() |
- ? builder->graph()->GetConstantTrue() |
- : builder->graph()->GetConstantFalse(); |
- materialize_false->set_inverted(invert_false()); |
- false_block->set_deopt_predecessor(materialize_false); |
- |
- if (false_block->IsInlineReturnTarget()) { |
- materialize_false->AddLeaveInlined(false_value, false_block); |
- } else { |
- materialize_false->last_environment()->Push(false_value); |
- materialize_false->Goto(false_block); |
- } |
- builder->subgraph()->set_exit_block(NULL); |
-} |
- |
// HGraphBuilder infrastructure for bailing out and checking bailouts. |
#define BAILOUT(reason) \ |
@@ -2159,14 +2061,55 @@ void HGraphBuilder::Bailout(const char* reason) { |
void HGraphBuilder::VisitForEffect(Expression* expr) { |
- EffectContext for_effect(this); |
- Visit(expr); |
+#ifdef DEBUG |
+ int original_count = environment()->total_count(); |
+#endif |
+ BinaryOperation* binary_op = expr->AsBinaryOperation(); |
+ |
+ // We use special casing for expression types not handled properly by our |
+ // usual trick of pretending they're in a value context and cleaning up |
+ // later. |
+ if (binary_op != NULL && binary_op->op() == Token::COMMA) { |
+ VISIT_FOR_EFFECT(binary_op->left()); |
+ VISIT_FOR_EFFECT(binary_op->right()); |
+ } else { |
+ { EffectContext for_effect(this); |
+ Visit(expr); |
+ } |
+ if (HasStackOverflow() || !subgraph()->HasExit()) return; |
+ // Discard return value. |
+ Pop(); |
+ // TODO(kasperl): Try to improve the way we compute the last added |
+ // instruction. The NULL check makes me uncomfortable. |
+ HValue* last = subgraph()->exit_block()->GetLastInstruction(); |
+ // We need to ensure we emit a simulate after inlined functions in an |
+ // effect context, to avoid having a bailout target the fictional |
+ // environment with the return value on top. |
+ if ((last != NULL && last->HasSideEffects()) || |
+ subgraph()->exit_block()->IsInlineReturnTarget()) { |
+ AddSimulate(expr->id()); |
+ } |
+ } |
+ |
+ ASSERT(environment()->total_count() == original_count); |
} |
void HGraphBuilder::VisitForValue(Expression* expr) { |
- ValueContext for_value(this); |
- Visit(expr); |
+#ifdef DEBUG |
+ int original_height = environment()->values()->length(); |
+#endif |
+ { ValueContext for_value(this); |
+ Visit(expr); |
+ } |
+ if (HasStackOverflow() || !subgraph()->HasExit()) return; |
+ // TODO(kasperl): Try to improve the way we compute the last added |
+ // instruction. The NULL check makes me uncomfortable. |
+ HValue* last = subgraph()->exit_block()->GetLastInstruction(); |
+ if (last != NULL && last->HasSideEffects()) { |
+ AddSimulate(expr->id()); |
+ } |
+ ASSERT(environment()->values()->length() == original_height + 1); |
} |
@@ -2301,7 +2244,99 @@ void HGraphBuilder::VisitForControl(Expression* expr, |
bool invert_false) { |
TestContext for_test(this, true_block, false_block, |
invert_true, invert_false); |
- Visit(expr); |
+ BinaryOperation* binary_op = expr->AsBinaryOperation(); |
+ UnaryOperation* unary_op = expr->AsUnaryOperation(); |
+ |
+ if (unary_op != NULL && unary_op->op() == Token::NOT) { |
+ VisitForControl(unary_op->expression(), |
+ false_block, |
+ true_block, |
+ !invert_false, |
+ !invert_true); |
+ } else if (binary_op != NULL && binary_op->op() == Token::AND) { |
+ // Translate left subexpression. |
+ HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
+ VisitForControl(binary_op->left(), |
+ eval_right, |
+ false_block, |
+ false, |
+ invert_false); |
+ if (HasStackOverflow()) return; |
+ eval_right->SetJoinId(binary_op->left()->id()); |
+ |
+ // Translate right subexpression. |
+ eval_right->last_environment()->Pop(); |
+ subgraph()->set_exit_block(eval_right); |
+ VisitForControl(binary_op->right(), |
+ true_block, |
+ false_block, |
+ invert_true, |
+ invert_false); |
+ } else if (binary_op != NULL && binary_op->op() == Token::OR) { |
+ // Translate left subexpression. |
+ HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
+ VisitForControl(binary_op->left(), |
+ true_block, |
+ eval_right, |
+ invert_true, |
+ false); |
+ if (HasStackOverflow()) return; |
+ eval_right->SetJoinId(binary_op->left()->id()); |
+ |
+ // Translate right subexpression |
+ eval_right->last_environment()->Pop(); |
+ subgraph()->set_exit_block(eval_right); |
+ VisitForControl(binary_op->right(), |
+ true_block, |
+ false_block, |
+ invert_true, |
+ invert_false); |
+ } else { |
+#ifdef DEBUG |
+ int original_length = environment()->values()->length(); |
+#endif |
+ // TODO(kmillikin): Refactor to avoid. This code is duplicated from |
+ // VisitForValue, except without pushing a value context on the |
+ // expression context stack. |
+ Visit(expr); |
+ if (HasStackOverflow() || !subgraph()->HasExit()) return; |
+ HValue* last = subgraph()->exit_block()->GetLastInstruction(); |
+ if (last != NULL && last->HasSideEffects()) { |
+ AddSimulate(expr->id()); |
+ } |
+ ASSERT(environment()->values()->length() == original_length + 1); |
+ HValue* value = Pop(); |
+ HBasicBlock* materialize_true = graph()->CreateBasicBlock(); |
+ HBasicBlock* materialize_false = graph()->CreateBasicBlock(); |
+ CurrentBlock()->Finish(new HBranch(materialize_true, |
+ materialize_false, |
+ value)); |
+ HValue* true_value = invert_true |
+ ? graph()->GetConstantFalse() |
+ : graph()->GetConstantTrue(); |
+ materialize_true->set_inverted(invert_true); |
+ true_block->set_deopt_predecessor(materialize_true); |
+ |
+ if (true_block->IsInlineReturnTarget()) { |
+ materialize_true->AddLeaveInlined(true_value, true_block); |
+ } else { |
+ materialize_true->last_environment()->Push(true_value); |
+ materialize_true->Goto(true_block); |
+ } |
+ HValue* false_value = invert_false |
+ ? graph()->GetConstantTrue() |
+ : graph()->GetConstantFalse(); |
+ materialize_false->set_inverted(invert_false); |
+ false_block->set_deopt_predecessor(materialize_false); |
+ |
+ if (false_block->IsInlineReturnTarget()) { |
+ materialize_false->AddLeaveInlined(false_value, false_block); |
+ } else { |
+ materialize_false->last_environment()->Push(false_value); |
+ materialize_false->Goto(false_block); |
+ } |
+ subgraph()->set_exit_block(NULL); |
+ } |
} |
@@ -2337,6 +2372,12 @@ void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
} |
+void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) { |
+ instr->set_position(position); |
+ PushAndAdd(instr); |
+} |
+ |
+ |
void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { |
const int kMaxStubArguments = 4; |
ASSERT_GE(kMaxStubArguments, argument_count); |
@@ -2351,7 +2392,7 @@ void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { |
} |
-void HGraphBuilder::ProcessCall(HCall* call) { |
+void HGraphBuilder::ProcessCall(HCall* call, int source_position) { |
for (int i = call->argument_count() - 1; i >= 0; --i) { |
HValue* value = Pop(); |
HPushArgument* push = new HPushArgument(value); |
@@ -2361,6 +2402,8 @@ void HGraphBuilder::ProcessCall(HCall* call) { |
for (int i = 0; i < call->argument_count(); ++i) { |
AddInstruction(call->PushArgumentAt(i)); |
} |
+ |
+ PushAndAdd(call, source_position); |
} |
@@ -2871,9 +2914,7 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
Handle<SharedFunctionInfo> shared_info = |
Compiler::BuildFunctionInfo(expr, graph_->info()->script()); |
CHECK_BAILOUT; |
- HFunctionLiteral* instr = |
- new HFunctionLiteral(shared_info, expr->pretenure()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure())); |
} |
@@ -2894,21 +2935,20 @@ void HGraphBuilder::VisitConditional(Conditional* expr) { |
ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); |
ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); |
current_subgraph_->AppendJoin(then_graph, else_graph, expr); |
- ast_context()->ReturnValue(Pop()); |
} |
-void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
+void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, |
LookupResult* lookup, |
bool is_store) { |
- if (var->is_this()) { |
+ if (expr->is_this()) { |
BAILOUT("global this reference"); |
} |
if (!graph()->info()->has_global_object()) { |
BAILOUT("no global object to optimize VariableProxy"); |
} |
Handle<GlobalObject> global(graph()->info()->global_object()); |
- global->Lookup(*var->name(), lookup); |
+ global->Lookup(*expr->name(), lookup); |
if (!lookup->IsProperty()) { |
BAILOUT("global variable cell not yet introduced"); |
} |
@@ -2921,6 +2961,23 @@ void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
} |
+void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) { |
+ LookupResult lookup; |
+ LookupGlobalPropertyCell(expr, &lookup, false); |
+ CHECK_BAILOUT; |
+ |
+ Handle<GlobalObject> global(graph()->info()->global_object()); |
+ // TODO(3039103): Handle global property load through an IC call when access |
+ // checks are enabled. |
+ if (global->IsAccessCheckNeeded()) { |
+ BAILOUT("global object requires access check"); |
+ } |
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
+ PushAndAdd(new HLoadGlobal(cell, check_hole)); |
+} |
+ |
+ |
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
Variable* variable = expr->AsVariable(); |
if (variable == NULL) { |
@@ -2929,22 +2986,9 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
BAILOUT("unsupported context for arguments object"); |
} |
- ast_context()->ReturnValue(environment()->Lookup(variable)); |
+ Push(environment()->Lookup(variable)); |
} else if (variable->is_global()) { |
- LookupResult lookup; |
- LookupGlobalPropertyCell(variable, &lookup, false); |
- CHECK_BAILOUT; |
- |
- Handle<GlobalObject> global(graph()->info()->global_object()); |
- // TODO(3039103): Handle global property load through an IC call when access |
- // checks are enabled. |
- if (global->IsAccessCheckNeeded()) { |
- BAILOUT("global object requires access check"); |
- } |
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
- bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
- HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ HandleGlobalVariableLoad(expr); |
} else { |
BAILOUT("reference to non-stack-allocated/non-global variable"); |
} |
@@ -2952,16 +2996,14 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
void HGraphBuilder::VisitLiteral(Literal* expr) { |
- HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(new HConstant(expr->handle(), Representation::Tagged())); |
} |
void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
- HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), |
- expr->flags(), |
- expr->literal_index()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(new HRegExpLiteral(expr->pattern(), |
+ expr->flags(), |
+ expr->literal_index())); |
} |
@@ -2970,8 +3012,6 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
expr->fast_elements(), |
expr->literal_index(), |
expr->depth())); |
- // The object is expected in the bailout environment during computation |
- // of the property values and is the value of the entire expression. |
PushAndAdd(literal); |
expr->CalculateEmitStore(); |
@@ -3008,7 +3048,6 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
default: UNREACHABLE(); |
} |
} |
- ast_context()->ReturnValue(Pop()); |
} |
@@ -3020,8 +3059,6 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
length, |
expr->literal_index(), |
expr->depth()); |
- // The array is expected in the bailout environment during computation |
- // of the property values and is the value of the entire expression. |
PushAndAdd(literal); |
HValue* elements = AddInstruction(new HLoadElements(literal)); |
@@ -3039,7 +3076,6 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
AddInstruction(new HStoreKeyedFastElement(elements, key, value)); |
AddSimulate(expr->GetIdForElement(i)); |
} |
- ast_context()->ReturnValue(Pop()); |
} |
@@ -3221,29 +3257,27 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
Push(value); |
instr->set_position(expr->position()); |
AddInstruction(instr); |
- if (instr->HasSideEffects()) AddSimulate(expr->id()); |
- } else { |
- // Build subgraph for generic store through IC. |
- { |
- HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
- SubgraphScope scope(this, subgraph); |
- if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
- subgraph->FinishExit(new HDeoptimize()); |
- } else { |
- HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
- Push(value); |
- instr->set_position(expr->position()); |
- AddInstruction(instr); |
- } |
- subgraphs.Add(subgraph); |
- } |
+ return; |
+ } |
- HBasicBlock* new_exit_block = |
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
- subgraph()->set_exit_block(new_exit_block); |
+ // Build subgraph for generic store through IC. |
+ { |
+ HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
+ SubgraphScope scope(this, subgraph); |
+ if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
+ subgraph->FinishExit(new HDeoptimize()); |
+ } else { |
+ HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
+ Push(value); |
+ instr->set_position(expr->position()); |
+ AddInstruction(instr); |
+ } |
+ subgraphs.Add(subgraph); |
} |
- if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
+ HBasicBlock* new_exit_block = |
+ BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
+ current_subgraph_->set_exit_block(new_exit_block); |
} |
@@ -3299,20 +3333,14 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
Push(value); |
instr->set_position(expr->position()); |
AddInstruction(instr); |
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
- ast_context()->ReturnValue(Pop()); |
} |
-// Because not every expression has a position and there is not common |
-// superclass of Assignment and CountOperation, we cannot just pass the |
-// owning expression instead of position and ast_id separately. |
-void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
+void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, |
HValue* value, |
- int position, |
- int ast_id) { |
+ int position) { |
LookupResult lookup; |
- LookupGlobalPropertyCell(var, &lookup, true); |
+ LookupGlobalPropertyCell(proxy, &lookup, true); |
CHECK_BAILOUT; |
Handle<GlobalObject> global(graph()->info()->global_object()); |
@@ -3320,7 +3348,6 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
HInstruction* instr = new HStoreGlobal(value, cell); |
instr->set_position(position); |
AddInstruction(instr); |
- if (instr->HasSideEffects()) AddSimulate(ast_id); |
} |
@@ -3344,15 +3371,10 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
VISIT_FOR_VALUE(operation); |
if (var->is_global()) { |
- HandleGlobalVariableAssignment(var, |
- Top(), |
- expr->position(), |
- expr->AssignmentId()); |
+ HandleGlobalVariableAssignment(proxy, Top(), expr->position()); |
} else { |
Bind(var, Top()); |
} |
- ast_context()->ReturnValue(Pop()); |
- |
} else if (prop != NULL) { |
prop->RecordTypeFeedback(oracle()); |
@@ -3370,7 +3392,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
load = BuildLoadNamedGeneric(obj, prop); |
} |
PushAndAdd(load); |
- if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
+ if (load->HasSideEffects()) { |
+ AddSimulate(expr->compound_bailout_id()); |
+ } |
VISIT_FOR_VALUE(expr->value()); |
HValue* right = Pop(); |
@@ -3382,11 +3406,10 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
HInstruction* store = BuildStoreNamed(obj, instr, prop); |
AddInstruction(store); |
- // Drop the simulated receiver and value. Return the value. |
+ |
+ // Drop the simulated receiver and value and put back the value. |
Drop(2); |
Push(instr); |
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
- ast_context()->ReturnValue(Pop()); |
} else { |
// Keyed property. |
@@ -3402,7 +3425,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
? BuildLoadKeyedFastElement(obj, key, prop) |
: BuildLoadKeyedGeneric(obj, key); |
PushAndAdd(load); |
- if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
+ if (load->HasSideEffects()) { |
+ AddSimulate(expr->compound_bailout_id()); |
+ } |
VISIT_FOR_VALUE(expr->value()); |
HValue* right = Pop(); |
@@ -3416,13 +3441,11 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
? BuildStoreKeyedFastElement(obj, key, instr, prop) |
: BuildStoreKeyedGeneric(obj, key, instr); |
AddInstruction(store); |
- // Drop the simulated receiver, key, and value. Return the value. |
+ |
+ // Drop the simulated receiver, key and value and put back the value. |
Drop(3); |
Push(instr); |
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
- ast_context()->ReturnValue(Pop()); |
} |
- |
} else { |
BAILOUT("invalid lhs in compound assignment"); |
} |
@@ -3442,14 +3465,9 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { |
if (var != NULL) { |
if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
- |
- // Handle the assignment. |
if (var->is_global()) { |
VISIT_FOR_VALUE(expr->value()); |
- HandleGlobalVariableAssignment(var, |
- Top(), |
- expr->position(), |
- expr->AssignmentId()); |
+ HandleGlobalVariableAssignment(proxy, Top(), expr->position()); |
} else { |
// We allow reference to the arguments object only in assignemtns |
// to local variables to make sure that the arguments object does |
@@ -3462,11 +3480,9 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { |
} else { |
VISIT_FOR_VALUE(expr->value()); |
} |
+ |
Bind(proxy->var(), Top()); |
} |
- // Return the value. |
- ast_context()->ReturnValue(Pop()); |
- |
} else if (prop != NULL) { |
HandlePropertyAssignment(expr); |
} else { |
@@ -3476,10 +3492,6 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { |
void HGraphBuilder::VisitThrow(Throw* expr) { |
- // We don't optimize functions with invalid left-hand sides in |
- // assignments, count operations, or for-in. Consequently throw can |
- // currently only occur in an effect context. |
- ASSERT(ast_context()->IsEffect()); |
VISIT_FOR_VALUE(expr->exception()); |
HValue* value = environment()->Pop(); |
@@ -3513,8 +3525,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
SubgraphScope scope(this, subgraph); |
HInstruction* instr = |
BuildLoadNamedField(object, expr, map, &lookup, false); |
- instr->set_position(expr->position()); |
- PushAndAdd(instr); |
+ PushAndAdd(instr, expr->position()); |
subgraphs.Add(subgraph); |
} else { |
needs_generic = true; |
@@ -3525,30 +3536,26 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
// generic load. |
if (maps.length() == 0) { |
HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
- instr->set_position(expr->position()); |
- PushAndAdd(instr); |
- if (instr->HasSideEffects()) AddSimulate(expr->id()); |
- } else { |
- // Build subgraph for generic load through IC. |
- { |
- HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
- SubgraphScope scope(this, subgraph); |
- if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
- subgraph->FinishExit(new HDeoptimize()); |
- } else { |
- HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
- instr->set_position(expr->position()); |
- PushAndAdd(instr); |
- } |
- subgraphs.Add(subgraph); |
- } |
+ PushAndAdd(instr, expr->position()); |
+ return; |
+ } |
- HBasicBlock* new_exit_block = |
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
- subgraph()->set_exit_block(new_exit_block); |
+ // Build subgraph for generic load through IC. |
+ { |
+ HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
+ SubgraphScope scope(this, subgraph); |
+ if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
+ subgraph->FinishExit(new HDeoptimize()); |
+ } else { |
+ HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
+ PushAndAdd(instr, expr->position()); |
+ } |
+ subgraphs.Add(subgraph); |
} |
- if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
+ HBasicBlock* new_exit_block = |
+ BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
+ current_subgraph_->set_exit_block(new_exit_block); |
} |
@@ -3661,12 +3668,11 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
return false; |
} |
- HInstruction* result = NULL; |
if (expr->key()->IsPropertyName()) { |
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
if (!name->IsEqualTo(CStrVector("length"))) return false; |
HInstruction* elements = AddInstruction(new HArgumentsElements); |
- result = new HArgumentsLength(elements); |
+ PushAndAdd(new HArgumentsLength(elements)); |
} else { |
VisitForValue(expr->key()); |
if (HasStackOverflow()) return false; |
@@ -3674,9 +3680,8 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
HInstruction* elements = AddInstruction(new HArgumentsElements); |
HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
AddInstruction(new HBoundsCheck(key, length)); |
- result = new HAccessArgumentsAt(elements, length, key); |
+ PushAndAdd(new HAccessArgumentsAt(elements, length, key)); |
} |
- ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
} |
@@ -3723,8 +3728,7 @@ void HGraphBuilder::VisitProperty(Property* expr) { |
? BuildLoadKeyedFastElement(obj, key, expr) |
: BuildLoadKeyedGeneric(obj, key); |
} |
- instr->set_position(expr->position()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr, expr->position()); |
} |
@@ -3759,9 +3763,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
// Build subgraphs for each of the specific maps. |
// |
- // TODO(ager): We should recognize when the prototype chains for different |
- // maps are identical. In that case we can avoid repeatedly generating the |
- // same prototype map checks. |
+ // TODO(ager): We should recognize when the prototype chains for |
+ // different maps are identical. In that case we can avoid |
+ // repeatedly generating the same prototype map checks. |
for (int i = 0; i < number_of_types; ++i) { |
Handle<Map> map = types->at(i); |
if (expr->ComputeTarget(map, name)) { |
@@ -3778,9 +3782,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
// during hydrogen processing. |
CHECK_BAILOUT; |
HCall* call = new HCallConstantFunction(expr->target(), argument_count); |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- PushAndAdd(call); |
+ ProcessCall(call, expr->position()); |
} |
subgraphs.Add(subgraph); |
} else { |
@@ -3788,34 +3790,30 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
} |
} |
- // If we couldn't compute the target for any of the maps just perform an |
- // IC call. |
+ // If we couldn't compute the target for any of the maps just |
+ // perform an IC call. |
if (maps.length() == 0) { |
HCall* call = new HCallNamed(name, argument_count); |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- ast_context()->ReturnInstruction(call, expr->id()); |
- } else { |
- // Build subgraph for generic call through IC. |
- { |
- HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
- SubgraphScope scope(this, subgraph); |
- if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
- subgraph->FinishExit(new HDeoptimize()); |
- } else { |
- HCall* call = new HCallNamed(name, argument_count); |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- PushAndAdd(call); |
- } |
- subgraphs.Add(subgraph); |
- } |
+ ProcessCall(call, expr->position()); |
+ return; |
+ } |
- HBasicBlock* new_exit_block = |
- BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); |
- subgraph()->set_exit_block(new_exit_block); |
- if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); |
+ // Build subgraph for generic call through IC. |
+ { |
+ HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
+ SubgraphScope scope(this, subgraph); |
+ if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
+ subgraph->FinishExit(new HDeoptimize()); |
+ } else { |
+ HCall* call = new HCallNamed(name, argument_count); |
+ ProcessCall(call, expr->position()); |
+ } |
+ subgraphs.Add(subgraph); |
} |
+ |
+ HBasicBlock* new_exit_block = |
+ BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); |
+ current_subgraph_->set_exit_block(new_exit_block); |
} |
@@ -4063,7 +4061,6 @@ bool HGraphBuilder::TryInline(Call* expr) { |
function_return_ = saved_function_return; |
oracle_ = saved_oracle; |
graph()->info()->SetOsrAstId(saved_osr_ast_id); |
- |
return true; |
} |
@@ -4089,55 +4086,10 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
case kMathSqrt: |
if (argument_count == 2) { |
HValue* argument = Pop(); |
- Drop(1); // Receiver. |
+ // Pop receiver. |
+ Pop(); |
HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
- op->set_position(expr->position()); |
- ast_context()->ReturnInstruction(op, expr->id()); |
- return true; |
- } |
- break; |
- case kMathPow: |
- if (argument_count == 3) { |
- HValue* right = Pop(); |
- HValue* left = Pop(); |
- Pop(); // Pop receiver. |
- HInstruction* result = NULL; |
- // Use sqrt() if exponent is 0.5 or -0.5. |
- if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
- double exponent = HConstant::cast(right)->DoubleValue(); |
- if (exponent == 0.5) { |
- result = new HUnaryMathOperation(left, kMathPowHalf); |
- ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
- } else if (exponent == -0.5) { |
- HConstant* double_one = |
- new HConstant(Handle<Object>(Smi::FromInt(1)), |
- Representation::Double()); |
- AddInstruction(double_one); |
- HUnaryMathOperation* square_root = |
- new HUnaryMathOperation(left, kMathPowHalf); |
- AddInstruction(square_root); |
- // MathPowHalf doesn't have side effects so there's no need for |
- // an environment simulation here. |
- ASSERT(!square_root->HasSideEffects()); |
- result = new HDiv(double_one, square_root); |
- ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
- } else if (exponent == 2.0) { |
- result = new HMul(left, left); |
- ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
- } |
- } else if (right->IsConstant() && |
- HConstant::cast(right)->HasInteger32Value() && |
- HConstant::cast(right)->Integer32Value() == 2) { |
- result = new HMul(left, left); |
- ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
- } |
- |
- result = new HPower(left, right); |
- ast_context()->ReturnInstruction(result, expr->id()); |
+ PushAndAdd(op, expr->position()); |
return true; |
} |
break; |
@@ -4182,10 +4134,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) { |
function, |
expr->GetReceiverTypes()->first(), |
true); |
- HInstruction* result = |
- new HApplyArguments(function, receiver, length, elements); |
- result->set_position(expr->position()); |
- ast_context()->ReturnInstruction(result, expr->id()); |
+ PushAndAdd(new HApplyArguments(function, receiver, length, elements), |
+ expr->position()); |
return true; |
} |
@@ -4213,10 +4163,12 @@ void HGraphBuilder::VisitCall(Call* expr) { |
CHECK_BAILOUT; |
call = new HCallKeyed(key, argument_count); |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- Drop(1); // Key. |
- ast_context()->ReturnInstruction(call, expr->id()); |
+ ProcessCall(call, expr->position()); |
+ HValue* result = Pop(); |
+ // Drop the receiver from the environment and put back the result of |
+ // the call. |
+ Drop(1); |
+ Push(result); |
return; |
} |
@@ -4239,19 +4191,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
if (expr->IsMonomorphic()) { |
AddCheckConstantFunction(expr, receiver, types->first(), true); |
- if (TryMathFunctionInline(expr)) { |
- return; |
- } else if (TryInline(expr)) { |
- if (subgraph()->HasExit()) { |
- HValue* return_value = Pop(); |
- // If we inlined a function in a test context then we need to emit |
- // a simulate here to shadow the ones at the end of the |
- // predecessor blocks. Those environments contain the return |
- // value on top and do not correspond to any actual state of the |
- // unoptimized code. |
- if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
- ast_context()->ReturnValue(return_value); |
- } |
+ if (TryMathFunctionInline(expr) || TryInline(expr)) { |
return; |
} else { |
// Check for bailout, as the TryInline call in the if condition above |
@@ -4259,7 +4199,6 @@ void HGraphBuilder::VisitCall(Call* expr) { |
CHECK_BAILOUT; |
call = new HCallConstantFunction(expr->target(), argument_count); |
} |
- |
} else if (types != NULL && types->length() > 1) { |
HandlePolymorphicCallNamed(expr, receiver, types, name); |
return; |
@@ -4307,19 +4246,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
IsGlobalObject()); |
environment()->SetExpressionStackAt(receiver_index, global_receiver); |
- if (TryInline(expr)) { |
- if (subgraph()->HasExit()) { |
- HValue* return_value = Pop(); |
- // If we inlined a function in a test context then we need to |
- // emit a simulate here to shadow the ones at the end of the |
- // predecessor blocks. Those environments contain the return |
- // value on top and do not correspond to any actual state of the |
- // unoptimized code. |
- if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
- ast_context()->ReturnValue(return_value); |
- } |
- return; |
- } |
+ if (TryInline(expr)) return; |
// Check for bailout, as trying to inline might fail due to bailout |
// during hydrogen processing. |
CHECK_BAILOUT; |
@@ -4342,9 +4269,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
} |
} |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- ast_context()->ReturnInstruction(call, expr->id()); |
+ ProcessCall(call, expr->position()); |
} |
@@ -4358,9 +4283,8 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { |
int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
HCall* call = new HCallNew(argument_count); |
- call->set_position(expr->position()); |
- ProcessCall(call); |
- ast_context()->ReturnInstruction(call, expr->id()); |
+ |
+ ProcessCall(call, expr->position()); |
} |
@@ -4368,7 +4292,7 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { |
// Lookup table for generators for runtime calls that are generated inline. |
// Elements of the table are member pointers to functions of HGraphBuilder. |
-#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
+#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
&HGraphBuilder::Generate##Name, |
const HGraphBuilder::InlineFunctionGenerator |
@@ -4382,7 +4306,7 @@ const HGraphBuilder::InlineFunctionGenerator |
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
Handle<String> name = expr->name(); |
if (name->IsEqualTo(CStrVector("_Log"))) { |
- ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
+ Push(graph()->GetConstantUndefined()); |
return; |
} |
@@ -4408,13 +4332,11 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
// Call the inline code generator using the pointer-to-member. |
- (this->*generator)(argument_count, expr->id()); |
+ (this->*generator)(argument_count); |
} else { |
ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
- call->set_position(RelocInfo::kNoPosition); |
- ProcessCall(call); |
- ast_context()->ReturnInstruction(call, expr->id()); |
+ ProcessCall(call, RelocInfo::kNoPosition); |
} |
} |
@@ -4423,7 +4345,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
Token::Value op = expr->op(); |
if (op == Token::VOID) { |
VISIT_FOR_EFFECT(expr->expression()); |
- ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
+ Push(graph()->GetConstantUndefined()); |
} else if (op == Token::DELETE) { |
Property* prop = expr->expression()->AsProperty(); |
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
@@ -4431,47 +4353,36 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
// Result of deleting non-property, non-variable reference is true. |
// Evaluate the subexpression for side effects. |
VISIT_FOR_EFFECT(expr->expression()); |
- ast_context()->ReturnValue(graph()->GetConstantTrue()); |
+ Push(graph_->GetConstantTrue()); |
} else if (var != NULL && |
!var->is_global() && |
var->AsSlot() != NULL && |
var->AsSlot()->type() != Slot::LOOKUP) { |
// Result of deleting non-global, non-dynamic variables is false. |
// The subexpression does not have side effects. |
- ast_context()->ReturnValue(graph()->GetConstantFalse()); |
+ Push(graph_->GetConstantFalse()); |
} else if (prop != NULL) { |
VISIT_FOR_VALUE(prop->obj()); |
VISIT_FOR_VALUE(prop->key()); |
HValue* key = Pop(); |
HValue* obj = Pop(); |
- ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), |
- expr->id()); |
+ PushAndAdd(new HDeleteProperty(obj, key)); |
} else if (var->is_global()) { |
BAILOUT("delete with global variable"); |
} else { |
BAILOUT("delete with non-global variable"); |
} |
} else if (op == Token::NOT) { |
- if (ast_context()->IsTest()) { |
- TestContext* context = TestContext::cast(ast_context()); |
- VisitForControl(expr->expression(), |
- context->if_false(), |
- context->if_true(), |
- !context->invert_false(), |
- !context->invert_true()); |
- } else { |
- HSubgraph* true_graph = CreateEmptySubgraph(); |
- HSubgraph* false_graph = CreateEmptySubgraph(); |
- VisitCondition(expr->expression(), |
- false_graph->entry_block(), |
- true_graph->entry_block(), |
- true, true); |
- if (HasStackOverflow()) return; |
- true_graph->environment()->Push(graph_->GetConstantTrue()); |
- false_graph->environment()->Push(graph_->GetConstantFalse()); |
- current_subgraph_->AppendJoin(true_graph, false_graph, expr); |
- ast_context()->ReturnValue(Pop()); |
- } |
+ HSubgraph* true_graph = CreateEmptySubgraph(); |
+ HSubgraph* false_graph = CreateEmptySubgraph(); |
+ VisitCondition(expr->expression(), |
+ false_graph->entry_block(), |
+ true_graph->entry_block(), |
+ true, true); |
+ if (HasStackOverflow()) return; |
+ true_graph->environment()->Push(graph_->GetConstantTrue()); |
+ false_graph->environment()->Push(graph_->GetConstantFalse()); |
+ current_subgraph_->AppendJoin(true_graph, false_graph, expr); |
} else if (op == Token::BIT_NOT || op == Token::SUB) { |
VISIT_FOR_VALUE(expr->expression()); |
HValue* value = Pop(); |
@@ -4487,11 +4398,11 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
UNREACHABLE(); |
break; |
} |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr); |
} else if (op == Token::TYPEOF) { |
VISIT_FOR_VALUE(expr->expression()); |
HValue* value = Pop(); |
- ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); |
+ PushAndAdd(new HTypeof(value)); |
} else { |
BAILOUT("Value: unsupported unary operation"); |
} |
@@ -4542,15 +4453,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
} |
if (var->is_global()) { |
- HandleGlobalVariableAssignment(var, |
- instr, |
- expr->position(), |
- expr->AssignmentId()); |
+ HandleGlobalVariableAssignment(proxy, instr, expr->position()); |
} else { |
ASSERT(var->IsStackAllocated()); |
Bind(var, instr); |
} |
- ast_context()->ReturnValue(Pop()); |
} else if (prop != NULL) { |
prop->RecordTypeFeedback(oracle()); |
@@ -4558,10 +4465,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
if (prop->key()->IsPropertyName()) { |
// Named property. |
- // Match the full code generator stack by simulating an extra stack |
- // element for postfix operations in a value context. |
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
- if (has_extra) Push(graph_->GetConstantUndefined()); |
+ // Match the full code generator stack by simulate an extra stack element |
+ // for postfix operations in a value context. |
+ if (expr->is_postfix() && !ast_context()->IsEffect()) { |
+ Push(graph_->GetConstantUndefined()); |
+ } |
VISIT_FOR_VALUE(prop->obj()); |
HValue* obj = Top(); |
@@ -4577,35 +4485,37 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
PushAndAdd(load); |
if (load->HasSideEffects()) AddSimulate(increment->id()); |
- HValue* before = Pop(); |
- // There is no deoptimization to after the increment, so we don't need |
- // to simulate the expression stack after this instruction. |
- HInstruction* after = BuildIncrement(before, inc); |
- AddInstruction(after); |
+ HValue* value = Pop(); |
- HInstruction* store = BuildStoreNamed(obj, after, prop); |
- AddInstruction(store); |
+ HInstruction* instr = BuildIncrement(value, inc); |
+ AddInstruction(instr); |
- // Overwrite the receiver in the bailout environment with the result |
- // of the operation, and the placeholder with the original value if |
- // necessary. |
- environment()->SetExpressionStackAt(0, after); |
- if (has_extra) environment()->SetExpressionStackAt(1, before); |
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
- Drop(has_extra ? 2 : 1); |
+ HInstruction* store = BuildStoreNamed(obj, instr, prop); |
+ AddInstruction(store); |
- ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
+ // Drop simulated receiver and push the result. |
+ // There is no deoptimization to after the increment, so we can simulate |
+ // the expression stack here. |
+ Drop(1); |
+ if (expr->is_prefix()) { |
+ Push(instr); |
+ } else { |
+ if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. |
+ Push(value); |
+ } |
} else { |
// Keyed property. |
// Match the full code generator stack by simulate an extra stack element |
// for postfix operations in a value context. |
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
- if (has_extra) Push(graph_->GetConstantUndefined()); |
+ if (expr->is_postfix() && !ast_context()->IsEffect()) { |
+ Push(graph_->GetConstantUndefined()); |
+ } |
VISIT_FOR_VALUE(prop->obj()); |
VISIT_FOR_VALUE(prop->key()); |
+ |
HValue* obj = environment()->ExpressionStackAt(1); |
HValue* key = environment()->ExpressionStackAt(0); |
@@ -4618,29 +4528,27 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
PushAndAdd(load); |
if (load->HasSideEffects()) AddSimulate(increment->id()); |
- HValue* before = Pop(); |
- // There is no deoptimization to after the increment, so we don't need |
- // to simulate the expression stack after this instruction. |
- HInstruction* after = BuildIncrement(before, inc); |
- AddInstruction(after); |
+ HValue* value = Pop(); |
+ |
+ HInstruction* instr = BuildIncrement(value, inc); |
+ AddInstruction(instr); |
HInstruction* store = is_fast_elements |
- ? BuildStoreKeyedFastElement(obj, key, after, prop) |
- : new HStoreKeyedGeneric(obj, key, after); |
+ ? BuildStoreKeyedFastElement(obj, key, instr, prop) |
+ : new HStoreKeyedGeneric(obj, key, instr); |
AddInstruction(store); |
- // Drop the key from the bailout environment. Overwrite the receiver |
- // with the result of the operation, and the placeholder with the |
- // original value if necessary. |
- Drop(1); |
- environment()->SetExpressionStackAt(0, after); |
- if (has_extra) environment()->SetExpressionStackAt(1, before); |
- if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
- Drop(has_extra ? 2 : 1); |
- |
- ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
+ // Drop simulated receiver and key and push the result. |
+ // There is no deoptimization to after the increment, so we can simulate |
+ // the expression stack here. |
+ Drop(2); |
+ if (expr->is_prefix()) { |
+ Push(instr); |
+ } else { |
+ if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. |
+ Push(value); |
+ } |
} |
- |
} else { |
BAILOUT("invalid lhs in count operation"); |
} |
@@ -4722,47 +4630,21 @@ static bool IsClassOfTest(CompareOperation* expr) { |
void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
if (expr->op() == Token::COMMA) { |
VISIT_FOR_EFFECT(expr->left()); |
- // Visit the right subexpression in the same AST context as the entire |
- // expression. |
- Visit(expr->right()); |
- |
+ VISIT_FOR_VALUE(expr->right()); |
} else if (expr->op() == Token::AND || expr->op() == Token::OR) { |
- bool is_logical_and = (expr->op() == Token::AND); |
- if (ast_context()->IsTest()) { |
- TestContext* context = TestContext::cast(ast_context()); |
- // Translate left subexpression. |
- HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
- if (is_logical_and) { |
- VisitForControl(expr->left(), eval_right, context->if_false(), |
- false, context->invert_false()); |
- } else { |
- VisitForControl(expr->left(), context->if_true(), eval_right, |
- context->invert_true(), false); |
- } |
- if (HasStackOverflow()) return; |
- eval_right->SetJoinId(expr->left()->id()); |
- |
- // Translate right subexpression by visiting it in the same AST |
- // context as the entire expression. |
- eval_right->last_environment()->Pop(); |
- subgraph()->set_exit_block(eval_right); |
- Visit(expr->right()); |
+ VISIT_FOR_VALUE(expr->left()); |
+ ASSERT(current_subgraph_->HasExit()); |
- } else { |
- VISIT_FOR_VALUE(expr->left()); |
- ASSERT(current_subgraph_->HasExit()); |
- |
- HValue* left = Top(); |
- HEnvironment* environment_copy = environment()->Copy(); |
- environment_copy->Pop(); |
- HSubgraph* right_subgraph; |
- right_subgraph = CreateBranchSubgraph(environment_copy); |
- ADD_TO_SUBGRAPH(right_subgraph, expr->right()); |
- current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); |
- current_subgraph_->exit_block()->SetJoinId(expr->id()); |
- ast_context()->ReturnValue(Pop()); |
- } |
+ HValue* left = Top(); |
+ bool is_logical_and = (expr->op() == Token::AND); |
+ HEnvironment* environment_copy = environment()->Copy(); |
+ environment_copy->Pop(); |
+ HSubgraph* right_subgraph; |
+ right_subgraph = CreateBranchSubgraph(environment_copy); |
+ ADD_TO_SUBGRAPH(right_subgraph, expr->right()); |
+ current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); |
+ current_subgraph_->exit_block()->SetJoinId(expr->id()); |
} else { |
VISIT_FOR_VALUE(expr->left()); |
VISIT_FOR_VALUE(expr->right()); |
@@ -4770,8 +4652,7 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
HInstruction* instr = BuildBinaryOperation(expr, left, right); |
- instr->set_position(expr->position()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr, expr->position()); |
} |
} |
@@ -4810,8 +4691,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
Literal* literal = expr->right()->AsLiteral(); |
Handle<String> rhs = Handle<String>::cast(literal->handle()); |
HInstruction* instr = new HClassOfTest(value, rhs); |
- instr->set_position(expr->position()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr, expr->position()); |
return; |
} |
@@ -4825,8 +4705,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
HValue* left = Pop(); |
HInstruction* instr = new HTypeofIs(left, |
Handle<String>::cast(right_literal->handle())); |
- instr->set_position(expr->position()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr, expr->position()); |
return; |
} |
@@ -4862,8 +4741,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
compare->SetInputRepresentation(r); |
instr = compare; |
} |
- instr->set_position(expr->position()); |
- ast_context()->ReturnInstruction(instr, expr->id()); |
+ PushAndAdd(instr, expr->position()); |
} |
@@ -4872,7 +4750,8 @@ void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
HValue* value = Pop(); |
HIsNull* compare = new HIsNull(value, expr->is_strict()); |
- ast_context()->ReturnInstruction(compare, expr->id()); |
+ |
+ PushAndAdd(compare); |
} |
@@ -4899,305 +4778,301 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
// Generators for inline runtime functions. |
// Support for types. |
-void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsSmi(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HIsSmi* result = new HIsSmi(value); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HIsSmi(value)); |
} |
-void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsSpecObject(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HHasInstanceType* result = |
+ HHasInstanceType* test = |
new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(test); |
} |
-void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsFunction(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ HHasInstanceType* test = |
+ new HHasInstanceType(value, JS_FUNCTION_TYPE); |
+ PushAndAdd(test); |
} |
-void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value); |
+ PushAndAdd(spec_test); |
} |
-void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsArray(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ HHasInstanceType* test = |
+ new HHasInstanceType(value, JS_ARRAY_TYPE); |
+ PushAndAdd(test); |
} |
-void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsRegExp(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ HHasInstanceType* test = |
+ new HHasInstanceType(value, JS_REGEXP_TYPE); |
+ PushAndAdd(test); |
} |
-void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) { |
BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
} |
-void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsObject(int argument_count) { |
BAILOUT("inlined runtime function: IsObject"); |
} |
-void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) { |
BAILOUT("inlined runtime function: IsUndetectableObject"); |
} |
void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
- int argument_count, |
- int ast_id) { |
+ int argument_count) { |
BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
} |
// Support for construct call checks. |
-void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateIsConstructCall(int argument_count) { |
BAILOUT("inlined runtime function: IsConstructCall"); |
} |
// Support for arguments.length and arguments[?]. |
-void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateArgumentsLength(int argument_count) { |
ASSERT(argument_count == 0); |
HInstruction* elements = AddInstruction(new HArgumentsElements); |
- HArgumentsLength* result = new HArgumentsLength(elements); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HArgumentsLength(elements)); |
} |
-void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateArguments(int argument_count) { |
ASSERT(argument_count == 1); |
HValue* index = Pop(); |
HInstruction* elements = AddInstruction(new HArgumentsElements); |
HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
- HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HAccessArgumentsAt(elements, length, index)); |
} |
// Support for accessing the class and value fields of an object. |
-void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateClassOf(int argument_count) { |
// The special form detected by IsClassOfTest is detected before we get here |
// and does not cause a bailout. |
BAILOUT("inlined runtime function: ClassOf"); |
} |
-void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateValueOf(int argument_count) { |
ASSERT(argument_count == 1); |
+ |
HValue* value = Pop(); |
- HValueOf* result = new HValueOf(value); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ HValueOf* op = new HValueOf(value); |
+ PushAndAdd(op); |
} |
-void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateSetValueOf(int argument_count) { |
BAILOUT("inlined runtime function: SetValueOf"); |
} |
// Fast support for charCodeAt(n). |
-void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) { |
BAILOUT("inlined runtime function: StringCharCodeAt"); |
} |
// Fast support for string.charAt(n) and string[n]. |
-void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateStringCharFromCode(int argument_count) { |
BAILOUT("inlined runtime function: StringCharFromCode"); |
} |
// Fast support for string.charAt(n) and string[n]. |
-void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateStringCharAt(int argument_count) { |
ASSERT_EQ(2, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Fast support for object equality testing. |
-void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateObjectEquals(int argument_count) { |
ASSERT(argument_count == 2); |
+ |
HValue* right = Pop(); |
HValue* left = Pop(); |
- HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCompareJSObjectEq(left, right)); |
} |
-void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateLog(int argument_count) { |
UNREACHABLE(); // We caught this in VisitCallRuntime. |
} |
// Fast support for Math.random(). |
-void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) { |
BAILOUT("inlined runtime function: RandomHeapNumber"); |
} |
// Fast support for StringAdd. |
-void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateStringAdd(int argument_count) { |
ASSERT_EQ(2, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Fast support for SubString. |
-void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateSubString(int argument_count) { |
ASSERT_EQ(3, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::SubString, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Fast support for StringCompare. |
-void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateStringCompare(int argument_count) { |
ASSERT_EQ(2, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Support for direct calls from JavaScript to native RegExp code. |
-void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateRegExpExec(int argument_count) { |
ASSERT_EQ(4, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Construct a RegExp exec result with two in-object properties. |
-void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) { |
ASSERT_EQ(3, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = |
- new HCallStub(CodeStub::RegExpConstructResult, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Support for fast native caches. |
-void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateGetFromCache(int argument_count) { |
BAILOUT("inlined runtime function: GetFromCache"); |
} |
// Fast support for number to string. |
-void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateNumberToString(int argument_count) { |
ASSERT_EQ(1, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count), |
+ RelocInfo::kNoPosition); |
} |
// Fast swapping of elements. Takes three expressions, the object and two |
// indices. This should only be used if the indices are known to be |
// non-negative and within bounds of the elements array at the call site. |
-void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateSwapElements(int argument_count) { |
BAILOUT("inlined runtime function: SwapElements"); |
} |
// Fast call for custom callbacks. |
-void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateCallFunction(int argument_count) { |
BAILOUT("inlined runtime function: CallFunction"); |
} |
// Fast call to math functions. |
-void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateMathPow(int argument_count) { |
ASSERT_EQ(2, argument_count); |
- HValue* right = Pop(); |
- HValue* left = Pop(); |
- HPower* result = new HPower(left, right); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ PushArgumentsForStubCall(argument_count); |
+ PushAndAdd(new HCallStub(CodeStub::MathPow, argument_count), |
+ RelocInfo::kNoPosition); |
} |
-void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateMathSin(int argument_count) { |
ASSERT_EQ(1, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = |
+ HCallStub* instr = |
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
- result->set_transcendental_type(TranscendentalCache::SIN); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ instr->set_transcendental_type(TranscendentalCache::SIN); |
+ PushAndAdd(instr, RelocInfo::kNoPosition); |
} |
-void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateMathCos(int argument_count) { |
ASSERT_EQ(1, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = |
+ HCallStub* instr = |
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
- result->set_transcendental_type(TranscendentalCache::COS); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ instr->set_transcendental_type(TranscendentalCache::COS); |
+ PushAndAdd(instr, RelocInfo::kNoPosition); |
} |
-void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateMathLog(int argument_count) { |
ASSERT_EQ(1, argument_count); |
PushArgumentsForStubCall(argument_count); |
- HCallStub* result = |
+ HCallStub* instr = |
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
- result->set_transcendental_type(TranscendentalCache::LOG); |
- ast_context()->ReturnInstruction(result, ast_id); |
+ instr->set_transcendental_type(TranscendentalCache::LOG); |
+ PushAndAdd(instr, RelocInfo::kNoPosition); |
} |
-void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { |
+void HGraphBuilder::GenerateMathSqrt(int argument_count) { |
BAILOUT("inlined runtime function: MathSqrt"); |
} |
// Check whether two RegExps are equivalent |
-void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) { |
BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
} |
-void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) { |
BAILOUT("inlined runtime function: GetCachedArrayIndex"); |
} |
-void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, |
- int ast_id) { |
+void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) { |
BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
} |