Skip to content

Commit 1360fc8

Browse files
committed
use PyType_FastSubclass for some type checks
1 parent 6deab92 commit 1360fc8

7 files changed

Lines changed: 50 additions & 14 deletions

File tree

src/embed_tests/TestRuntime.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,23 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
130130

131131
Runtime.Runtime.Py_Finalize();
132132
}
133+
134+
[Test]
135+
public static void PyType_Check_Sanity()
136+
{
137+
Runtime.Runtime.Py_Initialize();
138+
var builtins = Runtime.Runtime.GetBuiltins();
139+
var obj = Runtime.Runtime.PyObject_GetAttrString(builtins, "object");
140+
var t = Runtime.Runtime.PyObject_GetAttrString(builtins, "True");
141+
var none = Runtime.Runtime.PyObject_GetAttrString(builtins, "None");
142+
var noneType = Runtime.Runtime.PyObject_TYPE(none);
143+
var type = Runtime.Runtime.PyObject_TYPE(noneType);
144+
145+
Assert.IsTrue(Runtime.Runtime.PyType_Check(new BorrowedReference(obj)));
146+
Assert.IsTrue(Runtime.Runtime.PyType_Check(new BorrowedReference(type)));
147+
Assert.IsFalse(Runtime.Runtime.PyType_Check(new BorrowedReference(t)));
148+
149+
Runtime.Runtime.Py_Finalize();
150+
}
133151
}
134152
}

src/runtime/classbase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public static void tp_dealloc(IntPtr ob)
293293
{
294294
var reference = new BorrowedReference(ob);
295295
var self = GetManagedObject(reference, ObjectOffset.ReflectedObjectGCHandle(reference));
296-
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.tpHandle));
296+
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.Type));
297297
if (dict != IntPtr.Zero)
298298
{
299299
Runtime.XDecref(dict);

src/runtime/classderived.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ public static void Finalize(IPythonDerivedType obj)
877877
// the C# object is being destroyed which must mean there are no more
878878
// references to the Python object as well so now we can dealloc the
879879
// python object.
880-
IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.tpHandle));
880+
IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.Type));
881881
if (dict != IntPtr.Zero)
882882
{
883883
Runtime.XDecref(dict);

src/runtime/interop.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,24 +111,33 @@ internal static void ClrGcHandleOffsetAssertSanity(int offset)
111111
/// <summary>
112112
/// Returns dict offset in instances of the specified <paramref name="type"/>
113113
/// </summary>
114-
public static int TypeDictOffset(BorrowedReference type)
115-
=> TypeDictOffset(type.DangerousGetAddress());
116-
public static int TypeDictOffset(IntPtr type) {
117-
Debug.Assert(Runtime.PyType_Check(type));
118-
return Runtime.PyType_IsSubtype(type, Exceptions.BaseException)
114+
public static int TypeDictOffset(BorrowedReference type) {
115+
if (!Runtime.PyType_Check(type))
116+
throw new ArgumentException("Bad object type");
117+
118+
return IsExceptionSubtype(type)
119119
? ExceptionOffset.ob_dict
120120
: ob_dict;
121121
}
122+
public static int TypeDictOffset(IntPtr type)
123+
=> TypeDictOffset(new BorrowedReference(type));
122124

123125
public static int Size(IntPtr ob) {
124126
if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
125-
(Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) {
127+
(Runtime.PyType_Check(new BorrowedReference(ob)) && IsExceptionSubtype(new BorrowedReference(ob))))) {
126128
return ExceptionOffset.Size();
127129
}
128130

129131
return PyObject_HEAD_Size();
130132
}
131133

134+
static bool IsExceptionSubtype(BorrowedReference type)
135+
{
136+
bool isException = Runtime.PyType_FastSubclass(type, TypeFlags.BaseExceptionSubclass);
137+
Debug.Assert(Runtime.PyType_IsSubtype(type.DangerousGetAddress(), Exceptions.BaseException) == isException);
138+
return isException;
139+
}
140+
132141
public static int PyObject_HEAD_Size() {
133142
#if PYTHON_WITH_PYDEBUG
134143
return 6 * IntPtr.Size;

src/runtime/moduleobject.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public ModuleObject(string name)
5454
Runtime.XDecref(pyfilename);
5555
Runtime.XDecref(pydocstring);
5656

57-
Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(tpHandle), dict);
57+
Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(Type), dict);
5858

5959
InitializeModuleMembers();
6060
}

src/runtime/pytype.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static bool IsTypeType(PyObject obj) {
3434
throw new ArgumentNullException(nameof(obj));
3535
}
3636

37-
return Runtime.PyType_Check(obj.Handle);
37+
return Runtime.PyType_Check(obj.Reference);
3838
}
3939

4040
/// <summary>
@@ -45,7 +45,7 @@ public static bool IsTypeType(IntPtr typeHandle) {
4545
throw new ArgumentNullException(nameof(typeHandle));
4646
}
4747

48-
return Runtime.PyType_Check(typeHandle);
48+
return Runtime.PyType_Check(new BorrowedReference(typeHandle));
4949
}
5050

5151
/// <summary>

src/runtime/runtime.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects)
595595

596596
for (var i = 0; i < n; i++)
597597
{
598-
IntPtr op = PyTuple_GetItem(args, i);
598+
var op = new BorrowedReference(PyTuple_GetItem(args, i));
599599
if (mangleObjects && (!PyType_Check(op)))
600600
{
601601
op = PyObject_TYPE(op);
@@ -1802,9 +1802,18 @@ int updatepath
18021802
// Python type object API
18031803
//====================================================================
18041804

1805-
internal static bool PyType_Check(IntPtr ob)
1805+
internal static bool PyType_Check(BorrowedReference ob)
18061806
{
1807-
return PyObject_TypeCheck(ob, PyTypeType);
1807+
// fast path using raw memory access
1808+
BorrowedReference type = PyObject_TYPE(ob);
1809+
if (type == PyTypeType) return true;
1810+
return PyType_FastSubclass(type, TypeFlags.TypeSubclass);
1811+
}
1812+
1813+
internal static bool PyType_FastSubclass(BorrowedReference type, TypeFlags baseType)
1814+
{
1815+
var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags);
1816+
return (flags & baseType) != 0;
18081817
}
18091818

18101819
internal static void PyType_Modified(IntPtr type) => Delegates.PyType_Modified(type);

0 commit comments

Comments
 (0)