Categories: Java, OpenJDK

Testing Variadics on Windows ABI

I’ve been testing some changes based on feedback from PR 8295290: Add Windows ARM64 ABI support to the Foreign Function & Memory API · Pull Request #754 · openjdk/panama-foreign (github.com). I’m using my scratchpad repo to run tests against my local build. The java commands generates upcall and downcall log files. I (re?-)discovered that hsdis is required to disassemble the instructions when I accidentally built without it.

cd scratchpad/compilers/tests/aarch64/abi/intrinsics/
cp /d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/support/test/jdk/jtreg/native/lib/Intrinsics.dll .

/d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/jdk/bin/javac -g --enable-preview --release 20 MinimizedTestIntrinsics.java

/d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/jdk/bin/java.exe --enable-preview -Xlog:foreign+downcall=trace:file=downcall.txt::filecount=0 -Xlog:foreign+upcall=trace:file=upcall.txt::filecount=0 MinimizedTestIntrinsics

The MinimizedTestIntrinsics test works just fine. The VarArgs test is the problematic one.

cp /d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/support/test/jdk/jtreg/native/lib/varargs.dll .

/d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/jdk/bin/javac -g --enable-preview --release 20 MinimizedTestVarArgs.java

/d/java/forks/panama-foreign/build/windows-x86_64-server-slowdebug/jdk/bin/java.exe --enable-preview -Xlog:foreign+downcall=trace:file=downcall.txt::filecount=0 -Xlog:foreign+upcall=trace:file=upcall.txt::filecount=0 MinimizedTestVarArgs

Since both upcall and downcall logs are generated, debugging the JDK in Visual Studio can hit the breakpoint in panama-foreign/downcallLinker_x86_64.cpp at 617198dbbbbed1a7fdb9fdfe981ca09fec8bcf5b (github.com) as expected. However, Visual Studio doesn’t hit the breakpoint in panama-foreign/libVarArgs.c at 617198dbbbbed1a7fdb9fdfe981ca09fec8bcf5b (github.com). Switching back to WinDbg shows that the downcall actually happens.

bp varargs!varargs

Disassemble the VarArgs function to simplify stepping through the code (this enables me to interpret the assembly instructions, mapping them to the source code):

cd build\windows-aarch64-server-slowdebug\support\test\jdk\jtreg\native\support\libVarArgs\
dumpbin /disasm /out:libVarArgs.asm libVarArgs.obj
dumpbin /all /out:libVarArgs.txt libVarArgs.obj

Now stepping through the code, we observe that the process terminates.

VarArgs.dll Terminating the Process

Here’s a breakdown of the VarArgs code on x64:

...
0053: EB 0A              jmp         000000000000005F

// i++
0055: 8B 44 24 28        mov         eax,dword ptr [rsp+28h]
0059: FF C0              inc         eax
005B: 89 44 24 28        mov         dword ptr [rsp+28h],eax

// load num
005F: 8B 84 24 C8 06 00  mov         eax,dword ptr [rsp+6C8h]
      00

// i < num
0066: 39 44 24 28        cmp         dword ptr [rsp+28h],eax

// jump to last line of function: va_end(a_list)
006A: 0F 8D D1 15 00 00  jge         0000000000001641

// load i into rax
0070: 48 63 44 24 28     movsxd      rax,dword ptr [rsp+28h]
0075: 48 8B 8C 24 C0 06  mov         rcx,qword ptr [rsp+6C0h]
      00 00
007D: 48 8B 49 08        mov         rcx,qword ptr [rcx+8]

// load id into eax
0081: 8B 04 81           mov         eax,dword ptr [rcx+rax*4]
0084: 89 44 24 3C        mov         dword ptr [rsp+3Ch],eax
0088: 8B 44 24 3C        mov         eax,dword ptr [rsp+3Ch]
008C: 89 44 24 38        mov         dword ptr [rsp+38h],eax

// There are 88 (0x58) enums.
0090: 83 7C 24 38 57     cmp         dword ptr [rsp+38h],57h
0095: 0F 87 96 15 00 00  ja          0000000000001631
009B: 48 63 44 24 38     movsxd      rax,dword ptr [rsp+38h]
00A0: 48 8D 0D 00 00 00  lea         rcx,[__ImageBase]
      00
00A7: 8B 84 81 00 00 00  mov         eax,dword ptr $LN97[rcx+rax*4]
      00
00AE: 48 03 C1           add         rax,rcx
00B1: FF E0              jmp         rax
...
1631: B9 FF FF FF FF     mov         ecx,0FFFFFFFFh
1636: FF 15 00 00 00 00  call        qword ptr [__imp_exit]
163C: E9 14 EA FF FF     jmp         0000000000000055

From the assembly, what appears to be happening is the switch statement is immediately jumping to the default case, which calls exit(-1). So, pretty simple test failure. Why did I think it was a crash? I assumed that a crash was the only reason the JVM would terminate prematurely but this was actually a clean exit, by design. Perhaps an assertion failure would have made the issue more visible.

Article info



Leave a Reply

Your email address will not be published. Required fields are marked *