代码改变世界

Emit基础学习-选择分支

2009-07-13 09:51  Kevin-wang  阅读(389)  评论(0编辑  收藏  举报

 

 

C#代码

int sum = 0;
if (num1 > 0)
{
     sum 
= num1 + 100;
}


IL代码

    .maxstack 2
    
.locals init (
        [
0int32 num,
        [
1bool flag)
    
L_0000: ldc.i4.0 
    
L_0001: stloc.0 
    
L_0002: ldc.i4.0 
    
L_0003: stloc.1 
    
L_0004: ldarg.0 
    
L_0005: ldc.i4.0 
    
L_0006: cgt 
    
L_0008: ldc.i4.0 
    
L_0009: ceq 
    
L_000b: stloc.1 
    
L_000c: ldloc.1 
    
L_000d: brtrue.s L_0017
    
L_000f: ldarg.0 
    
L_0010: ldc.i4 100
    
L_0015: add 
    
L_0016: stloc.0 
    
L_0017: ret 

 

 

Emit代码

_Method = _TypeBuilder.DefineMethod("Dotest4",
          MethodAttributes.Public 
|MethodAttributes.Static,
          
null,new Type[] { typeof(int) });
_MethodIL 
= _Method.GetILGenerator();
l1 
= _MethodIL.DefineLabel();
// l2 = _MethodIL.DefineLabel();
//int _Sum=0;
LocalBuilder _v1 = _MethodIL.DeclareLocal(typeof(int));
_MethodIL.Emit(OpCodes.Ldc_I4_0);
_MethodIL.Emit(OpCodes.Stloc_0);

LocalBuilder _v2 
= _MethodIL.DeclareLocal(typeof(bool));
_MethodIL.Emit(OpCodes.Ldc_I4_0);
_MethodIL.Emit(OpCodes.Stloc_1);

_MethodIL.Emit(OpCodes.Ldarg_0);
_MethodIL.Emit(OpCodes.Ldc_I4_0);
_MethodIL.Emit(OpCodes.Cgt);

_MethodIL.Emit(OpCodes.Ldc_I4_0);
_MethodIL.Emit(OpCodes.Ceq);

_MethodIL.Emit(OpCodes.Stloc_1);

_MethodIL.Emit(OpCodes.Ldloc_1);

_MethodIL.Emit(OpCodes.Brtrue_S, l1);
//_sum=pNum+100;
_MethodIL.Emit(OpCodes.Ldarg_0);
_MethodIL.Emit(OpCodes.Ldc_I4, 
100);
_MethodIL.Emit(OpCodes.Add);
_MethodIL.Emit(OpCodes.Stloc_0);

_MethodIL.MarkLabel(l1);
_MethodIL.Emit(OpCodes.Ret);

C#代码条件表达式
使用Emit生成IL后反射的C#代码

return ((num1 > 100? -1 : 0);


手工编写的代码

return ((num > 100? -1 : 0);
   

IL代码
使用Emit生成的IL代码

.maxstack 3
L_0000: ldarg.0
L_0001: ldc.i4.s 100
L_0003: nop
L_0004: nop
L_0005: nop
L_0006: bgt.s L_000b
L_0008: ldc.i4.0
L_0009: br.s L_000c
L_000b: ldc.i4.m1
L_000c: ret


手工编写的代生成的IL代码

    .maxstack 2
    
.locals init (
        [
0int32 CS$1$0000)
    
L_0000: nop 
    
L_0001: ldarg.0 
    
L_0002: ldc.i4.s 100
    
L_0004: bgt.s L_0009
    
L_0006: ldc.i4.0 
    
L_0007: br.s L_000a
    
L_0009: ldc.i4.m1 
    
L_000a: stloc.0 
    
L_000b: br.s L_000d
    
L_000d: ldloc.0 
    
L_000e: ret


Emit代码

_Method = _TypeBuilder.DefineMethod("Dotest1",MethodAttributes.Public | MethodAttributes.Static,
    
typeof(int), new Type[] { typeof(int) });

_MethodIL 
= _Method.GetILGenerator();
failed 
= _MethodIL.DefineLabel();
endOfMthd 
= _MethodIL.DefineLabel();

//生成代码 
//if (num1 > 100)
//将索引为 0 的参数加载到计算堆栈上。
_MethodIL.Emit(OpCodes.Ldarg_0);
//将提供的 int8 值作为 int32 推送到计算堆栈上
_MethodIL.Emit(OpCodes.Ldc_I4_S, 100);
//如果第一个值大于第二个值,则将控制转移到目标指令
_MethodIL.Emit(OpCodes.Bgt_S, failed);

_MethodIL.Emit(OpCodes.Ldc_I4_0);
_MethodIL.Emit(OpCodes.Br_S, endOfMthd);

_MethodIL.MarkLabel(failed);
_MethodIL.Emit(OpCodes.Ldc_I4_M1);


_MethodIL.MarkLabel(endOfMthd);

_MethodIL.Emit(OpCodes.Ret);


Switch分支

C#代码

switch (num1)
{
    
case 4:
        
return 30;

    
case 7:
        
return 0x1f;

    
case 8:
        
return 0x1d;
}
return 0x1c;


生成的IL代码

.method public static int32 Dotest5(int32cil managed
{
    
.maxstack 7
    
.locals init (
        [
0int32 num,
        [
1int32 num2,
        [
2int32 num3)
    
L_0000: nop 
    
L_0001: ldc.i4.0 
    
L_0002: stloc.0 
    
L_0003: ldarg.0 
    
L_0004: stloc.2 
    
L_0005: ldloc.2 
    
L_0006: ldc.i4.4 
    
L_0007: beq.s L_0013
    
L_0009: ldloc.2 
    
L_000a: ldc.i4.7 
    
L_000b: beq.s L_001b
    
L_000d: ldloc.2 
    
L_000e: ldc.i4.8 
    
L_000f: beq.s L_0023
    
L_0011: br.s L_002b
    
L_0013: ldc.i4.s 30
    
L_0015: nop 
    
L_0016: nop 
    
L_0017: nop 
    
L_0018: stloc.0 
    
L_0019: br.s L_0033
    
L_001b: ldc.i4.s 0x1f
    
L_001d: nop 
    
L_001e: nop 
    
L_001f: nop 
    
L_0020: stloc.0 
    
L_0021: br.s L_0033
    
L_0023: ldc.i4.s 0x1d
    
L_0025: nop 
    
L_0026: nop 
    
L_0027: nop 
    
L_0028: stloc.0 
    
L_0029: br.s L_0033
    
L_002b: ldc.i4.s 0x1c
    
L_002d: nop 
    
L_002e: nop 
    
L_002f: nop 
    
L_0030: stloc.0 
    
L_0031: br.s L_0033
    
L_0033: ldloc.0 
    
L_0034: ret 
}


Emit生成代码


  _Method = _TypeBuilder.DefineMethod("Dotest5",
  MethodAttributes.Public 
| MethodAttributes.Static,
  
typeof(int), new Type[] { typeof(int) });

  _MethodIL 
= _Method.GetILGenerator();


  Label[] _Lbls 
= new Label[3];
  
//默认(switch语句的default节点)
  Label _defaultLabel = _MethodIL.DefineLabel();
  
//endswitch
  Label _endswitch = _MethodIL.DefineLabel();
  Label _endswitch2 
= _MethodIL.DefineLabel();

  
for (int i = 0; i < _Lbls.Length; i++)
  {
      _Lbls[i] 
= _MethodIL.DefineLabel();
  }
  
//声明变量 
  
//int result=0;
  LocalBuilder _result = _MethodIL.DeclareLocal(typeof(int));
  LocalBuilder _num1 
= _MethodIL.DeclareLocal(typeof(int));
  LocalBuilder _num2 
= _MethodIL.DeclareLocal(typeof(int));
  _MethodIL.Emit(OpCodes.Nop);

  _MethodIL.Emit(OpCodes.Ldc_I4_0);
  _MethodIL.Emit(OpCodes.Stloc_0);



  _MethodIL.Emit(OpCodes.Ldarg_0);
  _MethodIL.Emit(OpCodes.Stloc_2);

  
//_MethodIL.Emit(OpCodes.Switch, _Lbls);
  
//            L_0005: ldloc.2 
  
//L_0006: ldc.i4.4 
  
//L_0007: beq.s L_000f  //如果两个值相等,则将控制转移到目标指令。
  _MethodIL.Emit(OpCodes.Ldloc_2);
  _MethodIL.Emit(OpCodes.Ldc_I4_4);
  _MethodIL.Emit(OpCodes.Beq_S, _Lbls[
0]);

  _MethodIL.Emit(OpCodes.Ldloc_2);
  _MethodIL.Emit(OpCodes.Ldc_I4_7);
  _MethodIL.Emit(OpCodes.Beq_S, _Lbls[
1]);

  _MethodIL.Emit(OpCodes.Ldloc_2);
  _MethodIL.Emit(OpCodes.Ldc_I4_8);
  _MethodIL.Emit(OpCodes.Beq_S, _Lbls[
2]);

  _MethodIL.Emit(OpCodes.Br_S, _defaultLabel);


  _MethodIL.MarkLabel(_Lbls[
0]);
  _MethodIL.Emit(OpCodes.Ldc_I4_S, 
30);
  _MethodIL.Emit(OpCodes.Stloc_0);
  _MethodIL.Emit(OpCodes.Br_S, _endswitch);

  _MethodIL.MarkLabel(_Lbls[
1]);
  _MethodIL.Emit(OpCodes.Ldc_I4_S, 
31);
  _MethodIL.Emit(OpCodes.Stloc_0);
  _MethodIL.Emit(OpCodes.Br_S, _endswitch);

  _MethodIL.MarkLabel(_Lbls[
2]);
  _MethodIL.Emit(OpCodes.Ldc_I4_S, 
29);
  _MethodIL.Emit(OpCodes.Stloc_0);
  _MethodIL.Emit(OpCodes.Br_S, _endswitch);

  _MethodIL.MarkLabel(_defaultLabel);
  _MethodIL.Emit(OpCodes.Ldc_I4_S, 
28);
  _MethodIL.Emit(OpCodes.Stloc_0);
  _MethodIL.Emit(OpCodes.Br_S, _endswitch);

  _MethodIL.MarkLabel(_endswitch);

  _MethodIL.Emit(OpCodes.Ldloc_0);

  _MethodIL.Emit(OpCodes.Ret);