Refactor interrupt check patching for OSR.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Aug 2013 13:06:04 +0000 (13:06 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Aug 2013 13:06:04 +0000 (13:06 +0000)
This is to prepare for speculative concurrent OSR. I'm planning to add
another builtin to patch to, to indicate a concurrent OSR.

R=titzer@chromium.org
BUG=

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

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

src/arm/deoptimizer-arm.cc
src/compiler.cc
src/deoptimizer.cc
src/deoptimizer.h
src/ia32/deoptimizer-ia32.cc
src/mips/deoptimizer-mips.cc
src/runtime-profiler.cc
src/runtime.cc
src/x64/deoptimizer-x64.cc

index 5b42116..b2b19ce 100644 (file)
@@ -101,12 +101,7 @@ static const int32_t kBranchBeforeInterrupt =  0x5a000004;
 
 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
                                        Address pc_after,
-                                       Code* interrupt_code,
                                        Code* replacement_code) {
-  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
-                                 pc_after,
-                                 interrupt_code,
-                                 replacement_code));
   static const int kInstrSize = Assembler::kInstrSize;
   // Turn the jump into nops.
   CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
@@ -125,12 +120,7 @@ void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
 
 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* interrupt_code,
-                                        Code* replacement_code) {
-  ASSERT(InterruptCodeIsPatched(unoptimized_code,
-                                pc_after,
-                                interrupt_code,
-                                replacement_code));
+                                        Code* interrupt_code) {
   static const int kInstrSize = Assembler::kInstrSize;
   // Restore the original jump.
   CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
@@ -150,10 +140,10 @@ void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
 
 
 #ifdef DEBUG
-bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* interrupt_code,
-                                         Code* replacement_code) {
+Deoptimizer::InterruptPatchState Deoptimizer::GetInterruptPatchState(
+    Isolate* isolate,
+    Code* unoptimized_code,
+    Address pc_after) {
   static const int kInstrSize = Assembler::kInstrSize;
   ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
 
@@ -164,17 +154,23 @@ bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
   if (Assembler::IsNop(Assembler::instr_at(pc_after - 3 * kInstrSize))) {
     ASSERT(Assembler::IsLdrPcImmediateOffset(
         Assembler::instr_at(pc_after - 2 * kInstrSize)));
-    ASSERT(reinterpret_cast<uint32_t>(replacement_code->entry()) ==
+    Code* osr_builtin =
+        isolate->builtins()->builtin(Builtins::kOnStackReplacement);
+    ASSERT(reinterpret_cast<uint32_t>(osr_builtin->entry()) ==
            Memory::uint32_at(interrupt_address_pointer));
-    return true;
+    return PATCHED_FOR_OSR;
   } else {
+    // Get the interrupt stub code object to match against from cache.
+    Code* interrupt_code = NULL;
+    InterruptStub stub;
+    if (!stub.FindCodeInCache(&interrupt_code, isolate)) UNREACHABLE();
     ASSERT(Assembler::IsLdrPcImmediateOffset(
         Assembler::instr_at(pc_after - 2 * kInstrSize)));
     ASSERT_EQ(kBranchBeforeInterrupt,
               Memory::int32_at(pc_after - 3 * kInstrSize));
     ASSERT(reinterpret_cast<uint32_t>(interrupt_code->entry()) ==
            Memory::uint32_at(interrupt_address_pointer));
-    return false;
+    return NOT_PATCHED;
   }
 }
 #endif  // DEBUG
index 93898b1..1fba20f 100644 (file)
@@ -1024,13 +1024,7 @@ void Compiler::RecompileConcurrent(Handle<JSFunction> closure) {
     // aborted optimization.  In either case we want to continue executing
     // the unoptimized code without running into OSR.  If the unoptimized
     // code has been patched for OSR, unpatch it.
-    InterruptStub interrupt_stub;
-    Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
-    Handle<Code> replacement_code =
-        isolate->builtins()->OnStackReplacement();
-    Deoptimizer::RevertInterruptCode(shared->code(),
-                                     *interrupt_code,
-                                     *replacement_code);
+    Deoptimizer::RevertInterruptCode(isolate, shared->code());
   }
 
   if (isolate->has_pending_exception()) isolate->clear_pending_exception();
index f797565..a553ec1 100644 (file)
@@ -2578,9 +2578,17 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
 }
 
 
-void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
-                                     Code* interrupt_code,
-                                     Code* replacement_code) {
+void Deoptimizer::PatchInterruptCode(Isolate* isolate,
+                                     Code* unoptimized_code) {
+  DisallowHeapAllocation no_gc;
+  // Get the interrupt stub code object to match against.  We aren't
+  // prepared to generate it, but we don't expect to have to.
+  Code* interrupt_code = NULL;
+  InterruptStub interrupt_stub;
+  CHECK(interrupt_stub.FindCodeInCache(&interrupt_code, isolate));
+  Code* replacement_code =
+      isolate->builtins()->builtin(Builtins::kOnStackReplacement);
+
   // Iterate over the back edge table and patch every interrupt
   // call to an unconditional call to the replacement code.
   int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
@@ -2589,9 +2597,11 @@ void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
        !back_edges.Done();
        back_edges.Next()) {
     if (static_cast<int>(back_edges.loop_depth()) == loop_nesting_level) {
+      ASSERT_EQ(NOT_PATCHED, GetInterruptPatchState(isolate,
+                                                    unoptimized_code,
+                                                    back_edges.pc()));
       PatchInterruptCodeAt(unoptimized_code,
                            back_edges.pc(),
-                           interrupt_code,
                            replacement_code);
     }
   }
@@ -2599,14 +2609,17 @@ void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
   unoptimized_code->set_back_edges_patched_for_osr(true);
 #ifdef DEBUG
   Deoptimizer::VerifyInterruptCode(
-      unoptimized_code, interrupt_code, replacement_code, loop_nesting_level);
+      isolate, unoptimized_code, loop_nesting_level);
 #endif  // DEBUG
 }
 
 
-void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
-                                      Code* interrupt_code,
-                                      Code* replacement_code) {
+void Deoptimizer::RevertInterruptCode(Isolate* isolate,
+                                      Code* unoptimized_code) {
+  InterruptStub interrupt_stub;
+  Code* interrupt_code = *interrupt_stub.GetCode(isolate);
+  DisallowHeapAllocation no_gc;
+
   // Iterate over the back edge table and revert the patched interrupt calls.
   ASSERT(unoptimized_code->back_edges_patched_for_osr());
   int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
@@ -2615,10 +2628,10 @@ void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
        !back_edges.Done();
        back_edges.Next()) {
     if (static_cast<int>(back_edges.loop_depth()) <= loop_nesting_level) {
-      RevertInterruptCodeAt(unoptimized_code,
-                            back_edges.pc(),
-                            interrupt_code,
-                            replacement_code);
+      ASSERT_EQ(PATCHED_FOR_OSR, GetInterruptPatchState(isolate,
+                                                        unoptimized_code,
+                                                        back_edges.pc()));
+      RevertInterruptCodeAt(unoptimized_code, back_edges.pc(), interrupt_code);
     }
   }
 
@@ -2626,16 +2639,14 @@ void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
   unoptimized_code->set_allow_osr_at_loop_nesting_level(0);
 #ifdef DEBUG
   // Assert that none of the back edges are patched anymore.
-  Deoptimizer::VerifyInterruptCode(
-      unoptimized_code, interrupt_code, replacement_code, -1);
+  Deoptimizer::VerifyInterruptCode(isolate, unoptimized_code, -1);
 #endif  // DEBUG
 }
 
 
 #ifdef DEBUG
-void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
-                                      Code* interrupt_code,
-                                      Code* replacement_code,
+void Deoptimizer::VerifyInterruptCode(Isolate* isolate,
+                                      Code* unoptimized_code,
                                       int loop_nesting_level) {
   for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code);
        !back_edges.Done();
@@ -2645,10 +2656,9 @@ void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
     // Assert that all back edges for shallower loops (and only those)
     // have already been patched.
     CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level),
-             InterruptCodeIsPatched(unoptimized_code,
-                                    back_edges.pc(),
-                                    interrupt_code,
-                                    replacement_code));
+             GetInterruptPatchState(isolate,
+                                    unoptimized_code,
+                                    back_edges.pc()) != NOT_PATCHED);
   }
 }
 #endif  // DEBUG
index e5afd1a..0d62bd0 100644 (file)
@@ -144,6 +144,11 @@ class Deoptimizer : public Malloced {
     DEBUGGER
   };
 
+  enum InterruptPatchState {
+    NOT_PATCHED,
+    PATCHED_FOR_OSR
+  };
+
   static const int kBailoutTypesWithCodeEntry = SOFT + 1;
 
   struct JumpTableEntry {
@@ -231,40 +236,34 @@ class Deoptimizer : public Malloced {
 
   // Patch all interrupts with allowed loop depth in the unoptimized code to
   // unconditionally call replacement_code.
-  static void PatchInterruptCode(Code* unoptimized_code,
-                                 Code* interrupt_code,
-                                 Code* replacement_code);
+  static void PatchInterruptCode(Isolate* isolate,
+                                 Code* unoptimized_code);
 
   // Patch the interrupt at the instruction before pc_after in
   // the unoptimized code to unconditionally call replacement_code.
   static void PatchInterruptCodeAt(Code* unoptimized_code,
                                    Address pc_after,
-                                   Code* interrupt_code,
                                    Code* replacement_code);
 
   // Change all patched interrupts patched in the unoptimized code
   // back to normal interrupts.
-  static void RevertInterruptCode(Code* unoptimized_code,
-                                  Code* interrupt_code,
-                                  Code* replacement_code);
+  static void RevertInterruptCode(Isolate* isolate,
+                                  Code* unoptimized_code);
 
   // Change patched interrupt in the unoptimized code
   // back to a normal interrupt.
   static void RevertInterruptCodeAt(Code* unoptimized_code,
                                     Address pc_after,
-                                    Code* interrupt_code,
-                                    Code* replacement_code);
+                                    Code* interrupt_code);
 
 #ifdef DEBUG
-  static bool InterruptCodeIsPatched(Code* unoptimized_code,
-                                     Address pc_after,
-                                     Code* interrupt_code,
-                                     Code* replacement_code);
+  static InterruptPatchState GetInterruptPatchState(Isolate* isolate,
+                                                    Code* unoptimized_code,
+                                                    Address pc_after);
 
   // Verify that all back edges of a certain loop depth are patched.
-  static void VerifyInterruptCode(Code* unoptimized_code,
-                                  Code* interrupt_code,
-                                  Code* replacement_code,
+  static void VerifyInterruptCode(Isolate* isolate,
+                                  Code* unoptimized_code,
                                   int loop_nesting_level);
 #endif  // DEBUG
 
index a9bd8c5..f84b813 100644 (file)
@@ -200,12 +200,7 @@ static const byte kNopByteTwo = 0x90;
 
 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
                                        Address pc_after,
-                                       Code* interrupt_code,
                                        Code* replacement_code) {
-  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
-                                 pc_after,
-                                 interrupt_code,
-                                 replacement_code));
   // Turn the jump into nops.
   Address call_target_address = pc_after - kIntSize;
   *(call_target_address - 3) = kNopByteOne;
@@ -221,12 +216,7 @@ void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
 
 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* interrupt_code,
-                                        Code* replacement_code) {
-  ASSERT(InterruptCodeIsPatched(unoptimized_code,
-                                pc_after,
-                                interrupt_code,
-                                replacement_code));
+                                        Code* interrupt_code) {
   // Restore the original jump.
   Address call_target_address = pc_after - kIntSize;
   *(call_target_address - 3) = kJnsInstruction;
@@ -241,23 +231,29 @@ void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
 
 
 #ifdef DEBUG
-bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* interrupt_code,
-                                         Code* replacement_code) {
+Deoptimizer::InterruptPatchState Deoptimizer::GetInterruptPatchState(
+    Isolate* isolate,
+    Code* unoptimized_code,
+    Address pc_after) {
   Address call_target_address = pc_after - kIntSize;
   ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
   if (*(call_target_address - 3) == kNopByteOne) {
-    ASSERT_EQ(replacement_code->entry(),
-             Assembler::target_address_at(call_target_address));
     ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
-    return true;
+    Code* osr_builtin =
+        isolate->builtins()->builtin(Builtins::kOnStackReplacement);
+    ASSERT_EQ(osr_builtin->entry(),
+              Assembler::target_address_at(call_target_address));
+    return PATCHED_FOR_OSR;
   } else {
+    // Get the interrupt stub code object to match against from cache.
+    Code* interrupt_code = NULL;
+    InterruptStub stub;
+    if (!stub.FindCodeInCache(&interrupt_code, isolate)) UNREACHABLE();
     ASSERT_EQ(interrupt_code->entry(),
               Assembler::target_address_at(call_target_address));
     ASSERT_EQ(kJnsInstruction,  *(call_target_address - 3));
     ASSERT_EQ(kJnsOffset,       *(call_target_address - 2));
-    return false;
+    return NOT_PATCHED;
   }
 }
 #endif  // DEBUG
index 57d3880..31d31a0 100644 (file)
@@ -101,12 +101,7 @@ void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
 
 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* interrupt_code,
                                         Code* replacement_code) {
-  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
-                                 pc_after,
-                                 interrupt_code,
-                                 replacement_code));
   static const int kInstrSize = Assembler::kInstrSize;
   // Replace the sltu instruction with load-imm 1 to at, so beq is not taken.
   CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
@@ -123,12 +118,7 @@ void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
 
 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* interrupt_code,
-                                        Code* replacement_code) {
-  ASSERT(InterruptCodeIsPatched(unoptimized_code,
-                                 pc_after,
-                                 interrupt_code,
-                                 replacement_code));
+                                        Code* interrupt_code) {
   static const int kInstrSize = Assembler::kInstrSize;
   // Restore the sltu instruction so beq can be taken again.
   CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
@@ -143,23 +133,29 @@ void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
 
 
 #ifdef DEBUG
-bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* interrupt_code,
-                                         Code* replacement_code) {
+Deoptimizer::InterruptPatchState Deoptimizer::GetInterruptPatchState(
+    Isolate* isolate,
+    Code* unoptimized_code,
+    Address pc_after) {
   static const int kInstrSize = Assembler::kInstrSize;
   ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
   if (Assembler::IsAddImmediate(
       Assembler::instr_at(pc_after - 6 * kInstrSize))) {
+    Code* osr_builtin =
+        isolate->builtins()->builtin(Builtins::kOnStackReplacement);
     ASSERT(reinterpret_cast<uint32_t>(
         Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
-        reinterpret_cast<uint32_t>(replacement_code->entry()));
-    return true;
+        reinterpret_cast<uint32_t>(osr_builtin->entry()));
+    return PATCHED_FOR_OSR;
   } else {
+    // Get the interrupt stub code object to match against from cache.
+    Code* interrupt_code = NULL;
+    InterruptStub stub;
+    if (!stub.FindCodeInCache(&interrupt_code, isolate)) UNREACHABLE();
     ASSERT(reinterpret_cast<uint32_t>(
         Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
         reinterpret_cast<uint32_t>(interrupt_code->entry()));
-    return false;
+    return NOT_PATCHED;
   }
 }
 #endif  // DEBUG
index 3752b27..57c50dd 100644 (file)
@@ -177,18 +177,7 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
     PrintF(" for on-stack replacement]\n");
   }
 
-  // Get the interrupt stub code object to match against.  We aren't
-  // prepared to generate it, but we don't expect to have to.
-  Code* interrupt_code = NULL;
-  InterruptStub interrupt_stub;
-  bool found_code = interrupt_stub.FindCodeInCache(&interrupt_code, isolate_);
-  if (found_code) {
-    Code* replacement_code =
-        isolate_->builtins()->builtin(Builtins::kOnStackReplacement);
-    Code* unoptimized_code = shared->code();
-    Deoptimizer::PatchInterruptCode(
-        unoptimized_code, interrupt_code, replacement_code);
-  }
+  Deoptimizer::PatchInterruptCode(isolate_, shared->code());
 }
 
 
index 71d792a..5760982 100644 (file)
@@ -8662,12 +8662,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
     function->PrintName();
     PrintF("]\n");
   }
-  InterruptStub interrupt_stub;
-  Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
-  Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
-  Deoptimizer::RevertInterruptCode(*unoptimized,
-                                   *interrupt_code,
-                                   *replacement_code);
+  Deoptimizer::RevertInterruptCode(isolate, *unoptimized);
 
   // If the optimization attempt succeeded, return the AST id tagged as a
   // smi. This tells the builtin that we need to translate the unoptimized
index e9cf567..33d4f4d 100644 (file)
@@ -105,12 +105,7 @@ static const byte kNopByteTwo = 0x90;
 
 void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
                                        Address pc_after,
-                                       Code* interrupt_code,
                                        Code* replacement_code) {
-  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
-                                 pc_after,
-                                 interrupt_code,
-                                 replacement_code));
   // Turn the jump into nops.
   Address call_target_address = pc_after - kIntSize;
   *(call_target_address - 3) = kNopByteOne;
@@ -126,12 +121,7 @@ void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
 
 void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* interrupt_code,
-                                        Code* replacement_code) {
-  ASSERT(InterruptCodeIsPatched(unoptimized_code,
-                                pc_after,
-                                interrupt_code,
-                                replacement_code));
+                                        Code* interrupt_code) {
   // Restore the original jump.
   Address call_target_address = pc_after - kIntSize;
   *(call_target_address - 3) = kJnsInstruction;
@@ -146,23 +136,29 @@ void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
 
 
 #ifdef DEBUG
-bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* interrupt_code,
-                                         Code* replacement_code) {
+Deoptimizer::InterruptPatchState Deoptimizer::GetInterruptPatchState(
+    Isolate* isolate,
+    Code* unoptimized_code,
+    Address pc_after) {
   Address call_target_address = pc_after - kIntSize;
   ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
   if (*(call_target_address - 3) == kNopByteOne) {
-    ASSERT(replacement_code->entry() ==
-           Assembler::target_address_at(call_target_address));
     ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
-    return true;
+    Code* osr_builtin =
+        isolate->builtins()->builtin(Builtins::kOnStackReplacement);
+    ASSERT_EQ(osr_builtin->entry(),
+              Assembler::target_address_at(call_target_address));
+    return PATCHED_FOR_OSR;
   } else {
+    // Get the interrupt stub code object to match against from cache.
+    Code* interrupt_code = NULL;
+    InterruptStub stub;
+    if (!stub.FindCodeInCache(&interrupt_code, isolate)) UNREACHABLE();
     ASSERT_EQ(interrupt_code->entry(),
               Assembler::target_address_at(call_target_address));
     ASSERT_EQ(kJnsInstruction,  *(call_target_address - 3));
     ASSERT_EQ(kJnsOffset,       *(call_target_address - 2));
-    return false;
+    return NOT_PATCHED;
   }
 }
 #endif  // DEBUG