Skip to content

Commit bab16f9

Browse files
committed
Implement exec phase
1 parent 90025fd commit bab16f9

File tree

2 files changed

+139
-21
lines changed

2 files changed

+139
-21
lines changed

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

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@
5151
import com.oracle.graal.python.builtins.Builtin;
5252
import com.oracle.graal.python.builtins.CoreFunctions;
5353
import com.oracle.graal.python.builtins.Python3Core;
54+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5455
import com.oracle.graal.python.builtins.PythonBuiltins;
5556
import com.oracle.graal.python.builtins.objects.PNone;
5657
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
5758
import com.oracle.graal.python.builtins.objects.bytes.PBytesLike;
59+
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.ExecModuleNode;
5860
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodesFactory.DefaultCheckFunctionResultNodeGen;
5961
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.CheckFunctionResultNode;
6062
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
@@ -89,6 +91,7 @@
8991
import com.oracle.truffle.api.dsl.Cached;
9092
import com.oracle.truffle.api.dsl.CachedContext;
9193
import com.oracle.truffle.api.dsl.CachedLanguage;
94+
import com.oracle.truffle.api.dsl.Fallback;
9295
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
9396
import com.oracle.truffle.api.dsl.NodeFactory;
9497
import com.oracle.truffle.api.dsl.Specialization;
@@ -270,13 +273,40 @@ private HPyCheckFunctionResultNode getCheckHPyResultNode() {
270273
}
271274
}
272275

273-
@Builtin(name = "exec_dynamic", minNumOfPositionalArgs = 1)
276+
@Builtin(name = "exec_dynamic", minNumOfPositionalArgs = 1, doc = "exec_dynamic($module, mod, /)\n--\n\nInitialize an extension module.")
274277
@GenerateNodeFactory
275278
public abstract static class ExecDynamicNode extends PythonBuiltinNode {
276279
@Specialization
277-
public Object run(PythonModule extensionModule) {
278-
// TODO: implement PyModule_ExecDef
279-
return extensionModule;
280+
int doPythonModule(VirtualFrame frame, PythonModule extensionModule,
281+
@CachedLanguage PythonLanguage language,
282+
@Cached ExecModuleNode execModuleNode) {
283+
Object nativeModuleDef = extensionModule.getNativeModuleDef();
284+
if (nativeModuleDef == null) {
285+
return 0;
286+
}
287+
288+
// TODO(fa): check if module is already initialized
289+
290+
PythonContext context = getContext();
291+
if (!context.hasCApiContext()) {
292+
throw raise(PythonBuiltinClassType.SystemError, "C API not yet initialized");
293+
}
294+
295+
/*
296+
* ExecModuleNode will run the module definition's exec function which may run arbitrary
297+
* C code. So we need to setup an indirect call.
298+
*/
299+
Object state = IndirectCallContext.enter(frame, language, context, this);
300+
try {
301+
return execModuleNode.execute(context.getCApiContext(), extensionModule, nativeModuleDef);
302+
} finally {
303+
IndirectCallContext.exit(frame, language, context, state);
304+
}
305+
}
306+
307+
@Fallback
308+
static int doOther(@SuppressWarnings("unused") Object extensionModule) {
309+
return 0;
280310
}
281311
}
282312

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

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorDeleteMarker;
125125
import com.oracle.graal.python.builtins.objects.ints.PInt;
126126
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
127+
import com.oracle.graal.python.builtins.objects.module.ModuleGetNameNode;
127128
import com.oracle.graal.python.builtins.objects.module.PythonModule;
128129
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
129130
import com.oracle.graal.python.builtins.objects.str.NativeCharSequence;
@@ -3555,8 +3556,28 @@ static TruffleObject doGeneric(TruffleObject ptr,
35553556
}
35563557
}
35573558

3559+
abstract static class MultiPhaseExtensionModuleInitNode extends Node {
3560+
3561+
static final String M_NAME = "m_name";
3562+
static final String M_DOC = "m_doc";
3563+
static final String M_METHODS = "m_methods";
3564+
static final String M_SLOTS = "m_slots";
3565+
static final String M_SIZE = "m_size";
3566+
3567+
// according to definitions in 'moduleobject.h'
3568+
static final int SLOT_PY_MOD_CREATE = 1;
3569+
static final int SLOT_PY_MOD_EXEC = 2;
3570+
3571+
// member names of 'PyModuleDef_Slot'
3572+
static final String MODULEDEF_SLOT = "slot";
3573+
static final String MODULEDEF_VALUE = "value";
3574+
3575+
static final String FIELD_S_DID_NOT_RETURN_AN_ARRAY = "field '%s' did not return an array";
3576+
}
3577+
35583578
/**
3559-
* Creates a Python module from a module definition structure:
3579+
* Equivalent of {@code PyModule_FromDefAndSpec2}. Creates a Python module from a module
3580+
* definition structure:
35603581
*
35613582
* <pre>
35623583
* typedef struct PyModuleDef {
@@ -3573,24 +3594,14 @@ static TruffleObject doGeneric(TruffleObject ptr,
35733594
* </pre>
35743595
*/
35753596
@GenerateUncached
3576-
public abstract static class CreateModuleNode extends Node {
3597+
public abstract static class CreateModuleNode extends MultiPhaseExtensionModuleInitNode {
35773598

3578-
public static final String M_NAME = "m_name";
3579-
public static final String M_DOC = "m_doc";
3580-
public static final String M_METHODS = "m_methods";
3581-
public static final String M_SLOTS = "m_slots";
3582-
3583-
// according to definitions in 'moduleobject.h'
3584-
public static final int SLOT_PY_MOD_CREATE = 1;
3585-
public static final int SLOT_PY_MOD_EXEC = 2;
3586-
public static final String M_SIZE = "m_size";
3587-
private static final String FIELD_S_DID_NOT_RETURN_AN_ARRAY = "field '%s' did not return an array";
35883599
private static final String CREATION_FAILD_WITHOUT_EXCEPTION = "creation of module %s failed without setting an exception";
35893600
private static final String CREATION_RAISED_EXCEPTION = "creation of module %s raised unreported exception";
35903601
public static final String NOT_A_MODULE_OBJECT_BUT_REQUESTS_MODULE_STATE = "module %s is not a module object, but requests module state";
35913602

35923603
@TruffleBoundary
3593-
private static boolean checkLayout(Object moduleDef, InteropLibrary moduleDefLib) {
3604+
static boolean checkLayout(Object moduleDef, InteropLibrary moduleDefLib) {
35943605
String[] members = new String[]{"m_base", M_NAME, M_DOC, M_SIZE, M_METHODS, M_SLOTS, "m_traverse", "m_clear", "m_free"};
35953606
for (String member : members) {
35963607
if (!moduleDefLib.isMemberReadable(moduleDef, member)) {
@@ -3602,7 +3613,7 @@ private static boolean checkLayout(Object moduleDef, InteropLibrary moduleDefLib
36023613

36033614
public abstract Object execute(CApiContext capiContext, Object moduleSpec, Object moduleDef);
36043615

3605-
@Specialization(limit = "1")
3616+
@Specialization
36063617
static Object doGeneric(CApiContext capiContext, Object moduleSpec, PythonAbstractNativeObject moduleDefWrapper,
36073618
@CachedLanguage PythonLanguage language,
36083619
@Cached PythonObjectFactory factory,
@@ -3658,14 +3669,14 @@ static Object doGeneric(CApiContext capiContext, Object moduleSpec, PythonAbstra
36583669
for (long i = 0; i < nSlots; i++) {
36593670
Object slotDefinition = interopLib.readArrayElement(slotDefinitions, i);
36603671

3661-
Object slotIdObj = interopLib.readMember(slotDefinition, "slot");
3672+
Object slotIdObj = interopLib.readMember(slotDefinition, MODULEDEF_SLOT);
36623673
int slotId = interopLib.asInt(slotIdObj);
36633674
switch (slotId) {
36643675
case SLOT_PY_MOD_CREATE:
36653676
if (createFunction != null) {
36663677
throw raiseNode.raise(SystemError, "module %s has multiple create slots", mName);
36673678
}
3668-
createFunction = interopLib.readMember(slotDefinition, "value");
3679+
createFunction = interopLib.readMember(slotDefinition, MODULEDEF_VALUE);
36693680
break;
36703681
case SLOT_PY_MOD_EXEC:
36713682
hasExecutionSlots = true;
@@ -3709,7 +3720,9 @@ static Object doGeneric(CApiContext capiContext, Object moduleSpec, PythonAbstra
37093720
throw CompilerDirectives.shouldNotReachHere();
37103721
}
37113722
} else {
3712-
module = factory.createPythonModule(mName);
3723+
PythonModule pythonModule = factory.createPythonModule(mName);
3724+
pythonModule.setNativeModuleDef(moduleDef);
3725+
module = pythonModule;
37133726
}
37143727

37153728
// parse method definitions
@@ -3742,6 +3755,81 @@ static Object doGeneric(CApiContext capiContext, Object moduleSpec, PythonAbstra
37423755
}
37433756
}
37443757

3758+
/**
3759+
* Equivalent to {@code PyModule_ExecDef}.
3760+
*/
3761+
@GenerateUncached
3762+
public abstract static class ExecModuleNode extends MultiPhaseExtensionModuleInitNode {
3763+
private static final String EXECUTION_FAILED_WITHOUT_EXCEPTION = "execution of module %s failed without setting an exception";
3764+
private static final String EXECUTION_RAISED_EXCEPTION = "execution of module %s raised unreported exception";
3765+
3766+
public abstract int execute(CApiContext capiContext, PythonModule module, Object moduleDef);
3767+
3768+
@Specialization
3769+
static int doGeneric(CApiContext capiContext, PythonModule module, Object moduleDef,
3770+
@CachedLanguage PythonLanguage language,
3771+
@Cached PythonObjectFactory factory,
3772+
@Cached ModuleGetNameNode getNameNode,
3773+
@Cached PCallCapiFunction callGetterNode,
3774+
@CachedLibrary(limit = "3") InteropLibrary interopLib,
3775+
@Cached ToBorrowedRefNode moduleToNativeNode,
3776+
@Cached PRaiseNode raiseNode) {
3777+
// call to type the pointer
3778+
assert CreateModuleNode.checkLayout(moduleDef, interopLib);
3779+
3780+
String mName = getNameNode.execute(module);
3781+
int mSize;
3782+
try {
3783+
Object mSizeObj = interopLib.readMember(moduleDef, M_SIZE);
3784+
mSize = interopLib.asInt(mSizeObj);
3785+
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
3786+
CompilerDirectives.transferToInterpreterAndInvalidate();
3787+
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "Cannot create module from definition because: %m", e);
3788+
}
3789+
3790+
if (mSize >= 0) {
3791+
// TODO(fa): allocate md_state
3792+
}
3793+
3794+
// parse slot definitions
3795+
try {
3796+
Object slotDefinitions = callGetterNode.call(capiContext, FUN_GET_PYMODULEDEF_M_SLOTS, moduleDef);
3797+
if (interopLib.isNull(slotDefinitions)) {
3798+
return 0;
3799+
}
3800+
if (!interopLib.hasArrayElements(slotDefinitions)) {
3801+
CompilerDirectives.transferToInterpreterAndInvalidate();
3802+
throw raiseNode.raise(PythonBuiltinClassType.SystemError, FIELD_S_DID_NOT_RETURN_AN_ARRAY, M_SLOTS);
3803+
}
3804+
long nSlots = interopLib.getArraySize(slotDefinitions);
3805+
for (long i = 0; i < nSlots; i++) {
3806+
Object slotDefinition = interopLib.readArrayElement(slotDefinitions, i);
3807+
3808+
Object slotIdObj = interopLib.readMember(slotDefinition, MODULEDEF_SLOT);
3809+
int slotId = interopLib.asInt(slotIdObj);
3810+
switch (slotId) {
3811+
case SLOT_PY_MOD_CREATE:
3812+
// handled in CreateModuleNode
3813+
break;
3814+
case SLOT_PY_MOD_EXEC:
3815+
Object execFunction = interopLib.readMember(slotDefinition, MODULEDEF_VALUE);
3816+
Object result = interopLib.execute(execFunction, moduleToNativeNode.execute(capiContext, module));
3817+
int iResult = interopLib.asInt(result);
3818+
DefaultCheckFunctionResultNode.checkFunctionResult(mName, iResult != 0, true, language, capiContext.getContext(), raiseNode, factory,
3819+
EXECUTION_FAILED_WITHOUT_EXCEPTION, EXECUTION_RAISED_EXCEPTION);
3820+
break;
3821+
default:
3822+
throw raiseNode.raise(SystemError, "module %s initialized with unknown slot %i", mName, slotId);
3823+
}
3824+
}
3825+
} catch (UnsupportedMessageException | InvalidArrayIndexException | UnknownIdentifierException | UnsupportedTypeException | ArityException e) {
3826+
throw CompilerDirectives.shouldNotReachHere();
3827+
}
3828+
3829+
return 0;
3830+
}
3831+
}
3832+
37453833
/**
37463834
* <pre>
37473835
* struct PyMethodDef {

0 commit comments

Comments
 (0)