Quantcast
Channel: Active questions tagged methodhandle - Stack Overflow
Viewing all articles
Browse latest Browse all 36

Weird behaviour of Java MethodHandle.invokeExact

$
0
0

Here is a minimal working example (requires Java 22 or later):

(just using libc free for elaborating the behaviour)

import java.lang.foreign.*;import java.lang.invoke.MethodHandle;public class Main {    public static final Linker nativeLinker = Linker.nativeLinker();    public static final SymbolLookup stdlibLookup = nativeLinker.defaultLookup();    public static final SymbolLookup loaderLookup = SymbolLookup.loaderLookup();    private static final FunctionDescriptor DESCRIPTOR$free = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS);    private static final MethodHandle HANDLE$free =            loaderLookup.find("free")                    .or(() -> stdlibLookup.find("free"))                    .map(symbolSegment -> nativeLinker.downcallHandle(symbolSegment, DESCRIPTOR$free))                    .orElseThrow(() -> new RuntimeException("libc function free not found but y?"));    public static void free(MemorySegment address) {        try {            // I want to allow user code to use Java null and MemorySegment.NULL (C NULL) interchangeably            HANDLE$free.invokeExact(address != null ? address : MemorySegment.NULL);        } catch (Throwable throwable) {            throwable.printStackTrace(System.err);        }    }    public static void main(String[] args) {        free(null); // free(MemorySegment.NULL) will produce same result    }}

Run program and there will be an exception:

java.lang.invoke.WrongMethodTypeException: handle's method type (MemorySegment)void but found (Object)void    at java.base/java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:521)    at java.base/java.lang.invoke.Invokers.checkExactType(Invokers.java:530)    at Main.free(Main.java:19)    at Main.main(Main.java:26)

Java complains that the argument used to call invokeExact is an Object, not MemorySegment. However, the expression

address != null ? address : MemorySegment.NULL

should have type MemorySegment of course. And if we make a small modification to the code:

    public static void free(MemorySegment address) {        try {            MemorySegment temp = address != null ? address : MemorySegment.NULL;            HANDLE$free.invokeExact(temp);        } catch (Throwable throwable) {            throwable.printStackTrace(System.err);        }    }

it works correctly.

Also

  • HANDLE$free.invoke(address != null ? address : MemorySegment.NULL) works
  • HANDLE$free.invokeExact((MemorySegment)(address != null ? address : MemorySegment.NULL)) works, but
  • HANDLE$free.invokeExact((address != null ? address : MemorySegment.NULL)) does not work

Is this some kind of deliberate design, implementation limitation or JVM bugs?


Viewing all articles
Browse latest Browse all 36

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>