diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a29472..2b3cf7b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -93,6 +93,7 @@ jobs: - name: Install hl run: | git clone https://github.com/HaxeFoundation/hashlink.git hashlink + sudo apt-get update sudo apt-get install -qqy libpng-dev libturbojpeg-dev libvorbis-dev libopenal-dev libsdl2-dev libglu1-mesa-dev libmbedtls-dev libuv1-dev libsqlite3-dev cd hashlink make diff --git a/hld/Debugger.hx b/hld/Debugger.hx index 81d7c4f..0348294 100644 --- a/hld/Debugger.hx +++ b/hld/Debugger.hx @@ -398,6 +398,7 @@ class Debugger { readThreads(); prepareStack(cmd.r == Watchbreak); + eval.onBeforeBreak(); // if breakpoint has a condition, try to evaluate and do not actually break on false if( !onStep && !onEvalCall && !onPause && condition != null ) { diff --git a/hld/Eval.hx b/hld/Eval.hx index 68b8d68..a36eced 100644 --- a/hld/Eval.hx +++ b/hld/Eval.hx @@ -47,6 +47,7 @@ class Eval { var funIndex : Int; var codePos : Int; var ebp : Pointer; + var guidNames : Int64Map; public var maxArrLength : Int = 10; public var maxBytesLength : Int = 128; @@ -83,6 +84,10 @@ class Eval { this.ebp = ebp; } + public function onBeforeBreak() { + this.guidNames = null; + } + public function eval( expr : String ) : Value { if( expr == null || expr == "" ) return null; @@ -986,6 +991,16 @@ class Eval { c + "(" + [for( v in values ) valueStr(v,maxStringRec)].join(", ") + ")"; case VInlined(_): "inlined"; + case VGuid(i, name): + switch( v.hint ) { + case HBin: Value.int64Str(i, 2); + case HHex: Value.int64Str(i, 16); + default: + var str = Value.int64GuidStr(i); + if( name != null ) + str = '$name ($str)'; + str; + } } return str; } @@ -1078,6 +1093,10 @@ class Eval { VBool(m.getUI8(0) != 0); case HPacked(t): return { v : VPointer(p), t : t.v }; + case HGUID: + var i64 = haxe.Int64.make(readI32(p.offset(4)), readI32(p)); + var name = getGuidName(i64); + return { v : VGuid(i64, name), t : t }; default: p = readPointer(p); return valueCast(p, t); @@ -1611,4 +1630,43 @@ class Eval { return module.code.types[tid]; } + function getGuidName( i64 : haxe.Int64 ) : Null { + if( guidNames == null ) { + guidNames = new Int64Map(); + if( jit.hlVersion >= 1.15 ) { + var pmap = readPointer(jit.threads.offset(jit.align.ptr*3 + 8)); + if( !pmap.isNull() ) { + var m = @:privateAccess makeMap(pmap, HI64); + switch( m ) { + case VMap(_, nkeys, readKey, readValue, _): + for (n in 0...nkeys) { + var k = readKey(n); + var v = readValue(n); + switch( [k.v, v.v] ) { + case [VInt64(ki64), VString(vname, _)]: + guidNames.set(ki64, vname); + default: + } + } + default: throw "assert"; + } + } + } + } + return guidNames.get(i64); + } + +} + +// Map does not work on JS, see https://github.com/HaxeFoundation/haxe/issues/9872 +class Int64Map extends haxe.ds.BalancedTree { + override function compare(k1:haxe.Int64, k2:haxe.Int64):Int { + return if( k1 == k2 ) { + 0; + } else if( k1 > k2 ) { + 1; + } else { + -1; + } + } } diff --git a/hld/Value.hx b/hld/Value.hx index 5954053..345da95 100644 --- a/hld/Value.hx +++ b/hld/Value.hx @@ -18,6 +18,7 @@ enum ValueRepr { VEnum( c : String, values : Array, p : Pointer ); VBytes( length : Int, read : Int -> Int, p : Pointer ); VInlined( fields : Array ); + VGuid( i : haxe.Int64, name : String ); } enum FunRepr { @@ -125,6 +126,20 @@ enum Hint { return value; } + static final GUIDBASE = "#&0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + public static function int64GuidStr( value : haxe.Int64 ) : String { + if( value == 0 ) + return "0"; + var s = ""; + for( i in 0...11 ) { + if( i == 3 || i == 7 ) + s = '-' + s; + s = GUIDBASE.charAt(value.low&63) + s; + value = value >> 6; + } + return s; + } + public static function intEnumFlags( value : Int, eproto : format.hl.Data.EnumPrototype ) : String { var f = ""; for( i in 0...eproto.constructs.length ) { diff --git a/tests/RunCi.hx b/tests/RunCi.hx index b21ea32..5003082 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -11,7 +11,15 @@ class RunCi { var fullPath = sys.FileSystem.absolutePath(basePath + "unit/" + test); log('[INFO] $test begin'); changeDirectory(fullPath); - Sys.command("haxe", ["--main", "Test", "-hl", "test.hl"]); + var compileargs = ["--main", "Test", "-hl", "test.hl"]; + try { + var flags = sys.io.File.getContent(fullPath + "/compile.txt").split(" "); + compileargs = compileargs.concat(flags); + } catch( e ) { + trace("error" + e.message); + } + trace("run haxe with " + compileargs); + Sys.command("haxe", compileargs); var process = new sys.io.Process("hl", [debuggerHL, "--input", "input.txt"]); var expectedOutput = sys.io.File.getContent(fullPath + "/output.txt"); var startingTime = haxe.Timer.stamp(); diff --git a/tests/unit/TestGuid/Test.hx b/tests/unit/TestGuid/Test.hx new file mode 100644 index 0000000..c788491 --- /dev/null +++ b/tests/unit/TestGuid/Test.hx @@ -0,0 +1,13 @@ +class Test { + static function main() { + var id : hl.GUID = makeGUID(0xF1561985,0xF15008); + var id2 : hl.GUID = makeGUID(0xF1561985,0xF15009); + hl.Api.registerGUIDName(id, "SomeName"); + Sys.println(Std.string(id)); + Sys.println(Std.string(id2)); + } + + static function makeGUID(high,low) : hl.GUID { + return haxe.Int64.make(high,low); + } +} diff --git a/tests/unit/TestGuid/compile.txt b/tests/unit/TestGuid/compile.txt new file mode 100644 index 0000000..e9f297b --- /dev/null +++ b/tests/unit/TestGuid/compile.txt @@ -0,0 +1 @@ +-D hl-ver=1.15.0 \ No newline at end of file diff --git a/tests/unit/TestGuid/input.txt b/tests/unit/TestGuid/input.txt new file mode 100644 index 0000000..32638d5 --- /dev/null +++ b/tests/unit/TestGuid/input.txt @@ -0,0 +1,11 @@ +--ci +test.hl +"b Test.hx:5" +"b Test.hx:7" +r +"p id" +"p id2" +r +"p id" +"p id2" +q diff --git a/tests/unit/TestGuid/output.txt b/tests/unit/TestGuid/output.txt new file mode 100644 index 0000000..80bccef --- /dev/null +++ b/tests/unit/TestGuid/output.txt @@ -0,0 +1,17 @@ +> b Test.hx:5 +Breakpoint set line 5 +> b Test.hx:7 +Breakpoint set line 7 +> r +Thread paused Test.hx:5 ($Test::main) +> p id +z3K4-MI#w-J#6 : hl.GUID +> p id2 +z3K4-MI#w-J#7 : hl.GUID +> r +Thread paused Test.hx:7 ($Test::main) +> p id +SomeName (z3K4-MI#w-J#6) : hl.GUID +> p id2 +z3K4-MI#w-J#7 : hl.GUID +> q