Repository navigation
Expand file tree
/
Copy pathReflectedClrType.cs
More file actions
139 lines (115 loc) · 4.95 KB
/
Copy pathReflectedClrType.cs
File metadata and controls
139 lines (115 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using static Python.Runtime.PythonException;
namespace Python.Runtime;
[Serializable]
internal sealed class ReflectedClrType : PyType
{
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
internal ReflectedClrType(BorrowedReference original) : base(original) { }
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
/// <summary>
/// Get the Python type that reflects the given CLR type.
/// </summary>
/// <remarks>
/// Returned <see cref="ReflectedClrType"/> might be partially initialized.
/// </remarks>
public static ReflectedClrType GetOrCreate(Type type)
{
// Fast path: `cache` holds only fully-initialised types.
if (ClassManager.cache.TryGetValue(type, out var pyType))
return pyType;
// Shared with ClassManager.cache + TypeManager._slotsHolders writes
// so the multi-step type build below is atomic.
lock (ClassManager._cacheCreateLock)
{
// Re-check now that we hold the lock; another thread may have finished.
if (ClassManager.cache.TryGetValue(type, out pyType))
return pyType;
// Reentrant call from the same thread (self-referential class) sees the
// partial type that the outer frame allocated.
if (ClassManager._inProgressCache.TryGetValue(type, out pyType))
return pyType;
try
{
pyType = AllocateClass(type);
ClassManager._inProgressCache[type] = pyType;
var impl = ClassManager.CreateClass(type);
TypeManager.InitializeClassCore(type, pyType, impl);
ClassManager.InitClassBase(type, impl, pyType);
TypeManager.InitializeClass(pyType, impl, type);
// Publish the completed type so the fast path can see it.
ClassManager.cache[type] = pyType;
}
catch (Exception e)
{
throw new InternalPythonnetException($"Failed to create Python type for {type.FullName}", e);
}
finally
{
ClassManager._inProgressCache.Remove(type);
}
return pyType;
}
}
internal void Restore(Dictionary<string, object?> context)
{
var cb = (ClassBase)context["impl"]!;
Debug.Assert(cb is not null);
cb!.Load(this, context);
Restore(cb);
}
internal void Restore(ClassBase cb)
{
ClassManager.InitClassBase(cb.type.Value, cb, this);
TypeManager.InitializeClass(this, cb, cb.type.Value);
}
internal static NewReference CreateSubclass(ClassBase baseClass, IList<Type> interfaces,
string name, string? assembly, string? ns,
BorrowedReference dict)
{
try
{
Type subType = ClassDerivedObject.CreateDerivedType(name,
baseClass.type.Value,
interfaces,
dict,
ns,
assembly);
var py_type = GetOrCreate(subType);
// by default the class dict will have all the C# methods in it, but as this is a
// derived class we want the python overrides in there instead if they exist.
var cls_dict = Util.ReadRef(py_type, TypeOffset.tp_dict);
ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, dict));
// Update the __classcell__ if it exists
BorrowedReference cell = Runtime.PyDict_GetItemString(cls_dict, "__classcell__");
if (!cell.IsNull)
{
ThrowIfIsNotZero(Runtime.PyCell_Set(cell, py_type));
ThrowIfIsNotZero(Runtime.PyDict_DelItemString(cls_dict, "__classcell__"));
}
return new NewReference(py_type);
}
catch (Exception e)
{
return Exceptions.RaiseTypeError(e.Message);
}
}
static ReflectedClrType AllocateClass(Type clrType)
{
string name = TypeManager.GetPythonTypeName(clrType);
var type = TypeManager.AllocateTypeObject(name, Runtime.PyCLRMetaType);
type.Flags = TypeFlags.Default
| TypeFlags.HasClrInstance
| TypeFlags.HeapType
| TypeFlags.BaseType
| TypeFlags.HaveGC;
return new ReflectedClrType(type.Steal());
}
public override bool Equals(PyObject? other) => rawPtr == other?.DangerousGetAddressOrNull();
public override int GetHashCode() => rawPtr.GetHashCode();
}