Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8261906: Improve jextract support for virtual functions #456

Closed
wants to merge 13 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
@@ -66,24 +66,24 @@ public Constant addLayout(String javaName, MemoryLayout layout) {
() -> emitLayoutField(javaName, layout));
}

public Constant addFieldVarHandle(String javaName, String nativeName, MemoryLayout layout,
Class<?> type, String rootJavaName, List<String> prefixElementNames) {
return addVarHandle(javaName, nativeName, layout, type, rootJavaName, prefixElementNames);
public Constant addFieldVarHandle(String javaName, String nativeName, VarInfo varInfo,
String rootJavaName, List<String> prefixElementNames) {
return addVarHandle(javaName, nativeName, varInfo, rootJavaName, prefixElementNames);
}

public Constant addGlobalVarHandle(String javaName, String nativeName, MemoryLayout layout, Class<?> type) {
return addVarHandle(javaName, nativeName, layout, type, null, List.of());
public Constant addGlobalVarHandle(String javaName, String nativeName, VarInfo varInfo) {
return addVarHandle(javaName, nativeName, varInfo, null, List.of());
}

private Constant addVarHandle(String javaName, String nativeName, MemoryLayout layout, Class<?> type,
private Constant addVarHandle(String javaName, String nativeName, VarInfo varInfo,
String rootLayoutName, List<String> prefixElementNames) {
return emitIfAbsent(javaName, Constant.Kind.VAR_HANDLE,
() -> emitVarHandleField(javaName, nativeName, type, layout, rootLayoutName, prefixElementNames));
() -> emitVarHandleField(javaName, nativeName, varInfo, rootLayoutName, prefixElementNames));
}

public Constant addMethodHandle(String javaName, String nativeName, MethodType mtype, FunctionDescriptor desc, boolean varargs) {
public Constant addMethodHandle(String javaName, String nativeName, FunctionInfo functionInfo, boolean virtual) {
return emitIfAbsent(javaName, Constant.Kind.METHOD_HANDLE,
() -> emitMethodHandleField(javaName, nativeName, mtype, desc, varargs));
() -> emitMethodHandleField(javaName, nativeName, functionInfo, virtual));
}

public Constant addSegment(String javaName, String nativeName, MemoryLayout layout) {
@@ -141,7 +141,7 @@ String fieldName(String javaName) {
this.kind = kind;
}

private List<String> getterNameParts() {
List<String> getterNameParts() {
return List.of(className, javaName, kind.nameSuffix);
}

@@ -185,25 +185,26 @@ public Constant emitIfAbsent(String name, Constant.Kind kind, Supplier<Constant>
return constant;
}

private Constant emitMethodHandleField(String javaName, String nativeName, MethodType mtype,
FunctionDescriptor desc, boolean varargs) {
Constant functionDesc = addFunctionDesc(javaName, desc);
private Constant emitMethodHandleField(String javaName, String nativeName, FunctionInfo functionInfo, boolean virtual) {
Constant functionDesc = addFunctionDesc(javaName, functionInfo.descriptor());
incrAlign();
String fieldName = Constant.Kind.METHOD_HANDLE.fieldName(javaName);
indent();
append(memberMods() + "MethodHandle ");
append(fieldName + " = RuntimeHelper.downcallHandle(\n");
incrAlign();
indent();
append("LIBRARIES, \"" + nativeName + "\"");
append(",\n");
indent();
append("\"" + mtype.toMethodDescriptorString() + "\",\n");
if (!virtual) {
append("LIBRARIES, \"" + nativeName + "\"");
append(",\n");
indent();
}
append("\"" + functionInfo.methodType().toMethodDescriptorString() + "\",\n");
indent();
append(functionDesc.accessExpression());
append(", ");
// isVariadic
append(varargs);
append(functionInfo.isVarargs());
append("\n");
decrAlign();
indent();
@@ -212,13 +213,13 @@ private Constant emitMethodHandleField(String javaName, String nativeName, Metho
return new Constant(className(), javaName, Constant.Kind.METHOD_HANDLE);
}

private Constant emitVarHandleField(String javaName, String nativeName, Class<?> type, MemoryLayout layout,
private Constant emitVarHandleField(String javaName, String nativeName, VarInfo varInfo,
String rootLayoutName, List<String> prefixElementNames) {
String layoutAccess = rootLayoutName != null ?
Constant.Kind.LAYOUT.fieldName(rootLayoutName) :
addLayout(javaName, layout).accessExpression();
addLayout(javaName, varInfo.layout()).accessExpression();
incrAlign();
String typeName = type.getName();
String typeName = varInfo.carrier().getName();
boolean isAddr = typeName.contains("MemoryAddress");
if (isAddr) {
typeName = "long";
@@ -30,6 +30,8 @@
import jdk.internal.jextract.impl.ConstantBuilder.Constant;

import java.lang.invoke.MethodType;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class FunctionalInterfaceBuilder extends NestedClassBuilder {

@@ -49,6 +51,7 @@
JavaSourceBuilder classEnd() {
emitFunctionalInterfaceMethod();
emitFunctionalFactories();
emitFunctionalRestrictedFactory();
return super.classEnd();
}

@@ -91,4 +94,60 @@ private void emitFunctionalFactories() {
decrAlign();
});
}

private void emitFunctionalRestrictedFactory() {
emitWithConstantClass(className(), constantBuilder -> {
Constant mhConstant = constantBuilder.addMethodHandle(className(), className(), FunctionInfo.ofFunctionPointer(fiType, fiDesc), true);
incrAlign();
indent();
append(MEMBER_MODS + " " + className() + " ofAddressRestricted(MemoryAddress addr) {\n");
incrAlign();
indent();
append("return new " + className() + "() {\n");
incrAlign();
indent();
append("public " + fiType.returnType().getName() + " apply(");
String delim = "";
for (int i = 0 ; i < fiType.parameterCount(); i++) {
append(delim + fiType.parameterType(i).getName() + " x" + i);
delim = ", ";
}
append(") {\n");
incrAlign();
indent();
append("try {\n");
incrAlign();
indent();
if (!fiType.returnType().equals(void.class)) {
append("return (" + fiType.returnType().getName() + ")");
}
append(mhConstant.accessExpression() + ".invokeExact((Addressable)addr");
if (fiType.parameterCount() > 0) {
String params = IntStream.range(0, fiType.parameterCount())
.mapToObj(i -> "x" + i)
.collect(Collectors.joining(", "));
append(", " + params);
}
append(");\n");
decrAlign();
indent();
append("} catch (Throwable ex$) {\n");
incrAlign();
indent();
append("throw new AssertionError(\"should not reach here\", ex$);\n");
decrAlign();
indent();
append("}\n");
decrAlign();
indent();
append("}\n");
decrAlign();
indent();
append("};\n");
decrAlign();
indent();
append("}\n");
decrAlign();
});
}
}
@@ -60,32 +60,35 @@ String superClass() {
}

@Override
public void addVar(String javaName, String nativeName, MemoryLayout layout, Class<?> type) {
if (type.equals(MemorySegment.class)) {
public void addVar(String javaName, String nativeName, VarInfo varInfo) {
if (varInfo.carrier().equals(MemorySegment.class)) {
emitWithConstantClass(javaName, constantBuilder -> {
constantBuilder.addSegment(javaName, nativeName, layout)
constantBuilder.addSegment(javaName, nativeName, varInfo.layout())
.emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME, nativeName);
});
} else {
emitWithConstantClass(javaName, constantBuilder -> {
constantBuilder.addLayout(javaName, layout)
constantBuilder.addLayout(javaName, varInfo.layout())
.emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME);
Constant vhConstant = constantBuilder.addGlobalVarHandle(javaName, nativeName, layout, type)
Constant vhConstant = constantBuilder.addGlobalVarHandle(javaName, nativeName, varInfo)
.emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME);
Constant segmentConstant = constantBuilder.addSegment(javaName, nativeName, layout)
Constant segmentConstant = constantBuilder.addSegment(javaName, nativeName, varInfo.layout())
.emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME, nativeName);
emitGlobalGetter(segmentConstant, vhConstant, javaName, nativeName, type);
emitGlobalSetter(segmentConstant, vhConstant, javaName, nativeName, type);
emitGlobalGetter(segmentConstant, vhConstant, javaName, nativeName, varInfo.carrier());
emitGlobalSetter(segmentConstant, vhConstant, javaName, nativeName, varInfo.carrier());
if (varInfo.fiName().isPresent()) {
emitFunctionalInterfaceGetter(varInfo.fiName().get(), javaName);
}
});
}
}

@Override
public void addFunction(String javaName, String nativeName, MethodType mtype, FunctionDescriptor desc, boolean varargs, List<String> paramNames) {
public void addFunction(String javaName, String nativeName, FunctionInfo functionInfo) {
emitWithConstantClass(javaName, constantBuilder -> {
Constant mhConstant = constantBuilder.addMethodHandle(javaName, nativeName, mtype, desc, varargs)
Constant mhConstant = constantBuilder.addMethodHandle(javaName, nativeName, functionInfo, false)
.emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME, nativeName);
emitFunctionWrapper(mhConstant, javaName, nativeName, mtype, varargs, paramNames);
emitFunctionWrapper(mhConstant, javaName, nativeName, functionInfo);
});
}

@@ -115,33 +118,33 @@ public void addTypedef(String name, String superClass, Type type) {

// private generation

private void emitFunctionWrapper(Constant mhConstant, String javaName, String nativeName, MethodType mtype,
boolean varargs, List<String> paramNames) {
private void emitFunctionWrapper(Constant mhConstant, String javaName, String nativeName, FunctionInfo functionInfo) {
incrAlign();
indent();
append(MEMBER_MODS + " ");
append(mtype.returnType().getSimpleName() + " " + javaName + " (");
append(functionInfo.methodType().returnType().getSimpleName() + " " + javaName + " (");
String delim = "";
List<String> pExprs = new ArrayList<>();
List<String> paramNames = functionInfo.parameterNames().get();
final int numParams = paramNames.size();
for (int i = 0 ; i < numParams; i++) {
String pName = paramNames.get(i);
if (pName.isEmpty()) {
pName = "x" + i;
}
if (mtype.parameterType(i).equals(MemoryAddress.class)) {
if (functionInfo.methodType().parameterType(i).equals(MemoryAddress.class)) {
pExprs.add(pName + ".address()");
} else {
pExprs.add(pName);
}
Class<?> pType = mtype.parameterType(i);
Class<?> pType = functionInfo.methodType().parameterType(i);
if (pType.equals(MemoryAddress.class)) {
pType = Addressable.class;
}
append(delim + " " + pType.getSimpleName() + " " + pName);
delim = ", ";
}
if (varargs) {
if (functionInfo.isVarargs()) {
String lastArg = "x" + numParams;
if (numParams > 0) {
append(", ");
@@ -161,8 +164,8 @@ private void emitFunctionWrapper(Constant mhConstant, String javaName, String na
append("try {\n");
incrAlign();
indent();
if (!mtype.returnType().equals(void.class)) {
append("return (" + mtype.returnType().getName() + ")");
if (!functionInfo.methodType().returnType().equals(void.class)) {
append("return (" + functionInfo.methodType().returnType().getName() + ")");
}
append("mh$.invokeExact(" + String.join(", ", pExprs) + ");\n");
decrAlign();
@@ -180,6 +183,20 @@ private void emitFunctionWrapper(Constant mhConstant, String javaName, String na
decrAlign();
}

private void emitFunctionalInterfaceGetter(String fiName, String javaName) {
incrAlign();
indent();
append(MEMBER_MODS + " ");
append(fiName + " " + javaName + " () {\n");
incrAlign();
indent();
append("return " + fiName + ".ofAddressRestricted(" + javaName + "$get());\n");
decrAlign();
indent();
append("}\n");
decrAlign();
}

private void emitPrimitiveTypedef(Type.Primitive primType, String name) {
Type.Primitive.Kind kind = primType.kind();
if (primitiveKindSupported(kind) && !kind.layout().isEmpty()) {
@@ -35,6 +35,7 @@
import java.lang.invoke.MethodType;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;

@@ -120,11 +121,40 @@ JavaSourceBuilder classEnd() {

// public API (used by OutputFactory)

public void addVar(String javaName, String nativeName, MemoryLayout layout, Class<?> type) {
public static record FunctionInfo(
MethodType methodType,
FunctionDescriptor descriptor,
boolean isVarargs,
Optional<List<String>> parameterNames) {

static FunctionInfo ofFunction(MethodType methodType, FunctionDescriptor functionDescriptor, boolean isVarargs, List<String> parameterNames) {
return new FunctionInfo(methodType, functionDescriptor, isVarargs, Optional.of(parameterNames));
}

static FunctionInfo ofFunctionPointer(MethodType methodType, FunctionDescriptor functionDescriptor) {
return new FunctionInfo(methodType, functionDescriptor, false, Optional.empty());
}
}

public static record VarInfo(
Class<?> carrier,
MemoryLayout layout,
Optional<String> fiName) {

static VarInfo ofVar(Class<?> carrier, MemoryLayout layout) {
return new VarInfo(carrier, layout, Optional.empty());
}

static VarInfo ofFunctionalPointerVar(Class<?> carrier, MemoryLayout layout, String fiName) {
return new VarInfo(carrier, layout, Optional.ofNullable(fiName));
}
}

public void addVar(String javaName, String nativeName, VarInfo varInfo) {
throw new UnsupportedOperationException();
}

public void addFunction(String javaName, String nativeName, MethodType mtype, FunctionDescriptor desc, boolean varargs, List<String> paramNames) {
public void addFunction(String javaName, String nativeName, FunctionInfo functionInfo) {
throw new UnsupportedOperationException();
}

@@ -140,10 +170,12 @@ public StructBuilder addStruct(String name, Declaration parent, GroupLayout layo
return new StructBuilder(this, name.isEmpty() ? parent.name() : name, layout, type);
}

public void addFunctionalInterface(String name, MethodType mtype, FunctionDescriptor desc) {
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name, mtype, desc);
public String addFunctionalInterface(String name, FunctionInfo functionInfo) {
FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name,
functionInfo.methodType(), functionInfo.descriptor());
builder.classBegin();
builder.classEnd();
return builder.fullName();
}

public List<JavaFileObject> toFiles() {
Loading