I am dynamically Emitting a switch statement using System.Reflection.Emit.
I have used the ILDASM and copied a switch statement’s syntax as a reference. I run my code to build the function and I got an Illegal One-Byte branch exception. I figured out that the first couple of (break;) jumps use Br and the rest use Br_S. I then wrote another switch function example with a different number of cases and looked at the IL code. It uses a different number of Br statements at the beginning before using Br_S for the rest of the (break;) jumps. There is no good documentation on the difference between short form and normal form.
How do you know if you are supposed to use Br or Br_S?
--------------------------------------------
ILCODE EXAMPLE ONE
--------------------------------------------
IL_0111: switch (
IL_014b,
IL_015c,
IL_016a,
IL_0178,
IL_0186,
IL_0194,
IL_01a2,
IL_01ab,
IL_01b4,
IL_01bd,
IL_01c6,
IL_01cf)
IL_0146: br IL_01d8
IL_014b: ldarg.0
IL_014c: ldfld int32 [Northwind]Northwind.Order::orderId
IL_0151: box [mscorlib]System.Int32
IL_0156: stloc.0
IL_0157: br IL_01de
IL_015c: ldarg.0
IL_015d: ldfld valuetype [mscorlib]System.DateTime [Northwind]Northwind.Order::orderDate
IL_0162: box [mscorlib]System.DateTime
IL_0167: stloc.0
IL_0168: br.s IL_01de
IL_016a: ldarg.0
IL_016b: ldfld valuetype [mscorlib]System.DateTime [Northwind]Northwind.Order::requiredDate
IL_0170: box [mscorlib]System.DateTime
IL_0175: stloc.0
IL_0176: br.s IL_01de
--------------------------------------------
ILCODE EXAMPLE TWO
--------------------------------------------
IL_016b: switch (
IL_01b9,
IL_01ca,
IL_01d6,
IL_01e2,
IL_01ee,
IL_01fa,
IL_0208,
IL_0216,
IL_021f,
IL_0228,
IL_0231,
IL_023a,
IL_0243,
IL_024c,
IL_0255,
IL_025e,
IL_026c)
IL_01b4: br IL_0275
IL_01b9: ldarg.0
IL_01ba: ldfld int32 [Northwind]Northwind.Employee::employeeId
IL_01bf: box [mscorlib]System.Int32
IL_01c4: stloc.0
IL_01c5: br IL_027b
IL_01ca: ldarg.0
IL_01cb: call instance string [Northwind]Northwind.Employee::get_FirstName()
IL_01d0: stloc.0
IL_01d1: br IL_027b
IL_01d6: ldarg.0
IL_01d7: call instance string [Northwind]Northwind.Employee::get_LastName()
IL_01dc: stloc.0
IL_01dd: br IL_027b
IL_01e2: ldarg.0
IL_01e3: call instance string [Northwind]Northwind.Employee::get_Title()
IL_01e8: stloc.0
IL_01e9: br IL_027b
IL_01ee: ldarg.0
IL_01ef: call instance string [Northwind]Northwind.Employee::get_TitleOfCourtesy()
IL_01f4: stloc.0
IL_01f5: br IL_027b
IL_01fa: ldarg.0
IL_01fb: call instance valuetype [mscorlib]System.DateTime [Northwind]Northwind.Employee::get_BirthDate()
IL_0200: box [mscorlib]System.DateTime
IL_0205: stloc.0
IL_0206: br.s IL_027b
IL_0208: ldarg.0
IL_0209: call instance valuetype [mscorlib]System.DateTime [Northwind]Northwind.Employee::get_HireDate()
IL_020e: box [mscorlib]System.DateTime
IL_0213: stloc.0
IL_0214: br.s IL_027b
Holger Grund - 25 Jul 2004 18:01 GMT
> I am dynamically Emitting a switch statement using System.Reflection.Emit.
> I have used the ILDASM and copied a switch statement's syntax as a
reference. I run my code to build the function and I got an Illegal
One-Byte branch exception. I figured out that the first couple of (break;)
jumps use Br and the rest use Br_S. I then wrote another switch function
example with a different number of cases and looked at the IL code. It uses
a different number of Br statements at the beginning before using Br_S for
the rest of the (break;) jumps. There is no good documentation on the
difference between short form and normal form.
> How do you know if you are supposed to use Br or Br_S?
Well, you use br if the branch target is not in a range which can be
expressed in a 8 bit signed integer (the long form encodes the
offset in 32 bits).
BTW: CIL supports a switch instruction, which might do what you
want. Or did you use it?
> IL_0146: br IL_01d8
The offset is from the instruction after the "br". A "br.s"
is two bytes in size.
0x1d8-(0x146+2) = 0x90 > 0x7f => need a 32 bit offset
> IL_0168: br.s IL_01de
0x1de-0x16a = 0x74 < 0x7f => 8 bit offset is fine - use br.s
-hg