Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/hx/cppia/Cppia.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ struct ScriptCallable : public CppiaDynamicExpr
#ifdef CPPIA_JIT
void compile();
void genDefaults(CppiaCompiler *compiler);
#ifdef HXCPP_DEBUGGER
void genZeroLocals(CppiaCompiler *compiler);
#endif
void genArgs(CppiaCompiler *compiler, CppiaExpr *inThis, Expressions &inArgs, const JitVal &inThisVal);
void genCode(CppiaCompiler *compiler,const JitVal &inDest=JitVal(),ExprType type=etNull) HXCPP_OVERRIDE;
#endif
Expand Down
70 changes: 63 additions & 7 deletions src/hx/cppia/CppiaFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,30 @@ CppiaExpr *ScriptCallable::link(CppiaModule &inModule)
}

#ifdef HXCPP_STACK_SCRIPTABLE

// The base holds 'this', then the arguments and locals at their stackPos
// (stackSize covers all of them). Interpreted (both vtable dispatch and
// CppiaClosure paths), 'this' and the arguments are pushed at ctx->frame, and
// runFunction then allocates the whole layout again before the StackFrame:
// base = ctx->frame; StackFrame (inStack) = base + sizeof(Object*) + argBytes + stackSize
// Jitted code pushes its StackFrame right after the layout:
// StackFrame (inStack) = base + stackSize
static unsigned char *scriptableBase(unsigned char *inStack, int stackSize,
const std::vector<CppiaStackVar> &args, bool inCompiled)
{
if (inCompiled)
return inStack - stackSize;
int argBytes = 0;
for (int i = 0; i < (int)args.size(); i++)
argBytes += sTypeSize[args[i].argType];
return inStack - stackSize - sizeof(hx::Object *) - argBytes;
}

void ScriptCallable::getScriptableVariables(unsigned char *inStack, Array<Dynamic> outNames)
{
unsigned char *frame = inStack - stackSize;
unsigned char *base = scriptableBase(inStack, stackSize, args, compiled!=0);

hx::Object *thizz = *(hx::Object **)frame;
hx::Object *thizz = *(hx::Object **)base;
if (thizz)
outNames->push(HX_CSTRING("this"));

Expand All @@ -219,10 +238,10 @@ void ScriptCallable::getScriptableVariables(unsigned char *inStack, Array<Dynami

bool ScriptCallable::getScriptableValue(unsigned char *inStack, String inName, ::Dynamic &outValue)
{
unsigned char *frame = inStack - stackSize;
unsigned char *base = scriptableBase(inStack, stackSize, args, compiled!=0);
if (inName == HX_CSTRING("this"))
{
outValue = *(hx::Object **)frame;
outValue = *(hx::Object **)base;
return true;
}

Expand All @@ -232,7 +251,7 @@ bool ScriptCallable::getScriptableValue(unsigned char *inStack, String inName, :
CppiaStackVar *var = i->second;
if ( var->module->strings[ var->nameId]==inName)
{
outValue = var->getInFrame(frame);
outValue = var->getInFrame(base);
return true;
}
}
Expand All @@ -243,13 +262,13 @@ bool ScriptCallable::getScriptableValue(unsigned char *inStack, String inName, :

bool ScriptCallable::setScriptableValue(unsigned char *inStack, String inName, ::Dynamic inValue)
{
unsigned char *frame = inStack - stackSize;
unsigned char *base = scriptableBase(inStack, stackSize, args, compiled!=0);
for(CppiaStackVarMap::iterator i=varMap.begin();i!=varMap.end();++i)
{
CppiaStackVar *var = i->second;
if ( var->module->strings[ var->nameId]==inName)
{
var->setInFrame(frame,inValue);
var->setInFrame(base,inValue);
return true;
}
}
Expand Down Expand Up @@ -364,6 +383,27 @@ void ScriptCallable::genArgs(CppiaCompiler *compiler, CppiaExpr *inThis, Express
}


#ifdef HXCPP_DEBUGGER
static void SLJIT_CALL zeroLocals(unsigned char *inLocals, void *inSize)
{
memset(inLocals, 0, (size_t)inSize);
}

// The interpreter zeroes a frame's locals; jitted code writes each before
// reading it, but the debugger can read any of them at any time
void ScriptCallable::genZeroLocals(CppiaCompiler *compiler)
{
int argEnd = sizeof(void *);
for(int i=0;i<args.size();i++)
argEnd += sTypeSize[args[i].argType];
if (stackSize > argEnd)
{
compiler->add(sJitArg1.as(jtPointer), sJitFrame.as(jtPointer), argEnd );
compiler->callNative( (void *)zeroLocals, sJitArg1.as(jtPointer), JitVal((void *)(size_t)(stackSize - argEnd)) );
}
}
#endif

void ScriptCallable::genDefaults(CppiaCompiler *compiler)
{
if (hasDefaults)
Expand Down Expand Up @@ -646,10 +686,18 @@ void ScriptCallable::compile()
CppiaCompiler *compiler = CppiaCompiler::create(size);

// First pass calculates size...
#ifdef HXCPP_DEBUGGER
genZeroLocals(compiler);
#endif
genDefaults(compiler);

#ifdef HXCPP_STACK_TRACE
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,position) + stackSize), (void *)&position );
#if defined(HXCPP_STACK_LINE) && defined(HXCPP_DEBUGGER)
// As the StackFrame constructor does - the debugger walks these lists
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,variables) + stackSize), (void *)0 );
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,catchables) + stackSize), (void *)0 );
#endif
compiler->add(sJitArg1.as(jtPointer), sJitFrame.as(jtPointer), stackSize );
compiler->callNative( (void *)pushFrame, sJitCtx.as(jtPointer), sJitArg1.as(jtPointer) );

Expand All @@ -664,10 +712,18 @@ void ScriptCallable::compile()
compiler->beginGeneration(1);

// Second pass does the job
#ifdef HXCPP_DEBUGGER
genZeroLocals(compiler);
#endif
genDefaults(compiler);

#ifdef HXCPP_STACK_TRACE
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,position) + stackSize), (void *)&position );
#if defined(HXCPP_STACK_LINE) && defined(HXCPP_DEBUGGER)
// As the StackFrame constructor does - the debugger walks these lists
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,variables) + stackSize), (void *)0 );
compiler->move(sJitFrame.star(jtPointer)+(offsetof(StackFrame,catchables) + stackSize), (void *)0 );
#endif
compiler->add(sJitArg1.as(jtPointer), sJitFrame.as(jtPointer), stackSize );
compiler->callNative( (void *)pushFrame, sJitCtx.as(jtPointer), sJitArg1.as(jtPointer) );
#endif
Expand Down
28 changes: 28 additions & 0 deletions test/regression/CppiaDebuggerFrames/Inspect.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import cpp.vm.Debugger;

class Inspect {
static function frame(name:String):Int {
var thread = Debugger.getCurrentThreadNumber();
var stack = Debugger.getThreadInfo(thread, true).stack;
for (i in 0...stack.length)
if (stack[i].functionName == name)
return i;
return -1;
}

public static function caller(name:String):String {
var thread = Debugger.getCurrentThreadNumber();
var i = frame(name);
if (i < 0)
return "no frame for " + name;
var names = Debugger.getStackVariables(thread, i, true);
names.sort(Reflect.compare);
var values = [for (n in names) n == "this" ? "this=" + Std.string(Debugger.getStackVariableValue(thread, i, n, true) != null)
: n + "=" + Std.string(Debugger.getStackVariableValue(thread, i, n, true))];
return values.join(" ");
}

public static function set(name:String, variable:String, value:Dynamic) {
Debugger.setStackVariableValue(Debugger.getCurrentThreadNumber(), frame(name), variable, value, true);
}
}
16 changes: 16 additions & 0 deletions test/regression/CppiaDebuggerFrames/Main.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// hx::EnableJit, which Host.enableJit calls
@:cppInclude("hx/Scriptable.h")
class Main {
static function main() {
Inspect.caller("");
var script = haxe.io.Path.join([haxe.io.Path.directory(Sys.programPath()), "script.cppia"]);
for (jit in [false, true]) {
cpp.cppia.Host.enableJit(jit);
try {
cpp.cppia.Host.runFile(script);
} catch (e:Dynamic) {
Sys.println("error: " + e);
}
}
}
}
46 changes: 46 additions & 0 deletions test/regression/CppiaDebuggerFrames/Script.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class Script {
var label:String;

function new()
label = "probe";

function probe(a:Int, b:String):String {
var c = a * 2;
var seen = Inspect.caller("probe");
return seen + (c > 0 ? "" : "");
}

function mixed(i:Int, f:Float, s:String, j:Int, o:Array<Int>):String {
var k = i + j;
var seen = Inspect.caller("mixed");
return seen + (k > 0 && f > 0 && s != null && o != null ? "" : "");
}

function defaults(a:Int, b:Int = 7, ?c:String):String {
var seen = Inspect.caller("defaults");
return seen + (a + b > 0 && c == null ? "" : "");
}

function setter(n:Int):String {
var m = n;
Inspect.set("setter", "m", 99);
Inspect.set("setter", "n", 5);
return "m=" + m + " n=" + n;
}

static function staticProbe(x:Float):String {
var y = x + 1;
var seen = Inspect.caller("staticProbe");
return seen + (y > 0 ? "" : "");
}

static function main() {
var s = new Script();
Sys.println("method: " + s.probe(21, "two"));
Sys.println("mixed: " + s.mixed(1, 2.5, "s", 3, [4]));
Sys.println("defaults: " + s.defaults(1));
Sys.println("dynamic: " + Reflect.callMethod(s, Reflect.field(s, "mixed"), [5, 0.5, "d", 6, []]));
Sys.println("setter: " + s.setter(1));
Sys.println("static: " + staticProbe(1.5));
}
}
8 changes: 8 additions & 0 deletions test/regression/CppiaDebuggerFrames/build.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
--main Script
-cppia bin/script.cppia
--next
--main Main
-cpp bin
-D scriptable
-D HXCPP_DEBUGGER
--dce no
12 changes: 12 additions & 0 deletions test/regression/CppiaDebuggerFrames/stdout.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
method: a=21 b=two c=42 seen=null this=true
mixed: f=2.5 i=1 j=3 k=4 o=[4] s=s seen=null this=true
defaults: a=1 b=7 c=null seen=null this=true
dynamic: f=0.5 i=5 j=6 k=11 o=[] s=d seen=null this=true
setter: m=99 n=5
static: seen=null x=1.5 y=2.5
method: a=21 b=two c=42 seen=null this=true
mixed: f=2.5 i=1 j=3 k=4 o=[4] s=s seen=null this=true
defaults: a=1 b=7 c=null seen=null this=true
dynamic: f=0.5 i=5 j=6 k=11 o=[] s=d seen=null this=true
setter: m=99 n=5
static: seen=null x=1.5 y=2.5
Loading