On Fri, 16 Oct 2026 15:58:14 GMT, Jorn Vernee <[email protected]> wrote:

> Currently we do not directly support unsigned types in the Linker. The 
> javadoc has this to say about it:
> 
>>  A native linker typically does not provide canonical layouts for C's 
>> unsigned integral
>  types. Instead, they are modeled using the canonical layouts associated with 
> their
>  corresponding signed integral types. For instance, the C type `unsigned long`
>  maps to the canonical layout for `code long`.
> 
> This was done under the earlier assumption that ABIs treat signed and 
> unsigned types the same. However, it turns out that we missed certain cases 
> where this does matter for some ABIs. More concretely:
> 
> - Mac x64 and AArch64 ABIs require integral types smaller than `int`  to be 
> widened to `int` before being passed to a function 
> [1](https://developer.apple.com/documentation/xcode/writing-64-bit-intel-code-for-apple-platforms),
>  
> [2](https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms).
>  Clang even extends this behavior to Linux x64 (although this appears to be a 
> bug) 
> [3](https://mail.openjdk.org/archives/list/[email protected]/message/RJNMKNUXN7R5PSJETZKX3PMBJ7P6GYJG/).
> - RISCV requires arguments smaller than XLEN to be extended to 32 bits 
> according to their sign, and then sign extended to XLEN 
> [4](https://docs.riscv.org/reference/abi/v1.0/riscv-cc-procedure-calling-convention.html).
> - PowerPC requires small integer types (char, short, int, long, enum) to be 
> extended to long 
> [5](https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#PARAM-PASS).
> 
> In order to address these use cases we need to attach a bit of extra 
> information to a linkage request that indicates the signedness of certain 
> arguments. For this patch, we've chosen to attach that information directly 
> to the argument layouts through a newly introduced `boolean isSigned()` 
> method on a new `ValueLayout` subclass `OfIntegral` that is implemented by 
> `OfByte`, `OfShort`, `OfInt`, and `OfLong`.
> 
> This information is potentially used by the linker to implement the correct 
> extension. In cases where it doesn't affect the way functions are linker the 
> information is erased in order to provide more efficient caching, since 
> signed and unsigned types can share the same downcall handle in that case.
> 
> Testing: `jdk_foreign` test suite on Windows/Linux/Mac-x64, 
> Mac/Linux-AArch64, Linux-x64 using the fallback linker.
> 
> ---------
> - [x] I confirm that I make this contribution in accordance with the [OpenJDK 
> Interim AI Policy](https://openjdk.org/legal/ai).

I eye-balled the RISC-V and PPC changes for this. @feilongjiang and 
@TheRealMDoerr you might want to have a look at this as well.

Please let me know if this works.

Hey Martin, I think I know what the problem is. That test tries to allocate a 
downcall stub using the maximum number of arguments. Since I changed the call 
arranger to pass int and smaller arguments as long, and long takes up more 
slots, we are running into the argument limit. I think we just have to adjust 
the test for PowerPC.

The problem with handling ABI dependent conversions in the downcall stub is 
that it would be harder to intrinsify downcalls in C2 (which I still plan to do 
at some point...). Since C2 would have to replicate what the downcall stub does 
C2 would start having to keep track of platform specific behavior. The advice I 
got from C2 engineers back when I started working on the current incarnation of 
the linker was to put as much of the logic as possible on the Java side to keep 
what C2 has to do simpler, so doing that would have my preference. (In case 
you're interested, the code is a bit stale, but this is the prototype I have: 
https://github.com/openjdk/jdk/compare/master...JornVernee:jdk:NativeIntrinsics)

I've implemented the feedback so far. PPC and s390 will now only widen unsigned 
values to `long`.

I'm working out some final details about the design with Maurizio, then I will 
un-draft the PR.

That's a good point. We could move some of this logic to the Windows 
CallArranger as well, and convert to `long` first using 
`Double::doubleToRawLongBits`. I prototyped this and it seems to just work. The 
benefit of doing it in the backend is that we can handle the conversion and 
move into target register both at once with a single move operation.

I think for the intrinsification the important bit is that a move from an FP to 
GP register has a single implementation in the IR.

src/java.base/share/classes/java/lang/foreign/ValueLayout.java line 125:

> 123:     VarHandle varHandle();
> 124: 
> 125:     /**

This doc uses the term 'signedness' as a property of the type. I also 
considered using just 'sign', but I think that's incorrect. The two polarities 
of 'sign' or 'positive' and 'negative', whereas the two polarities of 
'signedness' are 'signed' and 'unsigned'.

See also: https://en.wiktionary.org/wiki/sign#English and 
https://en.wiktionary.org/wiki/signedness

-------------

PR Comment: https://git.openjdk.org/jdk/pull/33417#issuecomment-6219627159
PR Comment: https://git.openjdk.org/jdk/pull/33417#issuecomment-6225429824
PR Comment: https://git.openjdk.org/jdk/pull/33417#issuecomment-6368814610
PR Comment: https://git.openjdk.org/jdk/pull/33417#issuecomment-6451679656
PR Review Comment: https://git.openjdk.org/jdk/pull/33417#discussion_r4402461983

Reply via email to