Fast codegen: Working break and continue.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 10 Dec 2009 14:06:08 +0000 (14:06 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 10 Dec 2009 14:06:08 +0000 (14:06 +0000)
Started framework for all intra-functional outward control transfers,
including handling of try/finally.

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

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

12 files changed:
src/arm/fast-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/compiler.cc
src/fast-codegen.cc
src/fast-codegen.h
src/ia32/fast-codegen-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/x64/fast-codegen-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index 2c264d8..04fff5c 100644 (file)
@@ -521,21 +521,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
 }
 
 
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
-  Comment cmnt(masm_, "[ ReturnStatement");
-  Expression* expr = stmt->expression();
-  // Complete the statement based on the type of the subexpression.
-  if (expr->AsLiteral() != NULL) {
-    __ mov(r0, Operand(expr->AsLiteral()->handle()));
-  } else {
-    ASSERT_EQ(Expression::kValue, expr->context());
-    Visit(expr);
-    __ pop(r0);
-  }
-  EmitReturnSequence(stmt->statement_pos());
-}
-
-
 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
   Comment cmnt(masm_, "[ FunctionLiteral");
 
@@ -1668,6 +1653,8 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+Register FastCodeGenerator::result_register() { return r0; }
+
 #undef __
 
 
index a9567c0..876eec1 100644 (file)
@@ -162,6 +162,21 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
 }
 
 
+void MacroAssembler::Drop(int stack_elements, Condition cond) {
+  if (stack_elements > 0) {
+    add(sp, sp, Operand(stack_elements * kPointerSize), LeaveCC, cond);
+  }
+}
+
+
+void MacroAssembler::Call(Label* target) {
+  bl(target);
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> value) {
+  mov(dst, Operand(value));
+}
 
 
 void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
@@ -628,6 +643,15 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
 }
 
 
+void MacroAssembler::PopTryHandler() {
+  ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+  pop(r1);
+  mov(ip, Operand(ExternalReference(Top::k_handler_address)));
+  add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  str(r1, MemOperand(ip));
+}
+
+
 Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
                                    JSObject* holder, Register holder_reg,
                                    Register scratch,
index 0974329..88bfa9c 100644 (file)
@@ -64,6 +64,9 @@ class MacroAssembler: public Assembler {
   void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
   void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
   void Ret(Condition cond = al);
+  void Drop(int stack_elements, Condition cond = al);
+  void Call(Label* target);
+  void Move(Register dst, Handle<Object> value);
   // Jumps to the label at the index given by the Smi in "index".
   void SmiJumpTable(Register index, Vector<Label*> targets);
   // Load an object from the root table.
@@ -148,6 +151,9 @@ class MacroAssembler: public Assembler {
   // On exit, r0 contains TOS (code slot).
   void PushTryHandler(CodeLocation try_location, HandlerType type);
 
+  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Must preserve the result register.
+  void PopTryHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support
index 6fc8a8f..d8dd650 100644 (file)
@@ -690,12 +690,10 @@ void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
 
 
 void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {
-  BAILOUT("ContinueStatement");
 }
 
 
 void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
-  BAILOUT("BreakStatement");
 }
 
 
index b835faf..5c4a70b 100644 (file)
@@ -36,7 +36,7 @@
 namespace v8 {
 namespace internal {
 
-#define __ ACCESS_MASM(masm_)
+#define __ ACCESS_MASM(masm())
 
 Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
                                          Handle<Script> script,
@@ -232,8 +232,10 @@ void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
 
 void FastCodeGenerator::VisitBlock(Block* stmt) {
   Comment cmnt(masm_, "[ Block");
+  Breakable nested_statement(this, stmt);
   SetStatementPosition(stmt);
   VisitStatements(stmt->statements());
+  __ bind(nested_statement.break_target());
 }
 
 
@@ -278,15 +280,62 @@ void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
 
 
 void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
-  UNREACHABLE();
+  Comment cmnt(masm_,  "[ ContinueStatement");
+  NestedStatement* current = nesting_stack_;
+  int stack_depth = 0;
+  while (!current->IsContinueTarget(stmt->target())) {
+    stack_depth = current->Exit(stack_depth);
+    current = current->outer();
+  }
+  __ Drop(stack_depth);
+
+  Iteration* loop = current->AsIteration();
+  __ jmp(loop->continue_target());
 }
 
 
 void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
-  UNREACHABLE();
+  Comment cmnt(masm_,  "[ BreakStatement");
+  NestedStatement* current = nesting_stack_;
+  int stack_depth = 0;
+  while (!current->IsBreakTarget(stmt->target())) {
+    stack_depth = current->Exit(stack_depth);
+    current = current->outer();
+  }
+  __ Drop(stack_depth);
+
+  Breakable* target = current->AsBreakable();
+  __ jmp(target->break_target());
 }
 
 
+void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+  Comment cmnt(masm_, "[ ReturnStatement");
+  Expression* expr = stmt->expression();
+  // Complete the statement based on the type of the subexpression.
+  if (expr->AsLiteral() != NULL) {
+    __ Move(result_register(), expr->AsLiteral()->handle());
+  } else {
+    ASSERT_EQ(Expression::kValue, expr->context());
+    Visit(expr);
+    __ pop(result_register());
+  }
+
+  // Exit all nested statements.
+  NestedStatement* current = nesting_stack_;
+  int stack_depth = 0;
+  while (current != NULL) {
+    stack_depth = current->Exit(stack_depth);
+    current = current->outer();
+  }
+  __ Drop(stack_depth);
+
+  EmitReturnSequence(stmt->statement_pos());
+}
+
+
+
+
 void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
   UNREACHABLE();
 }
@@ -304,8 +353,10 @@ void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
 
 void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   Comment cmnt(masm_, "[ DoWhileStatement");
+  Label body, stack_limit_hit, stack_check_success;
+
+  Iteration loop_statement(this, stmt);
   increment_loop_depth();
-  Label body, exit, stack_limit_hit, stack_check_success;
 
   __ bind(&body);
   Visit(stmt->body());
@@ -316,10 +367,11 @@ void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
 
   // We are not in an expression context because we have been compiling
   // statements.  Set up a test expression context for the condition.
+  __ bind(loop_statement.continue_target());
   ASSERT_EQ(NULL, true_label_);
   ASSERT_EQ(NULL, false_label_);
   true_label_ = &body;
-  false_label_ = &exit;
+  false_label_ = loop_statement.break_target();
   ASSERT(stmt->cond()->context() == Expression::kTest);
   Visit(stmt->cond());
   true_label_ = NULL;
@@ -330,7 +382,7 @@ void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   __ CallStub(&stack_stub);
   __ jmp(&stack_check_success);
 
-  __ bind(&exit);
+  __ bind(loop_statement.break_target());
 
   decrement_loop_depth();
 }
@@ -338,16 +390,18 @@ void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
 
 void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   Comment cmnt(masm_, "[ WhileStatement");
+  Label body, stack_limit_hit, stack_check_success;
+
+  Iteration loop_statement(this, stmt);
   increment_loop_depth();
-  Label test, body, exit, stack_limit_hit, stack_check_success;
 
   // Emit the test at the bottom of the loop.
-  __ jmp(&test);
+  __ jmp(loop_statement.continue_target());
 
   __ bind(&body);
   Visit(stmt->body());
 
-  __ bind(&test);
+  __ bind(loop_statement.continue_target());
   // Check stack before looping.
   __ StackLimitCheck(&stack_limit_hit);
   __ bind(&stack_check_success);
@@ -357,7 +411,7 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   ASSERT_EQ(NULL, true_label_);
   ASSERT_EQ(NULL, false_label_);
   true_label_ = &body;
-  false_label_ = &exit;
+  false_label_ = loop_statement.break_target();
   ASSERT(stmt->cond()->context() == Expression::kTest);
   Visit(stmt->cond());
   true_label_ = NULL;
@@ -368,8 +422,7 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   __ CallStub(&stack_stub);
   __ jmp(&stack_check_success);
 
-  __ bind(&exit);
-
+  __ bind(loop_statement.break_target());
   decrement_loop_depth();
 }
 
@@ -513,6 +566,23 @@ void FastCodeGenerator::VisitThrow(Throw* expr) {
 }
 
 
+int FastCodeGenerator::TryFinally::Exit(int stack_depth) {
+  // The macros used here must preserve the result register.
+  __ Drop(stack_depth);
+  __ PopTryHandler();
+  __ Call(finally_entry_);
+  return 0;
+}
+
+
+int FastCodeGenerator::TryCatch::Exit(int stack_depth) {
+  // The macros used here must preserve the result register.
+  __ Drop(stack_depth);
+  __ PopTryHandler();
+  return 0;
+}
+
+
 #undef __
 
 
index 9b262a7..9a8c990 100644 (file)
@@ -35,6 +35,8 @@
 namespace v8 {
 namespace internal {
 
+// -----------------------------------------------------------------------------
+// Fast code generator.
 
 class FastCodeGenerator: public AstVisitor {
  public:
@@ -43,6 +45,7 @@ class FastCodeGenerator: public AstVisitor {
         function_(NULL),
         script_(script),
         is_eval_(is_eval),
+        nesting_stack_(NULL),
         loop_depth_(0),
         true_label_(NULL),
         false_label_(NULL) {
@@ -55,6 +58,159 @@ class FastCodeGenerator: public AstVisitor {
   void Generate(FunctionLiteral* fun);
 
  private:
+  class Breakable;
+  class Iteration;
+  class TryCatch;
+  class TryFinally;
+  class Finally;
+  class ForIn;
+
+  class NestedStatement BASE_EMBEDDED {
+   public:
+    explicit NestedStatement(FastCodeGenerator* codegen) : codegen_(codegen) {
+      // Link into codegen's nesting stack.
+      previous_ = codegen->nesting_stack_;
+      codegen->nesting_stack_ = this;
+    }
+    virtual ~NestedStatement() {
+      // Unlink from codegen's nesting stack.
+      ASSERT_EQ(this, codegen_->nesting_stack_);
+      codegen_->nesting_stack_ = previous_;
+    }
+
+    virtual Breakable* AsBreakable() { return NULL; }
+    virtual Iteration* AsIteration() { return NULL; }
+    virtual TryCatch* AsTryCatch() { return NULL; }
+    virtual TryFinally* AsTryFinally() { return NULL; }
+    virtual Finally* AsFinally() { return NULL; }
+    virtual ForIn* AsForIn() { return NULL; }
+
+    virtual bool IsContinueTarget(Statement* target) { return false; }
+    virtual bool IsBreakTarget(Statement* target) { return false; }
+
+    // Generate code to leave the nested statement. This includes
+    // cleaning up any stack elements in use and restoring the
+    // stack to the expectations of the surrounding statements.
+    // Takes a number of stack elements currently on top of the
+    // nested statement's stack, and returns a number of stack
+    // elements left on top of the surrounding statement's stack.
+    // The generated code must preserve the result register (which
+    // contains the value in case of a return).
+    virtual int Exit(int stack_depth) {
+      // Default implementation for the case where there is
+      // nothing to clean up.
+      return stack_depth;
+    }
+    NestedStatement* outer() { return previous_; }
+   protected:
+    MacroAssembler* masm() { return codegen_->masm(); }
+   private:
+    FastCodeGenerator* codegen_;
+    NestedStatement* previous_;
+    DISALLOW_COPY_AND_ASSIGN(NestedStatement);
+  };
+
+  class Breakable : public NestedStatement {
+   public:
+    Breakable(FastCodeGenerator* codegen,
+              BreakableStatement* break_target)
+        : NestedStatement(codegen),
+          target_(break_target) {}
+    virtual ~Breakable() {}
+    virtual Breakable* AsBreakable() { return this; }
+    virtual bool IsBreakTarget(Statement* statement) {
+      return target_ == statement;
+    }
+    BreakableStatement* statement() { return target_; }
+    Label* break_target() { return &break_target_label_; }
+   private:
+    BreakableStatement* target_;
+    Label break_target_label_;
+    DISALLOW_COPY_AND_ASSIGN(Breakable);
+  };
+
+  class Iteration : public Breakable {
+   public:
+    Iteration(FastCodeGenerator* codegen,
+              IterationStatement* iteration_statement)
+        : Breakable(codegen, iteration_statement) {}
+    virtual ~Iteration() {}
+    virtual Iteration* AsIteration() { return this; }
+    virtual bool IsContinueTarget(Statement* statement) {
+      return this->statement() == statement;
+    }
+    Label* continue_target() { return &continue_target_label_; }
+   private:
+    Label continue_target_label_;
+    DISALLOW_COPY_AND_ASSIGN(Iteration);
+  };
+
+  // The environment inside the try block of a try/catch statement.
+  class TryCatch : public NestedStatement {
+   public:
+    explicit TryCatch(FastCodeGenerator* codegen, Label* catch_entry)
+        : NestedStatement(codegen), catch_entry_(catch_entry) { }
+    virtual ~TryCatch() {}
+    virtual TryCatch* AsTryCatch() { return this; }
+    Label* catch_entry() { return catch_entry_; }
+    virtual int Exit(int stack_depth);
+   private:
+    Label* catch_entry_;
+    DISALLOW_COPY_AND_ASSIGN(TryCatch);
+  };
+
+  // The environment inside the try block of a try/finally statement.
+  class TryFinally : public NestedStatement {
+   public:
+    explicit TryFinally(FastCodeGenerator* codegen, Label* finally_entry)
+        : NestedStatement(codegen), finally_entry_(finally_entry) { }
+    virtual ~TryFinally() {}
+    virtual TryFinally* AsTryFinally() { return this; }
+    Label* finally_entry() { return finally_entry_; }
+    virtual int Exit(int stack_depth);
+   private:
+    Label* finally_entry_;
+    DISALLOW_COPY_AND_ASSIGN(TryFinally);
+  };
+
+  // A FinallyEnvironment represents being inside a finally block.
+  // Abnormal termination of the finally block needs to clean up
+  // the block's parameters from the stack.
+  class Finally : public NestedStatement {
+   public:
+    explicit Finally(FastCodeGenerator* codegen) : NestedStatement(codegen) { }
+    virtual ~Finally() {}
+    virtual Finally* AsFinally() { return this; }
+    virtual int Exit(int stack_depth) {
+      return stack_depth + kFinallyStackElementCount;
+    }
+   private:
+    // Number of extra stack slots occupied during a finally block.
+    static const int kFinallyStackElementCount = 2;
+    DISALLOW_COPY_AND_ASSIGN(Finally);
+  };
+
+  // A ForInEnvironment represents being inside a for-in loop.
+  // Abnormal termination of the for-in block needs to clean up
+  // the block's temporary storage from the stack.
+  class ForIn : public Iteration {
+   public:
+    ForIn(FastCodeGenerator* codegen,
+          ForInStatement* statement)
+        : Iteration(codegen, statement) { }
+    virtual ~ForIn() {}
+    virtual ForIn* AsForIn() { return this; }
+    virtual int Exit(int stack_depth) {
+      return stack_depth + kForInStackElementCount;
+    }
+   private:
+    // TODO(lrn): Check that this value is correct when implementing
+    // for-in.
+    static const int kForInStackElementCount = 5;
+    DISALLOW_COPY_AND_ASSIGN(ForIn);
+  };
+
+
   int SlotOffset(Slot* slot);
   void Move(Expression::Context destination, Register source);
   void Move(Expression::Context destination, Slot* source, Register scratch);
@@ -112,11 +268,13 @@ class FastCodeGenerator: public AstVisitor {
     loop_depth_--;
   }
 
+  MacroAssembler* masm() { return masm_; }
+  static Register result_register();
+
   // AST node visit functions.
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
-
   // Handles the shortcutted logical binary operations in VisitBinaryOperation.
   void EmitLogicalOperation(BinaryOperation* expr);
 
@@ -125,11 +283,14 @@ class FastCodeGenerator: public AstVisitor {
   Handle<Script> script_;
   bool is_eval_;
   Label return_label_;
+  NestedStatement* nesting_stack_;
   int loop_depth_;
 
   Label* true_label_;
   Label* false_label_;
 
+  friend class NestedStatement;
+
   DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
 };
 
index 41524d8..b6e16f3 100644 (file)
@@ -515,20 +515,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
 }
 
 
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
-  Comment cmnt(masm_, "[ ReturnStatement");
-  Expression* expr = stmt->expression();
-  if (expr->AsLiteral() != NULL) {
-    __ mov(eax, expr->AsLiteral()->handle());
-  } else {
-    ASSERT_EQ(Expression::kValue, expr->context());
-    Visit(expr);
-    __ pop(eax);
-  }
-  EmitReturnSequence(stmt->statement_pos());
-}
-
-
 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
   Comment cmnt(masm_, "[ FunctionLiteral");
 
@@ -1639,6 +1625,7 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
   // Convert current context to test context: End post-test code.
 }
 
+Register FastCodeGenerator::result_register() { return eax; }
 
 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
index 3b08884..ac2895e 100644 (file)
@@ -504,6 +504,13 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
 }
 
 
+void MacroAssembler::PopTryHandler() {
+  ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+  pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+  add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
+}
+
+
 Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
                                    JSObject* holder, Register holder_reg,
                                    Register scratch,
@@ -1350,6 +1357,18 @@ void MacroAssembler::Ret() {
 }
 
 
+void MacroAssembler::Drop(int stack_elements) {
+  if (stack_elements > 0) {
+    add(Operand(esp), Immediate(stack_elements * kPointerSize));
+  }
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> value) {
+  mov(dst, value);
+}
+
+
 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
index 5d6d43e..1d4bfa1 100644 (file)
@@ -149,6 +149,9 @@ class MacroAssembler: public Assembler {
   // address must be pushed before calling this helper.
   void PushTryHandler(CodeLocation try_location, HandlerType type);
 
+  // Unlink the stack handler on top of the stack from the try handler chain.
+  void PopTryHandler();
+
 
   // ---------------------------------------------------------------------------
   // Inline caching support
@@ -333,6 +336,12 @@ class MacroAssembler: public Assembler {
 
   void Ret();
 
+  void Drop(int element_count);
+
+  void Call(Label* target) { call(target); }
+
+  void Move(Register target, Handle<Object> value);
+
   struct Unresolved {
     int pc;
     uint32_t flags;  // see Bootstrapper::FixupFlags decoders/encoders.
index 7d9adb8..69a2ff3 100644 (file)
@@ -525,20 +525,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
 }
 
 
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
-  Comment cmnt(masm_, "[ ReturnStatement");
-  Expression* expr = stmt->expression();
-  if (expr->AsLiteral() != NULL) {
-    __ Move(rax, expr->AsLiteral()->handle());
-  } else {
-    Visit(expr);
-    ASSERT_EQ(Expression::kValue, expr->context());
-    __ pop(rax);
-  }
-  EmitReturnSequence(stmt->statement_pos());
-}
-
-
 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
   Comment cmnt(masm_, "[ FunctionLiteral");
 
@@ -1650,6 +1636,8 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+Register FastCodeGenerator::result_register() { return rax; }
+
 #undef __
 
 
index d58f943..c3ea925 100644 (file)
@@ -1345,6 +1345,13 @@ void MacroAssembler::Push(Smi* source) {
 }
 
 
+void MacroAssembler::Drop(int stack_elements) {
+  if (stack_elements > 0) {
+    addq(rsp, Immediate(stack_elements * kPointerSize));
+  }
+}
+
+
 void MacroAssembler::Test(const Operand& src, Smi* source) {
   intptr_t smi = reinterpret_cast<intptr_t>(source);
   if (is_int32(smi)) {
@@ -1431,6 +1438,14 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
 }
 
 
+void MacroAssembler::PopTryHandler() {
+  ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+  movq(kScratchRegister, ExternalReference(Top::k_handler_address));
+  pop(Operand(kScratchRegister, 0));
+  addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
+}
+
+
 void MacroAssembler::Ret() {
   ret(0);
 }
index 1dce159..9720005 100644 (file)
@@ -400,7 +400,7 @@ class MacroAssembler: public Assembler {
   void Test(const Operand& dst, Smi* source);
 
   // ---------------------------------------------------------------------------
-  // Macro instructions
+  // Macro instructions.
 
   // Load a register with a long value as efficiently as possible.
   void Set(Register dst, int64_t x);
@@ -412,6 +412,8 @@ class MacroAssembler: public Assembler {
   void Cmp(Register dst, Handle<Object> source);
   void Cmp(const Operand& dst, Handle<Object> source);
   void Push(Handle<Object> source);
+  void Drop(int stack_elements);
+  void Call(Label* target) { call(target); }
 
   // Control Flow
   void Jump(Address destination, RelocInfo::Mode rmode);
@@ -443,6 +445,8 @@ class MacroAssembler: public Assembler {
   // address must be pushed before calling this helper.
   void PushTryHandler(CodeLocation try_location, HandlerType type);
 
+  // Unlink the stack handler on top of the stack from the try handler chain.
+  void PopTryHandler();
 
   // ---------------------------------------------------------------------------
   // Inline caching support