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); }