Skip to content

Commit 9eb3f7e

Browse files
committed
[GR-31698] Add support for calling managed class tp_init from native
PullRequest: graalpython/1817
2 parents 4b48221 + 0043221 commit 9eb3f7e

File tree

11 files changed

+108
-9
lines changed

11 files changed

+108
-9
lines changed

graalpython/com.oracle.graal.python.cext/setup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@
5858
libhpy_name = "libhpy"
5959
libposix_name = "libposix"
6060

61+
MACOS = sys.platform == "darwin"
6162
verbosity = '--verbose' if sys.flags.verbose else '--quiet'
62-
darwin_native = sys.platform == "darwin" and __graalpython__.platform_id == "native"
63+
darwin_native = MACOS and __graalpython__.platform_id == "native"
6364
relative_rpath = "@loader_path" if darwin_native else r"$ORIGIN"
6465
so_ext = get_config_var("EXT_SUFFIX")
6566
SOABI = get_config_var("SOABI")
6667
is_managed = 'managed' in SOABI
67-
lib_ext = 'dylib' if sys.platform == "darwin" else 'so'
68+
lib_ext = 'dylib' if MACOS else 'so'
6869

6970
# configure logger
7071
logger = logging.getLogger(__name__)
@@ -361,6 +362,8 @@ def __init__(self, name, subdir="modules", files=None, deps=[], **kwargs):
361362
# common case: just a single file which is the module's name plus the file extension
362363
if not files:
363364
self.files = [name + ".c"]
365+
else:
366+
self.files = files
364367
self.kwargs = kwargs
365368

366369
def __call__(self):

graalpython/com.oracle.graal.python.cext/src/typeobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,8 @@ int PyType_Ready(PyTypeObject* cls) {
486486
} else {
487487
bases = PyTuple_Pack(1, base);
488488
}
489+
cls->tp_bases = bases;
489490
}
490-
cls->tp_bases = bases;
491491

492492
/* Initialize tp_dict */
493493
PyObject* dict = cls->tp_dict;

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,32 @@ def test_new(self):
204204
tester = TestNew()
205205
assert tester.get_none() is None
206206

207+
def test_init(self):
208+
TestInit = CPyExtType("TestInit",
209+
'''static PyObject* testnew_new(PyTypeObject* cls, PyObject* a, PyObject* b) {
210+
PyObject* obj;
211+
TestInitObject* typedObj;
212+
obj = PyBaseObject_Type.tp_new(cls, a, b);
213+
214+
typedObj = ((TestInitObject*)obj);
215+
typedObj->dict = (PyDictObject*) PyDict_Type.tp_new(&PyDict_Type, a, b);
216+
PyDict_Type.tp_init((PyObject*) typedObj->dict, a, b);
217+
PyDict_SetItemString((PyObject*) typedObj->dict, "test", PyLong_FromLong(42));
218+
219+
Py_XINCREF(obj);
220+
return obj;
221+
}
222+
static PyObject* get_dict_item(PyObject* self) {
223+
return PyDict_GetItemString((PyObject*) ((TestInitObject*)self)->dict, "test");
224+
}
225+
''',
226+
cmembers="PyDictObject *dict;",
227+
tp_new="testnew_new",
228+
tp_methods='{"get_dict_item", (PyCFunction)get_dict_item, METH_NOARGS, ""}'
229+
)
230+
tester = TestInit()
231+
assert tester.get_dict_item() == 42
232+
207233
def test_slots(self):
208234
TestSlots = CPyExtType("TestSlots",
209235
'''

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ private static void handleException(PythonContext context, PException e) {
136136
@Specialization
137137
Object register(Object callable, Object[] arguments, PKeyword[] keywords) {
138138
CompilerDirectives.transferToInterpreter();
139-
RootCallTarget callTarget = PythonLanguage.getCurrent().createCachedCallTarget(l -> new AtExitRootNode(l), AtExitRootNode.class);
139+
RootCallTarget callTarget = PythonLanguage.getCurrent().createCachedCallTarget(AtExitRootNode::new, AtExitRootNode.class);
140140
getContext().registerAtexitHook(callable, arguments, keywords, callTarget);
141141
return callable;
142142
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ public long hashWithState(ThreadState state,
694694
@Exclusive @Cached CastUnsignedToJavaLongHashNode castUnsignedToJavaLongHashNode) {
695695
Object hashMethod = lib.lookupAttributeOnType(this, __HASH__);
696696
if (!methodLib.isCallable(hashMethod) && lookupGet.execute(hashMethod, __GET__) == PNone.NO_VALUE) {
697-
throw raise.raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNHASHABLE_TYPE, this);
697+
throw raise.raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNHASHABLE_TYPE_P, this);
698698
}
699699
Object result = methodLib.callUnboundMethodIgnoreGetExceptionWithState(hashMethod, state, this);
700700
// see PyObject_GetHash and slot_tp_hash in CPython. The result of the

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,9 @@ public PythonAbstractNativeObject getPythonNativeObject(TruffleObject nativePtr,
495495
if (newRefProfile.profile(id == 0)) {
496496
return createPythonAbstractNativeObject(nativePtr, addRefCntNode, steal, attachLLVMTypeNode);
497497
} else if (validRefProfile.profile(id > 0)) {
498-
PythonAbstractNativeObject nativeObject;
499498
ref = lookupNativeObjectReference(id);
500499
if (ref != null) {
501-
nativeObject = ref.get();
500+
PythonAbstractNativeObject nativeObject = ref.get();
502501
if (resurrectProfile.profile(nativeObject == null)) {
503502
// Bad luck: the mapping is still there and wasn't cleaned up but we need a new
504503
// mapping. Therefore, we need to cancel the cleaner action and set a new native

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import static com.oracle.graal.python.nodes.SpecialMethodNames.RICHCMP;
6868
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTRIBUTE__;
6969
import static com.oracle.graal.python.nodes.SpecialMethodNames.__HASH__;
70+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
7071
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LEN__;
7172
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NEW__;
7273
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NEXT__;
@@ -534,6 +535,13 @@ static Object doTpNew(PythonManagedClass object, @SuppressWarnings("unused") Pyt
534535
return ManagedMethodWrappers.createKeywords(newFunction, callGetNewfuncTypeidNode.call(NativeCAPISymbol.FUN_GET_NEWFUNC_TYPE_ID));
535536
}
536537

538+
@Specialization(guards = "eq(TP_INIT, key)")
539+
static Object doTpInit(PythonManagedClass object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, @SuppressWarnings("unused") String key,
540+
@Cached LookupAttributeInMRONode.Dynamic getAttrNode) {
541+
Object initFun = getAttrNode.execute(object, __INIT__);
542+
return PyProcsWrapper.createInitWrapper(initFun);
543+
}
544+
537545
@Specialization(guards = "eq(TP_HASH, key)")
538546
static Object doTpHash(PythonManagedClass object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, @SuppressWarnings("unused") String key,
539547
@Cached LookupAttributeInMRONode.Dynamic getHashNode,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public enum NativeMember {
9797
TP_SETATTRO("tp_setattro"),
9898
TP_ITERNEXT("tp_iternext"),
9999
TP_NEW("tp_new"),
100+
TP_INIT("tp_init"),
100101
TP_DICT("tp_dict", OBJECT),
101102
TP_STR("tp_str"),
102103
TP_REPR("tp_repr"),

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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,20 @@
4949
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.TransformExceptionToNativeNode;
5050
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.PAsPointerNode;
5151
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapper.ToPyObjectNode;
52+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
53+
import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode;
54+
import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode;
55+
import com.oracle.graal.python.nodes.argument.positional.PositionalArgumentsNode;
5256
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
5357
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
58+
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
5459
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
5560
import com.oracle.graal.python.runtime.GilNode;
5661
import com.oracle.graal.python.runtime.exception.PException;
5762
import com.oracle.truffle.api.CompilerDirectives;
5863
import com.oracle.truffle.api.dsl.Cached;
5964
import com.oracle.truffle.api.dsl.Cached.Exclusive;
65+
import com.oracle.truffle.api.dsl.Specialization;
6066
import com.oracle.truffle.api.interop.ArityException;
6167
import com.oracle.truffle.api.interop.InteropLibrary;
6268
import com.oracle.truffle.api.interop.UnsupportedMessageException;
@@ -196,6 +202,57 @@ protected int execute(Object[] arguments,
196202

197203
}
198204

205+
@ExportLibrary(InteropLibrary.class)
206+
static class InitWrapper extends PyProcsWrapper {
207+
208+
public InitWrapper(Object delegate) {
209+
super(delegate);
210+
}
211+
212+
@ExportMessage(name = "execute")
213+
static class Execute {
214+
215+
@Specialization(guards = "arguments.length == 3")
216+
static int init(InitWrapper self, Object[] arguments,
217+
@CachedLibrary("self") PythonNativeWrapperLibrary lib,
218+
@Cached ExecutePositionalStarargsNode.ExecutePositionalStarargsInteropNode posStarargsNode,
219+
@Cached ExpandKeywordStarargsNode expandKwargsNode,
220+
@Cached CallVarargsMethodNode callNode,
221+
@Cached ToJavaNode toJavaNode,
222+
@Cached BranchProfile errorProfile,
223+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
224+
@Exclusive @Cached GilNode gil) {
225+
boolean mustRelease = gil.acquire();
226+
try {
227+
try {
228+
// convert args
229+
Object receiver = toJavaNode.execute(arguments[0]);
230+
Object starArgs = toJavaNode.execute(arguments[1]);
231+
Object kwArgs = toJavaNode.execute(arguments[2]);
232+
233+
Object[] starArgsArray = posStarargsNode.executeWithGlobalState(starArgs);
234+
Object[] pArgs = PositionalArgumentsNode.prependArgument(receiver, starArgsArray);
235+
PKeyword[] kwArgsArray = expandKwargsNode.execute(kwArgs);
236+
callNode.execute(null, lib.getDelegate(self), pArgs, kwArgsArray);
237+
return 0;
238+
} catch (PException e) {
239+
errorProfile.enter();
240+
transformExceptionToNativeNode.execute(null, e);
241+
return -1;
242+
}
243+
} finally {
244+
gil.release(mustRelease);
245+
}
246+
}
247+
248+
@Specialization(guards = "arguments.length != 3")
249+
static int error(@SuppressWarnings("unused") InitWrapper self, Object[] arguments) throws ArityException {
250+
throw ArityException.create(3, 3, arguments.length);
251+
}
252+
253+
}
254+
}
255+
199256
@ExportLibrary(InteropLibrary.class)
200257
static class SsizeargfuncWrapper extends PyProcsWrapper {
201258

@@ -245,6 +302,10 @@ public static SetAttrWrapper createSetAttrWrapper(Object setAttrMethod) {
245302
return new SetAttrWrapper(setAttrMethod);
246303
}
247304

305+
public static InitWrapper createInitWrapper(Object setInitMethod) {
306+
return new InitWrapper(setInitMethod);
307+
}
308+
248309
public static SsizeargfuncWrapper createSsizeargfuncWrapper(Object ssizeArgMethod, boolean newRef) {
249310
return new SsizeargfuncWrapper(ssizeArgMethod, newRef);
250311
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/slice/SliceBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public abstract static class HashNode extends PythonBuiltinNode {
221221
public static long hash(PSlice self,
222222
@Cached PRaiseNode raise) {
223223
CompilerDirectives.transferToInterpreter();
224-
throw raise.raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNHASHABLE_TYPE, PythonBuiltinClassType.PSlice);
224+
throw raise.raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNHASHABLE_TYPE_P, PythonBuiltinClassType.PSlice);
225225
}
226226
}
227227

0 commit comments

Comments
 (0)