Revision: 5954
Author: [email protected]
Date: Thu Dec 9 04:49:53 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=5954
Modified:
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/test/sputnik/README
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Dec 8 06:32:40 2010
+++ /branches/bleeding_edge/src/hydrogen.cc Thu Dec 9 04:49:53 2010
@@ -1983,6 +1983,9 @@
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
}
@@ -1991,6 +1994,101 @@
}
+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) \
@@ -2061,55 +2159,14 @@
void HGraphBuilder::VisitForEffect(Expression* 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);
+ EffectContext for_effect(this);
+ Visit(expr);
}
void HGraphBuilder::VisitForValue(Expression* 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);
+ ValueContext for_value(this);
+ Visit(expr);
}
@@ -2244,99 +2301,7 @@
bool invert_false) {
TestContext for_test(this, true_block, false_block,
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);
- 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);
- }
+ Visit(expr);
}
@@ -2370,12 +2335,6 @@
Push(instr);
AddInstruction(instr);
}
-
-
-void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) {
- instr->set_position(position);
- PushAndAdd(instr);
-}
void HGraphBuilder::PushArgumentsForStubCall(int argument_count) {
@@ -2392,7 +2351,7 @@
}
-void HGraphBuilder::ProcessCall(HCall* call, int source_position) {
+void HGraphBuilder::ProcessCall(HCall* call) {
for (int i = call->argument_count() - 1; i >= 0; --i) {
HValue* value = Pop();
HPushArgument* push = new HPushArgument(value);
@@ -2402,8 +2361,6 @@
for (int i = 0; i < call->argument_count(); ++i) {
AddInstruction(call->PushArgumentAt(i));
}
-
- PushAndAdd(call, source_position);
}
@@ -2914,7 +2871,9 @@
Handle<SharedFunctionInfo> shared_info =
Compiler::BuildFunctionInfo(expr, graph_->info()->script());
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 @@
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(VariableProxy* expr,
+void HGraphBuilder::LookupGlobalPropertyCell(Variable* var,
LookupResult* lookup,
bool is_store) {
- if (expr->is_this()) {
+ if (var->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(*expr->name(), lookup);
+ global->Lookup(*var->name(), lookup);
if (!lookup->IsProperty()) {
BAILOUT("global variable cell not yet introduced");
}
@@ -2959,23 +2919,6 @@
BAILOUT("read-only global variable");
}
}
-
-
-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) {
@@ -2986,9 +2929,22 @@
if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) {
BAILOUT("unsupported context for arguments object");
}
- Push(environment()->Lookup(variable));
+ ast_context()->ReturnValue(environment()->Lookup(variable));
} else if (variable->is_global()) {
- HandleGlobalVariableLoad(expr);
+ 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());
} else {
BAILOUT("reference to non-stack-allocated/non-global variable");
}
@@ -2996,14 +2952,16 @@
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) {
- PushAndAdd(new HRegExpLiteral(expr->pattern(),
- expr->flags(),
- expr->literal_index()));
+ HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(),
+ expr->flags(),
+ expr->literal_index());
+ ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -3012,6 +2970,8 @@
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();
@@ -3048,6 +3008,7 @@
default: UNREACHABLE();
}
}
+ ast_context()->ReturnValue(Pop());
}
@@ -3059,6 +3020,8 @@
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));
@@ -3076,6 +3039,7 @@
AddInstruction(new HStoreKeyedFastElement(elements, key, value));
AddSimulate(expr->GetIdForElement(i));
}
+ ast_context()->ReturnValue(Pop());
}
@@ -3257,27 +3221,29 @@
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
- return;
- }
-
- // 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 (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);
+ }
+
+ HBasicBlock* new_exit_block =
+ BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
+ subgraph()->set_exit_block(new_exit_block);
}
- HBasicBlock* new_exit_block =
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
- current_subgraph_->set_exit_block(new_exit_block);
+ if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
}
@@ -3333,14 +3299,20 @@
Push(value);
instr->set_position(expr->position());
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,
- int position) {
+ int position,
+ int ast_id) {
LookupResult lookup;
- LookupGlobalPropertyCell(proxy, &lookup, true);
+ LookupGlobalPropertyCell(var, &lookup, true);
CHECK_BAILOUT;
Handle<GlobalObject> global(graph()->info()->global_object());
@@ -3348,6 +3320,7 @@
HInstruction* instr = new HStoreGlobal(value, cell);
instr->set_position(position);
AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(ast_id);
}
@@ -3371,10 +3344,12 @@
VISIT_FOR_VALUE(operation);
if (var->is_global()) {
- HandleGlobalVariableAssignment(proxy, Top(), expr->position());
+ HandleGlobalVariableAssignment(var, Top(), expr->position(),
expr->id());
} else {
Bind(var, Top());
}
+ ast_context()->ReturnValue(Pop());
+
} else if (prop != NULL) {
prop->RecordTypeFeedback(oracle());
@@ -3392,9 +3367,7 @@
load = BuildLoadNamedGeneric(obj, prop);
}
PushAndAdd(load);
- if (load->HasSideEffects()) {
- AddSimulate(expr->compound_bailout_id());
- }
+ if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id());
VISIT_FOR_VALUE(expr->value());
HValue* right = Pop();
@@ -3406,10 +3379,11 @@
HInstruction* store = BuildStoreNamed(obj, instr, prop);
AddInstruction(store);
-
- // Drop the simulated receiver and value and put back the value.
+ if (store->HasSideEffects()) AddSimulate(expr->id());
+
+ // Drop the simulated receiver and value. Return the value.
Drop(2);
- Push(instr);
+ ast_context()->ReturnValue(instr);
} else {
// Keyed property.
@@ -3425,9 +3399,7 @@
? BuildLoadKeyedFastElement(obj, key, prop)
: BuildLoadKeyedGeneric(obj, key);
PushAndAdd(load);
- if (load->HasSideEffects()) {
- AddSimulate(expr->compound_bailout_id());
- }
+ if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id());
VISIT_FOR_VALUE(expr->value());
HValue* right = Pop();
@@ -3441,11 +3413,13 @@
? BuildStoreKeyedFastElement(obj, key, instr, prop)
: BuildStoreKeyedGeneric(obj, key, instr);
AddInstruction(store);
-
- // Drop the simulated receiver, key and value and put back the value.
+ if (store->HasSideEffects()) AddSimulate(expr->id());
+
+ // Drop the simulated receiver, key, and value. Return the value.
Drop(3);
- Push(instr);
- }
+ ast_context()->ReturnValue(instr);
+ }
+
} else {
BAILOUT("invalid lhs in compound assignment");
}
@@ -3465,9 +3439,11 @@
if (var != NULL) {
if (proxy->IsArguments()) BAILOUT("assignment to arguments");
+
+ // Handle the assignment.
if (var->is_global()) {
VISIT_FOR_VALUE(expr->value());
- HandleGlobalVariableAssignment(proxy, Top(), expr->position());
+ HandleGlobalVariableAssignment(var, Top(), expr->position(),
expr->id());
} else {
// We allow reference to the arguments object only in assignemtns
// to local variables to make sure that the arguments object does
@@ -3480,9 +3456,11 @@
} else {
VISIT_FOR_VALUE(expr->value());
}
-
Bind(proxy->var(), Top());
}
+ // Return the value.
+ ast_context()->ReturnValue(Pop());
+
} else if (prop != NULL) {
HandlePropertyAssignment(expr);
} else {
@@ -3492,6 +3470,10 @@
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();
@@ -3525,7 +3507,8 @@
SubgraphScope scope(this, subgraph);
HInstruction* instr =
BuildLoadNamedField(object, expr, map, &lookup, false);
- PushAndAdd(instr, expr->position());
+ instr->set_position(expr->position());
+ PushAndAdd(instr);
subgraphs.Add(subgraph);
} else {
needs_generic = true;
@@ -3536,26 +3519,30 @@
// generic load.
if (maps.length() == 0) {
HInstruction* instr = BuildLoadNamedGeneric(object, expr);
- PushAndAdd(instr, expr->position());
- return;
- }
-
- // 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);
+ 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);
+ }
+
+ HBasicBlock* new_exit_block =
+ BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
+ subgraph()->set_exit_block(new_exit_block);
}
- HBasicBlock* new_exit_block =
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
- current_subgraph_->set_exit_block(new_exit_block);
+ if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
}
@@ -3668,11 +3655,12 @@
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);
- PushAndAdd(new HArgumentsLength(elements));
+ result = new HArgumentsLength(elements);
} else {
VisitForValue(expr->key());
if (HasStackOverflow()) return false;
@@ -3680,8 +3668,9 @@
HInstruction* elements = AddInstruction(new HArgumentsElements);
HInstruction* length = AddInstruction(new HArgumentsLength(elements));
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;
}
@@ -3728,7 +3717,8 @@
? BuildLoadKeyedFastElement(obj, key, expr)
: BuildLoadKeyedGeneric(obj, key);
}
- PushAndAdd(instr, expr->position());
+ instr->set_position(expr->position());
+ ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -3763,9 +3753,9 @@
// 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)) {
@@ -3782,7 +3772,9 @@
// during hydrogen processing.
CHECK_BAILOUT;
HCall* call = new HCallConstantFunction(expr->target(),
argument_count);
- ProcessCall(call, expr->position());
+ call->set_position(expr->position());
+ ProcessCall(call);
+ PushAndAdd(call);
}
subgraphs.Add(subgraph);
} else {
@@ -3790,30 +3782,34 @@
}
}
- // 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);
- ProcessCall(call, expr->position());
- return;
- }
-
- // 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);
+ 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);
+ }
+
+ 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());
+ }
}
@@ -4061,6 +4057,7 @@
function_return_ = saved_function_return;
oracle_ = saved_oracle;
graph()->info()->SetOsrAstId(saved_osr_ast_id);
+
return true;
}
@@ -4086,10 +4083,10 @@
case kMathSqrt:
if (argument_count == 2) {
HValue* argument = Pop();
- // Pop receiver.
- Pop();
+ Drop(1); // Receiver.
HUnaryMathOperation* op = new HUnaryMathOperation(argument, id);
- PushAndAdd(op, expr->position());
+ op->set_position(expr->position());
+ ast_context()->ReturnInstruction(op, expr->id());
return true;
}
break;
@@ -4098,11 +4095,13 @@
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) {
- PushAndAdd(new HUnaryMathOperation(left, kMathPowHalf));
+ result = new HUnaryMathOperation(left, kMathPowHalf);
+ ast_context()->ReturnInstruction(result, expr->id());
return true;
} else if (exponent == -0.5) {
HConstant* double_one =
@@ -4112,20 +4111,27 @@
HUnaryMathOperation* square_root =
new HUnaryMathOperation(left, kMathPowHalf);
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;
} else if (exponent == 2.0) {
- PushAndAdd(new HMul(left, left));
+ 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) {
- PushAndAdd(new HMul(left, left));
+ result = new HMul(left, left);
+ ast_context()->ReturnInstruction(result, expr->id());
return true;
}
- PushAndAdd(new HPower(left, right));
+ result = new HPower(left, right);
+ ast_context()->ReturnInstruction(result, expr->id());
return true;
}
break;
@@ -4170,8 +4176,10 @@
function,
expr->GetReceiverTypes()->first(),
true);
- PushAndAdd(new HApplyArguments(function, receiver, length, elements),
- expr->position());
+ HInstruction* result =
+ new HApplyArguments(function, receiver, length, elements);
+ result->set_position(expr->position());
+ ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -4199,12 +4207,10 @@
CHECK_BAILOUT;
call = new HCallKeyed(key, argument_count);
- 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);
+ call->set_position(expr->position());
+ ProcessCall(call);
+ Drop(1); // Key.
+ ast_context()->ReturnInstruction(call, expr->id());
return;
}
@@ -4227,7 +4233,19 @@
if (expr->IsMonomorphic()) {
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;
} else {
// Check for bailout, as the TryInline call in the if condition
above
@@ -4235,6 +4253,7 @@
CHECK_BAILOUT;
call = new HCallConstantFunction(expr->target(), argument_count);
}
+
} else if (types != NULL && types->length() > 1) {
HandlePolymorphicCallNamed(expr, receiver, types, name);
return;
@@ -4282,7 +4301,19 @@
IsGlobalObject());
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
// during hydrogen processing.
CHECK_BAILOUT;
@@ -4305,7 +4336,9 @@
}
}
- ProcessCall(call, expr->position());
+ call->set_position(expr->position());
+ ProcessCall(call);
+ ast_context()->ReturnInstruction(call, expr->id());
}
@@ -4319,8 +4352,9 @@
int argument_count = expr->arguments()->length() + 1; // Plus
constructor.
HCall* call = new HCallNew(argument_count);
-
- ProcessCall(call, expr->position());
+ call->set_position(expr->position());
+ ProcessCall(call);
+ ast_context()->ReturnInstruction(call, expr->id());
}
@@ -4328,7 +4362,7 @@
// 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
@@ -4342,7 +4376,7 @@
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->IsEqualTo(CStrVector("_Log"))) {
- Push(graph()->GetConstantUndefined());
+ ast_context()->ReturnValue(graph()->GetConstantUndefined());
return;
}
@@ -4368,11 +4402,13 @@
InlineFunctionGenerator generator =
kInlineFunctionGenerators[lookup_index];
***The diff for this file has been truncated for email.***
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Tue Dec 7 03:31:57 2010
+++ /branches/bleeding_edge/src/hydrogen.h Thu Dec 9 04:49:53 2010
@@ -556,11 +556,30 @@
bool IsEffect() const { return kind_ == Expression::kEffect; }
bool IsValue() const { return kind_ == Expression::kValue; }
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:
AstContext(HGraphBuilder* owner, Expression::Context kind);
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:
HGraphBuilder* owner_;
Expression::Context kind_;
@@ -573,6 +592,10 @@
explicit EffectContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kEffect) {
}
+ virtual ~EffectContext();
+
+ virtual void ReturnValue(HValue* value);
+ virtual void ReturnInstruction(HInstruction* instr, int ast_id);
};
@@ -581,6 +604,10 @@
explicit ValueContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kValue) {
}
+ virtual ~ValueContext();
+
+ virtual void ReturnValue(HValue* value);
+ virtual void ReturnInstruction(HInstruction* instr, int ast_id);
};
@@ -597,6 +624,9 @@
invert_true_(invert_true),
invert_false_(invert_false) {
}
+
+ virtual void ReturnValue(HValue* value);
+ virtual void ReturnInstruction(HInstruction* instr, int ast_id);
static TestContext* cast(AstContext* context) {
ASSERT(context->IsTest());
@@ -610,6 +640,10 @@
bool invert_false() { return invert_false_; }
private:
+ // Build the shared core part of the translation unpacking a value into
+ // control flow.
+ void BuildBranch(HValue* value);
+
HBasicBlock* if_true_;
HBasicBlock* if_false_;
bool invert_true_;
@@ -630,10 +664,26 @@
inlined_count_(0) { }
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:
// 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.
class SubgraphScope;
@@ -650,19 +700,14 @@
// Simple accessors.
TypeFeedbackOracle* oracle() const { return oracle_; }
- HGraph* graph() const { return graph_; }
- HSubgraph* subgraph() const { return current_subgraph_; }
AstContext* ast_context() const { return ast_context_; }
void set_ast_context(AstContext* context) { ast_context_ = context; }
AstContext* call_context() const { return call_context_; }
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.
-#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc,
ressize) \
- void Generate##Name(int argument_count);
+#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
+ void Generate##Name(int argument_count, int ast_id);
INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
@@ -683,8 +728,6 @@
HSubgraph* true_graph,
HSubgraph* false_graph);
- void Push(HValue* value) { environment()->Push(value); }
- HValue* Pop() { return environment()->Pop(); }
HValue* Top() const { return environment()->Top(); }
void Drop(int n) { environment()->Drop(n); }
void Bind(Variable* var, HValue* value) { environment()->Bind(var,
value); }
@@ -708,18 +751,15 @@
HValue* VisitArgument(Expression* expr);
void VisitArgumentList(ZoneList<Expression*>* arguments);
- HInstruction* AddInstruction(HInstruction* instr);
- void AddSimulate(int id);
void AddPhi(HPhi* phi);
void PushAndAdd(HInstruction* instr);
- void PushAndAdd(HInstruction* instr, int position);
void PushArgumentsForStubCall(int argument_count);
- // Initialize the arguments to the call based on then environment, add it
- // to the graph, and drop the arguments from the environment.
- void ProcessCall(HCall* call, int source_position);
+ // Remove the arguments from the bailout environment and emit
instructions
+ // to push them as outgoing parameters.
+ void ProcessCall(HCall* call);
void AssumeRepresentation(HValue* value, Representation r);
static Representation ToRepresentation(TypeInfo info);
@@ -743,7 +783,7 @@
FunctionLiteral* function);
// Helpers for flow graph construction.
- void LookupGlobalPropertyCell(VariableProxy* expr,
+ void LookupGlobalPropertyCell(Variable* var,
LookupResult* lookup,
bool is_store);
@@ -753,10 +793,11 @@
bool TryMathFunctionInline(Call* expr);
void TraceInline(Handle<JSFunction> target, bool result);
- void HandleGlobalVariableAssignment(VariableProxy* proxy,
+ void HandleGlobalVariableAssignment(Variable* var,
HValue* value,
- int position);
- void HandleGlobalVariableLoad(VariableProxy* expr);
+ int position,
+ int ast_id);
+
void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr);
void HandlePolymorphicLoadNamedField(Property* expr,
=======================================
--- /branches/bleeding_edge/test/sputnik/README Tue Dec 7 03:01:02 2010
+++ /branches/bleeding_edge/test/sputnik/README Thu Dec 9 04:49:53 2010
@@ -1,6 +1,6 @@
To run the sputniktests you must check out the test suite from
googlecode.com. The test expectations are currently relative to
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
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev