8282import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .HandleContext ;
8383import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .NativeToPythonNode ;
8484import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .ToPythonWrapperNode ;
85+ import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes ;
8586import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes .CheckFunctionResultNode ;
8687import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
8788import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ApiInitException ;
127128import com .oracle .truffle .api .frame .VirtualFrame ;
128129import com .oracle .truffle .api .interop .ArityException ;
129130import com .oracle .truffle .api .interop .InteropLibrary ;
131+ import com .oracle .truffle .api .interop .InvalidArrayIndexException ;
130132import com .oracle .truffle .api .interop .TruffleObject ;
131133import com .oracle .truffle .api .interop .UnknownIdentifierException ;
132134import com .oracle .truffle .api .interop .UnsupportedMessageException ;
@@ -807,12 +809,15 @@ public static CApiContext ensureCapiWasLoaded(Node node, PythonContext context,
807809 Object initFunction = U .readMember (capiLibrary , "initialize_graal_capi" );
808810 CApiContext cApiContext = new CApiContext (context , capiLibrary , useNative );
809811 context .setCApiContext (cApiContext );
810- if (!U .isExecutable (initFunction )) {
811- Object signature = env .parseInternal (Source .newBuilder (J_NFI_LANGUAGE , "(ENV,(SINT32):POINTER):VOID" , "exec" ).build ()).call ();
812- initFunction = SignatureLibrary .getUncached ().bind (signature , initFunction );
813- U .execute (initFunction , new GetBuiltin ());
814- } else {
815- U .execute (initFunction , NativePointer .createNull (), new GetBuiltin ());
812+ try (BuiltinArrayWrapper builtinArrayWrapper = new BuiltinArrayWrapper ()) {
813+ if (useNative ) {
814+ Object signature = env .parseInternal (Source .newBuilder (J_NFI_LANGUAGE , "(ENV,(SINT32):POINTER):VOID" , "exec" ).build ()).call ();
815+ initFunction = SignatureLibrary .getUncached ().bind (signature , initFunction );
816+ U .execute (initFunction , builtinArrayWrapper );
817+ } else {
818+ assert U .isExecutable (initFunction );
819+ U .execute (initFunction , NativePointer .createNull (), builtinArrayWrapper );
820+ }
816821 }
817822
818823 assert PythonCApiAssertions .assertBuiltins (capiLibrary );
@@ -1051,29 +1056,48 @@ public PythonModule findExtension(TruffleString filename, TruffleString name) {
10511056 return extensions .get (Pair .create (filename , name ));
10521057 }
10531058
1059+ /**
1060+ * An array wrapper around {@link PythonCextBuiltinRegistry#builtins} which also implements
1061+ * {@link InteropLibrary#toNative(Object)}. This is intended to be passed to the C API
1062+ * initialization function. In order to avoid memory leaks if the wrapper receives
1063+ * {@code toNative}, it should be used in a try-with-resources.
1064+ */
10541065 @ ExportLibrary (InteropLibrary .class )
1055- static final class GetBuiltin implements TruffleObject {
1066+ @ SuppressWarnings ("static-method" )
1067+ static final class BuiltinArrayWrapper implements TruffleObject , AutoCloseable {
1068+ private long pointer ;
10561069
1057- @ SuppressWarnings ("static-method" )
10581070 @ ExportMessage
1059- boolean isExecutable () {
1071+ boolean hasArrayElements () {
10601072 return true ;
10611073 }
10621074
1063- @ SuppressWarnings ("static-method" )
1075+ @ ExportMessage
1076+ long getArraySize () {
1077+ return PythonCextBuiltinRegistry .builtins .length ;
1078+ }
1079+
1080+ @ ExportMessage
1081+ boolean isArrayElementReadable (long index ) {
1082+ return 0 <= index && index < PythonCextBuiltinRegistry .builtins .length ;
1083+ }
1084+
10641085 @ ExportMessage
10651086 @ TruffleBoundary
1066- Object execute (Object [] arguments ) {
1067- assert arguments .length == 1 ;
1068- int id = (int ) arguments [0 ];
1087+ Object readArrayElement (long index ) throws InvalidArrayIndexException {
1088+ if (!isArrayElementReadable (index )) {
1089+ throw InvalidArrayIndexException .create (index );
1090+ }
1091+ // cast is guaranteed by 'isArrayElementReadable'
1092+ return getCAPIBuiltinExecutable ((int ) index );
1093+ }
1094+
1095+ private static CApiBuiltinExecutable getCAPIBuiltinExecutable (int id ) {
1096+ CompilerAsserts .neverPartOfCompilation ();
10691097 try {
10701098 CApiBuiltinExecutable builtin = PythonCextBuiltinRegistry .builtins [id ];
1071- CApiContext cApiContext = PythonContext .get (null ).getCApiContext ();
1072- if (cApiContext != null ) {
1073- Object llvmLibrary = cApiContext .getLLVMLibrary ();
1074- assert builtin .call () == CApiCallPath .Direct || !isAvailable (builtin , llvmLibrary ) : "name clash in builtin vs. CAPI library: " + builtin .name ();
1075- }
1076- LOGGER .finer ("CApiContext.GetBuiltin " + id + " / " + builtin .name ());
1099+ assert builtin .call () == CApiCallPath .Direct || !isAvailable (builtin ) : "name clash in builtin vs. CAPI library: " + builtin .name ();
1100+ LOGGER .finer ("CApiContext.BuiltinArrayWrapper.get " + id + " / " + builtin .name ());
10771101 return builtin ;
10781102 } catch (Throwable e ) {
10791103 // this is a fatal error, so print it to stderr:
@@ -1082,12 +1106,64 @@ Object execute(Object[] arguments) {
10821106 }
10831107 }
10841108
1085- private static boolean isAvailable (CApiBuiltinExecutable builtin , Object llvmLibrary ) {
1086- if (!InteropLibrary .getUncached ().isMemberReadable (llvmLibrary , builtin .name ())) {
1109+ @ ExportMessage
1110+ boolean isPointer () {
1111+ return pointer != 0 ;
1112+ }
1113+
1114+ @ ExportMessage
1115+ long asPointer () throws UnsupportedMessageException {
1116+ if (pointer != 0 ) {
1117+ return pointer ;
1118+ }
1119+ throw UnsupportedMessageException .create ();
1120+ }
1121+
1122+ @ ExportMessage
1123+ @ TruffleBoundary
1124+ void toNative () {
1125+ if (pointer == 0 ) {
1126+ assert PythonContext .get (null ).isNativeAccessAllowed ();
1127+ Object ptr = CStructAccess .AllocateNode .callocUncached (PythonCextBuiltinRegistry .builtins .length , CStructAccess .POINTER_SIZE );
1128+ pointer = CExtCommonNodes .CoerceNativePointerToLongNode .executeUncached (ptr );
1129+ if (pointer != 0 ) {
1130+ InteropLibrary lib = null ;
1131+ for (int i = 0 ; i < PythonCextBuiltinRegistry .builtins .length ; i ++) {
1132+ CApiBuiltinExecutable capiBuiltinExecutable = getCAPIBuiltinExecutable (i );
1133+ if (lib == null || !lib .accepts (capiBuiltinExecutable )) {
1134+ lib = InteropLibrary .getUncached (capiBuiltinExecutable );
1135+ }
1136+ assert lib .accepts (capiBuiltinExecutable );
1137+ lib .toNative (capiBuiltinExecutable );
1138+ try {
1139+ CStructAccess .WritePointerNode .writeArrayElementUncached (pointer , i , lib .asPointer (capiBuiltinExecutable ));
1140+ } catch (UnsupportedMessageException e ) {
1141+ throw CompilerDirectives .shouldNotReachHere (e );
1142+ }
1143+ }
1144+ }
1145+ }
1146+ }
1147+
1148+ @ Override
1149+ public void close () {
1150+ if (pointer != 0 ) {
1151+ FreeNode .executeUncached (pointer );
1152+ }
1153+ }
1154+
1155+ private static boolean isAvailable (CApiBuiltinExecutable builtin ) {
1156+ CApiContext cApiContext = PythonContext .get (null ).getCApiContext ();
1157+ if (cApiContext == null ) {
1158+ return false ;
1159+ }
1160+ Object llvmLibrary = cApiContext .getLLVMLibrary ();
1161+ InteropLibrary lib = InteropLibrary .getUncached (llvmLibrary );
1162+ if (!lib .isMemberReadable (llvmLibrary , builtin .name ())) {
10871163 return false ;
10881164 }
10891165 try {
1090- InteropLibrary . getUncached () .readMember (llvmLibrary , builtin .name ());
1166+ lib .readMember (llvmLibrary , builtin .name ());
10911167 return true ;
10921168 } catch (UnsupportedMessageException e ) {
10931169 throw CompilerDirectives .shouldNotReachHere (e );
@@ -1122,14 +1198,14 @@ private static Source buildNFISource(Object srcObj) {
11221198 return Source .newBuilder (J_NFI_LANGUAGE , (String ) srcObj , "exec" ).build ();
11231199 }
11241200
1125- public long registerClosure (String nfiSignature , Object executable , Object delegate ) {
1201+ public long registerClosure (String nfiSignature , Object executable , Object delegate , SignatureLibrary signatureLibrary ) {
11261202 CompilerAsserts .neverPartOfCompilation ();
11271203 PythonContext context = getContext ();
1128- boolean panama = PythonOptions . UsePanama . getValue ( context .getEnv (). getOptions () );
1204+ boolean panama = context .getOption ( PythonOptions . UsePanama );
11291205 String srcString = (panama ? "with panama " : "" ) + nfiSignature ;
11301206 Source nfiSource = context .getLanguage ().getOrCreateSource (CApiContext ::buildNFISource , srcString );
11311207 Object signature = context .getEnv ().parseInternal (nfiSource ).call ();
1132- Object closure = SignatureLibrary . getUncached () .createClosure (signature , executable );
1208+ Object closure = signatureLibrary .createClosure (signature , executable );
11331209 long pointer = PythonUtils .coerceToLong (closure , InteropLibrary .getUncached ());
11341210 setClosurePointer (closure , delegate , executable , pointer );
11351211 return pointer ;
0 commit comments