Skip to content

Use PyType instances instead of raw pointers #1431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/runtime/classbase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ public static int tp_clear(IntPtr ob)
protected override void OnSave(InterDomainContext context)
{
base.OnSave(context);
if (pyHandle != tpHandle)
if (!this.IsClrMetaTypeInstance())
{
IntPtr dict = GetObjectDict(pyHandle);
Runtime.XIncref(dict);
Expand All @@ -384,7 +384,7 @@ protected override void OnSave(InterDomainContext context)
protected override void OnLoad(InterDomainContext context)
{
base.OnLoad(context);
if (pyHandle != tpHandle)
if (!this.IsClrMetaTypeInstance())
{
IntPtr dict = context.Storage.GetValue<IntPtr>("dict");
SetObjectDict(pyHandle, dict);
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/classderived.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,13 @@ internal static IntPtr ToPython(IPythonDerivedType obj)
/// </summary>
internal static Type CreateDerivedType(string name,
Type baseType,
IntPtr py_dict,
BorrowedReference dictRef,
string namespaceStr,
string assemblyName,
string moduleName = "Python.Runtime.Dynamic.dll")
{
// TODO: clean up
IntPtr py_dict = dictRef.DangerousGetAddress();
if (null != namespaceStr)
{
name = namespaceStr + "." + name;
Expand Down Expand Up @@ -824,7 +826,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec
try
{
// create the python object
IntPtr type = TypeManager.GetTypeHandle(obj.GetType());
BorrowedReference type = TypeManager.GetTypeReference(obj.GetType());
self = new CLRObject(obj, type);

// set __pyobj__ to self and deref the python object which will allow this
Expand Down
14 changes: 7 additions & 7 deletions src/runtime/classmanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage)
// Python object's dictionary tool; thus raising an AttributeError
// instead of a TypeError.
// Classes are re-initialized on in RestoreRuntimeData.
var dict = new BorrowedReference(Marshal.ReadIntPtr(cls.Value.tpHandle, TypeOffset.tp_dict));
using var dict = Runtime.PyObject_GenericGetDict(cls.Value.TypeReference);
foreach (var member in cls.Value.dotNetMembers)
{
// No need to decref the member, the ClassBase instance does
Expand All @@ -135,7 +135,7 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage)
}
}
// We modified the Type object, notify it we did.
Runtime.PyType_Modified(cls.Value.tpHandle);
Runtime.PyType_Modified(cls.Value.TypeReference);
}
}

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


IntPtr tp = TypeManager.GetTypeHandle(impl, type);
var pyType = TypeManager.GetType(impl, type);

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


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

// The type has been modified after PyType_Ready has been called
// Refresh the type
Runtime.PyType_Modified(tp);
Runtime.PyType_Modified(pyType.Reference);
}

internal static bool ShouldBindMethod(MethodBase mb)
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/clrobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ internal CLRObject(object ob, IntPtr tp)
if (ob is Exception e) Exceptions.SetArgsAndCause(e, py);
}

internal CLRObject(object ob, BorrowedReference tp) : this(ob, tp.DangerousGetAddress()) { }

protected CLRObject()
{
}
Expand Down
20 changes: 10 additions & 10 deletions src/runtime/constructorbinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ namespace Python.Runtime
internal class ConstructorBinding : ExtensionType
{
private MaybeType type; // The managed Type being wrapped in a ClassObject
private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create.
private PyType typeToCreate; // The python type tells GetInstHandle which Type to create.
private ConstructorBinder ctorBinder;

[NonSerialized]
private IntPtr repr;

public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder)
public ConstructorBinding(Type type, PyType typeToCreate, ConstructorBinder ctorBinder)
{
this.type = type;
this.pyTypeHndl = pyTypeHndl; // steal a type reference
this.typeToCreate = typeToCreate;
this.ctorBinder = ctorBinder;
repr = IntPtr.Zero;
}
Expand Down Expand Up @@ -110,7 +110,7 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key)
{
return Exceptions.RaiseTypeError("No match found for constructor signature");
}
var boundCtor = new BoundContructor(tp, self.pyTypeHndl, self.ctorBinder, ci);
var boundCtor = new BoundContructor(tp, self.typeToCreate, self.ctorBinder, ci);

return boundCtor.pyHandle;
}
Expand Down Expand Up @@ -169,7 +169,7 @@ public static int tp_clear(IntPtr ob)
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
{
var self = (ConstructorBinding)GetManagedObject(ob);
int res = PyVisit(self.pyTypeHndl, visit, arg);
int res = PyVisit(self.typeToCreate.Handle, visit, arg);
if (res != 0) return res;

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

public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci)
public BoundContructor(Type type, PyType typeToCreate, ConstructorBinder ctorBinder, ConstructorInfo ci)
{
this.type = type;
this.pyTypeHndl = pyTypeHndl; // steal a type reference
this.typeToCreate = typeToCreate;
this.ctorBinder = ctorBinder;
ctorInfo = ci;
repr = IntPtr.Zero;
Expand Down Expand Up @@ -229,7 +229,7 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw)
}
// Instantiate the python object that wraps the result of the method call
// and return the PyObject* to it.
return CLRObject.GetInstHandle(obj, self.pyTypeHndl);
return CLRObject.GetInstHandle(obj, self.typeToCreate.Reference).DangerousMoveToPointer();
}

/// <summary>
Expand Down Expand Up @@ -272,7 +272,7 @@ public static int tp_clear(IntPtr ob)
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
{
var self = (BoundContructor)GetManagedObject(ob);
int res = PyVisit(self.pyTypeHndl, visit, arg);
int res = PyVisit(self.typeToCreate.Handle, visit, arg);
if (res != 0) return res;

res = PyVisit(self.repr, visit, arg);
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ internal static void ErrorOccurredCheck(IntPtr pointer)
}
}

internal static IntPtr ErrorCheckIfNull(IntPtr pointer)
{
if (pointer == IntPtr.Zero && ErrorOccurred())
{
throw new PythonException();
}
return pointer;
}

/// <summary>
/// ExceptionMatches Method
/// </summary>
Expand Down
10 changes: 5 additions & 5 deletions src/runtime/extensiontype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public ExtensionType()
// The Python instance object is related to an instance of a
// particular concrete subclass with a hidden CLR gchandle.

IntPtr tp = TypeManager.GetTypeHandle(GetType());
BorrowedReference tp = TypeManager.GetTypeReference(GetType());

//int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt);
//if (rc > 1050)
Expand All @@ -27,11 +27,11 @@ public ExtensionType()
// DebugUtil.DumpType(tp);
//}

IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
NewReference py = Runtime.PyType_GenericAlloc(tp, 0);

// Steals a ref to tpHandle.
tpHandle = tp;
pyHandle = py;
// Borrowed reference. Valid as long as pyHandle is valid.
tpHandle = tp.DangerousGetAddress();
pyHandle = py.DangerousMoveToPointer();

#if DEBUG
GetGCHandle(ObjectReference, TypeReference, out var existing);
Expand Down
35 changes: 16 additions & 19 deletions src/runtime/managedtype.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand Down Expand Up @@ -27,8 +28,8 @@ internal enum TrackTypes
internal IntPtr pyHandle; // PyObject *
internal IntPtr tpHandle; // PyType *

internal BorrowedReference ObjectReference => new BorrowedReference(pyHandle);
internal BorrowedReference TypeReference => new BorrowedReference(tpHandle);
internal BorrowedReference ObjectReference => new(pyHandle);
internal BorrowedReference TypeReference => new(tpHandle);

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

Expand Down Expand Up @@ -78,12 +79,12 @@ internal void FreeGCHandle()
}
}

internal static ManagedType GetManagedObject(BorrowedReference ob)
internal static ManagedType? GetManagedObject(BorrowedReference ob)
=> GetManagedObject(ob.DangerousGetAddress());
/// <summary>
/// Given a Python object, return the associated managed object or null.
/// </summary>
internal static ManagedType GetManagedObject(IntPtr ob)
internal static ManagedType? GetManagedObject(IntPtr ob)
{
if (ob != IntPtr.Zero)
{
Expand All @@ -106,7 +107,7 @@ internal static ManagedType GetManagedObject(IntPtr ob)
/// <summary>
/// Given a Python object, return the associated managed object type or null.
/// </summary>
internal static ManagedType GetManagedObjectType(IntPtr ob)
internal static ManagedType? GetManagedObjectType(IntPtr ob)
{
if (ob != IntPtr.Zero)
{
Expand All @@ -121,18 +122,6 @@ internal static ManagedType GetManagedObjectType(IntPtr ob)
return null;
}


internal static ManagedType GetManagedObjectErr(IntPtr ob)
{
ManagedType result = GetManagedObject(ob);
if (result == null)
{
Exceptions.SetError(Exceptions.TypeError, "invalid argument, expected CLR type");
}
return result;
}


internal static bool IsInstanceOfManagedType(BorrowedReference ob)
=> IsInstanceOfManagedType(ob.DangerousGetAddressOrNull());
internal static bool IsInstanceOfManagedType(IntPtr ob)
Expand All @@ -156,6 +145,13 @@ internal static bool IsManagedType(BorrowedReference type)
return (flags & TypeFlags.HasClrInstance) != 0;
}

public bool IsClrMetaTypeInstance()
{
Debug.Assert(Runtime.PyCLRMetaType != IntPtr.Zero);
Debug.Assert(pyHandle != IntPtr.Zero);
return Runtime.PyObject_TYPE(pyHandle) == Runtime.PyCLRMetaType;
}

internal static IDictionary<ManagedType, TrackTypes> GetManagedObjects()
{
return _managedObjs;
Expand Down Expand Up @@ -185,7 +181,8 @@ internal void CallTypeClear()
{
return;
}
var clearPtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_clear);

var clearPtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_clear);
if (clearPtr == IntPtr.Zero)
{
return;
Expand All @@ -203,7 +200,7 @@ internal void CallTypeTraverse(Interop.ObjObjFunc visitproc, IntPtr arg)
{
return;
}
var traversePtr = Marshal.ReadIntPtr(tpHandle, TypeOffset.tp_traverse);
var traversePtr = Runtime.PyType_GetSlot(TypeReference, TypeSlotID.tp_traverse);
if (traversePtr == IntPtr.Zero)
{
return;
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/metatype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
{
if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__"))
{
return TypeManager.CreateSubType(name, base_type, dict);
return TypeManager.CreateSubType(name, base_type, clsDict.Reference);
}
}
}
Expand Down Expand Up @@ -266,7 +266,7 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value)
}

int res = Runtime.PyObject_GenericSetAttr(tp, name, value);
Runtime.PyType_Modified(tp);
Runtime.PyType_Modified(new BorrowedReference(tp));

return res;
}
Expand Down
13 changes: 13 additions & 0 deletions src/runtime/pytype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@

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

internal PyType(BorrowedReference reference) : base(reference)
{
if (!Runtime.PyType_Check(this.Handle))
throw new ArgumentException("object is not a type");
}

/// <summary>Checks if specified object is a Python type.</summary>
public static bool IsType(PyObject value)
{
Expand All @@ -21,6 +28,12 @@ public static bool IsType(PyObject value)
return Runtime.PyType_Check(value.obj);
}

internal IntPtr GetSlot(TypeSlotID slot)
{
IntPtr result = Runtime.PyType_GetSlot(this.Reference, slot);
return Exceptions.ErrorCheckIfNull(result);
}

private static BorrowedReference FromObject(PyObject o)
{
if (o is null) throw new ArgumentNullException(nameof(o));
Expand Down
Loading