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);
                }
            }
        }