Change the HGraphBuilder to dispatch on the context.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 9 Dec 2010 12:49:53 +0000 (12:49 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 9 Dec 2010 12:49:53 +0000 (12:49 +0000)
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

src/hydrogen.cc
src/hydrogen.h
test/sputnik/README

index ad327c4..153bd9a 100644 (file)
@@ -1983,6 +1983,9 @@ void HGraph::InsertRepresentationChanges() {
 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
     : owner_(owner), kind_(kind), outer_(owner->ast_context()) {
   owner->set_ast_context(this);  // Push.
+#ifdef DEBUG
+  original_count_ = owner->environment()->total_count();
+#endif
 }
 
 
@@ -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.
 #define BAILOUT(reason)                         \
@@ -2061,55 +2159,14 @@ void HGraphBuilder::Bailout(const char* reason) {
 
 
 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 @@ void HGraphBuilder::VisitForControl(Expression* expr,
                                     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);
 }
 
 
@@ -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) {
   const int kMaxStubArguments = 4;
   ASSERT_GE(kMaxStubArguments, 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) {
     HValue* value = Pop();
     HPushArgument* push = new HPushArgument(value);
@@ -2402,8 +2361,6 @@ void HGraphBuilder::ProcessCall(HCall* call, int source_position) {
   for (int i = 0; i < call->argument_count(); ++i) {
     AddInstruction(call->PushArgumentAt(i));
   }
-
-  PushAndAdd(call, source_position);
 }
 
 
@@ -2914,7 +2871,9 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
   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 @@ void HGraphBuilder::VisitConditional(Conditional* expr) {
   ADD_TO_SUBGRAPH(then_graph, expr->then_expression());
   ADD_TO_SUBGRAPH(else_graph, expr->else_expression());
   current_subgraph_->AppendJoin(then_graph, else_graph, expr);
+  ast_context()->ReturnValue(Pop());
 }
 
 
-void HGraphBuilder::LookupGlobalPropertyCell(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");
   }
@@ -2961,23 +2921,6 @@ void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr,
 }
 
 
-void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) {
-  LookupResult lookup;
-  LookupGlobalPropertyCell(expr, &lookup, false);
-  CHECK_BAILOUT;
-
-  Handle<GlobalObject> global(graph()->info()->global_object());
-  // TODO(3039103): Handle global property load through an IC call when access
-  // checks are enabled.
-  if (global->IsAccessCheckNeeded()) {
-    BAILOUT("global object requires access check");
-  }
-  Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
-  bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
-  PushAndAdd(new HLoadGlobal(cell, check_hole));
-}
-
-
 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
   Variable* variable = expr->AsVariable();
   if (variable == NULL) {
@@ -2986,9 +2929,22 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
     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::VisitVariableProxy(VariableProxy* 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) {
-  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 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
                                                 expr->fast_elements(),
                                                 expr->literal_index(),
                                                 expr->depth()));
+  // The object is expected in the bailout environment during computation
+  // of the property values and is the value of the entire expression.
   PushAndAdd(literal);
 
   expr->CalculateEmitStore();
@@ -3048,6 +3008,7 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
       default: UNREACHABLE();
     }
   }
+  ast_context()->ReturnValue(Pop());
 }
 
 
@@ -3059,6 +3020,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
                                              length,
                                              expr->literal_index(),
                                              expr->depth());
+  // The array is expected in the bailout environment during computation
+  // of the property values and is the value of the entire expression.
   PushAndAdd(literal);
   HValue* elements = AddInstruction(new HLoadElements(literal));
 
@@ -3076,6 +3039,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
     AddInstruction(new HStoreKeyedFastElement(elements, key, value));
     AddSimulate(expr->GetIdForElement(i));
   }
+  ast_context()->ReturnValue(Pop());
 }
 
 
@@ -3257,27 +3221,29 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
     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);
+    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);
     }
-    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 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
   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 @@ void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy,
   HInstruction* instr = new HStoreGlobal(value, cell);
   instr->set_position(position);
   AddInstruction(instr);
+  if (instr->HasSideEffects()) AddSimulate(ast_id);
 }
 
 
@@ -3371,10 +3344,12 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
     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 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
         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 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
 
       HInstruction* store = BuildStoreNamed(obj, instr, prop);
       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);
-      Push(instr);
+      ast_context()->ReturnValue(instr);
 
     } else {
       // Keyed property.
@@ -3425,9 +3399,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
           ? 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 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
           ? BuildStoreKeyedFastElement(obj, key, instr, prop)
           : BuildStoreKeyedGeneric(obj, key, instr);
       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);
-      Push(instr);
+      ast_context()->ReturnValue(instr);
     }
+
   } else {
     BAILOUT("invalid lhs in compound assignment");
   }
@@ -3465,9 +3439,11 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
 
   if (var != NULL) {
     if (proxy->IsArguments()) BAILOUT("assignment to arguments");
+
+    // Handle the assignment.
     if (var->is_global()) {
       VISIT_FOR_VALUE(expr->value());
-      HandleGlobalVariableAssignment(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 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
       } else {
         VISIT_FOR_VALUE(expr->value());
       }
-
       Bind(proxy->var(), Top());
     }
+    // Return the value.
+    ast_context()->ReturnValue(Pop());
+
   } else if (prop != NULL) {
     HandlePropertyAssignment(expr);
   } else {
@@ -3492,6 +3470,10 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
 
 
 void HGraphBuilder::VisitThrow(Throw* expr) {
+  // We don't optimize functions with invalid left-hand sides in
+  // assignments, count operations, or for-in.  Consequently throw can
+  // currently only occur in an effect context.
+  ASSERT(ast_context()->IsEffect());
   VISIT_FOR_VALUE(expr->exception());
 
   HValue* value = environment()->Pop();
@@ -3525,7 +3507,8 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
       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 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
   // 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());
+    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);
     }
-    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 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
     return false;
   }
 
+  HInstruction* result = NULL;
   if (expr->key()->IsPropertyName()) {
     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
     if (!name->IsEqualTo(CStrVector("length"))) return false;
     HInstruction* elements = AddInstruction(new HArgumentsElements);
-    PushAndAdd(new HArgumentsLength(elements));
+    result = new HArgumentsLength(elements);
   } else {
     VisitForValue(expr->key());
     if (HasStackOverflow()) return false;
@@ -3680,8 +3668,9 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
     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 @@ void HGraphBuilder::VisitProperty(Property* expr) {
         ? 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 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
 
   // Build subgraphs for each of the specific maps.
   //
-  // TODO(ager): We should recognize when the prototype chains for
-  // different maps are identical. In that case we can avoid
-  // repeatedly generating the same prototype map checks.
+  // TODO(ager): We should recognize when the prototype chains for different
+  // maps are identical. In that case we can avoid repeatedly generating the
+  // same prototype map checks.
   for (int i = 0; i < number_of_types; ++i) {
     Handle<Map> map = types->at(i);
     if (expr->ComputeTarget(map, name)) {
@@ -3782,7 +3772,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
         // 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 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
     }
   }
 
-  // If we couldn't compute the target for any of the maps just
-  // perform an IC call.
+  // If we couldn't compute the target for any of the maps just perform an
+  // IC call.
   if (maps.length() == 0) {
     HCall* call = new HCallNamed(name, argument_count);
-    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());
+    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);
     }
-    subgraphs.Add(subgraph);
-  }
 
-  HBasicBlock* new_exit_block =
-      BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id());
-  current_subgraph_->set_exit_block(new_exit_block);
+    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 @@ bool HGraphBuilder::TryInline(Call* expr) {
   function_return_ = saved_function_return;
   oracle_ = saved_oracle;
   graph()->info()->SetOsrAstId(saved_osr_ast_id);
+
   return true;
 }
 
@@ -4086,10 +4083,10 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
     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 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
         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 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
             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 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
                            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 @@ void HGraphBuilder::VisitCall(Call* expr) {
       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 @@ void HGraphBuilder::VisitCall(Call* expr) {
     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 @@ void HGraphBuilder::VisitCall(Call* expr) {
         CHECK_BAILOUT;
         call = new HCallConstantFunction(expr->target(), argument_count);
       }
+
     } else if (types != NULL && types->length() > 1) {
       HandlePolymorphicCallNamed(expr, receiver, types, name);
       return;
@@ -4282,7 +4301,19 @@ void HGraphBuilder::VisitCall(Call* expr) {
                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 @@ 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) {
 
   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 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) {
 
 // Lookup table for generators for runtime calls that are  generated inline.
 // Elements of the table are member pointers to functions of HGraphBuilder.
-#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)          \
+#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)  \
     &HGraphBuilder::Generate##Name,
 
 const HGraphBuilder::InlineFunctionGenerator
@@ -4342,7 +4376,7 @@ const HGraphBuilder::InlineFunctionGenerator
 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 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
     InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
 
     // Call the inline code generator using the pointer-to-member.
-    (this->*generator)(argument_count);
+    (this->*generator)(argument_count, expr->id());
   } else {
     ASSERT(function->intrinsic_type == Runtime::RUNTIME);
     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) {
   Token::Value op = expr->op();
   if (op == Token::VOID) {
     VISIT_FOR_EFFECT(expr->expression());
-    Push(graph()->GetConstantUndefined());
+    ast_context()->ReturnValue(graph()->GetConstantUndefined());
   } else if (op == Token::DELETE) {
     Property* prop = expr->expression()->AsProperty();
     Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
@@ -4389,36 +4425,47 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
       // Result of deleting non-property, non-variable reference is true.
       // Evaluate the subexpression for side effects.
       VISIT_FOR_EFFECT(expr->expression());
-      Push(graph_->GetConstantTrue());
+      ast_context()->ReturnValue(graph()->GetConstantTrue());
     } else if (var != NULL &&
                !var->is_global() &&
                var->AsSlot() != NULL &&
                var->AsSlot()->type() != Slot::LOOKUP) {
       // Result of deleting non-global, non-dynamic variables is false.
       // The subexpression does not have side effects.
-      Push(graph_->GetConstantFalse());
+      ast_context()->ReturnValue(graph()->GetConstantFalse());
     } else if (prop != NULL) {
       VISIT_FOR_VALUE(prop->obj());
       VISIT_FOR_VALUE(prop->key());
       HValue* key = Pop();
       HValue* obj = Pop();
-      PushAndAdd(new HDeleteProperty(obj, key));
+      ast_context()->ReturnInstruction(new HDeleteProperty(obj, key),
+                                       expr->id());
     } else if (var->is_global()) {
       BAILOUT("delete with global variable");
     } else {
       BAILOUT("delete with non-global variable");
     }
   } else if (op == Token::NOT) {
-    HSubgraph* true_graph = CreateEmptySubgraph();
-    HSubgraph* false_graph = CreateEmptySubgraph();
-    VisitCondition(expr->expression(),
-                   false_graph->entry_block(),
-                   true_graph->entry_block(),
-                   true, true);
-    if (HasStackOverflow()) return;
-    true_graph->environment()->Push(graph_->GetConstantTrue());
-    false_graph->environment()->Push(graph_->GetConstantFalse());
-    current_subgraph_->AppendJoin(true_graph, false_graph, expr);
+    if (ast_context()->IsTest()) {
+      TestContext* context = TestContext::cast(ast_context());
+      VisitForControl(expr->expression(),
+                      context->if_false(),
+                      context->if_true(),
+                      !context->invert_false(),
+                      !context->invert_true());
+    } else {
+      HSubgraph* true_graph = CreateEmptySubgraph();
+      HSubgraph* false_graph = CreateEmptySubgraph();
+      VisitCondition(expr->expression(),
+                     false_graph->entry_block(),
+                     true_graph->entry_block(),
+                     true, true);
+      if (HasStackOverflow()) return;
+      true_graph->environment()->Push(graph_->GetConstantTrue());
+      false_graph->environment()->Push(graph_->GetConstantFalse());
+      current_subgraph_->AppendJoin(true_graph, false_graph, expr);
+      ast_context()->ReturnValue(Pop());
+    }
   } else if (op == Token::BIT_NOT || op == Token::SUB) {
     VISIT_FOR_VALUE(expr->expression());
     HValue* value = Pop();
@@ -4434,11 +4481,11 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
         UNREACHABLE();
         break;
     }
-    PushAndAdd(instr);
+    ast_context()->ReturnInstruction(instr, expr->id());
   } else if (op == Token::TYPEOF) {
     VISIT_FOR_VALUE(expr->expression());
     HValue* value = Pop();
-    PushAndAdd(new HTypeof(value));
+    ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
   } else {
     BAILOUT("Value: unsupported unary operation");
   }
@@ -4489,11 +4536,12 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
     }
 
     if (var->is_global()) {
-      HandleGlobalVariableAssignment(proxy, instr, expr->position());
+      HandleGlobalVariableAssignment(var, instr, expr->position(), expr->id());
     } else {
       ASSERT(var->IsStackAllocated());
       Bind(var, instr);
     }
+    ast_context()->ReturnValue(Pop());
 
   } else if (prop != NULL) {
     prop->RecordTypeFeedback(oracle());
@@ -4501,8 +4549,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
     if (prop->key()->IsPropertyName()) {
       // Named property.
 
-      // Match the full code generator stack by simulate an extra stack element
-      // for postfix operations in a value context.
+      // Match the full code generator stack by simulating an extra stack
+      // element for postfix operations in a value context.
       if (expr->is_postfix() && !ast_context()->IsEffect()) {
         Push(graph_->GetConstantUndefined());
       }
@@ -4523,6 +4571,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
 
       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);
       AddInstruction(instr);
 
@@ -4530,8 +4580,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
       AddInstruction(store);
 
       // Drop simulated receiver and push the result.
-      // There is no deoptimization to after the increment, so we can simulate
-      // the expression stack here.
       Drop(1);
       if (expr->is_prefix()) {
         Push(instr);
@@ -4540,6 +4588,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
         Push(value);
       }
 
+      if (store->HasSideEffects()) AddSimulate(expr->id());
+      ast_context()->ReturnValue(Pop());
+
     } else {
       // Keyed property.
 
@@ -4566,6 +4617,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
 
       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);
       AddInstruction(instr);
 
@@ -4575,8 +4628,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
       AddInstruction(store);
 
       // Drop simulated receiver and key and push the result.
-      // There is no deoptimization to after the increment, so we can simulate
-      // the expression stack here.
       Drop(2);
       if (expr->is_prefix()) {
         Push(instr);
@@ -4584,7 +4635,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
         if (!ast_context()->IsEffect()) Drop(1);  // Drop simulated zero.
         Push(value);
       }
+
+      if (store->HasSideEffects()) AddSimulate(expr->id());
+      ast_context()->ReturnValue(Pop());
     }
+
   } else {
     BAILOUT("invalid lhs in count operation");
   }
@@ -4666,21 +4721,47 @@ static bool IsClassOfTest(CompareOperation* expr) {
 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
   if (expr->op() == Token::COMMA) {
     VISIT_FOR_EFFECT(expr->left());
-    VISIT_FOR_VALUE(expr->right());
-  } else if (expr->op() == Token::AND || expr->op() == Token::OR) {
-    VISIT_FOR_VALUE(expr->left());
-    ASSERT(current_subgraph_->HasExit());
+    // Visit the right subexpression in the same AST context as the entire
+    // expression.
+    Visit(expr->right());
 
-    HValue* left = Top();
+  } 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());
+      ASSERT(current_subgraph_->HasExit());
+
+      HValue* left = Top();
+      HEnvironment* environment_copy = environment()->Copy();
+      environment_copy->Pop();
+      HSubgraph* right_subgraph;
+      right_subgraph = CreateBranchSubgraph(environment_copy);
+      ADD_TO_SUBGRAPH(right_subgraph, expr->right());
+      current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left);
+      current_subgraph_->exit_block()->SetJoinId(expr->id());
+      ast_context()->ReturnValue(Pop());
+    }
 
-    HEnvironment* environment_copy = environment()->Copy();
-    environment_copy->Pop();
-    HSubgraph* right_subgraph;
-    right_subgraph = CreateBranchSubgraph(environment_copy);
-    ADD_TO_SUBGRAPH(right_subgraph, expr->right());
-    current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left);
-    current_subgraph_->exit_block()->SetJoinId(expr->id());
   } else {
     VISIT_FOR_VALUE(expr->left());
     VISIT_FOR_VALUE(expr->right());
@@ -4688,7 +4769,8 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
     HValue* right = Pop();
     HValue* left = Pop();
     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) {
     Literal* literal = expr->right()->AsLiteral();
     Handle<String> rhs = Handle<String>::cast(literal->handle());
     HInstruction* instr = new HClassOfTest(value, rhs);
-    PushAndAdd(instr, expr->position());
+    instr->set_position(expr->position());
+    ast_context()->ReturnInstruction(instr, expr->id());
     return;
   }
 
@@ -4741,7 +4824,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     HValue* left = Pop();
     HInstruction* instr = new HTypeofIs(left,
         Handle<String>::cast(right_literal->handle()));
-    PushAndAdd(instr, expr->position());
+    instr->set_position(expr->position());
+    ast_context()->ReturnInstruction(instr, expr->id());
     return;
   }
 
@@ -4777,7 +4861,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     compare->SetInputRepresentation(r);
     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) {
 
   HValue* value = Pop();
   HIsNull* compare = new HIsNull(value, expr->is_strict());
-
-  PushAndAdd(compare);
+  ast_context()->ReturnInstruction(compare, expr->id());
 }
 
 
@@ -4814,301 +4898,305 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) {
 
 // Generators for inline runtime functions.
 // Support for types.
-void HGraphBuilder::GenerateIsSmi(int argument_count) {
+void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) {
   ASSERT(argument_count == 1);
-
   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);
-
   HValue* value = Pop();
-  HHasInstanceType* test =
+  HHasInstanceType* result =
       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);
-
   HValue* value = Pop();
-  HHasInstanceType* test =
-      new HHasInstanceType(value, JS_FUNCTION_TYPE);
-  PushAndAdd(test);
+  HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
-void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) {
+void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count,
+                                                int ast_id) {
   ASSERT(argument_count == 1);
-
   HValue* value = Pop();
-  HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value);
-  PushAndAdd(spec_test);
+  HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value);
+  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);
-
   HValue* value = Pop();
-  HHasInstanceType* test =
-      new HHasInstanceType(value, JS_ARRAY_TYPE);
-  PushAndAdd(test);
+  HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
-void HGraphBuilder::GenerateIsRegExp(int argument_count) {
+void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
   ASSERT(argument_count == 1);
-
   HValue* value = Pop();
-  HHasInstanceType* test =
-      new HHasInstanceType(value, JS_REGEXP_TYPE);
-  PushAndAdd(test);
+  HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
-void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) {
+void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
+                                             int ast_id) {
   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");
 }
 
 
-void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) {
+void HGraphBuilder::GenerateIsUndetectableObject(int argument_count,
+                                                 int ast_id) {
   BAILOUT("inlined runtime function: IsUndetectableObject");
 }
 
 
 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
-    int argument_count) {
+    int argument_count,
+    int ast_id) {
   BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
 }
 
 
   // 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");
 }
 
 
 // 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);
   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);
   HValue* index = Pop();
   HInstruction* elements = AddInstruction(new HArgumentsElements);
   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.
-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
   // and does not cause a bailout.
   BAILOUT("inlined runtime function: ClassOf");
 }
 
 
-void HGraphBuilder::GenerateValueOf(int argument_count) {
+void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) {
   ASSERT(argument_count == 1);
-
   HValue* value = Pop();
-  HValueOf* op = new HValueOf(value);
-  PushAndAdd(op);
+  HValueOf* result = new HValueOf(value);
+  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");
 }
 
 
 // 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");
 }
 
 
 // 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");
 }
 
 
 // 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);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // 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);
-
   HValue* right = 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.
 }
 
 
 // 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");
 }
 
 
 // Fast support for StringAdd.
-void HGraphBuilder::GenerateStringAdd(int argument_count) {
+void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) {
   ASSERT_EQ(2, argument_count);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // Fast support for SubString.
-void HGraphBuilder::GenerateSubString(int argument_count) {
+void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) {
   ASSERT_EQ(3, argument_count);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::SubString, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::SubString, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // Fast support for StringCompare.
-void HGraphBuilder::GenerateStringCompare(int argument_count) {
+void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) {
   ASSERT_EQ(2, argument_count);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // 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);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // 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);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result =
+      new HCallStub(CodeStub::RegExpConstructResult, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // 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");
 }
 
 
 // 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);
   PushArgumentsForStubCall(argument_count);
-  PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count),
-             RelocInfo::kNoPosition);
+  HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count);
+  ast_context()->ReturnInstruction(result, ast_id);
 }
 
 
 // Fast swapping of elements. Takes three expressions, the object and two
 // indices. This should only be used if the indices are known to be
 // non-negative and within bounds of the elements array at the call site.
-void HGraphBuilder::GenerateSwapElements(int argument_count) {
+void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) {
   BAILOUT("inlined runtime function: SwapElements");
 }
 
 
 // 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");
 }
 
 
 // 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);
   HValue* right = 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);
   PushArgumentsForStubCall(argument_count);
-  HCallStub* instr =
+  HCallStub* result =
       new HCallStub(CodeStub::TranscendentalCache, argument_count);
-  instr->set_transcendental_type(TranscendentalCache::SIN);
-  PushAndAdd(instr, RelocInfo::kNoPosition);
+  result->set_transcendental_type(TranscendentalCache::SIN);
+  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);
   PushArgumentsForStubCall(argument_count);
-  HCallStub* instr =
+  HCallStub* result =
       new HCallStub(CodeStub::TranscendentalCache, argument_count);
-  instr->set_transcendental_type(TranscendentalCache::COS);
-  PushAndAdd(instr, RelocInfo::kNoPosition);
+  result->set_transcendental_type(TranscendentalCache::COS);
+  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);
   PushArgumentsForStubCall(argument_count);
-  HCallStub* instr =
+  HCallStub* result =
       new HCallStub(CodeStub::TranscendentalCache, argument_count);
-  instr->set_transcendental_type(TranscendentalCache::LOG);
-  PushAndAdd(instr, RelocInfo::kNoPosition);
+  result->set_transcendental_type(TranscendentalCache::LOG);
+  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");
 }
 
 
 // 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");
 }
 
 
-void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) {
+void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count,
+                                                int ast_id) {
   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");
 }
 
index 91f3c9e..5611d8d 100644 (file)
@@ -557,10 +557,29 @@ class AstContext {
   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 @@ class EffectContext: public AstContext {
   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 @@ class ValueContext: public AstContext {
   explicit ValueContext(HGraphBuilder* owner)
       : 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 {
         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());
     return reinterpret_cast<TestContext*>(context);
@@ -610,6 +640,10 @@ class TestContext: public AstContext {
   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_;
@@ -631,9 +665,25 @@ class HGraphBuilder: public AstVisitor {
 
   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 @@ class HGraphBuilder: public AstVisitor {
 
   // 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 @@ class HGraphBuilder: public AstVisitor {
                               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 @@ class HGraphBuilder: public AstVisitor {
   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 @@ class HGraphBuilder: public AstVisitor {
                                    FunctionLiteral* function);
 
   // Helpers for flow graph construction.
-  void LookupGlobalPropertyCell(VariableProxy* expr,
+  void LookupGlobalPropertyCell(Variable* var,
                                 LookupResult* lookup,
                                 bool is_store);
 
@@ -753,10 +793,11 @@ class HGraphBuilder: public AstVisitor {
   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,
index 3d39a67..94c689b 100644 (file)
@@ -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