82
82
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .HandleContext ;
83
83
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .NativeToPythonNode ;
84
84
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .ToPythonWrapperNode ;
85
+ import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes ;
85
86
import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes .CheckFunctionResultNode ;
86
87
import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
87
88
import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ApiInitException ;
127
128
import com .oracle .truffle .api .frame .VirtualFrame ;
128
129
import com .oracle .truffle .api .interop .ArityException ;
129
130
import com .oracle .truffle .api .interop .InteropLibrary ;
131
+ import com .oracle .truffle .api .interop .InvalidArrayIndexException ;
130
132
import com .oracle .truffle .api .interop .TruffleObject ;
131
133
import com .oracle .truffle .api .interop .UnknownIdentifierException ;
132
134
import com .oracle .truffle .api .interop .UnsupportedMessageException ;
@@ -807,12 +809,15 @@ public static CApiContext ensureCapiWasLoaded(Node node, PythonContext context,
807
809
Object initFunction = U .readMember (capiLibrary , "initialize_graal_capi" );
808
810
CApiContext cApiContext = new CApiContext (context , capiLibrary , useNative );
809
811
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
+ }
816
821
}
817
822
818
823
assert PythonCApiAssertions .assertBuiltins (capiLibrary );
@@ -1051,29 +1056,48 @@ public PythonModule findExtension(TruffleString filename, TruffleString name) {
1051
1056
return extensions .get (Pair .create (filename , name ));
1052
1057
}
1053
1058
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
+ */
1054
1065
@ 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 ;
1056
1069
1057
- @ SuppressWarnings ("static-method" )
1058
1070
@ ExportMessage
1059
- boolean isExecutable () {
1071
+ boolean hasArrayElements () {
1060
1072
return true ;
1061
1073
}
1062
1074
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
+
1064
1085
@ ExportMessage
1065
1086
@ 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 ();
1069
1097
try {
1070
1098
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 ());
1077
1101
return builtin ;
1078
1102
} catch (Throwable e ) {
1079
1103
// this is a fatal error, so print it to stderr:
@@ -1082,12 +1106,64 @@ Object execute(Object[] arguments) {
1082
1106
}
1083
1107
}
1084
1108
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 ())) {
1087
1163
return false ;
1088
1164
}
1089
1165
try {
1090
- InteropLibrary . getUncached () .readMember (llvmLibrary , builtin .name ());
1166
+ lib .readMember (llvmLibrary , builtin .name ());
1091
1167
return true ;
1092
1168
} catch (UnsupportedMessageException e ) {
1093
1169
throw CompilerDirectives .shouldNotReachHere (e );
@@ -1122,14 +1198,14 @@ private static Source buildNFISource(Object srcObj) {
1122
1198
return Source .newBuilder (J_NFI_LANGUAGE , (String ) srcObj , "exec" ).build ();
1123
1199
}
1124
1200
1125
- public long registerClosure (String nfiSignature , Object executable , Object delegate ) {
1201
+ public long registerClosure (String nfiSignature , Object executable , Object delegate , SignatureLibrary signatureLibrary ) {
1126
1202
CompilerAsserts .neverPartOfCompilation ();
1127
1203
PythonContext context = getContext ();
1128
- boolean panama = PythonOptions . UsePanama . getValue ( context .getEnv (). getOptions () );
1204
+ boolean panama = context .getOption ( PythonOptions . UsePanama );
1129
1205
String srcString = (panama ? "with panama " : "" ) + nfiSignature ;
1130
1206
Source nfiSource = context .getLanguage ().getOrCreateSource (CApiContext ::buildNFISource , srcString );
1131
1207
Object signature = context .getEnv ().parseInternal (nfiSource ).call ();
1132
- Object closure = SignatureLibrary . getUncached () .createClosure (signature , executable );
1208
+ Object closure = signatureLibrary .createClosure (signature , executable );
1133
1209
long pointer = PythonUtils .coerceToLong (closure , InteropLibrary .getUncached ());
1134
1210
setClosurePointer (closure , delegate , executable , pointer );
1135
1211
return pointer ;
0 commit comments