From b0604f2a977b7262ff702923f95b449f2bda238f Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 17 Jun 2016 15:11:56 -0700 Subject: [PATCH] Nuclide xdebug async stepping (1/N) -- Refactor stack depth disposition logic Summary: Make it easier for reuse by async stepping later. Reviewed By: alexmalyshev Differential Revision: D3406171 fbshipit-source-id: 2a20fc2e99e093d95e837540a3a018dd73c05818 --- hphp/runtime/vm/debugger-hook.cpp | 21 +++++++++++++++++---- hphp/runtime/vm/debugger-hook.h | 8 ++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/hphp/runtime/vm/debugger-hook.cpp b/hphp/runtime/vm/debugger-hook.cpp index f3bb1c6a430..5cbb5791e55 100644 --- a/hphp/runtime/vm/debugger-hook.cpp +++ b/hphp/runtime/vm/debugger-hook.cpp @@ -176,6 +176,8 @@ void phpDebuggerOpcodeHook(const unsigned char* pc) { req_data.clearActiveLineBreak(); } + auto curStackDisp = getStackDisposition(req_data.getDebuggerFlowDepth()); + // Check if the step in command is active. Special case builtins because they // are meaningless to the user if (UNLIKELY(req_data.getDebuggerStepIn() && !func->isBuiltin())) { @@ -184,8 +186,7 @@ void phpDebuggerOpcodeHook(const unsigned char* pc) { // Next command is not active, just break. hook->onStepInBreak(unit, line); return; - } else if (req_data.getDebuggerStackDepth() <= - req_data.getDebuggerFlowDepth()) { + } else if (curStackDisp != StackDepthDisposition::Deeper) { // Next command is active but we didn't step in. We are done. req_data.setDebuggerNext(false); hook->onNextBreak(unit, line); @@ -207,7 +208,7 @@ void phpDebuggerOpcodeHook(const unsigned char* pc) { // original, then we skip over the PopR opcode if it exists and then break // (matching hphpd). if (UNLIKELY(req_data.getDebuggerStepOut() == StepOutState::Out && - req_data.getDebuggerStackDepth() < req_data.getDebuggerFlowDepth() && + curStackDisp == StackDepthDisposition::Shallower && peek_op(pc) != OpPopR)) { req_data.setDebuggerStepOut(StepOutState::None); if (!req_data.getDebuggerNext()) { @@ -244,6 +245,17 @@ void phpDebuggerOpcodeHook(const unsigned char* pc) { TRACE(5, "out phpDebuggerOpcodeHook()\n"); } +StackDepthDisposition getStackDisposition(int baseline) { + auto& req_data = RID(); + auto curStackDepth = req_data.getDebuggerStackDepth(); + if (curStackDepth > baseline) { + return StackDepthDisposition::Deeper; + } else if (curStackDepth < baseline) { + return StackDepthDisposition::Shallower; + } + return StackDepthDisposition::Equal; +} + // Hook called on request start before main() is invoked void phpDebuggerRequestInitHook() { getDebuggerHook()->onRequestInit(); @@ -269,8 +281,9 @@ void phpDebuggerFuncExitHook(const ActRec* ar) { // If the step out command is active and if our stack depth has decreased, // we are out of the function being stepped out of + auto baseline = req_data.getDebuggerFlowDepth(); if (UNLIKELY(req_data.getDebuggerStepOut() == StepOutState::Stepping && - req_data.getDebuggerStackDepth() < req_data.getDebuggerFlowDepth())) { + getStackDisposition(baseline) == StackDepthDisposition::Shallower)) { req_data.setDebuggerStepOut(StepOutState::Out); } } diff --git a/hphp/runtime/vm/debugger-hook.h b/hphp/runtime/vm/debugger-hook.h index 29602578ef4..418bb082c13 100644 --- a/hphp/runtime/vm/debugger-hook.h +++ b/hphp/runtime/vm/debugger-hook.h @@ -62,6 +62,12 @@ bool isHphpd(const DebuggerHook*); // debugger interrupts for every opcode executed (modulo filters.) #define DEBUGGER_FORCE_INTR (RID().getDebuggerForceIntr()) +enum class StackDepthDisposition { + Equal, // Same. + Shallower, // Less than baseline. + Deeper, // Greater than baseline. +}; + //////////////////////////////////////////////////////////////////////////////// // DebuggerHook // A hook for debugger events. Any extension can subclass this class and @@ -243,6 +249,8 @@ void phpRemoveBreakPointLine(const Unit* unit, int line); bool phpHasBreakpoint(const Unit* unit, Offset offset); +StackDepthDisposition getStackDisposition(int baseline); + } #endif -- 2.11.4.GIT