FFM(Foreign Function & Memory)
可以调用外部的函数比如,native的lib中的函数
外部函数调用,以naitve的stdlib中的函数为例
// strlen
Linker linker = abi.nativeLinker();
MethodHandle strlen = abi.downcallHandle(
abi.defaultLookup().find("strlen").orElseThrow(),
// 返回值 是 long 参数是地址
FunctionDescriptor.of(JAVA_LONG, ADDRESS)
);
try (Arena arena = Arena.ofConfined()) {
// 创建Hello的char[]这种值
MemorySegment str = arena.allocateUtf8String("Hello");
long len = (long) strlen.invokeExact(str); // 5
System.out.println(len);
} catch (Throwable e) {
throw new RuntimeException(e);
}
// qsrot 参数是array 返回值也是array
final AddressLayout C_POINTER = ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE));
// qsort函数
MethodHandle qsort = abi.downcallHandle(abi.defaultLookup().find("qsort").get(),
FunctionDescriptor.ofVoid(C_POINTER, JAVA_LONG, JAVA_LONG, C_POINTER));
FunctionDescriptor qsortComparFunction = FunctionDescriptor.of(JAVA_INT,
C_POINTER.withTargetLayout(JAVA_INT), C_POINTER.withTargetLayout(JAVA_INT));
MethodHandle qsortCompar = MethodHandles.lookup().findStatic(
Demo1.class,"qsortCompare",qsortComparFunction.toMethodType()
);
int[] arr = new int[]{4,3,2,1,4,3};
//init native array
try (var arena = Arena.ofConfined()) {
MemorySegment nativeArr = arena.allocateArray(JAVA_INT, arr);
//call qsort
MemorySegment qsortUpcallStub = abi.upcallStub(qsortCompar, qsortComparFunction, arena);
qsort.invokeExact(nativeArr, (long)arr.length, JAVA_INT.byteSize(), qsortUpcallStub);
//convert back to Java array
System.out.println(Arrays.toString(nativeArr.toArray(JAVA_INT)));
} catch (Throwable e) {
throw new RuntimeException(e);
}
内存操作
基本的值类型
MemoryLayout seq = MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT);
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(seq);;
VarHandle indexHandle = seq.varHandle(MemoryLayout.PathElement.sequenceElement());
// init segment
for (int i = 0 ; i < 10 ; i++) {
indexHandle.set(segment, (long)i, i);
}
//check statically indexed handles
for (int i = 0 ; i < 10 ; i++) {
VarHandle preindexHandle = seq.varHandle(MemoryLayout.PathElement.sequenceElement(i));
int expected = (int)indexHandle.get(segment, (long)i);
int found = (int)preindexHandle.get(segment);
assert expected == found;
}
}
// slice
VarHandle byteHandle = ValueLayout.JAVA_BYTE.arrayElementVarHandle();
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(10, 1);
//init
for (byte i = 0 ; i < segment.byteSize() ; i++) {
byteHandle.set(segment, (long)i, i);
}
for (int offset = 0 ; offset < 10 ; offset++) {
MemorySegment slice = segment.asSlice(offset);
for (long i = offset ; i < 10 ; i++) {
assert byteHandle.get(segment, i) == byteHandle.get(slice, i - offset);
}
}
}