Skip to content

Commit 34971b1

Browse files
committed
Enable multi-inheritance in 'PyType_Ready'.
1 parent 9c1d13e commit 34971b1

File tree

6 files changed

+76
-6
lines changed

6 files changed

+76
-6
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,4 +382,3 @@ int PyTruffle_Debug(void *arg) {
382382
truffle_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Debug", arg);
383383
return 0;
384384
}
385-

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ Py_ssize_t PyObject_Size(PyObject *o) {
162162
return truffle_invoke_i(PY_TRUFFLE_CEXT, "PyObject_Size", to_java(o));
163163
}
164164

165+
static int add_subclass(PyTypeObject *base, PyTypeObject *type) {
166+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Add_Subclass", to_java(base->tp_subclasses), to_java(PyLong_FromVoidPtr(type)), to_java((PyObject*)type));
167+
if (result == ERROR_MARKER) {
168+
return -1;
169+
}
170+
base->tp_subclasses = to_sulong(result);
171+
return 0;
172+
}
173+
165174
int PyType_Ready(PyTypeObject* cls) {
166175
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
167176
#define ADD_METHOD(m) ADD_METHOD_OR_SLOT(m.ml_name, m.ml_meth, m.ml_flags, m.ml_doc)
@@ -205,13 +214,29 @@ int PyType_Ready(PyTypeObject* cls) {
205214
cls->tp_doc = "";
206215
}
207216

217+
/* Initialize tp_bases */
218+
PyObject* bases = cls->tp_bases;
219+
if (bases == NULL) {
220+
if (base == NULL) {
221+
bases = PyTuple_New(0);
222+
} else {
223+
bases = PyTuple_Pack(1, base);
224+
}
225+
if (bases == NULL) {
226+
cls->tp_flags &= ~Py_TPFLAGS_READYING;
227+
return -1;
228+
}
229+
cls->tp_bases = bases;
230+
}
231+
232+
208233
PyTypeObject* javacls = truffle_invoke(PY_TRUFFLE_CEXT,
209234
"PyType_Ready",
210235
// no conversion of cls here, because we
211236
// store this into the PyTypeObject
212237
cls,
213238
to_java_type(metaclass),
214-
to_java_type(base),
239+
to_java(bases),
215240
truffle_read_string(cls->tp_name),
216241
truffle_read_string(cls->tp_doc ? cls->tp_doc : ""));
217242
if (polyglot_is_value(javacls)) {
@@ -382,6 +407,18 @@ int PyType_Ready(PyTypeObject* cls) {
382407
// TODO ...
383408
}
384409

410+
/* Link into each base class's list of subclasses */
411+
bases = cls->tp_bases;
412+
Py_ssize_t n = PyTuple_GET_SIZE(bases);
413+
Py_ssize_t i;
414+
for (i = 0; i < n; i++) {
415+
PyTypeObject *b = polyglot_as__typeobject(PyTuple_GET_ITEM(bases, i));
416+
if (PyType_Check(b) && add_subclass((PyTypeObject *)b, cls) < 0) {
417+
cls->tp_flags &= ~Py_TPFLAGS_READYING;
418+
return -1;
419+
}
420+
}
421+
385422
// done
386423
cls->tp_flags = cls->tp_flags & ~Py_TPFLAGS_READYING;
387424
cls->tp_flags = cls->tp_flags | Py_TPFLAGS_READY;

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,15 +493,21 @@ abstract static class PyType_ReadyNode extends PythonBuiltinNode {
493493
@Child WriteAttributeToObjectNode writeNode = WriteAttributeToObjectNode.create();
494494

495495
@Specialization
496-
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PythonClass baseClass, String name, String doc) {
497-
PythonClass cclass = factory().createNativeClassWrapper(typestruct, metaClass, name, new PythonClass[]{baseClass});
496+
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PTuple baseClasses, String name, String doc) {
497+
Object[] array = baseClasses.getArray();
498+
PythonClass[] bases = new PythonClass[array.length];
499+
for (int i = 0; i < array.length; i++) {
500+
bases[i] = (PythonClass) array[i];
501+
}
502+
503+
PythonClass cclass = factory().createNativeClassWrapper(typestruct, metaClass, name, bases);
498504
writeNode.execute(cclass, SpecialAttributeNames.__DOC__, doc);
499505
return cclass;
500506
}
501507

502508
@Specialization
503-
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PythonClass baseClass, PString name, PString doc) {
504-
return run(typestruct, metaClass, baseClass, name.getValue(), doc.getValue());
509+
PythonClass run(TruffleObject typestruct, PythonClass metaClass, PTuple baseClasses, PString name, PString doc) {
510+
return run(typestruct, metaClass, baseClasses, name.getValue(), doc.getValue());
505511
}
506512
}
507513

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public abstract class NativeMemberNames {
5050
public static final String TP_AS_NUMBER = "tp_as_number";
5151
public static final String TP_HASH = "tp_hash";
5252
public static final String TP_RICHCOMPARE = "tp_richcompare";
53+
public static final String TP_SUBCLASSES = "tp_subclasses";
5354
public static final String _BASE = "_base";
5455
public static final String OB_ITEM = "ob_item";
5556
public static final String MA_USED = "ma_used";
@@ -76,6 +77,7 @@ public static boolean isValid(String key) {
7677
case TP_AS_NUMBER:
7778
case TP_HASH:
7879
case TP_RICHCOMPARE:
80+
case TP_SUBCLASSES:
7981
case _BASE:
8082
case OB_ITEM:
8183
case MA_USED:

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import com.oracle.graal.python.runtime.sequence.PSequence;
6666
import com.oracle.truffle.api.CompilerDirectives;
6767
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
68+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6869
import com.oracle.truffle.api.dsl.Cached;
6970
import com.oracle.truffle.api.dsl.Fallback;
7071
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -205,6 +206,12 @@ Object doTpRichcompare(PythonClass object, @SuppressWarnings("unused") String ke
205206
return getToSulongNode().execute(getCmpNode.execute(object, SpecialMethodNames.RICHCMP));
206207
}
207208

209+
@Specialization(guards = "eq(TP_SUBCLASSES, key)")
210+
Object doTpSubclasses(@SuppressWarnings("unused") PythonClass object, @SuppressWarnings("unused") String key) {
211+
// TODO create dict view on subclasses set
212+
return PythonObjectNativeWrapper.wrap(factory().createDict());
213+
}
214+
208215
@Specialization(guards = "eq(OB_ITEM, key)")
209216
Object doObItem(PSequence object, @SuppressWarnings("unused") String key) {
210217
return new PySequenceArrayWrapper(object);
@@ -302,6 +309,17 @@ long doTpFlags(PythonClass object, @SuppressWarnings("unused") String key, long
302309
return flags;
303310
}
304311

312+
@Specialization(guards = "eq(TP_SUBCLASSES, key)")
313+
@TruffleBoundary
314+
Object doTpSubclasses(PythonClass object, @SuppressWarnings("unused") String key, PythonObjectNativeWrapper value) {
315+
// TODO more type checking; do fast path
316+
PDict dict = (PDict) value.getPythonObject();
317+
for (Object item : dict.items()) {
318+
object.getSubClasses().add((PythonClass) item);
319+
}
320+
return value;
321+
}
322+
305323
@Fallback
306324
Object doGeneric(Object object, Object key, @SuppressWarnings("unused") Object value) {
307325
CompilerDirectives.transferToInterpreter();

graalpython/lib-graalpython/python_cext.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,14 @@ def PyType_IsSubtype(a, b):
684684
return b in a.mro()
685685

686686

687+
@may_raise
688+
def PyTruffle_Add_Subclass(bases_dict, key, cls):
689+
if not bases_dict:
690+
bases_dict = dict()
691+
bases_dict[key] = cls
692+
return bases_dict
693+
694+
687695
def PyTuple_New(size):
688696
return (None,) * size
689697

0 commit comments

Comments
 (0)