From eff33a814c8f7c2d95e28b530e672b607eb2b13d Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Tue, 12 May 2026 10:56:02 +0200 Subject: [PATCH 01/10] Move NativeSimpleType to annotations package and rename RAW_POINTER to POINTER --- .../python/annotations}/NativeSimpleType.java | 4 +-- .../processor/CApiBuiltinsProcessor.java | 4 ++- .../test/builtin/objects/TpSlotsTests.java | 2 +- .../modules/cext/PythonCextBuiltins.java | 4 +-- .../objects/cext/capi/CApiContext.java | 25 +++++++++--------- .../objects/cext/capi/PyCFunctionWrapper.java | 10 +++---- .../objects/cext/capi/TpSlotWrapper.java | 26 +++++++++---------- .../cext/capi/transitions/ArgDescriptor.java | 14 +++++----- .../objects/cext/common/NativeCExtSymbol.java | 2 +- .../nativeaccess/NativeAccessSupport.java | 4 ++- .../NativeAccessSupportJdk21.java | 2 ++ .../runtime/nativeaccess/NativeContext.java | 14 +++++----- .../nativeaccess/NativeFunctionPointer.java | 1 + .../runtime/nativeaccess/NativeSignature.java | 1 + 14 files changed, 61 insertions(+), 52 deletions(-) rename graalpython/{com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess => com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations}/NativeSimpleType.java (95%) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSimpleType.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/NativeSimpleType.java similarity index 95% rename from graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSimpleType.java rename to graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/NativeSimpleType.java index c2d169efc3..d4750eba04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSimpleType.java +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/NativeSimpleType.java @@ -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. @@ -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 } diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java index fd18b0b0bf..f3d000abef 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java @@ -86,6 +86,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; @@ -1504,6 +1505,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;"); @@ -1604,7 +1606,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("}"); diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/objects/TpSlotsTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/objects/TpSlotsTests.java index f188f9974c..85c30f5d3f 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/objects/TpSlotsTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/objects/TpSlotsTests.java @@ -49,6 +49,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TpSlots.Builder; import com.oracle.graal.python.builtins.objects.type.TpSlots.TpSlotGroup; @@ -57,7 +58,6 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative; import com.oracle.graal.python.runtime.nativeaccess.NativeContext; import com.oracle.graal.python.runtime.nativeaccess.NativeFunctionPointer; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; import com.oracle.graal.python.util.Function; public class TpSlotsTests { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java index 68323f962f..b77f1de174 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java @@ -113,6 +113,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.CApiConstant; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.GraalPythonModuleBuiltins.DebugNode; @@ -192,7 +193,6 @@ import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.exception.PythonErrorType; import com.oracle.graal.python.runtime.nativeaccess.NativeSignature; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.MroSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeByteSequenceStorage; @@ -636,7 +636,7 @@ Object getErrorReturnValue() { case SINT64 -> -1L; case FLOAT -> -1.0f; case DOUBLE -> -1.0; - case RAW_POINTER -> NULLPTR; + case POINTER -> NULLPTR; }; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java index ce3b3aaa84..cee5f0aa77 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java @@ -46,11 +46,11 @@ import static com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.readIntField; import static com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.readLongField; import static com.oracle.graal.python.builtins.objects.object.PythonObject.IMMORTAL_REFCNT; -import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___FILE__; import static com.oracle.graal.python.nodes.StringLiterals.T_DASH; import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_STRING; import static com.oracle.graal.python.nodes.StringLiterals.T_UNDERSCORE; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -79,6 +79,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.CApiConstant; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.modules.cext.PythonCApiAssertions; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltinRegistry; @@ -111,14 +112,6 @@ import com.oracle.graal.python.builtins.objects.str.StringNodes; import com.oracle.graal.python.builtins.objects.str.StringUtils; import com.oracle.graal.python.builtins.objects.thread.PLock; -import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport; -import com.oracle.graal.python.runtime.nativeaccess.NativeContext; -import com.oracle.graal.python.runtime.nativeaccess.NativeFunctionPointer; -import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; -import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; -import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; -import com.oracle.graal.python.runtime.nativeaccess.NativeSignature; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.GetClassNode; @@ -131,6 +124,13 @@ import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport; +import com.oracle.graal.python.runtime.nativeaccess.NativeContext; +import com.oracle.graal.python.runtime.nativeaccess.NativeFunctionPointer; +import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; +import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; +import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; +import com.oracle.graal.python.runtime.nativeaccess.NativeSignature; import com.oracle.graal.python.util.ConcurrentWeakSet; import com.oracle.graal.python.util.Function; import com.oracle.graal.python.util.PythonSystemThreadTask; @@ -811,8 +811,8 @@ void runBackgroundGCTask(PythonContext context) { /** * Called from native threads before using the C API. Returns * {@link #GRAALPY_ATTACH_NATIVE_OWNED} if this method entered the context and a matching - * {@link #detachNativeThread()} is required, {@link #GRAALPY_ATTACH_NATIVE_FOREIGN} if the context - * was already active on this thread from Truffle/Java/Python, and + * {@link #detachNativeThread()} is required, {@link #GRAALPY_ATTACH_NATIVE_FOREIGN} if the + * context was already active on this thread from Truffle/Java/Python, and * {@link #GRAALPY_ATTACH_NATIVE_FAILED} if entering failed. */ private int attachNativeThread() { @@ -957,7 +957,8 @@ private static CApiContext loadCApi(Node node, PythonContext context, TruffleStr if (PythonContext.isCurrentThreadVirtual()) { throw new ApiInitException(ErrorMessages.NATIVE_EXTENSIONS_VIRTUAL_THREAD); } - // Check this before marking the API as loaded so that we don't get a different error the second time a C import is attempted + // Check this before marking the API as loaded so that we don't get a different error + // the second time a C import is attempted if (!NativeAccessSupport.isAvailable()) { throw new ImportException(null, name, path, toTruffleStringUncached(NativeContext.UNAVAILABLE)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyCFunctionWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyCFunctionWrapper.java index 8890221a5c..f0d2945329 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyCFunctionWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyCFunctionWrapper.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.annotations.CApiUpcallTarget; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonInternalNode; @@ -67,7 +68,6 @@ import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.nativeaccess.NativeSignature; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; @@ -86,10 +86,10 @@ */ public abstract class PyCFunctionWrapper { - private static final NativeSignature SIGNATURE_1_ARG = NativeSignature.create(NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER); - private static final NativeSignature SIGNATURE_2_ARG = NativeSignature.create(NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER); - private static final NativeSignature SIGNATURE_3_ARG = NativeSignature.create(NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER, - NativeSimpleType.RAW_POINTER); + private static final NativeSignature SIGNATURE_1_ARG = NativeSignature.create(NativeSimpleType.POINTER, NativeSimpleType.POINTER); + private static final NativeSignature SIGNATURE_2_ARG = NativeSignature.create(NativeSimpleType.POINTER, NativeSimpleType.POINTER, NativeSimpleType.POINTER); + private static final NativeSignature SIGNATURE_3_ARG = NativeSignature.create(NativeSimpleType.POINTER, NativeSimpleType.POINTER, NativeSimpleType.POINTER, + NativeSimpleType.POINTER); private static final MethodHandle HANDLE_UNARY; private static final MethodHandle HANDLE_BINARY; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/TpSlotWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/TpSlotWrapper.java index 5ac79f6293..33b269e2a5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/TpSlotWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/TpSlotWrapper.java @@ -40,11 +40,11 @@ */ package com.oracle.graal.python.builtins.objects.cext.capi; +import static com.oracle.graal.python.annotations.NativeSimpleType.POINTER; +import static com.oracle.graal.python.annotations.NativeSimpleType.SINT32; +import static com.oracle.graal.python.annotations.NativeSimpleType.SINT64; import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.checkThrowableBeforeNative; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; -import static com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType.RAW_POINTER; -import static com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType.SINT32; -import static com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType.SINT64; import static com.oracle.graal.python.util.PythonUtils.EMPTY_OBJECT_ARRAY; import java.lang.invoke.MethodHandle; @@ -104,16 +104,16 @@ public abstract class TpSlotWrapper { - private static final NativeSignature SIGNATURE_P_P = NativeSignature.create(RAW_POINTER, RAW_POINTER); - private static final NativeSignature SIGNATURE_P_PP = NativeSignature.create(RAW_POINTER, RAW_POINTER, RAW_POINTER); - private static final NativeSignature SIGNATURE_P_PPP = NativeSignature.create(RAW_POINTER, RAW_POINTER, RAW_POINTER, RAW_POINTER); - private static final NativeSignature SIGNATURE_P_PPI = NativeSignature.create(RAW_POINTER, RAW_POINTER, RAW_POINTER, SINT32); - private static final NativeSignature SIGNATURE_P_PL = NativeSignature.create(RAW_POINTER, RAW_POINTER, SINT64); - private static final NativeSignature SIGNATURE_I_P = NativeSignature.create(SINT32, RAW_POINTER); - private static final NativeSignature SIGNATURE_I_PP = NativeSignature.create(SINT32, RAW_POINTER, RAW_POINTER); - private static final NativeSignature SIGNATURE_I_PPP = NativeSignature.create(SINT32, RAW_POINTER, RAW_POINTER, RAW_POINTER); - private static final NativeSignature SIGNATURE_I_PLP = NativeSignature.create(SINT32, RAW_POINTER, SINT64, RAW_POINTER); - private static final NativeSignature SIGNATURE_L_P = NativeSignature.create(SINT64, RAW_POINTER); + private static final NativeSignature SIGNATURE_P_P = NativeSignature.create(POINTER, POINTER); + private static final NativeSignature SIGNATURE_P_PP = NativeSignature.create(POINTER, POINTER, POINTER); + private static final NativeSignature SIGNATURE_P_PPP = NativeSignature.create(POINTER, POINTER, POINTER, POINTER); + private static final NativeSignature SIGNATURE_P_PPI = NativeSignature.create(POINTER, POINTER, POINTER, SINT32); + private static final NativeSignature SIGNATURE_P_PL = NativeSignature.create(POINTER, POINTER, SINT64); + private static final NativeSignature SIGNATURE_I_P = NativeSignature.create(SINT32, POINTER); + private static final NativeSignature SIGNATURE_I_PP = NativeSignature.create(SINT32, POINTER, POINTER); + private static final NativeSignature SIGNATURE_I_PPP = NativeSignature.create(SINT32, POINTER, POINTER, POINTER); + private static final NativeSignature SIGNATURE_I_PLP = NativeSignature.create(SINT32, POINTER, SINT64, POINTER); + private static final NativeSignature SIGNATURE_L_P = NativeSignature.create(SINT64, POINTER); private static final MethodHandle HANDLE_GET_ATTR; private static final MethodHandle HANDLE_BINARY_SLOT_FUNC; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ArgDescriptor.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ArgDescriptor.java index 5414762822..ca6f0fc009 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ArgDescriptor.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/ArgDescriptor.java @@ -40,6 +40,7 @@ */ package com.oracle.graal.python.builtins.objects.cext.capi.transitions; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.FromLongNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ToNativeBorrowedNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ToPythonStringNode; @@ -52,30 +53,29 @@ import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtToJavaNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtToNativeNode; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; import com.oracle.graal.python.util.Supplier; enum ArgBehavior { PyObject( - NativeSimpleType.RAW_POINTER, + NativeSimpleType.POINTER, PythonToNativeNode::create, NativeToPythonNode::create, NativeToPythonNode.getUncached(), PythonToNativeNewRefNode::create, NativeToPythonTransferNode::create, NativeToPythonTransferNode.getUncached()), - PyObjectBorrowed(NativeSimpleType.RAW_POINTER, ToNativeBorrowedNode::new, NativeToPythonNode::create, NativeToPythonNode.getUncached(), null, null, null), - PyObjectAsTruffleString(NativeSimpleType.RAW_POINTER, null, ToPythonStringNode::create, ToPythonStringNode.getUncached(), null, null, null), + PyObjectBorrowed(NativeSimpleType.POINTER, ToNativeBorrowedNode::new, NativeToPythonNode::create, NativeToPythonNode.getUncached(), null, null, null), + PyObjectAsTruffleString(NativeSimpleType.POINTER, null, ToPythonStringNode::create, ToPythonStringNode.getUncached(), null, null, null), PyTypeObject( - NativeSimpleType.RAW_POINTER, + NativeSimpleType.POINTER, PythonToNativeNode::create, NativeToPythonClassNode::create, NativeToPythonClassNode.getUncached(), PythonToNativeNewRefNode::create, NativeToPythonTransferNode::create, NativeToPythonTransferNode.getUncached()), - Pointer(NativeSimpleType.RAW_POINTER), - TruffleStringPointer(NativeSimpleType.RAW_POINTER, null, CharPtrToPythonNode::create, CharPtrToPythonNode.getUncached()), + Pointer(NativeSimpleType.POINTER), + TruffleStringPointer(NativeSimpleType.POINTER, null, CharPtrToPythonNode::create, CharPtrToPythonNode.getUncached()), Char8(NativeSimpleType.SINT8), UChar8(NativeSimpleType.SINT8), Char16(NativeSimpleType.SINT16), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/NativeCExtSymbol.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/NativeCExtSymbol.java index e6833a9631..d6981aab03 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/NativeCExtSymbol.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/NativeCExtSymbol.java @@ -40,10 +40,10 @@ */ package com.oracle.graal.python.builtins.objects.cext.common; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor; import com.oracle.graal.python.runtime.nativeaccess.NativeContext; import com.oracle.graal.python.runtime.nativeaccess.NativeFunctionPointer; -import com.oracle.graal.python.runtime.nativeaccess.NativeSimpleType; import com.oracle.truffle.api.strings.TruffleString; public interface NativeCExtSymbol { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupport.java index 2bc1692b5e..f0caf3e8d1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupport.java @@ -46,6 +46,8 @@ import org.graalvm.nativeimage.ImageInfo; +import com.oracle.graal.python.annotations.NativeSimpleType; + public abstract class NativeAccessSupport { private static final NativeAccessSupport INSTANCE = createImpl(); @@ -78,7 +80,7 @@ protected static Class asJavaType(NativeSimpleType type) { case SINT64 -> long.class; case FLOAT -> float.class; case DOUBLE -> double.class; - case RAW_POINTER -> long.class; + case POINTER -> long.class; }; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupportJdk21.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupportJdk21.java index 506e0f1029..d19c26e267 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupportJdk21.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeAccessSupportJdk21.java @@ -43,6 +43,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; +import com.oracle.graal.python.annotations.NativeSimpleType; + final class NativeAccessSupportJdk21 extends NativeAccessSupport { @Override protected Object createArenaImpl() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java index 6c54eeda78..7ad51b2330 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java @@ -44,6 +44,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -145,17 +146,16 @@ private static boolean isWindows() { private static final int RTLD_LAZY = 1; private static final int RTLD_NOW = 2; - private static final MethodHandle DLOPEN = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.RAW_POINTER, NativeSimpleType.SINT32); + private static final MethodHandle DLOPEN = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.POINTER, NativeSimpleType.SINT32); private static final MethodHandle DLCLOSE = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32, NativeSimpleType.SINT64); - private static final MethodHandle DLSYM = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.SINT64, NativeSimpleType.RAW_POINTER); - private static final MethodHandle LOAD_LIBRARY_EX = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.RAW_POINTER, NativeSimpleType.RAW_POINTER, + private static final MethodHandle DLSYM = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.SINT64, NativeSimpleType.POINTER); + private static final MethodHandle LOAD_LIBRARY_EX = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.POINTER, NativeSimpleType.POINTER, NativeSimpleType.SINT32); private static final MethodHandle FREE_LIBRARY = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32, NativeSimpleType.SINT64); - private static final MethodHandle GET_PROC_ADDRESS = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.SINT64, NativeSimpleType.RAW_POINTER); + private static final MethodHandle GET_PROC_ADDRESS = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.SINT64, NativeSimpleType.POINTER); private static final MethodHandle GET_LAST_ERROR = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32); - private static final MethodHandle FORMAT_MESSAGE = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32, NativeSimpleType.SINT32, NativeSimpleType.RAW_POINTER, NativeSimpleType.SINT32, - NativeSimpleType.SINT32, - NativeSimpleType.RAW_POINTER, NativeSimpleType.SINT32, NativeSimpleType.RAW_POINTER); + private static final MethodHandle FORMAT_MESSAGE = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32, NativeSimpleType.SINT32, NativeSimpleType.POINTER, NativeSimpleType.SINT32, + NativeSimpleType.SINT32, NativeSimpleType.POINTER, NativeSimpleType.SINT32, NativeSimpleType.POINTER); private static final MethodHandle DLERROR = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64); private static long dlopenPtr; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeFunctionPointer.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeFunctionPointer.java index 217975cfcd..e5e1e8df17 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeFunctionPointer.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeFunctionPointer.java @@ -40,6 +40,7 @@ */ package com.oracle.graal.python.runtime.nativeaccess; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSignature.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSignature.java index 0de2e9c2e1..c7785d779d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSignature.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeSignature.java @@ -43,6 +43,7 @@ import java.lang.invoke.MethodHandle; import java.util.Arrays; +import com.oracle.graal.python.annotations.NativeSimpleType; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; public final class NativeSignature { From f5ede8856b6b7f10a2dac794c9031504b0904406 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Tue, 12 May 2026 13:13:55 +0200 Subject: [PATCH 02/10] GenerateNativeDowncalls annotation and processor --- .../python/annotations/DowncallSignature.java | 58 ++++ .../annotations/GenerateNativeDowncalls.java | 52 +++ .../javax.annotation.processing.Processor | 3 +- .../processor/CApiBuiltinsProcessor.java | 35 +- .../GenerateNativeDowncallsProcessor.java | 312 ++++++++++++++++++ .../NativeDowncallMethodHandleGenerator.java | 83 +++++ 6 files changed, 512 insertions(+), 31 deletions(-) create mode 100644 graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java create mode 100644 graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java create mode 100644 graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java create mode 100644 graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java new file mode 100644 index 0000000000..9b055646a5 --- /dev/null +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java @@ -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.FIELD) +public @interface DowncallSignature { + NativeSimpleType returns(); + + NativeSimpleType[] argTypes() default {}; + + String[] argNames() default {}; + + String symbol() default ""; +} diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java new file mode 100644 index 0000000000..61ff310d42 --- /dev/null +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java @@ -0,0 +1,52 @@ +/* + * 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.TYPE) +public @interface GenerateNativeDowncalls { + String generatedClassName(); +} diff --git a/graalpython/com.oracle.graal.python.processor/src/META-INF/services/javax.annotation.processing.Processor b/graalpython/com.oracle.graal.python.processor/src/META-INF/services/javax.annotation.processing.Processor index 84137ac45b..c56a7e9bd4 100644 --- a/graalpython/com.oracle.graal.python.processor/src/META-INF/services/javax.annotation.processing.Processor +++ b/graalpython/com.oracle.graal.python.processor/src/META-INF/services/javax.annotation.processing.Processor @@ -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 \ No newline at end of file +com.oracle.graal.python.processor.SlotsProcessor diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java index f3d000abef..e6bf16d61f 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java @@ -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; @@ -292,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"; @@ -1262,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('('); @@ -1349,7 +1332,6 @@ private void generateExternalFunctionInvoker(List argTypes = Arrays.stream(sig.argumentTypes).map(this::toJavaNfiType).toList(); boolean isVoidReturn = "void".equals(returnType); @@ -1382,14 +1364,7 @@ private void generateExternalFunctionInvoker(List 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) { @@ -1465,9 +1440,9 @@ private void generateExternalFunctionInvoker(List argumentTypes, List argumentNames) { + } + + @Override + public Set getSupportedAnnotationTypes() { + return Set.of(GenerateNativeDowncalls.class.getName(), DowncallSignature.class.getName()); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + try { + doProcess(roundEnv); + } catch (IOException ex) { + ex.printStackTrace(); + } catch (ProcessingError ex) { + processingEnv.getMessager().printMessage(Kind.ERROR, ex.getMessage(), ex.getElement()); + } + return true; + } + + private void doProcess(RoundEnvironment roundEnv) throws IOException, ProcessingError { + validateDowncallSignatures(roundEnv); + for (Element element : roundEnv.getElementsAnnotatedWith(GenerateNativeDowncalls.class)) { + if (element.getKind() != ElementKind.ENUM) { + throw error(element, "Can only annotate enums with @GenerateNativeDowncalls"); + } + generateInvoker((TypeElement) element); + } + } + + private static void validateDowncallSignatures(RoundEnvironment roundEnv) throws ProcessingError { + for (Element element : roundEnv.getElementsAnnotatedWith(DowncallSignature.class)) { + if (element.getKind() != ElementKind.ENUM_CONSTANT) { + throw error(element, "@DowncallSignature can only annotate enum constants"); + } + Element enclosingElement = element.getEnclosingElement(); + if (enclosingElement == null || enclosingElement.getKind() != ElementKind.ENUM) { + throw error(element, "@DowncallSignature can only annotate enum constants"); + } + if (enclosingElement.getAnnotation(GenerateNativeDowncalls.class) == null) { + throw error(element, "Enum constants annotated with @DowncallSignature must be enclosed in an enum annotated with @GenerateNativeDowncalls"); + } + } + } + + private void generateInvoker(TypeElement enumElement) throws IOException, ProcessingError { + GenerateNativeDowncalls annotation = enumElement.getAnnotation(GenerateNativeDowncalls.class); + List downcalls = collectDowncalls(enumElement); + if (downcalls.isEmpty()) { + throw error(enumElement, "Annotated enum does not declare any downcalls"); + } + + String packageName = processingEnv.getElementUtils().getPackageOf(enumElement).getQualifiedName().toString(); + String enumQualifiedName = enumElement.getQualifiedName().toString(); + String enumTypeRef = enumQualifiedName.startsWith(packageName + ".") ? enumQualifiedName.substring(packageName.length() + 1) : enumQualifiedName; + String className = annotation.generatedClassName(); + + ArrayList lines = new ArrayList<>(); + lines.add("// @formatter:off"); + lines.add("// Checkstyle: stop"); + lines.add("// Generated by annotation processor: " + getClass().getName()); + lines.add("package " + packageName + ";"); + lines.add(""); + lines.add("import java.lang.invoke.MethodHandle;"); + lines.add("import java.lang.invoke.MethodType;"); + lines.add("import java.util.concurrent.atomic.AtomicLongArray;"); + lines.add(""); + lines.add("import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport;"); + lines.add("import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary;"); + lines.add("import com.oracle.truffle.api.CompilerDirectives;"); + lines.add("import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;"); + lines.add(""); + lines.add("final class " + className + " {"); + lines.add(" private final PythonContext context;"); + lines.add(" private final AtomicLongArray cachedFunctions = new AtomicLongArray(" + enumTypeRef + ".values().length);"); + lines.add(" private volatile NativeLibrary nativeLibrary;"); + lines.add(""); + + for (NativeDowncallDesc downcall : downcalls) { + NativeDowncallMethodHandleGenerator.emitMethodHandleField(lines, methodHandleName(downcall.name), downcall.returnType, downcall.argumentTypes); + } + + lines.add(""); + lines.add(" " + className + "(PythonContext context) {"); + lines.add(" this.context = context;"); + lines.add(" }"); + + for (NativeDowncallDesc downcall : downcalls) { + emitDowncallMethod(lines, enumTypeRef, downcall); + } + + lines.add(""); + lines.add(" @TruffleBoundary"); + lines.add(" private long lookup(" + enumTypeRef + " function, String symbolName) {"); + lines.add(" long symbol = cachedFunctions.get(function.ordinal());"); + lines.add(" if (symbol == 0) {"); + lines.add(" symbol = loadFunction(function, symbolName);"); + lines.add(" cachedFunctions.compareAndSet(function.ordinal(), 0, symbol);"); + lines.add(" symbol = cachedFunctions.get(function.ordinal());"); + lines.add(" }"); + lines.add(" return symbol;"); + lines.add(" }"); + lines.add(""); + lines.add(" @TruffleBoundary"); + lines.add(" private long loadFunction(" + enumTypeRef + " function, String symbolName) {"); + lines.add(" return ensureLibrary().lookupSymbol(symbolName);"); + lines.add(" }"); + lines.add(""); + lines.add(" @TruffleBoundary"); + lines.add(" private NativeLibrary ensureLibrary() {"); + lines.add(" NativeLibrary library = nativeLibrary;"); + lines.add(" if (library == null) {"); + lines.add(" library = " + enumTypeRef + ".loadNativeLibrary(context);"); + lines.add(" nativeLibrary = library;"); + lines.add(" }"); + lines.add(" return library;"); + lines.add(" }"); + lines.add("}"); + + var file = processingEnv.getFiler().createSourceFile(packageName + "." + className, enumElement); + try (var writer = file.openWriter()) { + writer.append(String.join(System.lineSeparator(), lines)); + } + } + + private static List collectDowncalls(TypeElement enumElement) throws ProcessingError { + List result = new ArrayList<>(); + for (Element enclosedElement : enumElement.getEnclosedElements()) { + if (enclosedElement.getKind() == ElementKind.ENUM_CONSTANT) { + result.add(extractDowncall((VariableElement) enclosedElement)); + } + } + return result; + } + + private static NativeDowncallDesc extractDowncall(VariableElement enumConstant) throws ProcessingError { + DowncallSignature annotation = enumConstant.getAnnotation(DowncallSignature.class); + if (annotation == null) { + throw error(enumConstant, "Enum constant in @GenerateNativeDowncalls enum must be annotated with @DowncallSignature"); + } + + NativeSimpleType[] argTypes = annotation.argTypes(); + List argumentTypes = new ArrayList<>(argTypes.length); + for (NativeSimpleType argType : argTypes) { + argumentTypes.add(nativeSimpleTypeToJavaType(argType)); + } + + List argumentNames = extractArgumentNames(enumConstant, argTypes.length, annotation.argNames()); + String symbolName = annotation.symbol().isBlank() ? enumConstant.getSimpleName().toString() : annotation.symbol(); + return new NativeDowncallDesc( + enumConstant.getSimpleName().toString(), + symbolName, + nativeSimpleTypeToJavaType(annotation.returns()), + argumentTypes, + argumentNames); + } + + private static List extractArgumentNames(VariableElement enumConstant, int argCount, String[] argNames) throws ProcessingError { + if (argNames.length == 0) { + if (argCount > 26) { + throw error(enumConstant, "Generated downcall stubs support at most 26 synthetic argument names (a-z); specify argNames explicitly for %d parameters", argCount); + } + List generatedNames = new ArrayList<>(argCount); + for (int i = 0; i < argCount; i++) { + generatedNames.add(NativeDowncallMethodHandleGenerator.argName(i)); + } + return generatedNames; + } + if (argNames.length != argCount) { + throw error(enumConstant, "@DowncallSignature argNames length must match argTypes length (%d != %d)", argNames.length, argCount); + } + HashSet seenNames = new HashSet<>(); + List result = new ArrayList<>(argCount); + for (String argName : argNames) { + if (argName.isBlank()) { + throw error(enumConstant, "@DowncallSignature argNames must not contain blank names"); + } + if (!SourceVersion.isIdentifier(argName) || SourceVersion.isKeyword(argName)) { + throw error(enumConstant, "@DowncallSignature argName is not a valid Java identifier: %s", argName); + } + if (!seenNames.add(argName)) { + throw error(enumConstant, "@DowncallSignature argNames must be unique: %s", argName); + } + result.add(argName); + } + return result; + } + + private static ProcessingError error(Element element, String fmt, Object... args) throws ProcessingError { + throw new ProcessingError(element, fmt, args); + } + + private static String nativeSimpleTypeToJavaType(NativeSimpleType type) { + return switch (type) { + case VOID -> "void"; + case SINT8 -> "byte"; + case SINT16 -> "short"; + case SINT32 -> "int"; + case SINT64, POINTER -> "long"; + case FLOAT -> "float"; + case DOUBLE -> "double"; + }; + } + + private static void emitDowncallMethod(List lines, String enumQualifiedName, NativeDowncallDesc downcall) { + lines.add(""); + lines.add(" @TruffleBoundary(allowInlining = true, transferToInterpreterOnException = false)"); + lines.add(" " + downcall.returnType + " " + downcall.name + "(" + typedArgs(downcall.argumentTypes, downcall.argumentNames) + ") {"); + lines.add(" long functionPointer = lookup(" + enumQualifiedName + "." + downcall.name + ", " + stringLiteral(downcall.symbolName) + ");"); + lines.add(" try {"); + if ("void".equals(downcall.returnType)) { + lines.add(" " + methodHandleName(downcall.name) + ".invokeExact(" + invokeArgs(downcall.argumentNames) + ");"); + } else { + lines.add(" return (" + downcall.returnType + ") " + methodHandleName(downcall.name) + ".invokeExact(" + invokeArgs(downcall.argumentNames) + ");"); + } + lines.add(" } catch (Throwable t) {"); + lines.add(" throw CompilerDirectives.shouldNotReachHere(t);"); + lines.add(" }"); + lines.add(" }"); + } + + private static String methodHandleName(String downcallName) { + return NativeDowncallMethodHandleGenerator.methodHandleVarName(downcallName.toUpperCase()); + } + + private static String typedArgs(List argTypes, List argNames) { + List args = new ArrayList<>(argTypes.size()); + for (int i = 0; i < argTypes.size(); i++) { + args.add(argTypes.get(i) + " " + argNames.get(i)); + } + return String.join(", ", args); + } + + private static String invokeArgs(List argNames) { + String args = String.join(", ", argNames); + return args.isEmpty() ? "functionPointer" : "functionPointer, " + args; + } + + private static String stringLiteral(String value) { + return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\""; + } +} diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java new file mode 100644 index 0000000000..827d84a4df --- /dev/null +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java @@ -0,0 +1,83 @@ +/* + * 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.processor; + +import java.util.ArrayList; +import java.util.List; + +final class NativeDowncallMethodHandleGenerator { + private NativeDowncallMethodHandleGenerator() { + } + + static String argName(int i) { + if (i >= 26) { + throw new IllegalArgumentException("Generated downcall stubs support at most 26 synthetic argument names (a-z), got index " + i); + } + return "" + (char) ('a' + i); + } + + static String methodHandleVarName(String signatureName) { + return "NATIVE_METHOD_HANDLE_" + signatureName; + } + + static String toClassLiteral(String javaType) { + return switch (javaType) { + case "void" -> "void.class"; + case "byte" -> "byte.class"; + case "short" -> "short.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); + }; + } + + static void emitMethodHandleField(List lines, String fieldName, String returnType, List argTypes) { + List methodTypeArgs = new ArrayList<>(); + methodTypeArgs.add("long.class"); + for (String argType : argTypes) { + methodTypeArgs.add(toClassLiteral(argType)); + } + lines.add(" private static final MethodHandle " + fieldName + " = NativeAccessSupport.createDowncallHandle(" + + "MethodType.methodType(" + toClassLiteral(returnType) + ", " + String.join(", ", methodTypeArgs) + "), false);"); + } +} From 0270378714d3e4c0c70b2bd55bac942e07e56431 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Tue, 12 May 2026 13:26:35 +0200 Subject: [PATCH 03/10] Migrate NFIPosixSupport to FFM API --- .../src/tests/test_posix.py | 12 + .../src/tests/test_socket.py | 30 + .../graal/python/runtime/NFIPosixSupport.java | 2788 ++++++++++------- .../runtime/nativeaccess/NativeContext.java | 25 + .../runtime/nativeaccess/NativeMemory.java | 156 + graalpython/python-libposix/src/posix.c | 8 +- 6 files changed, 1938 insertions(+), 1081 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_posix.py b/graalpython/com.oracle.graal.python.test/src/tests/test_posix.py index 5629fd5401..6511da2dca 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_posix.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_posix.py @@ -258,6 +258,18 @@ def __fspath__(self): with self.assertRaisesRegex(TypeError, r"expected C.__fspath__\(\) to return str or bytes, not bytearray"): os.open(C(), 0) + def test_open_bytes_path(self): + try: + with open(os.fsencode(TEST_FULL_PATH1), os.O_WRONLY | os.O_CREAT) as fd: + os.write(fd, b'hello') + with open(os.fsencode(TEST_FULL_PATH1), os.O_RDONLY) as fd: + self.assertEqual(b'hello', os.read(fd, 5)) + finally: + try: + os.unlink(TEST_FULL_PATH1) + except Exception: + pass + def test_fd_converter(self): class MyInt(int): def fileno(self): return 0 diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_socket.py b/graalpython/com.oracle.graal.python.test/src/tests/test_socket.py index c49686d2c3..12b7826de8 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_socket.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_socket.py @@ -110,3 +110,33 @@ def server(): sock.recv_into(buffer, 1) assert b == b'123' thread.join() + + +def test_sendto_recvfrom_roundtrip(): + try: + if __graalpython__.posix_module_backend() == "java": + return + except NameError: + pass + + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server: + server.bind(("127.0.0.1", 0)) + server_addr = server.getsockname() + + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client: + client.bind(("127.0.0.1", 0)) + client_addr = client.getsockname() + + sent = client.sendto(b"phase5", server_addr) + assert sent == 6 + + data, addr = server.recvfrom(64) + assert data == b"phase5" + assert addr == client_addr + + sent = server.sendto(b"reply", client_addr) + assert sent == 5 + + data, addr = client.recvfrom(64) + assert data == b"reply" + assert addr == server_addr diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java index a15d44f747..da0e7a03b8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java @@ -41,9 +41,10 @@ // skip GIL package com.oracle.graal.python.runtime; -import static com.oracle.graal.python.nodes.StringLiterals.J_DEFAULT; -import static com.oracle.graal.python.nodes.StringLiterals.J_NATIVE; -import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; +import static com.oracle.graal.python.annotations.NativeSimpleType.POINTER; +import static com.oracle.graal.python.annotations.NativeSimpleType.SINT32; +import static com.oracle.graal.python.annotations.NativeSimpleType.SINT64; +import static com.oracle.graal.python.annotations.NativeSimpleType.VOID; import static com.oracle.graal.python.nodes.StringLiterals.T_NATIVE; import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN6_ADDR_S6_ADDR; import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN_ADDR_S_ADDR; @@ -75,26 +76,24 @@ import static com.oracle.graal.python.runtime.PosixConstants._POSIX_HOST_NAME_MAX; import static com.oracle.graal.python.runtime.PosixSupportLibrary.POSIX_FILENAME_SEPARATOR; import static com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR_BE; import static com.oracle.graal.python.util.PythonUtils.EMPTY_LONG_ARRAY; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; -import static com.oracle.graal.python.util.PythonUtils.callCallTarget; -import static com.oracle.truffle.api.CompilerDirectives.SLOWPATH_PROBABILITY; -import static com.oracle.truffle.api.CompilerDirectives.injectBranchProbability; import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere; import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_8; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.logging.Level; import org.graalvm.nativeimage.ImageInfo; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.DowncallSignature; +import com.oracle.graal.python.annotations.GenerateNativeDowncalls; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; -import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; @@ -118,11 +117,12 @@ import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.util.FunctionWithSignature; +import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; +import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; +import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.ArrayUtils; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -133,26 +133,18 @@ import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.ArityException; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; -import com.oracle.truffle.nfi.api.SignatureLibrary; import sun.misc.Unsafe; /** - * Implementation that invokes the native POSIX functions directly using NFI. This requires either - * that the native access is allowed or to configure managed LLVM backend for NFI. + * Implementation that invokes the native POSIX support library through generated native-access + * downcalls. */ @ExportLibrary(PosixSupportLibrary.class) public final class NFIPosixSupport extends PosixSupport { @@ -162,6 +154,7 @@ public final class NFIPosixSupport extends PosixSupport { private static final int DIRENT_NAME_BUF_LENGTH = 256; private static final int PWD_OUTPUT_LEN = 5; private static final int PWD_BUFFER_MAX_SIZE = Integer.MAX_VALUE >> 2; + private static final int STRERROR_BUF_LENGTH = 1024; private static final int MAX_READ = Integer.MAX_VALUE / 2; @@ -171,313 +164,522 @@ public final class NFIPosixSupport extends PosixSupport { private static final Object CRYPT_LOCK = new Object(); - private enum PosixNativeFunction { - init_constants("([sint64], sint32):sint32"), - - get_errno("():sint32"), - set_errno("(sint32):void"), - call_mmap("(sint64, sint32, sint32, sint32, sint64):sint64"), - call_munmap("(sint64, sint64):sint32"), - call_msync("(sint64, sint64, sint64):void"), - call_strerror("(sint32, [sint8], sint32):void"), - call_getpid("():sint64"), - call_umask("(sint32):sint32"), - call_openat("(sint32, [sint8], sint32, sint32):sint32"), - call_close("(sint32):sint32"), - call_read("(sint32, [sint8], uint64):sint64"), - call_write("(sint32, [sint8], uint64):sint64"), - call_dup("(sint32):sint32"), - call_dup2("(sint32, sint32, sint32):sint32"), - call_pipe2("([sint32]):sint32"), - call_select("(sint32, [sint32], sint32, [sint32], sint32, [sint32], sint32, sint64, sint64, [sint8]):sint32"), - call_poll("(sint32, sint32, sint64, sint64):sint32"), - call_lseek("(sint32, sint64, sint32):sint64"), - call_ftruncate("(sint32, sint64):sint32"), - call_truncate("([sint8], sint64):sint32"), - call_fsync("(sint32):sint32"), - call_flock("(sint32, sint32):sint32"), - call_fcntl_lock("(sint32, sint32, sint32, sint32, sint64, sint64):sint32"), - call_fstatat("(sint32, [sint8], sint32, [sint64]):sint32"), - call_fstat("(sint32, [sint64]):sint32"), - call_statvfs("([sint8], [sint64]):sint32"), - call_fstatvfs("(sint32, [sint64]):sint32"), - call_uname("([sint8], [sint8], [sint8], [sint8], [sint8], sint32):sint32"), - call_unlinkat("(sint32, [sint8], sint32):sint32"), - call_linkat("(sint32, [sint8], sint32, [sint8], sint32):sint32"), - call_symlinkat("([sint8], sint32, [sint8]):sint32"), - call_mkdirat("(sint32, [sint8], sint32):sint32"), - call_getcwd("([sint8], uint64):sint32"), - call_chdir("([sint8]):sint32"), - call_fchdir("(sint32):sint32"), - call_isatty("(sint32):sint32"), - call_opendir("([sint8]):sint64"), - call_fdopendir("(sint32):sint64"), - call_closedir("(sint64):sint32"), - call_readdir("(sint64, [sint8], uint64, [sint64]):sint32"), - call_rewinddir("(sint64):void"), - call_utimensat("(sint32, [sint8], [sint64], sint32):sint32"), - call_futimens("(sint32, [sint64]):sint32"), - call_futimes("(sint32, [sint64]):sint32"), - call_lutimes("([sint8], [sint64]):sint32"), - call_utimes("([sint8], [sint64]):sint32"), - call_renameat("(sint32, [sint8], sint32, [sint8]):sint32"), - call_faccessat("(sint32, [sint8], sint32, sint32, sint32):sint32"), - call_fchmodat("(sint32, [sint8], sint32, sint32):sint32"), - call_fchmod("(sint32, sint32):sint32"), - call_fchownat("(sint32, [sint8], sint64, sint64, sint32):sint32"), - call_fchown("(sint32, sint64, sint64):sint32"), - call_readlinkat("(sint32, [sint8], [sint8], uint64):sint64"), - get_inheritable("(sint32):sint32"), - set_inheritable("(sint32, sint32):sint32"), - get_blocking("(sint32):sint32"), - set_blocking("(sint32, sint32):sint32"), - get_terminal_size("(sint32, [sint32]):sint32"), - call_raise("(sint32):sint32"), - call_alarm("(sint32):sint32"), - call_getitimer("(sint32, [sint64]):sint32"), - call_setitimer("(sint32, [sint64], [sint64]):sint32"), - signal_self("(sint32):sint32"), - call_kill("(sint64, sint32):sint32"), - call_killpg("(sint64, sint32):sint32"), - call_waitpid("(sint64, [sint32], sint32):sint64"), - call_wcoredump("(sint32):sint32"), - call_wifcontinued("(sint32):sint32"), - call_wifstopped("(sint32):sint32"), - call_wifsignaled("(sint32):sint32"), - call_wifexited("(sint32):sint32"), - call_wexitstatus("(sint32):sint32"), - call_wtermsig("(sint32):sint32"), - call_wstopsig("(sint32):sint32"), - call_getuid("():sint64"), - call_geteuid("():sint64"), - call_getgid("():sint64"), - call_getegid("():sint64"), - call_getppid("():sint64"), - call_getpgid("(sint64):sint64"), - call_setpgid("(sint64,sint64):sint32"), - call_getpgrp("():sint64"), - call_getsid("(sint64):sint64"), - call_setsid("():sint64"), - call_getgroups("(sint64, [sint64]):sint32"), - call_getrusage("(sint32, [sint64]):sint32"), - call_openpty("([sint32]):sint32"), - call_ctermid("([sint8]):sint32"), - call_setenv("([sint8], [sint8], sint32):sint32"), - call_unsetenv("([sint8]):sint32"), - fork_exec("([sint8], [sint64], sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, sint32, [sint32], sint64):sint32"), - call_execv("([sint8], [sint64], sint32):void"), - call_system("([sint8]):sint32"), - - call_getpwuid_r("(uint64,[sint8],sint32,[uint64]):sint32"), - call_getpwname_r("([sint8],[sint8],sint32,[uint64]):sint32"), - call_setpwent("():void"), - call_endpwent("():void"), - call_getpwent("([sint64]):pointer"), - get_getpwent_data("(pointer,[sint8],sint32,[uint64]):sint32"), - get_sysconf_getpw_r_size_max("():sint64"), - - call_socket("(sint32, sint32, sint32):sint32"), - call_accept("(sint32, [sint8], [sint32]):sint32"), - call_bind("(sint32, [sint8], sint32):sint32"), - call_connect("(sint32, [sint8], sint32):sint32"), - call_listen("(sint32, sint32):sint32"), - call_getpeername("(sint32, [sint8], [sint32]):sint32"), - call_getsockname("(sint32, [sint8], [sint32]):sint32"), - call_send("(sint32, [sint8], sint32, sint32, sint32):sint32"), - call_sendto("(sint32, [sint8], sint32, sint32, sint32, [sint8], sint32):sint32"), - call_recv("(sint32, [sint8], sint32, sint32, sint32):sint32"), - call_recvfrom("(sint32, [sint8], sint32, sint32, sint32, [sint8], [sint32]):sint32"), - call_shutdown("(sint32, sint32): sint32"), - call_getsockopt("(sint32, sint32, sint32, [sint8], [sint32]):sint32"), - call_setsockopt("(sint32, sint32, sint32, [sint8], sint32):sint32"), - - call_inet_addr("([sint8]):sint32"), - call_inet_aton("([sint8]):sint64"), - call_inet_ntoa("(sint32, [sint8]):sint32"), - call_inet_pton("(sint32, [sint8], [sint8]):sint32"), - call_inet_ntop("(sint32, [sint8], [sint8], sint32):sint32"), - call_gethostname("([sint8], sint64):sint32"), - - call_getnameinfo("([sint8], sint32, [sint8], sint32, [sint8], sint32, sint32):sint32"), - call_getaddrinfo("([sint8], [sint8], sint32, sint32, sint32, sint32, [sint64]):sint32"), - call_freeaddrinfo("(sint64):void"), - call_gai_strerror("(sint32, [sint8], sint32):void"), - get_addrinfo_members("(sint64, [sint32], [sint64], [sint8]):sint32"), - - call_sem_open("([sint8], sint32, sint32, sint32):pointer"), - call_sem_close("(pointer):sint32"), - call_sem_unlink("([sint8]):sint32"), - call_sem_getvalue("(pointer, [sint32]):sint32"), - call_sem_post("(pointer):sint32"), - call_sem_wait("(pointer):sint32"), - call_sem_trywait("(pointer):sint32"), - call_sem_timedwait("(pointer, sint64):sint32"), - - call_ioctl_bytes("(sint32, uint64, [sint8]):sint32"), - call_ioctl_int("(sint32, uint64, sint32):sint32"), - - call_sysconf("(sint32):sint64"), - - crypt("([sint8], [sint8]):sint64"); - - private final String signature; - - PosixNativeFunction(String signature) { - this.signature = signature; - } - } - - protected static final class InvokeNativeFunction extends Node { - private static final InvokeNativeFunction UNCACHED = new InvokeNativeFunction(SignatureLibrary.getUncached(), InteropLibrary.getUncached()); - - @Child private SignatureLibrary functionInterop; - @Child private InteropLibrary resultInterop; - - public InvokeNativeFunction(SignatureLibrary functionInterop, InteropLibrary resultInterop) { - this.functionInterop = functionInterop; - this.resultInterop = resultInterop; - } - - @NeverDefault - public static InvokeNativeFunction create() { - return new InvokeNativeFunction(SignatureLibrary.getFactory().createDispatched(2), null); - } - - public static InvokeNativeFunction getUncached() { - return UNCACHED; - } - - public Object call(NFIPosixSupport posix, PosixNativeFunction function, Object... args) { - if (injectBranchProbability(SLOWPATH_PROBABILITY, posix.nfiLibrary == null)) { - loadLibrary(this, posix); - } - if (injectBranchProbability(SLOWPATH_PROBABILITY, posix.cachedFunctions.get(function.ordinal()) == null)) { - loadFunction(this, posix, posix.nfiLibrary, function); - } - FunctionWithSignature funObject = posix.cachedFunctions.get(function.ordinal()); - try { - return functionInterop.call(funObject.signature(), funObject.function(), args); - } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); - } - } + @GenerateNativeDowncalls(generatedClassName = "PosixNativeFunctionInvoker") + enum PosixNativeFunction { + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT32}, argNames = {"out", "len"}) + init_constants, - public long callLong(NFIPosixSupport posix, PosixNativeFunction function, Object... args) { - try { - return getResultInterop().asLong(call(posix, function, args)); - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); - } - } + @DowncallSignature(returns = SINT32) + get_errno, - public int callInt(NFIPosixSupport posix, PosixNativeFunction function, Object... args) { - try { - return getResultInterop().asInt(call(posix, function, args)); - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); - } - } + @DowncallSignature(returns = VOID, argTypes = {SINT32}) + set_errno, - public byte callByte(NFIPosixSupport posix, PosixNativeFunction function, Object... args) { - try { - return getResultInterop().asByte(call(posix, function, args)); - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); - } - } + @DowncallSignature(returns = SINT64, argTypes = {SINT64, SINT32, SINT32, SINT32, SINT64}, argNames = {"length", "prot", "flags", "fd", "offset"}) + call_mmap, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT64}, argNames = {"address", "length"}) + call_munmap, + + @DowncallSignature(returns = VOID, argTypes = {SINT64, SINT64, SINT64}, argNames = {"address", "offset", "length"}) + call_msync, + + @DowncallSignature(returns = VOID, argTypes = {SINT32, POINTER, SINT32}, argNames = {"error", "buf", "buflen"}) + call_strerror, + + @DowncallSignature(returns = SINT64) + call_getpid, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_umask, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"dirFd", "pathname", "flags", "mode"}) + call_openat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_close, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, SINT64}, argNames = {"fd", "buf", "count"}) + call_read, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, SINT64}, argNames = {"fd", "buf", "count"}) + call_write, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_dup, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32}, argNames = {"oldfd", "newfd", "inheritable"}) + call_dup2, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"pipefd"}) + call_pipe2, + + @DowncallSignature(returns = SINT32, argTypes = { + SINT32, POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT64, SINT64, POINTER + }, argNames = { + "nfds", "readfds", "readfdsLen", "writefds", "writefdsLen", "errfds", "errfdsLen", "timeoutSec", "timeoutUsec", "selected" + }) + call_select, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT64, SINT64}, argNames = {"fd", "writing", "timeoutSec", "timeoutUsec"}) + call_poll, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32, SINT64, SINT32}, argNames = {"fd", "offset", "whence"}) + call_lseek, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64}, argNames = {"fd", "length"}) + call_ftruncate, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"path", "length"}) + call_truncate, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_fsync, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "operation"}) + call_flock, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, SINT32, SINT64, SINT64}, argNames = {"fd", "blocking", "lockType", "whence", "start", "length"}) + call_fcntl_lock, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER}, argNames = {"dirFd", "path", "followSymlinks", "out"}) + call_fstatat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "out"}) + call_fstat, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"path", "out"}) + call_statvfs, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "out"}) + call_fstatvfs, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, POINTER, POINTER, POINTER, SINT32}, argNames = {"sysname", "nodename", "release", "version", "machine", "size"}) + call_uname, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"dirFd", "pathname", "rmdir"}) + call_unlinkat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER, SINT32}, argNames = {"oldDirFd", "oldPath", "newDirFd", "newPath", "flags"}) + call_linkat, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT32, POINTER}, argNames = {"target", "dirFd", "linkpath"}) + call_symlinkat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"dirFd", "pathname", "mode"}) + call_mkdirat, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"buf", "size"}) + call_getcwd, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"path"}) + call_chdir, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_fchdir, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_isatty, + + @DowncallSignature(returns = SINT64, argTypes = {POINTER}, argNames = {"name"}) + call_opendir, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32}) + call_fdopendir, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64}, argNames = {"dirp"}) + call_closedir, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, SINT64, POINTER}, argNames = {"dirp", "nameBuf", "nameBufSize", "out"}) + call_readdir, + + @DowncallSignature(returns = VOID, argTypes = {SINT64}, argNames = {"dirp"}) + call_rewinddir, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER, SINT32}, argNames = {"dirFd", "path", "timespec", "followSymlinks"}) + call_utimensat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "timespec"}) + call_futimens, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "timeval"}) + call_futimes, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"filename", "timeval"}) + call_lutimes, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"filename", "timeval"}) + call_utimes, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER}, argNames = {"oldDirFd", "oldPath", "newDirFd", "newPath"}) + call_renameat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32, SINT32}, argNames = {"dirFd", "path", "mode", "effectiveIds", "followSymlinks"}) + call_faccessat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"dirFd", "path", "mode", "followSymlinks"}) + call_fchmodat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "mode"}) + call_fchmod, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT64, SINT64, SINT32}, argNames = {"dirfd", "pathname", "owner", "group", "followSymlinks"}) + call_fchownat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, SINT64}, argNames = {"fd", "owner", "group"}) + call_fchown, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, POINTER, SINT64}, argNames = {"dirFd", "path", "buf", "size"}) + call_readlinkat, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + get_inheritable, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "inheritable"}) + set_inheritable, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + get_blocking, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "blocking"}) + set_blocking, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "size"}) + get_terminal_size, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_raise, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_alarm, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"which", "current_value"}) + call_getitimer, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"which", "new_value", "old_value"}) + call_setitimer, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + signal_self, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT32}, argNames = {"pid", "signal"}) + call_kill, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT32}, argNames = {"pgid", "signal"}) + call_killpg, + + @DowncallSignature(returns = SINT64, argTypes = {SINT64, POINTER, SINT32}, argNames = {"pid", "status", "options"}) + call_waitpid, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wcoredump, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wifcontinued, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wifstopped, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wifsignaled, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wifexited, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wexitstatus, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wtermsig, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32}) + call_wstopsig, + + @DowncallSignature(returns = SINT64) + call_getuid, + + @DowncallSignature(returns = SINT64) + call_geteuid, + + @DowncallSignature(returns = SINT64) + call_getgid, + + @DowncallSignature(returns = SINT64) + call_getegid, + + @DowncallSignature(returns = SINT64) + call_getppid, + + @DowncallSignature(returns = SINT64, argTypes = {SINT64}) + call_getpgid, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT64}, argNames = {"pid", "pgid"}) + call_setpgid, + + @DowncallSignature(returns = SINT64) + call_getpgrp, + + @DowncallSignature(returns = SINT64, argTypes = {SINT64}) + call_getsid, + + @DowncallSignature(returns = SINT64) + call_setsid, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER}, argNames = {"size", "out"}) + call_getgroups, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"who", "out"}) + call_getrusage, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"outvars"}) + call_openpty, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"buf"}) + call_ctermid, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32}, argNames = {"name", "value", "overwrite"}) + call_setenv, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"name"}) + call_unsetenv, + + @DowncallSignature(returns = SINT32, argTypes = { + POINTER, POINTER, SINT32, SINT32, SINT32, + SINT32, SINT32, SINT32, SINT32, SINT32, + SINT32, SINT32, SINT32, SINT32, SINT32, + SINT32, SINT32, POINTER, SINT64 + }, argNames = { + "data", "offsets", "offsetsLen", "argsPos", "envPos", + "cwdPos", "stdinRdFd", "stdinWrFd", "stdoutRdFd", "stdoutWrFd", + "stderrRdFd", "stderrWrFd", "errPipeRdFd", "errPipeWrFd", "closeFds", + "restoreSignals", "callSetsid", "fdsToKeep", "fdsToKeepLen" + }) + fork_exec, + + @DowncallSignature(returns = VOID, argTypes = {POINTER, POINTER, SINT32}, argNames = {"data", "offsets", "offsetsLen"}) + call_execv, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"pathname"}) + call_system, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, SINT32, POINTER}, argNames = {"uid", "buffer", "bufferSize", "output"}) + call_getpwuid_r, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32, POINTER}, argNames = {"name", "buffer", "bufferSize", "output"}) + call_getpwname_r, + + @DowncallSignature(returns = VOID) + call_setpwent, + + @DowncallSignature(returns = VOID) + call_endpwent, + + @DowncallSignature(returns = POINTER, argTypes = {POINTER}, argNames = {"bufferSize"}) + call_getpwent, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32, POINTER}, argNames = {"p", "buffer", "bufferSize", "output"}) + get_getpwent_data, + + @DowncallSignature(returns = SINT64) + get_sysconf_getpw_r_size_max, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32}, argNames = {"family", "type", "protocol"}) + call_socket, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) + call_accept, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"sockfd", "addr", "addr_len"}) + call_bind, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"sockfd", "addr", "addr_len"}) + call_connect, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"sockfd", "backlog"}) + call_listen, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) + call_getpeername, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) + call_getsockname, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"sockfd", "buf", "len", "flags"}) + call_send, + + @DowncallSignature(returns = SINT32, argTypes = { + SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, SINT32 + }, argNames = { + "sockfd", "buf", "offset", "len", "flags", "addr", "addr_len" + }) + call_sendto, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"sockfd", "buf", "len", "flags"}) + call_recv, + + @DowncallSignature(returns = SINT32, argTypes = { + SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, POINTER + }, argNames = { + "sockfd", "buf", "offset", "len", "flags", "src_addr", "addr_len" + }) + call_recvfrom, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"sockfd", "how"}) + call_shutdown, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, POINTER, POINTER}, argNames = {"sockfd", "level", "optname", "buf", "bufLen"}) + call_getsockopt, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, POINTER, SINT32}, argNames = {"sockfd", "level", "optname", "buf", "bufLen"}) + call_setsockopt, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"src"}) + call_inet_addr, + + @DowncallSignature(returns = SINT64, argTypes = {POINTER}, argNames = {"src"}) + call_inet_aton, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"src", "dst"}) + call_inet_ntoa, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"family", "src", "dst"}) + call_inet_pton, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER, SINT32}, argNames = {"family", "src", "dst", "dstSize"}) + call_inet_ntop, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"buf", "bufLen"}) + call_gethostname, + + @DowncallSignature(returns = SINT32, argTypes = { + POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT32 + }, argNames = { + "addr", "addr_len", "hostBuf", "hostBufLen", "servBuf", "servBufLen", "flags" + }) + call_getnameinfo, + + @DowncallSignature(returns = SINT32, argTypes = { + POINTER, POINTER, SINT32, SINT32, SINT32, SINT32, POINTER + }, argNames = { + "node", "service", "family", "sockType", "protocol", "flags", "ptr" + }) + call_getaddrinfo, + + @DowncallSignature(returns = VOID, argTypes = {SINT64}, argNames = {"ptr"}) + call_freeaddrinfo, + + @DowncallSignature(returns = VOID, argTypes = {SINT32, POINTER, SINT32}, argNames = {"error", "buf", "buflen"}) + call_gai_strerror, + + @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, POINTER, POINTER}, argNames = {"ptr", "intData", "longData", "addr"}) + get_addrinfo_members, + + @DowncallSignature(returns = POINTER, argTypes = {POINTER, SINT32, SINT32, SINT32}, argNames = {"name", "openFlags", "mode", "value"}) + call_sem_open, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) + call_sem_close, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"name"}) + call_sem_unlink, - // Temporary - will be replaced with something else when we move this to Truffle - private static String getLibPath(PythonContext context) { - CompilerAsserts.neverPartOfCompilation(); - String libPythonName = PythonContext.getSupportLibName(NFIPosixSupport.SUPPORTING_NATIVE_LIB_NAME); + @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"handle", "value"}) + call_sem_getvalue, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) + call_sem_post, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) + call_sem_wait, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) + call_sem_trywait, + + @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"handle", "deadlineNs"}) + call_sem_timedwait, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, POINTER}, argNames = {"fd", "request", "buffer"}) + call_ioctl_bytes, + + @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, SINT32}, argNames = {"fd", "request", "arg"}) + call_ioctl_int, + + @DowncallSignature(returns = SINT64, argTypes = {SINT32}) + call_sysconf; + + @TruffleBoundary + static String getLibPath(PythonContext context) { + String libPythonName = PythonContext.getSupportLibName(SUPPORTING_NATIVE_LIB_NAME); TruffleFile homePath = context.getEnv().getInternalTruffleFile(context.getCAPIHome().toJavaStringUncached()); TruffleFile file = homePath.resolve(libPythonName); return file.getPath(); } @TruffleBoundary - private static void loadLibrary(Node node, NFIPosixSupport posix) { - String path = getLibPath(posix.context); + static NativeLibrary loadNativeLibrary(PythonContext context) { + String path = getLibPath(context); try { - posix.nfiLibrary = loadLibrary(node, posix, path); - } catch (Throwable e) { + return context.ensureNativeContext().loadLibrary(path, PosixConstants.RTLD_LOCAL.value); + } catch (NativeLibraryLoadException e) { throw new UnsupportedOperationException(String.format(""" Could not load posix support library from path '%s'. Troubleshooting:\s - Check permissions of the file. - Missing runtime Maven dependency 'org.graalvm.truffle:truffle-nfi-libffi' (should be a dependency of `org.graalvm.polyglot:python{-community}`)?""", - path)); + Check permissions of the file.""", path), e); } } + } - @TruffleBoundary - private static Object loadLibrary(Node node, NFIPosixSupport posix, String path) { - String backend = posix.nfiBackend.toJavaStringUncached(); - Env env = posix.context.getEnv(); - - posix.context.ensureNFILanguage(null, "PosixModuleBackend", "native"); - - Source loadSrc; - if (path != null) { - String withClause = backend.equals(J_NATIVE) ? "" : "with " + backend; - String src = String.format("%sload (RTLD_LOCAL) \"%s\"", withClause, path); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine(String.format("Loading native library: %s", src)); - } - loadSrc = Source.newBuilder(J_NFI_LANGUAGE, src, "load:" + SUPPORTING_NATIVE_LIB_NAME).internal(true).build(); - } else { - loadSrc = Source.newBuilder(J_NFI_LANGUAGE, J_DEFAULT, J_DEFAULT).internal(true).build(); - } - - return callCallTarget(env.parseInternal(loadSrc), node); - } + @GenerateNativeDowncalls(generatedClassName = "CryptNativeFunctionInvoker") + enum CryptNativeFunction { + @DowncallSignature(returns = POINTER, argTypes = {POINTER, POINTER}, argNames = {"word", "salt"}) + crypt; @TruffleBoundary - private static void loadFunction(Node node, NFIPosixSupport posix, Object library, PosixNativeFunction function) { - Object unbound; - try { - InteropLibrary interop = InteropLibrary.getUncached(); - - String sig = String.format("with %s %s", posix.nfiBackend, function.signature); - Source sigSrc = Source.newBuilder(J_NFI_LANGUAGE, sig, "posix-nfi-signature").internal(true).build(); - Object signature = PythonUtils.callCallTarget(posix.context.getEnv().parseInternal(sigSrc), node); - unbound = interop.readMember(library, function.name()); - posix.cachedFunctions.set(function.ordinal(), new FunctionWithSignature(signature, unbound)); - } catch (UnsupportedMessageException | UnknownIdentifierException e) { - throw CompilerDirectives.shouldNotReachHere(function.name(), e); + static NativeLibrary loadNativeLibrary(PythonContext context) { + if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_DARWIN) { + return context.ensureNativeContext().getDefaultLibrary(); } - } - - public InteropLibrary getResultInterop() { - if (resultInterop == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - resultInterop = insert(InteropLibrary.getFactory().createDispatched(2)); + /* + * We don't want to link the posix support library against libcrypt, because it might + * not be available on the target Linux system and would make the whole support library + * fail to load. Load it dynamically on demand instead. + */ + try { + return context.ensureNativeContext().loadLibrary("libcrypt.so", PosixConstants.RTLD_LOCAL.value); + } catch (NativeLibraryLoadException e) { + throw new UnsupportedOperationException("Could not load crypt support library 'libcrypt.so'.", e); } - return resultInterop; } } private final PythonContext context; private final TruffleString nfiBackend; - private volatile Object nfiLibrary; - private volatile Object cryptLibrary; - private final AtomicReferenceArray cachedFunctions; + private final PosixNativeFunctionInvoker posixNativeFunctionInvoker; + private final CryptNativeFunctionInvoker cryptNativeFunctionInvoker; @CompilationFinal(dimensions = 1) private long[] constantValues; public NFIPosixSupport(PythonContext context, TruffleString nfiBackend) { assert nfiBackend.equalsUncached(T_NATIVE, TS_ENCODING); this.context = context; this.nfiBackend = nfiBackend; - this.cachedFunctions = new AtomicReferenceArray<>(PosixNativeFunction.values().length); + this.posixNativeFunctionInvoker = new PosixNativeFunctionInvoker(context); + this.cryptNativeFunctionInvoker = new CryptNativeFunctionInvoker(context); setEnv(context.getEnv()); } long getConstant(NFIPosixConstants constant) { if (constantValues == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - constantValues = new long[NFIPosixConstants.values().length]; - int result = InvokeNativeFunction.getUncached().callInt(this, PosixNativeFunction.init_constants, constantValues, constantValues.length); - if (result != 0) { - throw CompilerDirectives.shouldNotReachHere("Mismatched build of posix native library"); + long[] values = new long[NFIPosixConstants.values().length]; + long nativeValues = NativeMemory.mallocLongArray(values.length); + try { + int result = posixNativeFunctionInvoker.init_constants(nativeValues, values.length); + if (result != 0) { + throw CompilerDirectives.shouldNotReachHere("Mismatched build of posix native library"); + } + NativeMemory.readLongArrayElements(nativeValues, 0, values, 0, values.length); + constantValues = values; + } finally { + NativeMemory.free(nativeValues); } } return constantValues[constant.ordinal()]; @@ -511,128 +713,143 @@ public TruffleString getBackend() { @ExportMessage public TruffleString strerror(int errorCode, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) { + @Bind Node inliningTarget, + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { // From man pages: The GNU C Library uses a buffer of 1024 characters for strerror(). // This buffer size therefore should be sufficient to avoid an ERANGE error when calling // strerror_r(). - byte[] buf = new byte[1024]; - invokeNode.call(this, PosixNativeFunction.call_strerror, errorCode, buf, buf.length); - // TODO PyUnicode_DecodeLocale - return cStringToTruffleString(buf, fromByteArrayNode, switchEncodingFromUtf8Node); + long buf = NativeMemory.mallocByteArray(STRERROR_BUF_LENGTH); + try { + posixNativeFunctionInvoker.call_strerror(errorCode, buf, STRERROR_BUF_LENGTH); + // TODO PyUnicode_DecodeLocale + return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, buf); + } finally { + NativeMemory.free(buf); + } } @ExportMessage - public long getpid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getpid); + public long getpid() { + return posixNativeFunctionInvoker.call_getpid(); } @ExportMessage - public int umask(int mask, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_umask, mask); + public int umask(int mask) throws PosixException { + int result = posixNativeFunctionInvoker.call_umask(mask); if (result < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return result; } @ExportMessage - public int openat(int dirFd, Object pathname, int flags, int mode, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int fd = invokeNode.callInt(this, PosixNativeFunction.call_openat, dirFd, pathToCString(pathname), flags, mode); - if (fd < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { + long pathnamePtr = pathToNativeCString(pathname); + try { + int fd = posixNativeFunctionInvoker.call_openat(dirFd, pathnamePtr, flags, mode); + if (fd < 0) { + throw getErrnoAndThrowPosixException(); + } + return fd; + } finally { + NativeMemory.free(pathnamePtr); } - return fd; } @ExportMessage - public int close(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - final int rv = invokeNode.callInt(this, PosixNativeFunction.call_close, fd); + public int close(int fd) throws PosixException { + final int rv = posixNativeFunctionInvoker.call_close(fd); if (rv < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return rv; } @ExportMessage - public Buffer read(int fd, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Buffer read(int fd, long length) throws PosixException { long count = Math.min(length, MAX_READ); Buffer buffer = Buffer.allocate(count); - setErrno(invokeNode, 0); // TODO CPython does this, but do we need it? - long n = invokeNode.callLong(this, PosixNativeFunction.call_read, fd, buffer.data, count); - if (n < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(count); + try { + posixNativeFunctionInvoker.set_errno(0); + long n = posixNativeFunctionInvoker.call_read(fd, nativeBuffer, count); + if (n < 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer.data, 0, (int) n); + return buffer.withLength(n); + } finally { + NativeMemory.free(nativeBuffer); } - return buffer.withLength(n); } @ExportMessage - public long write(int fd, Buffer data, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - setErrno(invokeNode, 0); // TODO CPython does this, but do we need it? - long n = invokeNode.callLong(this, PosixNativeFunction.call_write, fd, data.data, data.length); - if (n < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public long write(int fd, Buffer data) throws PosixException { + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); + try { + NativeMemory.writeByteArrayElements(nativeBuffer, 0, data.data, 0, (int) data.length); + posixNativeFunctionInvoker.set_errno(0); + long n = posixNativeFunctionInvoker.call_write(fd, nativeBuffer, data.length); + if (n < 0) { + throw getErrnoAndThrowPosixException(); + } + return n; + } finally { + NativeMemory.free(nativeBuffer); } - return n; } @ExportMessage - public int dup(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int newFd = invokeNode.callInt(this, PosixNativeFunction.call_dup, fd); + public int dup(int fd) throws PosixException { + int newFd = posixNativeFunctionInvoker.call_dup(fd); if (newFd < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return newFd; } @ExportMessage - public int dup2(int fd, int fd2, boolean inheritable, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int newFd = invokeNode.callInt(this, PosixNativeFunction.call_dup2, fd, fd2, inheritable ? 1 : 0); + public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { + int newFd = posixNativeFunctionInvoker.call_dup2(fd, fd2, inheritable ? 1 : 0); if (newFd < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return newFd; } @ExportMessage - public boolean getInheritable(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.get_inheritable, fd); + public boolean getInheritable(int fd) throws PosixException { + int result = posixNativeFunctionInvoker.get_inheritable(fd); if (result < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return result != 0; } @ExportMessage - public void setInheritable(int fd, boolean inheritable, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - if (invokeNode.callInt(this, PosixNativeFunction.set_inheritable, fd, inheritable ? 1 : 0) < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public void setInheritable(int fd, boolean inheritable) throws PosixException { + if (posixNativeFunctionInvoker.set_inheritable(fd, inheritable ? 1 : 0) < 0) { + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public int[] pipe( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int[] pipe() throws PosixException { int[] fds = new int[2]; - if (invokeNode.callInt(this, PosixNativeFunction.call_pipe2, fds) != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeFds = NativeMemory.mallocIntArray(fds.length); + try { + if (posixNativeFunctionInvoker.call_pipe2(nativeFds) != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readIntArrayElements(nativeFds, 0, fds, 0, fds.length); + return fds; + } finally { + NativeMemory.free(nativeFds); } - return fds; } @ExportMessage - public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { int largestFD = findMax(readfds, -1); largestFD = findMax(writefds, largestFD); largestFD = findMax(errorfds, largestFD); @@ -645,13 +862,31 @@ public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeva secs = timeout.getSeconds(); usecs = timeout.getMicroseconds(); } - int result = invokeNode.callInt(this, PosixNativeFunction.call_select, nfds, - readfds, readfds.length, - writefds, writefds.length, - errorfds, errorfds.length, - secs, usecs, selected); - if (result < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeReadFds = NULLPTR; + long nativeWriteFds = NULLPTR; + long nativeErrorFds = NULLPTR; + long nativeSelected = NULLPTR; + try { + nativeReadFds = NativeMemory.copyToNativeIntArrayOrNull(readfds); + nativeWriteFds = NativeMemory.copyToNativeIntArrayOrNull(writefds); + nativeErrorFds = NativeMemory.copyToNativeIntArrayOrNull(errorfds); + nativeSelected = NativeMemory.mallocByteArrayOrNull(selected.length); + int result = posixNativeFunctionInvoker.call_select(nfds, + nativeReadFds, readfds.length, + nativeWriteFds, writefds.length, + nativeErrorFds, errorfds.length, + secs, usecs, nativeSelected); + if (result < 0) { + throw getErrnoAndThrowPosixException(); + } + if (selected.length > 0) { + NativeMemory.readByteArrayElements(nativeSelected, 0, selected, 0, selected.length); + } + } finally { + NativeMemory.free(nativeSelected); + NativeMemory.free(nativeErrorFds); + NativeMemory.free(nativeWriteFds); + NativeMemory.free(nativeReadFds); } return new SelectResult( selectFillInResult(readfds, selected, 0), @@ -679,17 +914,15 @@ private static int findMax(int[] items, int currentMax) { } @ExportMessage - public boolean poll(int fd, boolean forWriting, Timeval timeout, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public boolean poll(int fd, boolean forWriting, Timeval timeout) throws PosixException { long secs = -1, usecs = -1; if (timeout != null) { secs = timeout.getSeconds(); usecs = timeout.getMicroseconds(); } - int result = invokeNode.callInt(this, PosixNativeFunction.call_poll, fd, - forWriting ? 1 : 0, secs, usecs); + int result = posixNativeFunctionInvoker.call_poll(fd, forWriting ? 1 : 0, secs, usecs); if (result < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } if (result == 0) { return false; @@ -699,298 +932,384 @@ public boolean poll(int fd, boolean forWriting, Timeval timeout, } @ExportMessage - public long lseek(int fd, long offset, int how, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long res = invokeNode.callLong(this, PosixNativeFunction.call_lseek, fd, offset, how); + public long lseek(int fd, long offset, int how) throws PosixException { + long res = posixNativeFunctionInvoker.call_lseek(fd, offset, how); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return res; } @ExportMessage - public void ftruncate(int fd, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_ftruncate, fd, length); + public void ftruncate(int fd, long length) throws PosixException { + int res = posixNativeFunctionInvoker.call_ftruncate(fd, length); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public void truncate(Object path, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_truncate, pathToCString(path), length); - if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public void truncate(Object path, long length) throws PosixException { + long pathPtr = pathToNativeCString(path); + try { + int res = posixNativeFunctionInvoker.call_truncate(pathPtr, length); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathPtr); } } @ExportMessage - public void fsync(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_fsync, fd); + public void fsync(int fd) throws PosixException { + int res = posixNativeFunctionInvoker.call_fsync(fd); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - void flock(int fd, int operation, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_flock, fd, operation); + void flock(int fd, int operation) throws PosixException { + int res = posixNativeFunctionInvoker.call_flock(fd, operation); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_fcntl_lock, fd, blocking, lockType, whence, start, length); + void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { + int res = posixNativeFunctionInvoker.call_fcntl_lock(fd, blocking ? 1 : 0, lockType, whence, start, length); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public boolean getBlocking(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.get_blocking, fd); + public boolean getBlocking(int fd) throws PosixException { + int result = posixNativeFunctionInvoker.get_blocking(fd); if (result < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return result != 0; } @ExportMessage - public void setBlocking(int fd, boolean blocking, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - if (invokeNode.callInt(this, PosixNativeFunction.set_blocking, fd, blocking ? 1 : 0) < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public void setBlocking(int fd, boolean blocking) throws PosixException { + if (posixNativeFunctionInvoker.set_blocking(fd, blocking ? 1 : 0) < 0) { + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public int[] getTerminalSize(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int[] getTerminalSize(int fd) throws PosixException { int[] size = new int[2]; - if (invokeNode.callInt(this, PosixNativeFunction.get_terminal_size, fd, size) != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeSize = NativeMemory.mallocIntArray(size.length); + try { + if (posixNativeFunctionInvoker.get_terminal_size(fd, nativeSize) != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readIntArrayElements(nativeSize, 0, size, 0, size.length); + return size; + } finally { + NativeMemory.free(nativeSize); } - return size; } @ExportMessage - public long sysconf(int name, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long result = invokeNode.callLong(this, PosixNativeFunction.call_sysconf, name); + public long sysconf(int name) throws PosixException { + long result = posixNativeFunctionInvoker.call_sysconf(name); if (result == -1) { - int errno = getErrno(invokeNode); + int errno = posixNativeFunctionInvoker.get_errno(); if (errno != 0) { - throw newPosixException(invokeNode, errno); + throw newPosixException(errno); } } return result; } @ExportMessage - public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { long[] out = new long[13]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_fstatat, dirFd, pathToCString(pathname), followSymlinks ? 1 : 0, out); - if (res != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long nativeOut = NULLPTR; + long pathnamePtr = NULLPTR; + try { + nativeOut = NativeMemory.mallocLongArray(out.length); + pathnamePtr = pathToNativeCString(pathname); + int res = posixNativeFunctionInvoker.call_fstatat(dirFd, pathnamePtr, followSymlinks ? 1 : 0, nativeOut); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readLongArrayElements(nativeOut, 0, out, 0, out.length); + return out; + } finally { + NativeMemory.free(pathnamePtr); + NativeMemory.free(nativeOut); } - return out; } @ExportMessage - public long[] fstat(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public long[] fstat(int fd) throws PosixException { long[] out = new long[13]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_fstat, fd, out); - if (res != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long nativeOut = NativeMemory.mallocLongArray(out.length); + try { + int res = posixNativeFunctionInvoker.call_fstat(fd, nativeOut); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readLongArrayElements(nativeOut, 0, out, 0, out.length); + return out; + } finally { + NativeMemory.free(nativeOut); } - return out; } @ExportMessage - public long[] statvfs(Object path, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public long[] statvfs(Object path) throws PosixException { long[] out = new long[11]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_statvfs, pathToCString(path), out); - if (res != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long nativeOut = NULLPTR; + long pathPtr = NULLPTR; + try { + nativeOut = NativeMemory.mallocLongArray(out.length); + pathPtr = pathToNativeCString(path); + int res = posixNativeFunctionInvoker.call_statvfs(pathPtr, nativeOut); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readLongArrayElements(nativeOut, 0, out, 0, out.length); + return out; + } finally { + NativeMemory.free(pathPtr); + NativeMemory.free(nativeOut); } - return out; } @ExportMessage - public long[] fstatvfs(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public long[] fstatvfs(int fd) throws PosixException { long[] out = new long[11]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_fstatvfs, fd, out); - if (res != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long nativeOut = NativeMemory.mallocLongArray(out.length); + try { + int res = posixNativeFunctionInvoker.call_fstatvfs(fd, nativeOut); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readLongArrayElements(nativeOut, 0, out, 0, out.length); + return out; + } finally { + NativeMemory.free(nativeOut); } - return out; } @ExportMessage public Object[] uname( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - byte[] sys = new byte[UNAME_BUF_LENGTH]; - byte[] node = new byte[UNAME_BUF_LENGTH]; - byte[] rel = new byte[UNAME_BUF_LENGTH]; - byte[] ver = new byte[UNAME_BUF_LENGTH]; - byte[] machine = new byte[UNAME_BUF_LENGTH]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_uname, sys, node, rel, ver, machine, UNAME_BUF_LENGTH); - if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); - } - return new Object[]{ - // TODO PyUnicode_DecodeFSDefault - cStringToTruffleString(sys, fromByteArrayNode, switchEncodingFromUtf8Node), - cStringToTruffleString(node, fromByteArrayNode, switchEncodingFromUtf8Node), - cStringToTruffleString(rel, fromByteArrayNode, switchEncodingFromUtf8Node), - cStringToTruffleString(ver, fromByteArrayNode, switchEncodingFromUtf8Node), - cStringToTruffleString(machine, fromByteArrayNode, switchEncodingFromUtf8Node) - }; + @Bind Node inliningTarget, + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws PosixException { + long sysPtr = NULLPTR; + long nodePtr = NULLPTR; + long relPtr = NULLPTR; + long verPtr = NULLPTR; + long machinePtr = NULLPTR; + try { + sysPtr = NativeMemory.mallocByteArray(UNAME_BUF_LENGTH); + nodePtr = NativeMemory.mallocByteArray(UNAME_BUF_LENGTH); + relPtr = NativeMemory.mallocByteArray(UNAME_BUF_LENGTH); + verPtr = NativeMemory.mallocByteArray(UNAME_BUF_LENGTH); + machinePtr = NativeMemory.mallocByteArray(UNAME_BUF_LENGTH); + int res = posixNativeFunctionInvoker.call_uname(sysPtr, nodePtr, relPtr, verPtr, machinePtr, UNAME_BUF_LENGTH); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + return new Object[]{ + // TODO PyUnicode_DecodeFSDefault + zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, sysPtr), + zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nodePtr), + zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, relPtr), + zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, verPtr), + zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, machinePtr) + }; + } finally { + NativeMemory.free(machinePtr); + NativeMemory.free(verPtr); + NativeMemory.free(relPtr); + NativeMemory.free(nodePtr); + NativeMemory.free(sysPtr); + } } @ExportMessage - public void unlinkat(int dirFd, Object pathname, boolean rmdir, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_unlinkat, dirFd, pathToCString(pathname), rmdir ? 1 : 0); - if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { + long pathnamePtr = pathToNativeCString(pathname); + try { + int result = posixNativeFunctionInvoker.call_unlinkat(dirFd, pathnamePtr, rmdir ? 1 : 0); + if (result != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathnamePtr); } } @ExportMessage - public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_linkat, oldFdDir, pathToCString(oldPath), newFdDir, pathToCString(newPath), flags); - if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { + long oldPathPtr = NULLPTR; + long newPathPtr = NULLPTR; + try { + oldPathPtr = pathToNativeCString(oldPath); + newPathPtr = pathToNativeCString(newPath); + int result = posixNativeFunctionInvoker.call_linkat(oldFdDir, oldPathPtr, newFdDir, newPathPtr, flags); + if (result != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(newPathPtr); + NativeMemory.free(oldPathPtr); } } @ExportMessage - public void symlinkat(Object target, int linkpathDirFd, Object linkpath, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_symlinkat, pathToCString(target), linkpathDirFd, pathToCString(linkpath)); - if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { + long targetPtr = NULLPTR; + long linkpathPtr = NULLPTR; + try { + targetPtr = pathToNativeCString(target); + linkpathPtr = pathToNativeCString(linkpath); + int result = posixNativeFunctionInvoker.call_symlinkat(targetPtr, linkpathDirFd, linkpathPtr); + if (result != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(linkpathPtr); + NativeMemory.free(targetPtr); } } @ExportMessage - public void mkdirat(int dirFd, Object pathname, int mode, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_mkdirat, dirFd, pathToCString(pathname), mode); - if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { + long pathnamePtr = pathToNativeCString(pathname); + try { + int result = posixNativeFunctionInvoker.call_mkdirat(dirFd, pathnamePtr, mode); + if (result != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathnamePtr); } } @ExportMessage - public Object getcwd( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Object getcwd() throws PosixException { for (int bufLen = 1024;; bufLen += 1024) { Buffer buffer = Buffer.allocate(bufLen); - int n = invokeNode.callInt(this, PosixNativeFunction.call_getcwd, buffer.data, bufLen); - if (n == 0) { - buffer = buffer.withLength(findZero(buffer.data)); - return buffer; - } - int errno = getErrno(invokeNode); - if (errno != OSErrorEnum.ERANGE.getNumber()) { - throw newPosixException(invokeNode, errno); + long nativeBuffer = NativeMemory.mallocByteArray(bufLen); + try { + int n = posixNativeFunctionInvoker.call_getcwd(nativeBuffer, bufLen); + if (n == 0) { + NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer.data, 0, bufLen); + buffer = buffer.withLength(findZero(buffer.data)); + return buffer; + } + int errno = posixNativeFunctionInvoker.get_errno(); + if (errno != OSErrorEnum.ERANGE.getNumber()) { + throw newPosixException(errno); + } + } finally { + NativeMemory.free(nativeBuffer); } } } @ExportMessage - public void chdir(Object path, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_chdir, pathToCString(path)); - if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void chdir(Object path) throws PosixException { + long pathPtr = pathToNativeCString(path); + try { + int result = posixNativeFunctionInvoker.call_chdir(pathPtr); + if (result != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathPtr); } } @ExportMessage - public void fchdir(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_fchdir, fd); + public void fchdir(int fd) throws PosixException { + int result = posixNativeFunctionInvoker.call_fchdir(fd); if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public boolean isatty(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_isatty, fd) != 0; + public boolean isatty(int fd) { + return posixNativeFunctionInvoker.call_isatty(fd) != 0; } @ExportMessage - public Object opendir(Object path, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long ptr = invokeNode.callLong(this, PosixNativeFunction.call_opendir, pathToCString(path)); - if (ptr == 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public Object opendir(Object path) throws PosixException { + long pathPtr = pathToNativeCString(path); + try { + long ptr = posixNativeFunctionInvoker.call_opendir(pathPtr); + if (ptr == 0) { + throw getErrnoAndThrowPosixException(); + } + return ptr; + } finally { + NativeMemory.free(pathPtr); } - return ptr; } @ExportMessage - public Object fdopendir(int fd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long ptr = invokeNode.callLong(this, PosixNativeFunction.call_fdopendir, fd); + public Object fdopendir(int fd) throws PosixException { + long ptr = posixNativeFunctionInvoker.call_fdopendir(fd); if (ptr == 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } return ptr; } @ExportMessage - public void closedir(Object dirStreamObj, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_closedir, dirStreamObj); + public void closedir(Object dirStreamObj) throws PosixException { + int res = posixNativeFunctionInvoker.call_closedir(((Long) dirStreamObj).longValue()); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public Object readdir(Object dirStreamObj, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Object readdir(Object dirStreamObj) throws PosixException { Buffer name = Buffer.allocate(DIRENT_NAME_BUF_LENGTH); long[] out = new long[2]; - int result; - do { - result = invokeNode.callInt(this, PosixNativeFunction.call_readdir, dirStreamObj, name.data, DIRENT_NAME_BUF_LENGTH, out); - } while (result != 0 && name.data[0] == '.' && (name.data[1] == 0 || (name.data[1] == '.' && name.data[2] == 0))); - if (result != 0) { - return new DirEntry(name.withLength(findZero(name.data)), out[0], (int) out[1]); + long dirStream = ((Long) dirStreamObj).longValue(); + long nativeName = NULLPTR; + long nativeOut = NULLPTR; + try { + nativeName = NativeMemory.mallocByteArray(DIRENT_NAME_BUF_LENGTH); + nativeOut = NativeMemory.mallocLongArray(out.length); + int result; + do { + result = posixNativeFunctionInvoker.call_readdir(dirStream, nativeName, DIRENT_NAME_BUF_LENGTH, nativeOut); + if (result != 0) { + NativeMemory.readByteArrayElements(nativeName, 0, name.data, 0, name.data.length); + } + } while (result != 0 && name.data[0] == '.' && (name.data[1] == 0 || (name.data[1] == '.' && name.data[2] == 0))); + if (result != 0) { + NativeMemory.readLongArrayElements(nativeOut, 0, out, 0, out.length); + return new DirEntry(name.withLength(findZero(name.data)), out[0], (int) out[1]); + } + } finally { + NativeMemory.free(nativeOut); + NativeMemory.free(nativeName); } - int errno = getErrno(invokeNode); + int errno = posixNativeFunctionInvoker.get_errno(); if (errno == 0) { return null; } - throw newPosixException(invokeNode, errno); + throw newPosixException(errno); } @ExportMessage - public void rewinddir(Object dirStreamObj, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - invokeNode.call(this, PosixNativeFunction.call_rewinddir, dirStreamObj); + public void rewinddir(Object dirStreamObj) { + posixNativeFunctionInvoker.call_rewinddir(((Long) dirStreamObj).longValue()); } @ExportMessage @@ -1046,405 +1365,504 @@ public int dirEntryGetType(Object dirEntryObj) { } @ExportMessage - public void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { assert PosixConstants.HAVE_UTIMENSAT.value; assert timespec == null || timespec.length == 4; - int ret = invokeNode.callInt(this, PosixNativeFunction.call_utimensat, dirFd, pathToCString(pathname), wrap(timespec), followSymlinks ? 1 : 0); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long pathnamePtr = NULLPTR; + long timespecPtr = NULLPTR; + try { + pathnamePtr = pathToNativeCString(pathname); + timespecPtr = timespec == null ? NULLPTR : NativeMemory.copyToNativeLongArray(timespec); + int ret = posixNativeFunctionInvoker.call_utimensat(dirFd, pathnamePtr, timespecPtr, followSymlinks ? 1 : 0); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(timespecPtr); + NativeMemory.free(pathnamePtr); } } @ExportMessage - public void futimens(int fd, long[] timespec, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void futimens(int fd, long[] timespec) throws PosixException { assert PosixConstants.HAVE_FUTIMENS.value; assert timespec == null || timespec.length == 4; - int ret = invokeNode.callInt(this, PosixNativeFunction.call_futimens, fd, wrap(timespec)); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long timespecPtr = timespec == null ? NULLPTR : NativeMemory.copyToNativeLongArray(timespec); + try { + int ret = posixNativeFunctionInvoker.call_futimens(fd, timespecPtr); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(timespecPtr); } } @ExportMessage - public void futimes(int fd, Timeval[] timeval, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void futimes(int fd, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; - int ret = invokeNode.callInt(this, PosixNativeFunction.call_futimes, fd, wrap(timeval)); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long timevalPtr = copyTimevalArrayToNativeOrNull(timeval); + try { + int ret = posixNativeFunctionInvoker.call_futimes(fd, timevalPtr); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(timevalPtr); } } @ExportMessage - public void lutimes(Object filename, Timeval[] timeval, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void lutimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; - int ret = invokeNode.callInt(this, PosixNativeFunction.call_lutimes, pathToCString(filename), wrap(timeval)); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long filenamePtr = NULLPTR; + long timevalPtr = NULLPTR; + try { + filenamePtr = pathToNativeCString(filename); + timevalPtr = copyTimevalArrayToNativeOrNull(timeval); + int ret = posixNativeFunctionInvoker.call_lutimes(filenamePtr, timevalPtr); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(timevalPtr); + NativeMemory.free(filenamePtr); } } @ExportMessage - public void utimes(Object filename, Timeval[] timeval, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void utimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; - int ret = invokeNode.callInt(this, PosixNativeFunction.call_utimes, pathToCString(filename), wrap(timeval)); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long filenamePtr = NULLPTR; + long timevalPtr = NULLPTR; + try { + filenamePtr = pathToNativeCString(filename); + timevalPtr = copyTimevalArrayToNativeOrNull(timeval); + int ret = posixNativeFunctionInvoker.call_utimes(filenamePtr, timevalPtr); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(timevalPtr); + NativeMemory.free(filenamePtr); } } @ExportMessage - public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_renameat, oldDirFd, pathToCString(oldPath), newDirFd, pathToCString(newPath)); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { + long oldPathPtr = NULLPTR; + long newPathPtr = NULLPTR; + try { + oldPathPtr = pathToNativeCString(oldPath); + newPathPtr = pathToNativeCString(newPath); + int ret = posixNativeFunctionInvoker.call_renameat(oldDirFd, oldPathPtr, newDirFd, newPathPtr); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(newPathPtr); + NativeMemory.free(oldPathPtr); } } @ExportMessage - public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_faccessat, dirFd, pathToCString(path), mode, effectiveIds ? 1 : 0, followSymlinks ? 1 : 0); + public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) { + long pathPtr = pathToNativeCString(path); + int ret; + try { + ret = posixNativeFunctionInvoker.call_faccessat(dirFd, pathPtr, mode, effectiveIds ? 1 : 0, followSymlinks ? 1 : 0); + } finally { + NativeMemory.free(pathPtr); + } if (ret != 0 && LOGGER.isLoggable(Level.FINE)) { - log(Level.FINE, "faccessat return value: %d, errno: %d", ret, getErrno(invokeNode)); + log(Level.FINE, "faccessat return value: %d, errno: %d", ret, posixNativeFunctionInvoker.get_errno()); } return ret == 0; } @ExportMessage - public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_fchmodat, dirFd, pathToCString(path), mode, followSymlinks ? 1 : 0); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { + long pathPtr = pathToNativeCString(path); + try { + int ret = posixNativeFunctionInvoker.call_fchmodat(dirFd, pathPtr, mode, followSymlinks ? 1 : 0); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathPtr); } } @ExportMessage - public void fchmod(int fd, int mode, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_fchmod, fd, mode); + public void fchmod(int fd, int mode) throws PosixException { + int ret = posixNativeFunctionInvoker.call_fchmod(fd, mode); if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_fchownat, dirFd, pathToCString(path), owner, group, followSymlinks ? 1 : 0); - if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { + long pathPtr = pathToNativeCString(path); + try { + int ret = posixNativeFunctionInvoker.call_fchownat(dirFd, pathPtr, owner, group, followSymlinks ? 1 : 0); + if (ret != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(pathPtr); } } @ExportMessage - public void fchown(int fd, long owner, long group, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int ret = invokeNode.callInt(this, PosixNativeFunction.call_fchown, fd, owner, group); + public void fchown(int fd, long owner, long group) throws PosixException { + int ret = posixNativeFunctionInvoker.call_fchown(fd, owner, group); if (ret != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public Object readlinkat(int dirFd, Object path, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Object readlinkat(int dirFd, Object path) throws PosixException { Buffer buffer = Buffer.allocate(PATH_MAX.value); - long n = invokeNode.callLong(this, PosixNativeFunction.call_readlinkat, dirFd, pathToCString(path), buffer.data, PATH_MAX.value); - if (n < 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + long pathPtr = pathToNativeCString(path); + try { + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(PATH_MAX.value); + try { + long n = posixNativeFunctionInvoker.call_readlinkat(dirFd, pathPtr, nativeBuffer, PATH_MAX.value); + if (n < 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer.data, 0, (int) n); + return buffer.withLength(n); + } finally { + NativeMemory.free(nativeBuffer); + } + } finally { + NativeMemory.free(pathPtr); } - return buffer.withLength(n); } @ExportMessage - public void kill(long pid, int signal, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_kill, pid, signal); + public void kill(long pid, int signal) throws PosixException { + int res = posixNativeFunctionInvoker.call_kill(pid, signal); if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public void raise(int signal, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_raise, signal); + public void raise(int signal) throws PosixException { + int res = posixNativeFunctionInvoker.call_raise(signal); if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public int alarm(int seconds, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_alarm, seconds); + public int alarm(int seconds) { + return posixNativeFunctionInvoker.call_alarm(seconds); } @ExportMessage - public Timeval[] getitimer(int which, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long[] currentValue = new long[4]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_getitimer, which, currentValue); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public Timeval[] getitimer(int which) throws PosixException { + long nativeCurrentValue = NativeMemory.mallocLongArray(4); + try { + int res = posixNativeFunctionInvoker.call_getitimer(which, nativeCurrentValue); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + return unwrapTimeval(nativeCurrentValue); + } finally { + NativeMemory.free(nativeCurrentValue); } - return unwrapTimeval(currentValue); } @ExportMessage - public Timeval[] setitimer(int which, Timeval delay, Timeval interval, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long[] oldValue = new long[4]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_setitimer, which, wrapItimerval(delay, interval), oldValue); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { + long nativeNewValue = NULLPTR; + long nativeOldValue = NULLPTR; + try { + nativeNewValue = wrapItimerval(delay, interval); + nativeOldValue = NativeMemory.mallocLongArray(4); + int res = posixNativeFunctionInvoker.call_setitimer(which, nativeNewValue, nativeOldValue); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + return unwrapTimeval(nativeOldValue); + } finally { + NativeMemory.free(nativeOldValue); + NativeMemory.free(nativeNewValue); } - return unwrapTimeval(oldValue); } @ExportMessage - public void signalSelf(int signal, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void signalSelf(int signal) throws PosixException { if (!ImageInfo.inImageRuntimeCode()) { throw new UnsupportedPosixFeatureException("self-signals are only supported in native standalone"); } - int res = invokeNode.callInt(this, PosixNativeFunction.signal_self, signal); + int res = posixNativeFunctionInvoker.signal_self(signal); if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public void killpg(long pgid, int signal, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_killpg, pgid, signal); + public void killpg(long pgid, int signal) throws PosixException { + int res = posixNativeFunctionInvoker.call_killpg(pgid, signal); if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage public long[] waitpid(long pid, int options, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int[] status = new int[1]; + @Bind Node node) throws PosixException { boolean hasNohang = (options & WNOHANG.getValueIfDefined()) != 0; int subOptions = options | WNOHANG.getValueIfDefined(); - Object wrappedStatus = status; - long res = invokeNode.callLong(this, PosixNativeFunction.call_waitpid, pid, wrappedStatus, subOptions); - while (res == 0 && !hasNohang) { - TruffleSafepoint.setBlockedThreadInterruptible(invokeNode, (ignored) -> { - Thread.sleep(20); - }, null); - res = invokeNode.callLong(this, PosixNativeFunction.call_waitpid, pid, wrappedStatus, subOptions); - } - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeStatus = NativeMemory.callocIntArray(1); + try { + long res = posixNativeFunctionInvoker.call_waitpid(pid, nativeStatus, subOptions); + while (res == 0 && !hasNohang) { + TruffleSafepoint.setBlockedThreadInterruptible(node, (ignored) -> { + Thread.sleep(20); + }, null); + res = posixNativeFunctionInvoker.call_waitpid(pid, nativeStatus, subOptions); + } + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + return new long[]{res, NativeMemory.readInt(nativeStatus)}; + } finally { + NativeMemory.free(nativeStatus); } - return new long[]{res, status[0]}; } @ExportMessage - public boolean wcoredump(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wcoredump, status) != 0; + public boolean wcoredump(int status) { + return posixNativeFunctionInvoker.call_wcoredump(status) != 0; } @ExportMessage - public boolean wifcontinued(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wifcontinued, status) != 0; + public boolean wifcontinued(int status) { + return posixNativeFunctionInvoker.call_wifcontinued(status) != 0; } @ExportMessage - public boolean wifstopped(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wifstopped, status) != 0; + public boolean wifstopped(int status) { + return posixNativeFunctionInvoker.call_wifstopped(status) != 0; } @ExportMessage - public boolean wifsignaled(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wifsignaled, status) != 0; + public boolean wifsignaled(int status) { + return posixNativeFunctionInvoker.call_wifsignaled(status) != 0; } @ExportMessage - public boolean wifexited(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wifexited, status) != 0; + public boolean wifexited(int status) { + return posixNativeFunctionInvoker.call_wifexited(status) != 0; } @ExportMessage - public int wexitstatus(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wexitstatus, status); + public int wexitstatus(int status) { + return posixNativeFunctionInvoker.call_wexitstatus(status); } @ExportMessage - public int wtermsig(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wtermsig, status); + public int wtermsig(int status) { + return posixNativeFunctionInvoker.call_wtermsig(status); } @ExportMessage - public int wstopsig(int status, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_wstopsig, status); + public int wstopsig(int status) { + return posixNativeFunctionInvoker.call_wstopsig(status); } @ExportMessage - public long getuid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getuid); + public long getuid() { + return posixNativeFunctionInvoker.call_getuid(); } @ExportMessage - public long geteuid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_geteuid); + public long geteuid() { + return posixNativeFunctionInvoker.call_geteuid(); } @ExportMessage - public long getgid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getgid); + public long getgid() { + return posixNativeFunctionInvoker.call_getgid(); } @ExportMessage - public long getegid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getegid); + public long getegid() { + return posixNativeFunctionInvoker.call_getegid(); } @ExportMessage - public long getppid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getppid); + public long getppid() { + return posixNativeFunctionInvoker.call_getppid(); } @ExportMessage - public void setpgid(long pid, long pgid, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_setpgid, pid, pgid); + public void setpgid(long pid, long pgid) throws PosixException { + int res = posixNativeFunctionInvoker.call_setpgid(pid, pgid); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public long getpgid(long pid, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long res = invokeNode.callLong(this, PosixNativeFunction.call_getpgid, pid); + public long getpgid(long pid) throws PosixException { + long res = posixNativeFunctionInvoker.call_getpgid(pid); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return res; } @ExportMessage - public long getpgrp(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callLong(this, PosixNativeFunction.call_getpgrp); + public long getpgrp() { + return posixNativeFunctionInvoker.call_getpgrp(); } @ExportMessage - public long getsid(long pid, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long res = invokeNode.callLong(this, PosixNativeFunction.call_getsid, pid); + public long getsid(long pid) throws PosixException { + long res = posixNativeFunctionInvoker.call_getsid(pid); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return res; } @ExportMessage - public long setsid( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long res = invokeNode.callLong(this, PosixNativeFunction.call_setsid); + public long setsid() throws PosixException { + long res = posixNativeFunctionInvoker.call_setsid(); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return res; } @ExportMessage - public long[] getgroups( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public long[] getgroups() throws PosixException { // The first call gets us the number of groups, so we can allocate the output array - int res = invokeNode.callInt(this, PosixNativeFunction.call_getgroups, 0, 0); + int res = posixNativeFunctionInvoker.call_getgroups(0, NULLPTR); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } if (res == 0) { return EMPTY_LONG_ARRAY; } long[] groups = new long[res]; - res = invokeNode.callInt(this, PosixNativeFunction.call_getgroups, groups.length, groups); - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeGroups = NativeMemory.mallocLongArray(groups.length); + try { + res = posixNativeFunctionInvoker.call_getgroups(groups.length, nativeGroups); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readLongArrayElements(nativeGroups, 0, groups, 0, groups.length); + return groups; + } finally { + NativeMemory.free(nativeGroups); } - return groups; } @ExportMessage - public RusageResult getrusage(int who, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long[] result = new long[16]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_getrusage, who, result); - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + public RusageResult getrusage(int who) throws PosixException { + long nativeResult = NativeMemory.mallocLongArray(16); + try { + int res = posixNativeFunctionInvoker.call_getrusage(who, nativeResult); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + return new RusageResult( + Double.longBitsToDouble(NativeMemory.readLongArrayElement(nativeResult, 0)), + Double.longBitsToDouble(NativeMemory.readLongArrayElement(nativeResult, 1)), + NativeMemory.readLongArrayElement(nativeResult, 2), + NativeMemory.readLongArrayElement(nativeResult, 3), + NativeMemory.readLongArrayElement(nativeResult, 4), + NativeMemory.readLongArrayElement(nativeResult, 5), + NativeMemory.readLongArrayElement(nativeResult, 6), + NativeMemory.readLongArrayElement(nativeResult, 7), + NativeMemory.readLongArrayElement(nativeResult, 8), + NativeMemory.readLongArrayElement(nativeResult, 9), + NativeMemory.readLongArrayElement(nativeResult, 10), + NativeMemory.readLongArrayElement(nativeResult, 11), + NativeMemory.readLongArrayElement(nativeResult, 12), + NativeMemory.readLongArrayElement(nativeResult, 13), + NativeMemory.readLongArrayElement(nativeResult, 14), + NativeMemory.readLongArrayElement(nativeResult, 15)); + } finally { + NativeMemory.free(nativeResult); } - return new RusageResult(Double.longBitsToDouble(result[0]), Double.longBitsToDouble(result[1]), - result[2], result[3], result[4], result[5], - result[6], result[7], result[8], result[9], result[10], - result[11], result[12], result[13], result[14], result[15]); } @ExportMessage - public OpenPtyResult openpty(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int[] outvars = new int[2]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_openpty, outvars); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public OpenPtyResult openpty() throws PosixException { + long nativeOutvars = NativeMemory.mallocIntArray(2); + try { + int res = posixNativeFunctionInvoker.call_openpty(nativeOutvars); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + return new OpenPtyResult( + NativeMemory.readIntArrayElement(nativeOutvars, 0), + NativeMemory.readIntArrayElement(nativeOutvars, 1)); + } finally { + NativeMemory.free(nativeOutvars); } - return new OpenPtyResult(outvars[0], outvars[1]); } @ExportMessage - public TruffleString ctermid(@Shared("invoke") @Cached InvokeNativeFunction invokeNode, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - byte[] buf = new byte[L_ctermid.value]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_ctermid, buf); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public TruffleString ctermid( + @Bind Node inliningTarget, + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws PosixException { + long nativeBuf = NativeMemory.mallocByteArray(L_ctermid.value); + try { + int res = posixNativeFunctionInvoker.call_ctermid(nativeBuf); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + // TODO PyUnicode_DecodeFSDefault + return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nativeBuf); + } finally { + NativeMemory.free(nativeBuf); } - // TODO PyUnicode_DecodeFSDefault - return cStringToTruffleString(buf, fromByteArrayNode, switchEncodingFromUtf8Node); } @ExportMessage - public void setenv(Object name, Object value, boolean overwrite, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_setenv, pathToCString(name), pathToCString(value), overwrite ? 1 : 0); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public void setenv(Object name, Object value, boolean overwrite) throws PosixException { + long namePtr = NULLPTR; + long valuePtr = NULLPTR; + try { + namePtr = pathToNativeCString(name); + valuePtr = pathToNativeCString(value); + int res = posixNativeFunctionInvoker.call_setenv(namePtr, valuePtr, overwrite ? 1 : 0); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(valuePtr); + NativeMemory.free(namePtr); } } @ExportMessage - public void unsetenv(Object name, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_unsetenv, pathToCString(name)); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + public void unsetenv(Object name) throws PosixException { + long namePtr = pathToNativeCString(name); + try { + int res = posixNativeFunctionInvoker.call_unsetenv(namePtr); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(namePtr); } } @ExportMessage public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int[] fdsToKeep, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int[] fdsToKeep) throws PosixException { // The following strings and string arrays need to be present in the native function: // - char** of executable names ('\0'-terminated strings with an extra NULL at the end) @@ -1499,14 +1917,14 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en cwdPos = -1; } } catch (OverflowException e) { - throw newPosixException(invokeNode, OSErrorEnum.E2BIG.getNumber()); + throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } // This also guarantees that offsetsLen did not overflow: we add +1 to dataLen for each // '\0', i.e. dataLen >= "number of strings" and offsetsLen < "number of strings" + 3 // (3 accounts for the NULL terminating the executables, args and env arrays). if (dataLen >= Integer.MAX_VALUE - 3) { - throw newPosixException(invokeNode, OSErrorEnum.E2BIG.getNumber()); + throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } byte[] data = new byte[(int) dataLen]; @@ -1527,25 +1945,35 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en } assert offset == dataLen; - int res = invokeNode.callInt(this, PosixNativeFunction.fork_exec, - data, offsets, offsets.length, argsPos, envPos, cwdPos, - stdinReadFd, stdinWriteFd, - stdoutReadFd, stdoutWriteFd, - stderrReadFd, stderrWriteFd, - errPipeReadFd, errPipeWriteFd, - closeFds ? 1 : 0, - restoreSignals ? 1 : 0, - callSetsid ? 1 : 0, - fdsToKeep, fdsToKeep.length); - if (res == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeData = NULLPTR; + long nativeOffsets = NULLPTR; + long nativeFdsToKeep = NULLPTR; + try { + nativeData = NativeMemory.copyToNativeByteArray(data); + nativeOffsets = NativeMemory.copyToNativeLongArray(offsets); + nativeFdsToKeep = NativeMemory.copyToNativeIntArrayOrNull(fdsToKeep); + int res = posixNativeFunctionInvoker.fork_exec(nativeData, nativeOffsets, offsets.length, argsPos, envPos, cwdPos, + stdinReadFd, stdinWriteFd, + stdoutReadFd, stdoutWriteFd, + stderrReadFd, stderrWriteFd, + errPipeReadFd, errPipeWriteFd, + closeFds ? 1 : 0, + restoreSignals ? 1 : 0, + callSetsid ? 1 : 0, + nativeFdsToKeep, fdsToKeep.length); + if (res == -1) { + throw getErrnoAndThrowPosixException(); + } + return res; + } finally { + NativeMemory.free(nativeFdsToKeep); + NativeMemory.free(nativeOffsets); + NativeMemory.free(nativeData); } - return res; } @ExportMessage - public void execv(Object pathname, Object[] args, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void execv(Object pathname, Object[] args) throws PosixException { // The following strings and string arrays need to be present in the native function: // - char* - the pathname ('\0'-terminated string) @@ -1569,7 +1997,7 @@ public void execv(Object pathname, Object[] args, // since we are using Java arrays limited to 2^31-1. dataLen = addLengthsOfCStrings(pathnameLen + 1L, args); } catch (OverflowException e) { - throw newPosixException(invokeNode, OSErrorEnum.E2BIG.getNumber()); + throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } // This also guarantees that offsetsLen did not overflow: we add +1 to dataLen for each @@ -1578,7 +2006,7 @@ public void execv(Object pathname, Object[] args, // Also, dataLen > pathnameLen, so this check makes sure that the cast of pathnameLen to int // below is safe. if (dataLen >= Integer.MAX_VALUE - 1) { - throw newPosixException(invokeNode, OSErrorEnum.E2BIG.getNumber()); + throw newPosixException(OSErrorEnum.E2BIG.getNumber()); } byte[] data = new byte[(int) dataLen]; @@ -1588,14 +2016,27 @@ public void execv(Object pathname, Object[] args, long offset = encodeCStringArray(data, pathnameLen + 1L, offsets, 1, args); assert offset == dataLen; - invokeNode.call(this, PosixNativeFunction.call_execv, data, offsets, offsets.length); - throw getErrnoAndThrowPosixException(invokeNode); + long nativeData = NULLPTR; + long nativeOffsets = NULLPTR; + try { + nativeData = NativeMemory.copyToNativeByteArray(data); + nativeOffsets = NativeMemory.copyToNativeLongArray(offsets); + posixNativeFunctionInvoker.call_execv(nativeData, nativeOffsets, offsets.length); + throw getErrnoAndThrowPosixException(); + } finally { + NativeMemory.free(nativeOffsets); + NativeMemory.free(nativeData); + } } @ExportMessage - public int system(Object command, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_system, pathToCString(command)); + public int system(Object command) { + long commandPtr = pathToNativeCString(command); + try { + return posixNativeFunctionInvoker.call_system(commandPtr); + } finally { + NativeMemory.free(commandPtr); + } } private static long addLengthsOfCStrings(long prevLen, Object[] src) throws OverflowException { @@ -1638,11 +2079,10 @@ public MMapHandle(long pointer, long length) { } @ExportMessage - public Object mmap(long length, int prot, int flags, int fd, long offset, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - long address = invokeNode.callLong(this, PosixNativeFunction.call_mmap, length, prot, flags, fd, offset); + public Object mmap(long length, int prot, int flags, int fd, long offset) throws PosixException { + long address = posixNativeFunctionInvoker.call_mmap(length, prot, flags, fd, offset); if (address == 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } return new MMapHandle(address, length); } @@ -1684,24 +2124,22 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) { } @ExportMessage - public void mmapFlush(Object mmap, long offset, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { + public void mmapFlush(Object mmap, long offset, long length) { MMapHandle handle = (MMapHandle) mmap; checkIndexAndLen(handle, offset, length); - invokeNode.call(this, PosixNativeFunction.call_msync, handle.pointer, offset, length); + posixNativeFunctionInvoker.call_msync(handle.pointer, offset, length); } @ExportMessage - public void mmapUnmap(Object mmap, long length, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void mmapUnmap(Object mmap, long length) throws PosixException { MMapHandle handle = (MMapHandle) mmap; if (length != handle.length) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new IllegalArgumentException(); } - int result = invokeNode.callInt(this, PosixNativeFunction.call_munmap, handle.pointer, length); + int result = posixNativeFunctionInvoker.call_munmap(handle.pointer, length); if (result != 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } } @@ -1724,280 +2162,416 @@ private static void checkIndexAndLen(MMapHandle handle, long index, long length) } @ExportMessage - public int socket(int domain, int type, int protocol, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_socket, domain, type, protocol); + public int socket(int domain, int type, int protocol) throws PosixException { + int result = posixNativeFunctionInvoker.call_socket(domain, type, protocol); if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } return result; } @ExportMessage - public AcceptResult accept(int sockfd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public AcceptResult accept(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); - int result = invokeNode.callInt(this, PosixNativeFunction.call_accept, sockfd, addr.data, addr.len); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeAddr = NULLPTR; + long nativeAddrLen = NULLPTR; + try { + nativeAddr = NativeMemory.mallocByteArray(addr.data.length); + nativeAddrLen = NativeMemory.mallocIntArray(1); + int result = posixNativeFunctionInvoker.call_accept(sockfd, nativeAddr, nativeAddrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + readNativeSockAddr(nativeAddr, nativeAddrLen, addr); + return new AcceptResult(result, addr); + } finally { + NativeMemory.free(nativeAddrLen); + NativeMemory.free(nativeAddr); } - return new AcceptResult(result, addr); } @ExportMessage - public void bind(int sockfd, UniversalSockAddr usa, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void bind(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; - int result = invokeNode.callInt(this, PosixNativeFunction.call_bind, sockfd, addr.data, addr.getLen()); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + int addrLen = addr.getLen(); + long nativeAddr = NULLPTR; + try { + nativeAddr = NativeMemory.copyToNativeByteArray(addr.data, 0, addrLen); + int result = posixNativeFunctionInvoker.call_bind(sockfd, nativeAddr, addrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(nativeAddr); } } @ExportMessage - public void connect(int sockfd, UniversalSockAddr usa, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void connect(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; - int result = invokeNode.callInt(this, PosixNativeFunction.call_connect, sockfd, addr.data, addr.getLen()); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + int addrLen = addr.getLen(); + long nativeAddr = NULLPTR; + try { + nativeAddr = NativeMemory.copyToNativeByteArray(addr.data, 0, addrLen); + int result = posixNativeFunctionInvoker.call_connect(sockfd, nativeAddr, addrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(nativeAddr); } } @ExportMessage - public void listen(int sockfd, int backlog, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int result = invokeNode.callInt(this, PosixNativeFunction.call_listen, sockfd, backlog); + public void listen(int sockfd, int backlog) throws PosixException { + int result = posixNativeFunctionInvoker.call_listen(sockfd, backlog); if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public UniversalSockAddr getpeername(int sockfd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public UniversalSockAddr getpeername(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); - int result = invokeNode.callInt(this, PosixNativeFunction.call_getpeername, sockfd, addr.data, addr.len); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeAddr = NULLPTR; + long nativeAddrLen = NULLPTR; + try { + nativeAddr = NativeMemory.mallocByteArray(addr.data.length); + nativeAddrLen = NativeMemory.mallocIntArray(1); + int result = posixNativeFunctionInvoker.call_getpeername(sockfd, nativeAddr, nativeAddrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + readNativeSockAddr(nativeAddr, nativeAddrLen, addr); + return addr; + } finally { + NativeMemory.free(nativeAddrLen); + NativeMemory.free(nativeAddr); } - return addr; } @ExportMessage - public UniversalSockAddr getsockname(int sockfd, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public UniversalSockAddr getsockname(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); - int result = invokeNode.callInt(this, PosixNativeFunction.call_getsockname, sockfd, addr.data, addr.len); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeAddr = NULLPTR; + long nativeAddrLen = NULLPTR; + try { + nativeAddr = NativeMemory.mallocByteArray(addr.data.length); + nativeAddrLen = NativeMemory.mallocIntArray(1); + int result = posixNativeFunctionInvoker.call_getsockname(sockfd, nativeAddr, nativeAddrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + readNativeSockAddr(nativeAddr, nativeAddrLen, addr); + return addr; + } finally { + NativeMemory.free(nativeAddrLen); + NativeMemory.free(nativeAddr); } - return addr; } @ExportMessage - public int send(int sockfd, byte[] buf, int offset, int len, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); - int result = invokeNode.callInt(this, PosixNativeFunction.call_send, sockfd, buf, offset, len, flags); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); + try { + NativeMemory.writeByteArrayElements(nativeBuffer, 0, buf, offset, len); + posixNativeFunctionInvoker.set_errno(0); + int result = posixNativeFunctionInvoker.call_send(sockfd, nativeBuffer, len, flags); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + return result; + } finally { + NativeMemory.free(nativeBuffer); } - return result; } @ExportMessage - public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr usa, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr usa) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl destAddr = (UniversalSockAddrImpl) usa; - int result = invokeNode.callInt(this, PosixNativeFunction.call_sendto, sockfd, buf, offset, len, flags, destAddr.data, destAddr.getLen()); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + int destAddrLen = destAddr.getLen(); + long nativeBuffer = NULLPTR; + long nativeDestAddr = NULLPTR; + try { + nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); + NativeMemory.writeByteArrayElements(nativeBuffer, 0, buf, offset, len); + nativeDestAddr = NativeMemory.mallocByteArrayOrNull(destAddrLen); + NativeMemory.writeByteArrayElements(nativeDestAddr, 0, destAddr.data, 0, destAddrLen); + posixNativeFunctionInvoker.set_errno(0); + int result = posixNativeFunctionInvoker.call_sendto(sockfd, nativeBuffer, 0, len, flags, nativeDestAddr, destAddrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + return result; + } finally { + NativeMemory.free(nativeDestAddr); + NativeMemory.free(nativeBuffer); } - return result; } @ExportMessage - public int recv(int sockfd, byte[] buf, int offset, int len, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); - int result = invokeNode.callInt(this, PosixNativeFunction.call_recv, sockfd, buf, offset, len, flags); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); + try { + posixNativeFunctionInvoker.set_errno(0); + int result = posixNativeFunctionInvoker.call_recv(sockfd, nativeBuffer, len, flags); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuffer, 0, buf, offset, result); + return result; + } finally { + NativeMemory.free(nativeBuffer); } - return result; } @ExportMessage - public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl srcAddr = new UniversalSockAddrImpl(this); - int result = invokeNode.callInt(this, PosixNativeFunction.call_recvfrom, sockfd, buf, offset, len, flags, srcAddr.data, srcAddr.len); - if (result == -1) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeBuffer = NULLPTR; + long nativeSrcAddr = NULLPTR; + long nativeAddrLen = NULLPTR; + try { + nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); + nativeSrcAddr = NativeMemory.mallocByteArray(srcAddr.data.length); + nativeAddrLen = NativeMemory.mallocIntArray(1); + posixNativeFunctionInvoker.set_errno(0); + int result = posixNativeFunctionInvoker.call_recvfrom(sockfd, nativeBuffer, 0, len, flags, nativeSrcAddr, nativeAddrLen); + if (result == -1) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuffer, 0, buf, offset, result); + readNativeSockAddr(nativeSrcAddr, nativeAddrLen, srcAddr); + return new RecvfromResult(result, srcAddr); + } finally { + NativeMemory.free(nativeAddrLen); + NativeMemory.free(nativeSrcAddr); + NativeMemory.free(nativeBuffer); } - return new RecvfromResult(result, srcAddr); } @ExportMessage - public void shutdown(int sockfd, int how, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_shutdown, sockfd, how); + public void shutdown(int sockfd, int how) throws PosixException { + int res = posixNativeFunctionInvoker.call_shutdown(sockfd, how); if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; - int[] bufLen = new int[]{optlen}; - int res = invokeNode.callInt(this, PosixNativeFunction.call_getsockopt, sockfd, level, optname, optval, bufLen); - if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeOptval = NULLPTR; + long nativeBufLen = NULLPTR; + try { + nativeOptval = NativeMemory.mallocByteArray(Math.max(optlen, 1)); + nativeBufLen = NativeMemory.mallocIntArray(1); + NativeMemory.writeInt(nativeBufLen, optlen); + int res = posixNativeFunctionInvoker.call_getsockopt(sockfd, level, optname, nativeOptval, nativeBufLen); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + int actualLen = NativeMemory.readInt(nativeBufLen); + if (actualLen < 0 || actualLen > optval.length) { + throw CompilerDirectives.shouldNotReachHere("Unexpected socket option length in getsockopt"); + } + if (actualLen > 0) { + NativeMemory.readByteArrayElements(nativeOptval, 0, optval, 0, actualLen); + } + return actualLen; + } finally { + NativeMemory.free(nativeBufLen); + NativeMemory.free(nativeOptval); } - return bufLen[0]; } @ExportMessage - public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; - int res = invokeNode.callInt(this, PosixNativeFunction.call_setsockopt, sockfd, level, optname, optval, optlen); - if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeOptval = NULLPTR; + try { + nativeOptval = NativeMemory.copyToNativeByteArrayOrNull(optval, 0, optlen); + int res = posixNativeFunctionInvoker.call_setsockopt(sockfd, level, optname, nativeOptval, optlen); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(nativeOptval); } } @ExportMessage - public int inet_addr(Object src, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.call_inet_addr, pathToCString(src)); + public int inet_addr(Object src) { + long srcPtr = pathToNativeCString(src); + try { + return posixNativeFunctionInvoker.call_inet_addr(srcPtr); + } finally { + NativeMemory.free(srcPtr); + } } @ExportMessage - public int inet_aton(Object src, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws InvalidAddressException { - long r = invokeNode.callLong(this, PosixNativeFunction.call_inet_aton, pathToCString(src)); - if (r < 0) { - throw new InvalidAddressException(); + public int inet_aton(Object src) throws InvalidAddressException { + long srcPtr = pathToNativeCString(src); + try { + long r = posixNativeFunctionInvoker.call_inet_aton(srcPtr); + if (r < 0) { + throw new InvalidAddressException(); + } + return (int) r; + } finally { + NativeMemory.free(srcPtr); } - return (int) r; } @ExportMessage - public Object inet_ntoa(int src, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) { + public Object inet_ntoa(int src) { Buffer buf = Buffer.allocate(INET_ADDRSTRLEN.value); - int len = invokeNode.callInt(this, PosixNativeFunction.call_inet_ntoa, src, buf.data); - return buf.withLength(len); + long nativeBuf = NativeMemory.mallocByteArray(INET_ADDRSTRLEN.value); + try { + int len = posixNativeFunctionInvoker.call_inet_ntoa(src, nativeBuf); + if (len > 0) { + NativeMemory.readByteArrayElements(nativeBuf, 0, buf.data, 0, len); + } + return buf.withLength(len); + } finally { + NativeMemory.free(nativeBuf); + } } @ExportMessage - public byte[] inet_pton(int family, Object src, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException, InvalidAddressException { + public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { byte[] buf = new byte[family == AF_INET.value ? 4 : 16]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_inet_pton, family, pathToCString(src), buf); - // Rather unusually, the return value of 0 does not indicate success but is used by - // inet_pton to report invalid format of the address (without setting errno). - // Success is reported by returning 1. - if (res == 1) { - return buf; - } - if (res == 0) { - throw new InvalidAddressException(); + long srcPtr = NULLPTR; + long nativeBuf = NULLPTR; + try { + srcPtr = pathToNativeCString(src); + nativeBuf = NativeMemory.mallocByteArray(buf.length); + int res = posixNativeFunctionInvoker.call_inet_pton(family, srcPtr, nativeBuf); + // Rather unusually, the return value of 0 does not indicate success but is used by + // inet_pton to report invalid format of the address (without setting errno). + // Success is reported by returning 1. + if (res == 1) { + NativeMemory.readByteArrayElements(nativeBuf, 0, buf, 0, buf.length); + return buf; + } + if (res == 0) { + throw new InvalidAddressException(); + } + throw getErrnoAndThrowPosixException(); + } finally { + NativeMemory.free(nativeBuf); + NativeMemory.free(srcPtr); } - throw getErrnoAndThrowPosixException(invokeNode); } @ExportMessage - public Object inet_ntop(int family, byte[] src, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Object inet_ntop(int family, byte[] src) throws PosixException { if ((family == AF_INET.value && src.length < 4) || (family == AF_INET6.value && src.length < 16)) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new IllegalArgumentException("Invalid length of IPv4/6 address"); } Buffer buf = Buffer.allocate(INET6_ADDRSTRLEN.value); - int res = invokeNode.callInt(this, PosixNativeFunction.call_inet_ntop, family, src, buf.data, INET6_ADDRSTRLEN.value); - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeSrc = NULLPTR; + long nativeBuf = NULLPTR; + try { + nativeSrc = NativeMemory.copyToNativeByteArray(src); + nativeBuf = NativeMemory.mallocByteArray(INET6_ADDRSTRLEN.value); + int res = posixNativeFunctionInvoker.call_inet_ntop(family, nativeSrc, nativeBuf, INET6_ADDRSTRLEN.value); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuf, 0, buf.data, 0, buf.data.length); + return buf.withLength(findZero(buf.data)); + } finally { + NativeMemory.free(nativeBuf); + NativeMemory.free(nativeSrc); } - return buf.withLength(findZero(buf.data)); } @ExportMessage - public Object gethostname(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + public Object gethostname() throws PosixException { int maxLen = (HOST_NAME_MAX.defined ? HOST_NAME_MAX.getValueIfDefined() : _POSIX_HOST_NAME_MAX.value) + 1; Buffer buf = Buffer.allocate(maxLen); - int res = invokeNode.callInt(this, PosixNativeFunction.call_gethostname, buf.data, maxLen); - if (res != 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeBuf = NativeMemory.mallocByteArray(maxLen); + try { + int res = posixNativeFunctionInvoker.call_gethostname(nativeBuf, maxLen); + if (res != 0) { + throw getErrnoAndThrowPosixException(); + } + NativeMemory.readByteArrayElements(nativeBuf, 0, buf.data, 0, buf.data.length); + return buf.withLength(findZero(buf.data)); + } finally { + NativeMemory.free(nativeBuf); } - return buf.withLength(findZero(buf.data)); } @ExportMessage public Object[] getnameinfo(UniversalSockAddr usa, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws GetAddrInfoException { + @Bind Node inliningTarget, + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { Buffer host = Buffer.allocate(NI_MAXHOST.value); Buffer serv = Buffer.allocate(NI_MAXSERV.value); UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; - int res = invokeNode.callInt(this, PosixNativeFunction.call_getnameinfo, addr.data, addr.getLen(), host.data, NI_MAXHOST.value, serv.data, NI_MAXSERV.value, flags); - if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(res, invokeNode, fromByteArrayNode, switchEncodingFromUtf8Node)); + long nativeAddr = NULLPTR; + long nativeHost = NULLPTR; + long nativeServ = NULLPTR; + try { + nativeAddr = NativeMemory.copyToNativeByteArray(addr.data, 0, addr.getLen()); + nativeHost = NativeMemory.mallocByteArray(NI_MAXHOST.value); + nativeServ = NativeMemory.mallocByteArray(NI_MAXSERV.value); + int res = posixNativeFunctionInvoker.call_getnameinfo(nativeAddr, addr.getLen(), nativeHost, NI_MAXHOST.value, nativeServ, NI_MAXSERV.value, flags); + if (res != 0) { + throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + } + NativeMemory.readByteArrayElements(nativeHost, 0, host.data, 0, host.data.length); + NativeMemory.readByteArrayElements(nativeServ, 0, serv.data, 0, serv.data.length); + return new Object[]{ + host.withLength(findZero(host.data)), + serv.withLength(findZero(serv.data)), + }; + } finally { + NativeMemory.free(nativeServ); + NativeMemory.free(nativeHost); + NativeMemory.free(nativeAddr); } - return new Object[]{ - host.withLength(findZero(host.data)), - serv.withLength(findZero(serv.data)), - }; } @ExportMessage public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws GetAddrInfoException { - long[] ptr = new long[1]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_getaddrinfo, pathToCStringOrNull(node), pathToCStringOrNull(service), family, sockType, protocol, flags, ptr); - if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(res, invokeNode, fromByteArrayNode, switchEncodingFromUtf8Node)); + @Bind Node inliningTarget, + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { + long nodePtr = NULLPTR; + long servicePtr = NULLPTR; + long nativePtr = NULLPTR; + try { + nodePtr = pathToNativeCStringOrNull(node); + servicePtr = pathToNativeCStringOrNull(service); + nativePtr = NativeMemory.mallocLongArray(1); + int res = posixNativeFunctionInvoker.call_getaddrinfo(nodePtr, servicePtr, family, sockType, protocol, flags, nativePtr); + if (res != 0) { + throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + } + long head = NativeMemory.readLong(nativePtr); + assert head != 0; // getaddrinfo should return at least one result + return new AddrInfoCursorImpl(this, head); + } finally { + NativeMemory.free(nativePtr); + NativeMemory.free(servicePtr); + NativeMemory.free(nodePtr); } - assert ptr[0] != 0; // getaddrinfo should return at least one result - return new AddrInfoCursorImpl(this, ptr[0], invokeNode); } @ExportMessage public TruffleString crypt(TruffleString word, TruffleString salt, - @Bind Node inliningTarget, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, + @Bind Node raisingNode, @Shared("toUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingToUtf8Node, @Shared("tsCopyBytes") @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode, - @Cached TruffleString.FromZeroTerminatedNativePointerNode fromZeroTerminatedNativePointerNode, - @Cached TruffleString.AsManagedNode asManagedNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - /* - * We don't want to link the posix library with libcrypt, because it might not be available - * on the target system and would make the whole posix library fail to load. So we load it - * dynamically on demand. - */ - if (injectBranchProbability(SLOWPATH_PROBABILITY, cryptLibrary == null)) { - try { - cryptLibrary = InvokeNativeFunction.loadLibrary(inliningTarget, this, PythonLanguage.getPythonOS() != PythonOS.PLATFORM_DARWIN ? "libcrypt.so" : null); - } catch (Throwable e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw PRaiseNode.raiseStatic(invokeNode, PythonBuiltinClassType.SystemError, ErrorMessages.UNABLE_TO_LOAD_LIBCRYPT); - } - } - PosixNativeFunction function = PosixNativeFunction.crypt; - if (injectBranchProbability(SLOWPATH_PROBABILITY, cachedFunctions.get(function.ordinal()) == null)) { - InvokeNativeFunction.loadFunction(inliningTarget, this, cryptLibrary, function); - } - FunctionWithSignature funObject = cachedFunctions.get(function.ordinal()); + @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws PosixException { /* * From the manpage: Upon successful completion, crypt returns a pointer to a string which * encodes both the hashed passphrase, and the settings that were used to encode it. See @@ -2006,33 +2580,48 @@ public TruffleString crypt(TruffleString word, TruffleString salt, * safe to call crypt from multiple threads simultaneously. Upon error, it may return a NULL * pointer or a pointer to an invalid hash, depending on the implementation. */ - // Note GIL is not enough as crypt is using global memory, so we need a really global lock - synchronized (CRYPT_LOCK) { - long resultPtr; - Object[] args = new Object[]{ - stringToUTF8CString(word, switchEncodingToUtf8Node, copyToByteArrayNode), - stringToUTF8CString(salt, switchEncodingToUtf8Node, copyToByteArrayNode)}; - try { - Object interopResult = invokeNode.functionInterop.call(funObject.signature(), funObject.function(), args); - resultPtr = invokeNode.getResultInterop().asLong(interopResult); - } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); + long wordPtr = NULLPTR; + long saltPtr = NULLPTR; + try { + wordPtr = stringToNativeUTF8CString(word, switchEncodingToUtf8Node, copyToByteArrayNode); + saltPtr = stringToNativeUTF8CString(salt, switchEncodingToUtf8Node, copyToByteArrayNode); + // Note GIL is not enough as crypt is using global memory, we need a really global lock + synchronized (CRYPT_LOCK) { + long resultPtr; + try { + resultPtr = cryptNativeFunctionInvoker.crypt(wordPtr, saltPtr); + } catch (UnsupportedOperationException e) { + // Thrown by the generated invoker when CryptNativeFunction.loadNativeLibrary + // fails during its lazy library initialization path. + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw PRaiseNode.raiseStatic(raisingNode, PythonBuiltinClassType.SystemError, ErrorMessages.UNABLE_TO_LOAD_LIBCRYPT); + } + // CPython doesn't handle the case of "invalid hash" return specially and neither do + // we + if (resultPtr == 0) { + throw getErrnoAndThrowPosixException(); + } + return zeroTerminatedUtf8ToTruffleStringNode.execute(raisingNode, resultPtr); + } + } finally { + if (wordPtr != NULLPTR) { + NativeMemory.free(wordPtr); } - // CPython doesn't handle the case of "invalid hash" return specially and neither do we - if (resultPtr == 0) { - throw getErrnoAndThrowPosixException(invokeNode); + if (saltPtr != NULLPTR) { + NativeMemory.free(saltPtr); } - // TODO PyUnicode_DecodeFSDefault - TruffleString utf8 = fromZeroTerminatedNativePointerNode.execute8Bit(resultPtr, 0, UTF_8, false); - return asManagedNode.execute(switchEncodingFromUtf8Node.execute(utf8, TS_ENCODING), TS_ENCODING); } } - private TruffleString gai_strerror(int errorCode, InvokeNativeFunction invokeNode, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) { - byte[] buf = new byte[1024]; - invokeNode.call(this, PosixNativeFunction.call_gai_strerror, errorCode, buf, buf.length); - // TODO PyUnicode_DecodeLocale - return cStringToTruffleString(buf, fromByteArrayNode, switchEncodingFromUtf8Node); + private TruffleString gai_strerror(Node inliningTarget, int errorCode, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { + long nativeBuf = NativeMemory.mallocByteArray(1024); + try { + posixNativeFunctionInvoker.call_gai_strerror(errorCode, nativeBuf, 1024); + // TODO PyUnicode_DecodeLocale + return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nativeBuf); + } finally { + NativeMemory.free(nativeBuf); + } } /** @@ -2075,12 +2664,26 @@ private static class AddrInfo { private final long[] longData = new long[2]; private byte[] socketAddress; - private void update(long ptr, NFIPosixSupport nfiPosixSupport, InvokeNativeFunction invokeNode) { + private void update(long ptr, NFIPosixSupport nfiPosixSupport) { socketAddress = new byte[(int) nfiPosixSupport.getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; - int res = invokeNode.callInt(nfiPosixSupport, PosixNativeFunction.get_addrinfo_members, ptr, intData, longData, - socketAddress); - if (res != 0) { - throw shouldNotReachHere("the length of ai_canonname does not fit into an int"); + long nativeIntData = NULLPTR; + long nativeLongData = NULLPTR; + long nativeSocketAddress = NULLPTR; + try { + nativeIntData = NativeMemory.mallocIntArray(intData.length); + nativeLongData = NativeMemory.mallocLongArray(longData.length); + nativeSocketAddress = NativeMemory.mallocByteArray(socketAddress.length); + int res = nfiPosixSupport.posixNativeFunctionInvoker.get_addrinfo_members(ptr, nativeIntData, nativeLongData, nativeSocketAddress); + if (res != 0) { + throw shouldNotReachHere("the length of ai_canonname does not fit into an int"); + } + NativeMemory.readIntArrayElements(nativeIntData, 0, intData, 0, intData.length); + NativeMemory.readLongArrayElements(nativeLongData, 0, longData, 0, longData.length); + NativeMemory.readByteArrayElements(nativeSocketAddress, 0, socketAddress, 0, socketAddress.length); + } finally { + NativeMemory.free(nativeSocketAddress); + NativeMemory.free(nativeLongData); + NativeMemory.free(nativeIntData); } } @@ -2129,28 +2732,28 @@ protected static class AddrInfoCursorImpl implements AddrInfoCursor { private long head; private AddrInfo info; - AddrInfoCursorImpl(NFIPosixSupport nfiPosixSupport, long head, InvokeNativeFunction invokeNode) { + AddrInfoCursorImpl(NFIPosixSupport nfiPosixSupport, long head) { this.nfiPosixSupport = nfiPosixSupport; this.head = head; info = new AddrInfo(); - info.update(head, nfiPosixSupport, invokeNode); + info.update(head, nfiPosixSupport); } @ExportMessage - void release(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { + void release() { checkReleased(); - invokeNode.call(nfiPosixSupport, PosixNativeFunction.call_freeaddrinfo, head); + nfiPosixSupport.posixNativeFunctionInvoker.call_freeaddrinfo(head); head = 0; } @ExportMessage - boolean next(@Shared("invoke") @Cached InvokeNativeFunction invokeNode) { + boolean next() { checkReleased(); long nextPtr = info.getNextPtr(); if (nextPtr == 0) { return false; } - info.update(nextPtr, nfiPosixSupport, invokeNode); + info.update(nextPtr, nfiPosixSupport); return true; } @@ -2249,7 +2852,7 @@ protected static class UniversalSockAddrImpl implements UniversalSockAddr { private final NFIPosixSupport nfiPosixSupport; private final byte[] data; - private final int[] len = new int[]{0}; + private int len = 0; UniversalSockAddrImpl(NFIPosixSupport nfiPosixSupport) { this.nfiPosixSupport = nfiPosixSupport; @@ -2343,52 +2946,54 @@ long getConstant(NFIPosixConstants constant) { } int getLen() { - return len[0]; + return len; } void setLen(int len) { - this.len[0] = len; + this.len = len; } } @ExportMessage - long semOpen(Object name, int openFlags, int mode, int value, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - Object ptr = invokeNode.call(this, PosixNativeFunction.call_sem_open, pathToCString(name), openFlags, mode, value); - if (invokeNode.getResultInterop().isNull(ptr)) { - throw getErrnoAndThrowPosixException(invokeNode); - } + long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { + long namePtr = pathToNativeCString(name); try { - return invokeNode.getResultInterop().asPointer(ptr); - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); + long ptr = posixNativeFunctionInvoker.call_sem_open(namePtr, openFlags, mode, value); + if (ptr == NULLPTR) { + throw getErrnoAndThrowPosixException(); + } + return ptr; + } finally { + NativeMemory.free(namePtr); } } @ExportMessage - void semClose(long handle, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_close, handle); + void semClose(long handle) throws PosixException { + int res = posixNativeFunctionInvoker.call_sem_close(handle); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - void semUnlink(Object name, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_unlink, pathToCString(name)); - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + void semUnlink(Object name) throws PosixException { + long namePtr = pathToNativeCString(name); + try { + int res = posixNativeFunctionInvoker.call_sem_unlink(namePtr); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + } finally { + NativeMemory.free(namePtr); } } private static final UnsupportedPosixFeatureException NO_SEM_GETVALUE_EXCEPTION = new UnsupportedPosixFeatureException("sem_getvalue is not available on the current platform"); @ExportMessage - int semGetValue(long handle, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + int semGetValue(long handle) throws PosixException { /* * msimacek: It works on Linux, and it doesn't work on Darwin. It might work on some other * Unix-likes, but it's hard to check, so let's assume it only works on Linux for now @@ -2396,42 +3001,43 @@ int semGetValue(long handle, if (PythonLanguage.getPythonOS() != PythonOS.PLATFORM_LINUX) { throw NO_SEM_GETVALUE_EXCEPTION; } - int[] value = new int[1]; - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_getvalue, handle, value); - if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + long nativeValue = NativeMemory.mallocIntArray(1); + try { + int res = posixNativeFunctionInvoker.call_sem_getvalue(handle, nativeValue); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + return NativeMemory.readInt(nativeValue); + } finally { + NativeMemory.free(nativeValue); } - return value[0]; } @ExportMessage - void semPost(long handle, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_post, handle); + void semPost(long handle) throws PosixException { + int res = posixNativeFunctionInvoker.call_sem_post(handle); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - void semWait(long handle, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_wait, handle); + void semWait(long handle) throws PosixException { + int res = posixNativeFunctionInvoker.call_sem_wait(handle); if (res < 0) { - throw getErrnoAndThrowPosixException(invokeNode); + throw getErrnoAndThrowPosixException(); } } @ExportMessage - boolean semTryWait(long handle, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_trywait, handle); + boolean semTryWait(long handle) throws PosixException { + int res = posixNativeFunctionInvoker.call_sem_trywait(handle); if (res < 0) { - int errno = getErrno(invokeNode); + int errno = posixNativeFunctionInvoker.get_errno(); if (errno == OSErrorEnum.EAGAIN.getNumber()) { return false; } - throw newPosixException(invokeNode, errno); + throw newPosixException(errno); } return true; } @@ -2439,16 +3045,15 @@ boolean semTryWait(long handle, @ExportMessage boolean semTimedWait(long handle, long deadlineNs, @Bind Node node, - @CachedLibrary("this") PosixSupportLibrary thisLib, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { + @CachedLibrary("this") PosixSupportLibrary thisLib) throws PosixException { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_LINUX) { - int res = invokeNode.callInt(this, PosixNativeFunction.call_sem_timedwait, handle, deadlineNs); + int res = posixNativeFunctionInvoker.call_sem_timedwait(handle, deadlineNs); if (res < 0) { - int errno = getErrno(invokeNode); + int errno = posixNativeFunctionInvoker.get_errno(); if (errno == OSErrorEnum.ETIMEDOUT.getNumber()) { return false; } - throw newPosixException(invokeNode, errno); + throw newPosixException(errno); } return true; } else { @@ -2470,19 +3075,22 @@ boolean semTimedWait(long handle, long deadlineNs, @ExportMessage @SuppressWarnings("static-method") public PwdResult getpwuid(long uid, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - return getpw(PosixNativeFunction.call_getpwuid_r, uid, invokeNode, fromByteArrayNode, switchEncodingFromUtf8Node); + return getpw(uid, NULLPTR, fromByteArrayNode, switchEncodingFromUtf8Node); } @ExportMessage @SuppressWarnings("static-method") public PwdResult getpwnam(Object name, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - return getpw(PosixNativeFunction.call_getpwname_r, pathToCString(name), invokeNode, fromByteArrayNode, switchEncodingFromUtf8Node); + long namePtr = pathToNativeCString(name); + try { + return getpw(-1, namePtr, fromByteArrayNode, switchEncodingFromUtf8Node); + } finally { + NativeMemory.free(namePtr); + } } @ExportMessage @@ -2494,39 +3102,52 @@ public boolean hasGetpwentries() { @ExportMessage @SuppressWarnings("static-method") public PwdResult[] getpwentries( - @Shared("invoke") @Cached InvokeNativeFunction invokeNode, @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { // Note: this is not thread safe, so potentially problematic while running multiple contexts // within one VM - int sysConfMax = getSysConfPwdSizeMax(invokeNode); + int sysConfMax = getSysConfPwdSizeMax(); int initialBufferSize = sysConfMax == -1 ? 1024 : sysConfMax; ArrayList result = new ArrayList<>(); - invokeNode.call(this, PosixNativeFunction.call_setpwent); - long[] bufferSize = new long[1]; - long[] output = new long[PWD_OUTPUT_LEN]; - byte[] buffer = new byte[initialBufferSize]; + posixNativeFunctionInvoker.call_setpwent(); + long nativeBufferSize = NULLPTR; + long nativeOutput = NULLPTR; + int currentBufferSize = initialBufferSize; + long nativeBuffer = NULLPTR; try { + nativeBufferSize = NativeMemory.mallocLongArray(1); + nativeOutput = NativeMemory.mallocLongArray(PWD_OUTPUT_LEN); + nativeBuffer = NativeMemory.mallocByteArray(currentBufferSize); while (true) { - Object pwPtr = invokeNode.call(this, PosixNativeFunction.call_getpwent, bufferSize); - if (invokeNode.getResultInterop().isNull(pwPtr)) { + long pwPtr = posixNativeFunctionInvoker.call_getpwent(nativeBufferSize); + if (pwPtr == NULLPTR) { break; } - if (bufferSize[0] < 0 || bufferSize[0] > PWD_BUFFER_MAX_SIZE) { + long bufferSize = NativeMemory.readLong(nativeBufferSize); + if (bufferSize < 0 || bufferSize > PWD_BUFFER_MAX_SIZE) { throw outOfMemoryPosixError(); } - if (buffer.length < bufferSize[0]) { - buffer = new byte[(int) bufferSize[0]]; + if (currentBufferSize < bufferSize) { + NativeMemory.free(nativeBuffer); + currentBufferSize = (int) bufferSize; + nativeBuffer = NativeMemory.mallocByteArray(currentBufferSize); } - int code = invokeNode.callInt(this, PosixNativeFunction.get_getpwent_data, pwPtr, buffer, buffer.length, output); + int code = posixNativeFunctionInvoker.get_getpwent_data(pwPtr, nativeBuffer, currentBufferSize, nativeOutput); if (code != 0) { throw CompilerDirectives.shouldNotReachHere("get_getpwent_data failed"); } + byte[] buffer = new byte[currentBufferSize]; + NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer, 0, buffer.length); + long[] output = new long[PWD_OUTPUT_LEN]; + NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); result.add(createPwdResult(buffer, output, fromByteArrayNode, switchEncodingFromUtf8Node)); } } finally { - invokeNode.call(this, PosixNativeFunction.call_endpwent); + posixNativeFunctionInvoker.call_endpwent(); + NativeMemory.free(nativeBuffer); + NativeMemory.free(nativeOutput); + NativeMemory.free(nativeBufferSize); } return toPwdResultArray(result); } @@ -2536,24 +3157,38 @@ private static PwdResult[] toPwdResultArray(ArrayList result) { return result.toArray(new PwdResult[0]); } - private PwdResult getpw(PosixNativeFunction pwfun, Object pwfunArg, InvokeNativeFunction invokeNode, TruffleString.FromByteArrayNode fromByteArrayNode, + private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - int sysConfMax = getSysConfPwdSizeMax(invokeNode); + int sysConfMax = getSysConfPwdSizeMax(); int bufferSize = sysConfMax == -1 ? 1024 : sysConfMax; while (bufferSize < PWD_BUFFER_MAX_SIZE) { - byte[] data = new byte[bufferSize]; - long[] output = new long[PWD_OUTPUT_LEN]; - int result = invokeNode.callInt(this, pwfun, pwfunArg, data, data.length, output); - if (result == -1) { - return null; - } - if (result == 0) { - return createPwdResult(data, output, fromByteArrayNode, switchEncodingFromUtf8Node); - } - if (result != OSErrorEnum.ERANGE.getNumber() || sysConfMax != -1) { - // no point in trying larger buffer if we got different error or the OS already told - // us that sysConfMax should be enough... - throw newPosixException(invokeNode, result); + long nativeData = NULLPTR; + long nativeOutput = NULLPTR; + try { + nativeData = NativeMemory.mallocByteArray(bufferSize); + nativeOutput = NativeMemory.mallocLongArray(PWD_OUTPUT_LEN); + int result = namePtr == NULLPTR + ? posixNativeFunctionInvoker.call_getpwuid_r(uid, nativeData, bufferSize, nativeOutput) + : posixNativeFunctionInvoker.call_getpwname_r(namePtr, nativeData, bufferSize, nativeOutput); + if (result == -1) { + return null; + } + if (result == 0) { + byte[] data = new byte[bufferSize]; + NativeMemory.readByteArrayElements(nativeData, 0, data, 0, data.length); + long[] output = new long[PWD_OUTPUT_LEN]; + NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); + return createPwdResult(data, output, fromByteArrayNode, switchEncodingFromUtf8Node); + } + if (result != OSErrorEnum.ERANGE.getNumber() || sysConfMax != -1) { + // no point in trying larger buffer if we got different error or the OS already + // told + // us that sysConfMax should be enough... + throw newPosixException(result); + } + } finally { + NativeMemory.free(nativeOutput); + NativeMemory.free(nativeData); } bufferSize <<= 1; } @@ -2570,21 +3205,31 @@ private static PwdResult createPwdResult(byte[] data, long[] output, TruffleStri } @ExportMessage - public int ioctlBytes(int fd, long request, byte[] arg, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_ioctl_bytes, fd, request, arg); - if (res < 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { + long nativeArg = NULLPTR; + try { + nativeArg = NativeMemory.mallocByteArray(Math.max(arg.length, 1)); + if (arg.length > 0) { + NativeMemory.writeByteArrayElements(nativeArg, 0, arg, 0, arg.length); + } + int res = posixNativeFunctionInvoker.call_ioctl_bytes(fd, request, nativeArg); + if (res < 0) { + throw getErrnoAndThrowPosixException(); + } + if (arg.length > 0) { + NativeMemory.readByteArrayElements(nativeArg, 0, arg, 0, arg.length); + } + return res; + } finally { + NativeMemory.free(nativeArg); } - return res; } @ExportMessage - public int ioctlInt(int fd, long request, int arg, - @Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException { - int res = invokeNode.callInt(this, PosixNativeFunction.call_ioctl_int, fd, request, arg); + public int ioctlInt(int fd, long request, int arg) throws PosixException { + int res = posixNativeFunctionInvoker.call_ioctl_int(fd, request, arg); if (res < 0) { - throw newPosixException(invokeNode, getErrno(invokeNode)); + throw getErrnoAndThrowPosixException(); } return res; } @@ -2609,9 +3254,9 @@ private static PosixException outOfMemoryPosixError() throws PosixException { private int sysConfPwdSizeMax = -1; - private int getSysConfPwdSizeMax(InvokeNativeFunction invokeNode) throws PosixException { - if (CompilerDirectives.injectBranchProbability(SLOWPATH_PROBABILITY, sysConfPwdSizeMax == -1)) { - long sysConfMaxLong = invokeNode.callLong(this, PosixNativeFunction.get_sysconf_getpw_r_size_max); + private int getSysConfPwdSizeMax() throws PosixException { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, sysConfPwdSizeMax == -1)) { + long sysConfMaxLong = posixNativeFunctionInvoker.get_sysconf_getpw_r_size_max(); if (sysConfMaxLong != -1 && (sysConfMaxLong < 0 || sysConfMaxLong > PWD_BUFFER_MAX_SIZE)) { throw outOfMemoryPosixError(); } @@ -2711,49 +3356,44 @@ public String toString() { // ------------------ // Helpers - private int getErrno(InvokeNativeFunction invokeNode) { - return invokeNode.callInt(this, PosixNativeFunction.get_errno); + private PosixException getErrnoAndThrowPosixException() throws PosixException { + throw newPosixException(posixNativeFunctionInvoker.get_errno()); } - private void setErrno(InvokeNativeFunction invokeNode, int errno) { - invokeNode.call(this, PosixNativeFunction.set_errno, errno); + @TruffleBoundary + private PosixException newPosixException(int errno) throws PosixException { + throw new PosixErrnoException(errno, strerror(errno, null, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached())); } - private PosixException getErrnoAndThrowPosixException(InvokeNativeFunction invokeNode) throws PosixException { - throw newPosixException(invokeNode, getErrno(invokeNode)); + private static long copyTimevalArrayToNativeOrNull(Timeval[] timeval) { + return timeval == null ? NULLPTR : NativeMemory.copyToNativeLongArray(new long[]{timeval[0].getSeconds(), timeval[0].getMicroseconds(), timeval[1].getSeconds(), timeval[1].getMicroseconds()}); } - @TruffleBoundary - private PosixException newPosixException(InvokeNativeFunction invokeNode, int errno) throws PosixException { - throw new PosixErrnoException(errno, strerror(errno, invokeNode, TruffleString.FromByteArrayNode.getUncached(), TruffleString.SwitchEncodingNode.getUncached())); + private static long wrapItimerval(Timeval delay, Timeval interval) { + long ptr = NativeMemory.mallocLongArray(4); + NativeMemory.writeLongArrayElement(ptr, 0, delay.getSeconds()); + NativeMemory.writeLongArrayElement(ptr, 1, delay.getMicroseconds()); + NativeMemory.writeLongArrayElement(ptr, 2, interval.getSeconds()); + NativeMemory.writeLongArrayElement(ptr, 3, interval.getMicroseconds()); + return ptr; } - private Object wrap(long[] value) { - if (value == null) { - return PNone.NO_VALUE; - } else { - return value; + private static void readNativeSockAddr(long nativeAddr, long nativeAddrLen, UniversalSockAddrImpl addr) { + int addrLen = NativeMemory.readInt(nativeAddrLen); + if (addrLen < 0 || addrLen > addr.data.length) { + throw CompilerDirectives.shouldNotReachHere("Unexpected socket address length"); } - } - - private Object wrap(Timeval[] timeval) { - if (timeval == null) { - return PNone.NO_VALUE; - } else { - return new long[]{timeval[0].getSeconds(), timeval[0].getMicroseconds(), timeval[1].getSeconds(), timeval[1].getMicroseconds()}; + addr.setLen(addrLen); + if (addrLen > 0) { + NativeMemory.readByteArrayElements(nativeAddr, 0, addr.data, 0, addrLen); } } - private static long[] wrapItimerval(Timeval delay, Timeval interval) { - return new long[]{delay.getSeconds(), delay.getMicroseconds(), interval.getSeconds(), interval.getMicroseconds()}; - } - - private static Timeval[] unwrapTimeval(long[] timeval) { - return new Timeval[]{new Timeval(timeval[0], timeval[1]), new Timeval(timeval[2], timeval[3])}; - } - - private static TruffleString cStringToTruffleString(byte[] buf, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingNode) { - return createString(buf, 0, findZero(buf), true, fromByteArrayNode, switchEncodingNode); + private static Timeval[] unwrapTimeval(long nativeTimeval) { + return new Timeval[]{ + new Timeval(NativeMemory.readLongArrayElement(nativeTimeval, 0), NativeMemory.readLongArrayElement(nativeTimeval, 1)), + new Timeval(NativeMemory.readLongArrayElement(nativeTimeval, 2), NativeMemory.readLongArrayElement(nativeTimeval, 3)) + }; } private static int findZero(byte[] buf) { @@ -2765,29 +3405,23 @@ private static int findZero(byte[] buf) { return buf.length; } - private Object pathToCStringOrNull(Object path) { - return path == null ? PNone.NO_VALUE : bufferToCString((Buffer) path); + private long pathToNativeCStringOrNull(Object path) { + return path == null ? NULLPTR : bufferToNativeCString((Buffer) path); } - private Object pathToCString(Object path) { - return bufferToCString((Buffer) path); + private long pathToNativeCString(Object path) { + return bufferToNativeCString((Buffer) path); } - private Object bufferToCString(Buffer path) { - return nullTerminate(path.data, (int) path.length); + private static long bufferToNativeCString(Buffer path) { + return NativeMemory.copyToNativeZeroTerminatedByteArray(path.data, 0, (int) path.length); } - private Object stringToUTF8CString(TruffleString input, + private long stringToNativeUTF8CString(TruffleString input, @Cached TruffleString.SwitchEncodingNode switchEncodingToUtf8Node, @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { byte[] utf8 = getStringBytes(input, switchEncodingToUtf8Node, copyToByteArrayNode); - return nullTerminate(utf8, utf8.length); - } - - private static byte[] nullTerminate(byte[] str, int length) { - byte[] terminated = new byte[length + 1]; - PythonUtils.arraycopy(str, 0, terminated, 0, length); - return terminated; + return NativeMemory.copyToNativeZeroTerminatedByteArray(utf8, 0, utf8.length); } private static void checkBounds(byte[] buf, int offset, int length) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java index 7ad51b2330..97e7aa5947 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeContext.java @@ -66,6 +66,7 @@ public final class NativeContext { private static final int FORMAT_MESSAGE_BUFFER_CHARS = 2048; private final ConcurrentLinkedQueue libraries = new ConcurrentLinkedQueue<>(); + private final NativeLibrary defaultLibrary; final Object arena; public static NativeContext create() { @@ -75,6 +76,7 @@ public static NativeContext create() { @TruffleBoundary NativeContext() { arena = NativeAccessSupport.createArena(); + defaultLibrary = isWindows() ? null : new NativeLibrary(this, getPosixDefaultLibraryHandle()); } public void close() { @@ -125,6 +127,15 @@ public NativeLibrary loadLibrary(String name, int flags) throws NativeLibraryLoa return library; } + public NativeLibrary getDefaultLibrary() { + CompilerAsserts.neverPartOfCompilation(); + if (defaultLibrary == null) { + throw new UnsupportedOperationException("Default library is only available on POSIX platforms."); + } + ensureLoader(); + return defaultLibrary; + } + @SuppressWarnings("static-method") long lookupOptionalSymbol(long library, String name) { // TODO(native-access) if logging enabled, keep track of ptr->name mappings @@ -145,6 +156,12 @@ private static boolean isWindows() { // TODO(native-access) platform-specific values for RTLD_* constants private static final int RTLD_LAZY = 1; private static final int RTLD_NOW = 2; + // RTLD_DEFAULT is a special dlsym() handle rather than a portable POSIX numeric constant. + // Linux libcs use ((void *) 0), while Darwin uses ((void *) -2). nativeaccess needs the raw + // handle to issue dlsym(RTLD_DEFAULT, ...) directly, so we hardcode the supported POSIX ABI + // values here instead of introducing another helper library just to fetch this constant. + private static final long RTLD_DEFAULT_LINUX = 0L; + private static final long RTLD_DEFAULT_DARWIN = -2L; private static final MethodHandle DLOPEN = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT64, NativeSimpleType.POINTER, NativeSimpleType.SINT32); private static final MethodHandle DLCLOSE = NativeAccessSupport.createDowncallHandle(NativeSimpleType.SINT32, NativeSimpleType.SINT64); @@ -255,4 +272,12 @@ private static String formatWindowsError(int errorCode) { NativeMemory.free(buffer); } } + + private static long getPosixDefaultLibraryHandle() { + return switch (PythonLanguage.getPythonOS()) { + case PLATFORM_LINUX -> RTLD_DEFAULT_LINUX; + case PLATFORM_DARWIN -> RTLD_DEFAULT_DARWIN; + default -> throw new UnsupportedOperationException("Default library is only available on POSIX platforms."); + }; + } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeMemory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeMemory.java index dd6dca5e49..4c4b900748 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeMemory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/nativeaccess/NativeMemory.java @@ -40,11 +40,23 @@ */ package com.oracle.graal.python.runtime.nativeaccess; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; + import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; +import com.oracle.graal.python.runtime.nativeaccess.NativeMemoryFactory.ZeroTerminatedUtf8ToTruffleStringNodeGen; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateCached; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.strings.TruffleString.Encoding; import sun.misc.Unsafe; @@ -101,6 +113,11 @@ public static long mallocByteArray(long count) { return malloc(count); } + public static long mallocByteArrayOrNull(long count) { + assert count >= 0; + return count == 0 ? NULLPTR : mallocByteArray(count); + } + public static long callocByteArray(long count) { assert count > 0; return calloc(count); @@ -184,13 +201,46 @@ public static byte[] readByteArrayElements(long arrayPtr, long srcIndex, int cou } public static void readByteArrayElements(long arrayPtr, long srcIndex, byte[] dst, int dstIndex, int count) { + if (count == 0) { + return; + } UNSAFE.copyMemory(null, arrayPtr + srcIndex, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + (long) dstIndex, count); } public static void writeByteArrayElements(long arrayPtr, long dstIndex, byte[] src, int offset, int count) { + if (count == 0) { + return; + } UNSAFE.copyMemory(src, Unsafe.ARRAY_BYTE_BASE_OFFSET + (long) offset, null, arrayPtr + dstIndex, count); } + public static long copyToNativeByteArray(byte[] src) { + return copyToNativeByteArray(src, 0, src.length); + } + + public static long copyToNativeByteArray(byte[] src, int offset, int count) { + assert offset >= 0 && count > 0 && offset + count <= src.length; + long ptr = mallocByteArray(count); + writeByteArrayElements(ptr, 0, src, offset, count); + return ptr; + } + + public static long copyToNativeByteArrayOrNull(byte[] src) { + return copyToNativeByteArrayOrNull(src, 0, src.length); + } + + public static long copyToNativeByteArrayOrNull(byte[] src, int offset, int count) { + assert offset >= 0 && count >= 0 && offset + count <= src.length; + return count == 0 ? NULLPTR : copyToNativeByteArray(src, offset, count); + } + + public static long copyToNativeZeroTerminatedByteArray(byte[] src, int offset, int count) { + long ptr = mallocByteArray(count + 1L); + writeByteArrayElements(ptr, 0, src, offset, count); + writeByteArrayElement(ptr, count, (byte) 0); + return ptr; + } + public static void copyByteArray(long dstArray, long dstIndex, long srcArray, long srcIndex, long count) { memcpy(dstArray + dstIndex, srcArray + srcIndex, count); } @@ -231,6 +281,48 @@ public static void writeIntArrayElement(long arrayPtr, long index, int value) { writeInt(arrayPtr + index * Integer.BYTES, value); } + public static int[] readIntArrayElements(long arrayPtr, long srcIndex, int count) { + int[] result = new int[count]; + readIntArrayElements(arrayPtr, srcIndex, result, 0, count); + return result; + } + + public static void readIntArrayElements(long arrayPtr, long srcIndex, int[] dst, int dstIndex, int count) { + if (count == 0) { + return; + } + assert canMultiplyWithoutOverflow(srcIndex, Integer.BYTES); + UNSAFE.copyMemory(null, arrayPtr + srcIndex * Integer.BYTES, dst, Unsafe.ARRAY_INT_BASE_OFFSET + (long) dstIndex * Integer.BYTES, (long) count * Integer.BYTES); + } + + public static void writeIntArrayElements(long arrayPtr, long dstIndex, int[] src, int offset, int count) { + if (count == 0) { + return; + } + assert canMultiplyWithoutOverflow(dstIndex, Integer.BYTES); + UNSAFE.copyMemory(src, Unsafe.ARRAY_INT_BASE_OFFSET + (long) offset * Integer.BYTES, null, arrayPtr + dstIndex * Integer.BYTES, (long) count * Integer.BYTES); + } + + public static long copyToNativeIntArray(int[] src) { + return copyToNativeIntArray(src, 0, src.length); + } + + public static long copyToNativeIntArray(int[] src, int offset, int count) { + assert offset >= 0 && count > 0 && offset + count <= src.length; + long ptr = mallocIntArray(count); + writeIntArrayElements(ptr, 0, src, offset, count); + return ptr; + } + + public static long copyToNativeIntArrayOrNull(int[] src) { + return copyToNativeIntArrayOrNull(src, 0, src.length); + } + + public static long copyToNativeIntArrayOrNull(int[] src, int offset, int count) { + assert offset >= 0 && count >= 0 && offset + count <= src.length; + return count == 0 ? NULLPTR : copyToNativeIntArray(src, offset, count); + } + public static long readLong(long pointer) { return UNSAFE.getLong(pointer); } @@ -256,10 +348,41 @@ public static long[] readLongArrayElements(long arrayPtr, long srcIndex, int cou } public static void readLongArrayElements(long arrayPtr, long srcIndex, long[] dst, int dstIndex, int count) { + if (count == 0) { + return; + } assert canMultiplyWithoutOverflow(srcIndex, Long.BYTES); UNSAFE.copyMemory(null, arrayPtr + srcIndex * Long.BYTES, dst, Unsafe.ARRAY_LONG_BASE_OFFSET + (long) dstIndex * Long.BYTES, (long) count * Long.BYTES); } + public static void writeLongArrayElements(long arrayPtr, long dstIndex, long[] src, int offset, int count) { + if (count == 0) { + return; + } + assert canMultiplyWithoutOverflow(dstIndex, Long.BYTES); + UNSAFE.copyMemory(src, Unsafe.ARRAY_LONG_BASE_OFFSET + (long) offset * Long.BYTES, null, arrayPtr + dstIndex * Long.BYTES, (long) count * Long.BYTES); + } + + public static long copyToNativeLongArray(long[] src) { + return copyToNativeLongArray(src, 0, src.length); + } + + public static long copyToNativeLongArray(long[] src, int offset, int count) { + assert offset >= 0 && count > 0 && offset + count <= src.length; + long ptr = mallocLongArray(count); + writeLongArrayElements(ptr, 0, src, offset, count); + return ptr; + } + + public static long copyToNativeLongArrayOrNull(long[] src) { + return copyToNativeLongArrayOrNull(src, 0, src.length); + } + + public static long copyToNativeLongArrayOrNull(long[] src, int offset, int count) { + assert offset >= 0 && count >= 0 && offset + count <= src.length; + return count == 0 ? NULLPTR : copyToNativeLongArray(src, offset, count); + } + public static long readPtr(long pointer) { return UNSAFE.getLong(pointer); } @@ -342,6 +465,39 @@ static String zeroTerminatedUtf16ToJavaString(long ptr) { return new String(bytes, StandardCharsets.UTF_16LE); } + /** + * Converts a zero-terminated UTF-8 string in native memory to a managed {@link TruffleString}. + * + * The result is always materialized on the Java side so callers may free the native buffer + * immediately after the call returns. + */ + @GenerateUncached + @GenerateInline + @GenerateCached(false) + public abstract static class ZeroTerminatedUtf8ToTruffleStringNode extends Node { + + public abstract TruffleString execute(Node inliningTarget, long ptr); + + @TruffleBoundary + public static TruffleString executeUncached(long ptr) { + return ZeroTerminatedUtf8ToTruffleStringNodeGen.getUncached().execute(null, ptr); + } + + @Specialization + static TruffleString doPointer(long ptr, + @Cached(inline = false) TruffleString.FromZeroTerminatedNativePointerNode fromNativePointerNode, + @Cached(inline = false) TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached(inline = false) TruffleString.AsManagedNode asManagedNode) { + TruffleString utf8 = fromNativePointerNode.execute8Bit(ptr, 0, Encoding.UTF_8, false); + return asManagedNode.execute(switchEncodingNode.execute(utf8, TS_ENCODING), TS_ENCODING); + } + + @NeverDefault + public static ZeroTerminatedUtf8ToTruffleStringNode getUncached() { + return ZeroTerminatedUtf8ToTruffleStringNodeGen.getUncached(); + } + } + private static boolean canMultiplyWithoutOverflow(long value, int stride) { assert value >= 0 : "Value must be non-negative"; assert stride > 0 && (stride & (stride - 1)) == 0 : "Stride must be a power of two"; diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index 5f4d23366f..a182f8bebf 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -866,8 +866,8 @@ int32_t call_getsockname(int32_t sockfd, int8_t *addr, int32_t *addr_len) { } //TODO len should be size_t, retval should be ssize_t -int32_t call_send(int32_t sockfd, void *buf, int32_t offset, int32_t len, int32_t flags) { - return send(sockfd, buf + offset, len, flags); +int32_t call_send(int32_t sockfd, void *buf, int32_t len, int32_t flags) { + return send(sockfd, buf, len, flags); } int32_t call_sendto(int32_t sockfd, void *buf, int32_t offset, int32_t len, int32_t flags, int8_t *addr, int32_t addr_len) { @@ -876,8 +876,8 @@ int32_t call_sendto(int32_t sockfd, void *buf, int32_t offset, int32_t len, int3 return sendto(sockfd, buf + offset, len, flags, (struct sockaddr *) &sa, addr_len); } -int32_t call_recv(int32_t sockfd, void *buf, int32_t offset, int32_t len, int32_t flags) { - return recv(sockfd, buf + offset, len, flags); +int32_t call_recv(int32_t sockfd, void *buf, int32_t len, int32_t flags) { + return recv(sockfd, buf, len, flags); } int32_t call_recvfrom(int32_t sockfd, void *buf, int32_t offset, int32_t len, int32_t flags, int8_t *src_addr, int32_t *addr_len) { From d74e683e9b62cf3c456a45627ce05b4a3bfaf228 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Mon, 18 May 2026 10:17:11 +0200 Subject: [PATCH 04/10] Zero-initialize buffer in select() --- graalpython/python-libposix/src/posix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index a182f8bebf..1719ebda34 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -204,9 +204,13 @@ int32_t call_select(int32_t nfds, int32_t* readfds, int32_t readfdsLen, int32_t* writefds, int32_t writefdsLen, int32_t* errfds, int32_t errfdsLen, int64_t timeoutSec, int64_t timeoutUsec, int8_t* selected) { fd_set readfdsSet, writefdsSet, errfdsSet; + int32_t selectedLen = readfdsLen + writefdsLen + errfdsLen; fill_fd_set(&readfdsSet, readfds, readfdsLen); fill_fd_set(&writefdsSet, writefds, writefdsLen); fill_fd_set(&errfdsSet, errfds, errfdsLen); + if (selectedLen > 0) { + memset(selected, 0, selectedLen * sizeof(*selected)); + } struct timeval timeout = {timeoutSec, timeoutUsec}; From 0944b6506e59a855974c1bb6be7f433047c6b787 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Mon, 18 May 2026 10:17:34 +0200 Subject: [PATCH 05/10] Fix getrusage() handling of double values --- .../src/tests/test_resource.py | 30 ++++++++++++-- graalpython/python-libposix/src/posix.c | 41 +++++++++++-------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_resource.py b/graalpython/com.oracle.graal.python.test/src/tests/test_resource.py index 5133726973..4ae2b0179b 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_resource.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_resource.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 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 @@ -37,9 +37,18 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import sys +import unittest + +try: + _POSIX_MODULE_BACKEND = __graalpython__.posix_module_backend() +except Exception: + _POSIX_MODULE_BACKEND = "cpython" + +_NATIVE_POSIX_LINUX = sys.platform == "linux" and _POSIX_MODULE_BACKEND == "native" + def test_import(): - import sys if sys.platform not in ['darwin', 'linux']: return imported = True @@ -50,7 +59,7 @@ def test_import(): assert imported -def test_gerusage(): +def test_getrusage(): from resource import getrusage, RUSAGE_SELF try: from resource import RUSAGE_THREAD @@ -66,3 +75,18 @@ def test_gerusage(): assert ru.ru_utime >= 0 assert ru.ru_stime >= 0 assert ru.ru_maxrss > 0 + + +@unittest.skipUnless(_NATIVE_POSIX_LINUX, "Requires native POSIX backend on Linux") +def test_gerusage_cpu_time_progress(): + import time + from resource import getrusage, RUSAGE_SELF + + start = getrusage(RUSAGE_SELF) + deadline = time.monotonic() + 0.25 + value = 0 + while time.monotonic() < deadline: + value = (value * 3 + 1) % 1000003 + end = getrusage(RUSAGE_SELF) + assert value >= 0 + assert (end.ru_utime + end.ru_stime) - (start.ru_utime + start.ru_stime) > 1e-3 diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index 1719ebda34..22df9e385f 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -736,25 +736,30 @@ int32_t call_getrusage(int32_t who, uint64_t* out) { int offset = 0; // POSIX prescribes only ru_utime and ru_stime members, macOS and Linux // have (at least) all those below -# define COPYVAL(v) memcpy(&out[offset++], &v, sizeof(v)) - COPYVAL(ru.ru_utime.tv_sec); - COPYVAL(ru.ru_stime.tv_sec); - COPYVAL(ru.ru_maxrss); - COPYVAL(ru.ru_ixrss); - COPYVAL(ru.ru_idrss); - COPYVAL(ru.ru_isrss); - COPYVAL(ru.ru_minflt); - COPYVAL(ru.ru_majflt); - COPYVAL(ru.ru_nswap); - COPYVAL(ru.ru_inblock); - COPYVAL(ru.ru_oublock); - COPYVAL(ru.ru_msgsnd); - COPYVAL(ru.ru_msgrcv); - COPYVAL(ru.ru_nsignals); - COPYVAL(ru.ru_nvcsw); - COPYVAL(ru.ru_nivcsw); +# define COPYDOUBLE(sec, usec) do { \ + double value = (double)(sec) + ((double)(usec) / 1000000.0); \ + memcpy(&out[offset++], &value, sizeof(value)); \ + } while (0) +# define COPYLONG(v) out[offset++] = (uint64_t)(int64_t)(v) + COPYDOUBLE(ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); + COPYDOUBLE(ru.ru_stime.tv_sec, ru.ru_stime.tv_usec); + COPYLONG(ru.ru_maxrss); + COPYLONG(ru.ru_ixrss); + COPYLONG(ru.ru_idrss); + COPYLONG(ru.ru_isrss); + COPYLONG(ru.ru_minflt); + COPYLONG(ru.ru_majflt); + COPYLONG(ru.ru_nswap); + COPYLONG(ru.ru_inblock); + COPYLONG(ru.ru_oublock); + COPYLONG(ru.ru_msgsnd); + COPYLONG(ru.ru_msgrcv); + COPYLONG(ru.ru_nsignals); + COPYLONG(ru.ru_nvcsw); + COPYLONG(ru.ru_nivcsw); return 0; -# undef COPYVAL +# undef COPYLONG +# undef COPYDOUBLE #else return -1; #endif From 954f36b48395869529ca75c918dbe8f6ea1b8898 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Tue, 19 May 2026 17:36:26 +0200 Subject: [PATCH 06/10] Eagerly initialize NFI to avoid deadlock --- .../src/tests/test_threading.py | 38 ++++++++++++++++++- .../graal/python/runtime/NFIPosixSupport.java | 12 ++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py b/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py index d1e6076bb7..c3401a8efc 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py @@ -37,9 +37,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import sys +import unittest + def test_stuck_thread(): - import sys import subprocess if sys.implementation.name == 'graalpy' and __graalpython__.posix_module_backend() == 'java': @@ -64,7 +66,6 @@ def test_stuck_thread(): def test_threads_joining_main_thread_at_shutdown(): import subprocess - import sys script = r""" import threading @@ -80,3 +81,36 @@ def f(): """ result = subprocess.run([sys.executable, "-c", script], stdout=subprocess.PIPE, stderr=subprocess.PIPE) assert result.returncode == 0, result.stderr.decode("utf-8", "replace") + + +@unittest.skipIf(sys.implementation.name == "graalpy", "Blocked on Truffle API support for blocking native reads during thread-local handshakes") +# see GR-75767 for details +def test_blocking_os_read_thread_does_not_deadlock_import_re(): + import subprocess + + if sys.platform == "win32": + return + + script = r""" +import os +import threading +import sys + +read_fd, write_fd = os.pipe() +threading.Thread(target=lambda: os.read(read_fd, 1), daemon=True).start() + +import re + +print("ok", flush=True) +os._exit(0) +""" + + result = subprocess.run( + [sys.executable, "-c", script], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + timeout=10, + ) + assert result.returncode == 0, result.stderr + assert result.stdout.rstrip().endswith("ok"), result.stdout diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java index da0e7a03b8..93089c3b9f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java @@ -45,6 +45,7 @@ import static com.oracle.graal.python.annotations.NativeSimpleType.SINT32; import static com.oracle.graal.python.annotations.NativeSimpleType.SINT64; import static com.oracle.graal.python.annotations.NativeSimpleType.VOID; +import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; import static com.oracle.graal.python.nodes.StringLiterals.T_NATIVE; import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN6_ADDR_S6_ADDR; import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN_ADDR_S_ADDR; @@ -138,6 +139,7 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import sun.misc.Unsafe; @@ -149,6 +151,7 @@ @ExportLibrary(PosixSupportLibrary.class) public final class NFIPosixSupport extends PosixSupport { private static final String SUPPORTING_NATIVE_LIB_NAME = "posix"; + private static final Source NFI_WARMUP_SIGNATURE = Source.newBuilder(J_NFI_LANGUAGE, "with native ():void", "python-nfi-warmup").internal(true).build(); private static final int UNAME_BUF_LENGTH = 256; private static final int DIRENT_NAME_BUF_LENGTH = 256; @@ -690,6 +693,15 @@ public void setEnv(Env env) { if (env.isPreInitialization()) { return; } + // Load NFI on the Python thread before any blocking native read can pin it. + // Workaround for GR-75767 + if (env.getInternalLanguages().containsKey(J_NFI_LANGUAGE)) { + try { + env.parseInternal(NFI_WARMUP_SIGNATURE).call(); + } catch (RuntimeException e1) { + LOGGER.log(Level.FINE, "Failed to eagerly initialize NFI warmup signature.", e1); + } + } // Java NIO (and TruffleFile) do not expect/support changing native working directory since // it is inherently thread-unsafe operation. It is not defined how NIO behaves when native // cwd changes, thus we need to prevent TruffleFile from resolving relative paths using From 4a1addbd65481ca7b9e1f6d536e7206c35e40684 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 22 May 2026 09:48:22 +0200 Subject: [PATCH 07/10] Refactor native downcall declarations --- .../python/annotations/DowncallSignature.java | 10 +- .../annotations/GenerateNativeDowncalls.java | 1 - .../GenerateNativeDowncallsProcessor.java | 163 ++--- .../NativeDowncallMethodHandleGenerator.java | 24 + .../graal/python/runtime/NFIPosixSupport.java | 596 +++++++++--------- 5 files changed, 404 insertions(+), 390 deletions(-) diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java index 9b055646a5..274e9210bf 100644 --- a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/DowncallSignature.java @@ -46,13 +46,13 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.SOURCE) -@Target(ElementType.FIELD) +@Target(ElementType.METHOD) public @interface DowncallSignature { - NativeSimpleType returns(); + NativeSimpleType returnType(); - NativeSimpleType[] argTypes() default {}; + NativeSimpleType[] argumentTypes() default {}; - String[] argNames() default {}; + Class retConversion() default void.class; - String symbol() default ""; + Class[] argConversions() default {}; } diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java index 61ff310d42..29df0a7f2b 100644 --- a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java +++ b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java @@ -48,5 +48,4 @@ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface GenerateNativeDowncalls { - String generatedClassName(); } diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java index d82f511855..d672e15c4d 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java @@ -42,7 +42,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,8 +50,12 @@ import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; import com.oracle.graal.python.annotations.DowncallSignature; @@ -60,7 +63,7 @@ import com.oracle.graal.python.annotations.NativeSimpleType; public class GenerateNativeDowncallsProcessor extends AbstractProcessor { - private record NativeDowncallDesc(String name, String symbolName, String returnType, List argumentTypes, List argumentNames) { + private record NativeDowncallDesc(String name, String symbolName, NativeSimpleType returnType, List argumentTypes, List argumentNames) { } @Override @@ -91,8 +94,11 @@ public boolean process(Set annotations, RoundEnvironment private void doProcess(RoundEnvironment roundEnv) throws IOException, ProcessingError { validateDowncallSignatures(roundEnv); for (Element element : roundEnv.getElementsAnnotatedWith(GenerateNativeDowncalls.class)) { - if (element.getKind() != ElementKind.ENUM) { - throw error(element, "Can only annotate enums with @GenerateNativeDowncalls"); + if (element.getKind() != ElementKind.CLASS) { + throw error(element, "Can only annotate classes with @GenerateNativeDowncalls"); + } + if (!element.getModifiers().contains(Modifier.ABSTRACT)) { + throw error(element, "@GenerateNativeDowncalls classes must be abstract"); } generateInvoker((TypeElement) element); } @@ -100,30 +106,32 @@ private void doProcess(RoundEnvironment roundEnv) throws IOException, Processing private static void validateDowncallSignatures(RoundEnvironment roundEnv) throws ProcessingError { for (Element element : roundEnv.getElementsAnnotatedWith(DowncallSignature.class)) { - if (element.getKind() != ElementKind.ENUM_CONSTANT) { - throw error(element, "@DowncallSignature can only annotate enum constants"); + if (element.getKind() != ElementKind.METHOD) { + throw error(element, "@DowncallSignature can only annotate methods"); } Element enclosingElement = element.getEnclosingElement(); - if (enclosingElement == null || enclosingElement.getKind() != ElementKind.ENUM) { - throw error(element, "@DowncallSignature can only annotate enum constants"); + if (enclosingElement == null || enclosingElement.getKind() != ElementKind.CLASS) { + throw error(element, "@DowncallSignature can only annotate methods in classes"); } if (enclosingElement.getAnnotation(GenerateNativeDowncalls.class) == null) { - throw error(element, "Enum constants annotated with @DowncallSignature must be enclosed in an enum annotated with @GenerateNativeDowncalls"); + throw error(element, "Methods annotated with @DowncallSignature must be enclosed in a class annotated with @GenerateNativeDowncalls"); + } + if (!element.getModifiers().contains(Modifier.ABSTRACT)) { + throw error(element, "@DowncallSignature methods must be abstract"); } } } - private void generateInvoker(TypeElement enumElement) throws IOException, ProcessingError { - GenerateNativeDowncalls annotation = enumElement.getAnnotation(GenerateNativeDowncalls.class); - List downcalls = collectDowncalls(enumElement); + private void generateInvoker(TypeElement invokerElement) throws IOException, ProcessingError { + List downcalls = collectDowncalls(invokerElement); if (downcalls.isEmpty()) { - throw error(enumElement, "Annotated enum does not declare any downcalls"); + throw error(invokerElement, "Annotated class does not declare any downcalls"); } - String packageName = processingEnv.getElementUtils().getPackageOf(enumElement).getQualifiedName().toString(); - String enumQualifiedName = enumElement.getQualifiedName().toString(); - String enumTypeRef = enumQualifiedName.startsWith(packageName + ".") ? enumQualifiedName.substring(packageName.length() + 1) : enumQualifiedName; - String className = annotation.generatedClassName(); + String packageName = processingEnv.getElementUtils().getPackageOf(invokerElement).getQualifiedName().toString(); + String invokerQualifiedName = invokerElement.getQualifiedName().toString(); + String invokerTypeRef = invokerQualifiedName.startsWith(packageName + ".") ? invokerQualifiedName.substring(packageName.length() + 1) : invokerQualifiedName; + String className = invokerElement.getSimpleName() + "Gen"; ArrayList lines = new ArrayList<>(); lines.add("// @formatter:off"); @@ -140,9 +148,9 @@ private void generateInvoker(TypeElement enumElement) throws IOException, Proces lines.add("import com.oracle.truffle.api.CompilerDirectives;"); lines.add("import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;"); lines.add(""); - lines.add("final class " + className + " {"); + lines.add("final class " + className + " extends " + invokerTypeRef + " {"); lines.add(" private final PythonContext context;"); - lines.add(" private final AtomicLongArray cachedFunctions = new AtomicLongArray(" + enumTypeRef + ".values().length);"); + lines.add(" private final AtomicLongArray cachedFunctions = new AtomicLongArray(" + downcalls.size() + ");"); lines.add(" private volatile NativeLibrary nativeLibrary;"); lines.add(""); @@ -155,24 +163,24 @@ private void generateInvoker(TypeElement enumElement) throws IOException, Proces lines.add(" this.context = context;"); lines.add(" }"); - for (NativeDowncallDesc downcall : downcalls) { - emitDowncallMethod(lines, enumTypeRef, downcall); + for (int i = 0; i < downcalls.size(); i++) { + emitDowncallMethod(lines, downcalls.get(i), i); } lines.add(""); lines.add(" @TruffleBoundary"); - lines.add(" private long lookup(" + enumTypeRef + " function, String symbolName) {"); - lines.add(" long symbol = cachedFunctions.get(function.ordinal());"); + lines.add(" private long lookup(int functionIndex, String symbolName) {"); + lines.add(" long symbol = cachedFunctions.get(functionIndex);"); lines.add(" if (symbol == 0) {"); - lines.add(" symbol = loadFunction(function, symbolName);"); - lines.add(" cachedFunctions.compareAndSet(function.ordinal(), 0, symbol);"); - lines.add(" symbol = cachedFunctions.get(function.ordinal());"); + lines.add(" symbol = loadFunction(symbolName);"); + lines.add(" cachedFunctions.compareAndSet(functionIndex, 0, symbol);"); + lines.add(" symbol = cachedFunctions.get(functionIndex);"); lines.add(" }"); lines.add(" return symbol;"); lines.add(" }"); lines.add(""); lines.add(" @TruffleBoundary"); - lines.add(" private long loadFunction(" + enumTypeRef + " function, String symbolName) {"); + lines.add(" private long loadFunction(String symbolName) {"); lines.add(" return ensureLibrary().lookupSymbol(symbolName);"); lines.add(" }"); lines.add(""); @@ -180,82 +188,90 @@ private void generateInvoker(TypeElement enumElement) throws IOException, Proces lines.add(" private NativeLibrary ensureLibrary() {"); lines.add(" NativeLibrary library = nativeLibrary;"); lines.add(" if (library == null) {"); - lines.add(" library = " + enumTypeRef + ".loadNativeLibrary(context);"); + lines.add(" library = " + invokerTypeRef + ".loadNativeLibrary(context);"); lines.add(" nativeLibrary = library;"); lines.add(" }"); lines.add(" return library;"); lines.add(" }"); lines.add("}"); - var file = processingEnv.getFiler().createSourceFile(packageName + "." + className, enumElement); + var file = processingEnv.getFiler().createSourceFile(packageName + "." + className, invokerElement); try (var writer = file.openWriter()) { writer.append(String.join(System.lineSeparator(), lines)); } } - private static List collectDowncalls(TypeElement enumElement) throws ProcessingError { + private static List collectDowncalls(TypeElement invokerElement) throws ProcessingError { List result = new ArrayList<>(); - for (Element enclosedElement : enumElement.getEnclosedElements()) { - if (enclosedElement.getKind() == ElementKind.ENUM_CONSTANT) { - result.add(extractDowncall((VariableElement) enclosedElement)); + Set methodNames = new java.util.HashSet<>(); + for (Element enclosedElement : invokerElement.getEnclosedElements()) { + if (enclosedElement.getKind() == ElementKind.METHOD && enclosedElement.getAnnotation(DowncallSignature.class) != null) { + NativeDowncallDesc downcall = extractDowncall((ExecutableElement) enclosedElement); + if (!methodNames.add(downcall.name)) { + throw error(enclosedElement, "Duplicate downcall method name: %s", downcall.name); + } + result.add(downcall); } } return result; } - private static NativeDowncallDesc extractDowncall(VariableElement enumConstant) throws ProcessingError { - DowncallSignature annotation = enumConstant.getAnnotation(DowncallSignature.class); + private static NativeDowncallDesc extractDowncall(ExecutableElement method) throws ProcessingError { + DowncallSignature annotation = method.getAnnotation(DowncallSignature.class); if (annotation == null) { - throw error(enumConstant, "Enum constant in @GenerateNativeDowncalls enum must be annotated with @DowncallSignature"); + throw error(method, "Downcall method in @GenerateNativeDowncalls class must be annotated with @DowncallSignature"); } - NativeSimpleType[] argTypes = annotation.argTypes(); - List argumentTypes = new ArrayList<>(argTypes.length); - for (NativeSimpleType argType : argTypes) { - argumentTypes.add(nativeSimpleTypeToJavaType(argType)); + NativeSimpleType[] argTypes = annotation.argumentTypes(); + if (argTypes.length != method.getParameters().size()) { + throw error(method, "@DowncallSignature argumentTypes length must match method parameter count (%d != %d)", argTypes.length, method.getParameters().size()); + } + validateJavaType(method, method.getReturnType(), annotation.returnType()); + for (int i = 0; i < argTypes.length; i++) { + validateJavaType(method.getParameters().get(i), method.getParameters().get(i).asType(), argTypes[i]); } - List argumentNames = extractArgumentNames(enumConstant, argTypes.length, annotation.argNames()); - String symbolName = annotation.symbol().isBlank() ? enumConstant.getSimpleName().toString() : annotation.symbol(); + List argumentTypes = List.of(argTypes); + List argumentNames = extractArgumentNames(method); + String symbolName = method.getSimpleName().toString(); return new NativeDowncallDesc( - enumConstant.getSimpleName().toString(), symbolName, - nativeSimpleTypeToJavaType(annotation.returns()), + symbolName, + annotation.returnType(), argumentTypes, argumentNames); } - private static List extractArgumentNames(VariableElement enumConstant, int argCount, String[] argNames) throws ProcessingError { - if (argNames.length == 0) { - if (argCount > 26) { - throw error(enumConstant, "Generated downcall stubs support at most 26 synthetic argument names (a-z); specify argNames explicitly for %d parameters", argCount); - } - List generatedNames = new ArrayList<>(argCount); - for (int i = 0; i < argCount; i++) { - generatedNames.add(NativeDowncallMethodHandleGenerator.argName(i)); - } - return generatedNames; - } - if (argNames.length != argCount) { - throw error(enumConstant, "@DowncallSignature argNames length must match argTypes length (%d != %d)", argNames.length, argCount); - } - HashSet seenNames = new HashSet<>(); - List result = new ArrayList<>(argCount); - for (String argName : argNames) { + private static List extractArgumentNames(ExecutableElement method) throws ProcessingError { + List result = new ArrayList<>(method.getParameters().size()); + for (VariableElement parameter : method.getParameters()) { + String argName = parameter.getSimpleName().toString(); if (argName.isBlank()) { - throw error(enumConstant, "@DowncallSignature argNames must not contain blank names"); + throw error(parameter, "Downcall parameter name must not be blank"); } if (!SourceVersion.isIdentifier(argName) || SourceVersion.isKeyword(argName)) { - throw error(enumConstant, "@DowncallSignature argName is not a valid Java identifier: %s", argName); - } - if (!seenNames.add(argName)) { - throw error(enumConstant, "@DowncallSignature argNames must be unique: %s", argName); + throw error(parameter, "Downcall parameter name is not a valid Java identifier: %s", argName); } result.add(argName); } return result; } + private static void validateJavaType(Element element, TypeMirror actualType, NativeSimpleType nativeType) throws ProcessingError { + TypeKind expected = switch (nativeType) { + case VOID -> TypeKind.VOID; + case SINT8 -> TypeKind.BYTE; + case SINT16 -> TypeKind.SHORT; + case SINT32 -> TypeKind.INT; + case SINT64, POINTER -> TypeKind.LONG; + case FLOAT -> TypeKind.FLOAT; + case DOUBLE -> TypeKind.DOUBLE; + }; + if (actualType.getKind() != expected) { + throw error(element, "Java type %s does not match native type %s", actualType, nativeType); + } + } + private static ProcessingError error(Element element, String fmt, Object... args) throws ProcessingError { throw new ProcessingError(element, fmt, args); } @@ -272,16 +288,17 @@ private static String nativeSimpleTypeToJavaType(NativeSimpleType type) { }; } - private static void emitDowncallMethod(List lines, String enumQualifiedName, NativeDowncallDesc downcall) { + private static void emitDowncallMethod(List lines, NativeDowncallDesc downcall, int functionIndex) { lines.add(""); lines.add(" @TruffleBoundary(allowInlining = true, transferToInterpreterOnException = false)"); - lines.add(" " + downcall.returnType + " " + downcall.name + "(" + typedArgs(downcall.argumentTypes, downcall.argumentNames) + ") {"); - lines.add(" long functionPointer = lookup(" + enumQualifiedName + "." + downcall.name + ", " + stringLiteral(downcall.symbolName) + ");"); + lines.add(" @Override"); + lines.add(" " + nativeSimpleTypeToJavaType(downcall.returnType) + " " + downcall.name + "(" + typedArgs(downcall.argumentTypes, downcall.argumentNames) + ") {"); + lines.add(" long functionPointer = lookup(" + functionIndex + ", " + stringLiteral(downcall.symbolName) + ");"); lines.add(" try {"); - if ("void".equals(downcall.returnType)) { + if (NativeSimpleType.VOID == downcall.returnType) { lines.add(" " + methodHandleName(downcall.name) + ".invokeExact(" + invokeArgs(downcall.argumentNames) + ");"); } else { - lines.add(" return (" + downcall.returnType + ") " + methodHandleName(downcall.name) + ".invokeExact(" + invokeArgs(downcall.argumentNames) + ");"); + lines.add(" return (" + nativeSimpleTypeToJavaType(downcall.returnType) + ") " + methodHandleName(downcall.name) + ".invokeExact(" + invokeArgs(downcall.argumentNames) + ");"); } lines.add(" } catch (Throwable t) {"); lines.add(" throw CompilerDirectives.shouldNotReachHere(t);"); @@ -293,10 +310,10 @@ private static String methodHandleName(String downcallName) { return NativeDowncallMethodHandleGenerator.methodHandleVarName(downcallName.toUpperCase()); } - private static String typedArgs(List argTypes, List argNames) { + private static String typedArgs(List argTypes, List argNames) { List args = new ArrayList<>(argTypes.size()); for (int i = 0; i < argTypes.size(); i++) { - args.add(argTypes.get(i) + " " + argNames.get(i)); + args.add(nativeSimpleTypeToJavaType(argTypes.get(i)) + " " + argNames.get(i)); } return String.join(", ", args); } diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java index 827d84a4df..e31e059c70 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/NativeDowncallMethodHandleGenerator.java @@ -43,6 +43,8 @@ import java.util.ArrayList; import java.util.List; +import com.oracle.graal.python.annotations.NativeSimpleType; + final class NativeDowncallMethodHandleGenerator { private NativeDowncallMethodHandleGenerator() { } @@ -71,6 +73,18 @@ static String toClassLiteral(String javaType) { }; } + static String toClassLiteral(NativeSimpleType nativeType) { + return switch (nativeType) { + case VOID -> "void.class"; + case SINT8 -> "byte.class"; + case SINT16 -> "short.class"; + case SINT32 -> "int.class"; + case SINT64, POINTER -> "long.class"; + case FLOAT -> "float.class"; + case DOUBLE -> "double.class"; + }; + } + static void emitMethodHandleField(List lines, String fieldName, String returnType, List argTypes) { List methodTypeArgs = new ArrayList<>(); methodTypeArgs.add("long.class"); @@ -80,4 +94,14 @@ static void emitMethodHandleField(List lines, String fieldName, String r lines.add(" private static final MethodHandle " + fieldName + " = NativeAccessSupport.createDowncallHandle(" + "MethodType.methodType(" + toClassLiteral(returnType) + ", " + String.join(", ", methodTypeArgs) + "), false);"); } + + static void emitMethodHandleField(List lines, String fieldName, NativeSimpleType returnType, List argTypes) { + List methodTypeArgs = new ArrayList<>(); + methodTypeArgs.add("long.class"); + for (NativeSimpleType argType : argTypes) { + methodTypeArgs.add(toClassLiteral(argType)); + } + lines.add(" private static final MethodHandle " + fieldName + " = NativeAccessSupport.createDowncallHandle(" + + "MethodType.methodType(" + toClassLiteral(returnType) + ", " + String.join(", ", methodTypeArgs) + "), false);"); + } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java index 93089c3b9f..57a0a407be 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java @@ -167,448 +167,422 @@ public final class NFIPosixSupport extends PosixSupport { private static final Object CRYPT_LOCK = new Object(); - @GenerateNativeDowncalls(generatedClassName = "PosixNativeFunctionInvoker") - enum PosixNativeFunction { - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT32}, argNames = {"out", "len"}) - init_constants, + @GenerateNativeDowncalls + abstract static class PosixNativeFunctionInvoker { + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT32}) + abstract int init_constants(long out, int len); - @DowncallSignature(returns = SINT32) - get_errno, + @DowncallSignature(returnType = SINT32) + abstract int get_errno(); - @DowncallSignature(returns = VOID, argTypes = {SINT32}) - set_errno, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT32}) + abstract void set_errno(int errno); - @DowncallSignature(returns = SINT64, argTypes = {SINT64, SINT32, SINT32, SINT32, SINT64}, argNames = {"length", "prot", "flags", "fd", "offset"}) - call_mmap, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT64, SINT32, SINT32, SINT32, SINT64}) + abstract long call_mmap(long length, int prot, int flags, int fd, long offset); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT64}, argNames = {"address", "length"}) - call_munmap, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, SINT64}) + abstract int call_munmap(long address, long length); - @DowncallSignature(returns = VOID, argTypes = {SINT64, SINT64, SINT64}, argNames = {"address", "offset", "length"}) - call_msync, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT64, SINT64, SINT64}) + abstract void call_msync(long address, long offset, long length); - @DowncallSignature(returns = VOID, argTypes = {SINT32, POINTER, SINT32}, argNames = {"error", "buf", "buflen"}) - call_strerror, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT32, POINTER, SINT32}) + abstract void call_strerror(int error, long buf, int buflen); - @DowncallSignature(returns = SINT64) - call_getpid, + @DowncallSignature(returnType = SINT64) + abstract long call_getpid(); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_umask, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_umask(int mask); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"dirFd", "pathname", "flags", "mode"}) - call_openat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32}) + abstract int call_openat(int dirFd, long pathname, int flags, int mode); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_close, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_close(int fd); - @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, SINT64}, argNames = {"fd", "buf", "count"}) - call_read, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) + abstract long call_read(int fd, long buf, long count); - @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, SINT64}, argNames = {"fd", "buf", "count"}) - call_write, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) + abstract long call_write(int fd, long buf, long count); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_dup, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_dup(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32}, argNames = {"oldfd", "newfd", "inheritable"}) - call_dup2, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT32}) + abstract int call_dup2(int oldfd, int newfd, int inheritable); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"pipefd"}) - call_pipe2, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_pipe2(long pipefd); - @DowncallSignature(returns = SINT32, argTypes = { - SINT32, POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT64, SINT64, POINTER - }, argNames = { - "nfds", "readfds", "readfdsLen", "writefds", "writefdsLen", "errfds", "errfdsLen", "timeoutSec", "timeoutUsec", "selected" - }) - call_select, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT64, SINT64, POINTER}) + abstract int call_select(int nfds, long readfds, int readfdsLen, long writefds, int writefdsLen, long errfds, int errfdsLen, long timeoutSec, long timeoutUsec, long selected); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT64, SINT64}, argNames = {"fd", "writing", "timeoutSec", "timeoutUsec"}) - call_poll, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT64, SINT64}) + abstract int call_poll(int fd, int writing, long timeoutSec, long timeoutUsec); - @DowncallSignature(returns = SINT64, argTypes = {SINT32, SINT64, SINT32}, argNames = {"fd", "offset", "whence"}) - call_lseek, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, SINT64, SINT32}) + abstract long call_lseek(int fd, long offset, int whence); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64}, argNames = {"fd", "length"}) - call_ftruncate, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT64}) + abstract int call_ftruncate(int fd, long length); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"path", "length"}) - call_truncate, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT64}) + abstract int call_truncate(long path, long length); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_fsync, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_fsync(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "operation"}) - call_flock, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int call_flock(int fd, int operation); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, SINT32, SINT64, SINT64}, argNames = {"fd", "blocking", "lockType", "whence", "start", "length"}) - call_fcntl_lock, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT32, SINT32, SINT64, SINT64}) + abstract int call_fcntl_lock(int fd, int blocking, int lockType, int whence, long start, long length); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER}, argNames = {"dirFd", "path", "followSymlinks", "out"}) - call_fstatat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, POINTER}) + abstract int call_fstatat(int dirFd, long path, int followSymlinks, long out); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "out"}) - call_fstat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_fstat(int fd, long out); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"path", "out"}) - call_statvfs, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER}) + abstract int call_statvfs(long path, long out); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "out"}) - call_fstatvfs, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_fstatvfs(int fd, long out); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, POINTER, POINTER, POINTER, SINT32}, argNames = {"sysname", "nodename", "release", "version", "machine", "size"}) - call_uname, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER, POINTER, POINTER, POINTER, SINT32}) + abstract int call_uname(long sysname, long nodename, long release, long version, long machine, int size); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"dirFd", "pathname", "rmdir"}) - call_unlinkat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32}) + abstract int call_unlinkat(int dirFd, long pathname, int rmdir); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER, SINT32}, argNames = {"oldDirFd", "oldPath", "newDirFd", "newPath", "flags"}) - call_linkat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, POINTER, SINT32}) + abstract int call_linkat(int oldDirFd, long oldPath, int newDirFd, long newPath, int flags); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT32, POINTER}, argNames = {"target", "dirFd", "linkpath"}) - call_symlinkat, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT32, POINTER}) + abstract int call_symlinkat(long target, int dirFd, long linkpath); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"dirFd", "pathname", "mode"}) - call_mkdirat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32}) + abstract int call_mkdirat(int dirFd, long pathname, int mode); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"buf", "size"}) - call_getcwd, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT64}) + abstract int call_getcwd(long buf, long size); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"path"}) - call_chdir, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_chdir(long path); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_fchdir, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_fchdir(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_isatty, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_isatty(int fd); - @DowncallSignature(returns = SINT64, argTypes = {POINTER}, argNames = {"name"}) - call_opendir, + @DowncallSignature(returnType = SINT64, argumentTypes = {POINTER}) + abstract long call_opendir(long name); - @DowncallSignature(returns = SINT64, argTypes = {SINT32}) - call_fdopendir, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32}) + abstract long call_fdopendir(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT64}, argNames = {"dirp"}) - call_closedir, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64}) + abstract int call_closedir(long dirp); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, SINT64, POINTER}, argNames = {"dirp", "nameBuf", "nameBufSize", "out"}) - call_readdir, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, POINTER, SINT64, POINTER}) + abstract int call_readdir(long dirp, long nameBuf, long nameBufSize, long out); - @DowncallSignature(returns = VOID, argTypes = {SINT64}, argNames = {"dirp"}) - call_rewinddir, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT64}) + abstract void call_rewinddir(long dirp); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER, SINT32}, argNames = {"dirFd", "path", "timespec", "followSymlinks"}) - call_utimensat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER, SINT32}) + abstract int call_utimensat(int dirFd, long path, long timespec, int followSymlinks); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "timespec"}) - call_futimens, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_futimens(int fd, long timespec); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "timeval"}) - call_futimes, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_futimes(int fd, long timeval); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"filename", "timeval"}) - call_lutimes, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER}) + abstract int call_lutimes(long filename, long timeval); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"filename", "timeval"}) - call_utimes, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER}) + abstract int call_utimes(long filename, long timeval); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, POINTER}, argNames = {"oldDirFd", "oldPath", "newDirFd", "newPath"}) - call_renameat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, POINTER}) + abstract int call_renameat(int oldDirFd, long oldPath, int newDirFd, long newPath); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32, SINT32}, argNames = {"dirFd", "path", "mode", "effectiveIds", "followSymlinks"}) - call_faccessat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32, SINT32}) + abstract int call_faccessat(int dirFd, long path, int mode, int effectiveIds, int followSymlinks); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"dirFd", "path", "mode", "followSymlinks"}) - call_fchmodat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32}) + abstract int call_fchmodat(int dirFd, long path, int mode, int followSymlinks); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "mode"}) - call_fchmod, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int call_fchmod(int fd, int mode); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT64, SINT64, SINT32}, argNames = {"dirfd", "pathname", "owner", "group", "followSymlinks"}) - call_fchownat, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT64, SINT64, SINT32}) + abstract int call_fchownat(int dirfd, long pathname, long owner, long group, int followSymlinks); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, SINT64}, argNames = {"fd", "owner", "group"}) - call_fchown, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT64, SINT64}) + abstract int call_fchown(int fd, long owner, long group); - @DowncallSignature(returns = SINT64, argTypes = {SINT32, POINTER, POINTER, SINT64}, argNames = {"dirFd", "path", "buf", "size"}) - call_readlinkat, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, POINTER, SINT64}) + abstract long call_readlinkat(int dirFd, long path, long buf, long size); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - get_inheritable, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int get_inheritable(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "inheritable"}) - set_inheritable, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int set_inheritable(int fd, int inheritable); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - get_blocking, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int get_blocking(int fd); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"fd", "blocking"}) - set_blocking, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int set_blocking(int fd, int blocking); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"fd", "size"}) - get_terminal_size, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int get_terminal_size(int fd, long size); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_raise, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_raise(int signal); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_alarm, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_alarm(int seconds); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"which", "current_value"}) - call_getitimer, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_getitimer(int which, long currentValue); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"which", "new_value", "old_value"}) - call_setitimer, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER}) + abstract int call_setitimer(int which, long newValue, long oldValue); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - signal_self, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int signal_self(int signal); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT32}, argNames = {"pid", "signal"}) - call_kill, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, SINT32}) + abstract int call_kill(long pid, int signal); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT32}, argNames = {"pgid", "signal"}) - call_killpg, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, SINT32}) + abstract int call_killpg(long pgid, int signal); - @DowncallSignature(returns = SINT64, argTypes = {SINT64, POINTER, SINT32}, argNames = {"pid", "status", "options"}) - call_waitpid, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT64, POINTER, SINT32}) + abstract long call_waitpid(long pid, long status, int options); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wcoredump, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wcoredump(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wifcontinued, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wifcontinued(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wifstopped, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wifstopped(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wifsignaled, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wifsignaled(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wifexited, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wifexited(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wexitstatus, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wexitstatus(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wtermsig, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wtermsig(int status); - @DowncallSignature(returns = SINT32, argTypes = {SINT32}) - call_wstopsig, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_wstopsig(int status); - @DowncallSignature(returns = SINT64) - call_getuid, + @DowncallSignature(returnType = SINT64) + abstract long call_getuid(); - @DowncallSignature(returns = SINT64) - call_geteuid, + @DowncallSignature(returnType = SINT64) + abstract long call_geteuid(); - @DowncallSignature(returns = SINT64) - call_getgid, + @DowncallSignature(returnType = SINT64) + abstract long call_getgid(); - @DowncallSignature(returns = SINT64) - call_getegid, + @DowncallSignature(returnType = SINT64) + abstract long call_getegid(); - @DowncallSignature(returns = SINT64) - call_getppid, + @DowncallSignature(returnType = SINT64) + abstract long call_getppid(); - @DowncallSignature(returns = SINT64, argTypes = {SINT64}) - call_getpgid, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT64}) + abstract long call_getpgid(long pid); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, SINT64}, argNames = {"pid", "pgid"}) - call_setpgid, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, SINT64}) + abstract int call_setpgid(long pid, long pgid); - @DowncallSignature(returns = SINT64) - call_getpgrp, + @DowncallSignature(returnType = SINT64) + abstract long call_getpgrp(); - @DowncallSignature(returns = SINT64, argTypes = {SINT64}) - call_getsid, + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT64}) + abstract long call_getsid(long pid); - @DowncallSignature(returns = SINT64) - call_setsid, + @DowncallSignature(returnType = SINT64) + abstract long call_setsid(); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER}, argNames = {"size", "out"}) - call_getgroups, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, POINTER}) + abstract int call_getgroups(long size, long out); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"who", "out"}) - call_getrusage, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_getrusage(int who, long out); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"outvars"}) - call_openpty, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_openpty(long outvars); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"buf"}) - call_ctermid, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_ctermid(long buf); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32}, argNames = {"name", "value", "overwrite"}) - call_setenv, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER, SINT32}) + abstract int call_setenv(long name, long value, int overwrite); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"name"}) - call_unsetenv, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_unsetenv(long name); - @DowncallSignature(returns = SINT32, argTypes = { - POINTER, POINTER, SINT32, SINT32, SINT32, - SINT32, SINT32, SINT32, SINT32, SINT32, - SINT32, SINT32, SINT32, SINT32, SINT32, - SINT32, SINT32, POINTER, SINT64 - }, argNames = { - "data", "offsets", "offsetsLen", "argsPos", "envPos", - "cwdPos", "stdinRdFd", "stdinWrFd", "stdoutRdFd", "stdoutWrFd", - "stderrRdFd", "stderrWrFd", "errPipeRdFd", "errPipeWrFd", "closeFds", - "restoreSignals", "callSetsid", "fdsToKeep", "fdsToKeepLen" + @DowncallSignature(returnType = SINT32, argumentTypes = { + POINTER, POINTER, SINT32, SINT32, SINT32, SINT32, SINT32, SINT32, SINT32, SINT32, SINT32, SINT32, + SINT32, SINT32, SINT32, SINT32, SINT32, POINTER, SINT64 }) - fork_exec, + abstract int fork_exec(long data, long offsets, int offsetsLen, int argsPos, int envPos, int cwdPos, int stdinRdFd, int stdinWrFd, int stdoutRdFd, int stdoutWrFd, int stderrRdFd, + int stderrWrFd, int errPipeRdFd, int errPipeWrFd, int closeFds, int restoreSignals, int callSetsid, long fdsToKeep, long fdsToKeepLen); - @DowncallSignature(returns = VOID, argTypes = {POINTER, POINTER, SINT32}, argNames = {"data", "offsets", "offsetsLen"}) - call_execv, + @DowncallSignature(returnType = VOID, argumentTypes = {POINTER, POINTER, SINT32}) + abstract void call_execv(long data, long offsets, int offsetsLen); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"pathname"}) - call_system, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_system(long pathname); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, SINT32, POINTER}, argNames = {"uid", "buffer", "bufferSize", "output"}) - call_getpwuid_r, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, POINTER, SINT32, POINTER}) + abstract int call_getpwuid_r(long uid, long buffer, int bufferSize, long output); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32, POINTER}, argNames = {"name", "buffer", "bufferSize", "output"}) - call_getpwname_r, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER, SINT32, POINTER}) + abstract int call_getpwname_r(long name, long buffer, int bufferSize, long output); - @DowncallSignature(returns = VOID) - call_setpwent, + @DowncallSignature(returnType = VOID) + abstract void call_setpwent(); - @DowncallSignature(returns = VOID) - call_endpwent, + @DowncallSignature(returnType = VOID) + abstract void call_endpwent(); - @DowncallSignature(returns = POINTER, argTypes = {POINTER}, argNames = {"bufferSize"}) - call_getpwent, + @DowncallSignature(returnType = POINTER, argumentTypes = {POINTER}) + abstract long call_getpwent(long bufferSize); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER, SINT32, POINTER}, argNames = {"p", "buffer", "bufferSize", "output"}) - get_getpwent_data, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER, SINT32, POINTER}) + abstract int get_getpwent_data(long p, long buffer, int bufferSize, long output); - @DowncallSignature(returns = SINT64) - get_sysconf_getpw_r_size_max, + @DowncallSignature(returnType = SINT64) + abstract long get_sysconf_getpw_r_size_max(); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32}, argNames = {"family", "type", "protocol"}) - call_socket, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT32}) + abstract int call_socket(int family, int type, int protocol); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) - call_accept, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER}) + abstract int call_accept(int sockfd, long addr, long addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"sockfd", "addr", "addr_len"}) - call_bind, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32}) + abstract int call_bind(int sockfd, long addr, int addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32}, argNames = {"sockfd", "addr", "addr_len"}) - call_connect, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32}) + abstract int call_connect(int sockfd, long addr, int addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"sockfd", "backlog"}) - call_listen, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int call_listen(int sockfd, int backlog); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) - call_getpeername, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER}) + abstract int call_getpeername(int sockfd, long addr, long addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"sockfd", "addr", "addr_len"}) - call_getsockname, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER}) + abstract int call_getsockname(int sockfd, long addr, long addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"sockfd", "buf", "len", "flags"}) - call_send, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32}) + abstract int call_send(int sockfd, long buf, int len, int flags); - @DowncallSignature(returns = SINT32, argTypes = { - SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, SINT32 - }, argNames = { - "sockfd", "buf", "offset", "len", "flags", "addr", "addr_len" - }) - call_sendto, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, SINT32}) + abstract int call_sendto(int sockfd, long buf, int offset, int len, int flags, long addr, int addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, SINT32, SINT32}, argNames = {"sockfd", "buf", "len", "flags"}) - call_recv, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32}) + abstract int call_recv(int sockfd, long buf, int len, int flags); - @DowncallSignature(returns = SINT32, argTypes = { - SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, POINTER - }, argNames = { - "sockfd", "buf", "offset", "len", "flags", "src_addr", "addr_len" - }) - call_recvfrom, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, SINT32, SINT32, SINT32, POINTER, POINTER}) + abstract int call_recvfrom(int sockfd, long buf, int offset, int len, int flags, long srcAddr, long addrLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32}, argNames = {"sockfd", "how"}) - call_shutdown, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32}) + abstract int call_shutdown(int sockfd, int how); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, POINTER, POINTER}, argNames = {"sockfd", "level", "optname", "buf", "bufLen"}) - call_getsockopt, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT32, POINTER, POINTER}) + abstract int call_getsockopt(int sockfd, int level, int optname, long buf, long bufLen); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT32, SINT32, POINTER, SINT32}, argNames = {"sockfd", "level", "optname", "buf", "bufLen"}) - call_setsockopt, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT32, SINT32, POINTER, SINT32}) + abstract int call_setsockopt(int sockfd, int level, int optname, long buf, int bufLen); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"src"}) - call_inet_addr, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_inet_addr(long src); - @DowncallSignature(returns = SINT64, argTypes = {POINTER}, argNames = {"src"}) - call_inet_aton, + @DowncallSignature(returnType = SINT64, argumentTypes = {POINTER}) + abstract long call_inet_aton(long src); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER}, argNames = {"src", "dst"}) - call_inet_ntoa, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER}) + abstract int call_inet_ntoa(int src, long dst); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER}, argNames = {"family", "src", "dst"}) - call_inet_pton, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER}) + abstract int call_inet_pton(int family, long src, long dst); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, POINTER, POINTER, SINT32}, argNames = {"family", "src", "dst", "dstSize"}) - call_inet_ntop, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, POINTER, POINTER, SINT32}) + abstract int call_inet_ntop(int family, long src, long dst, int dstSize); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"buf", "bufLen"}) - call_gethostname, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT64}) + abstract int call_gethostname(long buf, long bufLen); - @DowncallSignature(returns = SINT32, argTypes = { - POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT32 - }, argNames = { - "addr", "addr_len", "hostBuf", "hostBufLen", "servBuf", "servBufLen", "flags" - }) - call_getnameinfo, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT32, POINTER, SINT32, POINTER, SINT32, SINT32}) + abstract int call_getnameinfo(long addr, int addrLen, long hostBuf, int hostBufLen, long servBuf, int servBufLen, int flags); - @DowncallSignature(returns = SINT32, argTypes = { - POINTER, POINTER, SINT32, SINT32, SINT32, SINT32, POINTER - }, argNames = { - "node", "service", "family", "sockType", "protocol", "flags", "ptr" - }) - call_getaddrinfo, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER, SINT32, SINT32, SINT32, SINT32, POINTER}) + abstract int call_getaddrinfo(long node, long service, int family, int sockType, int protocol, int flags, long ptr); - @DowncallSignature(returns = VOID, argTypes = {SINT64}, argNames = {"ptr"}) - call_freeaddrinfo, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT64}) + abstract void call_freeaddrinfo(long ptr); - @DowncallSignature(returns = VOID, argTypes = {SINT32, POINTER, SINT32}, argNames = {"error", "buf", "buflen"}) - call_gai_strerror, + @DowncallSignature(returnType = VOID, argumentTypes = {SINT32, POINTER, SINT32}) + abstract void call_gai_strerror(int error, long buf, int buflen); - @DowncallSignature(returns = SINT32, argTypes = {SINT64, POINTER, POINTER, POINTER}, argNames = {"ptr", "intData", "longData", "addr"}) - get_addrinfo_members, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT64, POINTER, POINTER, POINTER}) + abstract int get_addrinfo_members(long ptr, long intData, long longData, long addr); - @DowncallSignature(returns = POINTER, argTypes = {POINTER, SINT32, SINT32, SINT32}, argNames = {"name", "openFlags", "mode", "value"}) - call_sem_open, + @DowncallSignature(returnType = POINTER, argumentTypes = {POINTER, SINT32, SINT32, SINT32}) + abstract long call_sem_open(long name, int openFlags, int mode, int value); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) - call_sem_close, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_sem_close(long handle); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"name"}) - call_sem_unlink, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_sem_unlink(long name); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, POINTER}, argNames = {"handle", "value"}) - call_sem_getvalue, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER}) + abstract int call_sem_getvalue(long handle, long value); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) - call_sem_post, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_sem_post(long handle); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) - call_sem_wait, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_sem_wait(long handle); - @DowncallSignature(returns = SINT32, argTypes = {POINTER}, argNames = {"handle"}) - call_sem_trywait, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER}) + abstract int call_sem_trywait(long handle); - @DowncallSignature(returns = SINT32, argTypes = {POINTER, SINT64}, argNames = {"handle", "deadlineNs"}) - call_sem_timedwait, + @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT64}) + abstract int call_sem_timedwait(long handle, long deadlineNs); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, POINTER}, argNames = {"fd", "request", "buffer"}) - call_ioctl_bytes, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT64, POINTER}) + abstract int call_ioctl_bytes(int fd, long request, long buffer); - @DowncallSignature(returns = SINT32, argTypes = {SINT32, SINT64, SINT32}, argNames = {"fd", "request", "arg"}) - call_ioctl_int, + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32, SINT64, SINT32}) + abstract int call_ioctl_int(int fd, long request, int arg); - @DowncallSignature(returns = SINT64, argTypes = {SINT32}) - call_sysconf; + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32}) + abstract long call_sysconf(int name); @TruffleBoundary static String getLibPath(PythonContext context) { @@ -631,10 +605,10 @@ static NativeLibrary loadNativeLibrary(PythonContext context) { } } - @GenerateNativeDowncalls(generatedClassName = "CryptNativeFunctionInvoker") - enum CryptNativeFunction { - @DowncallSignature(returns = POINTER, argTypes = {POINTER, POINTER}, argNames = {"word", "salt"}) - crypt; + @GenerateNativeDowncalls + abstract static class CryptNativeFunctionInvoker { + @DowncallSignature(returnType = POINTER, argumentTypes = {POINTER, POINTER}) + abstract long crypt(long word, long salt); @TruffleBoundary static NativeLibrary loadNativeLibrary(PythonContext context) { @@ -664,8 +638,8 @@ public NFIPosixSupport(PythonContext context, TruffleString nfiBackend) { assert nfiBackend.equalsUncached(T_NATIVE, TS_ENCODING); this.context = context; this.nfiBackend = nfiBackend; - this.posixNativeFunctionInvoker = new PosixNativeFunctionInvoker(context); - this.cryptNativeFunctionInvoker = new CryptNativeFunctionInvoker(context); + this.posixNativeFunctionInvoker = new PosixNativeFunctionInvokerGen(context); + this.cryptNativeFunctionInvoker = new CryptNativeFunctionInvokerGen(context); setEnv(context.getEnv()); } From 093e39f3b6a5a85df9f01eced5b8ffa44852deda Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 22 May 2026 10:56:09 +0200 Subject: [PATCH 08/10] Remove native downcall marker annotation --- .../annotations/GenerateNativeDowncalls.java | 51 ------------------- .../GenerateNativeDowncallsProcessor.java | 50 +++++++++--------- .../graal/python/runtime/NFIPosixSupport.java | 3 -- 3 files changed, 23 insertions(+), 81 deletions(-) delete mode 100644 graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java diff --git a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java b/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java deleted file mode 100644 index 29df0a7f2b..0000000000 --- a/graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/GenerateNativeDowncalls.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.TYPE) -public @interface GenerateNativeDowncalls { -} diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java index d672e15c4d..ede35d6f5f 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateNativeDowncallsProcessor.java @@ -42,6 +42,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -59,7 +60,6 @@ import javax.tools.Diagnostic.Kind; import com.oracle.graal.python.annotations.DowncallSignature; -import com.oracle.graal.python.annotations.GenerateNativeDowncalls; import com.oracle.graal.python.annotations.NativeSimpleType; public class GenerateNativeDowncallsProcessor extends AbstractProcessor { @@ -68,7 +68,7 @@ private record NativeDowncallDesc(String name, String symbolName, NativeSimpleTy @Override public Set getSupportedAnnotationTypes() { - return Set.of(GenerateNativeDowncalls.class.getName(), DowncallSignature.class.getName()); + return Set.of(DowncallSignature.class.getName()); } @Override @@ -92,34 +92,30 @@ public boolean process(Set annotations, RoundEnvironment } private void doProcess(RoundEnvironment roundEnv) throws IOException, ProcessingError { - validateDowncallSignatures(roundEnv); - for (Element element : roundEnv.getElementsAnnotatedWith(GenerateNativeDowncalls.class)) { - if (element.getKind() != ElementKind.CLASS) { - throw error(element, "Can only annotate classes with @GenerateNativeDowncalls"); - } - if (!element.getModifiers().contains(Modifier.ABSTRACT)) { - throw error(element, "@GenerateNativeDowncalls classes must be abstract"); - } - generateInvoker((TypeElement) element); + Set invokerElements = new LinkedHashSet<>(); + for (Element element : roundEnv.getElementsAnnotatedWith(DowncallSignature.class)) { + invokerElements.add(validateDowncallSignature(element)); + } + for (TypeElement invokerElement : invokerElements) { + generateInvoker(invokerElement); } } - private static void validateDowncallSignatures(RoundEnvironment roundEnv) throws ProcessingError { - for (Element element : roundEnv.getElementsAnnotatedWith(DowncallSignature.class)) { - if (element.getKind() != ElementKind.METHOD) { - throw error(element, "@DowncallSignature can only annotate methods"); - } - Element enclosingElement = element.getEnclosingElement(); - if (enclosingElement == null || enclosingElement.getKind() != ElementKind.CLASS) { - throw error(element, "@DowncallSignature can only annotate methods in classes"); - } - if (enclosingElement.getAnnotation(GenerateNativeDowncalls.class) == null) { - throw error(element, "Methods annotated with @DowncallSignature must be enclosed in a class annotated with @GenerateNativeDowncalls"); - } - if (!element.getModifiers().contains(Modifier.ABSTRACT)) { - throw error(element, "@DowncallSignature methods must be abstract"); - } + private static TypeElement validateDowncallSignature(Element element) throws ProcessingError { + if (element.getKind() != ElementKind.METHOD) { + throw error(element, "@DowncallSignature can only annotate methods"); + } + Element enclosingElement = element.getEnclosingElement(); + if (enclosingElement == null || enclosingElement.getKind() != ElementKind.CLASS) { + throw error(element, "@DowncallSignature can only annotate methods in classes"); + } + if (!enclosingElement.getModifiers().contains(Modifier.ABSTRACT)) { + throw error(enclosingElement, "@DowncallSignature methods must be enclosed in an abstract class"); + } + if (!element.getModifiers().contains(Modifier.ABSTRACT)) { + throw error(element, "@DowncallSignature methods must be abstract"); } + return (TypeElement) enclosingElement; } private void generateInvoker(TypeElement invokerElement) throws IOException, ProcessingError { @@ -219,7 +215,7 @@ private static List collectDowncalls(TypeElement invokerElem private static NativeDowncallDesc extractDowncall(ExecutableElement method) throws ProcessingError { DowncallSignature annotation = method.getAnnotation(DowncallSignature.class); if (annotation == null) { - throw error(method, "Downcall method in @GenerateNativeDowncalls class must be annotated with @DowncallSignature"); + throw error(method, "Downcall method must be annotated with @DowncallSignature"); } NativeSimpleType[] argTypes = annotation.argumentTypes(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java index 57a0a407be..4fd3cf8c8b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java @@ -92,7 +92,6 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.DowncallSignature; -import com.oracle.graal.python.annotations.GenerateNativeDowncalls; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; @@ -167,7 +166,6 @@ public final class NFIPosixSupport extends PosixSupport { private static final Object CRYPT_LOCK = new Object(); - @GenerateNativeDowncalls abstract static class PosixNativeFunctionInvoker { @DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT32}) abstract int init_constants(long out, int len); @@ -605,7 +603,6 @@ static NativeLibrary loadNativeLibrary(PythonContext context) { } } - @GenerateNativeDowncalls abstract static class CryptNativeFunctionInvoker { @DowncallSignature(returnType = POINTER, argumentTypes = {POINTER, POINTER}) abstract long crypt(long word, long salt); From 64c02efd9e847c7bc6fd5aa754ab779f235e7283 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 22 May 2026 11:44:55 +0200 Subject: [PATCH 09/10] Guard native POSIX backend on NativeAccess availability --- .../python/processor/CApiBuiltinsProcessor.java | 2 ++ .../graal/python/runtime/PythonContext.java | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java index e6bf16d61f..31f6d9e399 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java @@ -1603,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() {"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index 5f8d75d561..46887f23bb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -1873,13 +1873,18 @@ private void initializePosixSupport() { // The resources field will be removed once all posix builtins go through PosixSupport TruffleString.EqualNode eqNode = TruffleString.EqualNode.getUncached(); boolean selectedJavaBackend = eqNode.execute(T_JAVA, option, TS_ENCODING); - if (PythonImageBuildOptions.WITHOUT_NATIVE_POSIX || selectedJavaBackend) { - if (!selectedJavaBackend) { - writeWarning("Native Posix backend selected, but it was excluded from the runtime, " + - "switching to Java backend."); - } + boolean selectedNativeBackend = eqNode.execute(T_NATIVE, option, TS_ENCODING); + if (selectedJavaBackend) { + result = new EmulatedPosixSupport(this); + } else if (selectedNativeBackend && PythonImageBuildOptions.WITHOUT_NATIVE_POSIX) { + writeWarning("Native Posix backend selected, but it was excluded from the runtime, " + + "switching to Java backend."); + result = new EmulatedPosixSupport(this); + } else if (selectedNativeBackend && !NativeAccessSupport.isAvailable()) { + writeWarning("Native Posix backend selected, but native access downcalls are not available in this runtime, " + + "switching to Java backend."); result = new EmulatedPosixSupport(this); - } else if (eqNode.execute(T_NATIVE, option, TS_ENCODING)) { + } else if (selectedNativeBackend) { if (env.isPreInitialization()) { EmulatedPosixSupport emulatedPosixSupport = new EmulatedPosixSupport(this); NFIPosixSupport nativePosixSupport = new NFIPosixSupport(this, option); From d572e29f34361c78fc7cd540659775a4200359ad Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Fri, 22 May 2026 11:53:55 +0200 Subject: [PATCH 10/10] Rename native POSIX support --- .../python/builtins/objects/mmap/PMMap.java | 4 +- ...nstants.java => NativePosixConstants.java} | 4 +- ...ixSupport.java => NativePosixSupport.java} | 86 +++++++++---------- .../python/runtime/PosixSupportLibrary.java | 2 +- .../graal/python/runtime/PythonContext.java | 6 +- graalpython/python-libposix/src/fork_exec.c | 4 +- graalpython/python-libposix/src/posix.c | 6 +- .../python-libposix/src/posix_no_gnu.c | 4 +- 8 files changed, 58 insertions(+), 58 deletions(-) rename graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/{NFIPosixConstants.java => NativePosixConstants.java} (96%) rename graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/{NFIPosixSupport.java => NativePosixSupport.java} (97%) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index 6d95332953..836b012b3d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -48,7 +48,7 @@ import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; -import com.oracle.graal.python.runtime.NFIPosixSupport; +import com.oracle.graal.python.runtime.NativePosixSupport; import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; import com.oracle.graal.python.runtime.PythonContext; @@ -211,7 +211,7 @@ void close(PosixSupportLibrary posixLib, Object posixSupport) { @ExportMessage boolean isNative( @Bind Node inliningTarget) { - return PythonContext.get(inliningTarget).getPosixSupport() instanceof NFIPosixSupport; + return PythonContext.get(inliningTarget).getPosixSupport() instanceof NativePosixSupport; } @ExportMessage diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixConstants.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixConstants.java similarity index 96% rename from graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixConstants.java rename to graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixConstants.java index ef20d53718..edb4fb39df 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixConstants.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -40,7 +40,7 @@ */ package com.oracle.graal.python.runtime; -public enum NFIPosixConstants { +public enum NativePosixConstants { // start generated SIZEOF_STRUCT_SOCKADDR, SIZEOF_STRUCT_SOCKADDR_SA_FAMILY, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java similarity index 97% rename from graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java rename to graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 4fd3cf8c8b..35ca5ebdab 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -47,21 +47,21 @@ import static com.oracle.graal.python.annotations.NativeSimpleType.VOID; import static com.oracle.graal.python.nodes.StringLiterals.J_NFI_LANGUAGE; import static com.oracle.graal.python.nodes.StringLiterals.T_NATIVE; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN6_ADDR_S6_ADDR; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_IN_ADDR_S_ADDR; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_ADDR; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_FLOWINFO; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_PORT; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_ADDR; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY; -import static com.oracle.graal.python.runtime.NFIPosixConstants.OFFSETOF_STRUCT_SOCKADDR_UN_SUN_PATH; -import static com.oracle.graal.python.runtime.NFIPosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; -import static com.oracle.graal.python.runtime.NFIPosixConstants.SIZEOF_STRUCT_SOCKADDR_IN6; -import static com.oracle.graal.python.runtime.NFIPosixConstants.SIZEOF_STRUCT_SOCKADDR_SA_FAMILY; -import static com.oracle.graal.python.runtime.NFIPosixConstants.SIZEOF_STRUCT_SOCKADDR_STORAGE; -import static com.oracle.graal.python.runtime.NFIPosixConstants.SIZEOF_STRUCT_SOCKADDR_UN_SUN_PATH; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_IN6_ADDR_S6_ADDR; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_IN_ADDR_S_ADDR; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_ADDR; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_FLOWINFO; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_PORT; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_ADDR; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY; +import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_UN_SUN_PATH; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN6; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_SA_FAMILY; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_STORAGE; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_UN_SUN_PATH; import static com.oracle.graal.python.runtime.PosixConstants.AF_INET; import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6; import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX; @@ -148,7 +148,7 @@ * downcalls. */ @ExportLibrary(PosixSupportLibrary.class) -public final class NFIPosixSupport extends PosixSupport { +public final class NativePosixSupport extends PosixSupport { private static final String SUPPORTING_NATIVE_LIB_NAME = "posix"; private static final Source NFI_WARMUP_SIGNATURE = Source.newBuilder(J_NFI_LANGUAGE, "with native ():void", "python-nfi-warmup").internal(true).build(); @@ -160,7 +160,7 @@ public final class NFIPosixSupport extends PosixSupport { private static final int MAX_READ = Integer.MAX_VALUE / 2; - private static final TruffleLogger LOGGER = PythonLanguage.getLogger(NFIPosixSupport.class); + private static final TruffleLogger LOGGER = PythonLanguage.getLogger(NativePosixSupport.class); private static final Unsafe UNSAFE = PythonUtils.initUnsafe(); @@ -626,24 +626,24 @@ static NativeLibrary loadNativeLibrary(PythonContext context) { } private final PythonContext context; - private final TruffleString nfiBackend; + private final TruffleString nativeBackend; private final PosixNativeFunctionInvoker posixNativeFunctionInvoker; private final CryptNativeFunctionInvoker cryptNativeFunctionInvoker; @CompilationFinal(dimensions = 1) private long[] constantValues; - public NFIPosixSupport(PythonContext context, TruffleString nfiBackend) { - assert nfiBackend.equalsUncached(T_NATIVE, TS_ENCODING); + public NativePosixSupport(PythonContext context, TruffleString nativeBackend) { + assert nativeBackend.equalsUncached(T_NATIVE, TS_ENCODING); this.context = context; - this.nfiBackend = nfiBackend; + this.nativeBackend = nativeBackend; this.posixNativeFunctionInvoker = new PosixNativeFunctionInvokerGen(context); this.cryptNativeFunctionInvoker = new CryptNativeFunctionInvokerGen(context); setEnv(context.getEnv()); } - long getConstant(NFIPosixConstants constant) { + long getConstant(NativePosixConstants constant) { if (constantValues == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - long[] values = new long[NFIPosixConstants.values().length]; + long[] values = new long[NativePosixConstants.values().length]; long nativeValues = NativeMemory.mallocLongArray(values.length); try { int result = posixNativeFunctionInvoker.init_constants(nativeValues, values.length); @@ -680,7 +680,7 @@ public void setEnv(Env env) { // native cwd is global, but Truffle cwd is per context. // TruffleFile will be unaware of the real working directory and keep resolving against the // original working directory. This should not matter since we do not use TruffleFile for - // ordinary I/O when using NFI backend. + // ordinary I/O when using the native backend. try { TruffleFile truffleFile = context.getEnv().getInternalTruffleFile(".").getAbsoluteFile(); context.getEnv().setCurrentWorkingDirectory(truffleFile); @@ -691,7 +691,7 @@ public void setEnv(Env env) { @ExportMessage public TruffleString getBackend() { - return nfiBackend; + return nativeBackend; } @ExportMessage @@ -1305,7 +1305,7 @@ public Object dirEntryGetName(Object dirEntryObj) { @ExportMessage public static class DirEntryGetPath { @Specialization(guards = "endsWithSlash(scandirPath)") - static Buffer withSlash(@SuppressWarnings("unused") NFIPosixSupport receiver, DirEntry dirEntry, Object scandirPath) { + static Buffer withSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { Buffer scandirPathBuffer = (Buffer) scandirPath; int pathLen = scandirPathBuffer.data.length; int nameLen = (int) dirEntry.name.length; @@ -1316,7 +1316,7 @@ static Buffer withSlash(@SuppressWarnings("unused") NFIPosixSupport receiver, Di } @Specialization(guards = "!endsWithSlash(scandirPath)") - static Buffer withoutSlash(@SuppressWarnings("unused") NFIPosixSupport receiver, DirEntry dirEntry, Object scandirPath) { + static Buffer withoutSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { Buffer scandirPathBuffer = (Buffer) scandirPath; int pathLen = scandirPathBuffer.data.length; int nameLen = (int) dirEntry.name.length; @@ -2627,7 +2627,7 @@ private TruffleString gai_strerror(Node inliningTarget, int errorCode, NativeMem * } * * - * To avoid multiple NFI calls, we transfer the data in batch using arrays of {@code int}s and + * To avoid multiple native calls, we transfer the data in batch using arrays of {@code int}s and * {@code long}s - int values are stored in {@code intData}, the {@code ai_canonname} and * {@code ai_next} pointers are stored in {@code longData} and the socket address pointed to by * {@code ai_addr} is copied into Java byte array {@code socketAddress}. We also cache two @@ -2647,8 +2647,8 @@ private static class AddrInfo { private final long[] longData = new long[2]; private byte[] socketAddress; - private void update(long ptr, NFIPosixSupport nfiPosixSupport) { - socketAddress = new byte[(int) nfiPosixSupport.getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; + private void update(long ptr, NativePosixSupport nativePosixSupport) { + socketAddress = new byte[(int) nativePosixSupport.getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; long nativeIntData = NULLPTR; long nativeLongData = NULLPTR; long nativeSocketAddress = NULLPTR; @@ -2656,7 +2656,7 @@ private void update(long ptr, NFIPosixSupport nfiPosixSupport) { nativeIntData = NativeMemory.mallocIntArray(intData.length); nativeLongData = NativeMemory.mallocLongArray(longData.length); nativeSocketAddress = NativeMemory.mallocByteArray(socketAddress.length); - int res = nfiPosixSupport.posixNativeFunctionInvoker.get_addrinfo_members(ptr, nativeIntData, nativeLongData, nativeSocketAddress); + int res = nativePosixSupport.posixNativeFunctionInvoker.get_addrinfo_members(ptr, nativeIntData, nativeLongData, nativeSocketAddress); if (res != 0) { throw shouldNotReachHere("the length of ai_canonname does not fit into an int"); } @@ -2711,21 +2711,21 @@ long getNextPtr() { @ExportLibrary(AddrInfoCursorLibrary.class) protected static class AddrInfoCursorImpl implements AddrInfoCursor { - private final NFIPosixSupport nfiPosixSupport; + private final NativePosixSupport nativePosixSupport; private long head; private AddrInfo info; - AddrInfoCursorImpl(NFIPosixSupport nfiPosixSupport, long head) { - this.nfiPosixSupport = nfiPosixSupport; + AddrInfoCursorImpl(NativePosixSupport nativePosixSupport, long head) { + this.nativePosixSupport = nativePosixSupport; this.head = head; info = new AddrInfo(); - info.update(head, nfiPosixSupport); + info.update(head, nativePosixSupport); } @ExportMessage void release() { checkReleased(); - nfiPosixSupport.posixNativeFunctionInvoker.call_freeaddrinfo(head); + nativePosixSupport.posixNativeFunctionInvoker.call_freeaddrinfo(head); head = 0; } @@ -2736,7 +2736,7 @@ boolean next() { if (nextPtr == 0) { return false; } - info.update(nextPtr, nfiPosixSupport); + info.update(nextPtr, nativePosixSupport); return true; } @@ -2779,7 +2779,7 @@ Object getCanonName() { @ExportMessage UniversalSockAddr getSockAddr() { - UniversalSockAddrImpl addr = new UniversalSockAddrImpl(nfiPosixSupport); + UniversalSockAddrImpl addr = new UniversalSockAddrImpl(nativePosixSupport); PythonUtils.arraycopy(info.socketAddress, 0, addr.data, 0, info.getAddrLen()); addr.setFamily(info.getAddrFamily()); addr.setLen(info.getAddrLen()); @@ -2833,12 +2833,12 @@ UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUn @ExportLibrary(UniversalSockAddrLibrary.class) protected static class UniversalSockAddrImpl implements UniversalSockAddr { - private final NFIPosixSupport nfiPosixSupport; + private final NativePosixSupport nativePosixSupport; private final byte[] data; private int len = 0; - UniversalSockAddrImpl(NFIPosixSupport nfiPosixSupport) { - this.nfiPosixSupport = nfiPosixSupport; + UniversalSockAddrImpl(NativePosixSupport nativePosixSupport) { + this.nativePosixSupport = nativePosixSupport; this.data = new byte[(int) getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; } @@ -2924,8 +2924,8 @@ UnixSockAddr asUnixSockAddr() { return new UnixSockAddr(pathBuf); } - long getConstant(NFIPosixConstants constant) { - return nfiPosixSupport.getConstant(constant); + long getConstant(NativePosixConstants constant) { + return nativePosixSupport.getConstant(constant); } int getLen() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java index baa1a22992..7aaccb04d9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java @@ -348,7 +348,7 @@ public record OpenPtyResult(int masterFd, int slaveFd) { public abstract TruffleString ctermid(Object receiver) throws PosixException; - // note: this leaks memory in nfi backend and is not synchronized + // note: this leaks memory in native backend and is not synchronized // TODO is it worth synchronizing at least all accesses made through PosixSupportLibrary? public abstract void setenv(Object receiver, Object name, Object value, boolean overwrite) throws PosixException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index 46887f23bb..7ae13c26b8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -1887,21 +1887,21 @@ private void initializePosixSupport() { } else if (selectedNativeBackend) { if (env.isPreInitialization()) { EmulatedPosixSupport emulatedPosixSupport = new EmulatedPosixSupport(this); - NFIPosixSupport nativePosixSupport = new NFIPosixSupport(this, option); + NativePosixSupport nativePosixSupport = new NativePosixSupport(this, option); result = new PreInitPosixSupport(env, nativePosixSupport, emulatedPosixSupport); } else if (TruffleOptions.AOT) { // We always use a PreInitPosixSupport on SVM to keep the type of the posixSupport // field consistent for both pre-initialized and not-pre-initialized contexts so // that host inlining and PE see only one type, and also to avoid polymorphism when // calling library methods. - NFIPosixSupport nativePosixSupport = new NFIPosixSupport(this, option); + NativePosixSupport nativePosixSupport = new NativePosixSupport(this, option); result = new PreInitPosixSupport(env, nativePosixSupport, null); } else { if (!getOption(PythonOptions.RunViaLauncher)) { writeWarning("Native Posix backend is not fully supported when embedding. For example, standard I/O always uses file " + "descriptors 0, 1 and 2 regardless of stream redirection specified in Truffle environment"); } - result = new NFIPosixSupport(this, option); + result = new NativePosixSupport(this, option); } } else { throw new IllegalStateException(String.format("Wrong value for the PosixModuleBackend option: '%s'", option)); diff --git a/graalpython/python-libposix/src/fork_exec.c b/graalpython/python-libposix/src/fork_exec.c index 1ddb1b54b3..9f941ec68f 100644 --- a/graalpython/python-libposix/src/fork_exec.c +++ b/graalpython/python-libposix/src/fork_exec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, 2025, Oracle and/or its affiliates. +/* Copyright (c) 2021, 2026, Oracle and/or its affiliates. * Copyright (C) 1996-2020 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -396,7 +396,7 @@ child_exec(char *const exec_array[], /* - * data, offsets, offsetsLen, argsPos, envPos, cwdPos - see comment in NFiPosixSupport.forkExec() + * data, offsets, offsetsLen, argsPos, envPos, cwdPos - see comment in NativePosixSupport.forkExec() * stdinRdFd - read end of the pipe for the child's stdin - closed by parent, dupped to fd 0 by child * stdinWrFd - write end of the pipe for the child's stdin - closed by child, written to by parent * stdoutRdFd - read end of the pipe for the child's stdout - closed by child, read from by parent diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index 22df9e385f..12893a061c 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -40,7 +40,7 @@ */ // Helper functions that mostly delegate to POSIX functions -// These functions are called from NFIPosixSupport Java class using NFI +// These functions are called from NativePosixSupport Java class using native-access downcalls // This file uses GNU extensions. Functions that require non-GNU versions (e.g. strerror_r) // need to go to posix_no_gnu.c @@ -781,7 +781,7 @@ int32_t call_unsetenv(char *name) { return unsetenv(name); } -// See comment in NFiPosixSupport.execv() for the description of arguments +// See comment in NativePosixSupport.execv() for the description of arguments void call_execv(char *data, int64_t *offsets, int32_t offsetsLen) { // We reuse the memory allocated for offsets to avoid the need to allocate and reliably free another array char **strings = (char **) offsets; @@ -1008,7 +1008,7 @@ void call_gai_strerror(int32_t error, char *buf, int32_t buflen) { } int32_t get_addrinfo_members(int64_t ptr, int32_t *intData, int64_t *longData, int8_t *addr) { - // see NFIPosixSupport.AddrInfo for description of the way data is transferred + // see NativePosixSupport.AddrInfo for description of the way data is transferred struct addrinfo *ai = (struct addrinfo *) ptr; memcpy(addr, ai->ai_addr, ai->ai_addrlen); diff --git a/graalpython/python-libposix/src/posix_no_gnu.c b/graalpython/python-libposix/src/posix_no_gnu.c index 88ef31bb2e..7b3c76ae3a 100644 --- a/graalpython/python-libposix/src/posix_no_gnu.c +++ b/graalpython/python-libposix/src/posix_no_gnu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -40,7 +40,7 @@ */ // This source contains functions that require POSIX functions without GNU extensions -// These functions are called from NFIPosixSupport Java class using NFI +// These functions are called from NativePosixSupport Java class using native-access downcalls #include #include