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