ILGenerator.Emit Method (OpCode, Label[])
Puts the specified instruction onto the Microsoft intermediate language (MSIL) stream and leaves space to include a label when fixes are done.
[Visual Basic] Overloads Public Overridable Sub Emit( _ ByVal opcode As OpCode, _ ByVal labels() As Label _ ) [C#] public virtual void Emit( OpCode opcode, Label[] labels ); [C++] public: virtual void Emit( OpCode opcode, Label labels[] ); [JScript] public function Emit( opcode : OpCode, labels : Label[] );
Parameters
- opcode
- The Microsoft intermediate language (MSIL) instruction to be emitted onto the stream.
- labels
- The array of label objects to which to branch from this location. All of the labels will be used.
Remarks
Emits a switch table.
The instruction values are defined in the OpCodes enumeration.Labels are created using DefineLabel and their location within the stream is fixed by using MarkLabel. If a single-byte instruction is used, the label can represent a jump of at most 127 bytes along the stream. instruction must represent a branch instruction. Since branches are relative instructions, label will be replaced with the correct offset to branch during the fixup process.
Example
[Visual Basic, C#, C++] The code sample below illustrates the creation of a dynamic method with a jump table. The jump table is built using an array of Label.
[Visual Basic] Imports System Imports System.Threading Imports System.Reflection Imports System.Reflection.Emit _ Class DynamicJumpTableDemo Public Shared Function BuildMyType() As Type Dim myDomain As AppDomain = Thread.GetDomain() Dim myAsmName As New AssemblyName() myAsmName.Name = "MyDynamicAssembly" Dim myAsmBuilder As AssemblyBuilder = myDomain.DefineDynamicAssembly(myAsmName, _ AssemblyBuilderAccess.Run) Dim myModBuilder As ModuleBuilder = myAsmBuilder.DefineDynamicModule("MyJumpTableDemo") Dim myTypeBuilder As TypeBuilder = myModBuilder.DefineType("JumpTableDemo", _ TypeAttributes.Public) Dim myMthdBuilder As MethodBuilder = myTypeBuilder.DefineMethod("SwitchMe", _ MethodAttributes.Public Or MethodAttributes.Static, _ GetType(String), New Type() {GetType(Integer)}) Dim myIL As ILGenerator = myMthdBuilder.GetILGenerator() Dim defaultCase As Label = myIL.DefineLabel() Dim endOfMethod As Label = myIL.DefineLabel() ' We are initializing our jump table. Note that the labels ' will be placed later using the MarkLabel method. Dim jumpTable() As Label = {myIL.DefineLabel(), _ myIL.DefineLabel(), _ myIL.DefineLabel(), _ myIL.DefineLabel(), _ myIL.DefineLabel()} ' arg0, the number we passed, is pushed onto the stack. ' In this case, due to the design of the code sample, ' the value pushed onto the stack happens to match the ' index of the label (in IL terms, the index of the offset ' in the jump table). If this is not the case, such as ' when switching based on non-integer values, rules for the correspondence ' between the possible case values and each index of the offsets ' must be established outside of the ILGenerator.Emit calls, ' much as a compiler would. myIL.Emit(OpCodes.Ldarg_0) myIL.Emit(OpCodes.Switch, jumpTable) ' Branch on default case myIL.Emit(OpCodes.Br_S, defaultCase) ' Case arg0 = 0 myIL.MarkLabel(jumpTable(0)) myIL.Emit(OpCodes.Ldstr, "are no bananas") myIL.Emit(OpCodes.Br_S, endOfMethod) ' Case arg0 = 1 myIL.MarkLabel(jumpTable(1)) myIL.Emit(OpCodes.Ldstr, "is one banana") myIL.Emit(OpCodes.Br_S, endOfMethod) ' Case arg0 = 2 myIL.MarkLabel(jumpTable(2)) myIL.Emit(OpCodes.Ldstr, "are two bananas") myIL.Emit(OpCodes.Br_S, endOfMethod) ' Case arg0 = 3 myIL.MarkLabel(jumpTable(3)) myIL.Emit(OpCodes.Ldstr, "are three bananas") myIL.Emit(OpCodes.Br_S, endOfMethod) ' Case arg0 = 4 myIL.MarkLabel(jumpTable(4)) myIL.Emit(OpCodes.Ldstr, "are four bananas") myIL.Emit(OpCodes.Br_S, endOfMethod) ' Default case myIL.MarkLabel(defaultCase) myIL.Emit(OpCodes.Ldstr, "are many bananas") myIL.MarkLabel(endOfMethod) myIL.Emit(OpCodes.Ret) Return myTypeBuilder.CreateType() End Function 'BuildMyType Public Shared Sub Main() Dim myType As Type = BuildMyType() Console.Write("Enter an integer between 0 and 5: ") Dim theValue As Integer = Convert.ToInt32(Console.ReadLine()) Console.WriteLine("---") Dim myInstance As [Object] = Activator.CreateInstance(myType, New Object() {}) Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe", _ BindingFlags.InvokeMethod, Nothing, _ myInstance, New Object() {theValue})) End Sub 'Main End Class 'DynamicJumpTableDemo [C#] using System; using System.Threading; using System.Reflection; using System.Reflection.Emit; class DynamicJumpTableDemo { public static Type BuildMyType() { AppDomain myDomain = Thread.GetDomain(); AssemblyName myAsmName = new AssemblyName(); myAsmName.Name = "MyDynamicAssembly"; AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly( myAsmName, AssemblyBuilderAccess.Run); ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule( "MyJumpTableDemo"); TypeBuilder myTypeBuilder = myModBuilder.DefineType("JumpTableDemo", TypeAttributes.Public); MethodBuilder myMthdBuilder = myTypeBuilder.DefineMethod("SwitchMe", MethodAttributes.Public | MethodAttributes.Static, typeof(string), new Type[] {typeof(int)}); ILGenerator myIL = myMthdBuilder.GetILGenerator(); Label defaultCase = myIL.DefineLabel(); Label endOfMethod = myIL.DefineLabel(); // We are initializing our jump table. Note that the labels // will be placed later using the MarkLabel method. Label[] jumpTable = new Label[] { myIL.DefineLabel(), myIL.DefineLabel(), myIL.DefineLabel(), myIL.DefineLabel(), myIL.DefineLabel() }; // arg0, the number we passed, is pushed onto the stack. // In this case, due to the design of the code sample, // the value pushed onto the stack happens to match the // index of the label (in IL terms, the index of the offset // in the jump table). If this is not the case, such as // when switching based on non-integer values, rules for the correspondence // between the possible case values and each index of the offsets // must be established outside of the ILGenerator.Emit calls, // much as a compiler would. myIL.Emit(OpCodes.Ldarg_0); myIL.Emit(OpCodes.Switch, jumpTable); // Branch on default case myIL.Emit(OpCodes.Br_S, defaultCase); // Case arg0 = 0 myIL.MarkLabel(jumpTable[0]); myIL.Emit(OpCodes.Ldstr, "are no bananas"); myIL.Emit(OpCodes.Br_S, endOfMethod); // Case arg0 = 1 myIL.MarkLabel(jumpTable[1]); myIL.Emit(OpCodes.Ldstr, "is one banana"); myIL.Emit(OpCodes.Br_S, endOfMethod); // Case arg0 = 2 myIL.MarkLabel(jumpTable[2]); myIL.Emit(OpCodes.Ldstr, "are two bananas"); myIL.Emit(OpCodes.Br_S, endOfMethod); // Case arg0 = 3 myIL.MarkLabel(jumpTable[3]); myIL.Emit(OpCodes.Ldstr, "are three bananas"); myIL.Emit(OpCodes.Br_S, endOfMethod); // Case arg0 = 4 myIL.MarkLabel(jumpTable[4]); myIL.Emit(OpCodes.Ldstr, "are four bananas"); myIL.Emit(OpCodes.Br_S, endOfMethod); // Default case myIL.MarkLabel(defaultCase); myIL.Emit(OpCodes.Ldstr, "are many bananas"); myIL.MarkLabel(endOfMethod); myIL.Emit(OpCodes.Ret); return myTypeBuilder.CreateType(); } public static void Main() { Type myType = BuildMyType(); Console.Write("Enter an integer between 0 and 5: "); int theValue = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("---"); Object myInstance = Activator.CreateInstance(myType, new object[0]); Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe", BindingFlags.InvokeMethod, null, myInstance, new object[] {theValue})); } } [C++] #using <mscorlib.dll> using namespace System; using namespace System::Threading; using namespace System::Reflection; using namespace System::Reflection::Emit; Type* BuildMyType() { AppDomain* myDomain = Thread::GetDomain(); AssemblyName* myAsmName = new AssemblyName(); myAsmName->Name = S"MyDynamicAssembly"; AssemblyBuilder* myAsmBuilder = myDomain->DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess::Run); ModuleBuilder* myModBuilder = myAsmBuilder->DefineDynamicModule(S"MyJumpTableDemo"); TypeBuilder* myTypeBuilder = myModBuilder->DefineType(S"JumpTableDemo", TypeAttributes::Public); Type* temp0 [] = {__typeof(int)}; MethodBuilder* myMthdBuilder = myTypeBuilder->DefineMethod( S"SwitchMe", static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::Static), __typeof(String), temp0); ILGenerator* myIL = myMthdBuilder->GetILGenerator(); Label defaultCase = myIL->DefineLabel(); Label endOfMethod = myIL->DefineLabel(); // We are initializing our jump table. Note that the labels // will be placed later using the MarkLabel method. Label jumpTable [] = new Label[5]; jumpTable[0] = myIL->DefineLabel(); jumpTable[1] = myIL->DefineLabel(); jumpTable[2] = myIL->DefineLabel(); jumpTable[3] = myIL->DefineLabel(); jumpTable[4] = myIL->DefineLabel(); // arg0, the number we passed, is pushed onto the stack. // In this case, due to the design of the code sample, // the value pushed onto the stack happens to match the // index of the label (in IL terms, the index of the offset // in the jump table). If this is not the case, such as // when switching based on non-integer values, rules for the correspondence // between the possible case values and each index of the offsets // must be established outside of the ILGenerator::Emit calls, // much as a compiler would. myIL->Emit(OpCodes::Ldarg_0); myIL->Emit(OpCodes::Switch, jumpTable); // Branch on default case myIL->Emit(OpCodes::Br_S, defaultCase); // Case arg0 = 0 myIL->MarkLabel(jumpTable[0]); myIL->Emit(OpCodes::Ldstr, S"are no bananas"); myIL->Emit(OpCodes::Br_S, endOfMethod); // Case arg0 = 1 myIL->MarkLabel(jumpTable[1]); myIL->Emit(OpCodes::Ldstr, S"is one banana"); myIL->Emit(OpCodes::Br_S, endOfMethod); // Case arg0 = 2 myIL->MarkLabel(jumpTable[2]); myIL->Emit(OpCodes::Ldstr, S"are two bananas"); myIL->Emit(OpCodes::Br_S, endOfMethod); // Case arg0 = 3 myIL->MarkLabel(jumpTable[3]); myIL->Emit(OpCodes::Ldstr, S"are three bananas"); myIL->Emit(OpCodes::Br_S, endOfMethod); // Case arg0 = 4 myIL->MarkLabel(jumpTable[4]); myIL->Emit(OpCodes::Ldstr, S"are four bananas"); myIL->Emit(OpCodes::Br_S, endOfMethod); // Default case myIL->MarkLabel(defaultCase); myIL->Emit(OpCodes::Ldstr, S"are many bananas"); myIL->MarkLabel(endOfMethod); myIL->Emit(OpCodes::Ret); return myTypeBuilder->CreateType(); } int main() { Type* myType = BuildMyType(); Console::Write(S"Enter an integer between 0 and 5: "); int theValue = Convert::ToInt32(Console::ReadLine()); Console::WriteLine(S"---"); Object* myInstance = Activator::CreateInstance(myType, new Object*[0]); Object* temp1 [] = {__box(theValue)}; Console::WriteLine(S"Yes, there {0} today!", myType->InvokeMember(S"SwitchMe", BindingFlags::InvokeMethod, 0, myInstance, temp1)); }
[JScript] No example is available for JScript. To view a Visual Basic, C#, or C++ example, click the Language Filter button
in the upper-left corner of the page.
Requirements
Platforms: Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 family
See Also
ILGenerator Class | ILGenerator Members | System.Reflection.Emit Namespace | ILGenerator.Emit Overload List