Begin using a list of bailouts instead of a singleton in the fast code generator.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 19 Feb 2010 14:52:39 +0000 (14:52 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 19 Feb 2010 14:52:39 +0000 (14:52 +0000)
A list of bailout descriptions is kept in the CompilationInfo
structure that is shared between the primary and secondary code
generators.  The primary adds a description to the list for each
bailout position.

Responsibility for binding labels is moved from the primary to the
secondary code generator. All the labels still target the start of the
secondary code and the compilation state of the primary is still
ignored.

Move the compilation mode flag to the CompilationInfo.

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

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

14 files changed:
src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/arm/fast-codegen-arm.cc
src/codegen.cc
src/compiler.h
src/fast-codegen.cc
src/fast-codegen.h
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/ia32/fast-codegen-ia32.cc
src/ia32/fast-codegen-ia32.h
src/x64/codegen-x64.cc
src/x64/codegen-x64.h
src/x64/fast-codegen-x64.cc

index c8c56ff6ab4bf5b09fa764555c2cdba827adf4ff..95c50f262f0da4318287d2057ac301c24aef25fb 100644 (file)
@@ -142,7 +142,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
 // r1: called JS function
 // cp: callee's context
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -174,7 +174,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
     }
 #endif
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
       // tos: code slot
 
@@ -277,6 +277,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
       frame_->Adjust(4);
       allocator_->Unuse(r1);
       allocator_->Unuse(lr);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
index de098d0234aeebd7ea5b843f1c7fc3cd2fa309c4..1a2e5525a2ae49cd5203946303a4cd73cfeabd83 100644 (file)
@@ -150,15 +150,6 @@ class CodeGenState BASE_EMBEDDED {
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -244,7 +235,7 @@ class CodeGenerator: public AstVisitor {
   inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // The following are used by class Reference.
   void LoadReference(Reference* ref);
index a07b0d2dcbe0b7fc6244f3604e36313695c39a6b..aa7128fcaec71a198d71316cd69858d6ff541b6c 100644 (file)
@@ -148,17 +148,25 @@ void FastCodeGenerator::EmitBitOr() {
     if (!destination().is(no_reg)) {
       __ orr(destination(), accumulator1(), Operand(accumulator0()));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
-    __ BranchOnNotSmi(scratch0(), bailout());
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ mov(scratch0(), destination());
-    __ orr(destination(), accumulator1(), Operand(accumulator0()));
-    __ BranchOnNotSmi(destination(), bailout());
+    // Left is in accumulator1, right in accumulator0.
+    if (destination().is(accumulator0())) {
+      __ mov(scratch0(), accumulator0());
+      __ orr(destination(), accumulator1(), Operand(accumulator1()));
+      Label* bailout =
+          info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+      __ BranchOnNotSmi(destination(), bailout);
+    } else if (destination().is(accumulator1())) {
+      __ mov(scratch0(), accumulator1());
+      __ orr(destination(), accumulator1(), Operand(accumulator0()));
+      Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+      __ BranchOnNotSmi(destination(), bailout);
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ orr(scratch0(), accumulator1(), Operand(accumulator0()));
+      Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+      __ BranchOnNotSmi(scratch0(), bailout);
+    }
   }
 
   // If we didn't bailout, the result (in fact, both inputs too) is known to
@@ -179,6 +187,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to cp (context) at
   // this point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -189,7 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -202,7 +211,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ ldr(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), scratch1(), map, bailout(), true);
+    __ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(function()->body());
@@ -217,8 +226,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
   __ add(sp, sp, Operand(sp_delta));
   __ Jump(lr);
-
-  __ bind(&bailout_);
 }
 
 
index 7f121688c1086f65e061b757543cf36bbad9f70f..dbd1100d9e6befd07d56e6411479337fb9b45a37 100644 (file)
@@ -248,7 +248,7 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
   CodeGenerator cgen(&masm);
   CodeGeneratorScope scope(&cgen);
   live_edit_tracker.RecordFunctionScope(info->function()->scope());
-  cgen.Generate(info, PRIMARY);
+  cgen.Generate(info);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
index 6ee2246b298d5ed60227348cbba461fee52897a0..f01889d0a13856dfa7a35d445ded0f7158c855a3 100644 (file)
@@ -41,6 +41,37 @@ namespace internal {
 // is constructed based on the resources available at compile-time.
 class CompilationInfo BASE_EMBEDDED {
  public:
+  // Compilation mode.  Either the compiler is used as the primary
+  // compiler and needs to setup everything or the compiler is used as
+  // the secondary compiler for split compilation and has to handle
+  // bailouts.
+  enum Mode {
+    PRIMARY,
+    SECONDARY
+  };
+
+  // A description of the compilation state at a bailout to the secondary
+  // code generator.
+  //
+  // The state is currently simple: there are no parameters or local
+  // variables to worry about ('this' can be found in the stack frame).
+  // There are at most two live values.
+  //
+  // There is a label that should be bound to the beginning of the bailout
+  // stub code.
+  class Bailout : public ZoneObject {
+   public:
+    Bailout(Register left, Register right) : left_(left), right_(right) {}
+
+    Label* label() { return &label_; }
+
+   private:
+    Register left_;
+    Register right_;
+    Label label_;
+  };
+
+
   // Lazy compilation of a JSFunction.
   CompilationInfo(Handle<JSFunction> closure,
                   int loop_nesting,
@@ -117,9 +148,13 @@ class CompilationInfo BASE_EMBEDDED {
   int loop_nesting() { return loop_nesting_; }
   bool has_receiver() { return !receiver_.is_null(); }
   Handle<Object> receiver() { return receiver_; }
+  List<Bailout*>* bailouts() { return &bailouts_; }
 
-  // Accessors for mutable fields, possibly set by analysis passes with
+  // Accessors for mutable fields (possibly set by analysis passes) with
   // default values given by Initialize.
+  Mode mode() { return mode_; }
+  void set_mode(Mode mode) { mode_ = mode; }
+
   bool has_this_properties() { return has_this_properties_; }
   void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
 
@@ -137,8 +172,19 @@ class CompilationInfo BASE_EMBEDDED {
   // Derived accessors.
   Scope* scope() { return function()->scope(); }
 
+  // Add a bailout with two live values.
+  Label* AddBailout(Register left, Register right) {
+    Bailout* bailout = new Bailout(left, right);
+    bailouts_.Add(bailout);
+    return bailout->label();
+  }
+
+  // Add a bailout with no live values.
+  Label* AddBailout() { return AddBailout(no_reg, no_reg); }
+
  private:
   void Initialize() {
+    mode_ = PRIMARY;
     has_this_properties_ = false;
     has_globals_ = false;
   }
@@ -148,6 +194,7 @@ class CompilationInfo BASE_EMBEDDED {
   Handle<Script> script_;
 
   FunctionLiteral* function_;
+  Mode mode_;
 
   bool is_eval_;
   int loop_nesting_;
@@ -157,6 +204,10 @@ class CompilationInfo BASE_EMBEDDED {
   bool has_this_properties_;
   bool has_globals_;
 
+  // An ordered list of bailout points encountered during fast-path
+  // compilation.
+  List<Bailout*> bailouts_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
 };
 
index ecd26527cb489d9c6bf7018d3d78585cbd411ee6..602d6b88ce9e0861072226eb388bcb7c5dcf68fe 100644 (file)
@@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
   // macro assembler.
   CodeGenerator cgen(&masm);
   CodeGeneratorScope scope(&cgen);
-  cgen.Generate(info, CodeGenerator::SECONDARY);
+  info->set_mode(CompilationInfo::SECONDARY);
+  cgen.Generate(info);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
index f39da21ad7da6e2f9a292e033d4dab841b4198ab..e96daf65b5ffcf66f8775e1656494244fa60676d 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "ast.h"
 #include "compiler.h"
+#include "list.h"
 
 namespace v8 {
 namespace internal {
@@ -80,7 +81,6 @@ class FastCodeGenerator: public AstVisitor {
  private:
   MacroAssembler* masm() { return masm_; }
   CompilationInfo* info() { return info_; }
-  Label* bailout() { return &bailout_; }
 
   Register destination() { return destination_; }
   void set_destination(Register reg) { destination_ = reg; }
@@ -146,7 +146,6 @@ class FastCodeGenerator: public AstVisitor {
 
   MacroAssembler* masm_;
   CompilationInfo* info_;
-  Label bailout_;
   Register destination_;
   uint32_t smi_bits_;
 
index f0ad26defed06940678cfde33cfd09a2692390bb..1882ac59e1fc06c31ac05e86a26a7c003746ee33 100644 (file)
@@ -125,7 +125,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
 // edi: called JS function
 // esi: callee's context
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -164,7 +164,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
     // esi: callee's context
     allocator_->Initialize();
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
 
       // Allocate space for locals and initialize them.
@@ -255,6 +255,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
       // frame to match this state.
       frame_->Adjust(3);
       allocator_->Unuse(edi);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
index 561e1523efb530d407b15605eeea1de521405289..cd7a7bbb26bc5f02a8dbbf75774a660060849d18 100644 (file)
@@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -384,7 +375,7 @@ class CodeGenerator: public AstVisitor {
   void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // Generate the return sequence code.  Should be called no more than
   // once per compiled function, immediately after binding the return
index c24091b1945f3e9d14ca53f7e059d08c28cb646a..f1c2507712934cc53b985a4407ab19dda0dd58c0 100644 (file)
@@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
   // macro assembler.
   CodeGenerator cgen(&masm);
   CodeGeneratorScope scope(&cgen);
-  cgen.Generate(info, CodeGenerator::SECONDARY);
+  info->set_mode(CompilationInfo::SECONDARY);
+  cgen.Generate(info);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
     return Handle<Code>::null();
@@ -587,20 +588,27 @@ void FastCodeGenerator::EmitBitOr() {
       // commutative.
       __ or_(destination(), Operand(other_accumulator(destination())));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ mov(scratch0(), accumulator1());
-    __ or_(scratch0(), Operand(accumulator0()));
-    __ test(scratch0(), Immediate(kSmiTagMask));
-    __ j(not_zero, bailout(), not_taken);
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ mov(scratch0(), destination());
-    __ or_(destination(), Operand(other_accumulator(destination())));
-    __ test(destination(), Immediate(kSmiTagMask));
-    __ j(not_zero, bailout(), not_taken);
+    // Left is in accumulator1, right in accumulator0.
+    Label* bailout = NULL;
+    if (destination().is(accumulator0())) {
+      __ mov(scratch0(), accumulator0());
+      __ or_(destination(), Operand(accumulator1()));  // Or is commutative.
+      __ test(destination(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+    } else if (destination().is(accumulator1())) {
+      __ mov(scratch0(), accumulator1());
+      __ or_(destination(), Operand(accumulator0()));
+      __ test(destination(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(scratch0(), accumulator0());
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ mov(scratch0(), accumulator1());
+      __ or_(scratch0(), Operand(accumulator0()));
+      __ test(scratch0(), Immediate(kSmiTagMask));
+      bailout = info()->AddBailout(accumulator1(), accumulator0());
+    }
+    __ j(not_zero, bailout, not_taken);
   }
 
   // If we didn't bailout, the result (in fact, both inputs too) is known to
@@ -623,6 +631,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -633,7 +642,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -646,7 +655,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ mov(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), map, bailout(), true);
+    __ CheckMap(scratch0(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(function()->body());
@@ -659,8 +668,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   __ mov(esp, ebp);
   __ pop(ebp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);
-
-  __ bind(&bailout_);
 }
 
 
index a070c51fd13868470df91c85ee0d30c9e46b61e8..e0851afe06549f3d32f55f54ad6b9604f508daad 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "ast.h"
 #include "compiler.h"
+#include "list.h"
 
 namespace v8 {
 namespace internal {
@@ -76,7 +77,6 @@ class FastCodeGenerator: public AstVisitor {
  private:
   MacroAssembler* masm() { return masm_; }
   CompilationInfo* info() { return info_; }
-  Label* bailout() { return &bailout_; }
 
   Register destination() { return destination_; }
   void set_destination(Register reg) { destination_ = reg; }
@@ -142,7 +142,7 @@ class FastCodeGenerator: public AstVisitor {
 
   MacroAssembler* masm_;
   CompilationInfo* info_;
-  Label bailout_;
+
   Register destination_;
   uint32_t smi_bits_;
 
index fa2cb8dfa00a202146bd895490429e43f9a8f2fa..28a522f344d0182ebdf0be05d80951ea4c683c73 100644 (file)
@@ -277,7 +277,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
 }
 
 
-void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+void CodeGenerator::Generate(CompilationInfo* info) {
   // Record the position for debugging purposes.
   CodeForFunctionPosition(info->function());
 
@@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
     // rsi: callee's context
     allocator_->Initialize();
 
-    if (mode == PRIMARY) {
+    if (info->mode() == CompilationInfo::PRIMARY) {
       frame_->Enter();
 
       // Allocate space for locals and initialize them.
@@ -407,6 +407,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
       // frame to match this state.
       frame_->Adjust(3);
       allocator_->Unuse(rdi);
+
+      // Bind all the bailout labels to the beginning of the function.
+      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
+      for (int i = 0; i < bailouts->length(); i++) {
+        __ bind(bailouts->at(i)->label());
+      }
     }
 
     // Initialize the function return target after the locals are set
index b9a2c9994bea4b08fca4953dd49fca8d012bd764..4593a28393e4f12771f2c8dd46efbdce0375d3d3 100644 (file)
@@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
 
 class CodeGenerator: public AstVisitor {
  public:
-  // Compilation mode.  Either the compiler is used as the primary
-  // compiler and needs to setup everything or the compiler is used as
-  // the secondary compiler for split compilation and has to handle
-  // bailouts.
-  enum Mode {
-    PRIMARY,
-    SECONDARY
-  };
-
   // Takes a function literal, generates code for it. This function should only
   // be called by compiler.cc.
   static Handle<Code> MakeCode(CompilationInfo* info);
@@ -385,7 +376,7 @@ class CodeGenerator: public AstVisitor {
   void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
 
   // Main code generation function
-  void Generate(CompilationInfo* info, Mode mode);
+  void Generate(CompilationInfo* info);
 
   // Generate the return sequence code.  Should be called no more than
   // once per compiled function, immediately after binding the return
index 1af7685544991170055d9fd1c5146283930d7b70..4dbf26a424c932d11cc5f03384b9a6a626d2b2a9 100644 (file)
@@ -156,21 +156,28 @@ void FastCodeGenerator::EmitBitOr() {
       // commutative.
       __ or_(destination(), other_accumulator(destination()));
     }
-  } else if (destination().is(no_reg)) {
-    // Result is not needed but do not clobber the operands in case of
-    // bailout.
-    __ movq(scratch0(), accumulator1());
-    __ or_(scratch0(), accumulator0());
-    __ JumpIfNotSmi(scratch0(), bailout());
   } else {
-    // Preserve the destination operand in a scratch register in case of
-    // bailout.
-    __ movq(scratch0(), destination());
-    __ or_(destination(), other_accumulator(destination()));
-    __ JumpIfNotSmi(destination(), bailout());
+    // Left is in accumulator1, right in accumulator0.
+    if (destination().is(accumulator0())) {
+      __ movq(scratch0(), accumulator0());
+      __ or_(destination(), accumulator1());  // Or is commutative.
+      Label* bailout =
+          info()->AddBailout(accumulator1(), scratch0());  // Left, right.
+      __ JumpIfNotSmi(destination(), bailout);
+    } else if (destination().is(accumulator1())) {
+      __ movq(scratch0(), accumulator1());
+      __ or_(destination(), accumulator0());
+      Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+      __ JumpIfNotSmi(destination(), bailout);
+    } else {
+      ASSERT(destination().is(no_reg));
+      __ movq(scratch0(), accumulator1());
+      __ or_(scratch0(), accumulator0());
+      Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
+      __ JumpIfNotSmi(scratch0(), bailout);
+    }
   }
 
-
   // If we didn't bailout, the result (in fact, both inputs too) is known to
   // be a smi.
   set_as_smi(accumulator0());
@@ -191,6 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   // Note that we keep a live register reference to esi (context) at this
   // point.
 
+  Label* bailout_to_beginning = info()->AddBailout();
   // Receiver (this) is allocated to a fixed register.
   if (info()->has_this_properties()) {
     Comment cmnt(masm(), ";; MapCheck(this)");
@@ -201,7 +209,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
     Handle<Map> map(object->map());
     EmitLoadReceiver();
-    __ CheckMap(receiver_reg(), map, bailout(), false);
+    __ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
   }
 
   // If there is a global variable access check if the global object is the
@@ -214,7 +222,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
     ASSERT(info()->has_global_object());
     Handle<Map> map(info()->global_object()->map());
     __ movq(scratch0(), CodeGenerator::GlobalObject());
-    __ CheckMap(scratch0(), map, bailout(), true);
+    __ CheckMap(scratch0(), map, bailout_to_beginning, true);
   }
 
   VisitStatements(info()->function()->body());
@@ -227,8 +235,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
   __ movq(rsp, rbp);
   __ pop(rbp);
   __ ret((scope()->num_parameters() + 1) * kPointerSize);
-
-  __ bind(&bailout_);
 }