Skip to content

Commit 21169db

Browse files
committed
use PyType instances instead of raw pointers in TypeManager type cache and ConstructorBinding instances
1 parent 5ded48d commit 21169db

13 files changed

+142
-157
lines changed

src/runtime/classbase.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ public static int tp_clear(IntPtr ob)
373373
protected override void OnSave(InterDomainContext context)
374374
{
375375
base.OnSave(context);
376-
if (pyHandle != tpHandle)
376+
if (!this.IsClrMetaTypeInstance())
377377
{
378378
IntPtr dict = GetObjectDict(pyHandle);
379379
Runtime.XIncref(dict);
@@ -384,7 +384,7 @@ protected override void OnSave(InterDomainContext context)
384384
protected override void OnLoad(InterDomainContext context)
385385
{
386386
base.OnLoad(context);
387-
if (pyHandle != tpHandle)
387+
if (!this.IsClrMetaTypeInstance())
388388
{
389389
IntPtr dict = context.Storage.GetValue<IntPtr>("dict");
390390
SetObjectDict(pyHandle, dict);

src/runtime/classderived.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@ internal static IntPtr ToPython(IPythonDerivedType obj)
122122
/// </summary>
123123
internal static Type CreateDerivedType(string name,
124124
Type baseType,
125-
IntPtr py_dict,
125+
BorrowedReference dictRef,
126126
string namespaceStr,
127127
string assemblyName,
128128
string moduleName = "Python.Runtime.Dynamic.dll")
129129
{
130+
// TODO: clean up
131+
IntPtr py_dict = dictRef.DangerousGetAddress();
130132
if (null != namespaceStr)
131133
{
132134
name = namespaceStr + "." + name;
@@ -824,7 +826,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec
824826
try
825827
{
826828
// create the python object
827-
IntPtr type = TypeManager.GetTypeHandle(obj.GetType());
829+
BorrowedReference type = TypeManager.GetTypeReference(obj.GetType());
828830
self = new CLRObject(obj, type);
829831

830832
// set __pyobj__ to self and deref the python object which will allow this

src/runtime/classmanager.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage)
117117
// Python object's dictionary tool; thus raising an AttributeError
118118
// instead of a TypeError.
119119
// Classes are re-initialized on in RestoreRuntimeData.
120-
var dict = new BorrowedReference(Marshal.ReadIntPtr(cls.Value.tpHandle, TypeOffset.tp_dict));
120+
using var dict = Runtime.PyObject_GenericGetDict(cls.Value.TypeReference);
121121
foreach (var member in cls.Value.dotNetMembers)
122122
{
123123
// No need to decref the member, the ClassBase instance does
@@ -135,7 +135,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage)
135135
}
136136
}
137137
// We modified the Type object, notify it we did.
138-
Runtime.PyType_Modified(cls.Value.tpHandle);
138+
Runtime.PyType_Modified(cls.Value.TypeReference);
139139
}
140140
}
141141

@@ -155,7 +155,7 @@ internal static Dictionary<ManagedType, InterDomainContext> RestoreRuntimeData(R
155155
// re-init the class
156156
InitClassBase(pair.Key.Value, pair.Value);
157157
// We modified the Type object, notify it we did.
158-
Runtime.PyType_Modified(pair.Value.tpHandle);
158+
Runtime.PyType_Modified(pair.Value.TypeReference);
159159
var context = contexts[pair.Value.pyHandle];
160160
pair.Value.Load(context);
161161
loadedObjs.Add(pair.Value, context);
@@ -266,10 +266,10 @@ private static void InitClassBase(Type type, ClassBase impl)
266266
// point to the managed methods providing the implementation.
267267

268268

269-
IntPtr tp = TypeManager.GetTypeHandle(impl, type);
269+
var pyType = TypeManager.GetType(impl, type);
270270

271271
// Finally, initialize the class __dict__ and return the object.
272-
var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict));
272+
using var dict = Runtime.PyObject_GenericGetDict(pyType.Reference);
273273

274274

275275
if (impl.dotNetMembers == null)
@@ -312,7 +312,7 @@ private static void InitClassBase(Type type, ClassBase impl)
312312
// Implement Overloads on the class object
313313
if (!CLRModule._SuppressOverloads)
314314
{
315-
var ctors = new ConstructorBinding(type, tp, co.binder);
315+
var ctors = new ConstructorBinding(type, pyType, co.binder);
316316
// ExtensionType types are untracked, so don't Incref() them.
317317
// TODO: deprecate __overloads__ soon...
318318
Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.ObjectReference);
@@ -332,7 +332,7 @@ private static void InitClassBase(Type type, ClassBase impl)
332332

333333
// The type has been modified after PyType_Ready has been called
334334
// Refresh the type
335-
Runtime.PyType_Modified(tp);
335+
Runtime.PyType_Modified(pyType.Reference);
336336
}
337337

338338
internal static bool ShouldBindMethod(MethodBase mb)

src/runtime/clrobject.cs

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ internal CLRObject(object ob, IntPtr tp)
2626
if (ob is Exception e) Exceptions.SetArgsAndCause(e, py);
2727
}
2828

29+
internal CLRObject(object ob, BorrowedReference tp) : this(ob, tp.DangerousGetAddress()) { }
30+
2931
protected CLRObject()
3032
{
3133
}

src/runtime/constructorbinding.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ namespace Python.Runtime
2323
internal class ConstructorBinding : ExtensionType
2424
{
2525
private MaybeType type; // The managed Type being wrapped in a ClassObject
26-
private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create.
26+
private PyType typeToCreate; // The python type tells GetInstHandle which Type to create.
2727
private ConstructorBinder ctorBinder;
2828

2929
[NonSerialized]
3030
private IntPtr repr;
3131

32-
public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder)
32+
public ConstructorBinding(Type type, PyType typeToCreate, ConstructorBinder ctorBinder)
3333
{
3434
this.type = type;
35-
this.pyTypeHndl = pyTypeHndl; // steal a type reference
35+
this.typeToCreate = typeToCreate;
3636
this.ctorBinder = ctorBinder;
3737
repr = IntPtr.Zero;
3838
}
@@ -110,7 +110,7 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key)
110110
{
111111
return Exceptions.RaiseTypeError("No match found for constructor signature");
112112
}
113-
var boundCtor = new BoundContructor(tp, self.pyTypeHndl, self.ctorBinder, ci);
113+
var boundCtor = new BoundContructor(tp, self.typeToCreate, self.ctorBinder, ci);
114114

115115
return boundCtor.pyHandle;
116116
}
@@ -169,7 +169,7 @@ public static int tp_clear(IntPtr ob)
169169
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
170170
{
171171
var self = (ConstructorBinding)GetManagedObject(ob);
172-
int res = PyVisit(self.pyTypeHndl, visit, arg);
172+
int res = PyVisit(self.typeToCreate.Handle, visit, arg);
173173
if (res != 0) return res;
174174

175175
res = PyVisit(self.repr, visit, arg);
@@ -190,15 +190,15 @@ public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
190190
internal class BoundContructor : ExtensionType
191191
{
192192
private Type type; // The managed Type being wrapped in a ClassObject
193-
private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create.
193+
private PyType typeToCreate; // The python type tells GetInstHandle which Type to create.
194194
private ConstructorBinder ctorBinder;
195195
private ConstructorInfo ctorInfo;
196196
private IntPtr repr;
197197

198-
public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci)
198+
public BoundContructor(Type type, PyType typeToCreate, ConstructorBinder ctorBinder, ConstructorInfo ci)
199199
{
200200
this.type = type;
201-
this.pyTypeHndl = pyTypeHndl; // steal a type reference
201+
this.typeToCreate = typeToCreate;
202202
this.ctorBinder = ctorBinder;
203203
ctorInfo = ci;
204204
repr = IntPtr.Zero;
@@ -229,7 +229,7 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw)
229229
}
230230
// Instantiate the python object that wraps the result of the method call
231231
// and return the PyObject* to it.
232-
return CLRObject.GetInstHandle(obj, self.pyTypeHndl);
232+
return CLRObject.GetInstHandle(obj, self.typeToCreate.Reference).DangerousMoveToPointer();
233233
}
234234

235235
/// <summary>
@@ -272,7 +272,7 @@ public static int tp_clear(IntPtr ob)
272272
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
273273
{
274274
var self = (BoundContructor)GetManagedObject(ob);
275-
int res = PyVisit(self.pyTypeHndl, visit, arg);
275+
int res = PyVisit(self.typeToCreate.Handle, visit, arg);
276276
if (res != 0) return res;
277277

278278
res = PyVisit(self.repr, visit, arg);

src/runtime/exceptions.cs

+9
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,15 @@ internal static void ErrorOccurredCheck(IntPtr pointer)
206206
}
207207
}
208208

209+
internal static IntPtr ErrorCheckIfNull(IntPtr pointer)
210+
{
211+
if (pointer == IntPtr.Zero && ErrorOccurred())
212+
{
213+
throw new PythonException();
214+
}
215+
return pointer;
216+
}
217+
209218
/// <summary>
210219
/// ExceptionMatches Method
211220
/// </summary>

src/runtime/extensiontype.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public ExtensionType()
1818
// The Python instance object is related to an instance of a
1919
// particular concrete subclass with a hidden CLR gchandle.
2020

21-
IntPtr tp = TypeManager.GetTypeHandle(GetType());
21+
BorrowedReference tp = TypeManager.GetTypeReference(GetType());
2222

2323
//int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt);
2424
//if (rc > 1050)
@@ -27,11 +27,11 @@ public ExtensionType()
2727
// DebugUtil.DumpType(tp);
2828
//}
2929

30-
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
30+
NewReference py = Runtime.PyType_GenericAlloc(tp, 0);
3131

32-
// Steals a ref to tpHandle.
33-
tpHandle = tp;
34-
pyHandle = py;
32+
// Borrowed reference. Valid as long as pyHandle is valid.
33+
tpHandle = tp.DangerousGetAddress();
34+
pyHandle = py.DangerousMoveToPointer();
3535

3636
#if DEBUG
3737
GetGCHandle(ObjectReference, TypeReference, out var existing);

src/runtime/managedtype.cs

+16-19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#nullable enable
12
using System;
23
using System.Collections.Generic;
34
using System.Diagnostics;
@@ -27,8 +28,8 @@ internal enum TrackTypes
2728
internal IntPtr pyHandle; // PyObject *
2829
internal IntPtr tpHandle; // PyType *
2930

30-
internal BorrowedReference ObjectReference => new BorrowedReference(pyHandle);
31-
internal BorrowedReference TypeReference => new BorrowedReference(tpHandle);
31+
internal BorrowedReference ObjectReference => new(pyHandle);
32+
internal BorrowedReference TypeReference => new(tpHandle);
3233

3334
private static readonly Dictionary<ManagedType, TrackTypes> _managedObjs = new Dictionary<ManagedType, TrackTypes>();
3435

@@ -78,12 +79,12 @@ internal void FreeGCHandle()
7879
}
7980
}
8081

81-
internal static ManagedType GetManagedObject(BorrowedReference ob)
82+
internal static ManagedType? GetManagedObject(BorrowedReference ob)
8283
=> GetManagedObject(ob.DangerousGetAddress());
8384
/// <summary>
8485
/// Given a Python object, return the associated managed object or null.
8586
/// </summary>
86-
internal static ManagedType GetManagedObject(IntPtr ob)
87+
internal static ManagedType? GetManagedObject(IntPtr ob)
8788
{
8889
if (ob != IntPtr.Zero)
8990
{
@@ -106,7 +107,7 @@ internal static ManagedType GetManagedObject(IntPtr ob)
106107
/// <summary>
107108
/// Given a Python object, return the associated managed object type or null.
108109
/// </summary>
109-
internal static ManagedType GetManagedObjectType(IntPtr ob)
110+
internal static ManagedType? GetManagedObjectType(IntPtr ob)
110111
{
111112
if (ob != IntPtr.Zero)
112113
{
@@ -121,18 +122,6 @@ internal static ManagedType GetManagedObjectType(IntPtr ob)
121122
return null;
122123
}
123124

124-
125-
internal static ManagedType GetManagedObjectErr(IntPtr ob)
126-
{
127-
ManagedType result = GetManagedObject(ob);
128-
if (result == null)
129-
{
130-
Exceptions.SetError(Exceptions.TypeError, "invalid argument, expected CLR type");
131-
}
132-
return result;
133-
}
134-
135-
136125
internal static bool IsInstanceOfManagedType(BorrowedReference ob)
137126
=> IsInstanceOfManagedType(ob.DangerousGetAddressOrNull());
138127
internal static bool IsInstanceOfManagedType(IntPtr ob)
@@ -156,6 +145,13 @@ internal static bool IsManagedType(BorrowedReference type)
156145
return (flags & TypeFlags.HasClrInstance) != 0;
157146
}
158147

148+
public bool IsClrMetaTypeInstance()
149+
{
150+
Debug.Assert(Runtime.PyCLRMetaType != IntPtr.Zero);
151+
Debug.Assert(pyHandle != IntPtr.Zero);
152+
return Runtime.PyObject_TYPE(pyHandle) == Runtime.PyCLRMetaType;
153+
}
154+
159155
internal static IDictionary<ManagedType, TrackTypes> GetManagedObjects()
160156
{
161157
return _managedObjs;
@@ -185,7 +181,8 @@ internal void CallTypeClear()
185181
{
186182
return;
187183
}
188-
var clearPtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_clear);
184+
185+
var clearPtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_clear);
189186
if (clearPtr == IntPtr.Zero)
190187
{
191188
return;
@@ -203,7 +200,7 @@ internal void CallTypeTraverse(Interop.ObjObjFunc visitproc, IntPtr arg)
203200
{
204201
return;
205202
}
206-
var traversePtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_traverse);
203+
var traversePtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_traverse);
207204
if (traversePtr == IntPtr.Zero)
208205
{
209206
return;

src/runtime/metatype.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
132132
{
133133
if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__"))
134134
{
135-
return TypeManager.CreateSubType(name, base_type, dict);
135+
return TypeManager.CreateSubType(name, base_type, clsDict.Reference);
136136
}
137137
}
138138
}
@@ -266,7 +266,7 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value)
266266
}
267267

268268
int res = Runtime.PyObject_GenericSetAttr(tp, name, value);
269-
Runtime.PyType_Modified(tp);
269+
Runtime.PyType_Modified(new BorrowedReference(tp));
270270

271271
return res;
272272
}

src/runtime/pytype.cs

+13
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66

77
namespace Python.Runtime
88
{
9+
[Serializable]
910
public class PyType : PyObject
1011
{
1112
/// <summary>Creates heap type object from the <paramref name="spec"/>.</summary>
1213
public PyType(TypeSpec spec, PyTuple? bases = null) : base(FromSpec(spec, bases)) { }
1314
/// <summary>Wraps an existing type object.</summary>
1415
public PyType(PyObject o) : base(FromObject(o)) { }
1516

17+
internal PyType(BorrowedReference reference) : base(reference)
18+
{
19+
if (!Runtime.PyType_Check(this.Handle))
20+
throw new ArgumentException("object is not a type");
21+
}
22+
1623
/// <summary>Checks if specified object is a Python type.</summary>
1724
public static bool IsType(PyObject value)
1825
{
@@ -21,6 +28,12 @@ public static bool IsType(PyObject value)
2128
return Runtime.PyType_Check(value.obj);
2229
}
2330

31+
internal IntPtr GetSlot(TypeSlotID slot)
32+
{
33+
IntPtr result = Runtime.PyType_GetSlot(this.Reference, slot);
34+
return Exceptions.ErrorCheckIfNull(result);
35+
}
36+
2437
private static BorrowedReference FromObject(PyObject o)
2538
{
2639
if (o is null) throw new ArgumentNullException(nameof(o));

0 commit comments

Comments
 (0)