Some issues on jextract generation.

Sundararajan Athijegannathan sundararajan.athijegannathan at oracle.com
Wed Apr 20 12:05:06 UTC 2022


C enums are not always used as enums strictly. Sometimes values are OR'ed or AND'ed and passed around as int value. That's accepted by C compiler even if the value of the outside the specified enum constants. Mapping those to Java enum will break those idioms when C code is ported to Java. Java user may have to call enum ordinal value method to achieve the same.

-Sundar
________________________________
From: panama-dev <panama-dev-retn at openjdk.java.net> on behalf of dede <andmarco at cgocable.ca>
Sent: 18 April 2022 00:48
To: panama-dev at openjdk.java.net <panama-dev at openjdk.java.net>
Subject: Some issues on jextract generation.

Hi, we have these issues for you:

1) Why you do not generate all the enum like the class:
   org.openjdk.jextract.clang.CursorKind   (CXCursorKind)
   inside: include/clang-c/Index.h -> enum CXCursorKind...
   and the result for method (by example) is like this:
   CXCursorKind clang_getCursorKind(CXCursor C);
     And not : public static int clang_getCursorKind ( MemorySegment x0);
     (But this is possible to keep the two ways).
and:
   org.openjdk.jextract.clang.TypeKind (CXTypeKind)
   inside: include/clang-c/Index.h -> enum CXTypeKind...
   and the result for method (by example) is like this:
   CXString clang_getTypeKindSpelling(SegmentAllocator allocator, CXTypeKind K);
and: CallingConvention, ...
     and CursorLanguage (particular, handly modified)
and:
   when this enum is declared inside a structure,
   we have just to use it directly.

2) When we have a generated structure, all of these have:
      -a $struct$LAYOUT.
      -data that depends of a MemorySegment.
   By example: (this is an example)
   public class GLFWvidmode {
     static final  GroupLayout $struct$LAYOUT =
        MemoryLayout.structLayout(
        Constants$root.C_LONG$LAYOUT.withName("width"), ...
     ).withName("GLFWvidmode");
     public static MemoryLayout $LAYOUT() {
        return GLFWvidmode.$struct$LAYOUT;
     }
     static final VarHandle width$VH =
        $struct$LAYOUT.varHandle(MemoryLayout.PathElement
        .groupElement("width"));
      public static VarHandle width$VH() {
        return GLFWvidmode.width$VH;
      }
      public static int width$get(MemorySegment seg) {
        return (int)GLFWvidmode.width$VH.get(seg);
      }
      public static void width$set(MemorySegment seg, int x) {
        GLFWvidmode.width$VH.set(seg, x);
      }
      ...
      // Just to add this attribute:
      protected MemorySegment nativeObj;
      // Add these constructors:
      public GLFWvidmode(final MemorySegment nativeObj) {
          this.nativeObj = Objects.requireNonNull(nativeObj);
      }
      public GLFWvidmode(final ResourceScope scope) {
          this(MemorySegment.allocateNative(
              Objects.requireNonNull($struct$LAYOUT),
              Objects.requireNonNullElse(scope,
                 ResourceScope.globalScope())));
      }
      public GLFWvidmode(final MemoryAddress memoryAddress,
            final ResourceScope scope) {
        // if memoryAddress is NULL then new GLFWvidmode(scope);
        this(MemorySegment.ofAddress(memAddress,
            $struct$LAYOUT.byteSize(),
            Objects.requireNonNullElse(scope,
               ResourceScope.globalScope())));
      }
     ...
      public MemorySegment getNativeObj()  {
         // When we need that for special case.
         return this.nativeObj;
      }
      ...
      // Just to add these methods at this class:
      public int getWidth() {
         return width$get(this.nativeObj);
      }
      public int setWidth(int v) {
         width$set(this.nativeObj, v);
      }
      ...
      +We have a special case, this is when we have slice method.
      But this can be solved easily because this is an array
      (or an unmodifiable List) of Object.
      -The class org.zjv.foreign.natives.clang.CXToken is a good example:
      public static MemorySegment int_data$slice(MemorySegment seg) {
        return seg.asSlice(0, 16);
      }
      // We know this is a primitive array:
      public int[] get_int_data() {
        return int_data$slice(this.nativeObj).toArray(C_INT);
      }
      -When this is not a primitive but Object, this can be:
      public Something[] getSomethings() { // Not efficient.
        MemorySegment seg = something$slice(this.nativeObj);
        int dataSize = (int) Something.sizeof();
        int arraySize = seg.byteSize() / dataSize;
        Something[] array = new Something[arraySize];
        for (int i = 0; i < arraySize; i++) {
            array[i] = new Something(seg.asSlice(i*dataSize);
        }
        return array;
      } // This will be better if we use something like Iterator....
      -If this is a slice of Pointer (MemoryAddress) the
       ResourceScope is necessary to convert address to segment.
       (MemorySegment.NULL not exist)...
    Other improvements are possible.

3) Finally for CPP classes, the native object is not a MemorySegment
   but a MemoryAddress. The remainder stays the same.
   We will try to generate a CPP wrapper and makefile for that.

Thank you in advance.



More information about the panama-dev mailing list