RFR: 7903649: Field and global variables of array type should have indexed accessors

Maurizio Cimadamore mcimadamore at openjdk.org
Mon Jan 29 17:40:51 UTC 2024


This PR adds support for indexed accessors for struct fields and global variables whose type is an array type. These accessors feature a number of `long` access coordinates which has the same cardinality as that of the underlying array type.

For instance, consider the following global variable declaration:


int ints[2][3][4];


For this, jextract now emits:


    private static SequenceLayout ints$LAYOUT() {
        class Holder {
            static final SequenceLayout LAYOUT = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(3, MemoryLayout.sequenceLayout(4, foo_h.C_INT)));
        }
        return Holder.LAYOUT;
    }

    private static MemorySegment ints$SEGMENT() {
        class Holder {
            static final MemorySegment SEGMENT = foo_h.findOrThrow("ints")
                .reinterpret(ints$LAYOUT().byteSize());
        }
        return Holder.SEGMENT;
    }

    /**
     * Getter for variable:
     * {@snippet lang=c :
     * int ints[2][3][4]
     * }
     */
    public static MemorySegment ints() {
        return ints$SEGMENT();
    }

    /**
     * Setter for variable:
     * {@snippet lang=c :
     * int ints[2][3][4]
     * }
     */
    public static void ints(MemorySegment varValue) {
        MemorySegment.copy(varValue, 0L, ints$SEGMENT(), 0L, ints$LAYOUT().byteSize());
    }

    private static VarHandle ints$ELEM_HANDLE() {
        class Holder {
            static final VarHandle HANDLE = ints$LAYOUT().varHandle(sequenceElement(), sequenceElement(), sequenceElement());
        }
        return Holder.HANDLE;
    }

    /**
     * Indexed getter for variable:
     * {@snippet lang=c :
     * int ints[2][3][4]
     * }
     */
    public static int ints(long index0, long index1, long index2) {
        return (int)ints$ELEM_HANDLE().get(ints$SEGMENT(), 0L, index0, index1, index2);
    }

    /**
     * Indexed setter for variable:
     * {@snippet lang=c :
     * int ints[2][3][4]
     * }
     */
    public static void ints(long index0, long index1, long index2, int varValue) {
        ints$ELEM_HANDLE().set(ints$SEGMENT(), 0L, index0, index1, index2, varValue);
    }


If the array element type is a struct, different code needs to be generated. Consider this global variable declaration:


struct Point { int x; int y; } points[2][3][4];


This generates the following:


    private static SequenceLayout points$LAYOUT() {
        class Holder {
            static final SequenceLayout LAYOUT = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(3, MemoryLayout.sequenceLayout(4, Point.layout())));
        }
        return Holder.LAYOUT;
    }

    private static MemorySegment points$SEGMENT() {
        class Holder {
            static final MemorySegment SEGMENT = foo_h.findOrThrow("points")
                .reinterpret(points$LAYOUT().byteSize());
        }
        return Holder.SEGMENT;
    }

    /**
     * Getter for variable:
     * {@snippet lang=c :
     * struct Point points[2][3][4]
     * }
     */
    public static MemorySegment points() {
        return points$SEGMENT();
    }

    /**
     * Setter for variable:
     * {@snippet lang=c :
     * struct Point points[2][3][4]
     * }
     */
    public static void points(MemorySegment varValue) {
        MemorySegment.copy(varValue, 0L, points$SEGMENT(), 0L, points$LAYOUT().byteSize());
    }

    private static MethodHandle points$ELEM_HANDLE() {
        class Holder {
            static final MethodHandle HANDLE = points$LAYOUT().sliceHandle(sequenceElement(), sequenceElement(), sequenceElement());
        }
        return Holder.HANDLE;
    }

    /**
     * Indexed getter for variable:
     * {@snippet lang=c :
     * struct Point points[2][3][4]
     * }
     */
    public static MemorySegment points(long index0, long index1, long index2) {
        try {
            return (MemorySegment)points$ELEM_HANDLE().invokeExact(points$SEGMENT(), 0L, index0, index1, index2);
        } catch (Throwable ex$) {
            throw new AssertionError("should not reach here", ex$);
        }
    }

    /**
     * Indexed setter for variable:
     * {@snippet lang=c :
     * struct Point points[2][3][4]
     * }
     */
    public static void points(long index0, long index1, long index2, MemorySegment varValue) {
        MemorySegment.copy(varValue, 0L, points(index0, index1, index2), 0L, Point.layout().byteSize());
    }


(note that bulk copy is used for the setter).

For struct fields, we generate similar code - the only difference is that the var/method handle for accessing the array element is declared in a plain field (instead of using the holder idiom), similarly to what happens with other struct declarations. Note also that, for structs, the indexed accessors must receive an additional `MemorySegment` parameter (the segment struct being accessed).

-------------

Commit messages:
 - Initial push

Changes: https://git.openjdk.org/jextract/pull/198/files
 Webrev: https://webrevs.openjdk.org/?repo=jextract&pr=198&range=00
  Issue: https://bugs.openjdk.org/browse/CODETOOLS-7903649
  Stats: 522 lines in 8 files changed: 502 ins; 9 del; 11 mod
  Patch: https://git.openjdk.org/jextract/pull/198.diff
  Fetch: git fetch https://git.openjdk.org/jextract.git pull/198/head:pull/198

PR: https://git.openjdk.org/jextract/pull/198


More information about the jextract-dev mailing list