Exemplo n.º 1
0
 private InstructionBlock InstructionsFromCCIMethodFrom(CCI.Method method, ref int i)
 {
     var instructions = new AList<Instruction>();
     while (i < method.Instructions.Count)
     {
         var instruction = method.Instructions[i++];
         if (instruction.OpCode == CCI.OpCode._Locals)
         {
             // Skip: already captured and fixed locals in MethodDefFromCCIMethod
         }
         else
         {
             var offset = instruction.Offset;
             while (instruction.OpCode == CCI.OpCode.Unaligned_ || instruction.OpCode == CCI.OpCode.Volatile_ ||
                    instruction.OpCode == CCI.OpCode.Tail_)
             {
                 // Skip over any ignored prefixes, but remember instruction begins at original offset
                 // NOTE: What ever happened to the "no." prefix mentioned in the spec?
                 if (i >= method.Instructions.Count)
                     throw new InvalidOperationException("invalid instructions");
                 instruction = method.Instructions[i++];
             }
             switch (instruction.OpCode)
             {
             case CCI.OpCode.Cpblk:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Cpblk));
                 break;
             case CCI.OpCode.Initblk:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Initblk));
                 break;
             case CCI.OpCode.Arglist:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Arglist));
                 break;
             case CCI.OpCode.Localloc:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Localloc));
                 break;
             case CCI.OpCode.Jmp:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Jmp));
                 break;
             case CCI.OpCode.Calli:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Calli));
                 break;
             case CCI.OpCode.Sizeof:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Sizeof));
                 break;
             case CCI.OpCode.Mkrefany:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Mkrefany));
                 break;
             case CCI.OpCode.Refanytype:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Refanytype));
                 break;
             case CCI.OpCode.Refanyval:
                 instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Refanyval));
                 break;
             case CCI.OpCode.Nop:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Nop));
                 break;
             case CCI.OpCode.Break:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Break));
                 break;
             case CCI.OpCode.Dup:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Dup));
                 break;
             case CCI.OpCode.Pop:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Pop));
                 break;
             case CCI.OpCode.Ldnull:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Ldnull));
                 break;
             case CCI.OpCode.Ckfinite:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Ckfinite));
                 break;
             case CCI.OpCode.Throw:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Throw));
                 break;
             case CCI.OpCode.Rethrow:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Rethrow));
                 break;
             case CCI.OpCode.Ldind_Ref:
                 instructions.Add(new MiscInstruction(offset, MiscOp.LdindRef));
                 break;
             case CCI.OpCode.Stind_Ref:
                 instructions.Add(new MiscInstruction(offset, MiscOp.StindRef));
                 break;
             case CCI.OpCode.Ldelem_Ref:
                 instructions.Add(new MiscInstruction(offset, MiscOp.LdelemRef));
                 break;
             case CCI.OpCode.Stelem_Ref:
                 instructions.Add(new MiscInstruction(offset, MiscOp.StelemRef));
                 break;
             case CCI.OpCode.Ldlen:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Ldlen));
                 break;
             case CCI.OpCode.Ret:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Ret));
                 break;
             case CCI.OpCode.Endfilter:
                 instructions.Add(new MiscInstruction(offset, MiscOp.Endfilter));
                 break;
             case CCI.OpCode.Endfinally: // aka EndFault
                 instructions.Add(new MiscInstruction(offset, MiscOp.Endfinally));
                 break;
             case CCI.OpCode.Br_S:
             case CCI.OpCode.Br:
                 instructions.Add(new BranchInstruction(offset, BranchOp.Br, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Brtrue_S: // aka brinst.s
             case CCI.OpCode.Brtrue: // aka brinst
                 instructions.Add
                     (new BranchInstruction(offset, BranchOp.Brtrue, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Brfalse_S: // aka brzero.s, brnull.s
             case CCI.OpCode.Brfalse: // aka brzero, brnull
                 instructions.Add
                     (new BranchInstruction(offset, BranchOp.Brfalse, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Beq:
             case CCI.OpCode.Beq_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.Breq, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Bne_Un:
             case CCI.OpCode.Bne_Un_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.Brne, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Leave:
             case CCI.OpCode.Leave_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.Leave, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Blt:
             case CCI.OpCode.Blt_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrLt, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Blt_Un:
             case CCI.OpCode.Blt_Un_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrLt, true, (int)instruction.Value));
                 break;
             case CCI.OpCode.Ble:
             case CCI.OpCode.Ble_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrLe, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Ble_Un:
             case CCI.OpCode.Ble_Un_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrLe, true, (int)instruction.Value));
                 break;
             case CCI.OpCode.Bgt:
             case CCI.OpCode.Bgt_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrGt, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Bgt_Un:
             case CCI.OpCode.Bgt_Un_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrGt, true, (int)instruction.Value));
                 break;
             case CCI.OpCode.Bge:
             case CCI.OpCode.Bge_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrGe, false, (int)instruction.Value));
                 break;
             case CCI.OpCode.Bge_Un:
             case CCI.OpCode.Bge_Un_S:
                 instructions.Add(new BranchInstruction(offset, BranchOp.BrGe, true, (int)instruction.Value));
                 break;
             case CCI.OpCode.Switch:
                 {
                     var targets = new AList<int>();
                     var ccitargets = (CCI.Int32List)instruction.Value;
                     for (var j = 0; j < ccitargets.Count; j++)
                         targets.Add(ccitargets[j]);
                     instructions.Add(new SwitchInstruction(offset, targets));
                     break;
                 }
             case CCI.OpCode.Ceq:
                 instructions.Add(new CompareInstruction(offset, CompareOp.Ceq, false));
                 break;
             case CCI.OpCode.Clt:
                 instructions.Add(new CompareInstruction(offset, CompareOp.Clt, false));
                 break;
             case CCI.OpCode.Clt_Un:
                 instructions.Add(new CompareInstruction(offset, CompareOp.Clt, true));
                 break;
             case CCI.OpCode.Cgt:
                 instructions.Add(new CompareInstruction(offset, CompareOp.Cgt, false));
                 break;
             case CCI.OpCode.Cgt_Un:
                 instructions.Add(new CompareInstruction(offset, CompareOp.Cgt, true));
                 break;
             case CCI.OpCode.Ldarg_0:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 0));
                 break;
             case CCI.OpCode.Ldarg_1:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 1));
                 break;
             case CCI.OpCode.Ldarg_2:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 2));
                 break;
             case CCI.OpCode.Ldarg_3:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 3));
                 break;
             case CCI.OpCode.Ldarg:
             case CCI.OpCode.Ldarg_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.Ld,
                           ArgLocal.Arg,
                           TrueArgFromCCIParameter(method, (CCI.Parameter)instruction.Value)));
                 break;
             case CCI.OpCode.Ldarga:
             case CCI.OpCode.Ldarga_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.Lda,
                           ArgLocal.Arg,
                           TrueArgFromCCIParameter(method, (CCI.Parameter)instruction.Value)));
                 break;
             case CCI.OpCode.Starg:
             case CCI.OpCode.Starg_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.St,
                           ArgLocal.Arg,
                           TrueArgFromCCIParameter(method, (CCI.Parameter)instruction.Value)));
                 break;
             case CCI.OpCode.Ldloc_0:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 0));
                 break;
             case CCI.OpCode.Ldloc_1:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 1));
                 break;
             case CCI.OpCode.Ldloc_2:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 2));
                 break;
             case CCI.OpCode.Ldloc_3:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 3));
                 break;
             case CCI.OpCode.Ldloc:
             case CCI.OpCode.Ldloc_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.Ld,
                           ArgLocal.Local,
                           TrueLocalFromCCILocal(method, (CCI.Local)instruction.Value)));
                 break;
             case CCI.OpCode.Ldloca:
             case CCI.OpCode.Ldloca_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.Lda,
                           ArgLocal.Local,
                           TrueLocalFromCCILocal(method, (CCI.Local)instruction.Value)));
                 break;
             case CCI.OpCode.Stloc_0:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 0));
                 break;
             case CCI.OpCode.Stloc_1:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 1));
                 break;
             case CCI.OpCode.Stloc_2:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 2));
                 break;
             case CCI.OpCode.Stloc_3:
                 instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 3));
                 break;
             case CCI.OpCode.Stloc:
             case CCI.OpCode.Stloc_S:
                 instructions.Add
                     (new ArgLocalInstruction
                          (offset,
                           ArgLocalOp.St,
                           ArgLocal.Local,
                           TrueLocalFromCCILocal(method, (CCI.Local)instruction.Value)));
                 break;
             case CCI.OpCode.Ldfld:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Ldfld, FieldRefFromCCIField((CCI.Field)instruction.Value), false));
                 break;
             case CCI.OpCode.Ldsfld:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Ldfld, FieldRefFromCCIField((CCI.Field)instruction.Value), true));
                 break;
             case CCI.OpCode.Ldflda:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Ldflda, FieldRefFromCCIField((CCI.Field)instruction.Value), false));
                 break;
             case CCI.OpCode.Ldsflda:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Ldflda, FieldRefFromCCIField((CCI.Field)instruction.Value), true));
                 break;
             case CCI.OpCode.Stfld:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Stfld, FieldRefFromCCIField((CCI.Field)instruction.Value), false));
                 break;
             case CCI.OpCode.Stsfld:
                 instructions.Add
                     (new FieldInstruction
                          (offset, FieldOp.Stfld, FieldRefFromCCIField((CCI.Field)instruction.Value), true));
                 break;
             case CCI.OpCode.Ldtoken:
                 {
                     var typeTok = instruction.Value as CCI.TypeNode;
                     if (typeTok != null)
                         instructions.Add
                             (new TypeInstruction(offset, TypeOp.Ldtoken, TypeRefFromCCIType(typeTok)));
                     else
                     {
                         var fieldTok = instruction.Value as CCI.Field;
                         if (fieldTok != null)
                             instructions.Add
                                 (new FieldInstruction(offset, FieldOp.Ldtoken, FieldRefFromCCIField(fieldTok), default(bool)));
                         else
                         {
                             var methodTok = instruction.Value as CCI.Method;
                             if (methodTok != null)
                                 instructions.Add
                                     (new MethodInstruction
                                          (offset,
                                           MethodOp.Ldtoken,
                                           null,
                                           false,
                                           MethodRefFromCCIMethod(methodTok)));
                             else
                                 throw new InvalidOperationException("invalid instruction");
                         }
                     }
                     break;
                 }
             case CCI.OpCode.Constrained_:
                 {
                     var constrained = (CCI.TypeNode)instruction.Value;
                     if (i >= method.Instructions.Count)
                         throw new InvalidOperationException("invalid instructions");
                     instruction = method.Instructions[i++];
                     if (instruction.OpCode != CCI.OpCode.Callvirt)
                         throw new InvalidOperationException("invalid instruction");
                     instructions.Add
                         (new MethodInstruction
                              (offset,
                               MethodOp.Call,
                               TypeRefFromCCIType(constrained),
                               true,
                               MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                     break;
                 }
             case CCI.OpCode.Call:
                 instructions.Add
                     (new MethodInstruction
                          (offset,
                           MethodOp.Call,
                           null,
                           false,
                           MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                 break;
             case CCI.OpCode.Callvirt:
                 instructions.Add
                     (new MethodInstruction
                          (offset,
                           MethodOp.Call,
                           null,
                           true,
                           MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                 break;
             case CCI.OpCode.Ldftn:
                 instructions.Add
                     (new MethodInstruction
                          (offset,
                           MethodOp.Ldftn,
                           null,
                           false,
                           MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                 break;
             case CCI.OpCode.Ldvirtftn:
                 instructions.Add
                     (new MethodInstruction
                          (offset,
                           MethodOp.Ldftn,
                           null,
                           true,
                           MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                 break;
             case CCI.OpCode.Newobj:
                 instructions.Add
                     (new MethodInstruction
                          (offset,
                           MethodOp.Newobj,
                           null,
                           false,
                           MethodRefFromCCIMethod((CCI.Method)instruction.Value)));
                 break;
             case CCI.OpCode.Ldind_I1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int8Ref));
                 break;
             case CCI.OpCode.Ldind_U1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.UInt8Ref));
                 break;
             case CCI.OpCode.Ldind_I2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int16Ref));
                 break;
             case CCI.OpCode.Ldind_U2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.UInt16Ref));
                 break;
             case CCI.OpCode.Ldind_I4:
             case CCI.OpCode.Ldind_U4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int32Ref));
                 break;
             case CCI.OpCode.Ldind_I8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int64Ref));
                 break;
             case CCI.OpCode.Ldind_I:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.IntNativeRef));
                 break;
             case CCI.OpCode.Ldind_R4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.SingleRef));
                 break;
             case CCI.OpCode.Ldind_R8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.DoubleRef));
                 break;
             case CCI.OpCode.Ldobj:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Ldobj, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Stind_I1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int8Ref));
                 break;
             case CCI.OpCode.Stind_I2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int16Ref));
                 break;
             case CCI.OpCode.Stind_I4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int32Ref));
                 break;
             case CCI.OpCode.Stind_I8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int64Ref));
                 break;
             case CCI.OpCode.Stind_I:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.IntNativeRef));
                 break;
             case CCI.OpCode.Stind_R4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.SingleRef));
                 break;
             case CCI.OpCode.Stind_R8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.DoubleRef));
                 break;
             case CCI.OpCode.Stobj:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Stobj, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Cpobj:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Cpobj, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Newarr:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Newarr, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Initobj:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Initobj, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Castclass:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Castclass, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Isinst:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Isinst, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Box:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Box, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Unbox:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Unbox, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Unbox_Any:
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.UnboxAny, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Ldelem_I1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int8Ref));
                 break;
             case CCI.OpCode.Ldelem_U1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.UInt8Ref));
                 break;
             case CCI.OpCode.Ldelem_I2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int16Ref));
                 break;
             case CCI.OpCode.Ldelem_U2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.UInt16Ref));
                 break;
             case CCI.OpCode.Ldelem_I4:
             case CCI.OpCode.Ldelem_U4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int32Ref));
                 break;
             case CCI.OpCode.Ldelem_I8: // aka ldelem.u8
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int64Ref));
                 break;
             case CCI.OpCode.Ldelem_I:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.IntNativeRef));
                 break;
             case CCI.OpCode.Ldelem_R4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.SingleRef));
                 break;
             case CCI.OpCode.Ldelem_R8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.DoubleRef));
                 break;
             case CCI.OpCode.Ldelem: // aka ldelem.any
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Ldelem, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Stelem_I1:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int8Ref));
                 break;
             case CCI.OpCode.Stelem_I2:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int16Ref));
                 break;
             case CCI.OpCode.Stelem_I4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int32Ref));
                 break;
             case CCI.OpCode.Stelem_I8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int64Ref));
                 break;
             case CCI.OpCode.Stelem_I:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.IntNativeRef));
                 break;
             case CCI.OpCode.Stelem_R4:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.SingleRef));
                 break;
             case CCI.OpCode.Stelem_R8:
                 instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.DoubleRef));
                 break;
             case CCI.OpCode.Stelem: // aka stelem.any
                 instructions.Add
                     (new TypeInstruction
                          (offset, TypeOp.Stelem, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Readonly_:
                 if (i >= method.Instructions.Count)
                     throw new InvalidOperationException("invalid instruction");
                 instruction = method.Instructions[i++];
                 if (instruction.OpCode != CCI.OpCode.Ldelema)
                     throw new InvalidOperationException("invalid instruction");
                 instructions.Add
                     (new LdElemAddrInstruction
                          (offset, true, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Ldelema:
                 instructions.Add
                     (new LdElemAddrInstruction
                          (offset, false, TypeRefFromCCIType((CCI.TypeNode)instruction.Value)));
                 break;
             case CCI.OpCode.Ldc_I4_0:
                 instructions.Add(new LdInt32Instruction(offset, 0));
                 break;
             case CCI.OpCode.Ldc_I4_1:
                 instructions.Add(new LdInt32Instruction(offset, 1));
                 break;
             case CCI.OpCode.Ldc_I4_2:
                 instructions.Add(new LdInt32Instruction(offset, 2));
                 break;
             case CCI.OpCode.Ldc_I4_3:
                 instructions.Add(new LdInt32Instruction(offset, 3));
                 break;
             case CCI.OpCode.Ldc_I4_4:
                 instructions.Add(new LdInt32Instruction(offset, 4));
                 break;
             case CCI.OpCode.Ldc_I4_5:
                 instructions.Add(new LdInt32Instruction(offset, 5));
                 break;
             case CCI.OpCode.Ldc_I4_6:
                 instructions.Add(new LdInt32Instruction(offset, 6));
                 break;
             case CCI.OpCode.Ldc_I4_7:
                 instructions.Add(new LdInt32Instruction(offset, 7));
                 break;
             case CCI.OpCode.Ldc_I4_8:
                 instructions.Add(new LdInt32Instruction(offset, 8));
                 break;
             case CCI.OpCode.Ldc_I4_M1:
                 instructions.Add(new LdInt32Instruction(offset, -1));
                 break;
             case CCI.OpCode.Ldc_I4:
             case CCI.OpCode.Ldc_I4_S:
                 instructions.Add(new LdInt32Instruction(offset, (int)instruction.Value));
                 break;
             case CCI.OpCode.Ldc_I8:
                 instructions.Add(new LdInt64Instruction(offset, (long)instruction.Value));
                 break;
             case CCI.OpCode.Ldc_R4:
                 instructions.Add(new LdSingleInstruction(offset, (float)instruction.Value));
                 break;
             case CCI.OpCode.Ldc_R8:
                 instructions.Add(new LdDoubleInstruction(offset, (double)instruction.Value));
                 break;
             case CCI.OpCode.Ldstr:
                 instructions.Add(new LdStringInstruction(offset, (string)instruction.Value));
                 break;
             case CCI.OpCode.Add:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Add, false, false));
                 break;
             case CCI.OpCode.Add_Ovf:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Add, true, false));
                 break;
             case CCI.OpCode.Add_Ovf_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Add, true, true));
                 break;
             case CCI.OpCode.Sub:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Sub, false, false));
                 break;
             case CCI.OpCode.Sub_Ovf:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Sub, true, false));
                 break;
             case CCI.OpCode.Sub_Ovf_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Sub, true, true));
                 break;
             case CCI.OpCode.Mul:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Mul, false, false));
                 break;
             case CCI.OpCode.Mul_Ovf:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Mul, true, false));
                 break;
             case CCI.OpCode.Mul_Ovf_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Mul, true, true));
                 break;
             case CCI.OpCode.Div:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Div, false, false));
                 break;
             case CCI.OpCode.Div_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Div, false, true));
                 break;
             case CCI.OpCode.Rem:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Rem, false, false));
                 break;
             case CCI.OpCode.Rem_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Rem, false, true));
                 break;
             case CCI.OpCode.Neg:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Neg, false, false));
                 break;
             case CCI.OpCode.And:
                 instructions.Add(new ArithInstruction(offset, ArithOp.And, false, false));
                 break;
             case CCI.OpCode.Or:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Or, false, false));
                 break;
             case CCI.OpCode.Xor:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Xor, false, false));
                 break;
             case CCI.OpCode.Not:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Not, false, false));
                 break;
             case CCI.OpCode.Shl:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Shl, false, false));
                 break;
             case CCI.OpCode.Shr:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Shr, false, false));
                 break;
             case CCI.OpCode.Shr_Un:
                 instructions.Add(new ArithInstruction(offset, ArithOp.Shr, false, true));
                 break;
             case CCI.OpCode.Conv_I1:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, false, false));
                 break;
             case CCI.OpCode.Conv_U1:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, false, false));
                 break;
             case CCI.OpCode.Conv_I2:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, false, false));
                 break;
             case CCI.OpCode.Conv_U2:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, false, false));
                 break;
             case CCI.OpCode.Conv_I4:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, false, false));
                 break;
             case CCI.OpCode.Conv_U4:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, false, false));
                 break;
             case CCI.OpCode.Conv_I8:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, false, false));
                 break;
             case CCI.OpCode.Conv_U8:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, false, false));
                 break;
             case CCI.OpCode.Conv_I:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, false, false));
                 break;
             case CCI.OpCode.Conv_U:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, false, false));
                 break;
             case CCI.OpCode.Conv_R4:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Single, false, false));
                 break;
             case CCI.OpCode.Conv_R8:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Double, false, false));
                 break;
             case CCI.OpCode.Conv_R_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Double, false, true));
                 break;
             case CCI.OpCode.Conv_Ovf_I1:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_U1:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_I2:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_U2:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_I4:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_U4:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_I8:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_U8:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_I:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_U:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, true, false));
                 break;
             case CCI.OpCode.Conv_Ovf_I1_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_U1_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_I2_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_U2_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_I4_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_U4_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_I8_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_U8_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_I_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, true, true));
                 break;
             case CCI.OpCode.Conv_Ovf_U_Un:
                 instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, true, true));
                 break;
             case CCI.OpCode._Try:
                 {
                     // We are recognising the grammar:
                     //   I ::= _Try I* _EndTry 
                     //           ( ( (_Catch <type> I* _EndHandler) | 
                     //               (_Filter I* _Endfilter _Catch <null> I* _EndHandler) )* |
                     //             (_Fault I* _EndHandler) |
                     //             (_Finally I* _EndHandler) ) |
                     //         <any other instruction>
                     var tryBody = InstructionsFromCCIMethodFrom(method, ref i);
                     if (i >= method.Instructions.Count || method.Instructions[i].OpCode != CCI.OpCode._EndTry)
                         throw new InvalidOperationException("invalid instructions");
                     i++;
                     var handlers = new AList<TryInstructionHandler>();
                     var done = false;
                     while (i < method.Instructions.Count && !done)
                     {
                         instruction = method.Instructions[i];
                         switch (instruction.OpCode)
                         {
                         case CCI.OpCode._Catch:
                             {
                                 if (handlers.Any
                                     (h =>
                                      (h is FaultTryInstructionHandler || h is FinallyTryInstructionHandler)))
                                     throw new InvalidOperationException("invalid instructions");
                                 var type = instruction.Value as CCI.TypeNode;
                                 if (type == null)
                                     throw new InvalidOperationException("invalid instruction");
                                 i++;
                                 if (i >= method.Instructions.Count)
                                     throw new InvalidOperationException("invalid instructions");
                                 var handlerBody = InstructionsFromCCIMethodFrom(method, ref i);
                                 if (i >= method.Instructions.Count ||
                                     method.Instructions[i].OpCode != CCI.OpCode._EndHandler)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 handlers.Add
                                     (new CatchTryInstructionHandler(TypeRefFromCCIType(type), handlerBody));
                                 break;
                             }
                         case CCI.OpCode._Filter:
                             {
                                 if (handlers.Any
                                     (h =>
                                      (h is FaultTryInstructionHandler || h is FinallyTryInstructionHandler)))
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 var filterBody = InstructionsFromCCIMethodFrom(method, ref i);
                                 if (i >= method.Instructions.Count ||
                                     method.Instructions[i].OpCode != CCI.OpCode._EndFilter)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 if (i >= method.Instructions.Count)
                                     throw new InvalidOperationException("invalid instructions");
                                 instruction = method.Instructions[i];
                                 if (instruction.OpCode != CCI.OpCode._Catch || instruction.Value != null)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 var handlerBody = InstructionsFromCCIMethodFrom(method, ref i);
                                 if (i >= method.Instructions.Count ||
                                     method.Instructions[i].OpCode != CCI.OpCode._EndHandler)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 handlers.Add(new FilterTryInstructionHandler(filterBody, handlerBody));
                                 break;
                             }
                         case CCI.OpCode._Fault:
                             {
                                 if (handlers.Count > 0)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 var handlerBody = InstructionsFromCCIMethodFrom(method, ref i);
                                 if (i >= method.Instructions.Count ||
                                     method.Instructions[i].OpCode != CCI.OpCode._EndHandler)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 handlers.Add(new FaultTryInstructionHandler(handlerBody));
                                 break;
                             }
                         case CCI.OpCode._Finally:
                             {
                                 if (handlers.Count > 0)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 var handlerBody = InstructionsFromCCIMethodFrom(method, ref i);
                                 if (i >= method.Instructions.Count ||
                                     method.Instructions[i].OpCode != CCI.OpCode._EndHandler)
                                     throw new InvalidOperationException("invalid instructions");
                                 i++;
                                 handlers.Add(new FinallyTryInstructionHandler(handlerBody));
                                 break;
                             }
                         default:
                             done = true;
                             break;
                         }
                     }
                     if (handlers.Count == 0)
                         throw new InvalidOperationException("invalid instructions");
                     instructions.Add(new TryInstruction(offset, tryBody, handlers));
                     break;
                 }
             case CCI.OpCode._EndTry:
             case CCI.OpCode._EndHandler:
             case CCI.OpCode._EndFilter:
                 // Backup
                 i--;
                 if (instructions.Count == 0)
                     throw new InvalidOperationException("empty instructions");
                 return new InstructionBlock(null, instructions);
             case CCI.OpCode._Catch:
             case CCI.OpCode._Filter:
             case CCI.OpCode._Fault:
             case CCI.OpCode._Finally:
                 // Handled in _Try above
                 throw new InvalidOperationException("invalid instructions");
             default:
                 throw new InvalidOperationException("invalid instruction");
             }
         }
     }
     // Always at least one instruciton, otherwise control would have fallen through
     if (instructions.Count == 0)
         throw new InvalidOperationException("empty instructions");
     return new InstructionBlock(null, instructions);
 }