Skip to content

Commit

Permalink
Add debugger test. Record the stack depth before the debugger callbac…
Browse files Browse the repository at this point in the history
…k is made. Remove the stack context before exiting GC free zone.
  • Loading branch information
hughsando committed Mar 19, 2017
1 parent 3ee1c9a commit 4a2fbdb
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 19 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ script:
- haxe --run RunTests telemetry
- haxe --run RunTests std32
- haxe --run RunTests std64
- haxe --run RunTests debugger
- haxe --run RunTests native
- cd ~/haxe/tests/unit
- haxe compile-cpp.hxml -D HXCPP_M32 && ./bin/cpp/TestMain-debug && rm -rf bin/cpp
- haxe compile-cpp.hxml -D HXCPP_M64 && ./bin/cpp/TestMain-debug
Expand Down
45 changes: 27 additions & 18 deletions src/hx/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,35 +282,45 @@ class DebuggerContext
// This thread cannot stop while making the callback
mCanStop = false;

mWaitMutex.Lock();
mWaiting = true;
mWaitMutex.Unlock();

// Call the handler to announce the status.
StackFrame *frame = mStackContext->getCurrentStackFrame();
// Record this before g_eventNotificationHandler is run, since it might change in there
mStackContext->mDebugger->mStepLevel = mStackContext->getDepth();
g_eventNotificationHandler
(mThreadNumber, THREAD_STOPPED, mStackContext->getDepth()-1,
(mThreadNumber, THREAD_STOPPED, mStackContext->mDebugger->mStepLevel,
String(frame->position->className), String(frame->position->functionName),
String(frame->position->fileName), frame->lineNumber);

// Wait until the debugger thread sets mWaiting to false and signals
// the semaphore
mWaitMutex.Lock();
mWaiting = true;

while (mWaiting) {
mWaitMutex.Unlock();
hx::EnterGCFreeZone();
mWaitSemaphore.Wait();
hx::ExitGCFreeZone();
mWaitMutex.Lock();
if (mWaiting)
{
// Wait until the debugger thread sets mWaiting to false and signals
// the semaphore
mWaitMutex.Lock();

while (mWaiting) {
mWaitMutex.Unlock();
hx::EnterGCFreeZone();
mWaitSemaphore.Wait();
hx::ExitGCFreeZone();
mWaitMutex.Lock();
}

mWaitMutex.Unlock();
}

mWaitMutex.Unlock();

// Save the breakpoint status in the call stack so that queries for
// thread info will know the current status of the thread
mStatus = DBG_STATUS_RUNNING;
mBreakpoint = -1;

// Announce the new status
g_eventNotificationHandler(mThreadNumber, THREAD_STARTED);
Dynamic handler = hx::g_eventNotificationHandler;
if (handler!=null())
handler(mThreadNumber, THREAD_STARTED);

// Can stop again
mCanStop = true;
Expand Down Expand Up @@ -412,8 +422,7 @@ class Breakpoints

int ret = gNextBreakpointNumber++;

Breakpoints *newBreakpoints = new Breakpoints
(gBreakpoints, ret, className, functionName);
Breakpoints *newBreakpoints = new Breakpoints(gBreakpoints, ret, className, functionName);

gBreakpoints->RemoveRef();

Expand Down Expand Up @@ -536,7 +545,7 @@ class Breakpoints
while (iter != gList.end()) {
DebuggerContext *stack = *iter++;
if (stack->mThreadNumber == threadNumber) {
gStepLevel = stack->mStackContext->getDepth() - 1;
gStepLevel = stack->mStackContext->mDebugger->mStepLevel;
stack->Continue(1);
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/hx/gc/Immix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4172,8 +4172,8 @@ class LocalAllocator : public hx::StackContext

~LocalAllocator()
{
EnterGCFreeZone();
onThreadDetach();
EnterGCFreeZone();
sGlobalAlloc->RemoveLocal(this);
hx::tlsStackContext = 0;

Expand Down
9 changes: 9 additions & 0 deletions test/RunTests.hx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ class RunTests
}


public static function debugger()
{
setDir("debugger");

command("haxe", ["compile.hxml"] );
command("bin" + sep + "App-debug",[]);
}

public static function opMatrix()
{
setDir("opMatrix");
Expand Down Expand Up @@ -177,6 +185,7 @@ class RunTests
run("std32", std32);
run("std64", std64);
run("native", native);
run("debugger", debugger);

Sys.println("");

Expand Down
45 changes: 45 additions & 0 deletions test/debugger/App.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

class App
{
public static var hasRunBreakMe = false;
public static var hasRunBreakMe2 = false;

function breakMe()
{
hasRunBreakMe = true;
}

function breakMe2() hasRunBreakMe2 = true;


public function new()
{
breakMe();
breakMe2();
Lines.lineStep();
}

public static function main()
{
TestDebugger.setup();

new App();

if (!TestDebugger.finished)
{
Sys.println("Not all breakpoints triggered");
Sys.exit(-1);
}
else if (!TestDebugger.ok)
{
Sys.println("Some debugger checks failed");
Sys.exit(-1);
}
else
{
Sys.println("All good!");
}

}
}

20 changes: 20 additions & 0 deletions test/debugger/Lines.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Lines // line 1
{ // line 2
public static var line = -1; // line 3
// line 4
public static function lineStep() // line 5
{ // line 6
line = 7; // line 7;
callFunction(); // 8
line = 9; // line 9;
callFunction(); // 10
// 11
line = 12; // 12
} // line 13
// 14
public static function callFunction() // 15
{ // 16
// 17
line = 18;
}
}
152 changes: 152 additions & 0 deletions test/debugger/TestDebugger.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import cpp.vm.Debugger;
import cpp.vm.Thread;

typedef DebuggerContext = { className : String,
functionName : String,
fileName : String,
lineNumber : Int };

typedef DebuggerTest = { setup:Void->Void,
test:DebuggerContext->Bool,
name:String,
resume:Int->Void };

class TestDebugger
{
public static var ok = true;
public static var finished = false;
static var jobs:Array<DebuggerTest>;
static var currentTest:DebuggerContext->Bool;
static var currentName:String;
static var currentResume:Void->Void;


public static function setup()
{
Debugger.enableCurrentThreadDebugging(false);
var mainThread = Thread.current();
cpp.vm.Thread.create( function() {
startDebugger();
mainThread.sendMessage("setup");
});

var message = Thread.readMessage(true);
Sys.println("Debugger : " + message);
Debugger.enableCurrentThreadDebugging(true);

}

static function handleThreadEvent(threadNumber : Int, event : Int,
stackFrame : Int,
className : String,
functionName : String,
fileName : String, lineNumber : Int)
{
if (event==Debugger.THREAD_STOPPED)
{
var ctx = { className:className, functionName:functionName, fileName:fileName, lineNumber:lineNumber };

if (!currentTest(ctx))
{
ok = false;
Sys.println('Test failed : $currentName - got $ctx');
Sys.exit(-1);
}
else
{
nextTest(threadNumber);
}
}
}

static function cont(id:Int)
{
Debugger.continueThreads(-1,1);
}

static function step(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_INTO,1);
}


static function stepOver(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_OVER,1);
}


static function stepOut(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_OUT,1);
}

static function nextTest(threadId:Int)
{
var test = jobs.shift();
if (test==null)
{
finished = true;
currentName = null;
currentTest = null;
currentResume = null;
Debugger.setEventNotificationHandler(null);
cont(-1);
}
else
{
currentName = test.name;
currentTest = test.test;
test.setup();
Sys.println(' $currentName...');
test.resume(threadId);
}
}


static function startDebugger()
{
Debugger.setEventNotificationHandler(handleThreadEvent);
jobs = [
{ setup:function() Debugger.addClassFunctionBreakpoint("App","breakMe"),
test:function(ctx) return !App.hasRunBreakMe,
name:"Set function breakpoint App.breakMe",
resume:cont },
{ setup:function() Debugger.addClassFunctionBreakpoint("App","breakMe2"),
test:function(ctx) return App.hasRunBreakMe && !App.hasRunBreakMe2,
name:"Set function breakpoint App.breakMe2",
resume:cont},
{ setup:function() Debugger.addFileLineBreakpoint("Lines.hx",7),
test:function(ctx) return Lines.line==-1,
name:"Set line breakpoint Lines.hx:7",
resume:cont},
{ setup:function() { },
test:function(ctx) return Lines.line==7,
name:"Step from Lines.hx:7",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==18,
name:"Step over callFunction",
resume:stepOver},
{ setup:function() { },
test:function(ctx) return Lines.line==9,
name:"Step over line 9",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==9,
name:"step into callFunction",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==18,
name:"step out of callFunction",
resume:stepOut },
{ setup:function() { },
test:function(ctx) return Lines.line==12,
name:"step out of Lines",
resume:stepOut },


];
nextTest(-1);
}
}
4 changes: 4 additions & 0 deletions test/debugger/compile.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-main App
-cpp bin
-D HXCPP_DEBUGGER
-debug

3 comments on commit 4a2fbdb

@delahee
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my my my... that sounds like sweetness included 💃

@madrazo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄

@jcward
Copy link
Contributor

@jcward jcward commented on 4a2fbdb Mar 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.