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).

This would make it possible to undo [JDK‑8308031] 
(<https://github.com/openjdk/jdk/pull/14225>)

[JDK‑8308031]: https://bugs.openjdk.org/browse/JDK-8308031

src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java 
line 796:

> 794:                 cb.i2l();
> 795:                 cb.loadConstant(0xFFL);
> 796:                 cb.land();

It’s probably better to first do the truncation and then widen to `long`, as 
that way can use `sipush 0x00_FF` instead of needing a `CONSTANT_Long { 0xFF }` 
to be introduced to the constant pool (the bytecode length ends up being the 
same, as `CONSTANT_Long` needs `ldc2_w`):
Suggestion:

                cb.loadConstant(0xFF);
                cb.iand();
                cb.i2l();

src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java 
line 800:

> 798:             case USHORT_TO_LONG -> {
> 799:                 cb.loadConstant(0xFFFF);
> 800:                 cb.iand();

Since `USHORT_TO_INT` now uses `i2c`, `USHORT_TO_LONG` should probably do the 
same:
Suggestion:

                cb.i2c();

src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java 
line 813:

> 811:             case USHORT_TO_INT -> {
> 812:                 cb.loadConstant(0xFFFF);
> 813:                 cb.iand();

I personally prefer using `i2c` for this, as `0xFFFF` doesn’t fit into a 
`sipush` and must instead be stored in a `CONSTANT_Integer`.

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java 
line 266:

> 264:         static final MemorySegment UINT32_TYPE = 
> MemorySegment.ofAddress(ffi_type_uint32());
> 265:         static final MemorySegment SINT64_TYPE = 
> MemorySegment.ofAddress(ffi_type_sint64());
> 266:         static final MemorySegment UINT64_TYPE = 
> MemorySegment.ofAddress(ffi_type_uint64());

On the previous lines, `uintN` precedes `sintN`:
Suggestion:

        static final MemorySegment UINT32_TYPE = 
MemorySegment.ofAddress(ffi_type_uint32());
        static final MemorySegment SINT32_TYPE = 
MemorySegment.ofAddress(ffi_type_sint32());
        static final MemorySegment UINT64_TYPE = 
MemorySegment.ofAddress(ffi_type_uint64());
        static final MemorySegment SINT64_TYPE = 
MemorySegment.ofAddress(ffi_type_sint64());

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

PR Comment: https://git.openjdk.org/jdk/pull/33417#issuecomment-6324823591
PR Review Comment: https://git.openjdk.org/jdk/pull/33417#discussion_r4329244730
PR Review Comment: https://git.openjdk.org/jdk/pull/33417#discussion_r4361665091
PR Review Comment: https://git.openjdk.org/jdk/pull/33417#discussion_r4329208011
PR Review Comment: https://git.openjdk.org/jdk/pull/33417#discussion_r4329459986

Reply via email to