-
Notifications
You must be signed in to change notification settings - Fork 1
/
MethodFlow.cs
116 lines (106 loc) · 6.77 KB
/
MethodFlow.cs
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
using System;
using System.Reflection;
using System.Reflection.Emit;
using JetBrains.Annotations;
namespace ILGeneratorExtensions
{
/// <summary>
/// Contains extension methods for controlling flow to other methods
/// </summary>
[PublicAPI]
public static partial class MethodFlow
{
/// <summary>
/// Exits the current method and jumps immediately to the given method, using the same arguments
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to jump to</param>
[PublicAPI]
public static ILGenerator JumpTo(this ILGenerator generator, MethodInfo method) => generator.FluentEmit(OpCodes.Jmp, method);
/// <summary>
/// Calls the given method, popping the requisite number of arguments from the evaluation stack (including the this reference if it is an instance method)
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator Call(this ILGenerator generator, MethodInfo method) => generator.FluentEmit(OpCodes.Call, method);
/// <summary>
/// Calls the given method with virtual semantics, popping a reference (and performing a null check) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator CallVirtual(this ILGenerator generator, MethodInfo method) => generator.FluentEmit(OpCodes.Callvirt, method);
/// <summary>
/// Performs a tail call to the given method, popping the requisite number of arguments from the evaluation stack (including the this reference if it is an instance method)
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator TailCall(this ILGenerator generator, MethodInfo method)
{
return generator.FluentEmit(OpCodes.Tailcall)
.FluentEmit(OpCodes.Call, method);
}
/// <summary>
/// Performs a tail call to the given method with virtual semantics, popping a reference (and performing a null check) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator TailCallVirtual(this ILGenerator generator, MethodInfo method)
{
return generator.FluentEmit(OpCodes.Tailcall)
.FluentEmit(OpCodes.Callvirt, method);
}
/// <summary>
/// Performs a constrained virtual call to the given method, popping an address to storage location of the value or reference (and performing a null check if necessary) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <typeparam name="T">The type to constrain the call to</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator ConstrainedCall<T>(this ILGenerator generator, MethodInfo method)
=> generator.ConstrainedCall(typeof (T), method);
/// <summary>
/// Performs a constrained virtual call to the given method, popping an address to storage location of the value or reference (and performing a null check if necessary) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="constrainedType">The type to constrain the call to</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator ConstrainedCall(this ILGenerator generator, Type constrainedType, MethodInfo method)
{
return generator.FluentEmit(OpCodes.Constrained, constrainedType)
.FluentEmit(OpCodes.Callvirt, method);
}
/// <summary>
/// Performs a constrained virtual tail call to the given method, popping an address to storage location of the value or reference (and performing a null check if necessary) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <typeparam name="T">The type to constrain the call to</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator ConstrainedTailCall<T>(this ILGenerator generator, MethodInfo method)
=> generator.ConstrainedTailCall(typeof(T), method);
/// <summary>
/// Performs a constrained virtual tail call to the given method, popping an address to storage location of the value or reference (and performing a null check if necessary) and the requisite number of arguments from the evaluation stack
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="constrainedType">The type to constrain the call to</param>
/// <param name="method">The method to call</param>
[PublicAPI]
public static ILGenerator ConstrainedTailCall(this ILGenerator generator, Type constrainedType, MethodInfo method)
{
return generator.FluentEmit(OpCodes.Constrained, constrainedType)
.FluentEmit(OpCodes.Tailcall)
.FluentEmit(OpCodes.Callvirt, method);
}
/// <summary>
/// Pops a value from the evaluation stack and returns it to the calling method
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator Return(this ILGenerator generator) => generator.FluentEmit(OpCodes.Ret);
}
}