Add tracing of the stack height to full code generator.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 28 Jul 2011 10:17:41 +0000 (10:17 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 28 Jul 2011 10:17:41 +0000 (10:17 +0000)
BUG=
TEST=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8755 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/flag-definitions.h
src/full-codegen.cc
src/full-codegen.h
src/ia32/full-codegen-ia32.cc

index 005c137..6900a9e 100644 (file)
@@ -400,6 +400,7 @@ DEFINE_bool(print_json_ast, false, "print source AST as JSON")
 DEFINE_bool(print_builtin_json_ast, false,
             "print source AST for builtins as JSON")
 DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
+DEFINE_bool(verify_stack_height, false, "verify stack height tracing on ia32")
 
 // compiler.cc
 DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
index 8c2f0d1..e5375fc 100644 (file)
@@ -437,6 +437,7 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
 
 void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
   __ push(reg);
+  codegen()->increment_stack_height();
 }
 
 
@@ -450,11 +451,13 @@ void FullCodeGenerator::TestContext::Plug(Register reg) const {
 
 void FullCodeGenerator::EffectContext::PlugTOS() const {
   __ Drop(1);
+  codegen()->decrement_stack_height();
 }
 
 
 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
   __ pop(result_register());
+  codegen()->decrement_stack_height();
 }
 
 
@@ -465,6 +468,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const {
 void FullCodeGenerator::TestContext::PlugTOS() const {
   // For simplicity we always test the accumulator register.
   __ pop(result_register());
+  codegen()->decrement_stack_height();
   codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
   codegen()->DoTest(this);
 }
@@ -960,6 +964,7 @@ void FullCodeGenerator::VisitEnterWithContextStatement(
   VisitForStackValue(stmt->expression());
   PushFunctionArgumentForContextAllocation();
   __ CallRuntime(Runtime::kPushWithContext, 2);
+  decrement_stack_height();
   StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
 }
 
@@ -1128,8 +1133,10 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
   {
     TryCatch try_block(this, &catch_entry);
     __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
+    increment_stack_height(StackHandlerConstants::kSize / kPointerSize);
     Visit(stmt->try_block());
     __ PopTryHandler();
+    decrement_stack_height(StackHandlerConstants::kSize / kPointerSize);
   }
   __ bind(&done);
 }
@@ -1161,6 +1168,10 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   // cooked before GC.
   Label finally_entry;
   Label try_handler_setup;
+  const int original_stack_height = stack_height();
+  const int finally_block_stack_height = original_stack_height + 2;
+  const int try_block_stack_height = original_stack_height + 4;
+  STATIC_ASSERT(StackHandlerConstants::kSize / kPointerSize == 4);
 
   // Setup the try-handler chain. Use a call to
   // Jump to try-handler setup and try-block code. Use call to put try-handler
@@ -1182,6 +1193,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
     // Finally block implementation.
     Finally finally_block(this);
     EnterFinallyBlock();
+    set_stack_height(finally_block_stack_height);
     Visit(stmt->finally_block());
     ExitFinallyBlock();  // Return to the calling code.
   }
@@ -1191,8 +1203,10 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
     // Setup try handler (stack pointer registers).
     TryFinally try_block(this, &finally_entry);
     __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
+    set_stack_height(try_block_stack_height);
     Visit(stmt->try_block());
     __ PopTryHandler();
+    set_stack_height(original_stack_height);
   }
   // Execute the finally block on the way out.  Clobber the unpredictable
   // value in the accumulator with one that's safe for GC.  The finally
@@ -1222,6 +1236,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
   __ bind(&true_case);
   SetExpressionPosition(expr->then_expression(),
                         expr->then_expression_position());
+  int start_stack_height = stack_height();
   if (context()->IsTest()) {
     const TestContext* for_test = TestContext::cast(context());
     VisitForControl(expr->then_expression(),
@@ -1235,6 +1250,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
 
   PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
   __ bind(&false_case);
+  set_stack_height(start_stack_height);
   if (context()->IsTest()) ForwardBailoutToChild(expr);
   SetExpressionPosition(expr->else_expression(),
                         expr->else_expression_position());
@@ -1275,8 +1291,11 @@ void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
 
 void FullCodeGenerator::VisitThrow(Throw* expr) {
   Comment cmnt(masm_, "[ Throw");
+  // Throw has no effect on the stack height or the current expression context.
+  // Usually the expression context is null, because throw is a statement.
   VisitForStackValue(expr->exception());
   __ CallRuntime(Runtime::kThrow, 1);
+  decrement_stack_height();
   // Never returns here.
 }
 
index 6b174f7..9bd6e5e 100644 (file)
@@ -83,6 +83,7 @@ class FullCodeGenerator: public AstVisitor {
         scope_(NULL),
         nesting_stack_(NULL),
         loop_depth_(0),
+        stack_height_(0),
         context_(NULL),
         bailout_entries_(0),
         stack_checks_(2),  // There's always at least one.
@@ -519,6 +520,35 @@ class FullCodeGenerator: public AstVisitor {
     loop_depth_--;
   }
 
+#if defined(V8_TARGET_ARCH_IA32)
+  int stack_height() { return stack_height_; }
+  void set_stack_height(int depth) { stack_height_ = depth; }
+  void increment_stack_height() { stack_height_++; }
+  void increment_stack_height(int delta) { stack_height_ += delta; }
+  void decrement_stack_height() {
+    if (FLAG_verify_stack_height) {
+      ASSERT(stack_height_ > 0);
+    }
+    stack_height_--;
+  }
+  void decrement_stack_height(int delta) {
+    stack_height_-= delta;
+    if (FLAG_verify_stack_height) {
+      ASSERT(stack_height_ >= 0);
+    }
+  }
+  // Call this function only if FLAG_verify_stack_height is true.
+  void verify_stack_height();  // Generates a runtime check of esp - ebp.
+#else
+  int stack_height() { return 0; }
+  void set_stack_height(int depth) {}
+  void increment_stack_height() {}
+  void increment_stack_height(int delta) {}
+  void decrement_stack_height() {}
+  void decrement_stack_height(int delta) {}
+  void verify_stack_height() {}
+#endif  // V8_TARGET_ARCH_IA32
+
   MacroAssembler* masm() { return masm_; }
 
   class ExpressionContext;
@@ -578,6 +608,10 @@ class FullCodeGenerator: public AstVisitor {
 
     virtual ~ExpressionContext() {
       codegen_->set_new_context(old_);
+      if (FLAG_verify_stack_height) {
+        ASSERT_EQ(expected_stack_height_, codegen()->stack_height());
+        codegen()->verify_stack_height();
+      }
     }
 
     Isolate* isolate() const { return codegen_->isolate(); }
@@ -631,6 +665,7 @@ class FullCodeGenerator: public AstVisitor {
     FullCodeGenerator* codegen() const { return codegen_; }
     MacroAssembler* masm() const { return masm_; }
     MacroAssembler* masm_;
+    int expected_stack_height_;  // The expected stack height esp - ebp on exit.
 
    private:
     const ExpressionContext* old_;
@@ -640,7 +675,9 @@ class FullCodeGenerator: public AstVisitor {
   class AccumulatorValueContext : public ExpressionContext {
    public:
     explicit AccumulatorValueContext(FullCodeGenerator* codegen)
-        : ExpressionContext(codegen) { }
+        : ExpressionContext(codegen) {
+      expected_stack_height_ = codegen->stack_height();
+    }
 
     virtual void Plug(bool flag) const;
     virtual void Plug(Register reg) const;
@@ -661,7 +698,9 @@ class FullCodeGenerator: public AstVisitor {
   class StackValueContext : public ExpressionContext {
    public:
     explicit StackValueContext(FullCodeGenerator* codegen)
-        : ExpressionContext(codegen) { }
+        : ExpressionContext(codegen) {
+      expected_stack_height_ = codegen->stack_height() + 1;
+    }
 
     virtual void Plug(bool flag) const;
     virtual void Plug(Register reg) const;
@@ -690,7 +729,9 @@ class FullCodeGenerator: public AstVisitor {
           condition_(condition),
           true_label_(true_label),
           false_label_(false_label),
-          fall_through_(fall_through) { }
+          fall_through_(fall_through) {
+      expected_stack_height_ = codegen->stack_height();
+    }
 
     static const TestContext* cast(const ExpressionContext* context) {
       ASSERT(context->IsTest());
@@ -727,7 +768,10 @@ class FullCodeGenerator: public AstVisitor {
   class EffectContext : public ExpressionContext {
    public:
     explicit EffectContext(FullCodeGenerator* codegen)
-        : ExpressionContext(codegen) { }
+        : ExpressionContext(codegen) {
+      expected_stack_height_ = codegen->stack_height();
+    }
+
 
     virtual void Plug(bool flag) const;
     virtual void Plug(Register reg) const;
@@ -751,6 +795,7 @@ class FullCodeGenerator: public AstVisitor {
   Label return_label_;
   NestedStatement* nesting_stack_;
   int loop_depth_;
+  int stack_height_;
   const ExpressionContext* context_;
   ZoneList<BailoutEntry> bailout_entries_;
   ZoneList<BailoutEntry> stack_checks_;
index 7d41d95..994c9ff 100644 (file)
@@ -166,6 +166,11 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
     }
   }
 
+  set_stack_height(2 + scope()->num_stack_slots());
+  if (FLAG_verify_stack_height) {
+    verify_stack_height();
+  }
+
   bool function_in_register = true;
 
   // Possibly allocate a local context.
@@ -358,6 +363,15 @@ void FullCodeGenerator::EmitReturnSequence() {
 }
 
 
+void FullCodeGenerator::verify_stack_height() {
+  ASSERT(FLAG_verify_stack_height);
+  __ sub(Operand(ebp), Immediate(kPointerSize * stack_height()));
+  __ cmp(ebp, Operand(esp));
+  __ Assert(equal, "Full codegen stack height not as expected.");
+  __ add(Operand(ebp), Immediate(kPointerSize * stack_height()));
+}
+
+
 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
 }
 
@@ -372,6 +386,7 @@ void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
   MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
   // Memory operands can be pushed directly.
   __ push(slot_operand);
+  codegen()->increment_stack_height();
 }
 
 
@@ -425,6 +440,7 @@ void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
   } else {
     __ push(Immediate(lit));
   }
+  codegen()->increment_stack_height();
 }
 
 
@@ -462,6 +478,7 @@ void FullCodeGenerator::EffectContext::DropAndPlug(int count,
                                                    Register reg) const {
   ASSERT(count > 0);
   __ Drop(count);
+  codegen()->decrement_stack_height(count);
 }
 
 
@@ -471,6 +488,7 @@ void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
   ASSERT(count > 0);
   __ Drop(count);
   __ Move(result_register(), reg);
+  codegen()->decrement_stack_height(count);
 }
 
 
@@ -479,6 +497,7 @@ void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
   ASSERT(count > 0);
   if (count > 1) __ Drop(count - 1);
   __ mov(Operand(esp, 0), reg);
+  codegen()->decrement_stack_height(count - 1);
 }
 
 
@@ -490,6 +509,7 @@ void FullCodeGenerator::TestContext::DropAndPlug(int count,
   __ Move(result_register(), reg);
   codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
   codegen()->DoTest(this);
+  codegen()->decrement_stack_height(count);
 }
 
 
@@ -523,6 +543,7 @@ void FullCodeGenerator::StackValueContext::Plug(
   __ bind(materialize_false);
   __ push(Immediate(isolate()->factory()->false_value()));
   __ bind(&done);
+  codegen()->increment_stack_height();
 }
 
 
@@ -550,6 +571,7 @@ void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
       ? isolate()->factory()->true_value()
       : isolate()->factory()->false_value();
   __ push(Immediate(value));
+  codegen()->increment_stack_height();
 }
 
 
@@ -722,14 +744,18 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
         // Note: For variables we must not push an initial value (such as
         // 'undefined') because we may have a (legal) redeclaration and we
         // must not destroy the current value.
+        increment_stack_height(3);
         if (mode == Variable::CONST) {
           __ push(Immediate(isolate()->factory()->the_hole_value()));
+          increment_stack_height();
         } else if (function != NULL) {
           VisitForStackValue(function);
         } else {
           __ push(Immediate(Smi::FromInt(0)));  // No initial value!
+          increment_stack_height();
         }
         __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+        decrement_stack_height(4);
         break;
       }
     }
@@ -748,8 +774,10 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
       }
 
       __ push(eax);
+      increment_stack_height();
       VisitForAccumulatorValue(function);
       __ pop(edx);
+      decrement_stack_height();
 
       ASSERT(prop->key()->AsLiteral() != NULL &&
              prop->key()->AsLiteral()->handle()->IsSmi());
@@ -785,6 +813,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
   Breakable nested_statement(this, stmt);
   SetStatementPosition(stmt);
 
+  int switch_clause_stack_height = stack_height();
   // Keep the switch value on the stack until a case matches.
   VisitForStackValue(stmt->tag());
   PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
@@ -849,6 +878,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
     __ jmp(default_clause->body_target());
   }
 
+  set_stack_height(switch_clause_stack_height);
   // Compile all the case bodies.
   for (int i = 0; i < clauses->length(); i++) {
     Comment cmnt(masm_, "[ Case body");
@@ -890,6 +920,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ bind(&done_convert);
   __ push(eax);
+  increment_stack_height();
 
   // Check cache validity in generated code. This is a fast case for
   // the JSObject::IsSimpleEnum cache validity checks. If we cannot
@@ -973,6 +1004,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   __ push(eax);  // Fixed array length (as smi).
   __ push(Immediate(Smi::FromInt(0)));  // Initial index.
 
+  increment_stack_height(4);
   // Generate code for doing the condition check.
   __ bind(&loop);
   __ mov(eax, Operand(esp, 0 * kPointerSize));  // Get the current index.
@@ -1028,6 +1060,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   __ bind(loop_statement.break_target());
   __ add(Operand(esp), Immediate(5 * kPointerSize));
 
+  decrement_stack_height(5);
   // Exit and decrement the loop depth.
   __ bind(&exit);
   decrement_loop_depth();
@@ -1363,6 +1396,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
     if (!result_saved) {
       __ push(eax);  // Save result on the stack
       result_saved = true;
+      increment_stack_height();
     }
     switch (property->kind()) {
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
@@ -1387,6 +1421,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
         // Fall through.
       case ObjectLiteral::Property::PROTOTYPE:
         __ push(Operand(esp, 0));  // Duplicate receiver.
+        increment_stack_height();
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
@@ -1395,16 +1430,20 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
         } else {
           __ Drop(3);
         }
+        decrement_stack_height(3);
         break;
       case ObjectLiteral::Property::SETTER:
       case ObjectLiteral::Property::GETTER:
         __ push(Operand(esp, 0));  // Duplicate receiver.
+        increment_stack_height();
         VisitForStackValue(key);
         __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
                           Smi::FromInt(1) :
                           Smi::FromInt(0)));
+        increment_stack_height();
         VisitForStackValue(value);
         __ CallRuntime(Runtime::kDefineAccessor, 4);
+        decrement_stack_height(4);
         break;
       default: UNREACHABLE();
     }
@@ -1467,6 +1506,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
     if (!result_saved) {
       __ push(eax);
       result_saved = true;
+      increment_stack_height();
     }
     VisitForAccumulatorValue(subexpr);
 
@@ -1495,7 +1535,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
   // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
   // on the left-hand side.
   if (!expr->target()->IsValidLeftHandSide()) {
-    VisitForEffect(expr->target());
+    ASSERT(expr->target()->AsThrow() != NULL);
+    VisitInCurrentContext(expr->target());  // Throw does not plug the context
+    context()->Plug(eax);
     return;
   }
 
@@ -1520,6 +1562,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
         // We need the receiver both on the stack and in the accumulator.
         VisitForAccumulatorValue(property->obj());
         __ push(result_register());
+        increment_stack_height();
       } else {
         VisitForStackValue(property->obj());
       }
@@ -1530,6 +1573,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
         VisitForAccumulatorValue(property->key());
         __ mov(edx, Operand(esp, 0));
         __ push(eax);
+        increment_stack_height();
       } else {
         VisitForStackValue(property->obj());
         VisitForStackValue(property->key());
@@ -1541,7 +1585,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
   // For compound assignments we need another deoptimization point after the
   // variable/property load.
   if (expr->is_compound()) {
-    { AccumulatorValueContext context(this);
+    AccumulatorValueContext result_context(this);
+    { AccumulatorValueContext left_operand_context(this);
       switch (assign_type) {
         case VARIABLE:
           EmitVariableLoad(expr->target()->AsVariableProxy());
@@ -1560,13 +1605,13 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
 
     Token::Value op = expr->binary_op();
     __ push(eax);  // Left operand goes on the stack.
+    increment_stack_height();
     VisitForAccumulatorValue(expr->value());
 
     OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
         ? OVERWRITE_RIGHT
         : NO_OVERWRITE;
     SetSourcePosition(expr->position() + 1);
-    AccumulatorValueContext context(this);
     if (ShouldInlineSmiCase(op)) {
       EmitInlineSmiBinaryOp(expr->binary_operation(),
                             op,
@@ -1630,6 +1675,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
   // stack. Right operand is in eax.
   Label smi_case, done, stub_call;
   __ pop(edx);
+  decrement_stack_height();
   __ mov(ecx, eax);
   __ or_(eax, Operand(edx));
   JumpPatchSite patch_site(masm_);
@@ -1721,6 +1767,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
   __ pop(edx);
+  decrement_stack_height();
   BinaryOpStub stub(op, mode);
   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
@@ -1733,7 +1780,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
   // Invalid left-hand sides are rewritten to have a 'throw
   // ReferenceError' on the left-hand side.
   if (!expr->IsValidLeftHandSide()) {
-    VisitForEffect(expr);
+    ASSERT(expr->AsThrow() != NULL);
+    VisitInCurrentContext(expr);  // Throw does not plug the context
+    context()->Plug(eax);
     return;
   }
 
@@ -1757,9 +1806,11 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
     }
     case NAMED_PROPERTY: {
       __ push(eax);  // Preserve value.
+      increment_stack_height();
       VisitForAccumulatorValue(prop->obj());
       __ mov(edx, eax);
       __ pop(eax);  // Restore value.
+      decrement_stack_height();
       __ mov(ecx, prop->key()->AsLiteral()->handle());
       Handle<Code> ic = is_strict_mode()
           ? isolate()->builtins()->StoreIC_Initialize_Strict()
@@ -1769,6 +1820,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
     }
     case KEYED_PROPERTY: {
       __ push(eax);  // Preserve value.
+      increment_stack_height();
       if (prop->is_synthetic()) {
         ASSERT(prop->obj()->AsVariableProxy() != NULL);
         ASSERT(prop->key()->AsLiteral() != NULL);
@@ -1782,8 +1834,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
         VisitForAccumulatorValue(prop->key());
         __ mov(ecx, eax);
         __ pop(edx);
+        decrement_stack_height();
       }
       __ pop(eax);  // Restore value.
+      decrement_stack_height();
       Handle<Code> ic = is_strict_mode()
           ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
           : isolate()->builtins()->KeyedStoreIC_Initialize();
@@ -1900,6 +1954,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
     __ mov(edx, Operand(esp, 0));
   } else {
     __ pop(edx);
+    decrement_stack_height();
   }
   Handle<Code> ic = is_strict_mode()
       ? isolate()->builtins()->StoreIC_Initialize_Strict()
@@ -1913,6 +1968,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
     __ CallRuntime(Runtime::kToFastProperties, 1);
     __ pop(eax);
     __ Drop(1);
+    decrement_stack_height();
   }
   PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
   context()->Plug(eax);
@@ -1934,10 +1990,12 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   }
 
   __ pop(ecx);
+  decrement_stack_height();
   if (expr->ends_initialization_block()) {
     __ mov(edx, Operand(esp, 0));  // Leave receiver on the stack for later.
   } else {
     __ pop(edx);
+    decrement_stack_height();
   }
   // Record source code position before IC call.
   SetSourcePosition(expr->position());
@@ -1953,6 +2011,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
     __ push(edx);
     __ CallRuntime(Runtime::kToFastProperties, 1);
     __ pop(eax);
+    decrement_stack_height();
   }
 
   PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
@@ -1972,6 +2031,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
     VisitForStackValue(expr->obj());
     VisitForAccumulatorValue(expr->key());
     __ pop(edx);
+    decrement_stack_height();
     EmitKeyedPropertyLoad(expr);
     context()->Plug(eax);
   }
@@ -1999,6 +2059,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
   RecordJSReturnSite(expr);
   // Restore context register.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  decrement_stack_height(arg_count + 1);
   context()->Plug(eax);
 }
 
@@ -2013,6 +2074,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
   __ pop(ecx);
   __ push(eax);
   __ push(ecx);
+  increment_stack_height();
 
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2032,6 +2094,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
   RecordJSReturnSite(expr);
   // Restore context register.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  decrement_stack_height(arg_count + 1);
   context()->DropAndPlug(1, eax);  // Drop the key still on the stack.
 }
 
@@ -2053,6 +2116,8 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
   RecordJSReturnSite(expr);
   // Restore context register.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+
+  decrement_stack_height(arg_count + 1);
   context()->DropAndPlug(1, eax);
 }
 
@@ -2100,7 +2165,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       VisitForStackValue(fun);
       // Reserved receiver slot.
       __ push(Immediate(isolate()->factory()->undefined_value()));
-
+      increment_stack_height();
       // Push the arguments.
       for (int i = 0; i < arg_count; i++) {
         VisitForStackValue(args->at(i));
@@ -2144,10 +2209,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     RecordJSReturnSite(expr);
     // Restore context register.
     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    decrement_stack_height(arg_count + 1);  // Function is left on the stack.
     context()->DropAndPlug(1, eax);
   } else if (var != NULL && !var->is_this() && var->is_global()) {
     // Push global object as receiver for the call IC.
     __ push(GlobalObjectOperand());
+    increment_stack_height();
     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   } else if (var != NULL && var->AsSlot() != NULL &&
              var->AsSlot()->type() == Slot::LOOKUP) {
@@ -2170,7 +2237,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     __ push(Immediate(var->name()));
     __ CallRuntime(Runtime::kLoadContextSlot, 2);
     __ push(eax);  // Function.
+    increment_stack_height();
     __ push(edx);  // Receiver.
+    increment_stack_height();
 
     // If fast case code has been generated, emit code to push the
     // function and receiver and have the slow path jump around this
@@ -2179,7 +2248,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       Label call;
       __ jmp(&call);
       __ bind(&done);
-      // Push function.
+      // Push function.  Stack height already incremented in slow case above.
       __ push(eax);
       // The receiver is implicitly the global receiver. Indicate this
       // by passing the hole to the call function stub.
@@ -2225,9 +2294,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
         // Push result (function).
         __ push(eax);
+        increment_stack_height();
         // Push Global receiver.
         __ mov(ecx, GlobalObjectOperand());
         __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
+        increment_stack_height();
         EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
       } else {
         { PreservePositionScope scope(masm()->positions_recorder());
@@ -2243,6 +2314,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     // Load global receiver object.
     __ mov(ebx, GlobalObjectOperand());
     __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
+    increment_stack_height();
     // Emit function call.
     EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
   }
@@ -2283,6 +2355,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   Handle<Code> construct_builtin =
       isolate()->builtins()->JSConstructCall();
   __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
+
+  decrement_stack_height(arg_count + 1);
   context()->Plug(eax);
 }
 
@@ -2595,6 +2669,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
                          &if_true, &if_false, &fall_through);
 
   __ pop(ebx);
+  decrement_stack_height();
   __ cmp(eax, Operand(ebx));
   PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
   Split(equal, if_true, if_false, fall_through);
@@ -2709,6 +2784,7 @@ void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
     VisitForStackValue(args->at(1));
     VisitForStackValue(args->at(2));
     __ CallRuntime(Runtime::kLog, 2);
+    decrement_stack_height(2);
   }
   // Finally, we're expected to leave a value on the top of the stack.
   __ mov(eax, isolate()->factory()->undefined_value());
@@ -2774,6 +2850,7 @@ void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
   VisitForStackValue(args->at(1));
   VisitForStackValue(args->at(2));
   __ CallStub(&stub);
+  decrement_stack_height(3);
   context()->Plug(eax);
 }
 
@@ -2787,6 +2864,7 @@ void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
   VisitForStackValue(args->at(2));
   VisitForStackValue(args->at(3));
   __ CallStub(&stub);
+  decrement_stack_height(4);
   context()->Plug(eax);
 }
 
@@ -2821,6 +2899,7 @@ void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
   } else {
     __ CallRuntime(Runtime::kMath_pow, 2);
   }
+  decrement_stack_height(2);
   context()->Plug(eax);
 }
 
@@ -2831,6 +2910,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
   VisitForStackValue(args->at(0));  // Load the object.
   VisitForAccumulatorValue(args->at(1));  // Load the value.
   __ pop(ebx);  // eax = value. ebx = object.
+  decrement_stack_height();
 
   Label done;
   // If the object is a smi, return the value.
@@ -2860,6 +2940,7 @@ void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
 
   NumberToStringStub stub;
   __ CallStub(&stub);
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -2894,6 +2975,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
   Register result = edx;
 
   __ pop(object);
+  decrement_stack_height();
 
   Label need_conversion;
   Label index_out_of_range;
@@ -2942,6 +3024,7 @@ void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
   Register result = eax;
 
   __ pop(object);
+  decrement_stack_height();
 
   Label need_conversion;
   Label index_out_of_range;
@@ -2986,6 +3069,7 @@ void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
 
   StringAddStub stub(NO_STRING_ADD_FLAGS);
   __ CallStub(&stub);
+  decrement_stack_height(2);
   context()->Plug(eax);
 }
 
@@ -2998,6 +3082,7 @@ void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
 
   StringCompareStub stub;
   __ CallStub(&stub);
+  decrement_stack_height(2);
   context()->Plug(eax);
 }
 
@@ -3009,6 +3094,7 @@ void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3020,6 +3106,7 @@ void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3031,6 +3118,7 @@ void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3040,6 +3128,7 @@ void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallRuntime(Runtime::kMath_sqrt, 1);
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3059,6 +3148,7 @@ void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
   __ InvokeFunction(edi, count, CALL_FUNCTION,
                     NullCallWrapper(), CALL_AS_METHOD);
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  decrement_stack_height(arg_count + 1);
   context()->Plug(eax);
 }
 
@@ -3071,6 +3161,7 @@ void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
   VisitForStackValue(args->at(1));
   VisitForStackValue(args->at(2));
   __ CallStub(&stub);
+  decrement_stack_height(3);
   context()->Plug(eax);
 }
 
@@ -3144,6 +3235,7 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
   __ CallRuntime(Runtime::kSwapElements, 3);
 
   __ bind(&done);
+  decrement_stack_height(3);
   context()->Plug(eax);
 }
 
@@ -3229,6 +3321,7 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
   __ mov(eax, Immediate(isolate()->factory()->true_value()));
   __ bind(&done);
 
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3532,6 +3625,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
   __ add(Operand(esp), Immediate(3 * kPointerSize));
 
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  decrement_stack_height();
   context()->Plug(eax);
 }
 
@@ -3584,6 +3678,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     // Prepare for calling JS runtime function.
     __ mov(eax, GlobalObjectOperand());
     __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
+    increment_stack_height();
   }
 
   // Push the arguments ("left-to-right").
@@ -3606,6 +3701,11 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     // Call the C runtime function.
     __ CallRuntime(expr->function(), arg_count);
   }
+  decrement_stack_height(arg_count);
+  if (expr->is_jsruntime()) {
+    decrement_stack_height();
+  }
+
   context()->Plug(eax);
 }
 
@@ -3627,6 +3727,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           VisitForStackValue(prop->key());
           __ push(Immediate(Smi::FromInt(strict_mode_flag())));
           __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+          decrement_stack_height(2);
           context()->Plug(eax);
         }
       } else if (var != NULL) {
@@ -3696,6 +3797,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
         VisitForTypeofValue(expr->expression());
       }
       __ CallRuntime(Runtime::kTypeof, 1);
+      decrement_stack_height();
       context()->Plug(eax);
       break;
     }
@@ -3750,7 +3852,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
   // as the left-hand side.
   if (!expr->expression()->IsValidLeftHandSide()) {
-    VisitForEffect(expr->expression());
+    ASSERT(expr->expression()->AsThrow() != NULL);
+    VisitInCurrentContext(expr->expression());
+    // Visiting Throw does not plug the context.
+    context()->Plug(eax);
     return;
   }
 
@@ -3775,17 +3880,20 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     // Reserve space for result of postfix operation.
     if (expr->is_postfix() && !context()->IsEffect()) {
       __ push(Immediate(Smi::FromInt(0)));
+      increment_stack_height();
     }
     if (assign_type == NAMED_PROPERTY) {
       // Put the object both on the stack and in the accumulator.
       VisitForAccumulatorValue(prop->obj());
       __ push(eax);
+      increment_stack_height();
       EmitNamedPropertyLoad(prop);
     } else {
       VisitForStackValue(prop->obj());
       VisitForAccumulatorValue(prop->key());
       __ mov(edx, Operand(esp, 0));
       __ push(eax);
+      increment_stack_height();
       EmitKeyedPropertyLoad(prop);
     }
   }
@@ -3816,6 +3924,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       switch (assign_type) {
         case VARIABLE:
           __ push(eax);
+          increment_stack_height();
           break;
         case NAMED_PROPERTY:
           __ mov(Operand(esp, kPointerSize), eax);
@@ -3889,6 +3998,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     case NAMED_PROPERTY: {
       __ mov(ecx, prop->key()->AsLiteral()->handle());
       __ pop(edx);
+      decrement_stack_height();
       Handle<Code> ic = is_strict_mode()
           ? isolate()->builtins()->StoreIC_Initialize_Strict()
           : isolate()->builtins()->StoreIC_Initialize();
@@ -3906,6 +4016,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     case KEYED_PROPERTY: {
       __ pop(ecx);
       __ pop(edx);
+      decrement_stack_height();
+      decrement_stack_height();
       Handle<Code> ic = is_strict_mode()
           ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
           : isolate()->builtins()->KeyedStoreIC_Initialize();
@@ -4063,6 +4175,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
     case Token::IN:
       VisitForStackValue(expr->right());
       __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
+      decrement_stack_height(2);
       PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
       __ cmp(eax, isolate()->factory()->true_value());
       Split(equal, if_true, if_false, fall_through);
@@ -4072,6 +4185,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
       VisitForStackValue(expr->right());
       InstanceofStub stub(InstanceofStub::kNoFlags);
       __ CallStub(&stub);
+      decrement_stack_height(2);
       PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
       __ test(eax, Operand(eax));
       // The stub returns 0 for true.
@@ -4116,6 +4230,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
         default:
           UNREACHABLE();
       }
+      decrement_stack_height();
 
       bool inline_smi_code = ShouldInlineSmiCase(op);
       JumpPatchSite patch_site(masm_);