Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows support (32-bit long values) #106

Closed
jwharm opened this issue Jun 8, 2024 · 0 comments
Closed

Windows support (32-bit long values) #106

jwharm opened this issue Jun 8, 2024 · 0 comments
Assignees

Comments

@jwharm
Copy link
Owner

jwharm commented Jun 8, 2024

Java-GI is intended to run on 64-bit Windows, Linux and MacOS systems. However, sizeof(long) differs between these platforms, and needs to be accounted for. Consult the table in https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models for context. Currently java-gi assumes sizeof(long) == 64. This is incorrect on Windows.

Ideally this is resolved without creating platform-specific Java-GI jar files. The Java bindings can provide the "lowest common denominator", i.e. always use int in Java when the native type is long. When allocating memory and calling native functions, the marshaling code can use the actual data type (32 or 64 bit) at runtime.

Investigation

It's probably useful to create a small tool that logs all occurences of long in the gir files so it will be possible to investigate the specific examples and how often they occur. If a specific situation is very uncommon, it may be best to simply exclude it from the Java bindings.

Runtime detection

We can detect at runtime what platform we're on, by adding a utility method Interop::longAsInt that returns true when sizeof(long) is 32 bit (i.e. on Windows). It is determined using:

<linker>.canonicalLayouts().get("long").equals(ValueLayout.JAVA_LONG)

The result can be stored in a static field for performance reasons.

Memory layouts

Generating memory layouts

For memory layouts with long fields, generate two layouts, one with 64-bit long fields (ValueLayout.JAVA_LONG) and one with 32-bit (ValueLayout.JAVA_INT). This can result in different padding. Calling getMemoryLayout() will return one of the two layouts.

Field accessors and Record allocators

Field read() and write() methods for long fields must always use int on all platforms.

  • Because the VarHandles use normal invoke behavior (as opposed to invokeExact behavior), the int values are widened automatically to long when appropriate (the VarHandle is created from the generated memory layout).
  • This prevents reading and writing actual long values (larger than Integer.MAX_VALUE) in Linux/MacOS, even though the C API allows it there, to preserve platform-independent behavior.

The Record constructors must override long parameters with int, but do not require any other changes.

Methods, Callbacks and Signals

Method invocation and parameter marshaling

When a method has long parameters or return value, generate two MethodHandle invocations, one for LLP64 (Windows) long values and one with LP64 (Linux/MacOS).

The LLP64 version can work as usual, assuming 32 bit sizes (int values) in Java and in C.

In the second version, long parameters and return values should be int in Java, but need a cast to long in the MethodHandle invocation.

  • long parameters must insert a (long) cast in the parameter list
  • long return values must prepend a (int) (long) cast (currently it is only a (long) cast).

Function descriptor

When generating a function descriptor with long parameters, generate those layouts with a ternary expression Interop.longAsInt() ? ValueLayout.LONG : ValueLayout.INT.

Aliases

Aliases (typedefs) for long do not seem to exist currently (in GNOME 46 gir files).

@jwharm jwharm self-assigned this Jun 8, 2024
@jwharm jwharm closed this as completed in 74795da Jul 14, 2024
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

No branches or pull requests

1 participant