Bug 1541404 part 30 - Fix some debugger issues. r=tcampbell
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 15 May 2019 14:24:26 +0000
changeset 532767 6c6307b33331b070584d259ddefdc5439d56d759
parent 532766 2cd499a2a7d92aa352bd6e51c58e3c74535fbab5
child 532768 03b65e2fa7f638f0089c9f64c69872940e4277f2
push id11272
push userapavel@mozilla.com
push dateThu, 16 May 2019 15:28:22 +0000
treeherdermozilla-beta@2265bfc5920d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1541404
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1541404 part 30 - Fix some debugger issues. r=tcampbell With this we pass all debugger jit-tests. Differential Revision: https://phabricator.services.mozilla.com/D30901
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/BaselineJIT.cpp
js/src/vm/Realm.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -5679,16 +5679,48 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   return emitReturn();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_AWAIT() {
   return emit_JSOP_YIELD();
 }
 
+template <>
+template <typename F>
+bool BaselineCompilerCodeGen::emitAfterYieldDebugInstrumentation(
+    const F& ifDebuggee, Register) {
+  if (handler.compileDebugInstrumentation()) {
+    return ifDebuggee();
+  }
+  return true;
+}
+
+template <>
+template <typename F>
+bool BaselineInterpreterCodeGen::emitAfterYieldDebugInstrumentation(
+    const F& ifDebuggee, Register scratch) {
+  // Note that we can't use emitDebugInstrumentation here because the frame's
+  // DEBUGGEE flag hasn't been initialized yet.
+
+  // If the current Realm is not a debuggee we're done.
+  Label done;
+  masm.loadPtr(AbsoluteAddress(cx->addressOfRealm()), scratch);
+  masm.branchTest32(Assembler::Zero,
+                    Address(scratch, Realm::offsetOfDebugModeBits()),
+                    Imm32(Realm::debugModeIsDebuggeeBit()), &done);
+
+  if (!ifDebuggee()) {
+    return false;
+  }
+
+  masm.bind(&done);
+  return true;
+}
+
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_AFTERYIELD() {
   if (!emit_JSOP_JUMPTARGET()) {
     return false;
   }
 
   auto ifDebuggee = [this]() {
     frame.assertSyncedStack();
@@ -5708,17 +5740,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
     masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
     {
       masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
       masm.jump(&return_);
     }
     masm.bind(&done);
     return true;
   };
-  return emitDebugInstrumentation(ifDebuggee);
+  return emitAfterYieldDebugInstrumentation(ifDebuggee, R0.scratchReg());
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_FINALYIELDRVAL() {
   // Store generator in R0.
   frame.popRegsAndSync(1);
   masm.unboxObject(R0, R0.scratchReg());
 
@@ -6664,17 +6696,19 @@ bool BaselineInterpreterGenerator::emitI
 
   Address pcAddr = frame.addressOfInterpreterPC();
 
   // Entry point for interpreting a bytecode op. No registers are live. PC is
   // loaded from frame->interpreterPC.
   masm.bind(handler.interpretOpLabel());
   interpretOpOffset_ = masm.currentOffset();
 
-  // Emit a patchable call for debugger breakpoints/stepping.
+  // Emit a patchable call for debugger breakpoints/stepping. Note: there must
+  // be no code between interpretOpOffset_ and this debug trap. EnterBaseline
+  // and BaselineCompileFromBaselineInterpreter depend on this.
   if (!emitDebugTrap()) {
     return false;
   }
 
   // Load pc, bytecode op.
   masm.loadPtr(pcAddr, PCRegAtStart);
   masm.load8ZeroExtend(Address(PCRegAtStart, 0), scratch1);
 
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -378,16 +378,20 @@ class BaselineCodeGen {
   template <typename F1, typename F2>
   MOZ_MUST_USE bool emitDebugInstrumentation(
       const F1& ifDebuggee, const mozilla::Maybe<F2>& ifNotDebuggee);
   template <typename F>
   MOZ_MUST_USE bool emitDebugInstrumentation(const F& ifDebuggee) {
     return emitDebugInstrumentation(ifDebuggee, mozilla::Maybe<F>());
   }
 
+  template <typename F>
+  MOZ_MUST_USE bool emitAfterYieldDebugInstrumentation(const F& ifDebuggee,
+                                                       Register scratch);
+
   // ifSet should be a function emitting code for when the script has |flag|
   // set. ifNotSet emits code for when the flag isn't set.
   template <typename F1, typename F2>
   MOZ_MUST_USE bool emitTestScriptFlag(JSScript::ImmutableFlags flag,
                                        const F1& ifSet, const F2& ifNotSet,
                                        Register scratch);
 
   // If |script->hasFlag(flag) == value|, execute the code emitted by |emit|.
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -149,16 +149,20 @@ JitExecStatus jit::EnterBaselineAtBranch
     if (fp->isDebuggee()) {
       MOZ_RELEASE_ASSERT(baseline->hasDebugInstrumentation());
       data.jitcode += MacroAssembler::ToggledCallSize(data.jitcode);
     }
   } else {
     const BaselineInterpreter& interp =
         cx->runtime()->jitRuntime()->baselineInterpreter();
     data.jitcode = interp.interpretOpAddr().value;
+    if (fp->isDebuggee()) {
+      // Skip the debug trap emitted by emitInterpreterLoop.
+      data.jitcode += MacroAssembler::ToggledCallSize(data.jitcode);
+    }
   }
 
   // Note: keep this in sync with SetEnterJitData.
 
   data.osrFrame = fp;
   data.osrNumStackValues =
       fp->script()->nfixed() + cx->interpreterRegs().stackDepth();
 
@@ -418,18 +422,26 @@ bool jit::BaselineCompileFromBaselineInt
     case Method_CantCompile:
     case Method_Skipped:
       *res = nullptr;
       return true;
 
     case Method_Compiled: {
       if (*pc == JSOP_LOOPENTRY) {
         PCMappingSlotInfo slotInfo;
-        *res = script->baselineScript()->nativeCodeForPC(script, pc, &slotInfo);
+        BaselineScript* baselineScript = script->baselineScript();
+        *res = baselineScript->nativeCodeForPC(script, pc, &slotInfo);
         MOZ_ASSERT(slotInfo.isStackSynced());
+        if (frame->isDebuggee()) {
+          // Skip the debug trap emitted by emitInterpreterLoop because the
+          // Baseline Interpreter already handled it for the current op. This
+          // matches EnterBaseline.
+          MOZ_RELEASE_ASSERT(baselineScript->hasDebugInstrumentation());
+          *res += MacroAssembler::ToggledCallSize(*res);
+        }
       } else {
         *res = script->baselineScript()->warmUpCheckPrologueAddr();
       }
       frame->prepareForBaselineInterpreterToJitOSR();
       return true;
     }
   }
 
--- a/js/src/vm/Realm.h
+++ b/js/src/vm/Realm.h
@@ -806,16 +806,20 @@ class JS::Realm : public JS::shadow::Rea
   void sweepSavedStacks();
 
   static constexpr size_t offsetOfCompartment() {
     return offsetof(JS::Realm, compartment_);
   }
   static constexpr size_t offsetOfRegExps() {
     return offsetof(JS::Realm, regExps);
   }
+  static constexpr size_t offsetOfDebugModeBits() {
+    return offsetof(JS::Realm, debugModeBits_);
+  }
+  static constexpr uint32_t debugModeIsDebuggeeBit() { return IsDebuggee; }
 
   // Note: global_ is a read-barriered object, but it's fine to skip the read
   // barrier when the realm is active. See the comment in JSContext::global().
   static constexpr size_t offsetOfActiveGlobal() {
     static_assert(sizeof(global_) == sizeof(uintptr_t),
                   "JIT code assumes field is pointer-sized");
     return offsetof(JS::Realm, global_);
   }