Skip to content

Fix cppia JIT "Bad move target" on untyped register moves - #1369

Open
MeguminBOT wants to merge 1 commit into
HaxeFoundation:masterfrom
MeguminBOT:fix-cppia-jit-bad-move-target
Open

Fix cppia JIT "Bad move target" on untyped register moves#1369
MeguminBOT wants to merge 1 commit into
HaxeFoundation:masterfrom
MeguminBOT:fix-cppia-jit-bad-move-target

Conversation

@MeguminBOT

Copy link
Copy Markdown

Remake of #1366

The problem

With the JIT on, a cppia module containing an ordinary integer expression fails to load:

Error : Bad move target

The failure is at module boot, because JIT compilation runs over the whole module there, so one
expression takes the entire module down. cppia with jit off runs the same code correctly.

Why

CppiaCompiler::convert moves between two untyped registers in three places, for example when
converting an Int to a String:

if (inSrc.uses(SLJIT_R1))
{
   move(sJitArg0, inSrc);
   ...

Neither side is given a width. When both operands are untyped, getCommonType(jtAny, jtAny) returns
jtAny, which move() rejects with setError("Bad move target"). That is thrown, caught in
CppiaModule, and re-raised as the load error above.

It needs both conditions at once, which is why it is easy to miss: the source has to be in R1 and
untyped. An expression like "" + (a * b) reaches the branch but with a typed source, and
"" + ints[0] has an untyped source but does not reach the branch.

The fix

In src/hx/cppia/CppiaCompiler.cpp, give both sides a width:

move(sJitArg0.as(jtInt), inSrc.as(jtInt));          // the etString case, from etInt
move(sJitArg0.as(jtPointer), inSrc.as(jtPointer));  // the two etObject cases

Test

test/cppia covers it. ClientUntypedMove in Client.hx subtracts one array element from another
into a string, and testUntypedRegisterMove in cases/TestCommon.hx checks the answer.

cd test/cppia
haxe compile-host.hxml
haxe compile-client.hxml
cd bin && ./CppiaHost.exe client.cppia -jit

The -jit matters, and RunTests.hx already runs the suite both ways.

Without the fix, the -jit run fails at setupClass failed: Bad move target and exits 1, since the
module never loads. The same build without -jit reports ALL TESTS OK.

Reproducing by hand

class Script {
   public static function run():String {
      var a:Int = 2;
      var ints:Array<Int> = [7,8,9];

      return "" + (ints[a - 1] - ints[0]);
   }

   public static function main():Void {}
}

Built with haxe -m Script --cppia script.cppia and loaded from a host built with
-D scriptable --dce no, calling cpp.cppia.Host.enableJit(true) before
cpp.cppia.Module.fromData(bytes).boot().

result
before, JIT on Error : Bad move target at boot
after, JIT on 1
either way, JIT off 1

CppiaCompiler::convert moves between two untyped registers in three places.
getCommonType(jtAny, jtAny) returns jtAny, which move() rejects.

The cppia test suite covers it, run with -jit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant