Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.graal.python.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface DowncallSignature {
NativeSimpleType returnType();

NativeSimpleType[] argumentTypes() default {};

Class<?> retConversion() default void.class;

Class<?>[] argConversions() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.graal.python.runtime.nativeaccess;
package com.oracle.graal.python.annotations;

/**
* Simple native carrier types used by native access signatures.
Expand All @@ -55,5 +55,5 @@ public enum NativeSimpleType {
SINT64,
FLOAT,
DOUBLE,
RAW_POINTER; // arg must be long, retval is long
POINTER; // raw pointer represented in Java as a long
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
com.oracle.graal.python.processor.ArgumentClinicProcessor
com.oracle.graal.python.processor.GenerateEnumConstantsProcessor
com.oracle.graal.python.processor.GenerateNativeDowncallsProcessor
com.oracle.graal.python.processor.CApiBuiltinsProcessor
com.oracle.graal.python.processor.SlotsProcessor
com.oracle.graal.python.processor.SlotsProcessor
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
*/
package com.oracle.graal.python.processor;

import static com.oracle.graal.python.processor.NativeDowncallMethodHandleGenerator.argName;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -86,6 +88,7 @@
import com.oracle.graal.python.annotations.CApiFields;
import com.oracle.graal.python.annotations.CApiStructs;
import com.oracle.graal.python.annotations.CApiUpcallTarget;
import com.oracle.graal.python.annotations.NativeSimpleType;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
Expand Down Expand Up @@ -291,10 +294,6 @@ private String capiTypeToForeignPrimitiveType(VariableElement element) {
return type.equals("void") ? "void" : ("j" + type);
}

private static String argName(int i) {
return "" + (char) ('a' + i);
}

private static final String CAPI_BUILTIN = "com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin";
private static final String CAPI_BUILTINS = "com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltins";
private static final String CAPI_WRAPPER_DESCRIPTOR = "com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CApiWrapperDescriptor";
Expand Down Expand Up @@ -1261,21 +1260,6 @@ private TypeMirror toJavaNfiType(TypeMirror typeMirror) {
return processingEnv.getTypeUtils().getPrimitiveType(TypeKind.LONG);
}

private static String getNativeMethodHandleVarName(String signatureName) {
return "NATIVE_METHOD_HANDLE_" + signatureName;
}

private static String toClassLiteral(String javaType) {
return switch (javaType) {
case "void" -> "void.class";
case "int" -> "int.class";
case "long" -> "long.class";
case "float" -> "float.class";
case "double" -> "double.class";
default -> throw new IllegalArgumentException("Unexpected Java type: " + javaType);
};
}

private boolean isCannotRaise(VariableElement signature) {
String externalFunctionSignatureInitializer = getExternalFunctionSignatureInitializer(signature);
int start = externalFunctionSignatureInitializer.indexOf('(');
Expand Down Expand Up @@ -1348,7 +1332,6 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
assert sig.returnType != null;
assert sig.argumentTypes != null;
String returnType = toJavaNfiType(sig.returnType);
String returnTypeLiteral = toClassLiteral(returnType);
List<String> argTypes = Arrays.stream(sig.argumentTypes).map(this::toJavaNfiType).toList();

boolean isVoidReturn = "void".equals(returnType);
Expand Down Expand Up @@ -1381,14 +1364,7 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
for (String argType : argTypes) {
typedArgs.add(argType + " " + argName(i++));
}

List<String> methodTypeArgs = new ArrayList<>();
methodTypeArgs.add("long.class");
for (String argType : argTypes) {
methodTypeArgs.add(toClassLiteral(argType));
}
lines.add(" private static final MethodHandle " + getNativeMethodHandleVarName(sig.name) + " = NativeAccessSupport.createDowncallHandle(" +
"MethodType.methodType(" + returnTypeLiteral + ", " + String.join(", ", methodTypeArgs) + "), false);");
NativeDowncallMethodHandleGenerator.emitMethodHandleField(lines, NativeDowncallMethodHandleGenerator.methodHandleVarName(sig.name), returnType, argTypes);

lines.add("");
if (sig.cannotRaise) {
Expand Down Expand Up @@ -1464,9 +1440,9 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
lines.add(" public static " + returnType + " invoke" + sig.name + "(" + String.join(", ", rawInvokeArgs) + ") throws Throwable {");
String directArgExpr = cArgs.isEmpty() ? "function" : "function, " + String.join(", ", cArgs);
if (isVoidReturn) {
lines.add(" " + getNativeMethodHandleVarName(sig.name) + ".invokeExact(" + directArgExpr + ");");
lines.add(" " + NativeDowncallMethodHandleGenerator.methodHandleVarName(sig.name) + ".invokeExact(" + directArgExpr + ");");
} else {
lines.add(" return (" + returnType + ") " + getNativeMethodHandleVarName(sig.name) + ".invokeExact(" + directArgExpr + ");");
lines.add(" return (" + returnType + ") " + NativeDowncallMethodHandleGenerator.methodHandleVarName(sig.name) + ".invokeExact(" + directArgExpr + ");");
}
lines.add(" }");
}
Expand Down Expand Up @@ -1504,6 +1480,7 @@ private void generateNativeAccessSupport(Element[] origins) throws IOException {
lines.add("import java.util.OptionalLong;");
lines.add("");
lines.add("import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere;");
lines.add("import " + NativeSimpleType.class.getCanonicalName() + ";");
lines.add("");
lines.add("public final class " + NATIVE_ACCESS_SUPPORT_IMPL_CLASS_NAME + " extends " + NATIVE_ACCESS_SUPPORT_CLASS_NAME + " {");
lines.add(" private static final MethodHandle OF_ADDRESS;");
Expand Down Expand Up @@ -1604,7 +1581,7 @@ private void generateNativeAccessSupport(Element[] origins) throws IOException {
lines.add(" case SINT64 -> ValueLayout.JAVA_LONG;");
lines.add(" case FLOAT -> ValueLayout.JAVA_FLOAT;");
lines.add(" case DOUBLE -> ValueLayout.JAVA_DOUBLE;");
lines.add(" case RAW_POINTER -> ValueLayout.JAVA_LONG;");
lines.add(" case POINTER -> ValueLayout.JAVA_LONG;");
lines.add(" };");
lines.add(" }");
lines.add("}");
Expand All @@ -1626,6 +1603,8 @@ private void generateDummyNativeAccessSupport(Element[] origins) throws IOExcept
lines.add("import java.lang.invoke.MethodHandle;");
lines.add("import java.lang.invoke.MethodType;");
lines.add("");
lines.add("import " + NativeSimpleType.class.getCanonicalName() + ";");
lines.add("");
lines.add("public final class " + NATIVE_ACCESS_SUPPORT_IMPL_CLASS_NAME + " extends " + NATIVE_ACCESS_SUPPORT_CLASS_NAME + " {");
lines.add(" @Override");
lines.add(" protected Object createArenaImpl() {");
Expand Down
Loading
Loading