Skip to content

Commit 4a25dcd

Browse files
committed
[GR-53923] Add native slot wrappers in a single upcall
PullRequest: graalpython/3810
2 parents 45cdf9c + 5493156 commit 4a25dcd

File tree

12 files changed

+183
-784
lines changed

12 files changed

+183
-784
lines changed

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

Lines changed: 8 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ _Py_IDENTIFIER(__module__);
7070
_Py_IDENTIFIER(__eq__);
7171
_Py_IDENTIFIER(__hash__);
7272

73-
// GraalPy change: forward delcarations of our helpers
74-
static void add_slot(PyTypeObject* cls, char* name, void* meth, int flags, int signature, char* doc);
75-
static int type_ready_graalpy_slot_conv(PyTypeObject* cls);
76-
7773

7874
static PyObject *
7975
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -4114,6 +4110,7 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
41144110
extern void
41154111
_PyDictKeys_DecRef(PyDictKeysObject *keys);
41164112

4113+
41174114
static void
41184115
type_dealloc_common(PyTypeObject *type)
41194116
{
@@ -4540,6 +4537,7 @@ PyTypeObject PyType_Type = {
45404537
#endif // GraalPy change
45414538
};
45424539

4540+
45434541
#if 0 // GraalPy change
45444542
/* The base type of all types (eventually)... except itself. */
45454543

@@ -6250,11 +6248,9 @@ static int
62506248
type_ready_fill_dict(PyTypeObject *type)
62516249
{
62526250
/* Add type-specific descriptors to tp_dict */
6253-
#if 0 // GraalPy change
62546251
if (add_operators(type) < 0) {
62556252
return -1;
62566253
}
6257-
#endif // GraalPy change
62586254
if (type_add_methods(type) < 0) {
62596255
return -1;
62606256
}
@@ -6439,10 +6435,7 @@ type_ready_set_new(PyTypeObject *type)
64396435

64406436
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
64416437
if (type->tp_new != NULL) {
6442-
// If "__new__" key does not exists in the type dictionary,
6443-
// set it to tp_new_wrapper().
6444-
// GraalPy change
6445-
add_slot(type, "__new__", type->tp_new, METH_KEYWORDS | METH_VARARGS, JWRAPPER_NEW, NULL);
6438+
// GraalPy change: the wrapper is created in add_operators with the rest of slots
64466439
}
64476440
else {
64486441
// tp_new is NULL: inherit tp_new from base
@@ -6497,10 +6490,8 @@ type_ready_post_checks(PyTypeObject *type)
64976490
}
64986491
return 0;
64996492
}
6500-
#endif // GraalPy change
65016493

6502-
// GraalPy-specific
6503-
static int type_ready_graalpy_slot_conv(PyTypeObject* cls);
6494+
#endif // GraalPy change
65046495

65056496
static int
65066497
type_ready(PyTypeObject *type)
@@ -6536,10 +6527,6 @@ type_ready(PyTypeObject *type)
65366527
if (type_ready_fill_dict(type) < 0) {
65376528
return -1;
65386529
}
6539-
// GraalPy change
6540-
if (type_ready_graalpy_slot_conv(type) < 0) {
6541-
return -1;
6542-
}
65436530
if (type_ready_inherit(type) < 0) {
65446531
return -1;
65456532
}
@@ -8785,6 +8772,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
87858772
}
87868773
return 0;
87878774
}
8775+
#endif // GraalPy change
87888776

87898777
/* This function is called by PyType_Ready() to populate the type's
87908778
dictionary with method descriptors for function slots. For each
@@ -8819,46 +8807,12 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
88198807
static int
88208808
add_operators(PyTypeObject *type)
88218809
{
8822-
PyObject *dict = type->tp_dict;
8823-
slotdef *p;
8824-
PyObject *descr;
8825-
void **ptr;
8826-
8827-
assert(slotdefs_initialized);
8828-
for (p = slotdefs; p->name; p++) {
8829-
if (p->wrapper == NULL)
8830-
continue;
8831-
ptr = slotptr(type, p->offset);
8832-
if (!ptr || !*ptr)
8833-
continue;
8834-
int r = PyDict_Contains(dict, p->name_strobj);
8835-
if (r > 0)
8836-
continue;
8837-
if (r < 0) {
8838-
return -1;
8839-
}
8840-
if (*ptr == (void *)PyObject_HashNotImplemented) {
8841-
/* Classes may prevent the inheritance of the tp_hash
8842-
slot by storing PyObject_HashNotImplemented in it. Make it
8843-
visible as a None value for the __hash__ attribute. */
8844-
if (PyDict_SetItem(dict, p->name_strobj, Py_None) < 0)
8845-
return -1;
8846-
}
8847-
else {
8848-
descr = PyDescr_NewWrapper(type, p, *ptr);
8849-
if (descr == NULL)
8850-
return -1;
8851-
if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) {
8852-
Py_DECREF(descr);
8853-
return -1;
8854-
}
8855-
Py_DECREF(descr);
8856-
}
8857-
}
8858-
return 0;
8810+
// GraalPy change: different implementation
8811+
return GraalPyTruffleType_AddOperators(type);
88598812
}
88608813

88618814

8815+
#if 0 // GraalPy change
88628816
/* Cooperative 'super' */
88638817

88648818
typedef struct {
@@ -9310,165 +9264,3 @@ PyTypeObject PySuper_Type = {
93109264
.tp_vectorcall = (vectorcallfunc)super_vectorcall,
93119265
};
93129266
#endif // GraalPy change
9313-
9314-
9315-
// GraalPy additions
9316-
9317-
static void add_slot(PyTypeObject* type, char* name, void* meth, int flags, int signature, char* doc) {
9318-
if (meth) {
9319-
GraalPyTruffleType_AddSlot(type,
9320-
type->tp_dict,
9321-
name,
9322-
meth,
9323-
flags,
9324-
(signature != 0 ? signature : get_method_flags_wrapper(flags)),
9325-
doc);
9326-
}
9327-
}
9328-
9329-
static int type_ready_graalpy_slot_conv(PyTypeObject* cls) {
9330-
#define ADD_SLOT_CONV(__name__, __meth__, __flags__, __signature__) add_slot(cls, (__name__), (__meth__), (__flags__), (__signature__), NULL)
9331-
9332-
// TODO: once all slots are converted, we can do one upcall to managed implementation
9333-
// of add_operators that will use TpSlots#SLOTDEFS and the same algorithm as CPython
9334-
9335-
/*
9336-
* NOTE: ADD_SLOT_CONV won't overwrite existing attributes, so the order is crucial and must
9337-
* reflect CPython's 'slotdefs' array.
9338-
*/
9339-
9340-
// add special methods defined directly on the type structs
9341-
ADD_SLOT_CONV("__dealloc__", cls->tp_dealloc, -1, JWRAPPER_DIRECT);
9342-
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_getattr
9343-
// tp_getattr and tp_setattr are deprecated, and should be the same as
9344-
// tp_getattro and tp_setattro
9345-
9346-
// NOTE: The slots may be called from managed code, i.e., we need to wrap the functions
9347-
// and convert arguments that should be C primitives.
9348-
// ADD_SLOT_CONV("__getattribute__", cls->tp_getattr, -2, JWRAPPER_GETATTR); tp_getattr does not have wrapper set in slotdefs and hence is ignored in add_operators
9349-
// ADD_SLOT_CONV("__setattr__", cls->tp_setattr, -3, JWRAPPER_SETATTR); dtto for tp_setattr
9350-
ADD_SLOT_CONV("__repr__", cls->tp_repr, -1, JWRAPPER_REPR);
9351-
ADD_SLOT_CONV("__hash__", cls->tp_hash, -1, JWRAPPER_HASHFUNC);
9352-
ADD_SLOT_CONV("__call__", cls->tp_call, METH_KEYWORDS | METH_VARARGS, JWRAPPER_CALL);
9353-
ADD_SLOT_CONV("__str__", cls->tp_str, -1, JWRAPPER_STR);
9354-
ADD_SLOT_CONV("__getattribute__", cls->tp_getattro, -2, JWRAPPER_BINARYFUNC);
9355-
ADD_SLOT_CONV("__setattr__", cls->tp_setattro, -3, JWRAPPER_SETATTRO);
9356-
ADD_SLOT_CONV("__delattr__", cls->tp_setattro, -3, JWRAPPER_DELATTRO);
9357-
ADD_SLOT_CONV("__clear__", cls->tp_clear, -1, JWRAPPER_INQUIRY);
9358-
9359-
richcmpfunc richcompare = cls->tp_richcompare;
9360-
if (richcompare) {
9361-
ADD_SLOT_CONV("__lt__", richcompare, -2, JWRAPPER_LT);
9362-
ADD_SLOT_CONV("__le__", richcompare, -2, JWRAPPER_LE);
9363-
ADD_SLOT_CONV("__eq__", richcompare, -2, JWRAPPER_EQ);
9364-
ADD_SLOT_CONV("__ne__", richcompare, -2, JWRAPPER_NE);
9365-
ADD_SLOT_CONV("__gt__", richcompare, -2, JWRAPPER_GT);
9366-
ADD_SLOT_CONV("__ge__", richcompare, -2, JWRAPPER_GE);
9367-
}
9368-
ADD_SLOT_CONV("__iter__", cls->tp_iter, -1, JWRAPPER_UNARYFUNC);
9369-
ADD_SLOT_CONV("__next__", cls->tp_iternext, -1, JWRAPPER_ITERNEXT);
9370-
ADD_SLOT_CONV("__get__", cls->tp_descr_get, -3, JWRAPPER_DESCR_GET);
9371-
ADD_SLOT_CONV("__set__", cls->tp_descr_set, -3, JWRAPPER_DESCR_SET);
9372-
ADD_SLOT_CONV("__delete__", cls->tp_descr_set, -2, JWRAPPER_DESCR_DELETE);
9373-
ADD_SLOT_CONV("__init__", cls->tp_init, METH_KEYWORDS | METH_VARARGS, JWRAPPER_INITPROC);
9374-
ADD_SLOT_CONV("__alloc__", cls->tp_alloc, -2, JWRAPPER_ALLOC);
9375-
/* Note: '__new__' was added here previously but we don't do it similar to CPython.
9376-
They also skip it because the appropriate 'slotdef' doesn't have a wrapper.
9377-
Adding '__new__' is done by function 'type_ready_set_new'. */
9378-
ADD_SLOT_CONV("__free__", cls->tp_free, -1, JWRAPPER_DIRECT);
9379-
ADD_SLOT_CONV("__del__", cls->tp_del, -1, JWRAPPER_DIRECT);
9380-
ADD_SLOT_CONV("__finalize__", cls->tp_finalize, -1, JWRAPPER_DIRECT);
9381-
9382-
// 'tp_as_number' takes precedence over 'tp_as_mapping' and 'tp_as_sequence' !
9383-
PyNumberMethods* numbers = cls->tp_as_number;
9384-
if (numbers) {
9385-
ADD_SLOT_CONV("__add__", numbers->nb_add, -2, JWRAPPER_BINARYFUNC_L);
9386-
ADD_SLOT_CONV("__radd__", numbers->nb_add, -2, JWRAPPER_BINARYFUNC_R);
9387-
ADD_SLOT_CONV("__sub__", numbers->nb_subtract, -2, JWRAPPER_BINARYFUNC_L);
9388-
ADD_SLOT_CONV("__rsub__", numbers->nb_subtract, -2, JWRAPPER_BINARYFUNC_R);
9389-
ADD_SLOT_CONV("__mul__", numbers->nb_multiply, -2, JWRAPPER_BINARYFUNC_L);
9390-
ADD_SLOT_CONV("__rmul__", numbers->nb_multiply, -2, JWRAPPER_BINARYFUNC_R);
9391-
ADD_SLOT_CONV("__mod__", numbers->nb_remainder, -2, JWRAPPER_BINARYFUNC_L);
9392-
ADD_SLOT_CONV("__rmod__", numbers->nb_remainder, -2, JWRAPPER_BINARYFUNC_R);
9393-
ADD_SLOT_CONV("__divmod__", numbers->nb_divmod, -2, JWRAPPER_BINARYFUNC_L);
9394-
ADD_SLOT_CONV("__rdivmod__", numbers->nb_divmod, -2, JWRAPPER_BINARYFUNC_R);
9395-
ADD_SLOT_CONV("__pow__", numbers->nb_power, -3, JWRAPPER_TERNARYFUNC);
9396-
ADD_SLOT_CONV("__rpow__", numbers->nb_power, -3, JWRAPPER_TERNARYFUNC_R);
9397-
ADD_SLOT_CONV("__neg__", numbers->nb_negative, -1, JWRAPPER_UNARYFUNC);
9398-
ADD_SLOT_CONV("__pos__", numbers->nb_positive, -1, JWRAPPER_UNARYFUNC);
9399-
ADD_SLOT_CONV("__abs__", numbers->nb_absolute, -1, JWRAPPER_UNARYFUNC);
9400-
ADD_SLOT_CONV("__bool__", numbers->nb_bool, -1, JWRAPPER_INQUIRY);
9401-
ADD_SLOT_CONV("__invert__", numbers->nb_invert, -1, JWRAPPER_UNARYFUNC);
9402-
ADD_SLOT_CONV("__lshift__", numbers->nb_lshift, -2, JWRAPPER_BINARYFUNC_L);
9403-
ADD_SLOT_CONV("__rlshift__", numbers->nb_lshift, -2, JWRAPPER_BINARYFUNC_R);
9404-
ADD_SLOT_CONV("__rshift__", numbers->nb_rshift, -2, JWRAPPER_BINARYFUNC_L);
9405-
ADD_SLOT_CONV("__rrshift__", numbers->nb_rshift, -2, JWRAPPER_BINARYFUNC_R);
9406-
ADD_SLOT_CONV("__and__", numbers->nb_and, -2, JWRAPPER_BINARYFUNC_L);
9407-
ADD_SLOT_CONV("__rand__", numbers->nb_and, -2, JWRAPPER_BINARYFUNC_R);
9408-
ADD_SLOT_CONV("__xor__", numbers->nb_xor, -2, JWRAPPER_BINARYFUNC_L);
9409-
ADD_SLOT_CONV("__rxor__", numbers->nb_xor, -2, JWRAPPER_BINARYFUNC_R);
9410-
ADD_SLOT_CONV("__or__", numbers->nb_or, -2, JWRAPPER_BINARYFUNC_L);
9411-
ADD_SLOT_CONV("__ror__", numbers->nb_or, -2, JWRAPPER_BINARYFUNC_R);
9412-
ADD_SLOT_CONV("__int__", numbers->nb_int, -1, JWRAPPER_UNARYFUNC);
9413-
ADD_SLOT_CONV("__float__", numbers->nb_float, -1, JWRAPPER_UNARYFUNC);
9414-
ADD_SLOT_CONV("__iadd__", numbers->nb_inplace_add, -2, JWRAPPER_BINARYFUNC);
9415-
ADD_SLOT_CONV("__isub__", numbers->nb_inplace_subtract, -2, JWRAPPER_BINARYFUNC);
9416-
ADD_SLOT_CONV("__imul__", numbers->nb_inplace_multiply, -2, JWRAPPER_BINARYFUNC);
9417-
ADD_SLOT_CONV("__imod__", numbers->nb_inplace_remainder, -2, JWRAPPER_BINARYFUNC);
9418-
ADD_SLOT_CONV("__ipow__", numbers->nb_inplace_power, -3, JWRAPPER_TERNARYFUNC);
9419-
ADD_SLOT_CONV("__ilshift__", numbers->nb_inplace_lshift, -2, JWRAPPER_BINARYFUNC);
9420-
ADD_SLOT_CONV("__irshift__", numbers->nb_inplace_rshift, -2, JWRAPPER_BINARYFUNC);
9421-
ADD_SLOT_CONV("__iand__", numbers->nb_inplace_and, -2, JWRAPPER_BINARYFUNC);
9422-
ADD_SLOT_CONV("__ixor__", numbers->nb_inplace_xor, -2, JWRAPPER_BINARYFUNC);
9423-
ADD_SLOT_CONV("__ior__", numbers->nb_inplace_or, -2, JWRAPPER_BINARYFUNC);
9424-
ADD_SLOT_CONV("__floordiv__", numbers->nb_floor_divide, -2, JWRAPPER_BINARYFUNC_L);
9425-
ADD_SLOT_CONV("__rfloordiv__", numbers->nb_floor_divide, -2, JWRAPPER_BINARYFUNC_R);
9426-
ADD_SLOT_CONV("__truediv__", numbers->nb_true_divide, -2, JWRAPPER_BINARYFUNC_L);
9427-
ADD_SLOT_CONV("__rtruediv__", numbers->nb_true_divide, -2, JWRAPPER_BINARYFUNC_R);
9428-
ADD_SLOT_CONV("__ifloordiv__", numbers->nb_inplace_floor_divide, -2, JWRAPPER_BINARYFUNC);
9429-
ADD_SLOT_CONV("__itruediv__", numbers->nb_inplace_true_divide, -2, JWRAPPER_BINARYFUNC);
9430-
ADD_SLOT_CONV("__index__", numbers->nb_index, -1, JWRAPPER_UNARYFUNC);
9431-
ADD_SLOT_CONV("__matmul__", numbers->nb_matrix_multiply, -2, JWRAPPER_BINARYFUNC_L);
9432-
ADD_SLOT_CONV("__rmatmul__", numbers->nb_matrix_multiply, -2, JWRAPPER_BINARYFUNC_R);
9433-
ADD_SLOT_CONV("__imatmul__", numbers->nb_inplace_matrix_multiply, -2, JWRAPPER_BINARYFUNC_L);
9434-
}
9435-
9436-
// 'tp_as_mapping' takes precedence over 'tp_as_sequence' !
9437-
PyMappingMethods* mappings = cls->tp_as_mapping;
9438-
if (mappings) {
9439-
ADD_SLOT_CONV("__len__", mappings->mp_length, -1, JWRAPPER_LENFUNC);
9440-
ADD_SLOT_CONV("__getitem__", mappings->mp_subscript, -2, JWRAPPER_BINARYFUNC);
9441-
ADD_SLOT_CONV("__setitem__", mappings->mp_ass_subscript, -3, JWRAPPER_OBJOBJARGPROC);
9442-
ADD_SLOT_CONV("__delitem__", mappings->mp_ass_subscript, -3, JWRAPPER_MP_DELITEM);
9443-
}
9444-
9445-
PySequenceMethods* sequences = cls->tp_as_sequence;
9446-
if (sequences) {
9447-
// sequence functions first, so that the number functions take precendence
9448-
ADD_SLOT_CONV("__len__", sequences->sq_length, -1, JWRAPPER_LENFUNC);
9449-
ADD_SLOT_CONV("__add__", sequences->sq_concat, -2, JWRAPPER_BINARYFUNC);
9450-
ADD_SLOT_CONV("__mul__", sequences->sq_repeat, -2, JWRAPPER_SSIZE_ARG);
9451-
ADD_SLOT_CONV("__rmul__", sequences->sq_repeat, -2, JWRAPPER_SSIZE_ARG);
9452-
ADD_SLOT_CONV("__getitem__", sequences->sq_item, -2, JWRAPPER_GETITEM);
9453-
ADD_SLOT_CONV("__setitem__", sequences->sq_ass_item, -3, JWRAPPER_SETITEM);
9454-
ADD_SLOT_CONV("__delitem__", sequences->sq_ass_item, -3, JWRAPPER_DELITEM);
9455-
ADD_SLOT_CONV("__contains__", sequences->sq_contains, -2, JWRAPPER_OBJOBJPROC);
9456-
ADD_SLOT_CONV("__iadd__", sequences->sq_inplace_concat, -2, JWRAPPER_BINARYFUNC);
9457-
ADD_SLOT_CONV("__imul__", sequences->sq_inplace_repeat, -2, JWRAPPER_SSIZE_ARG);
9458-
}
9459-
9460-
PyAsyncMethods* async = cls->tp_as_async;
9461-
if (async) {
9462-
ADD_SLOT_CONV("__await__", async->am_await, -1, JWRAPPER_UNARYFUNC);
9463-
ADD_SLOT_CONV("__aiter__", async->am_aiter, -1, JWRAPPER_UNARYFUNC);
9464-
ADD_SLOT_CONV("__anext__", async->am_anext, -1, JWRAPPER_UNARYFUNC);
9465-
}
9466-
9467-
PyBufferProcs* buffers = cls->tp_as_buffer;
9468-
if (buffers) {
9469-
// TODO ...
9470-
}
9471-
9472-
#undef ADD_SLOT_CONV
9473-
return 0;
9474-
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextMethodBuiltins.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApi9BuiltinNode;
5757
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
5858
import com.oracle.graal.python.builtins.objects.PNone;
59-
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.CreateFunctionNode;
59+
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes;
6060
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
6161
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
6262
import com.oracle.graal.python.nodes.HiddenAttr;
@@ -83,19 +83,18 @@ public final class PythonCextMethodBuiltins {
8383
@GenerateCached(false)
8484
abstract static class CFunctionNewExMethodNode extends Node {
8585

86-
abstract Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object cls, Object doc);
86+
abstract Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object cls, Object doc);
8787

88-
final Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object doc) {
88+
final Object execute(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object doc) {
8989
return execute(inliningTarget, methodDefPtr, name, methObj, flags, wrapper, self, module, PNone.NO_VALUE, doc);
9090
}
9191

9292
@Specialization
93-
static Object doNativeCallable(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, Object flags, int wrapper, Object self, Object module, Object cls, Object doc,
93+
static Object doNativeCallable(Node inliningTarget, Object methodDefPtr, TruffleString name, Object methObj, int flags, int wrapper, Object self, Object module, Object cls, Object doc,
9494
@Bind PythonLanguage language,
95-
@Cached CreateFunctionNode createFunctionNode,
9695
@Cached HiddenAttr.WriteNode writeHiddenAttrNode,
9796
@Cached(inline = false) WriteAttributeToPythonObjectNode writeAttrNode) {
98-
Object f = createFunctionNode.execute(inliningTarget, name, methObj, wrapper, PNone.NO_VALUE, flags);
97+
Object f = ExternalFunctionNodes.PExternalFunctionWrapper.createWrapperFunction(name, methObj, PNone.NO_VALUE, flags, wrapper, language);
9998
assert f instanceof PBuiltinFunction;
10099
PBuiltinFunction func = (PBuiltinFunction) f;
101100
writeHiddenAttrNode.execute(inliningTarget, func, METHOD_DEF_PTR, methodDefPtr);

0 commit comments

Comments
 (0)