Debugger: make debug code on-stack replacement more robust.
authoryangguo <yangguo@chromium.org>
Tue, 14 Jul 2015 06:38:42 +0000 (23:38 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Jul 2015 06:38:53 +0000 (06:38 +0000)
The new implemtation counts the number of calls (or continuations)
before the PC to find the corresponding PC in the new code.

R=mstarzinger@chromium.org
BUG=chromium:507070
LOG=N

Review URL: https://codereview.chromium.org/1235603002

Cr-Commit-Position: refs/heads/master@{#29636}

21 files changed:
src/arm/assembler-arm.h
src/arm/full-codegen-arm.cc
src/arm64/assembler-arm64.cc
src/arm64/assembler-arm64.h
src/arm64/full-codegen-arm64.cc
src/assembler.cc
src/assembler.h
src/debug.cc
src/ia32/assembler-ia32.h
src/ia32/full-codegen-ia32.cc
src/mips/assembler-mips.h
src/mips/full-codegen-mips.cc
src/mips64/assembler-mips64.h
src/mips64/full-codegen-mips64.cc
src/ppc/assembler-ppc.h
src/ppc/full-codegen-ppc.cc
src/x64/assembler-x64.h
src/x64/full-codegen-x64.cc
src/x87/assembler-x87.h
src/x87/full-codegen-x87.cc
test/mjsunit/regress/regress-crbug-507070.js [new file with mode: 0644]

index 1d09830c5126d0c3c2a82d30b1ff440b36b917cf..485bcb6fef0cf1f346159b7f48fd3ba3ff8b5d9a 100644 (file)
@@ -1357,6 +1357,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index 476bd05e7395afa602c8b0e5b179ec7b0443b0b8..bd6e4ab9d56267b240abecf510516d03d8fa68e7 100644 (file)
@@ -2172,8 +2172,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2244,9 +2244,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(r0);                                       // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ ldr(r0, MemOperand(sp, generator_object_depth));
index fed0798c04217a47775024f2ae8e95fae969c004..31c8ad9c560616c20666af2f38a402271553d2c6 100644 (file)
@@ -2905,16 +2905,15 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
        (rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_CONSTRUCT_CALL)) ||
       (rmode == RelocInfo::INTERNAL_REFERENCE) ||
       (rmode == RelocInfo::CONST_POOL) || (rmode == RelocInfo::VENEER_POOL) ||
-      (rmode == RelocInfo::DEOPT_REASON)) {
+      (rmode == RelocInfo::DEOPT_REASON) ||
+      (rmode == RelocInfo::GENERATOR_CONTINUATION)) {
     // Adjust code for new modes.
-    DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
-           || RelocInfo::IsJSReturn(rmode)
-           || RelocInfo::IsComment(rmode)
-           || RelocInfo::IsDeoptReason(rmode)
-           || RelocInfo::IsPosition(rmode)
-           || RelocInfo::IsInternalReference(rmode)
-           || RelocInfo::IsConstPool(rmode)
-           || RelocInfo::IsVeneerPool(rmode));
+    DCHECK(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsJSReturn(rmode) ||
+           RelocInfo::IsComment(rmode) || RelocInfo::IsDeoptReason(rmode) ||
+           RelocInfo::IsPosition(rmode) ||
+           RelocInfo::IsInternalReference(rmode) ||
+           RelocInfo::IsConstPool(rmode) || RelocInfo::IsVeneerPool(rmode) ||
+           RelocInfo::IsGeneratorContinuation(rmode));
     // These modes do not need an entry in the constant pool.
   } else {
     constpool_.RecordEntry(data, rmode);
index b13d2199a0b94cbf2d87511784e327f54ba9aaca..cf534bc1c3cfeff6265839b154e313eedf213ee1 100644 (file)
@@ -1025,6 +1025,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index 09e08f3428d0619ceb95fd02b14e996f7a0c4a1d..7dad7d918ffade7bb84f1f84c4e7a6f218516caa 100644 (file)
@@ -5099,11 +5099,11 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ B(&suspend);
-
       // TODO(jbramley): This label is bound here because the following code
       // looks at its pos(). Is it possible to do something more efficient here,
       // perhaps using Adr?
       __ Bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ B(&resume);
 
       __ Bind(&suspend);
@@ -5174,12 +5174,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ Push(x0);                                       // result
-      __ B(&l_suspend);
 
+      __ B(&l_suspend);
       // TODO(jbramley): This label is bound here because the following code
       // looks at its pos(). Is it possible to do something more efficient here,
       // perhaps using Adr?
       __ Bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ B(&l_resume);
 
       __ Bind(&l_suspend);
index 70d35b0f21538b9ad8b589a4af640a733c51d9ff..5a0c0595cb583636061e54a61fb8995ff8f1032c 100644 (file)
@@ -774,7 +774,9 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
     case DEBUG_BREAK_SLOT_AT_CONSTRUCT_CALL:
       return "debug break slot at construct call";
     case CODE_AGE_SEQUENCE:
-      return "code_age_sequence";
+      return "code age sequence";
+    case GENERATOR_CONTINUATION:
+      return "generator continuation";
     case NUMBER_OF_MODES:
     case PC_JUMP:
       UNREACHABLE();
@@ -869,6 +871,7 @@ void RelocInfo::Verify(Isolate* isolate) {
     case DEBUG_BREAK_SLOT_AT_POSITION:
     case DEBUG_BREAK_SLOT_AT_CALL:
     case DEBUG_BREAK_SLOT_AT_CONSTRUCT_CALL:
+    case GENERATOR_CONTINUATION:
     case NONE32:
     case NONE64:
       break;
@@ -1810,6 +1813,12 @@ void Assembler::RecordJSReturn() {
 }
 
 
+void Assembler::RecordGeneratorContinuation() {
+  EnsureSpace ensure_space(this);
+  RecordRelocInfo(RelocInfo::GENERATOR_CONTINUATION);
+}
+
+
 void Assembler::RecordDebugBreakSlot() {
   EnsureSpace ensure_space(this);
   RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
index 1b4c76540757a17de02e341327d7f4dacc812064..4fb3a5654084964f934beba41e673d269f1784a0 100644 (file)
@@ -386,6 +386,9 @@ class RelocInfo {
     // Encoded internal reference, used only on MIPS, MIPS64 and PPC.
     INTERNAL_REFERENCE_ENCODED,
 
+    // Continuation points for a generator yield.
+    GENERATOR_CONTINUATION,
+
     // Marks constant and veneer pools. Only used on ARM and ARM64.
     // They use a custom noncompact encoding.
     CONST_POOL,
@@ -491,6 +494,9 @@ class RelocInfo {
   static inline bool IsCodeAgeSequence(Mode mode) {
     return mode == CODE_AGE_SEQUENCE;
   }
+  static inline bool IsGeneratorContinuation(Mode mode) {
+    return mode == GENERATOR_CONTINUATION;
+  }
   static inline int ModeMask(Mode mode) { return 1 << mode; }
 
   // Accessors
index 1098f608c4c227cc752b36900892191581062a53..c8240e084fe85126357aeed1863a829337536eba 100644 (file)
@@ -1436,56 +1436,58 @@ static void CollectActiveFunctionsFromThread(
 }
 
 
-// Figure out how many bytes of "pc_offset" correspond to actual code by
-// subtracting off the bytes that correspond to constant/veneer pools.  See
-// Assembler::CheckConstPool() and Assembler::CheckVeneerPool(). Note that this
-// is only useful for architectures using constant pools or veneer pools.
-static int ComputeCodeOffsetFromPcOffset(Code *code, int pc_offset) {
+// Count the number of calls before the current frame PC to find the
+// corresponding PC in the newly recompiled code.
+static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
+                                       Address old_pc) {
+  DCHECK_EQ(old_code->kind(), Code::FUNCTION);
+  DCHECK_EQ(new_code->kind(), Code::FUNCTION);
+  DCHECK(!old_code->has_debug_break_slots());
+  DCHECK(new_code->has_debug_break_slots());
+  int mask = RelocInfo::kCodeTargetMask;
+  int index = 0;
+  intptr_t delta = 0;
+  for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
+    RelocInfo* rinfo = it.rinfo();
+    Address current_pc = rinfo->pc();
+    // The frame PC is behind the call instruction by the call instruction size.
+    if (current_pc > old_pc) break;
+    index++;
+    delta = old_pc - current_pc;
+  }
+
+  RelocIterator it(new_code, mask);
+  for (int i = 1; i < index; i++) it.next();
+  return it.rinfo()->pc() + delta;
+}
+
+
+// Count the number of continuations at which the current pc offset is at.
+static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) {
   DCHECK_EQ(code->kind(), Code::FUNCTION);
   DCHECK(!code->has_debug_break_slots());
-  DCHECK_LE(0, pc_offset);
-  DCHECK_LT(pc_offset, code->instruction_end() - code->instruction_start());
-
-  int mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
-             RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
-  byte *pc = code->instruction_start() + pc_offset;
-  int code_offset = pc_offset;
+  Address pc = code->instruction_start() + pc_offset;
+  int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
+  int index = 0;
   for (RelocIterator it(code, mask); !it.done(); it.next()) {
-    RelocInfo* info = it.rinfo();
-    if (info->pc() >= pc) break;
-    DCHECK(RelocInfo::IsConstPool(info->rmode()));
-    code_offset -= static_cast<int>(info->data());
-    DCHECK_LE(0, code_offset);
+    index++;
+    RelocInfo* rinfo = it.rinfo();
+    Address current_pc = rinfo->pc();
+    if (current_pc == pc) break;
+    DCHECK(current_pc < pc);
   }
-
-  return code_offset;
+  return index;
 }
 
 
-// The inverse of ComputeCodeOffsetFromPcOffset.
-static int ComputePcOffsetFromCodeOffset(Code *code, int code_offset) {
+// Find the pc offset for the given continuation index.
+static int ComputePcOffsetFromContinuationIndex(Code* code, int index) {
   DCHECK_EQ(code->kind(), Code::FUNCTION);
-
-  int mask = RelocInfo::kDebugBreakSlotMask |
-             RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
-             RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
-  int reloc = 0;
-  for (RelocIterator it(code, mask); !it.done(); it.next()) {
-    RelocInfo* info = it.rinfo();
-    if (info->pc() - code->instruction_start() - reloc >= code_offset) break;
-    if (RelocInfo::IsDebugBreakSlot(info->rmode())) {
-      reloc += Assembler::kDebugBreakSlotLength;
-    } else {
-      DCHECK(RelocInfo::IsConstPool(info->rmode()));
-      reloc += static_cast<int>(info->data());
-    }
-  }
-
-  int pc_offset = code_offset + reloc;
-
-  DCHECK_LT(code->instruction_start() + pc_offset, code->instruction_end());
-
-  return pc_offset;
+  DCHECK(code->has_debug_break_slots());
+  int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
+  RelocIterator it(code, mask);
+  for (int i = 1; i < index; i++) it.next();
+  return static_cast<int>(it.rinfo()->pc() - code->instruction_start());
 }
 
 
@@ -1510,13 +1512,8 @@ static void RedirectActivationsToRecompiledCodeOnThread(
       continue;
     }
 
-    int old_pc_offset =
-        static_cast<int>(frame->pc() - frame_code->instruction_start());
-    int code_offset = ComputeCodeOffsetFromPcOffset(*frame_code, old_pc_offset);
-    int new_pc_offset = ComputePcOffsetFromCodeOffset(*new_code, code_offset);
-
-    // Compute the equivalent pc in the new code.
-    byte* new_pc = new_code->instruction_start() + new_pc_offset;
+    Address new_pc =
+        ComputeNewPcForRedirect(*new_code, *frame_code, frame->pc());
 
     if (FLAG_trace_deopt) {
       PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
@@ -1603,8 +1600,8 @@ static void RecompileAndRelocateSuspendedGenerators(
 
     EnsureFunctionHasDebugBreakSlots(fun);
 
-    int code_offset = generators[i]->continuation();
-    int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset);
+    int index = generators[i]->continuation();
+    int pc_offset = ComputePcOffsetFromContinuationIndex(fun->code(), index);
     generators[i]->set_continuation(pc_offset);
   }
 }
@@ -1726,11 +1723,11 @@ void Debug::PrepareForBreakPoints() {
           int pc_offset = gen->continuation();
           DCHECK_LT(0, pc_offset);
 
-          int code_offset =
-              ComputeCodeOffsetFromPcOffset(fun->code(), pc_offset);
+          int index =
+              ComputeContinuationIndexFromPcOffset(fun->code(), pc_offset);
 
           // This will be fixed after we recompile the functions.
-          gen->set_continuation(code_offset);
+          gen->set_continuation(index);
 
           suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
         } else if (obj->IsSharedFunctionInfo()) {
index 31a9dfdb14c1bc8d45b4e72b826564df817ac90b..c42cfb68e54763e525e15f3ff5fd9bbc76849945 100644 (file)
@@ -1436,6 +1436,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index 1cd3d445945234b2a9abd6dec48d7b848ee4d04c..3d375fc4b6ce9f9ac660d5fc14eb4f3c3a81ba22 100644 (file)
@@ -2093,8 +2093,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2167,9 +2167,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(eax);                                      // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ mov(eax, Operand(esp, generator_object_depth));
index bc2854a4046e9db59cc305332715227d8e83b09b..06d56004448a84e58976be3e09cec54dcea0951b 100644 (file)
@@ -1061,6 +1061,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index ec362afba465c81b09f16ce8313158cf4b5d417a..8f45b7d5d9c56368237214aa31c6df53806c0095 100644 (file)
@@ -2165,8 +2165,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2237,10 +2237,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(a0);                                       // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ mov(a0, v0);
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ lw(a0, MemOperand(sp, generator_object_depth));
index 5414d5c6a744d3c0fbb9d3a161856309ff108d1e..4ccf0ced0047b83855612172b6e720799b766a4e 100644 (file)
@@ -1103,6 +1103,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index 99777e0845871c696e89a47bb6b3ad7fe3446157..9fad990e8db61b218bd488a06a4f96b97732f4ac 100644 (file)
@@ -2162,8 +2162,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2233,10 +2233,13 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(a0);                                       // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ mov(a0, v0);
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ ld(a0, MemOperand(sp, generator_object_depth));
index 8a3efb313e80b9dac53448f61ec679d9c841bb98..60077182c8afaf5cffc684ab8218e7512280e5a5 100644 (file)
@@ -1298,6 +1298,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index e7b945bc1d27aa1d2aeda912bdb076040a3b5767..97850a190b702ba54d1dc262f07db0a04113db0f 100644 (file)
@@ -2137,8 +2137,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ b(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ b(&resume);
 
       __ bind(&suspend);
@@ -2211,9 +2211,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(r3);  // result
+
       __ b(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ b(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ LoadP(r3, MemOperand(sp, generator_object_depth));
index f5780a40bdbad57c7a93a48aadf7c34dc3365a25..17dcdc73ff7ac3a191ee5019b8606e1f58ffca4a 100644 (file)
@@ -1617,6 +1617,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index 1bcbdfe59999528f1693f2395f0edec2906ea7b4..eb12a4758d805528329126ad00e0c923bbf1bc05 100644 (file)
@@ -2126,8 +2126,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2201,9 +2201,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ Push(rax);                                      // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ movp(rax, Operand(rsp, generator_object_depth));
index 5498b8eaedf0acea222f3cadfdb17d42193f9a08..932dac702ab4b7715704cc1a075292bf39b6d9d4 100644 (file)
@@ -954,6 +954,9 @@ class Assembler : public AssemblerBase {
   // Mark address of the ExitJSFrame code.
   void RecordJSReturn();
 
+  // Mark generator continuation.
+  void RecordGeneratorContinuation();
+
   // Mark address of a debug break slot.
   void RecordDebugBreakSlot();
   void RecordDebugBreakSlotForCall(int argc);
index ffebbe3effad018dc4ed6de19edb4a6ad6a35b6b..6a1565080e30939121fb7c852d94133b001f3e3a 100644 (file)
@@ -2084,8 +2084,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       Label suspend, continuation, post_runtime, resume;
 
       __ jmp(&suspend);
-
       __ bind(&continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&resume);
 
       __ bind(&suspend);
@@ -2158,9 +2158,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       EnterTryBlock(handler_index, &l_catch);
       const int try_block_size = TryCatch::kElementCount * kPointerSize;
       __ push(eax);                                      // result
+
       __ jmp(&l_suspend);
       __ bind(&l_continuation);
+      __ RecordGeneratorContinuation();
       __ jmp(&l_resume);
+
       __ bind(&l_suspend);
       const int generator_object_depth = kPointerSize + try_block_size;
       __ mov(eax, Operand(esp, generator_object_depth));
diff --git a/test/mjsunit/regress/regress-crbug-507070.js b/test/mjsunit/regress/regress-crbug-507070.js
new file mode 100644 (file)
index 0000000..e368fa5
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --cache=code
+
+try { } catch(e) { }
+try { try { } catch (e) { } } catch(e) { }
+try {
+  var Debug = %GetDebugContext().Debug;
+  Debug.setListener(function(){});
+} catch(e) { }
+(function() {
+  Debug.setBreakPoint(function(){}, 0, 0);
+})();
+
+var a = 1;
+a += a;
+Debug.setListener(null);
+assertEquals(2, a);