Skip to content
Permalink
Browse files
8252700: jextract ignores typedef to undefined structs
Reviewed-by: mcimadamore
  • Loading branch information
sundararajana committed Sep 4, 2020
1 parent 2407b9d commit 8eee4edaec86d60e93e037c7cbe401cd07b29b82
@@ -27,6 +27,7 @@
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.jextract.Declaration;
import jdk.incubator.jextract.Type;

import javax.tools.JavaFileObject;
@@ -40,14 +41,15 @@
* method is called to get overall generated source string.
*/
class HeaderBuilder extends JavaSourceBuilder {

private final AnnotationWriter annotationWriter;
protected final StringBuffer sb;

// current line alignment (number of 4-spaces)
private int align;

HeaderBuilder(String className, String pkgName, ConstantHelper constantHelper) {
HeaderBuilder(String className, String pkgName, ConstantHelper constantHelper, AnnotationWriter annotationWriter) {
super(className, pkgName, constantHelper);
this.annotationWriter = annotationWriter;
this.sb = new StringBuffer();
}

@@ -194,23 +196,61 @@ private boolean primitiveKindSupported(Type.Primitive.Kind kind) {
};
}

void emitTypedef(String className, String superClassName) {
void emitTypedef(Declaration.Typedef td, String superClassName) {
String className = td.name();
boolean superClassExists = superClassName != null;
incrAlign();
indent();
append(PUB_MODS);
append("class ");
append(annotationWriter.getCAnnotation(td.type()));
append(" class ");
String uniqueName = uniqueNestedClassName(className);
append(uniqueName);
append(" extends ");
append(superClassName);
if (superClassExists) {
append(" extends ");
append(superClassName);
}
append(" {\n");

incrAlign();
indent();
// private constructor
append("private ");
append(uniqueName);
append("() {}\n");
decrAlign();

// typedef of incomplete struct/union
// generate a class with just allocatePointer methods with right annotation
if (!superClassExists) {
String anno = annotationWriter.getCAnnotation(Type.pointer(td.type()));
// allocatePointer
incrAlign();
indent();
append(PUB_MODS);
append(anno + " MemorySegment allocatePointer() {\n");
incrAlign();
indent();
append("return MemorySegment.allocateNative(C_POINTER);\n");
decrAlign();
indent();
append("}\n");
decrAlign();

// allocatePointer (scope version)
incrAlign();
indent();
append(PUB_MODS);
append(anno + " MemorySegment allocatePointer(NativeScope scope) {\n");
incrAlign();
indent();
append("return scope.allocate(C_POINTER);\n");
decrAlign();
indent();
append("}\n");
decrAlign();
}

indent();
append("}\n");
decrAlign();
@@ -64,7 +64,7 @@ public class OutputFactory implements Declaration.Visitor<Void, Declaration> {
protected JavaSourceBuilder currentBuilder;
protected final ConstantHelper constantHelper;
protected final TypeTranslator typeTranslator = new TypeTranslator();
protected final AnnotationWriter annotationWriter = new AnnotationWriter();
protected final AnnotationWriter annotationWriter;
private final String pkgName;
private final Map<Declaration, String> structClassNames = new HashMap<>();
private final Set<Declaration.Typedef> unresolvedStructTypedefs = new HashSet<>();
@@ -98,15 +98,18 @@ public static JavaFileObject[] generateWrapped(Declaration.Scoped decl, String h
ConstantHelper constantHelper = ConstantHelper.make(source, qualName,
ClassDesc.of(pkgName, "RuntimeHelper"), ClassDesc.of("jdk.incubator.foreign", "CSupport"),
libraryNames.toArray(String[]::new));
return new OutputFactory(pkgName,
new HeaderBuilder(clsName, pkgName, constantHelper), constantHelper).generate(decl);
AnnotationWriter annotationWriter = new AnnotationWriter();
HeaderBuilder headerBuilder = new HeaderBuilder(clsName, pkgName, constantHelper, annotationWriter);
return new OutputFactory(pkgName, headerBuilder, constantHelper, annotationWriter).generate(decl);
}

private OutputFactory(String pkgName, HeaderBuilder toplevelBuilder, ConstantHelper constantHelper) {
private OutputFactory(String pkgName, HeaderBuilder toplevelBuilder, ConstantHelper constantHelper,
AnnotationWriter annotationWriter) {
this.pkgName = pkgName;
this.toplevelBuilder = toplevelBuilder;
this.currentBuilder = toplevelBuilder;
this.constantHelper = constantHelper;
this.annotationWriter = annotationWriter;
}

private static String getCLangConstantsHolder() {
@@ -133,9 +136,7 @@ JavaFileObject[] generate(Declaration.Scoped decl) {
// check if unresolved typedefs can be resolved now!
for (Declaration.Typedef td : unresolvedStructTypedefs) {
Declaration.Scoped structDef = ((Type.Declared)td.type()).tree();
if (structDefinitionSeen(structDef)) {
toplevelBuilder.emitTypedef(td.name(), structDefinitionName(structDef));
}
toplevelBuilder.emitTypedef(td, structDefinitionSeen(structDef)? structDefinitionName(structDef) : null);
}
toplevelBuilder.classEnd();
try {
@@ -216,9 +217,8 @@ public Void visitScoped(Declaration.Scoped d, Declaration parent) {
String className = d.name().isEmpty() ? parent.name() : d.name();
MemoryLayout parentLayout = parentLayout(d);
String parentLayoutFieldName = className + "$struct";
String anno = annotationWriter.getCAnnotation(Type.declared(d));
String arrayAnno = annotationWriter.getCAnnotation(Type.array(Type.declared(d)));
currentBuilder = new StructBuilder(currentBuilder, className, parentLayoutFieldName, parentLayout, pkgName, constantHelper, anno, arrayAnno);
currentBuilder = new StructBuilder(currentBuilder, className, parentLayoutFieldName, parentLayout,
pkgName, constantHelper, annotationWriter, Type.declared(d));
addStructDefinition(d, currentBuilder.className);
currentBuilder.incrAlign();
currentBuilder.classBegin();
@@ -373,7 +373,7 @@ public Void visitTypedef(Declaration.Typedef tree, Declaration parent) {
* };
*/
if (structDefinitionSeen(s)) {
toplevelBuilder.emitTypedef(tree.name(), structDefinitionName(s));
toplevelBuilder.emitTypedef(tree, structDefinitionName(s));
} else {
/*
* Definition of typedef'ed struct/union not seen yet. May be the definition comes later.
@@ -26,6 +26,8 @@

import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.jextract.Declaration;
import jdk.incubator.jextract.Type;

/**
* This class generates static utilities class for C structs, unions.
@@ -37,15 +39,17 @@ class StructBuilder extends JavaSourceBuilder {
private final MemoryLayout parentLayout;
private final String structAnno;
private final String structArrayAnno;
private final String structPtrAnno;

StructBuilder(JavaSourceBuilder prev, String className, String parentLayoutFieldName, MemoryLayout parentLayout, String pkgName,
ConstantHelper constantHelper, String structAnno, String structArrayAnno) {
StructBuilder(JavaSourceBuilder prev, String className, String parentLayoutFieldName, MemoryLayout parentLayout,
String pkgName, ConstantHelper constantHelper, AnnotationWriter annotationWriter, Type structType) {
super(prev.uniqueNestedClassName(className), pkgName, constantHelper);
this.prev = prev;
this.parentLayoutFieldName = parentLayoutFieldName;
this.parentLayout = parentLayout;
this.structAnno = structAnno;
this.structArrayAnno = structArrayAnno;
this.structAnno = annotationWriter.getCAnnotation(structType);
this.structArrayAnno = annotationWriter.getCAnnotation(Type.array(structType));
this.structPtrAnno = annotationWriter.getCAnnotation(Type.pointer(structType));
}

JavaSourceBuilder prev() {
@@ -104,6 +108,8 @@ JavaSourceBuilder classEnd() {
emitScopeAllocate();
emitAllocateArray();
emitScopeAllocateArray();
emitAllocatePoiner();
emitScopeAllocatePointer();
return super.classEnd();
}

@@ -191,6 +197,7 @@ void addSegmentGetter(String javaName, String nativeName, MemoryLayout layout) {
indent();
append("}\n");
decrAlign();

}

private void emitSizeof() {
@@ -224,9 +231,10 @@ private void emitAllocateArray() {
append(structArrayAnno + " MemorySegment allocateArray(int len) {\n");
incrAlign();
indent();
append("return MemorySegment.allocateNative(MemoryLayout.ofSequence(len, $LAYOUT()));");
append("return MemorySegment.allocateNative(MemoryLayout.ofSequence(len, $LAYOUT()));\n");
decrAlign();
append("}\n");
indent();
append('}');
decrAlign();
}

@@ -237,8 +245,37 @@ private void emitScopeAllocateArray() {
append(structArrayAnno + " MemorySegment allocateArray(int len, NativeScope scope) {\n");
incrAlign();
indent();
append("return scope.allocate(MemoryLayout.ofSequence(len, $LAYOUT()));");
append("return scope.allocate(MemoryLayout.ofSequence(len, $LAYOUT()));\n");
decrAlign();
indent();
append("}\n");
decrAlign();
}

private void emitAllocatePoiner() {
incrAlign();
indent();
append(PUB_MODS);
append(structPtrAnno + " MemorySegment allocatePointer() {\n");
incrAlign();
indent();
append("return MemorySegment.allocateNative(C_POINTER);\n");
decrAlign();
indent();
append("}\n");
decrAlign();
}

private void emitScopeAllocatePointer() {
incrAlign();
indent();
append(PUB_MODS);
append(structPtrAnno + " MemorySegment allocatePointer(NativeScope scope) {\n");
incrAlign();
indent();
append("return scope.allocate(C_POINTER);\n");
decrAlign();
indent();
append("}\n");
decrAlign();
}
@@ -21,8 +21,9 @@
* questions.
*/

import java.lang.reflect.Method;
import java.nio.file.Path;

import jdk.incubator.foreign.NativeScope;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertNotNull;
@@ -47,9 +48,13 @@ public void testTypedefs() {
Class<?> cls = loader.loadClass("test8245767_h");
assertNotNull(cls);

// no class should be generated for typedef on opaque struct
// class should be generated for typedef on opaque struct
Class<?> fooCls = loader.loadClass("test8245767_h$Foo");
assertNull(fooCls);
assertNotNull(fooCls);
Method alloc = findMethod(fooCls, "allocatePointer");
assertNotNull(alloc);
alloc = findMethod(fooCls, "allocatePointer", NativeScope.class);
assertNotNull(alloc);

// check Point_t
Class<?> point_tCls = loader.loadClass("test8245767_h$Point_t");
@@ -27,6 +27,7 @@
import java.lang.reflect.Parameter;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeScope;
import java.nio.file.Path;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
@@ -57,6 +58,10 @@ public void test() throws Throwable {
checkGlobalFunctions(headerClass);
checkGlobalVariables(headerClass);

Class<?> fooTypedefClass = loader.loadClass("test8252634_h$Foo");
checkAnnotation(fooTypedefClass, "struct foo");
checkFooAllocatePointer(fooTypedefClass);

Class<?> pointClass = loader.loadClass("test8252634_h$Point");
checkPointGetters(pointClass);
checkPointSetters(pointClass);
@@ -117,8 +122,23 @@ private void checkPointSetters(Class<?> pointClass) throws Throwable {
private void checkPointAllocate(Class<?> pointClass) throws Throwable {
Method allocate = findMethod(pointClass, "allocate");
checkAnnotation(allocate.getAnnotatedReturnType(), "struct Point");
allocate = findMethod(pointClass, "allocate", NativeScope.class);
checkAnnotation(allocate.getAnnotatedReturnType(), "struct Point");
Method allocateArray = findMethod(pointClass, "allocateArray", int.class);
checkAnnotation(allocateArray.getAnnotatedReturnType(), "struct Point[]");
allocateArray = findMethod(pointClass, "allocateArray", int.class, NativeScope.class);
checkAnnotation(allocateArray.getAnnotatedReturnType(), "struct Point[]");
Method allocatePointer = findMethod(pointClass, "allocatePointer");
checkAnnotation(allocatePointer.getAnnotatedReturnType(), "struct Point*");
allocatePointer = findMethod(pointClass, "allocatePointer", NativeScope.class);
checkAnnotation(allocatePointer.getAnnotatedReturnType(), "struct Point*");
}

private void checkFooAllocatePointer(Class<?> fooClass) throws Throwable {
Method allocatePointer = findMethod(fooClass, "allocatePointer");
checkAnnotation(allocatePointer.getAnnotatedReturnType(), "struct foo*");
allocatePointer = findMethod(fooClass, "allocatePointer", NativeScope.class);
checkAnnotation(allocatePointer.getAnnotatedReturnType(), "struct foo*");
}

private void checkAnnotation(AnnotatedElement ae, String expected) throws Throwable {
@@ -36,6 +36,8 @@ void func(int (*callback)(int));
typedef int* int_ptr;
int_ptr p;

typedef struct foo Foo;

#ifdef __cplusplus
}
#endif // __cplusplus

0 comments on commit 8eee4ed

Please sign in to comment.