Skip to content

Commit c6e2bf8

Browse files
committed
[GR-47961][GR-47946] Fix inheriting tp_basicsize and tp_new
2 parents 860d127 + 780805d commit c6e2bf8

File tree

17 files changed

+573
-415
lines changed

17 files changed

+573
-415
lines changed

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

Lines changed: 121 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def test_inheret_numbers_slots(self):
231231
}
232232
233233
static PyObject* B_has_add_slot(PyObject* cls) {
234-
return (&B_Type)->tp_as_number != NULL && (&B_Type)->tp_as_number->nb_add != NULL ? Py_True : Py_False;
234+
return Py_NewRef((&B_Type)->tp_as_number != NULL && (&B_Type)->tp_as_number->nb_add != NULL ? Py_True : Py_False);
235235
}
236236
237237
''',
@@ -282,7 +282,7 @@ def test_inheret_numbers_slots(self):
282282
}
283283
284284
static PyObject* E_has_add_slot(PyObject* cls) {
285-
return (&E_Type)->tp_as_number != NULL && (&E_Type)->tp_as_number->nb_add != NULL ? Py_True : Py_False;
285+
return Py_NewRef((&E_Type)->tp_as_number != NULL && (&E_Type)->tp_as_number->nb_add != NULL ? Py_True : Py_False);
286286
}
287287
''',
288288
tp_methods='''{"create_E", (PyCFunction)create_E, METH_NOARGS | METH_CLASS, ""},
@@ -668,7 +668,7 @@ def ignore_test_float_subclass(self):
668668
return new_fp(PyLong_AsLong(l) + PyLong_AsLong(r));
669669
}
670670
}
671-
return Py_NotImplemented;
671+
return Py_NewRef(Py_NotImplemented);
672672
}
673673
""",
674674
cmembers="PyFloatObject base;",
@@ -716,42 +716,146 @@ def test_custom_basicsize(self):
716716
'''
717717
Py_ssize_t global_basicsize = -1;
718718
719-
static PyObject* get_basicsize(PyObject* self, PyObject* is_graalpython) {
720-
// The basicsize will be the struct's size plus a pointer to the object's dict and weaklist.
721-
// Graalpython does currently not implement the weaklist, so do not add in this case.
722-
if (PyObject_IsTrue(is_graalpython)) {
723-
return PyLong_FromSsize_t(global_basicsize + sizeof(PyObject*));
724-
} else {
725-
return PyLong_FromSsize_t(global_basicsize + 2 * sizeof(PyObject*));
726-
}
719+
static PyObject* get_basicsize(PyObject* self, PyObject* ignored) {
720+
return PyLong_FromSsize_t(global_basicsize + 2 * sizeof(PyObject*));
727721
}
728722
''',
729723
cmembers='''long long field0;
730724
int field1;
731725
''',
732-
tp_methods='{"get_basicsize", (PyCFunction)get_basicsize, METH_O, ""}',
726+
tp_methods='{"get_basicsize", (PyCFunction)get_basicsize, METH_NOARGS, ""}',
733727
post_ready_code="global_basicsize = TestCustomBasicsizeType.tp_basicsize;"
734728
)
735729
class TestCustomBasicsizeSubclass(TestCustomBasicsize):
736730
pass
737731

738732
obj = TestCustomBasicsizeSubclass()
739733

740-
# TODO pass False as soon as we implement 'tp_weaklistoffset'
741-
expected_basicsize = obj.get_basicsize(GRAALPYTHON)
734+
expected_basicsize = obj.get_basicsize()
742735
actual_basicsize = TestCustomBasicsizeSubclass.__basicsize__
743736
assert expected_basicsize == actual_basicsize, "expected = %s, actual = %s" % (expected_basicsize, actual_basicsize)
744737

738+
def test_tp_basicsize(self):
739+
TpBasicsize1Type = CPyExtType("TpBasicsize1",
740+
'''
741+
int vv = 0;
742+
743+
static PyObject* set_values(PyObject* oself) {
744+
TpBasicsize1Object * self = (TpBasicsize1Object *) oself;
745+
for (int i = 0; i < 20; i++) {
746+
self->f[i] = vv++;
747+
}
748+
Py_RETURN_NONE;
749+
}
750+
static PyObject* get_values(PyObject* self, PyObject* idx) {
751+
int i = (int)PyNumber_AsSsize_t(idx, NULL);
752+
return PyLong_FromLong(((TpBasicsize1Object *) self)->f[i]);
753+
}
754+
''',
755+
tp_methods='''
756+
{"set_values", (PyCFunction)set_values, METH_NOARGS, NULL},
757+
{"get_value", (PyCFunction)get_values, METH_O, NULL}
758+
''',
759+
cmembers='Py_ssize_t f[20];',
760+
)
761+
762+
TpBasicsize2Type = CPyExtType("TpBasicsize2",
763+
'''
764+
int vvv = 0;
765+
766+
static PyObject* set_values(PyObject* oself) {
767+
TpBasicsize2Object * self = (TpBasicsize2Object *) oself;
768+
for (int i = 0; i < 10; i++) {
769+
self->f[i] = vvv++;
770+
}
771+
Py_RETURN_NONE;
772+
}
773+
static PyObject* get_values(PyObject* self, PyObject* idx) {
774+
int i = (int)PyNumber_AsSsize_t(idx, NULL);
775+
return PyLong_FromLong(((TpBasicsize2Object *) self)->f[i]);
776+
}
777+
''',
778+
tp_methods='''
779+
{"set_values", (PyCFunction)set_values, METH_NOARGS, NULL},
780+
{"get_value", (PyCFunction)get_values, METH_O, NULL}
781+
''',
782+
cmembers='Py_ssize_t f[10];',
783+
)
784+
785+
TpBasicsize3Type = CPyExtType("TpBasicsize3",
786+
'''
787+
''',
788+
cmembers='',
789+
)
790+
791+
try:
792+
class Foo(TpBasicsize2Type, TpBasicsize1Type):
793+
pass
794+
except TypeError:
795+
pass
796+
else:
797+
assert False, "should raise: TypeError: multiple bases have instance lay-out conflict"
798+
799+
class Foo(TpBasicsize3Type, TpBasicsize1Type):
800+
pass
801+
802+
assert Foo.__base__ == TpBasicsize1Type
803+
assert Foo.__basicsize__ == 192, "Foo.__basicsize__ %d != 192" % Foo.__basicsize__
804+
objs = [Foo() for i in range(5)]
805+
for foo in objs:
806+
foo.set_values()
807+
vv = 0
808+
for foo in objs:
809+
for i in range(20):
810+
assert foo.get_value(i) == vv
811+
vv += 1
812+
813+
class Foo(TpBasicsize2Type, TpBasicsize3Type):
814+
pass
815+
816+
assert Foo.__base__ == TpBasicsize2Type
817+
assert Foo.__basicsize__ == 112, "Foo.__basicsize__ %d != 112" % Foo.__basicsize__
818+
objs = [Foo() for i in range(5)]
819+
for foo in objs:
820+
foo.set_values()
821+
vvv = 0
822+
for foo in objs:
823+
for i in range(10):
824+
assert foo.get_value(i) == vvv, "Failed"
825+
vvv += 1
826+
827+
def test_new_inherited_from_dominant_base(self):
828+
DominantBase = CPyExtType(
829+
'DominantBase',
830+
'''
831+
PyObject* base_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
832+
return Py_NewRef(Py_Ellipsis);
833+
}
834+
''',
835+
cmembers='int foo; int bar;',
836+
tp_new='base_new',
837+
)
838+
assert DominantBase() is Ellipsis
839+
840+
WeakBase = CPyExtType('WeakBase')
841+
842+
class Subclass(WeakBase, DominantBase):
843+
pass
844+
845+
# In CPython 3.10, Subclass.__new__ is WeakBase.__new__, but Subclass.tp_new is DominantBase.tp_new
846+
847+
assert Subclass() is Ellipsis
848+
745849
def test_descrget(self):
746850
TestDescrGet = CPyExtType(
747851
"TestDescrGet",
748852
'''
749853
PyObject* testdescr_get(PyObject* self, PyObject* obj, PyObject* type) {
750854
if (obj == NULL) {
751-
obj = Py_Ellipsis;
855+
obj = Py_NewRef(Py_Ellipsis);
752856
}
753857
if (type == NULL) {
754-
type = Py_Ellipsis;
858+
type = Py_NewRef(Py_Ellipsis);
755859
}
756860
return Py_BuildValue("OOO", self, obj, type);
757861
}
@@ -1248,7 +1352,7 @@ def compile_module(self, name):
12481352
// this will free the tuple
12491353
Py_DECREF(object);
12501354
1251-
return Py_None;
1355+
Py_RETURN_NONE;
12521356
}
12531357
''',
12541358
arguments=["PyObject* element"],

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -335,25 +335,25 @@ public enum PythonBuiltinClassType implements TruffleObject {
335335
AST("AST", "_ast", "ast", Flags.PUBLIC_BASE_WDICT),
336336

337337
// _ctype
338-
CArgObject("CArgObject", Flags.PUBLIC_BASE_WDICT),
339-
CThunkObject("CThunkObject", J__CTYPES, Flags.PUBLIC_BASE_WDICT),
338+
CArgObject("CArgObject", Flags.PUBLIC_BASE_WODICT),
339+
CThunkObject("CThunkObject", J__CTYPES, Flags.PUBLIC_BASE_WODICT),
340340
StgDict("StgDict", Flags.PRIVATE_DERIVED_WODICT, DICT_M_FLAGS),
341-
PyCStructType("PyCStructType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCSTRUCTTYPE_M_FLAGS),
342-
UnionType("UnionType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, UNIONTYPE_M_FLAGS),
343-
PyCPointerType("PyCPointerType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCPOINTERTYPE_M_FLAGS),
344-
PyCArrayType("PyCArrayType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCARRAYTYPE_M_FLAGS),
345-
PyCSimpleType("PyCSimpleType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCSIMPLETYPE_M_FLAGS),
346-
PyCFuncPtrType("PyCFuncPtrType", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCFUNCPTRTYPE_M_FLAGS),
347-
Structure("Structure", J__CTYPES, Flags.PUBLIC_BASE_WDICT), /*- type = PyCStructType */
348-
Union("Union", J__CTYPES, Flags.PUBLIC_BASE_WDICT), /*- type = UnionType */
349-
PyCPointer("_Pointer", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCPOINTER_M_FLAGS), /*- type = PyCPointerType */
350-
PyCArray("Array", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCARRAY_M_FLAGS), /*- type = PyCArrayType */
351-
PyCData("_CData", J__CTYPES, Flags.PUBLIC_BASE_WDICT), /*- type = PyCStructType */
352-
SimpleCData("_SimpleCData", J__CTYPES, Flags.PUBLIC_BASE_WDICT, SIMPLECDATA_M_FLAGS), /*- type = PyCStructType */
353-
PyCFuncPtr("PyCFuncPtr", J__CTYPES, Flags.PUBLIC_BASE_WDICT, PYCFUNCPTR_M_FLAGS), /*- type = PyCFuncPtrType */
354-
CField("CField", J__CTYPES, Flags.PUBLIC_BASE_WDICT),
355-
DictRemover("DictRemover", J__CTYPES, Flags.PUBLIC_BASE_WDICT),
356-
StructParam("StructParam_Type", J__CTYPES, Flags.PUBLIC_BASE_WDICT),
341+
PyCStructType("PyCStructType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSTRUCTTYPE_M_FLAGS),
342+
UnionType("UnionType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, UNIONTYPE_M_FLAGS),
343+
PyCPointerType("PyCPointerType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCPOINTERTYPE_M_FLAGS),
344+
PyCArrayType("PyCArrayType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCARRAYTYPE_M_FLAGS),
345+
PyCSimpleType("PyCSimpleType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCSIMPLETYPE_M_FLAGS),
346+
PyCFuncPtrType("PyCFuncPtrType", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCFUNCPTRTYPE_M_FLAGS),
347+
Structure("Structure", J__CTYPES, Flags.PUBLIC_BASE_WODICT), /*- type = PyCStructType */
348+
Union("Union", J__CTYPES, Flags.PUBLIC_BASE_WODICT), /*- type = UnionType */
349+
PyCPointer("_Pointer", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCPOINTER_M_FLAGS), /*- type = PyCPointerType */
350+
PyCArray("Array", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCARRAY_M_FLAGS), /*- type = PyCArrayType */
351+
PyCData("_CData", J__CTYPES, Flags.PUBLIC_BASE_WODICT), /*- type = PyCStructType */
352+
SimpleCData("_SimpleCData", J__CTYPES, Flags.PUBLIC_BASE_WODICT, SIMPLECDATA_M_FLAGS), /*- type = PyCStructType */
353+
PyCFuncPtr("PyCFuncPtr", J__CTYPES, Flags.PUBLIC_BASE_WODICT, PYCFUNCPTR_M_FLAGS), /*- type = PyCFuncPtrType */
354+
CField("CField", J__CTYPES, Flags.PUBLIC_BASE_WODICT),
355+
DictRemover("DictRemover", J__CTYPES, Flags.PUBLIC_BASE_WODICT),
356+
StructParam("StructParam_Type", J__CTYPES, Flags.PUBLIC_BASE_WODICT),
357357
ArgError("ArgumentError", J__CTYPES, Flags.EXCEPTION),
358358

359359
// _multibytecodec

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
8282
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
8383
import com.oracle.graal.python.builtins.objects.type.PythonClass;
84-
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetSuperClassNode;
84+
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassNode;
8585
import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs;
8686
import com.oracle.graal.python.lib.PyObjectGetAttr;
8787
import com.oracle.graal.python.lib.PyObjectStrAsTruffleStringNode;
@@ -167,7 +167,7 @@ private static PythonClass initClass(TruffleString className, TruffleString supe
167167

168168
private static PythonClass initClass(TruffleString className, PythonAbstractClass superClass, BuiltinDescr[] descrs, PythonModule codecsTruffleModule, PythonLanguage language,
169169
PythonObjectFactory factory) {
170-
PythonClass clazz = factory.createPythonClassAndFixupSlots(language, PythonBuiltinClassType.PythonClass, className, new PythonAbstractClass[]{superClass});
170+
PythonClass clazz = factory.createPythonClassAndFixupSlots(language, PythonBuiltinClassType.PythonClass, className, superClass, new PythonAbstractClass[]{superClass});
171171
for (BuiltinDescr d : descrs) {
172172
PythonUtils.createMethod(language, clazz, d.nodeClass, d.enclosingType ? clazz : null, 1, d.nodeSupplier, factory);
173173
}
@@ -328,11 +328,11 @@ Object init(VirtualFrame frame, PythonObject self, Object[] args, PKeyword[] kw,
328328
@Cached PyObjectGetAttr getAttrNode,
329329
@Cached("createSetAttr()") SetAttributeNode setAttrNode,
330330
@Cached GetPythonObjectClassNode getClass,
331-
@Cached GetSuperClassNode getSuperClassNode,
331+
@Cached GetBaseClassNode getBaseClassNode,
332332
@Cached CallNode callNode) {
333333
assert args.length > 0;
334-
Object superClass = getSuperClassNode.execute(inliningTarget, getClass.execute(inliningTarget, self));
335-
Object superInit = getAttrNode.execute(frame, inliningTarget, superClass, T___INIT__);
334+
Object base = getBaseClassNode.execute(inliningTarget, getClass.execute(inliningTarget, self));
335+
Object superInit = getAttrNode.execute(frame, inliningTarget, base, T___INIT__);
336336
Object[] callArgs = new Object[args.length];
337337
callArgs[0] = self;
338338
if (args.length > 1) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstTypeFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -74,7 +74,7 @@ final class AstTypeFactory {
7474
}
7575

7676
PythonClass makeType(TruffleString name, PythonAbstractClass base, TruffleString[] fields, TruffleString[] attributes, TruffleString[] optional, TruffleString docString) {
77-
PythonClass newType = factory.createPythonClassAndFixupSlots(language, PythonBuiltinClassType.PythonClass, name, new PythonAbstractClass[]{base});
77+
PythonClass newType = factory.createPythonClassAndFixupSlots(language, PythonBuiltinClassType.PythonClass, name, base, new PythonAbstractClass[]{base});
7878
newType.setAttribute(T___MODULE__, T_AST);
7979
newType.setAttribute(T___DOC__, docString);
8080
newType.setAttribute(T__FIELDS, factory.createTuple(convertToObjectArray(fields)));

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ctypes/StructureBuiltins.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
import com.oracle.graal.python.builtins.objects.common.KeywordsStorage;
6262
import com.oracle.graal.python.builtins.objects.function.PKeyword;
6363
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassNode;
64-
import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.GetBaseClassNodeGen;
6564
import com.oracle.graal.python.lib.PyObjectGetItem;
6665
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
6766
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -201,7 +200,7 @@ int _init_pos_args_boundary(Object self, Object type, Object[] args, PKeyword[]
201200
return _init_pos_args(null, null, self, type, args, kwds, idx, setAttr,
202201
getItemNode, CastToTruffleStringNode.getUncached(),
203202
HashingStorageGetItemNodeGen.getUncached(), PyTypeStgDictNodeGen.getUncached(),
204-
GetBaseClassNodeGen.getUncached(), TruffleString.EqualNode.getUncached(), 0);
203+
GetBaseClassNode.getUncached(), TruffleString.EqualNode.getUncached(), 0);
205204
}
206205
}
207206

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
import com.oracle.graal.python.builtins.modules.io.IONodes.IOMode;
8686
import com.oracle.graal.python.builtins.objects.PNone;
8787
import com.oracle.graal.python.builtins.objects.object.PythonObject;
88+
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
8889
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
8990
import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs;
9091
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -132,7 +133,8 @@ public void initialize(Python3Core core) {
132133
addBuiltinConstant("SEEK_END", SEEK_END);
133134
addBuiltinConstant("DEFAULT_BUFFER_SIZE", DEFAULT_BUFFER_SIZE);
134135
PythonBuiltinClass unsupportedOpExcType = core.lookupType(IOUnsupportedOperation);
135-
unsupportedOpExcType.setSuperClass(core.lookupType(OSError), core.lookupType(ValueError));
136+
PythonBuiltinClass osError = core.lookupType(OSError);
137+
unsupportedOpExcType.setBases(osError, new PythonAbstractClass[]{osError, core.lookupType(ValueError)});
136138
addBuiltinConstant(IOUnsupportedOperation.getName(), unsupportedOpExcType);
137139
addBuiltinConstant(BlockingIOError.getName(), core.lookupType(BlockingIOError));
138140

0 commit comments

Comments
 (0)