Skip to content

Commit ccbb044

Browse files
committed
Split PyTruffle_Type_Modified
1 parent 59d816e commit ccbb044

File tree

3 files changed

+57
-43
lines changed

3 files changed

+57
-43
lines changed

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

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,17 +303,50 @@ _PyTypes_Fini(PyInterpreterState *interp)
303303
clear_slotdefs();
304304
}
305305
}
306-
#endif // GraalPy change
307306

308307

309308
void
310309
PyType_Modified(PyTypeObject *type)
311310
{
312-
// GraalPy change: different implementation
313-
GraalPyTruffle_Type_Modified(type, type->tp_name, type->tp_mro);
311+
/* Invalidate any cached data for the specified type and all
312+
subclasses. This function is called after the base
313+
classes, mro, or attributes of the type are altered.
314+
315+
Invariants:
316+
317+
- before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type,
318+
it must first be set on all super types.
319+
320+
This function clears the Py_TPFLAGS_VALID_VERSION_TAG of a
321+
type (so it must first clear it on all subclasses). The
322+
tp_version_tag value is meaningless unless this flag is set.
323+
We don't assign new version tags eagerly, but only as
324+
needed.
325+
*/
326+
if (!_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) {
327+
return;
328+
}
329+
330+
PyObject *subclasses = type->tp_subclasses;
331+
if (subclasses != NULL) {
332+
assert(PyDict_CheckExact(subclasses));
333+
334+
Py_ssize_t i = 0;
335+
PyObject *ref;
336+
while (PyDict_Next(subclasses, &i, NULL, &ref)) {
337+
assert(PyWeakref_CheckRef(ref));
338+
PyObject *obj = PyWeakref_GET_OBJECT(ref);
339+
if (obj == Py_None) {
340+
continue;
341+
}
342+
PyType_Modified(_PyType_CAST(obj));
343+
}
344+
}
345+
346+
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
347+
type->tp_version_tag = 0; /* 0 is not a valid version tag */
314348
}
315349

316-
#if 0 // GraalPy change
317350
static void
318351
type_mro_modified(PyTypeObject *type, PyObject *bases) {
319352
/*
@@ -6555,7 +6588,7 @@ PyType_Ready(PyTypeObject *type)
65556588
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
65566589
}
65576590

6558-
/* GraalPy change: Types are often just static mem; so register them to be able to rule out invalid accesses. */
6591+
// GraalPy change
65596592
if (PyTruffle_Trace_Memory()) {
65606593
GraalPyTruffle_Trace_Type(type, type->tp_name != NULL);
65616594
}
@@ -6575,8 +6608,8 @@ PyType_Ready(PyTypeObject *type)
65756608
type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
65766609
assert(_PyType_CheckConsistency(type));
65776610

6578-
// GraalPy change: it may be that the type was used uninitialized
6579-
GraalPyTruffle_Type_Modified(type, type->tp_name, NULL);
6611+
// GraalPy change
6612+
GraalPyTruffle_InitializeOldStyleSlots(type);
65806613

65816614
// GraalPy change: for reason, see first call to Py_INCREF in this function
65826615
Py_DECREF(type);

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

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode;
6464
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
6565
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath;
66-
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiTernaryBuiltinNode;
6766
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
6867
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.PyObjectSetAttrNode;
6968
import com.oracle.graal.python.builtins.objects.PNone;
@@ -78,6 +77,7 @@
7877
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.GetterRoot;
7978
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;
8079
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.SetterRoot;
80+
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor;
8181
import com.oracle.graal.python.builtins.objects.cext.common.CArrayWrappers.CArrayWrapper;
8282
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.EnsureExecutableNode;
8383
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
@@ -89,7 +89,6 @@
8989
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
9090
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptor;
9191
import com.oracle.graal.python.builtins.objects.object.PythonObject;
92-
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9392
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
9493
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
9594
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
@@ -106,7 +105,6 @@
106105
import com.oracle.graal.python.runtime.PythonContext;
107106
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
108107
import com.oracle.graal.python.runtime.sequence.storage.MroSequenceStorage;
109-
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
110108
import com.oracle.graal.python.util.Function;
111109
import com.oracle.graal.python.util.PythonUtils;
112110
import com.oracle.truffle.api.CompilerDirectives;
@@ -217,51 +215,35 @@ static PDict doGeneric(PythonNativeClass nativeClass) {
217215
}
218216
}
219217

220-
@CApiBuiltin(ret = Int, args = {PyTypeObject, ConstCharPtrAsTruffleString, PyObject}, call = Ignored)
221-
abstract static class PyTruffle_Type_Modified extends CApiTernaryBuiltinNode {
218+
@CApiBuiltin(ret = ArgDescriptor.Void, args = {PyTypeObject}, call = Ignored)
219+
abstract static class PyTruffle_InitializeOldStyleSlots extends CApiUnaryBuiltinNode {
222220

223221
@TruffleBoundary
224-
@Specialization(guards = "isNoValue(mroTuple)")
225-
static int doIt(PythonAbstractNativeObject clazz, TruffleString name, @SuppressWarnings("unused") PNone mroTuple,
222+
@Specialization
223+
static Object doIt(PythonAbstractNativeObject clazz,
226224
@Bind("this") Node inliningTarget) {
227-
PythonContext context = PythonContext.get(inliningTarget);
228-
CyclicAssumption nativeClassStableAssumption = context.getNativeClassStableAssumption(clazz, false);
229-
if (nativeClassStableAssumption != null) {
230-
nativeClassStableAssumption.invalidate("PyType_Modified(\"" + name.toJavaStringUncached() + "\") (without MRO) called");
231-
}
232-
SpecialMethodSlot.reinitializeSpecialMethodSlots(clazz, context.getLanguage());
233-
// TODO: this is called from two places: at the end of PyType_Ready, and theoretically
234-
// could be called from:
235-
//
236-
// void PyType_Modified(PyTypeObject* type) -> GraalPyTruffle_Type_Modified(type,
237-
// type->tp_name, type->tp_mro);
238-
//
239-
// in unlikely (impossible?) case that type->tp_mro was NULL. Should we distinguish
240-
// the two cases? As a cleanup if it is impossible situation (separate two different
241-
// upcalls), or because at the end of PyType_Ready, we do not want to call
242-
// TpSlots.updateAllSlots(clazz), but from PyType_Modified we do.
243-
return 0;
225+
SpecialMethodSlot.reinitializeSpecialMethodSlots(clazz, PythonLanguage.get(inliningTarget));
226+
return PNone.NO_VALUE;
244227
}
228+
}
229+
230+
@CApiBuiltin(ret = ArgDescriptor.Void, args = {PyTypeObject}, call = Direct)
231+
abstract static class PyType_Modified extends CApiUnaryBuiltinNode {
245232

246233
@TruffleBoundary
247234
@Specialization
248-
static int doIt(PythonAbstractNativeObject clazz, TruffleString name, PTuple mroTuple,
235+
static Object doIt(PythonAbstractNativeObject clazz,
249236
@Bind("this") Node inliningTarget) {
250237
PythonContext context = PythonContext.get(inliningTarget);
251238
CyclicAssumption nativeClassStableAssumption = context.getNativeClassStableAssumption(clazz, false);
252239
if (nativeClassStableAssumption != null) {
253-
nativeClassStableAssumption.invalidate("PyType_Modified(\"" + name.toJavaStringUncached() + "\") called");
240+
nativeClassStableAssumption.invalidate("PyType_Modified(\"" + TypeNodes.GetNameNode.executeUncached(clazz).toJavaStringUncached() + "\") called");
254241
}
255-
SequenceStorage sequenceStorage = mroTuple.getSequenceStorage();
256-
if (sequenceStorage instanceof MroSequenceStorage) {
257-
((MroSequenceStorage) sequenceStorage).lookupChanged();
258-
} else {
259-
CompilerDirectives.transferToInterpreterAndInvalidate();
260-
throw new IllegalStateException("invalid MRO object for native type \"" + name.toJavaStringUncached() + "\"");
261-
}
262-
SpecialMethodSlot.reinitializeSpecialMethodSlots(PythonNativeClass.cast(clazz), context.getLanguage());
242+
MroSequenceStorage mroStorage = TypeNodes.GetMroStorageNode.executeUncached(clazz);
243+
mroStorage.lookupChanged();
244+
// Reload slots from native, which also invalidates cached slot lookups
263245
clazz.setTpSlots(TpSlots.fromNative(clazz, context));
264-
return 0;
246+
return PNone.NO_VALUE;
265247
}
266248
}
267249

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,6 @@ public final class CApiFunction {
482482
@CApiBuiltin(name = "PyType_GetQualName", ret = PyObject, args = {PyTypeObject}, call = CImpl)
483483
@CApiBuiltin(name = "PyType_GetSlot", ret = Pointer, args = {PyTypeObject, Int}, call = CImpl)
484484
@CApiBuiltin(name = "PyType_IsSubtype", ret = Int, args = {PyTypeObject, PyTypeObject}, call = CImpl)
485-
@CApiBuiltin(name = "PyType_Modified", ret = Void, args = {PyTypeObject}, call = CImpl)
486485
@CApiBuiltin(name = "PyType_Ready", ret = Int, args = {PyTypeObject}, call = CImpl)
487486
@CApiBuiltin(name = "PyUnicode_Append", ret = Void, args = {PyObjectPtr, PyObject}, call = CImpl)
488487
@CApiBuiltin(name = "PyUnicode_AppendAndDel", ret = Void, args = {PyObjectPtr, PyObject}, call = CImpl)

0 commit comments

Comments
 (0)