4040 */
4141package com .oracle .graal .python .builtins .modules ;
4242
43- import static com .oracle .graal .python .nodes .SpecialAttributeNames .__FILE__ ;
4443import static com .oracle .graal .python .runtime .exception .PythonErrorType .NotImplementedError ;
4544
4645import java .io .IOException ;
5049import com .oracle .graal .python .PythonLanguage ;
5150import com .oracle .graal .python .builtins .Builtin ;
5251import com .oracle .graal .python .builtins .CoreFunctions ;
52+ import com .oracle .graal .python .builtins .Python3Core ;
53+ import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
5354import com .oracle .graal .python .builtins .PythonBuiltins ;
54- import com .oracle .graal .python .builtins .modules .PythonCextBuiltinsFactory .DefaultCheckFunctionResultNodeGen ;
5555import com .oracle .graal .python .builtins .objects .PNone ;
5656import com .oracle .graal .python .builtins .objects .bytes .PBytes ;
5757import com .oracle .graal .python .builtins .objects .bytes .PBytesLike ;
58+ import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .ExecModuleNode ;
59+ import com .oracle .graal .python .builtins .objects .cext .capi .DynamicObjectNativeWrapper ;
60+ import com .oracle .graal .python .builtins .objects .cext .capi .ExternalFunctionNodesFactory .DefaultCheckFunctionResultNodeGen ;
61+ import com .oracle .graal .python .builtins .objects .cext .capi .NativeMember ;
5862import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes .CheckFunctionResultNode ;
5963import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
64+ import com .oracle .graal .python .builtins .objects .cext .common .CExtContext .ModuleSpec ;
6065import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ApiInitException ;
6166import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ImportException ;
6267import com .oracle .graal .python .builtins .objects .cext .hpy .HPyExternalFunctionNodes .HPyCheckFunctionResultNode ;
6368import com .oracle .graal .python .builtins .objects .cext .hpy .HPyExternalFunctionNodesFactory .HPyCheckHandleResultNodeGen ;
6469import com .oracle .graal .python .builtins .objects .code .PCode ;
65- import com .oracle .graal .python .builtins .objects .dict . PDict ;
70+ import com .oracle .graal .python .builtins .objects .common . HashingStorageLibrary ;
6671import com .oracle .graal .python .builtins .objects .ints .IntBuiltins ;
6772import com .oracle .graal .python .builtins .objects .ints .PInt ;
6873import com .oracle .graal .python .builtins .objects .module .PythonModule ;
6974import com .oracle .graal .python .builtins .objects .object .PythonObject ;
7075import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
7176import com .oracle .graal .python .builtins .objects .str .PString ;
72- import com .oracle .graal .python .nodes .ErrorMessages ;
73- import com .oracle .graal .python .nodes .PRaiseNode ;
7477import com .oracle .graal .python .nodes .attributes .ReadAttributeFromDynamicObjectNode ;
7578import com .oracle .graal .python .nodes .attributes .SetAttributeNode ;
7679import com .oracle .graal .python .nodes .function .PythonBuiltinBaseNode ;
8184import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
8285import com .oracle .graal .python .runtime .GilNode ;
8386import com .oracle .graal .python .runtime .PythonContext ;
84- import com .oracle .graal .python .builtins .Python3Core ;
8587import com .oracle .graal .python .runtime .PythonOptions ;
86- import com .oracle .graal .python .runtime .exception .PythonErrorType ;
8788import com .oracle .truffle .api .CompilerDirectives ;
8889import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
8990import com .oracle .truffle .api .dsl .Cached ;
9091import com .oracle .truffle .api .dsl .CachedContext ;
9192import com .oracle .truffle .api .dsl .CachedLanguage ;
93+ import com .oracle .truffle .api .dsl .Fallback ;
9294import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
9395import com .oracle .truffle .api .dsl .NodeFactory ;
9496import com .oracle .truffle .api .dsl .Specialization ;
@@ -212,7 +214,7 @@ Object run(VirtualFrame frame, PythonObject moduleSpec, @SuppressWarnings("unuse
212214 PythonContext context = getContext ();
213215 Object state = IndirectCallContext .enter (frame , language , context , this );
214216 try {
215- return run (context , name , path );
217+ return run (context , new ModuleSpec ( name , path , moduleSpec ) );
216218 } catch (ApiInitException ie ) {
217219 throw ie .reraise (getConstructAndRaiseNode (), frame );
218220 } catch (ImportException ie ) {
@@ -225,29 +227,16 @@ Object run(VirtualFrame frame, PythonObject moduleSpec, @SuppressWarnings("unuse
225227 }
226228
227229 @ TruffleBoundary
228- private Object run (PythonContext context , String name , String path ) throws IOException , ApiInitException , ImportException {
229-
230- Object existingModule = findExtensionObject (name , path );
230+ private Object run (PythonContext context , ModuleSpec spec ) throws IOException , ApiInitException , ImportException {
231+ Object existingModule = findExtensionObject (spec );
231232 if (existingModule != null ) {
232233 return existingModule ;
233234 }
234-
235- Object result = CExtContext .loadCExtModule (this , context , name , path , getCheckResultNode (), getCheckHPyResultNode ());
236- if (!(result instanceof PythonModule )) {
237- // PyModuleDef_Init(pyModuleDef)
238- // TODO: PyModule_FromDefAndSpec((PyModuleDef*)m, spec);
239- throw PRaiseNode .raiseUncached (this , PythonErrorType .NotImplementedError , ErrorMessages .MULTI_PHASE_INIT_OF_EXTENSION_MODULE_S , name );
240- } else {
241- ((PythonModule ) result ).setAttribute (__FILE__ , path );
242- // TODO: _PyImport_FixupExtensionObject(result, name, path, sys.modules)
243- PDict sysModules = context .getSysModules ();
244- sysModules .setItem (name , result );
245- return result ;
246- }
235+ return CExtContext .loadCExtModule (this , context , spec , getCheckResultNode (), getCheckHPyResultNode ());
247236 }
248237
249238 @ SuppressWarnings ({"static-method" , "unused" })
250- private Object findExtensionObject (String name , String path ) {
239+ private Object findExtensionObject (ModuleSpec spec ) {
251240 // TODO: to avoid initializing an extension module twice, keep an internal dict
252241 // and possibly return from there, i.e., _PyImport_FindExtensionObject(name, path)
253242 return null ;
@@ -270,13 +259,52 @@ private HPyCheckFunctionResultNode getCheckHPyResultNode() {
270259 }
271260 }
272261
273- @ Builtin (name = "exec_dynamic" , minNumOfPositionalArgs = 1 )
262+ @ Builtin (name = "exec_dynamic" , minNumOfPositionalArgs = 1 , doc = "exec_dynamic($module, mod, /) \n -- \n \n Initialize an extension module." )
274263 @ GenerateNodeFactory
275264 public abstract static class ExecDynamicNode extends PythonBuiltinNode {
276265 @ Specialization
277- public Object run (PythonModule extensionModule ) {
278- // TODO: implement PyModule_ExecDef
279- return extensionModule ;
266+ int doPythonModule (VirtualFrame frame , PythonModule extensionModule ,
267+ @ CachedLanguage PythonLanguage language ,
268+ @ CachedLibrary (limit = "1" ) HashingStorageLibrary lib ,
269+ @ Cached ExecModuleNode execModuleNode ) {
270+ Object nativeModuleDef = extensionModule .getNativeModuleDef ();
271+ if (nativeModuleDef == null ) {
272+ return 0 ;
273+ }
274+
275+ /*
276+ * Check if module is already initialized. CPython does that by testing if 'md_state !=
277+ * NULL'. So, we do the same. Currently, we store this in the generic storage of the
278+ * native wrapper.
279+ */
280+ DynamicObjectNativeWrapper nativeWrapper = extensionModule .getNativeWrapper ();
281+ if (nativeWrapper != null && nativeWrapper .getNativeMemberStore () != null ) {
282+ Object item = lib .getItem (nativeWrapper .getNativeMemberStore (), NativeMember .MD_STATE .getMemberName ());
283+ if (item != PNone .NO_VALUE ) {
284+ return 0 ;
285+ }
286+ }
287+
288+ PythonContext context = getContext ();
289+ if (!context .hasCApiContext ()) {
290+ throw raise (PythonBuiltinClassType .SystemError , "C API not yet initialized" );
291+ }
292+
293+ /*
294+ * ExecModuleNode will run the module definition's exec function which may run arbitrary
295+ * C code. So we need to setup an indirect call.
296+ */
297+ Object state = IndirectCallContext .enter (frame , language , context , this );
298+ try {
299+ return execModuleNode .execute (context .getCApiContext (), extensionModule , nativeModuleDef );
300+ } finally {
301+ IndirectCallContext .exit (frame , language , context , state );
302+ }
303+ }
304+
305+ @ Fallback
306+ static int doOther (@ SuppressWarnings ("unused" ) Object extensionModule ) {
307+ return 0 ;
280308 }
281309 }
282310
0 commit comments