Skip to content

Commit ac0b4a1

Browse files
committedOct 29, 2021
8276136: functional interface extraction broken after API refresh
Reviewed-by: jvernee
1 parent 2bfc3e4 commit ac0b4a1

File tree

9 files changed

+67
-64
lines changed

9 files changed

+67
-64
lines changed
 

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/FunctionalInterfaceBuilder.java

+20-6
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ public class FunctionalInterfaceBuilder extends ClassSourceBuilder {
3939
private static final String MEMBER_MODS = "static";
4040

4141
private final MethodType fiType;
42+
private final MethodType downcallType;
4243
private final FunctionDescriptor fiDesc;
4344

4445
FunctionalInterfaceBuilder(JavaSourceBuilder enclosing, String className,
45-
MethodType fiType, FunctionDescriptor fiDesc) {
46+
FunctionInfo functionInfo) {
4647
super(enclosing, Kind.INTERFACE, className);
47-
this.fiType = fiType;
48-
this.fiDesc = fiDesc;
48+
this.fiType = functionInfo.methodType();
49+
this.downcallType = functionInfo.reverseMethodType();
50+
this.fiDesc = functionInfo.descriptor();
4951
}
5052

5153
@Override
@@ -90,14 +92,14 @@ private void emitFunctionalFactories() {
9092

9193
private void emitFunctionalFactoryForPointer() {
9294
emitWithConstantClass(constantBuilder -> {
93-
Constant mhConstant = constantBuilder.addMethodHandle(className(), className(), FunctionInfo.ofFunctionPointer(fiType, fiDesc), true);
95+
Constant mhConstant = constantBuilder.addMethodHandle(className(), className(), FunctionInfo.ofFunctionPointer(downcallType, fiType, fiDesc), true);
9496
incrAlign();
9597
indent();
9698
append(MEMBER_MODS + " " + className() + " ofAddress(MemoryAddress addr, ResourceScope scope) {\n");
9799
incrAlign();
98100
indent();
99101
append("NativeSymbol symbol = NativeSymbol.ofAddress(");
100-
append("\"" + className() + "::\" + Long.toHexString(addr.toRawLongValue()), addr, scope);");
102+
append("\"" + className() + "::\" + Long.toHexString(addr.toRawLongValue()), addr, scope);\n");
101103
append("return (");
102104
String delim = "";
103105
for (int i = 0 ; i < fiType.parameterCount(); i++) {
@@ -112,11 +114,23 @@ private void emitFunctionalFactoryForPointer() {
112114
indent();
113115
if (!fiType.returnType().equals(void.class)) {
114116
append("return (" + fiType.returnType().getName() + ")");
117+
if (fiType.returnType() != downcallType.returnType()) {
118+
// add cast for invokeExact
119+
append("(" + downcallType.returnType().getName() + ")");
120+
}
115121
}
116122
append(mhConstant.accessExpression() + ".invokeExact(symbol");
117123
if (fiType.parameterCount() > 0) {
118124
String params = IntStream.range(0, fiType.parameterCount())
119-
.mapToObj(i -> "x" + i)
125+
.mapToObj(i -> {
126+
String paramExpr = "x" + i;
127+
if (fiType.parameterType(i) != downcallType.parameterType(i)) {
128+
// add cast for invokeExact
129+
return "(" + downcallType.parameterType(i).getName() + ")" + paramExpr;
130+
} else {
131+
return paramExpr;
132+
}
133+
})
120134
.collect(Collectors.joining(", "));
121135
append(", " + params);
122136
}

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/HeaderFileBuilder.java

-3
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ private List<String> emitFunctionWrapperDecl(String javaName, MethodType methodT
192192
}
193193
pExprs.add(pName);
194194
Class<?> pType = methodType.parameterType(i);
195-
if (pType.equals(MemoryAddress.class)) {
196-
pType = Addressable.class;
197-
}
198195
append(delim + " " + pType.getSimpleName() + " " + pName);
199196
delim = ", ";
200197
}

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/JavaSourceBuilder.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ public abstract class JavaSourceBuilder {
4747

4848
public static record FunctionInfo(
4949
MethodType methodType,
50+
MethodType reverseMethodType,
5051
FunctionDescriptor descriptor,
5152
boolean isVarargs,
5253
Optional<List<String>> parameterNames) {
5354

5455
static FunctionInfo ofFunction(MethodType methodType, FunctionDescriptor functionDescriptor, boolean isVarargs, List<String> parameterNames) {
55-
return new FunctionInfo(methodType, functionDescriptor, isVarargs, Optional.of(parameterNames));
56+
return new FunctionInfo(methodType, null, functionDescriptor, isVarargs, Optional.of(parameterNames));
5657
}
5758

58-
static FunctionInfo ofFunctionPointer(MethodType methodType, FunctionDescriptor functionDescriptor) {
59-
return new FunctionInfo(methodType, functionDescriptor, false, Optional.empty());
59+
static FunctionInfo ofFunctionPointer(MethodType upcallType, MethodType downcallType, FunctionDescriptor functionDescriptor) {
60+
return new FunctionInfo(upcallType, downcallType, functionDescriptor, false, Optional.empty());
6061
}
6162
}
6263

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/OutputFactory.java

+8-20
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public Void visitConstant(Declaration.Constant constant, Declaration parent) {
190190
}
191191
toplevelBuilder.addConstant(Utils.javaSafeIdentifier(constant.name()),
192192
constant.value() instanceof String ? MemorySegment.class :
193-
typeTranslator.getJavaType(constant.type()), constant.value());
193+
getJavaType(constant.type()), constant.value());
194194
return null;
195195
}
196196

@@ -228,7 +228,7 @@ public Void visitScoped(Declaration.Scoped d, Declaration parent) {
228228
}
229229

230230
private String generateFunctionalInterface(Type.Function func, String name) {
231-
return functionInfo(func, name, false, FunctionInfo::ofFunctionPointer)
231+
return functionInfo(func, name, false, (mtype, desc) -> FunctionInfo.ofFunctionPointer(mtype, getMethodType(func, true), desc))
232232
.map(fInfo -> currentBuilder.addFunctionalInterface(Utils.javaSafeIdentifier(name), fInfo))
233233
.orElse(null);
234234
}
@@ -432,7 +432,7 @@ public Void visitVariable(Declaration.Variable tree, Declaration parent) {
432432
return null;
433433
}
434434

435-
private Optional<FunctionInfo> functionInfo(Type.Function funcPtr, String nativeName, boolean allowVarargs,
435+
private Optional<FunctionInfo> functionInfo(Type.Function funcPtr, String nativeName, boolean downcall,
436436
BiFunction<MethodType, FunctionDescriptor, FunctionInfo> functionInfoFactory) {
437437
FunctionDescriptor descriptor = Type.descriptorFor(funcPtr).orElse(null);
438438
if (descriptor == null) {
@@ -441,7 +441,7 @@ private Optional<FunctionInfo> functionInfo(Type.Function funcPtr, String native
441441
}
442442

443443
//generate functional interface
444-
if (!allowVarargs && funcPtr.varargs() && !funcPtr.argumentTypes().isEmpty()) {
444+
if (!downcall && funcPtr.varargs() && !funcPtr.argumentTypes().isEmpty()) {
445445
warn("varargs in callbacks is not supported: " + funcPtr);
446446
return Optional.empty();
447447
}
@@ -453,7 +453,7 @@ private Optional<FunctionInfo> functionInfo(Type.Function funcPtr, String native
453453
return Optional.empty();
454454
}
455455

456-
MethodType mtype = getMethodType(funcPtr, allowVarargs);
456+
MethodType mtype = getMethodType(funcPtr, downcall);
457457
return mtype != null ?
458458
Optional.of(functionInfoFactory.apply(mtype, descriptor)) :
459459
Optional.empty();
@@ -477,7 +477,7 @@ static void warn(String msg) {
477477

478478
private Class<?> getJavaType(Type type) {
479479
try {
480-
return typeTranslator.getJavaType(type);
480+
return typeTranslator.getJavaType(type, false);
481481
} catch (UnsupportedOperationException uoe) {
482482
warn(uoe.toString());
483483
if (JextractTool.DEBUG) {
@@ -487,21 +487,9 @@ private Class<?> getJavaType(Type type) {
487487
}
488488
}
489489

490-
private MethodType getMethodType(Type.Function type) {
490+
private MethodType getMethodType(Type.Function type, boolean downcall) {
491491
try {
492-
return typeTranslator.getMethodType(type);
493-
} catch (UnsupportedOperationException uoe) {
494-
warn(uoe.toString());
495-
if (JextractTool.DEBUG) {
496-
uoe.printStackTrace();
497-
}
498-
return null;
499-
}
500-
}
501-
502-
private MethodType getMethodType(Type.Function type, boolean varargsCheck) {
503-
try {
504-
return typeTranslator.getMethodType(type, varargsCheck);
492+
return typeTranslator.getMethodType(type, downcall);
505493
} catch (UnsupportedOperationException uoe) {
506494
warn(uoe.toString());
507495
if (JextractTool.DEBUG) {

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/StructBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public StructBuilder addStruct(String name, Declaration parent, GroupLayout layo
116116

117117
@Override
118118
public String addFunctionalInterface(String name, FunctionInfo functionInfo) {
119-
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name, functionInfo.methodType(), functionInfo.descriptor());
119+
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name, functionInfo);
120120
builder.classBegin();
121121
builder.classEnd();
122122
return builder.className();

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/ToplevelBuilder.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ public StructBuilder addStruct(String name, Declaration parent, GroupLayout layo
125125

126126
@Override
127127
public String addFunctionalInterface(String name, FunctionInfo functionInfo) {
128-
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this,
129-
name, functionInfo.methodType(), functionInfo.descriptor());
128+
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name, functionInfo);
130129
builders.add(builder);
131130
builder.classBegin();
132131
builder.classEnd();

‎src/jdk.incubator.jextract/share/classes/jdk/internal/jextract/impl/TypeTranslator.java

+22-29
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
package jdk.internal.jextract.impl;
2727

28+
import jdk.incubator.foreign.Addressable;
2829
import jdk.incubator.foreign.ValueLayout;
2930
import jdk.incubator.jextract.Type.Primitive;
3031
import jdk.incubator.jextract.Type;
@@ -34,9 +35,9 @@
3435

3536
import java.lang.invoke.MethodType;
3637

37-
public class TypeTranslator implements Type.Visitor<Class<?>, Void> {
38+
public class TypeTranslator implements Type.Visitor<Class<?>, Boolean> {
3839
@Override
39-
public Class<?> visitPrimitive(Type.Primitive t, Void aVoid) {
40+
public Class<?> visitPrimitive(Type.Primitive t, Boolean isArg) {
4041
if (t.kind().layout().isEmpty()) {
4142
return void.class;
4243
} else {
@@ -74,32 +75,28 @@ static Class<?> layoutToClass(boolean fp, MemoryLayout layout) {
7475
}
7576

7677
@Override
77-
public Class<?> visitDelegated(Type.Delegated t, Void aVoid) {
78+
public Class<?> visitDelegated(Type.Delegated t, Boolean isArg) {
7879
return t.kind() == Type.Delegated.Kind.POINTER ?
79-
MemoryAddress.class :
80-
t.type().accept(this, null);
80+
(isArg ? Addressable.class : MemoryAddress.class) :
81+
t.type().accept(this, isArg);
8182
}
8283

8384
@Override
84-
public Class<?> visitFunction(Type.Function t, Void aVoid) {
85-
return MemoryAddress.class; // function pointer
85+
public Class<?> visitFunction(Type.Function t, Boolean isArg) {
86+
return isArg ? Addressable.class : MemoryAddress.class; // function pointer
8687
}
8788

8889
@Override
89-
public Class<?> visitDeclared(Type.Declared t, Void aVoid) {
90-
switch (t.tree().kind()) {
91-
case UNION:
92-
case STRUCT:
93-
return MemorySegment.class;
94-
case ENUM:
95-
return layoutToClass(false, t.tree().layout().orElseThrow(UnsupportedOperationException::new));
96-
default:
97-
throw new UnsupportedOperationException("declaration kind: " + t.tree().kind());
98-
}
90+
public Class<?> visitDeclared(Type.Declared t, Boolean isArg) {
91+
return switch (t.tree().kind()) {
92+
case UNION, STRUCT -> MemorySegment.class;
93+
case ENUM -> layoutToClass(false, t.tree().layout().orElseThrow(UnsupportedOperationException::new));
94+
default -> throw new UnsupportedOperationException("declaration kind: " + t.tree().kind());
95+
};
9996
}
10097

10198
@Override
102-
public Class<?> visitArray(Type.Array t, Void aVoid) {
99+
public Class<?> visitArray(Type.Array t, Boolean isArg) {
103100
if (t.kind() == Type.Array.Kind.VECTOR) {
104101
throw new UnsupportedOperationException("vector");
105102
} else {
@@ -108,24 +105,20 @@ public Class<?> visitArray(Type.Array t, Void aVoid) {
108105
}
109106

110107
@Override
111-
public Class<?> visitType(Type t, Void aVoid) {
108+
public Class<?> visitType(Type t, Boolean isArg) {
112109
throw new UnsupportedOperationException(t.getClass().toString());
113110
}
114111

115-
Class<?> getJavaType(Type t) {
116-
return t.accept(this, null);
117-
}
118-
119-
MethodType getMethodType(Type.Function type) {
120-
return getMethodType(type, true);
112+
Class<?> getJavaType(Type t, boolean isArg) {
113+
return t.accept(this, isArg);
121114
}
122115

123-
MethodType getMethodType(Type.Function type, boolean varargsCheck) {
124-
MethodType mtype = MethodType.methodType(getJavaType(type.returnType()));
116+
MethodType getMethodType(Type.Function type, boolean downcall) {
117+
MethodType mtype = MethodType.methodType(getJavaType(type.returnType(), !downcall));
125118
for (Type arg : type.argumentTypes()) {
126-
mtype = mtype.appendParameterTypes(getJavaType(arg));
119+
mtype = mtype.appendParameterTypes(getJavaType(arg, downcall));
127120
}
128-
if (varargsCheck && type.varargs()) {
121+
if (downcall && type.varargs()) {
129122
mtype = mtype.appendParameterTypes(Object[].class);
130123
}
131124
return mtype;

‎test/jdk/tools/jextract/funcPointerInvokers/TestFuncPointerInvokers.java

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* questions.
2222
*/
2323

24+
import jdk.incubator.foreign.MemoryAddress;
2425
import jdk.incubator.foreign.MemorySegment;
2526
import jdk.incubator.foreign.ResourceScope;
2627
import org.testng.annotations.Test;
@@ -130,4 +131,12 @@ public void testGlobalFIFunctionPointer() {
130131
assertEquals(val.get(), 42);
131132
}
132133
}
134+
135+
@Test
136+
public void testGlobalFIFunctionPointerAddress() {
137+
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
138+
fp_addr$set(fp_addr.allocate((addr) -> MemoryAddress.ofLong(addr.toRawLongValue() + 1), scope).address());
139+
assertEquals(fp_addr.ofAddress(fp_addr$get(), scope).apply(MemoryAddress.ofLong(42)), MemoryAddress.ofLong(43));
140+
}
141+
}
133142
}

‎test/jdk/tools/jextract/funcPointerInvokers/func.h

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct Baz {
4545

4646
EXPORT void (*fp)(int arg);
4747

48+
EXPORT int* (*fp_addr)(int *arg);
49+
4850
#ifdef __cplusplus
4951
}
5052
#endif // __cplusplus

0 commit comments

Comments
 (0)
Please sign in to comment.