1+ using System ;
2+ using System . Reflection ;
3+ using System . Reflection . Emit ;
4+ using System . Diagnostics ;
5+
6+
7+ #if LIGHT_EXPRESSION
8+ using ExpressionType = System . Linq . Expressions . ExpressionType ;
9+ using static FastExpressionCompiler . LightExpression . Expression ;
10+ namespace FastExpressionCompiler . LightExpression . IssueTests ;
11+ #else
12+ using System . Linq . Expressions ;
13+ using static System . Linq . Expressions . Expression ;
14+ namespace FastExpressionCompiler . IssueTests ;
15+ #endif
16+
17+ public struct Issue475_Reuse_DynamicMethod_if_possible : ITestX
18+ {
19+ public void Run ( TestRun t )
20+ {
21+ TryToReuseTheDynamicMethod ( t ) ;
22+ }
23+
24+ internal static FieldInfo IlGeneratorField = typeof ( DynamicMethod ) . GetField ( "_ilGenerator" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
25+ internal static FieldInfo MethodHandleField = typeof ( DynamicMethod ) . GetField ( "_methodHandle" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
26+ internal static MethodInfo GetMethodDescriptorMethod = typeof ( DynamicMethod ) . GetMethod ( "GetMethodDescriptor" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
27+ internal static MethodInfo CreateDelegateMethod = typeof ( Delegate ) . GetMethod ( "CreateDelegateNoSecurityCheck" , BindingFlags . Static | BindingFlags . NonPublic ) ;
28+
29+ void TryToReuseTheDynamicMethod ( TestContext t )
30+ {
31+ // Let's say there is a DynamicMethod of Func<int, int> returning its argument,
32+ // at the end I want to reuse the created DynamicMethod for another Func<int, int> returning arg + 42
33+
34+ var dynMethod = new DynamicMethod ( string . Empty ,
35+ typeof ( int ) ,
36+ [ typeof ( ExpressionCompiler . ArrayClosure ) , typeof ( int ) ] ,
37+ typeof ( ExpressionCompiler . ArrayClosure ) ,
38+ true ) ;
39+
40+ var il = dynMethod . GetILGenerator ( ) ;
41+
42+ il . Emit ( OpCodes . Ldarg_1 ) ;
43+ il . Emit ( OpCodes . Ret ) ;
44+
45+ var runtimeMethodHandle = GetMethodDescriptorMethod . Invoke ( dynMethod , null ) ;
46+ var func = ( Func < int , int > ) CreateDelegateMethod . Invoke ( null , [ typeof ( Func < int , int > ) , ExpressionCompiler . EmptyArrayClosure , runtimeMethodHandle ] ) ;
47+
48+ // var func = (Func<int, int>)dynMethod.CreateDelegate(typeof(Func<int, int>), ExpressionCompiler.EmptyArrayClosure);
49+ t . AreEqual ( 41 , func ( 41 ) ) ;
50+
51+ // Debug.WriteLine($"Field_initLocals: {Field_initLocals.GetValue(dynMethod)}");
52+ IlGeneratorField . SetValue ( dynMethod , null ) ;
53+
54+ // required: Keeps the old delegate if not set to null
55+ MethodHandleField . SetValue ( dynMethod , null ) ;
56+
57+ var il2 = dynMethod . GetILGenerator ( ) ;
58+
59+ il2 . Emit ( OpCodes . Ldarg_1 ) ;
60+ il2 . Emit ( OpCodes . Ldc_I4 , 42 ) ;
61+ il2 . Emit ( OpCodes . Add ) ;
62+ il2 . Emit ( OpCodes . Ret ) ;
63+
64+ t . AreEqual ( 41 , func ( 41 ) ) ;
65+
66+ // CreateDelegate does:
67+ // RuntimeMethodHandle runtimeMethodHandle = GetMethodDescriptor();
68+ // MulticastDelegate d = (MulticastDelegate)Delegate.CreateDelegateNoSecurityCheck(delegateType, target, runtimeMethodHandle);
69+ // // stash this MethodInfo by brute force.
70+ // d.StoreDynamicMethod(this);
71+ // return d;
72+
73+ // todo: @wip Calling this second time in `-c:Release` will produce `Fatal error. Internal CLR error. (0x80131506) ## :-( Failed with ERROR: -1073741819` (the -c:Debug is working fine)
74+ // runtimeMethodHandle = GetMethodDescriptorMethod.Invoke(dynMethod, null);
75+
76+ // var func2 = (Func<int, int>)CreateDelegateMethod.Invoke(null, [typeof(Func<int, int>), ExpressionCompiler.EmptyArrayClosure, runtimeMethodHandle]);
77+
78+ // var func2 = (Func<int, int>)dynMethod.CreateDelegate(typeof(Func<int, int>), ExpressionCompiler.EmptyArrayClosure);
79+ // t.AreEqual(83, func2(41));
80+ }
81+
82+ public static object Reuse ( )
83+ {
84+ var dynMethod = new DynamicMethod ( string . Empty ,
85+ typeof ( int ) ,
86+ [ typeof ( ExpressionCompiler . ArrayClosure ) , typeof ( int ) ] ,
87+ typeof ( ExpressionCompiler . ArrayClosure ) ,
88+ true ) ;
89+
90+ var il = dynMethod . GetILGenerator ( ) ;
91+
92+ il . Emit ( OpCodes . Ldarg_1 ) ;
93+ il . Emit ( OpCodes . Ret ) ;
94+
95+ _ = ( Func < int , int > ) dynMethod . CreateDelegate ( typeof ( Func < int , int > ) , ExpressionCompiler . EmptyArrayClosure ) ;
96+
97+ IlGeneratorField . SetValue ( dynMethod , null ) ;
98+ // Field_initLocals.SetValue(dynMethod, true);
99+
100+ var il2 = dynMethod . GetILGenerator ( ) ;
101+
102+ il2 . Emit ( OpCodes . Ldarg_1 ) ;
103+ il2 . Emit ( OpCodes . Ldc_I4 , 42 ) ;
104+ il2 . Emit ( OpCodes . Add ) ;
105+ il2 . Emit ( OpCodes . Ret ) ;
106+
107+ return ( Func < int , int > ) dynMethod . CreateDelegate ( typeof ( Func < int , int > ) , ExpressionCompiler . EmptyArrayClosure ) ;
108+ }
109+
110+ public static object NoReuse ( )
111+ {
112+ var dynMethod = new DynamicMethod ( string . Empty ,
113+ typeof ( int ) ,
114+ [ typeof ( ExpressionCompiler . ArrayClosure ) , typeof ( int ) ] ,
115+ typeof ( ExpressionCompiler . ArrayClosure ) ,
116+ true ) ;
117+
118+ var il = dynMethod . GetILGenerator ( ) ;
119+
120+ il . Emit ( OpCodes . Ldarg_1 ) ;
121+ il . Emit ( OpCodes . Ret ) ;
122+
123+ _ = ( Func < int , int > ) dynMethod . CreateDelegate ( typeof ( Func < int , int > ) , ExpressionCompiler . EmptyArrayClosure ) ;
124+
125+ var dynMethod2 = new DynamicMethod ( string . Empty ,
126+ typeof ( int ) ,
127+ [ typeof ( ExpressionCompiler . ArrayClosure ) , typeof ( int ) ] ,
128+ typeof ( ExpressionCompiler . ArrayClosure ) ,
129+ true ) ;
130+
131+ var il2 = dynMethod2 . GetILGenerator ( ) ;
132+
133+ il2 . Emit ( OpCodes . Ldarg_1 ) ;
134+ il2 . Emit ( OpCodes . Ldc_I4 , 42 ) ;
135+ il2 . Emit ( OpCodes . Add ) ;
136+ il2 . Emit ( OpCodes . Ret ) ;
137+
138+ return ( Func < int , int > ) dynMethod2 . CreateDelegate ( typeof ( Func < int , int > ) , ExpressionCompiler . EmptyArrayClosure ) ;
139+ }
140+
141+ // internal static FieldInfo Field_initLocals = typeof(DynamicMethod).GetField("_initLocals", BindingFlags.Instance | BindingFlags.NonPublic);
142+
143+ internal static Action < DynamicMethod > GetDynamicMethodResetDelegate ( )
144+ {
145+ // Reset the DynamicMethod internals to enable its reuse
146+ // _ilGenerator = null;
147+ // _initLocals = true;
148+ // _methodHandle = null; // but this reset breaks the CLR
149+
150+ var dynMethod = new DynamicMethod ( string . Empty ,
151+ typeof ( void ) ,
152+ [ typeof ( ExpressionCompiler . ArrayClosure ) , typeof ( DynamicMethod ) ] ,
153+ typeof ( ExpressionCompiler . ArrayClosure ) ,
154+ true ) ;
155+
156+ var il = dynMethod . GetILGenerator ( ) ;
157+ il . Emit ( OpCodes . Ldarg_1 ) ;
158+ il . Emit ( OpCodes . Ldnull ) ;
159+ il . Emit ( OpCodes . Stfld , IlGeneratorField ) ;
160+ // il.Emit(OpCodes.Ldarg_1);
161+ // il.Emit(OpCodes.Ldc_I4_1);
162+ // il.Emit(OpCodes.Stfld, Field_initLocals);
163+ il . Emit ( OpCodes . Ret ) ;
164+
165+ return ( Action < DynamicMethod > ) dynMethod . CreateDelegate ( typeof ( Action < DynamicMethod > ) , ExpressionCompiler . EmptyArrayClosure ) ;
166+ }
167+
168+ internal static Lazy < Action < DynamicMethod > > ResetDynamicMethod = new ( GetDynamicMethodResetDelegate ) ;
169+ }
0 commit comments