static int CountCilInstructions(MemoryReader memReader) { int count = 0; while (memReader.NotEndOfBytes) { count++; OperationCode cilOpCode = memReader.ReadOpcode(); switch (cilOpCode) { case OperationCode.Ldarg_S: case OperationCode.Ldarga_S: case OperationCode.Starg_S: case OperationCode.Ldloc_S: case OperationCode.Ldloca_S: case OperationCode.Stloc_S: case OperationCode.Ldc_I4_S: case OperationCode.Br_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bgt_S: case OperationCode.Ble_S: case OperationCode.Blt_S: case OperationCode.Bne_Un_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_Un_S: case OperationCode.Leave_S: case OperationCode.Unaligned_: case OperationCode.No_: memReader.SkipBytes(1); break; case OperationCode.Ldarg: case OperationCode.Ldarga: case OperationCode.Starg: case OperationCode.Ldloc: case OperationCode.Ldloca: case OperationCode.Stloc: memReader.SkipBytes(2); break; case OperationCode.Ldc_I4: case OperationCode.Jmp: case OperationCode.Call: case OperationCode.Calli: case OperationCode.Br: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bgt: case OperationCode.Ble: case OperationCode.Blt: case OperationCode.Bne_Un: case OperationCode.Bge_Un: case OperationCode.Bgt_Un: case OperationCode.Ble_Un: case OperationCode.Blt_Un: case OperationCode.Callvirt: case OperationCode.Cpobj: case OperationCode.Ldobj: case OperationCode.Ldstr: case OperationCode.Newobj: case OperationCode.Castclass: case OperationCode.Isinst: case OperationCode.Unbox: case OperationCode.Ldfld: case OperationCode.Ldflda: case OperationCode.Stfld: case OperationCode.Ldsfld: case OperationCode.Ldsflda: case OperationCode.Stsfld: case OperationCode.Stobj: case OperationCode.Box: case OperationCode.Newarr: case OperationCode.Ldelema: case OperationCode.Ldelem: case OperationCode.Stelem: case OperationCode.Unbox_Any: case OperationCode.Refanyval: case OperationCode.Mkrefany: case OperationCode.Ldtoken: case OperationCode.Leave: case OperationCode.Ldftn: case OperationCode.Ldvirtftn: case OperationCode.Initobj: case OperationCode.Constrained_: case OperationCode.Sizeof: case OperationCode.Ldc_R4: memReader.SkipBytes(4); break; case OperationCode.Ldc_I8: case OperationCode.Ldc_R8: memReader.SkipBytes(8); break; case OperationCode.Switch: int numTargets = (int)memReader.ReadUInt32(); memReader.SkipBytes(4*numTargets); break; default: break; } } memReader.SeekOffset(0); return count; }
bool PopulateCilInstructions() { MethodBodyDocument document = new MethodBodyDocument(this.MethodDefinition); MemoryReader memReader = new MemoryReader(this.MethodIL.EncodedILMemoryBlock); var numInstructions = CountCilInstructions(memReader); if (numInstructions == 0) return true; CilInstruction[] instrList = new CilInstruction[numInstructions]; int instructionNumber = 0; while (memReader.NotEndOfBytes) { object/*?*/ value = null; uint offset = (uint)memReader.Offset; OperationCode cilOpCode = memReader.ReadOpcode(); switch (cilOpCode) { case OperationCode.Nop: case OperationCode.Break: break; case OperationCode.Ldarg_0: case OperationCode.Ldarg_1: case OperationCode.Ldarg_2: case OperationCode.Ldarg_3: value = this.GetParameter((uint)(cilOpCode - OperationCode.Ldarg_0)); break; case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: value = this.GetLocal((uint)(cilOpCode - OperationCode.Ldloc_0)); break; case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: value = this.GetLocal((uint)(cilOpCode - OperationCode.Stloc_0)); break; case OperationCode.Ldarg_S: case OperationCode.Ldarga_S: case OperationCode.Starg_S: value = this.GetParameter(memReader.ReadByte()); break; case OperationCode.Ldloc_S: case OperationCode.Ldloca_S: case OperationCode.Stloc_S: value = this.GetLocal(memReader.ReadByte()); break; case OperationCode.Ldnull: case OperationCode.Ldc_I4_M1: case OperationCode.Ldc_I4_0: case OperationCode.Ldc_I4_1: case OperationCode.Ldc_I4_2: case OperationCode.Ldc_I4_3: case OperationCode.Ldc_I4_4: case OperationCode.Ldc_I4_5: case OperationCode.Ldc_I4_6: case OperationCode.Ldc_I4_7: case OperationCode.Ldc_I4_8: break; case OperationCode.Ldc_I4_S: value = (int)memReader.ReadSByte(); break; case OperationCode.Ldc_I4: value = memReader.ReadInt32(); break; case OperationCode.Ldc_I8: value = memReader.ReadInt64(); break; case OperationCode.Ldc_R4: value = memReader.ReadSingle(); break; case OperationCode.Ldc_R8: value = memReader.ReadDouble(); break; case OperationCode.Dup: case OperationCode.Pop: break; case OperationCode.Jmp: value = this.GetMethod(memReader.ReadUInt32()); break; case OperationCode.Call: { IMethodReference methodReference = this.GetMethod(memReader.ReadUInt32()); IArrayTypeReference/*?*/ arrayType = methodReference.ContainingType as IArrayTypeReference; if (arrayType != null) { // For Get(), Set() and Address() on arrays, the runtime provides method implementations. // Hence, CCI2 replaces these with pseudo instrcutions Array_Set, Array_Get and Array_Addr. // All other methods on arrays will not use pseudo instruction and will have methodReference as their operand. if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Set.UniqueKey) { cilOpCode = OperationCode.Array_Set; value = arrayType; } else if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Get.UniqueKey) { cilOpCode = OperationCode.Array_Get; value = arrayType; } else if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Address.UniqueKey) { cilOpCode = OperationCode.Array_Addr; value = arrayType; } else { value = methodReference; } } else { value = methodReference; } } break; case OperationCode.Calli: value = this.GetFunctionPointerType(memReader.ReadUInt32()); break; case OperationCode.Ret: break; case OperationCode.Br_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bgt_S: case OperationCode.Ble_S: case OperationCode.Blt_S: case OperationCode.Bne_Un_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_Un_S: { uint jumpOffset = (uint)(memReader.Offset + 1 + memReader.ReadSByte()); if (jumpOffset >= this.EndOfMethodOffset) { // Error... } value = jumpOffset; } break; case OperationCode.Br: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bgt: case OperationCode.Ble: case OperationCode.Blt: case OperationCode.Bne_Un: case OperationCode.Bge_Un: case OperationCode.Bgt_Un: case OperationCode.Ble_Un: case OperationCode.Blt_Un: { uint jumpOffset = (uint)(memReader.Offset + 4 + memReader.ReadInt32()); if (jumpOffset >= this.EndOfMethodOffset) { // Error... } value = jumpOffset; } break; case OperationCode.Switch: { uint numTargets = memReader.ReadUInt32(); uint[] result = new uint[numTargets]; uint asOffset = memReader.Offset + numTargets * 4; for (int i = 0; i < numTargets; i++) { uint targetAddress = memReader.ReadUInt32() + asOffset; if (targetAddress >= this.EndOfMethodOffset) { // Error... } result[i] = targetAddress; } value = result; } break; case OperationCode.Ldind_I1: case OperationCode.Ldind_U1: case OperationCode.Ldind_I2: case OperationCode.Ldind_U2: case OperationCode.Ldind_I4: case OperationCode.Ldind_U4: case OperationCode.Ldind_I8: case OperationCode.Ldind_I: case OperationCode.Ldind_R4: case OperationCode.Ldind_R8: case OperationCode.Ldind_Ref: case OperationCode.Stind_Ref: case OperationCode.Stind_I1: case OperationCode.Stind_I2: case OperationCode.Stind_I4: case OperationCode.Stind_I8: case OperationCode.Stind_R4: case OperationCode.Stind_R8: case OperationCode.Add: case OperationCode.Sub: case OperationCode.Mul: case OperationCode.Div: case OperationCode.Div_Un: case OperationCode.Rem: case OperationCode.Rem_Un: case OperationCode.And: case OperationCode.Or: case OperationCode.Xor: case OperationCode.Shl: case OperationCode.Shr: case OperationCode.Shr_Un: case OperationCode.Neg: case OperationCode.Not: case OperationCode.Conv_I1: case OperationCode.Conv_I2: case OperationCode.Conv_I4: case OperationCode.Conv_I8: case OperationCode.Conv_R4: case OperationCode.Conv_R8: case OperationCode.Conv_U4: case OperationCode.Conv_U8: break; case OperationCode.Callvirt: { IMethodReference methodReference = this.GetMethod(memReader.ReadUInt32()); IArrayTypeReference/*?*/ arrayType = methodReference.ContainingType as IArrayTypeReference; if (arrayType != null) { // For Get(), Set() and Address() on arrays, the runtime provides method implementations. // Hence, CCI2 replaces these with pseudo instructions Array_Set, Array_Get and Array_Addr. // All other methods on arrays will not use pseudo instruction and will have methodReference as their operand. if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Set.UniqueKey) { cilOpCode = OperationCode.Array_Set; value = arrayType; } else if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Get.UniqueKey) { cilOpCode = OperationCode.Array_Get; value = arrayType; } else if (methodReference.Name.UniqueKey == this.PEFileToObjectModel.NameTable.Address.UniqueKey) { cilOpCode = OperationCode.Array_Addr; value = arrayType; } else { value = methodReference; } } else { value = methodReference; } } break; case OperationCode.Cpobj: case OperationCode.Ldobj: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Ldstr: value = this.GetUserStringForToken(memReader.ReadUInt32()); break; case OperationCode.Newobj: { IMethodReference methodReference = this.GetMethod(memReader.ReadUInt32()); IArrayTypeReference/*?*/ arrayType = methodReference.ContainingType as IArrayTypeReference; if (arrayType != null && !arrayType.IsVector) { uint numParam = IteratorHelper.EnumerableCount(methodReference.Parameters); if (numParam != arrayType.Rank) cilOpCode = OperationCode.Array_Create_WithLowerBound; else cilOpCode = OperationCode.Array_Create; value = arrayType; } else { value = methodReference; } } break; case OperationCode.Castclass: case OperationCode.Isinst: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Conv_R_Un: break; case OperationCode.Unbox: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Throw: break; case OperationCode.Ldfld: case OperationCode.Ldflda: case OperationCode.Stfld: value = this.GetField(memReader.ReadUInt32()); break; case OperationCode.Ldsfld: case OperationCode.Ldsflda: case OperationCode.Stsfld: value = this.GetField(memReader.ReadUInt32()); var fieldRef = value as FieldReference; if (fieldRef != null) fieldRef.isStatic = true; break; case OperationCode.Stobj: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Conv_Ovf_I1_Un: case OperationCode.Conv_Ovf_I2_Un: case OperationCode.Conv_Ovf_I4_Un: case OperationCode.Conv_Ovf_I8_Un: case OperationCode.Conv_Ovf_U1_Un: case OperationCode.Conv_Ovf_U2_Un: case OperationCode.Conv_Ovf_U4_Un: case OperationCode.Conv_Ovf_U8_Un: case OperationCode.Conv_Ovf_I_Un: case OperationCode.Conv_Ovf_U_Un: break; case OperationCode.Box: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Newarr: { var elementType = this.GetType(memReader.ReadUInt32()); if (elementType != null) value = Vector.GetVector(elementType, PEFileToObjectModel.InternFactory); else value = Dummy.ArrayType; } break; case OperationCode.Ldlen: break; case OperationCode.Ldelema: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Ldelem_I1: case OperationCode.Ldelem_U1: case OperationCode.Ldelem_I2: case OperationCode.Ldelem_U2: case OperationCode.Ldelem_I4: case OperationCode.Ldelem_U4: case OperationCode.Ldelem_I8: case OperationCode.Ldelem_I: case OperationCode.Ldelem_R4: case OperationCode.Ldelem_R8: case OperationCode.Ldelem_Ref: case OperationCode.Stelem_I: case OperationCode.Stelem_I1: case OperationCode.Stelem_I2: case OperationCode.Stelem_I4: case OperationCode.Stelem_I8: case OperationCode.Stelem_R4: case OperationCode.Stelem_R8: case OperationCode.Stelem_Ref: break; case OperationCode.Ldelem: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Stelem: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Unbox_Any: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Conv_Ovf_I1: case OperationCode.Conv_Ovf_U1: case OperationCode.Conv_Ovf_I2: case OperationCode.Conv_Ovf_U2: case OperationCode.Conv_Ovf_I4: case OperationCode.Conv_Ovf_U4: case OperationCode.Conv_Ovf_I8: case OperationCode.Conv_Ovf_U8: break; case OperationCode.Refanyval: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Ckfinite: break; case OperationCode.Mkrefany: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Ldtoken: value = this.GetRuntimeHandleFromToken(memReader.ReadUInt32()); break; case OperationCode.Conv_U2: case OperationCode.Conv_U1: case OperationCode.Conv_I: case OperationCode.Conv_Ovf_I: case OperationCode.Conv_Ovf_U: case OperationCode.Add_Ovf: case OperationCode.Add_Ovf_Un: case OperationCode.Mul_Ovf: case OperationCode.Mul_Ovf_Un: case OperationCode.Sub_Ovf: case OperationCode.Sub_Ovf_Un: case OperationCode.Endfinally: break; case OperationCode.Leave: { uint leaveOffset = (uint)(memReader.Offset + 4 + memReader.ReadInt32()); if (leaveOffset >= this.EndOfMethodOffset) { // Error... } value = leaveOffset; } break; case OperationCode.Leave_S: { uint leaveOffset = (uint)(memReader.Offset + 1 + memReader.ReadSByte()); if (leaveOffset >= this.EndOfMethodOffset) { // Error... } value = leaveOffset; } break; case OperationCode.Stind_I: case OperationCode.Conv_U: case OperationCode.Arglist: case OperationCode.Ceq: case OperationCode.Cgt: case OperationCode.Cgt_Un: case OperationCode.Clt: case OperationCode.Clt_Un: break; case OperationCode.Ldftn: case OperationCode.Ldvirtftn: value = this.GetMethod(memReader.ReadUInt32()); break; case OperationCode.Ldarg: case OperationCode.Ldarga: case OperationCode.Starg: value = this.GetParameter(memReader.ReadUInt16()); break; case OperationCode.Ldloc: case OperationCode.Ldloca: case OperationCode.Stloc: value = this.GetLocal(memReader.ReadUInt16()); break; case OperationCode.Localloc: value = PointerType.GetPointerType(this.PEFileToObjectModel.PlatformType.SystemVoid, this.PEFileToObjectModel.InternFactory); break; case OperationCode.Endfilter: break; case OperationCode.Unaligned_: value = memReader.ReadByte(); break; case OperationCode.Volatile_: case OperationCode.Tail_: break; case OperationCode.Initobj: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Constrained_: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Cpblk: case OperationCode.Initblk: break; case OperationCode.No_: value = (OperationCheckFlags)memReader.ReadByte(); break; case OperationCode.Rethrow: break; case OperationCode.Sizeof: value = this.GetType(memReader.ReadUInt32()); break; case OperationCode.Refanytype: case OperationCode.Readonly_: break; default: this.PEFileToObjectModel.PEFileReader.ErrorContainer.AddILError(this.MethodDefinition, offset, MetadataReaderErrorKind.UnknownILInstruction); break; } instrList[instructionNumber++] = new CilInstruction(cilOpCode, document, offset, value); } this.MethodBody.SetCilInstructions(instrList); return true; }