-
Notifications
You must be signed in to change notification settings - Fork 774
Expand file tree
/
Copy pathCodeGenerator.cs
More file actions
100 lines (88 loc) · 3.41 KB
/
CodeGenerator.cs
File metadata and controls
100 lines (88 loc) · 3.41 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
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace Python.Runtime
{
/// <summary>
/// Several places in the runtime generate code on the fly to support
/// dynamic functionality. The CodeGenerator class manages the dynamic
/// assembly used for code generation and provides utility methods for
/// certain repetitive tasks.
/// </summary>
internal class CodeGenerator
{
private readonly AssemblyBuilder aBuilder;
private readonly ModuleBuilder mBuilder;
const string NamePrefix = "__Python_Runtime_Generated_";
internal CodeGenerator()
{
var aname = new AssemblyName { Name = GetUniqueAssemblyName(NamePrefix + "Assembly") };
var aa = AssemblyBuilderAccess.Run;
aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa);
mBuilder = aBuilder.DefineDynamicModule(NamePrefix + "Module");
}
/// <summary>
/// DefineType is a shortcut utility to get a new TypeBuilder.
/// </summary>
internal TypeBuilder DefineType(string name)
{
var attrs = TypeAttributes.Public;
return mBuilder.DefineType(name, attrs);
}
/// <summary>
/// DefineType is a shortcut utility to get a new TypeBuilder.
/// </summary>
internal TypeBuilder DefineType(string name, Type basetype)
{
var attrs = TypeAttributes.Public;
return mBuilder.DefineType(name, attrs, basetype);
}
/// <summary>
/// Generates code, that copies potentially modified objects in args array
/// back to the corresponding byref arguments
/// </summary>
internal static void GenerateMarshalByRefsBack(ILGenerator il, IReadOnlyList<Type> argTypes)
{
// assumes argument array is in loc_0
for (int i = 0; i < argTypes.Count; ++i)
{
var type = argTypes[i];
if (type.IsByRef)
{
type = type.GetElementType();
il.Emit(OpCodes.Ldarg, i + 1); // for stobj/stind later at the end
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
if (type.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, type);
il.Emit(OpCodes.Stobj, type);
}
else
{
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Stind_Ref);
}
}
}
}
static string GetUniqueAssemblyName(string name)
{
var taken = new HashSet<string>(AppDomain.CurrentDomain
.GetAssemblies()
.Select(a => a.GetName().Name));
for (int i = 0; i < int.MaxValue; i++)
{
string candidate = name + i.ToString(CultureInfo.InvariantCulture);
if (!taken.Contains(candidate))
return candidate;
}
throw new NotSupportedException("Too many assemblies");
}
}
}