Skip to content

Commit 52460d1

Browse files
committed
Skip reload of already initialized ext modules.
1 parent 7834a6c commit 52460d1

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
5757
import com.oracle.graal.python.builtins.objects.bytes.PBytesLike;
5858
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.ExecModuleNode;
59+
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper;
5960
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodesFactory.DefaultCheckFunctionResultNodeGen;
61+
import com.oracle.graal.python.builtins.objects.cext.capi.NativeMember;
6062
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.CheckFunctionResultNode;
6163
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
6264
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext.ModuleSpec;
@@ -65,6 +67,7 @@
6567
import com.oracle.graal.python.builtins.objects.cext.hpy.HPyExternalFunctionNodes.HPyCheckFunctionResultNode;
6668
import com.oracle.graal.python.builtins.objects.cext.hpy.HPyExternalFunctionNodesFactory.HPyCheckHandleResultNodeGen;
6769
import com.oracle.graal.python.builtins.objects.code.PCode;
70+
import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
6871
import com.oracle.graal.python.builtins.objects.ints.IntBuiltins;
6972
import com.oracle.graal.python.builtins.objects.ints.PInt;
7073
import com.oracle.graal.python.builtins.objects.module.PythonModule;
@@ -262,13 +265,25 @@ public abstract static class ExecDynamicNode extends PythonBuiltinNode {
262265
@Specialization
263266
int doPythonModule(VirtualFrame frame, PythonModule extensionModule,
264267
@CachedLanguage PythonLanguage language,
268+
@CachedLibrary(limit = "1") HashingStorageLibrary lib,
265269
@Cached ExecModuleNode execModuleNode) {
266270
Object nativeModuleDef = extensionModule.getNativeModuleDef();
267271
if (nativeModuleDef == null) {
268272
return 0;
269273
}
270274

271-
// TODO(fa): check if module is already initialized
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+
}
272287

273288
PythonContext context = getContext();
274289
if (!context.hasCApiContext()) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_BYTE_ARRAY_TO_NATIVE;
5151
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_TRUFFLE_STRING_TO_CSTR;
5252
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_WHCAR_SIZE;
53+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeMember.MD_STATE;
5354
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeMember.OB_REFCNT;
5455
import static com.oracle.graal.python.nodes.SpecialMethodNames.__COMPLEX__;
5556
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemError;
@@ -99,6 +100,7 @@
99100
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.VoidPtrToJavaNodeGen;
100101
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.PrimitiveNativeWrapper;
101102
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.PythonObjectNativeWrapper;
103+
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.WriteNativeMemberNode;
102104
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.DefaultCheckFunctionResultNode;
103105
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethKeywordsRoot;
104106
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethNoargsRoot;
@@ -3759,7 +3761,7 @@ static Object doGeneric(CApiContext capiContext, ModuleSpec moduleSpec, PythonAb
37593761
}
37603762

37613763
/**
3762-
* Equivalent to {@code PyModule_ExecDef}.
3764+
* Equivalent of {@code PyModule_ExecDef}.
37633765
*/
37643766
@GenerateUncached
37653767
public abstract static class ExecModuleNode extends MultiPhaseExtensionModuleInitNode {
@@ -3774,6 +3776,8 @@ static int doGeneric(CApiContext capiContext, PythonModule module, Object module
37743776
@Cached PythonObjectFactory factory,
37753777
@Cached ModuleGetNameNode getNameNode,
37763778
@Cached PCallCapiFunction callGetterNode,
3779+
@Cached WriteNativeMemberNode writeNativeMemberNode,
3780+
@Cached PCallCapiFunction callMallocNode,
37773781
@CachedLibrary(limit = "3") InteropLibrary interopLib,
37783782
@Cached ToBorrowedRefNode moduleToNativeNode,
37793783
@Cached PRaiseNode raiseNode) {
@@ -3790,12 +3794,21 @@ static int doGeneric(CApiContext capiContext, PythonModule module, Object module
37903794
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "Cannot create module from definition because: %m", e);
37913795
}
37923796

3793-
if (mSize >= 0) {
3794-
// TODO(fa): allocate md_state
3795-
}
3796-
3797-
// parse slot definitions
37983797
try {
3798+
// allocate md_state if necessary
3799+
if (mSize >= 0) {
3800+
// The cast is not nice but it will at least fail if we change the wrapper type.
3801+
PythonNativeWrapper moduleWrapper = (PythonNativeWrapper) moduleToNativeNode.execute(capiContext, module);
3802+
/*
3803+
* TODO(fa): We currently leak 'md_state' and need to use a shared finalizer or
3804+
* similar. We ignore that for now since the size will usually be very small
3805+
* and/or we could also use a Truffle buffer object.
3806+
*/
3807+
Object moduleStatePtr = callMallocNode.call(capiContext, NativeCAPISymbol.FUN_PYMEM_RAWMALLOC, mSize);
3808+
writeNativeMemberNode.execute(module, moduleWrapper, MD_STATE.getMemberName(), moduleStatePtr);
3809+
}
3810+
3811+
// parse slot definitions
37993812
Object slotDefinitions = callGetterNode.call(capiContext, FUN_GET_PYMODULEDEF_M_SLOTS, moduleDef);
38003813
if (interopLib.isNull(slotDefinitions)) {
38013814
return 0;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/NativeCAPISymbol.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
155155
FUN_NATIVE_UNICODE_AS_STRING("native_unicode_as_string"),
156156
FUN_PY_UNICODE_GET_LENGTH("PyUnicode_GetLength"),
157157
FUN_GET_UINT32_ARRAY_TYPE_ID("get_uint32_array_typeid"),
158+
FUN_PYMEM_RAWMALLOC("PyMem_RawMalloc"),
158159
FUN_PY_TRUFFLE_FREE("PyTruffle_Free"),
159160
FUN_INCREF("Py_IncRef"),
160161
FUN_DECREF("Py_DecRef"),

0 commit comments

Comments
 (0)