-
Notifications
You must be signed in to change notification settings - Fork 752
Replace magic offsets with proper offset calculation #1441
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
removed some macro-like method copy-pastes from CPython and bits of dead code All Python types created to represent CLR concepts derive from `CLR MetaType` (as before), which now has two new fields: - `tp_clr_inst_offset`, which is similar to `tp_dictoffset` in that it tells where to find `GCHandle` in instances of this type (e.g. where to find `GCHandle` pointing to `System.Uri` in corresponding Python object) - `tp_clr_inst`, which holds an optional instance of `ManagedType`, that implements the behavior of the type itself (e.g. `GCHandle` pointing to `ClassObject(type = System.Uri)`) So the layout of all Python types created by Python.NET is PyType type; nint tp_clr_inst_offset; GCHandel tp_clr_inst; (points, for example, to an instance of `ClassObject`) When a Python type, that reflects CLR type is created, the layout of instances will be: BaseTypeFields base; optional (if not in base): IntPtr dict; optional (if not in base): IntPtr weaklist; GCHandle gcHandle; (points to `CLRObject` instance, which in turn, for example, points to the actual instance of `System.Uri`) The offset to GC handle is recorded in the Python type's `tp_clr_inst_offset`, and can be found as `PyObject_Type(inst).tp_clr_inst_offset`. Or, preferably, accessor functions in `ManagedType` should be used.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,6 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using System.Runtime.Serialization; | ||
|
||
namespace Python.Runtime | ||
{ | ||
|
@@ -355,19 +352,21 @@ public static void tp_dealloc(IntPtr ob) | |
{ | ||
ManagedType self = GetManagedObject(ob); | ||
tp_clear(ob); | ||
Runtime.PyObject_GC_UnTrack(self.pyHandle); | ||
Runtime.PyObject_GC_Del(self.pyHandle); | ||
self.FreeGCHandle(); | ||
Runtime.PyObject_GC_UnTrack(ob); | ||
Runtime.PyObject_GC_Del(ob); | ||
self?.FreeGCHandle(); | ||
} | ||
|
||
public static int tp_clear(IntPtr ob) | ||
{ | ||
ManagedType self = GetManagedObject(ob); | ||
if (!self.IsTypeObject()) | ||
|
||
bool isTypeObject = Runtime.PyObject_TYPE(ob) == Runtime.PyCLRMetaType; | ||
if (!isTypeObject) | ||
{ | ||
ClearObjectDict(ob); | ||
} | ||
self.tpHandle = IntPtr.Zero; | ||
if (self is not null) self.tpHandle = IntPtr.Zero; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above |
||
return 0; | ||
} | ||
|
||
|
@@ -391,7 +390,7 @@ protected override void OnLoad(InterDomainContext context) | |
SetObjectDict(pyHandle, dict); | ||
} | ||
gcHandle = AllocGCHandle(); | ||
Marshal.WriteIntPtr(pyHandle, TypeOffset.magic(), (IntPtr)gcHandle); | ||
SetGCHandle(ObjectReference, gcHandle); | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,26 +14,16 @@ internal CLRObject(object ob, IntPtr tp) | |
System.Diagnostics.Debug.Assert(tp != IntPtr.Zero); | ||
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); | ||
|
||
var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); | ||
if ((flags & TypeFlags.Subclass) != 0) | ||
{ | ||
IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp)); | ||
if (dict == IntPtr.Zero) | ||
{ | ||
dict = Runtime.PyDict_New(); | ||
Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict); | ||
} | ||
} | ||
|
||
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper); | ||
Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); | ||
tpHandle = tp; | ||
pyHandle = py; | ||
inst = ob; | ||
|
||
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper); | ||
InitGCHandle(ObjectReference, type: TypeReference, gc); | ||
|
||
// Fix the BaseException args (and __cause__ in case of Python 3) | ||
// slot if wrapping a CLR exception | ||
Exceptions.SetArgsAndCause(py); | ||
if (ob is Exception e) Exceptions.SetArgsAndCause(e, py); | ||
} | ||
|
||
protected CLRObject() | ||
|
@@ -78,6 +68,9 @@ internal static IntPtr GetInstHandle(object ob) | |
return co.pyHandle; | ||
} | ||
|
||
internal static NewReference GetReference(object ob) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this throw if ob is null? (maybe debug only) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does raise a |
||
=> NewReference.DangerousFromPointer(GetInstHandle(ob)); | ||
|
||
internal static CLRObject Restore(object ob, IntPtr pyHandle, InterDomainContext context) | ||
{ | ||
CLRObject co = new CLRObject() | ||
|
@@ -101,7 +94,7 @@ protected override void OnLoad(InterDomainContext context) | |
{ | ||
base.OnLoad(context); | ||
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper); | ||
Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gc); | ||
SetGCHandle(ObjectReference, TypeReference, gc); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,26 +15,6 @@ internal static class ImportHook | |
private static IntPtr py_clr_module; | ||
static BorrowedReference ClrModuleReference => new BorrowedReference(py_clr_module); | ||
|
||
private static IntPtr module_def = IntPtr.Zero; | ||
|
||
internal static void InitializeModuleDef() | ||
{ | ||
if (module_def == IntPtr.Zero) | ||
{ | ||
module_def = ModuleDefOffset.AllocModuleDef("clr"); | ||
} | ||
} | ||
|
||
internal static void ReleaseModuleDef() | ||
{ | ||
if (module_def == IntPtr.Zero) | ||
{ | ||
return; | ||
} | ||
ModuleDefOffset.FreeModuleDef(module_def); | ||
module_def = IntPtr.Zero; | ||
} | ||
|
||
/// <summary> | ||
/// Initialize just the __import__ hook itself. | ||
/// </summary> | ||
|
@@ -90,8 +70,7 @@ internal static unsafe void Initialize() | |
root = new CLRModule(); | ||
|
||
// create a python module with the same methods as the clr module-like object | ||
InitializeModuleDef(); | ||
py_clr_module = Runtime.PyModule_Create2(module_def, 3); | ||
py_clr_module = Runtime.PyModule_New("clr").DangerousMoveToPointer(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely sure of the internal differences with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// both dicts are borrowed references | ||
BorrowedReference mod_dict = Runtime.PyModule_GetDict(ClrModuleReference); | ||
|
@@ -116,13 +95,8 @@ internal static void Shutdown() | |
|
||
RestoreImport(); | ||
|
||
bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1; | ||
Runtime.XDecref(py_clr_module); | ||
py_clr_module = IntPtr.Zero; | ||
if (shouldFreeDef) | ||
{ | ||
ReleaseModuleDef(); | ||
} | ||
|
||
Runtime.XDecref(root.pyHandle); | ||
root = null; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this expected?/Should this be an error in debug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen a scenario or two when this happens after
tp_clear
is called. Same as below.