Change the HGraphBuilder to dispatch on the context.

Before, expressions didn't take advantage of knowing their context in
the AST.  Now, we use the context to decide what to do with a value at
the end of visiting an expression.

Review URL: http://codereview.chromium.org/5620007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5954 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6691d531
...@@ -1983,6 +1983,9 @@ void HGraph::InsertRepresentationChanges() { ...@@ -1983,6 +1983,9 @@ void HGraph::InsertRepresentationChanges() {
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
: owner_(owner), kind_(kind), outer_(owner->ast_context()) { : owner_(owner), kind_(kind), outer_(owner->ast_context()) {
owner->set_ast_context(this); // Push. owner->set_ast_context(this); // Push.
#ifdef DEBUG
original_count_ = owner->environment()->total_count();
#endif
} }
...@@ -1991,6 +1994,101 @@ AstContext::~AstContext() { ...@@ -1991,6 +1994,101 @@ 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. // HGraphBuilder infrastructure for bailing out and checking bailouts.
#define BAILOUT(reason) \ #define BAILOUT(reason) \
...@@ -2061,55 +2159,14 @@ void HGraphBuilder::Bailout(const char* reason) { ...@@ -2061,55 +2159,14 @@ void HGraphBuilder::Bailout(const char* reason) {
void HGraphBuilder::VisitForEffect(Expression* expr) { void HGraphBuilder::VisitForEffect(Expression* expr) {
#ifdef DEBUG EffectContext for_effect(this);
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); 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) { void HGraphBuilder::VisitForValue(Expression* expr) {
#ifdef DEBUG ValueContext for_value(this);
int original_height = environment()->values()->length();
#endif
{ ValueContext for_value(this);
Visit(expr); 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);
} }
...@@ -2244,99 +2301,7 @@ void HGraphBuilder::VisitForControl(Expression* expr, ...@@ -2244,99 +2301,7 @@ void HGraphBuilder::VisitForControl(Expression* expr,
bool invert_false) { bool invert_false) {
TestContext for_test(this, true_block, false_block, TestContext for_test(this, true_block, false_block,
invert_true, invert_false); invert_true, invert_false);
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); 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);
}
} }
...@@ -2372,12 +2337,6 @@ void HGraphBuilder::PushAndAdd(HInstruction* instr) { ...@@ -2372,12 +2337,6 @@ void HGraphBuilder::PushAndAdd(HInstruction* instr) {
} }
void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) {
instr->set_position(position);
PushAndAdd(instr);
}
void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { void HGraphBuilder::PushArgumentsForStubCall(int argument_count) {
const int kMaxStubArguments = 4; const int kMaxStubArguments = 4;
ASSERT_GE(kMaxStubArguments, argument_count); ASSERT_GE(kMaxStubArguments, argument_count);
...@@ -2392,7 +2351,7 @@ void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { ...@@ -2392,7 +2351,7 @@ void HGraphBuilder::PushArgumentsForStubCall(int argument_count) {
} }
void HGraphBuilder::ProcessCall(HCall* call, int source_position) { void HGraphBuilder::ProcessCall(HCall* call) {
for (int i = call->argument_count() - 1; i >= 0; --i) { for (int i = call->argument_count() - 1; i >= 0; --i) {
HValue* value = Pop(); HValue* value = Pop();
HPushArgument* push = new HPushArgument(value); HPushArgument* push = new HPushArgument(value);
...@@ -2402,8 +2361,6 @@ void HGraphBuilder::ProcessCall(HCall* call, int source_position) { ...@@ -2402,8 +2361,6 @@ void HGraphBuilder::ProcessCall(HCall* call, int source_position) {
for (int i = 0; i < call->argument_count(); ++i) { for (int i = 0; i < call->argument_count(); ++i) {
AddInstruction(call->PushArgumentAt(i)); AddInstruction(call->PushArgumentAt(i));
} }
PushAndAdd(call, source_position);
} }
...@@ -2914,7 +2871,9 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -2914,7 +2871,9 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo> shared_info =
Compiler::BuildFunctionInfo(expr, graph_->info()->script()); Compiler::BuildFunctionInfo(expr, graph_->info()->script());
CHECK_BAILOUT; CHECK_BAILOUT;
PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure())); HFunctionLiteral* instr =
new HFunctionLiteral(shared_info, expr->pretenure());
ast_context()->ReturnInstruction(instr, expr->id());
} }
...@@ -2935,20 +2894,21 @@ void HGraphBuilder::VisitConditional(Conditional* expr) { ...@@ -2935,20 +2894,21 @@ void HGraphBuilder::VisitConditional(Conditional* expr) {
ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); ADD_TO_SUBGRAPH(then_graph, expr->then_expression());
ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); ADD_TO_SUBGRAPH(else_graph, expr->else_expression());
current_subgraph_->AppendJoin(then_graph, else_graph, expr); current_subgraph_->AppendJoin(then_graph, else_graph, expr);
ast_context()->ReturnValue(Pop());
} }
void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, void HGraphBuilder::LookupGlobalPropertyCell(Variable* var,
LookupResult* lookup, LookupResult* lookup,
bool is_store) { bool is_store) {
if (expr->is_this()) { if (var->is_this()) {
BAILOUT("global this reference"); BAILOUT("global this reference");
} }
if (!graph()->info()->has_global_object()) { if (!graph()->info()->has_global_object()) {
BAILOUT("no global object to optimize VariableProxy"); BAILOUT("no global object to optimize VariableProxy");
} }
Handle<GlobalObject> global(graph()->info()->global_object()); Handle<GlobalObject> global(graph()->info()->global_object());
global->Lookup(*expr->name(), lookup); global->Lookup(*var->name(), lookup);
if (!lookup->IsProperty()) { if (!lookup->IsProperty()) {
BAILOUT("global variable cell not yet introduced"); BAILOUT("global variable cell not yet introduced");
} }
...@@ -2961,9 +2921,18 @@ void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, ...@@ -2961,9 +2921,18 @@ void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr,
} }
void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) { void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
Variable* variable = expr->AsVariable();
if (variable == NULL) {
BAILOUT("reference to rewritten variable");
} else if (variable->IsStackAllocated()) {
if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) {
BAILOUT("unsupported context for arguments object");
}
ast_context()->ReturnValue(environment()->Lookup(variable));
} else if (variable->is_global()) {
LookupResult lookup; LookupResult lookup;
LookupGlobalPropertyCell(expr, &lookup, false); LookupGlobalPropertyCell(variable, &lookup, false);
CHECK_BAILOUT; CHECK_BAILOUT;
Handle<GlobalObject> global(graph()->info()->global_object()); Handle<GlobalObject> global(graph()->info()->global_object());
...@@ -2974,21 +2943,8 @@ void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) { ...@@ -2974,21 +2943,8 @@ void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) {
} }
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
PushAndAdd(new HLoadGlobal(cell, check_hole)); HLoadGlobal* instr = new HLoadGlobal(cell, check_hole);
} ast_context()->ReturnInstruction(instr, expr->id());
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
Variable* variable = expr->AsVariable();
if (variable == NULL) {
BAILOUT("reference to rewritten variable");
} else if (variable->IsStackAllocated()) {
if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) {
BAILOUT("unsupported context for arguments object");
}
Push(environment()->Lookup(variable));
} else if (variable->is_global()) {
HandleGlobalVariableLoad(expr);
} else { } else {
BAILOUT("reference to non-stack-allocated/non-global variable"); BAILOUT("reference to non-stack-allocated/non-global variable");
} }
...@@ -2996,14 +2952,16 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { ...@@ -2996,14 +2952,16 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
void HGraphBuilder::VisitLiteral(Literal* expr) { void HGraphBuilder::VisitLiteral(Literal* expr) {
PushAndAdd(new HConstant(expr->handle(), Representation::Tagged())); HConstant* instr = new HConstant(expr->handle(), Representation::Tagged());
ast_context()->ReturnInstruction(instr, expr->id());
} }
void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
PushAndAdd(new HRegExpLiteral(expr->pattern(), HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(),
expr->flags(), expr->flags(),
expr->literal_index())); expr->literal_index());
ast_context()->ReturnInstruction(instr, expr->id());
} }
...@@ -3012,6 +2970,8 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -3012,6 +2970,8 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
expr->fast_elements(), expr->fast_elements(),
expr->literal_index(), expr->literal_index(),
expr->depth())); 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); PushAndAdd(literal);
expr->CalculateEmitStore(); expr->CalculateEmitStore();
...@@ -3048,6 +3008,7 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -3048,6 +3008,7 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
default: UNREACHABLE(); default: UNREACHABLE();
} }
} }
ast_context()->ReturnValue(Pop());
} }
...@@ -3059,6 +3020,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -3059,6 +3020,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
length, length,
expr->literal_index(), expr->literal_index(),
expr->depth()); 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); PushAndAdd(literal);
HValue* elements = AddInstruction(new HLoadElements(literal)); HValue* elements = AddInstruction(new HLoadElements(literal));
...@@ -3076,6 +3039,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -3076,6 +3039,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
AddInstruction(new HStoreKeyedFastElement(elements, key, value)); AddInstruction(new HStoreKeyedFastElement(elements, key, value));
AddSimulate(expr->GetIdForElement(i)); AddSimulate(expr->GetIdForElement(i));
} }
ast_context()->ReturnValue(Pop());
} }
...@@ -3257,9 +3221,8 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, ...@@ -3257,9 +3221,8 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
Push(value); Push(value);
instr->set_position(expr->position()); instr->set_position(expr->position());
AddInstruction(instr); AddInstruction(instr);
return; if (instr->HasSideEffects()) AddSimulate(expr->id());
} } else {
// Build subgraph for generic store through IC. // Build subgraph for generic store through IC.
{ {
HSubgraph* subgraph = CreateBranchSubgraph(environment()); HSubgraph* subgraph = CreateBranchSubgraph(environment());
...@@ -3277,7 +3240,10 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, ...@@ -3277,7 +3240,10 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
HBasicBlock* new_exit_block = HBasicBlock* new_exit_block =
BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
current_subgraph_->set_exit_block(new_exit_block); subgraph()->set_exit_block(new_exit_block);
}
if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
} }
...@@ -3333,14 +3299,20 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { ...@@ -3333,14 +3299,20 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
Push(value); Push(value);
instr->set_position(expr->position()); instr->set_position(expr->position());
AddInstruction(instr); AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(expr->id());
ast_context()->ReturnValue(Pop());
} }
void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, // 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,
HValue* value, HValue* value,
int position) { int position,
int ast_id) {
LookupResult lookup; LookupResult lookup;
LookupGlobalPropertyCell(proxy, &lookup, true); LookupGlobalPropertyCell(var, &lookup, true);
CHECK_BAILOUT; CHECK_BAILOUT;
Handle<GlobalObject> global(graph()->info()->global_object()); Handle<GlobalObject> global(graph()->info()->global_object());
...@@ -3348,6 +3320,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, ...@@ -3348,6 +3320,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy,
HInstruction* instr = new HStoreGlobal(value, cell); HInstruction* instr = new HStoreGlobal(value, cell);
instr->set_position(position); instr->set_position(position);
AddInstruction(instr); AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(ast_id);
} }
...@@ -3371,10 +3344,12 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -3371,10 +3344,12 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
VISIT_FOR_VALUE(operation); VISIT_FOR_VALUE(operation);
if (var->is_global()) { if (var->is_global()) {
HandleGlobalVariableAssignment(proxy, Top(), expr->position()); HandleGlobalVariableAssignment(var, Top(), expr->position(), expr->id());
} else { } else {
Bind(var, Top()); Bind(var, Top());
} }
ast_context()->ReturnValue(Pop());
} else if (prop != NULL) { } else if (prop != NULL) {
prop->RecordTypeFeedback(oracle()); prop->RecordTypeFeedback(oracle());
...@@ -3392,9 +3367,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -3392,9 +3367,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
load = BuildLoadNamedGeneric(obj, prop); load = BuildLoadNamedGeneric(obj, prop);
} }
PushAndAdd(load); PushAndAdd(load);
if (load->HasSideEffects()) { if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id());
AddSimulate(expr->compound_bailout_id());
}
VISIT_FOR_VALUE(expr->value()); VISIT_FOR_VALUE(expr->value());
HValue* right = Pop(); HValue* right = Pop();
...@@ -3406,10 +3379,11 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -3406,10 +3379,11 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
HInstruction* store = BuildStoreNamed(obj, instr, prop); HInstruction* store = BuildStoreNamed(obj, instr, prop);
AddInstruction(store); AddInstruction(store);
if (store->HasSideEffects()) AddSimulate(expr->id());
// Drop the simulated receiver and value and put back the value. // Drop the simulated receiver and value. Return the value.
Drop(2); Drop(2);
Push(instr); ast_context()->ReturnValue(instr);
} else { } else {
// Keyed property. // Keyed property.
...@@ -3425,9 +3399,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -3425,9 +3399,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
? BuildLoadKeyedFastElement(obj, key, prop) ? BuildLoadKeyedFastElement(obj, key, prop)
: BuildLoadKeyedGeneric(obj, key); : BuildLoadKeyedGeneric(obj, key);
PushAndAdd(load); PushAndAdd(load);
if (load->HasSideEffects()) { if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id());
AddSimulate(expr->compound_bailout_id());
}
VISIT_FOR_VALUE(expr->value()); VISIT_FOR_VALUE(expr->value());
HValue* right = Pop(); HValue* right = Pop();
...@@ -3441,11 +3413,13 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ...@@ -3441,11 +3413,13 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
? BuildStoreKeyedFastElement(obj, key, instr, prop) ? BuildStoreKeyedFastElement(obj, key, instr, prop)
: BuildStoreKeyedGeneric(obj, key, instr); : BuildStoreKeyedGeneric(obj, key, instr);
AddInstruction(store); AddInstruction(store);
if (store->HasSideEffects()) AddSimulate(expr->id());
// Drop the simulated receiver, key and value and put back the value. // Drop the simulated receiver, key, and value. Return the value.
Drop(3); Drop(3);
Push(instr); ast_context()->ReturnValue(instr);
} }
} else { } else {
BAILOUT("invalid lhs in compound assignment"); BAILOUT("invalid lhs in compound assignment");
} }
...@@ -3465,9 +3439,11 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -3465,9 +3439,11 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
if (var != NULL) { if (var != NULL) {
if (proxy->IsArguments()) BAILOUT("assignment to arguments"); if (proxy->IsArguments()) BAILOUT("assignment to arguments");
// Handle the assignment.
if (var->is_global()) { if (var->is_global()) {
VISIT_FOR_VALUE(expr->value()); VISIT_FOR_VALUE(expr->value());
HandleGlobalVariableAssignment(proxy, Top(), expr->position()); HandleGlobalVariableAssignment(var, Top(), expr->position(), expr->id());
} else { } else {
// We allow reference to the arguments object only in assignemtns // We allow reference to the arguments object only in assignemtns
// to local variables to make sure that the arguments object does // to local variables to make sure that the arguments object does
...@@ -3480,9 +3456,11 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -3480,9 +3456,11 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
} else { } else {
VISIT_FOR_VALUE(expr->value()); VISIT_FOR_VALUE(expr->value());
} }
Bind(proxy->var(), Top()); Bind(proxy->var(), Top());
} }
// Return the value.
ast_context()->ReturnValue(Pop());
} else if (prop != NULL) { } else if (prop != NULL) {
HandlePropertyAssignment(expr); HandlePropertyAssignment(expr);
} else { } else {
...@@ -3492,6 +3470,10 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -3492,6 +3470,10 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
void HGraphBuilder::VisitThrow(Throw* 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()); VISIT_FOR_VALUE(expr->exception());
HValue* value = environment()->Pop(); HValue* value = environment()->Pop();
...@@ -3525,7 +3507,8 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, ...@@ -3525,7 +3507,8 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
SubgraphScope scope(this, subgraph); SubgraphScope scope(this, subgraph);
HInstruction* instr = HInstruction* instr =
BuildLoadNamedField(object, expr, map, &lookup, false); BuildLoadNamedField(object, expr, map, &lookup, false);
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
PushAndAdd(instr);
subgraphs.Add(subgraph); subgraphs.Add(subgraph);
} else { } else {
needs_generic = true; needs_generic = true;
...@@ -3536,10 +3519,10 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, ...@@ -3536,10 +3519,10 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
// generic load. // generic load.
if (maps.length() == 0) { if (maps.length() == 0) {
HInstruction* instr = BuildLoadNamedGeneric(object, expr); HInstruction* instr = BuildLoadNamedGeneric(object, expr);
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
return; PushAndAdd(instr);
} if (instr->HasSideEffects()) AddSimulate(expr->id());
} else {
// Build subgraph for generic load through IC. // Build subgraph for generic load through IC.
{ {
HSubgraph* subgraph = CreateBranchSubgraph(environment()); HSubgraph* subgraph = CreateBranchSubgraph(environment());
...@@ -3548,14 +3531,18 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, ...@@ -3548,14 +3531,18 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
subgraph->FinishExit(new HDeoptimize()); subgraph->FinishExit(new HDeoptimize());
} else { } else {
HInstruction* instr = BuildLoadNamedGeneric(object, expr); HInstruction* instr = BuildLoadNamedGeneric(object, expr);
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
PushAndAdd(instr);
} }
subgraphs.Add(subgraph); subgraphs.Add(subgraph);
} }
HBasicBlock* new_exit_block = HBasicBlock* new_exit_block =
BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
current_subgraph_->set_exit_block(new_exit_block); subgraph()->set_exit_block(new_exit_block);
}
if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
} }
...@@ -3668,11 +3655,12 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { ...@@ -3668,11 +3655,12 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
return false; return false;
} }
HInstruction* result = NULL;
if (expr->key()->IsPropertyName()) { if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
if (!name->IsEqualTo(CStrVector("length"))) return false; if (!name->IsEqualTo(CStrVector("length"))) return false;
HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* elements = AddInstruction(new HArgumentsElements);
PushAndAdd(new HArgumentsLength(elements)); result = new HArgumentsLength(elements);
} else { } else {
VisitForValue(expr->key()); VisitForValue(expr->key());
if (HasStackOverflow()) return false; if (HasStackOverflow()) return false;
...@@ -3680,8 +3668,9 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { ...@@ -3680,8 +3668,9 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* elements = AddInstruction(new HArgumentsElements);
HInstruction* length = AddInstruction(new HArgumentsLength(elements)); HInstruction* length = AddInstruction(new HArgumentsLength(elements));
AddInstruction(new HBoundsCheck(key, length)); AddInstruction(new HBoundsCheck(key, length));
PushAndAdd(new HAccessArgumentsAt(elements, length, key)); result = new HAccessArgumentsAt(elements, length, key);
} }
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} }
...@@ -3728,7 +3717,8 @@ void HGraphBuilder::VisitProperty(Property* expr) { ...@@ -3728,7 +3717,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
? BuildLoadKeyedFastElement(obj, key, expr) ? BuildLoadKeyedFastElement(obj, key, expr)
: BuildLoadKeyedGeneric(obj, key); : BuildLoadKeyedGeneric(obj, key);
} }
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
} }
...@@ -3763,9 +3753,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, ...@@ -3763,9 +3753,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
// Build subgraphs for each of the specific maps. // Build subgraphs for each of the specific maps.
// //
// TODO(ager): We should recognize when the prototype chains for // TODO(ager): We should recognize when the prototype chains for different
// different maps are identical. In that case we can avoid // maps are identical. In that case we can avoid repeatedly generating the
// repeatedly generating the same prototype map checks. // same prototype map checks.
for (int i = 0; i < number_of_types; ++i) { for (int i = 0; i < number_of_types; ++i) {
Handle<Map> map = types->at(i); Handle<Map> map = types->at(i);
if (expr->ComputeTarget(map, name)) { if (expr->ComputeTarget(map, name)) {
...@@ -3782,7 +3772,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, ...@@ -3782,7 +3772,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
// during hydrogen processing. // during hydrogen processing.
CHECK_BAILOUT; CHECK_BAILOUT;
HCall* call = new HCallConstantFunction(expr->target(), argument_count); HCall* call = new HCallConstantFunction(expr->target(), argument_count);
ProcessCall(call, expr->position()); call->set_position(expr->position());
ProcessCall(call);
PushAndAdd(call);
} }
subgraphs.Add(subgraph); subgraphs.Add(subgraph);
} else { } else {
...@@ -3790,14 +3782,14 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, ...@@ -3790,14 +3782,14 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
} }
} }
// If we couldn't compute the target for any of the maps just // If we couldn't compute the target for any of the maps just perform an
// perform an IC call. // IC call.
if (maps.length() == 0) { if (maps.length() == 0) {
HCall* call = new HCallNamed(name, argument_count); HCall* call = new HCallNamed(name, argument_count);
ProcessCall(call, expr->position()); call->set_position(expr->position());
return; ProcessCall(call);
} ast_context()->ReturnInstruction(call, expr->id());
} else {
// Build subgraph for generic call through IC. // Build subgraph for generic call through IC.
{ {
HSubgraph* subgraph = CreateBranchSubgraph(environment()); HSubgraph* subgraph = CreateBranchSubgraph(environment());
...@@ -3806,14 +3798,18 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, ...@@ -3806,14 +3798,18 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
subgraph->FinishExit(new HDeoptimize()); subgraph->FinishExit(new HDeoptimize());
} else { } else {
HCall* call = new HCallNamed(name, argument_count); HCall* call = new HCallNamed(name, argument_count);
ProcessCall(call, expr->position()); call->set_position(expr->position());
ProcessCall(call);
PushAndAdd(call);
} }
subgraphs.Add(subgraph); subgraphs.Add(subgraph);
} }
HBasicBlock* new_exit_block = HBasicBlock* new_exit_block =
BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id());
current_subgraph_->set_exit_block(new_exit_block); subgraph()->set_exit_block(new_exit_block);
if (new_exit_block != NULL) ast_context()->ReturnValue(Pop());
}
} }
...@@ -4061,6 +4057,7 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4061,6 +4057,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
function_return_ = saved_function_return; function_return_ = saved_function_return;
oracle_ = saved_oracle; oracle_ = saved_oracle;
graph()->info()->SetOsrAstId(saved_osr_ast_id); graph()->info()->SetOsrAstId(saved_osr_ast_id);
return true; return true;
} }
...@@ -4086,10 +4083,10 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { ...@@ -4086,10 +4083,10 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
case kMathSqrt: case kMathSqrt:
if (argument_count == 2) { if (argument_count == 2) {
HValue* argument = Pop(); HValue* argument = Pop();
// Pop receiver. Drop(1); // Receiver.
Pop();
HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); HUnaryMathOperation* op = new HUnaryMathOperation(argument, id);
PushAndAdd(op, expr->position()); op->set_position(expr->position());
ast_context()->ReturnInstruction(op, expr->id());
return true; return true;
} }
break; break;
...@@ -4098,11 +4095,13 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { ...@@ -4098,11 +4095,13 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
HValue* right = Pop(); HValue* right = Pop();
HValue* left = Pop(); HValue* left = Pop();
Pop(); // Pop receiver. Pop(); // Pop receiver.
HInstruction* result = NULL;
// Use sqrt() if exponent is 0.5 or -0.5. // Use sqrt() if exponent is 0.5 or -0.5.
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
double exponent = HConstant::cast(right)->DoubleValue(); double exponent = HConstant::cast(right)->DoubleValue();
if (exponent == 0.5) { if (exponent == 0.5) {
PushAndAdd(new HUnaryMathOperation(left, kMathPowHalf)); result = new HUnaryMathOperation(left, kMathPowHalf);
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} else if (exponent == -0.5) { } else if (exponent == -0.5) {
HConstant* double_one = HConstant* double_one =
...@@ -4112,20 +4111,27 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { ...@@ -4112,20 +4111,27 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
HUnaryMathOperation* square_root = HUnaryMathOperation* square_root =
new HUnaryMathOperation(left, kMathPowHalf); new HUnaryMathOperation(left, kMathPowHalf);
AddInstruction(square_root); AddInstruction(square_root);
PushAndAdd(new HDiv(double_one, 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; return true;
} else if (exponent == 2.0) { } else if (exponent == 2.0) {
PushAndAdd(new HMul(left, left)); result = new HMul(left, left);
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} }
} else if (right->IsConstant() && } else if (right->IsConstant() &&
HConstant::cast(right)->HasInteger32Value() && HConstant::cast(right)->HasInteger32Value() &&
HConstant::cast(right)->Integer32Value() == 2) { HConstant::cast(right)->Integer32Value() == 2) {
PushAndAdd(new HMul(left, left)); result = new HMul(left, left);
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} }
PushAndAdd(new HPower(left, right)); result = new HPower(left, right);
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} }
break; break;
...@@ -4170,8 +4176,10 @@ bool HGraphBuilder::TryCallApply(Call* expr) { ...@@ -4170,8 +4176,10 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
function, function,
expr->GetReceiverTypes()->first(), expr->GetReceiverTypes()->first(),
true); true);
PushAndAdd(new HApplyArguments(function, receiver, length, elements), HInstruction* result =
expr->position()); new HApplyArguments(function, receiver, length, elements);
result->set_position(expr->position());
ast_context()->ReturnInstruction(result, expr->id());
return true; return true;
} }
...@@ -4199,12 +4207,10 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -4199,12 +4207,10 @@ void HGraphBuilder::VisitCall(Call* expr) {
CHECK_BAILOUT; CHECK_BAILOUT;
call = new HCallKeyed(key, argument_count); call = new HCallKeyed(key, argument_count);
ProcessCall(call, expr->position()); call->set_position(expr->position());
HValue* result = Pop(); ProcessCall(call);
// Drop the receiver from the environment and put back the result of Drop(1); // Key.
// the call. ast_context()->ReturnInstruction(call, expr->id());
Drop(1);
Push(result);
return; return;
} }
...@@ -4227,7 +4233,19 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -4227,7 +4233,19 @@ void HGraphBuilder::VisitCall(Call* expr) {
if (expr->IsMonomorphic()) { if (expr->IsMonomorphic()) {
AddCheckConstantFunction(expr, receiver, types->first(), true); AddCheckConstantFunction(expr, receiver, types->first(), true);
if (TryMathFunctionInline(expr) || TryInline(expr)) { 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);
}
return; return;
} else { } else {
// Check for bailout, as the TryInline call in the if condition above // Check for bailout, as the TryInline call in the if condition above
...@@ -4235,6 +4253,7 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -4235,6 +4253,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
CHECK_BAILOUT; CHECK_BAILOUT;
call = new HCallConstantFunction(expr->target(), argument_count); call = new HCallConstantFunction(expr->target(), argument_count);
} }
} else if (types != NULL && types->length() > 1) { } else if (types != NULL && types->length() > 1) {
HandlePolymorphicCallNamed(expr, receiver, types, name); HandlePolymorphicCallNamed(expr, receiver, types, name);
return; return;
...@@ -4282,7 +4301,19 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -4282,7 +4301,19 @@ void HGraphBuilder::VisitCall(Call* expr) {
IsGlobalObject()); IsGlobalObject());
environment()->SetExpressionStackAt(receiver_index, global_receiver); environment()->SetExpressionStackAt(receiver_index, global_receiver);
if (TryInline(expr)) return; 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;
}
// Check for bailout, as trying to inline might fail due to bailout // Check for bailout, as trying to inline might fail due to bailout
// during hydrogen processing. // during hydrogen processing.
CHECK_BAILOUT; CHECK_BAILOUT;
...@@ -4305,7 +4336,9 @@ void HGraphBuilder::VisitCall(Call* expr) { ...@@ -4305,7 +4336,9 @@ void HGraphBuilder::VisitCall(Call* expr) {
} }
} }
ProcessCall(call, expr->position()); call->set_position(expr->position());
ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
} }
...@@ -4319,8 +4352,9 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { ...@@ -4319,8 +4352,9 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) {
int argument_count = expr->arguments()->length() + 1; // Plus constructor. int argument_count = expr->arguments()->length() + 1; // Plus constructor.
HCall* call = new HCallNew(argument_count); HCall* call = new HCallNew(argument_count);
call->set_position(expr->position());
ProcessCall(call, expr->position()); ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
} }
...@@ -4342,7 +4376,7 @@ const HGraphBuilder::InlineFunctionGenerator ...@@ -4342,7 +4376,7 @@ const HGraphBuilder::InlineFunctionGenerator
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->IsEqualTo(CStrVector("_Log"))) { if (name->IsEqualTo(CStrVector("_Log"))) {
Push(graph()->GetConstantUndefined()); ast_context()->ReturnValue(graph()->GetConstantUndefined());
return; return;
} }
...@@ -4368,11 +4402,13 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { ...@@ -4368,11 +4402,13 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
// Call the inline code generator using the pointer-to-member. // Call the inline code generator using the pointer-to-member.
(this->*generator)(argument_count); (this->*generator)(argument_count, expr->id());
} else { } else {
ASSERT(function->intrinsic_type == Runtime::RUNTIME); ASSERT(function->intrinsic_type == Runtime::RUNTIME);
HCall* call = new HCallRuntime(name, expr->function(), argument_count); HCall* call = new HCallRuntime(name, expr->function(), argument_count);
ProcessCall(call, RelocInfo::kNoPosition); call->set_position(RelocInfo::kNoPosition);
ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
} }
} }
...@@ -4381,7 +4417,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4381,7 +4417,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
Token::Value op = expr->op(); Token::Value op = expr->op();
if (op == Token::VOID) { if (op == Token::VOID) {
VISIT_FOR_EFFECT(expr->expression()); VISIT_FOR_EFFECT(expr->expression());
Push(graph()->GetConstantUndefined()); ast_context()->ReturnValue(graph()->GetConstantUndefined());
} else if (op == Token::DELETE) { } else if (op == Token::DELETE) {
Property* prop = expr->expression()->AsProperty(); Property* prop = expr->expression()->AsProperty();
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
...@@ -4389,26 +4425,35 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4389,26 +4425,35 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
// Result of deleting non-property, non-variable reference is true. // Result of deleting non-property, non-variable reference is true.
// Evaluate the subexpression for side effects. // Evaluate the subexpression for side effects.
VISIT_FOR_EFFECT(expr->expression()); VISIT_FOR_EFFECT(expr->expression());
Push(graph_->GetConstantTrue()); ast_context()->ReturnValue(graph()->GetConstantTrue());
} else if (var != NULL && } else if (var != NULL &&
!var->is_global() && !var->is_global() &&
var->AsSlot() != NULL && var->AsSlot() != NULL &&
var->AsSlot()->type() != Slot::LOOKUP) { var->AsSlot()->type() != Slot::LOOKUP) {
// Result of deleting non-global, non-dynamic variables is false. // Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects. // The subexpression does not have side effects.
Push(graph_->GetConstantFalse()); ast_context()->ReturnValue(graph()->GetConstantFalse());
} else if (prop != NULL) { } else if (prop != NULL) {
VISIT_FOR_VALUE(prop->obj()); VISIT_FOR_VALUE(prop->obj());
VISIT_FOR_VALUE(prop->key()); VISIT_FOR_VALUE(prop->key());
HValue* key = Pop(); HValue* key = Pop();
HValue* obj = Pop(); HValue* obj = Pop();
PushAndAdd(new HDeleteProperty(obj, key)); ast_context()->ReturnInstruction(new HDeleteProperty(obj, key),
expr->id());
} else if (var->is_global()) { } else if (var->is_global()) {
BAILOUT("delete with global variable"); BAILOUT("delete with global variable");
} else { } else {
BAILOUT("delete with non-global variable"); BAILOUT("delete with non-global variable");
} }
} else if (op == Token::NOT) { } 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* true_graph = CreateEmptySubgraph();
HSubgraph* false_graph = CreateEmptySubgraph(); HSubgraph* false_graph = CreateEmptySubgraph();
VisitCondition(expr->expression(), VisitCondition(expr->expression(),
...@@ -4419,6 +4464,8 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4419,6 +4464,8 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
true_graph->environment()->Push(graph_->GetConstantTrue()); true_graph->environment()->Push(graph_->GetConstantTrue());
false_graph->environment()->Push(graph_->GetConstantFalse()); false_graph->environment()->Push(graph_->GetConstantFalse());
current_subgraph_->AppendJoin(true_graph, false_graph, expr); current_subgraph_->AppendJoin(true_graph, false_graph, expr);
ast_context()->ReturnValue(Pop());
}
} else if (op == Token::BIT_NOT || op == Token::SUB) { } else if (op == Token::BIT_NOT || op == Token::SUB) {
VISIT_FOR_VALUE(expr->expression()); VISIT_FOR_VALUE(expr->expression());
HValue* value = Pop(); HValue* value = Pop();
...@@ -4434,11 +4481,11 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4434,11 +4481,11 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
PushAndAdd(instr); ast_context()->ReturnInstruction(instr, expr->id());
} else if (op == Token::TYPEOF) { } else if (op == Token::TYPEOF) {
VISIT_FOR_VALUE(expr->expression()); VISIT_FOR_VALUE(expr->expression());
HValue* value = Pop(); HValue* value = Pop();
PushAndAdd(new HTypeof(value)); ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
} else { } else {
BAILOUT("Value: unsupported unary operation"); BAILOUT("Value: unsupported unary operation");
} }
...@@ -4489,11 +4536,12 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4489,11 +4536,12 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
} }
if (var->is_global()) { if (var->is_global()) {
HandleGlobalVariableAssignment(proxy, instr, expr->position()); HandleGlobalVariableAssignment(var, instr, expr->position(), expr->id());
} else { } else {
ASSERT(var->IsStackAllocated()); ASSERT(var->IsStackAllocated());
Bind(var, instr); Bind(var, instr);
} }
ast_context()->ReturnValue(Pop());
} else if (prop != NULL) { } else if (prop != NULL) {
prop->RecordTypeFeedback(oracle()); prop->RecordTypeFeedback(oracle());
...@@ -4501,8 +4549,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4501,8 +4549,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
if (prop->key()->IsPropertyName()) { if (prop->key()->IsPropertyName()) {
// Named property. // Named property.
// Match the full code generator stack by simulate an extra stack element // Match the full code generator stack by simulating an extra stack
// for postfix operations in a value context. // element for postfix operations in a value context.
if (expr->is_postfix() && !ast_context()->IsEffect()) { if (expr->is_postfix() && !ast_context()->IsEffect()) {
Push(graph_->GetConstantUndefined()); Push(graph_->GetConstantUndefined());
} }
...@@ -4523,6 +4571,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4523,6 +4571,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* value = Pop(); HValue* value = Pop();
// There is no deoptimization to after the increment, so we don't need
// to simulate the expression stack after this instruction.
HInstruction* instr = BuildIncrement(value, inc); HInstruction* instr = BuildIncrement(value, inc);
AddInstruction(instr); AddInstruction(instr);
...@@ -4530,8 +4580,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4530,8 +4580,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
AddInstruction(store); AddInstruction(store);
// Drop simulated receiver and push the result. // 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); Drop(1);
if (expr->is_prefix()) { if (expr->is_prefix()) {
Push(instr); Push(instr);
...@@ -4540,6 +4588,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4540,6 +4588,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
Push(value); Push(value);
} }
if (store->HasSideEffects()) AddSimulate(expr->id());
ast_context()->ReturnValue(Pop());
} else { } else {
// Keyed property. // Keyed property.
...@@ -4566,6 +4617,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4566,6 +4617,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* value = Pop(); HValue* value = Pop();
// There is no deoptimization to after the increment, so we don't need
// to simulate the expression stack after this instruction.
HInstruction* instr = BuildIncrement(value, inc); HInstruction* instr = BuildIncrement(value, inc);
AddInstruction(instr); AddInstruction(instr);
...@@ -4575,8 +4628,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4575,8 +4628,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
AddInstruction(store); AddInstruction(store);
// Drop simulated receiver and key and push the result. // 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); Drop(2);
if (expr->is_prefix()) { if (expr->is_prefix()) {
Push(instr); Push(instr);
...@@ -4584,7 +4635,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -4584,7 +4635,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero.
Push(value); Push(value);
} }
if (store->HasSideEffects()) AddSimulate(expr->id());
ast_context()->ReturnValue(Pop());
} }
} else { } else {
BAILOUT("invalid lhs in count operation"); BAILOUT("invalid lhs in count operation");
} }
...@@ -4666,14 +4721,37 @@ static bool IsClassOfTest(CompareOperation* expr) { ...@@ -4666,14 +4721,37 @@ static bool IsClassOfTest(CompareOperation* expr) {
void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
if (expr->op() == Token::COMMA) { if (expr->op() == Token::COMMA) {
VISIT_FOR_EFFECT(expr->left()); VISIT_FOR_EFFECT(expr->left());
VISIT_FOR_VALUE(expr->right()); // Visit the right subexpression in the same AST context as the entire
// expression.
Visit(expr->right());
} else if (expr->op() == Token::AND || expr->op() == Token::OR) { } 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());
} else {
VISIT_FOR_VALUE(expr->left()); VISIT_FOR_VALUE(expr->left());
ASSERT(current_subgraph_->HasExit()); ASSERT(current_subgraph_->HasExit());
HValue* left = Top(); HValue* left = Top();
bool is_logical_and = (expr->op() == Token::AND);
HEnvironment* environment_copy = environment()->Copy(); HEnvironment* environment_copy = environment()->Copy();
environment_copy->Pop(); environment_copy->Pop();
HSubgraph* right_subgraph; HSubgraph* right_subgraph;
...@@ -4681,6 +4759,9 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -4681,6 +4759,9 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
ADD_TO_SUBGRAPH(right_subgraph, expr->right()); ADD_TO_SUBGRAPH(right_subgraph, expr->right());
current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left);
current_subgraph_->exit_block()->SetJoinId(expr->id()); current_subgraph_->exit_block()->SetJoinId(expr->id());
ast_context()->ReturnValue(Pop());
}
} else { } else {
VISIT_FOR_VALUE(expr->left()); VISIT_FOR_VALUE(expr->left());
VISIT_FOR_VALUE(expr->right()); VISIT_FOR_VALUE(expr->right());
...@@ -4688,7 +4769,8 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -4688,7 +4769,8 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
HValue* right = Pop(); HValue* right = Pop();
HValue* left = Pop(); HValue* left = Pop();
HInstruction* instr = BuildBinaryOperation(expr, left, right); HInstruction* instr = BuildBinaryOperation(expr, left, right);
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
} }
} }
...@@ -4727,7 +4809,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -4727,7 +4809,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
Literal* literal = expr->right()->AsLiteral(); Literal* literal = expr->right()->AsLiteral();
Handle<String> rhs = Handle<String>::cast(literal->handle()); Handle<String> rhs = Handle<String>::cast(literal->handle());
HInstruction* instr = new HClassOfTest(value, rhs); HInstruction* instr = new HClassOfTest(value, rhs);
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
return; return;
} }
...@@ -4741,7 +4824,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -4741,7 +4824,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HValue* left = Pop(); HValue* left = Pop();
HInstruction* instr = new HTypeofIs(left, HInstruction* instr = new HTypeofIs(left,
Handle<String>::cast(right_literal->handle())); Handle<String>::cast(right_literal->handle()));
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
return; return;
} }
...@@ -4777,7 +4861,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -4777,7 +4861,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
compare->SetInputRepresentation(r); compare->SetInputRepresentation(r);
instr = compare; instr = compare;
} }
PushAndAdd(instr, expr->position()); instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
} }
...@@ -4786,8 +4871,7 @@ void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { ...@@ -4786,8 +4871,7 @@ void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) {
HValue* value = Pop(); HValue* value = Pop();
HIsNull* compare = new HIsNull(value, expr->is_strict()); HIsNull* compare = new HIsNull(value, expr->is_strict());
ast_context()->ReturnInstruction(compare, expr->id());
PushAndAdd(compare);
} }
...@@ -4814,301 +4898,305 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) { ...@@ -4814,301 +4898,305 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) {
// Generators for inline runtime functions. // Generators for inline runtime functions.
// Support for types. // Support for types.
void HGraphBuilder::GenerateIsSmi(int argument_count) { void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
PushAndAdd(new HIsSmi(value)); HIsSmi* result = new HIsSmi(value);
ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateIsSpecObject(int argument_count) { void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HHasInstanceType* test = HHasInstanceType* result =
new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE);
PushAndAdd(test); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateIsFunction(int argument_count) { void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HHasInstanceType* test = HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE);
new HHasInstanceType(value, JS_FUNCTION_TYPE); ast_context()->ReturnInstruction(result, ast_id);
PushAndAdd(test);
} }
void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) { void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count,
int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value); HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value);
PushAndAdd(spec_test); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateIsArray(int argument_count) { void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HHasInstanceType* test = HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE);
new HHasInstanceType(value, JS_ARRAY_TYPE); ast_context()->ReturnInstruction(result, ast_id);
PushAndAdd(test);
} }
void HGraphBuilder::GenerateIsRegExp(int argument_count) { void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HHasInstanceType* test = HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE);
new HHasInstanceType(value, JS_REGEXP_TYPE); ast_context()->ReturnInstruction(result, ast_id);
PushAndAdd(test);
} }
void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) { void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: IsNonNegativeSmi"); BAILOUT("inlined runtime function: IsNonNegativeSmi");
} }
void HGraphBuilder::GenerateIsObject(int argument_count) { void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: IsObject"); BAILOUT("inlined runtime function: IsObject");
} }
void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) { void HGraphBuilder::GenerateIsUndetectableObject(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: IsUndetectableObject"); BAILOUT("inlined runtime function: IsUndetectableObject");
} }
void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
int argument_count) { int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
} }
// Support for construct call checks. // Support for construct call checks.
void HGraphBuilder::GenerateIsConstructCall(int argument_count) { void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: IsConstructCall"); BAILOUT("inlined runtime function: IsConstructCall");
} }
// Support for arguments.length and arguments[?]. // Support for arguments.length and arguments[?].
void HGraphBuilder::GenerateArgumentsLength(int argument_count) { void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) {
ASSERT(argument_count == 0); ASSERT(argument_count == 0);
HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* elements = AddInstruction(new HArgumentsElements);
PushAndAdd(new HArgumentsLength(elements)); HArgumentsLength* result = new HArgumentsLength(elements);
ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateArguments(int argument_count) { void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* index = Pop(); HValue* index = Pop();
HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* elements = AddInstruction(new HArgumentsElements);
HInstruction* length = AddInstruction(new HArgumentsLength(elements)); HInstruction* length = AddInstruction(new HArgumentsLength(elements));
PushAndAdd(new HAccessArgumentsAt(elements, length, index)); HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index);
ast_context()->ReturnInstruction(result, ast_id);
} }
// Support for accessing the class and value fields of an object. // Support for accessing the class and value fields of an object.
void HGraphBuilder::GenerateClassOf(int argument_count) { void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) {
// The special form detected by IsClassOfTest is detected before we get here // The special form detected by IsClassOfTest is detected before we get here
// and does not cause a bailout. // and does not cause a bailout.
BAILOUT("inlined runtime function: ClassOf"); BAILOUT("inlined runtime function: ClassOf");
} }
void HGraphBuilder::GenerateValueOf(int argument_count) { void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) {
ASSERT(argument_count == 1); ASSERT(argument_count == 1);
HValue* value = Pop(); HValue* value = Pop();
HValueOf* op = new HValueOf(value); HValueOf* result = new HValueOf(value);
PushAndAdd(op); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateSetValueOf(int argument_count) { void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: SetValueOf"); BAILOUT("inlined runtime function: SetValueOf");
} }
// Fast support for charCodeAt(n). // Fast support for charCodeAt(n).
void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) { void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: StringCharCodeAt"); BAILOUT("inlined runtime function: StringCharCodeAt");
} }
// Fast support for string.charAt(n) and string[n]. // Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharFromCode(int argument_count) { void HGraphBuilder::GenerateStringCharFromCode(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: StringCharFromCode"); BAILOUT("inlined runtime function: StringCharFromCode");
} }
// Fast support for string.charAt(n) and string[n]. // Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharAt(int argument_count) { void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count); ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count), HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Fast support for object equality testing. // Fast support for object equality testing.
void HGraphBuilder::GenerateObjectEquals(int argument_count) { void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) {
ASSERT(argument_count == 2); ASSERT(argument_count == 2);
HValue* right = Pop(); HValue* right = Pop();
HValue* left = Pop(); HValue* left = Pop();
PushAndAdd(new HCompareJSObjectEq(left, right)); HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right);
ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateLog(int argument_count) { void HGraphBuilder::GenerateLog(int argument_count, int ast_id) {
UNREACHABLE(); // We caught this in VisitCallRuntime. UNREACHABLE(); // We caught this in VisitCallRuntime.
} }
// Fast support for Math.random(). // Fast support for Math.random().
void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) { void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: RandomHeapNumber"); BAILOUT("inlined runtime function: RandomHeapNumber");
} }
// Fast support for StringAdd. // Fast support for StringAdd.
void HGraphBuilder::GenerateStringAdd(int argument_count) { void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count); ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count), HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Fast support for SubString. // Fast support for SubString.
void HGraphBuilder::GenerateSubString(int argument_count) { void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) {
ASSERT_EQ(3, argument_count); ASSERT_EQ(3, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::SubString, argument_count), HCallStub* result = new HCallStub(CodeStub::SubString, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Fast support for StringCompare. // Fast support for StringCompare.
void HGraphBuilder::GenerateStringCompare(int argument_count) { void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count); ASSERT_EQ(2, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count), HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Support for direct calls from JavaScript to native RegExp code. // Support for direct calls from JavaScript to native RegExp code.
void HGraphBuilder::GenerateRegExpExec(int argument_count) { void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) {
ASSERT_EQ(4, argument_count); ASSERT_EQ(4, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count), HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Construct a RegExp exec result with two in-object properties. // Construct a RegExp exec result with two in-object properties.
void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) { void HGraphBuilder::GenerateRegExpConstructResult(int argument_count,
int ast_id) {
ASSERT_EQ(3, argument_count); ASSERT_EQ(3, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count), HCallStub* result =
RelocInfo::kNoPosition); new HCallStub(CodeStub::RegExpConstructResult, argument_count);
ast_context()->ReturnInstruction(result, ast_id);
} }
// Support for fast native caches. // Support for fast native caches.
void HGraphBuilder::GenerateGetFromCache(int argument_count) { void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: GetFromCache"); BAILOUT("inlined runtime function: GetFromCache");
} }
// Fast support for number to string. // Fast support for number to string.
void HGraphBuilder::GenerateNumberToString(int argument_count) { void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count); ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count), HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count);
RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
// Fast swapping of elements. Takes three expressions, the object and two // Fast swapping of elements. Takes three expressions, the object and two
// indices. This should only be used if the indices are known to be // 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. // non-negative and within bounds of the elements array at the call site.
void HGraphBuilder::GenerateSwapElements(int argument_count) { void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: SwapElements"); BAILOUT("inlined runtime function: SwapElements");
} }
// Fast call for custom callbacks. // Fast call for custom callbacks.
void HGraphBuilder::GenerateCallFunction(int argument_count) { void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: CallFunction"); BAILOUT("inlined runtime function: CallFunction");
} }
// Fast call to math functions. // Fast call to math functions.
void HGraphBuilder::GenerateMathPow(int argument_count) { void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) {
ASSERT_EQ(2, argument_count); ASSERT_EQ(2, argument_count);
HValue* right = Pop(); HValue* right = Pop();
HValue* left = Pop(); HValue* left = Pop();
PushAndAdd(new HPower(left, right)); HPower* result = new HPower(left, right);
ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateMathSin(int argument_count) { void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count); ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
HCallStub* instr = HCallStub* result =
new HCallStub(CodeStub::TranscendentalCache, argument_count); new HCallStub(CodeStub::TranscendentalCache, argument_count);
instr->set_transcendental_type(TranscendentalCache::SIN); result->set_transcendental_type(TranscendentalCache::SIN);
PushAndAdd(instr, RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateMathCos(int argument_count) { void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count); ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
HCallStub* instr = HCallStub* result =
new HCallStub(CodeStub::TranscendentalCache, argument_count); new HCallStub(CodeStub::TranscendentalCache, argument_count);
instr->set_transcendental_type(TranscendentalCache::COS); result->set_transcendental_type(TranscendentalCache::COS);
PushAndAdd(instr, RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateMathLog(int argument_count) { void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) {
ASSERT_EQ(1, argument_count); ASSERT_EQ(1, argument_count);
PushArgumentsForStubCall(argument_count); PushArgumentsForStubCall(argument_count);
HCallStub* instr = HCallStub* result =
new HCallStub(CodeStub::TranscendentalCache, argument_count); new HCallStub(CodeStub::TranscendentalCache, argument_count);
instr->set_transcendental_type(TranscendentalCache::LOG); result->set_transcendental_type(TranscendentalCache::LOG);
PushAndAdd(instr, RelocInfo::kNoPosition); ast_context()->ReturnInstruction(result, ast_id);
} }
void HGraphBuilder::GenerateMathSqrt(int argument_count) { void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) {
BAILOUT("inlined runtime function: MathSqrt"); BAILOUT("inlined runtime function: MathSqrt");
} }
// Check whether two RegExps are equivalent // Check whether two RegExps are equivalent
void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) { void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: IsRegExpEquivalent"); BAILOUT("inlined runtime function: IsRegExpEquivalent");
} }
void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) { void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: GetCachedArrayIndex"); BAILOUT("inlined runtime function: GetCachedArrayIndex");
} }
void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) { void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count,
int ast_id) {
BAILOUT("inlined runtime function: FastAsciiArrayJoin"); BAILOUT("inlined runtime function: FastAsciiArrayJoin");
} }
......
...@@ -557,10 +557,29 @@ class AstContext { ...@@ -557,10 +557,29 @@ class AstContext {
bool IsValue() const { return kind_ == Expression::kValue; } bool IsValue() const { return kind_ == Expression::kValue; }
bool IsTest() const { return kind_ == Expression::kTest; } bool IsTest() const { return kind_ == Expression::kTest; }
// 'Fill' this context with a hydrogen value. The value is assumed to
// have already been inserted in the instruction stream (or not need to
// be, e.g., HPhi). Call this function in tail position in the Visit
// functions for expressions.
virtual void ReturnValue(HValue* value) = 0;
// Add a hydrogen instruction to the instruction stream (recording an
// environment simulation if necessary) and then fill this context with
// the instruction as value.
virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
protected: protected:
AstContext(HGraphBuilder* owner, Expression::Context kind); AstContext(HGraphBuilder* owner, Expression::Context kind);
virtual ~AstContext(); virtual ~AstContext();
HGraphBuilder* owner() const { return owner_; }
// We want to be able to assert, in a context-specific way, that the stack
// height makes sense when the context is filled.
#ifdef DEBUG
int original_count_;
#endif
private: private:
HGraphBuilder* owner_; HGraphBuilder* owner_;
Expression::Context kind_; Expression::Context kind_;
...@@ -573,6 +592,10 @@ class EffectContext: public AstContext { ...@@ -573,6 +592,10 @@ class EffectContext: public AstContext {
explicit EffectContext(HGraphBuilder* owner) explicit EffectContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kEffect) { : AstContext(owner, Expression::kEffect) {
} }
virtual ~EffectContext();
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
}; };
...@@ -581,6 +604,10 @@ class ValueContext: public AstContext { ...@@ -581,6 +604,10 @@ class ValueContext: public AstContext {
explicit ValueContext(HGraphBuilder* owner) explicit ValueContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kValue) { : AstContext(owner, Expression::kValue) {
} }
virtual ~ValueContext();
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
}; };
...@@ -598,6 +625,9 @@ class TestContext: public AstContext { ...@@ -598,6 +625,9 @@ class TestContext: public AstContext {
invert_false_(invert_false) { invert_false_(invert_false) {
} }
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
static TestContext* cast(AstContext* context) { static TestContext* cast(AstContext* context) {
ASSERT(context->IsTest()); ASSERT(context->IsTest());
return reinterpret_cast<TestContext*>(context); return reinterpret_cast<TestContext*>(context);
...@@ -610,6 +640,10 @@ class TestContext: public AstContext { ...@@ -610,6 +640,10 @@ class TestContext: public AstContext {
bool invert_false() { return invert_false_; } bool invert_false() { return invert_false_; }
private: private:
// Build the shared core part of the translation unpacking a value into
// control flow.
void BuildBranch(HValue* value);
HBasicBlock* if_true_; HBasicBlock* if_true_;
HBasicBlock* if_false_; HBasicBlock* if_false_;
bool invert_true_; bool invert_true_;
...@@ -631,9 +665,25 @@ class HGraphBuilder: public AstVisitor { ...@@ -631,9 +665,25 @@ class HGraphBuilder: public AstVisitor {
HGraph* CreateGraph(CompilationInfo* info); HGraph* CreateGraph(CompilationInfo* info);
// Simple accessors.
HGraph* graph() const { return graph_; }
HSubgraph* subgraph() const { return current_subgraph_; }
HEnvironment* environment() const { return subgraph()->environment(); }
HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
// Adding instructions.
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(int id);
// Bailout environment manipulation.
void Push(HValue* value) { environment()->Push(value); }
HValue* Pop() { return environment()->Pop(); }
private: private:
// Type of a member function that generates inline code for a native function. // Type of a member function that generates inline code for a native function.
typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count); typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
int ast_id);
// Forward declarations for inner scope classes. // Forward declarations for inner scope classes.
class SubgraphScope; class SubgraphScope;
...@@ -650,19 +700,14 @@ class HGraphBuilder: public AstVisitor { ...@@ -650,19 +700,14 @@ class HGraphBuilder: public AstVisitor {
// Simple accessors. // Simple accessors.
TypeFeedbackOracle* oracle() const { return oracle_; } TypeFeedbackOracle* oracle() const { return oracle_; }
HGraph* graph() const { return graph_; }
HSubgraph* subgraph() const { return current_subgraph_; }
AstContext* ast_context() const { return ast_context_; } AstContext* ast_context() const { return ast_context_; }
void set_ast_context(AstContext* context) { ast_context_ = context; } void set_ast_context(AstContext* context) { ast_context_ = context; }
AstContext* call_context() const { return call_context_; } AstContext* call_context() const { return call_context_; }
HBasicBlock* function_return() const { return function_return_; } HBasicBlock* function_return() const { return function_return_; }
HEnvironment* environment() const { return subgraph()->environment(); }
HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
// Generators for inline runtime functions. // Generators for inline runtime functions.
#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
void Generate##Name(int argument_count); void Generate##Name(int argument_count, int ast_id);
INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
...@@ -683,8 +728,6 @@ class HGraphBuilder: public AstVisitor { ...@@ -683,8 +728,6 @@ class HGraphBuilder: public AstVisitor {
HSubgraph* true_graph, HSubgraph* true_graph,
HSubgraph* false_graph); HSubgraph* false_graph);
void Push(HValue* value) { environment()->Push(value); }
HValue* Pop() { return environment()->Pop(); }
HValue* Top() const { return environment()->Top(); } HValue* Top() const { return environment()->Top(); }
void Drop(int n) { environment()->Drop(n); } void Drop(int n) { environment()->Drop(n); }
void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
...@@ -708,18 +751,15 @@ class HGraphBuilder: public AstVisitor { ...@@ -708,18 +751,15 @@ class HGraphBuilder: public AstVisitor {
HValue* VisitArgument(Expression* expr); HValue* VisitArgument(Expression* expr);
void VisitArgumentList(ZoneList<Expression*>* arguments); void VisitArgumentList(ZoneList<Expression*>* arguments);
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(int id);
void AddPhi(HPhi* phi); void AddPhi(HPhi* phi);
void PushAndAdd(HInstruction* instr); void PushAndAdd(HInstruction* instr);
void PushAndAdd(HInstruction* instr, int position);
void PushArgumentsForStubCall(int argument_count); void PushArgumentsForStubCall(int argument_count);
// Initialize the arguments to the call based on then environment, add it // Remove the arguments from the bailout environment and emit instructions
// to the graph, and drop the arguments from the environment. // to push them as outgoing parameters.
void ProcessCall(HCall* call, int source_position); void ProcessCall(HCall* call);
void AssumeRepresentation(HValue* value, Representation r); void AssumeRepresentation(HValue* value, Representation r);
static Representation ToRepresentation(TypeInfo info); static Representation ToRepresentation(TypeInfo info);
...@@ -743,7 +783,7 @@ class HGraphBuilder: public AstVisitor { ...@@ -743,7 +783,7 @@ class HGraphBuilder: public AstVisitor {
FunctionLiteral* function); FunctionLiteral* function);
// Helpers for flow graph construction. // Helpers for flow graph construction.
void LookupGlobalPropertyCell(VariableProxy* expr, void LookupGlobalPropertyCell(Variable* var,
LookupResult* lookup, LookupResult* lookup,
bool is_store); bool is_store);
...@@ -753,10 +793,11 @@ class HGraphBuilder: public AstVisitor { ...@@ -753,10 +793,11 @@ class HGraphBuilder: public AstVisitor {
bool TryMathFunctionInline(Call* expr); bool TryMathFunctionInline(Call* expr);
void TraceInline(Handle<JSFunction> target, bool result); void TraceInline(Handle<JSFunction> target, bool result);
void HandleGlobalVariableAssignment(VariableProxy* proxy, void HandleGlobalVariableAssignment(Variable* var,
HValue* value, HValue* value,
int position); int position,
void HandleGlobalVariableLoad(VariableProxy* expr); int ast_id);
void HandlePropertyAssignment(Assignment* expr); void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr); void HandleCompoundAssignment(Assignment* expr);
void HandlePolymorphicLoadNamedField(Property* expr, void HandlePolymorphicLoadNamedField(Property* expr,
......
To run the sputniktests you must check out the test suite from To run the sputniktests you must check out the test suite from
googlecode.com. The test expectations are currently relative to googlecode.com. The test expectations are currently relative to
version 28. To get the tests run the following command within version 28. To get the tests run the following command within
v8/tests/sputnik/ v8/test/sputnik/
svn co http://sputniktests.googlecode.com/svn/trunk/ -r28 sputniktests svn co http://sputniktests.googlecode.com/svn/trunk/ -r28 sputniktests
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment