Skip to content

Commit b2a911d

Browse files
committed
Replaced magic offsets with per-type calculation
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.
1 parent 16f04e9 commit b2a911d

18 files changed

+264
-502
lines changed

src/embed_tests/TestPyType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.InteropServices;
12
using System.Text;
23

34
using NUnit.Framework;
@@ -30,7 +31,7 @@ public void CanCreateHeapType()
3031
using var doc = new StrPtr(docStr, Encoding.UTF8);
3132
var spec = new TypeSpec(
3233
name: name,
33-
basicSize: ObjectOffset.Size(Runtime.Runtime.PyTypeType),
34+
basicSize: Marshal.ReadInt32(Runtime.Runtime.PyBaseObjectType, TypeOffset.tp_basicsize),
3435
slots: new TypeSpec.Slot[] {
3536
new (TypeSlotID.tp_doc, doc.RawPointer),
3637
},

src/runtime/classbase.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4-
using System.Diagnostics;
5-
using System.Runtime.InteropServices;
6-
using System.Runtime.Serialization;
74

85
namespace Python.Runtime
96
{
@@ -355,19 +352,21 @@ public static void tp_dealloc(IntPtr ob)
355352
{
356353
ManagedType self = GetManagedObject(ob);
357354
tp_clear(ob);
358-
Runtime.PyObject_GC_UnTrack(self.pyHandle);
359-
Runtime.PyObject_GC_Del(self.pyHandle);
360-
self.FreeGCHandle();
355+
Runtime.PyObject_GC_UnTrack(ob);
356+
Runtime.PyObject_GC_Del(ob);
357+
self?.FreeGCHandle();
361358
}
362359

363360
public static int tp_clear(IntPtr ob)
364361
{
365362
ManagedType self = GetManagedObject(ob);
366-
if (!self.IsTypeObject())
363+
364+
bool isTypeObject = Runtime.PyObject_TYPE(ob) == Runtime.PyCLRMetaType;
365+
if (!isTypeObject)
367366
{
368367
ClearObjectDict(ob);
369368
}
370-
self.tpHandle = IntPtr.Zero;
369+
if (self is not null) self.tpHandle = IntPtr.Zero;
371370
return 0;
372371
}
373372

@@ -391,7 +390,7 @@ protected override void OnLoad(InterDomainContext context)
391390
SetObjectDict(pyHandle, dict);
392391
}
393392
gcHandle = AllocGCHandle();
394-
Marshal.WriteIntPtr(pyHandle, TypeOffset.magic(), (IntPtr)gcHandle);
393+
SetGCHandle(ObjectReference, gcHandle);
395394
}
396395

397396

src/runtime/classderived.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Linq;
45
using System.Reflection;
56
using System.Reflection.Emit;
@@ -75,8 +76,8 @@ internal ClassDerivedObject(Type tp) : base(tp)
7576
// So we don't call PyObject_GC_Del here and instead we set the python
7677
// reference to a weak reference so that the C# object can be collected.
7778
GCHandle gc = GCHandle.Alloc(self, GCHandleType.Weak);
78-
int gcOffset = ObjectOffset.magic(Runtime.PyObject_TYPE(self.pyHandle));
79-
Marshal.WriteIntPtr(self.pyHandle, gcOffset, (IntPtr)gc);
79+
Debug.Assert(self.TypeReference == Runtime.PyObject_TYPE(self.ObjectReference));
80+
SetGCHandle(self.ObjectReference, self.TypeReference, gc);
8081
self.gcHandle.Free();
8182
self.gcHandle = gc;
8283
}
@@ -106,7 +107,7 @@ internal static IntPtr ToPython(IPythonDerivedType obj)
106107
Runtime._Py_NewReference(self.pyHandle);
107108
#endif
108109
GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal);
109-
Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc);
110+
SetGCHandle(self.ObjectReference, self.TypeReference, gc);
110111
self.gcHandle.Free();
111112
self.gcHandle = gc;
112113

@@ -883,11 +884,6 @@ public static void Finalize(IPythonDerivedType obj)
883884
// the C# object is being destroyed which must mean there are no more
884885
// references to the Python object as well so now we can dealloc the
885886
// python object.
886-
IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.tpHandle));
887-
if (dict != IntPtr.Zero)
888-
{
889-
Runtime.XDecref(dict);
890-
}
891887
Runtime.PyObject_GC_Del(self.pyHandle);
892888
self.gcHandle.Free();
893889
}

src/runtime/clrobject.cs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,16 @@ internal CLRObject(object ob, IntPtr tp)
1414
System.Diagnostics.Debug.Assert(tp != IntPtr.Zero);
1515
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
1616

17-
var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags);
18-
if ((flags & TypeFlags.Subclass) != 0)
19-
{
20-
IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp));
21-
if (dict == IntPtr.Zero)
22-
{
23-
dict = Runtime.PyDict_New();
24-
Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict);
25-
}
26-
}
27-
28-
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);
29-
Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
3017
tpHandle = tp;
3118
pyHandle = py;
3219
inst = ob;
3320

21+
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);
22+
InitGCHandle(ObjectReference, type: TypeReference, gc);
23+
3424
// Fix the BaseException args (and __cause__ in case of Python 3)
3525
// slot if wrapping a CLR exception
36-
Exceptions.SetArgsAndCause(py);
26+
if (ob is Exception e) Exceptions.SetArgsAndCause(e, py);
3727
}
3828

3929
protected CLRObject()
@@ -78,6 +68,9 @@ internal static IntPtr GetInstHandle(object ob)
7868
return co.pyHandle;
7969
}
8070

71+
internal static NewReference GetReference(object ob)
72+
=> NewReference.DangerousFromPointer(GetInstHandle(ob));
73+
8174
internal static CLRObject Restore(object ob, IntPtr pyHandle, InterDomainContext context)
8275
{
8376
CLRObject co = new CLRObject()
@@ -101,7 +94,7 @@ protected override void OnLoad(InterDomainContext context)
10194
{
10295
base.OnLoad(context);
10396
GCHandle gc = AllocGCHandle(TrackTypes.Wrapper);
104-
Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gc);
97+
SetGCHandle(ObjectReference, TypeReference, gc);
10598
}
10699
}
107100
}

src/runtime/converter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
580580
{
581581
if (Runtime.PyBytes_Size(value) == 1)
582582
{
583-
op = Runtime.PyBytes_AS_STRING(value);
583+
op = Runtime.PyBytes_AsString(value);
584584
result = (byte)Marshal.ReadByte(op);
585585
return true;
586586
}
@@ -606,7 +606,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
606606
{
607607
if (Runtime.PyBytes_Size(value) == 1)
608608
{
609-
op = Runtime.PyBytes_AS_STRING(value);
609+
op = Runtime.PyBytes_AsString(value);
610610
result = (byte)Marshal.ReadByte(op);
611611
return true;
612612
}
@@ -632,7 +632,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
632632
{
633633
if (Runtime.PyBytes_Size(value) == 1)
634634
{
635-
op = Runtime.PyBytes_AS_STRING(value);
635+
op = Runtime.PyBytes_AsString(value);
636636
result = (byte)Marshal.ReadByte(op);
637637
return true;
638638
}

src/runtime/exceptions.cs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,8 @@ internal static void Shutdown()
156156
/// pointer.
157157
/// </summary>
158158
/// <param name="ob">The python object wrapping </param>
159-
internal static void SetArgsAndCause(IntPtr ob)
159+
internal static void SetArgsAndCause(Exception e, IntPtr ob)
160160
{
161-
// e: A CLR Exception
162-
Exception e = ExceptionClassObject.ToException(ob);
163-
if (e == null)
164-
{
165-
return;
166-
}
167-
168161
IntPtr args;
169162
if (!string.IsNullOrEmpty(e.Message))
170163
{
@@ -177,13 +170,14 @@ internal static void SetArgsAndCause(IntPtr ob)
177170
args = Runtime.PyTuple_New(0);
178171
}
179172

180-
Marshal.WriteIntPtr(ob, ExceptionOffset.args, args);
173+
if (Runtime.PyObject_SetAttrString(ob, "args", args) != 0)
174+
throw new PythonException();
181175

182176
if (e.InnerException != null)
183177
{
184178
// Note: For an AggregateException, InnerException is only the first of the InnerExceptions.
185-
IntPtr cause = CLRObject.GetInstHandle(e.InnerException);
186-
Marshal.WriteIntPtr(ob, ExceptionOffset.cause, cause);
179+
using var cause = CLRObject.GetReference(e.InnerException);
180+
Runtime.PyException_SetCause(ob, cause.DangerousMoveToPointer());
187181
}
188182
}
189183

src/runtime/extensiontype.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ public ExtensionType()
3333
tpHandle = tp;
3434
pyHandle = py;
3535

36+
#if DEBUG
37+
GetGCHandle(ObjectReference, TypeReference, out var existing);
38+
System.Diagnostics.Debug.Assert(existing == IntPtr.Zero);
39+
#endif
3640
SetupGc();
3741
}
3842

3943
void SetupGc ()
4044
{
4145
GCHandle gc = AllocGCHandle(TrackTypes.Extension);
42-
Marshal.WriteIntPtr(pyHandle, ObjectOffset.magic(tpHandle), (IntPtr)gc);
46+
InitGCHandle(ObjectReference, TypeReference, gc);
4347

4448
// We have to support gc because the type machinery makes it very
4549
// hard not to - but we really don't have a need for it in most

src/runtime/importhook.cs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,6 @@ internal static class ImportHook
1515
private static IntPtr py_clr_module;
1616
static BorrowedReference ClrModuleReference => new BorrowedReference(py_clr_module);
1717

18-
private static IntPtr module_def = IntPtr.Zero;
19-
20-
internal static void InitializeModuleDef()
21-
{
22-
if (module_def == IntPtr.Zero)
23-
{
24-
module_def = ModuleDefOffset.AllocModuleDef("clr");
25-
}
26-
}
27-
28-
internal static void ReleaseModuleDef()
29-
{
30-
if (module_def == IntPtr.Zero)
31-
{
32-
return;
33-
}
34-
ModuleDefOffset.FreeModuleDef(module_def);
35-
module_def = IntPtr.Zero;
36-
}
37-
3818
/// <summary>
3919
/// Initialize just the __import__ hook itself.
4020
/// </summary>
@@ -90,8 +70,7 @@ internal static unsafe void Initialize()
9070
root = new CLRModule();
9171

9272
// create a python module with the same methods as the clr module-like object
93-
InitializeModuleDef();
94-
py_clr_module = Runtime.PyModule_Create2(module_def, 3);
73+
py_clr_module = Runtime.PyModule_New("clr").DangerousMoveToPointer();
9574

9675
// both dicts are borrowed references
9776
BorrowedReference mod_dict = Runtime.PyModule_GetDict(ClrModuleReference);
@@ -116,13 +95,8 @@ internal static void Shutdown()
11695

11796
RestoreImport();
11897

119-
bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1;
12098
Runtime.XDecref(py_clr_module);
12199
py_clr_module = IntPtr.Zero;
122-
if (shouldFreeDef)
123-
{
124-
ReleaseModuleDef();
125-
}
126100

127101
Runtime.XDecref(root.pyHandle);
128102
root = null;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy