mwe здесь: < /p>
Код: Выделить всё
ccb.c
Код: Выделить всё
#include
#include
typedef struct {
char const *s1;
char const *s2;
} S;
typedef void (*callback_fn)(S s, char const *data);
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
EXPORT extern void ccb(callback_fn fn) {
char const *data = "Let's be together, forever, we are never gonna be apart.";
fprintf(stderr, "(C) address of data = %p\n", (void*)data);
fn(
((S) {
"Shall I leave you be, Is it love if I can set you free?",
"But even it's not reality,",
}),
data
);
}
Код: Выделить всё
gcc.exe ccb.c -shared -fPIC -o ccb.dll
< /code>
или < /p>
cl.exe /utf-8 /nologo /LD /MD /DWIN32 /Zi ccb.c /Fe:ccb.dll /link User32.lib
< /code>
CCB.java
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
public final class CCB {
static final StructLayout LAYOUT$S = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_BYTE).withName("s1"),
ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_BYTE).withName("s2")
);
static final FunctionDescriptor DESCRIPTOR$ccb = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS.withName("fn"));
static final FunctionDescriptor DESCRIPTOR$callback = FunctionDescriptor.ofVoid(
LAYOUT$S.withName("s"),
ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_BYTE).withName("data")
);
static final MethodHandle hCCB;
static {
System.loadLibrary("ccb");
Linker linker = Linker.nativeLinker();
SymbolLookup stdlibLookup = linker.defaultLookup();
SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
MemorySegment pfnCCB = loaderLookup.find("ccb")
.or(() -> stdlibLookup.find("ccb"))
.orElse(MemorySegment.NULL);
if (pfnCCB.equals(MemorySegment.NULL)) {
throw new RuntimeException("Failed to find ccb symbol");
}
hCCB = linker.downcallHandle(pfnCCB, DESCRIPTOR$ccb);
}
static final class Ref {
T value;
}
@FunctionalInterface
interface MemorySegmentConsumer {
void accept(MemorySegment segment);
}
static void callback(
MemorySegmentConsumer consumer,
MemorySegment s,
MemorySegment data
) {
for (int i = 0; i < 2; i++) {
MemorySegment segment = s.getAtIndex(ValueLayout.ADDRESS, i).reinterpret(Long.MAX_VALUE);
System.err.println("(J) callback: s->s" + (i + 1) + " = " + segment.getString(0));
}
data = data.reinterpret(Long.MAX_VALUE);
System.err.println("(J) callback: data = " + data.getString(0));
System.err.println("(J) callback: address of data = " + Long.toUnsignedString(data.address(), 16));
consumer.accept(data);
}
public static void main(String[] args) {
Ref ref = new Ref();
MemorySegmentConsumer consumer = segment -> ref.value = segment;
try (Arena arena = Arena.ofConfined()) {
Linker linker = Linker.nativeLinker();
MethodHandle MH$callback = MethodHandles.lookup().findStatic(
CCB.class,
"callback",
DESCRIPTOR$callback.toMethodType().insertParameterTypes(0, MemorySegmentConsumer.class)
);
MemorySegment pfnCallback = linker.upcallStub(
MH$callback.bindTo(consumer),
DESCRIPTOR$callback,
arena
);
hCCB.invokeExact(pfnCallback);
System.err.println("(J) main: data = " + ref.value.getString(0)); //
Program output:
(J) callback: s->s1 = Shall I leave you be, Is it love if I can set you free?
(J) callback: s->s2 = But even it's not reality,
(J) callback: data = Let's be together, forever, we are never gonna be apart.
(J) callback: address of data = 7fffa5009000
Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalStateException: Already closed
at CCB.main(CCB.java:81)
Caused by: java.lang.IllegalStateException: Already closed
at java.base/jdk.internal.foreign.MemorySessionImpl.alreadyClosed(MemorySessionImpl.java:318)
at java.base/jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError.newRuntimeException(ScopedMemoryAccess.java:114)
at java.base/jdk.internal.misc.ScopedMemoryAccess.getLongUnaligned(ScopedMemoryAccess.java:2574)
at java.base/jdk.internal.foreign.StringSupport.strlenByte(StringSupport.java:142)
at java.base/jdk.internal.foreign.StringSupport.readByte(StringSupport.java:71)
at java.base/jdk.internal.foreign.StringSupport.read(StringSupport.java:54)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.getString(AbstractMemorySegmentImpl.java:907)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.getString(AbstractMemorySegmentImpl.java:900)
at CCB.main(CCB.java:79)
(C) address of data = 00007fffa5009000
< /code>
And when observed from IDE:

Such behavior is not observed when there's only pointer parameters, and not observed when the structure is smaller (only 1 pointer size).
Also, this behavior is not observed on Linux:

Is this some kind of deliberate design, technical limitation or bug?
Подробнее здесь: https://stackoverflow.com/questions/797 ... -accepting