From ee9632c4bae2fd954b58f20058b2e33786b04afa Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 27 Aug 2019 15:57:33 +0000 Subject: [PATCH] Bug 1576567 part 3 - Use real NOPs for debug trap handler calls in interpreter loop. r=tcampbell We now use real NOPs on all platforms. On x86/x64 this used to be a CMP instruction and on ARM64 this involved an unconditional LDR with some other instructions. Depends on D43413 Differential Revision: https://phabricator.services.mozilla.com/D43414 --HG-- extra : moz-landing-system : lando --- js/src/jit/BaselineCodeGen.cpp | 26 ++++++++++++++++---------- js/src/jit/BaselineCodeGen.h | 4 ++++ js/src/jit/BaselineJIT.cpp | 13 +++++++++++-- js/src/jit/BaselineJIT.h | 6 +++++- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/js/src/jit/BaselineCodeGen.cpp b/js/src/jit/BaselineCodeGen.cpp index 8fe994648606..17025f5025db 100644 --- a/js/src/jit/BaselineCodeGen.cpp +++ b/js/src/jit/BaselineCodeGen.cpp @@ -6866,15 +6866,7 @@ MethodStatus BaselineCompiler::emitBody() { } bool BaselineInterpreterGenerator::emitDebugTrap() { - JitRuntime* jrt = cx->runtime()->jitRuntime(); - - JitCode* handlerCode = - jrt->debugTrapHandler(cx, DebugTrapHandlerKind::Interpreter); - if (!handlerCode) { - return false; - } - - CodeOffset offset = masm.toggledCall(handlerCode, /* enabled = */ false); + CodeOffset offset = masm.nopPatchableToCall(); if (!debugTrapOffsets_.append(offset.offset())) { ReportOutOfMemory(cx); return false; @@ -6995,6 +6987,20 @@ bool BaselineInterpreterGenerator::emitInterpreterLoop() { restoreInterpreterPCReg(); masm.jump(&bailoutPrologue_); + // Emit debug trap handler code (target of patchable call instructions). This + // is just a tail call to the debug trap handler trampoline code. + { + JitRuntime* jrt = cx->runtime()->jitRuntime(); + JitCode* handlerCode = + jrt->debugTrapHandler(cx, DebugTrapHandlerKind::Interpreter); + if (!handlerCode) { + return false; + } + + debugTrapHandlerOffset_ = masm.currentOffset(); + masm.jump(handlerCode); + } + // Emit code for JSOP_UNUSED* ops. Label invalidOp; masm.bind(&invalidOp); @@ -7129,7 +7135,7 @@ bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) { bailoutPrologueOffset_.offset(), handler.generatorThrowOrReturnCallOffset(), profilerEnterFrameToggleOffset_.offset(), - profilerExitFrameToggleOffset_.offset(), + profilerExitFrameToggleOffset_.offset(), debugTrapHandlerOffset_, std::move(handler.debugInstrumentationOffsets()), std::move(debugTrapOffsets_), std::move(handler.codeCoverageOffsets()), std::move(handler.icReturnOffsets()), handler.callVMOffsets()); diff --git a/js/src/jit/BaselineCodeGen.h b/js/src/jit/BaselineCodeGen.h index c4e09133ca1a..12688737498e 100644 --- a/js/src/jit/BaselineCodeGen.h +++ b/js/src/jit/BaselineCodeGen.h @@ -768,6 +768,10 @@ class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen { // Like interpretOpOffset_ but skips the debug trap for the current op. uint32_t interpretOpNoDebugTrapOffset_ = 0; + // Offset of the jump (tail call) to the debug trap handler trampoline code. + // When the debugger is enabled, NOPs are patched to calls to this location. + uint32_t debugTrapHandlerOffset_ = 0; + public: explicit BaselineInterpreterGenerator(JSContext* cx); diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 18bed968b060..346980cd0082 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -899,9 +899,16 @@ void BaselineInterpreter::toggleDebuggerInstrumentation(bool enable) { } // Toggle DebugTrapHandler calls. + + uint8_t* debugTrapHandler = codeAtOffset(debugTrapHandlerOffset_); + for (uint32_t offset : debugTrapOffsets_) { - CodeLocationLabel trapLocation(code_, CodeOffset(offset)); - Assembler::ToggleCall(trapLocation, enable); + uint8_t* trap = codeAtOffset(offset); + if (enable) { + MacroAssembler::patchNopToCall(trap, debugTrapHandler); + } else { + MacroAssembler::patchCallToNop(trap); + } } } @@ -1012,6 +1019,7 @@ void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset, uint32_t generatorThrowOrReturnCallOffset, uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset, + uint32_t debugTrapHandlerOffset, CodeOffsetVector&& debugInstrumentationOffsets, CodeOffsetVector&& debugTrapOffsets, CodeOffsetVector&& codeCoverageOffsets, @@ -1024,6 +1032,7 @@ void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset, generatorThrowOrReturnCallOffset_ = generatorThrowOrReturnCallOffset; profilerEnterToggleOffset_ = profilerEnterToggleOffset; profilerExitToggleOffset_ = profilerExitToggleOffset; + debugTrapHandlerOffset_ = debugTrapHandlerOffset; debugInstrumentationOffsets_ = std::move(debugInstrumentationOffsets); debugTrapOffsets_ = std::move(debugTrapOffsets); codeCoverageOffsets_ = std::move(codeCoverageOffsets); diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index fa123494eda7..4d30d2d9eb12 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -504,6 +504,10 @@ class BaselineInterpreter { uint32_t profilerEnterToggleOffset_ = 0; uint32_t profilerExitToggleOffset_ = 0; + // Offset of the jump (tail call) to the debug trap handler trampoline code. + // When the debugger is enabled, NOPs are patched to calls to this location. + uint32_t debugTrapHandlerOffset_ = 0; + // The offsets of toggled jumps for debugger instrumentation. using CodeOffsetVector = Vector; CodeOffsetVector debugInstrumentationOffsets_; @@ -538,7 +542,7 @@ class BaselineInterpreter { uint32_t bailoutPrologueOffset, uint32_t generatorThrowOrReturnCallOffset, uint32_t profilerEnterToggleOffset, - uint32_t profilerExitToggleOffset, + uint32_t profilerExitToggleOffset, uint32_t debugTrapHandlerOffset, CodeOffsetVector&& debugInstrumentationOffsets, CodeOffsetVector&& debugTrapOffsets, CodeOffsetVector&& codeCoverageOffsets,