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
