/// <summary> /// </summary> /// <param name="methodBody"> /// </param> /// <param name="module"> /// </param> /// <param name="genericContext"> /// </param> /// <param name="stackCall"> /// </param> /// <returns> /// </returns> public IEnumerable<OpCodePart> OpCodes(IMethodBody methodBody, IModule module, IGenericContext genericContext, Queue<IMethod> stackCall) { if (!methodBody.HasBody) { yield break; } var extended = false; var startAddress = 0; var currentAddress = 0; var ilAsByteArray = methodBody.GetILAsByteArray(); var enumerator = ilAsByteArray.GetEnumerator(); while (enumerator.MoveNext()) { var @byte = (byte)enumerator.Current; if (@byte == 0xFE) { extended = true; continue; } var code = (Code)(extended ? (@byte + 0xE1) : @byte); extended = false; var opCode = opCodesMap[code]; startAddress = currentAddress; currentAddress += opCode.Size; switch (code) { case Code.Br_S: case Code.Beq_S: case Code.Brtrue_S: case Code.Brfalse_S: case Code.Blt_S: case Code.Blt_Un_S: case Code.Bgt_S: case Code.Bgt_Un_S: case Code.Bge_S: case Code.Bge_Un_S: case Code.Ble_S: case Code.Ble_Un_S: case Code.Bne_Un_S: case Code.Ldc_I4_S: case Code.Ldloc_S: case Code.Ldloca_S: case Code.Stloc_S: case Code.Leave_S: case Code.Ldarg_S: case Code.Starg_S: case Code.Ldarga_S: // read token, next var token = ReadInt32ShortForm(enumerator, ref currentAddress); var @int32 = token; yield return new OpCodeInt32Part(opCode, startAddress, currentAddress, @int32); continue; case Code.Br: case Code.Beq: case Code.Brtrue: case Code.Brfalse: case Code.Blt: case Code.Blt_Un: case Code.Bgt: case Code.Bgt_Un: case Code.Bge: case Code.Bge_Un: case Code.Ble: case Code.Ble_Un: case Code.Bne_Un: case Code.Ldc_I4: case Code.Ldloc: case Code.Stloc: case Code.Leave: case Code.Starg: // read token, next token = ReadInt32(enumerator, ref currentAddress); @int32 = token; yield return new OpCodeInt32Part(opCode, startAddress, currentAddress, @int32); continue; case Code.Ldc_I8: // read token, next var bytes = ReadBytes(enumerator, 8, ref currentAddress); var @int64 = BitConverter.ToInt64(bytes, 0); yield return new OpCodeInt64Part(opCode, startAddress, currentAddress, @int64); continue; case Code.Ldc_R4: // read token, next bytes = ReadBytes(enumerator, 4, ref currentAddress); var @single = BitConverter.ToSingle(bytes, 0); yield return new OpCodeSinglePart(opCode, startAddress, currentAddress, @single); continue; case Code.Ldc_R8: // read token, next bytes = ReadBytes(enumerator, 8, ref currentAddress); var @double = BitConverter.ToDouble(bytes, 0); yield return new OpCodeDoublePart(opCode, startAddress, currentAddress, @double); continue; case Code.Ldstr: // read token, next token = ReadInt32(enumerator, ref currentAddress); var @string = module.ResolveString(token); yield return new OpCodeStringPart(opCode, startAddress, currentAddress, @string); continue; case Code.Newobj: // read token, next token = ReadInt32(enumerator, ref currentAddress); var constructor = module.ResolveMember(token, genericContext) as IConstructor; this.AddGenericSpecializedType(constructor.DeclaringType); this.AddGenericSpecializedMethod(constructor, stackCall); foreach (var methodParameter in constructor.GetParameters()) { this.AddStructType(methodParameter.ParameterType); } this.AddUsedType(constructor.DeclaringType); this.AddCalledMethod(constructor); yield return new OpCodeConstructorInfoPart(opCode, startAddress, currentAddress, constructor); continue; case Code.Call: case Code.Callvirt: // read token, next token = ReadInt32(enumerator, ref currentAddress); var method = module.ResolveMethod(token, genericContext); this.AddGenericSpecializedType(method.DeclaringType); this.AddGenericSpecializedMethod(method, stackCall); foreach (var methodParameter in method.GetParameters()) { this.AddStructType(methodParameter.ParameterType); } this.AddUsedType(method.DeclaringType); this.AddCalledMethod(method); yield return new OpCodeMethodInfoPart(opCode, startAddress, currentAddress, method); continue; case Code.Ldftn: case Code.Ldvirtftn: // read token, next token = ReadInt32(enumerator, ref currentAddress); method = module.ResolveMethod(token, genericContext); this.AddGenericSpecializedType(method.DeclaringType); this.AddGenericSpecializedMethod(method, stackCall); this.AddUsedType(method.DeclaringType); yield return new OpCodeMethodInfoPart(opCode, startAddress, currentAddress, method); continue; case Code.Stfld: case Code.Stsfld: case Code.Ldfld: case Code.Ldflda: case Code.Ldsfld: case Code.Ldsflda: // read token, next token = ReadInt32(enumerator, ref currentAddress); var field = module.ResolveField(token, genericContext); this.AddGenericSpecializedType(field.FieldType); this.AddGenericSpecializedType(field.DeclaringType); this.AddUsedType(field.DeclaringType); if (code == Code.Ldsfld || code == Code.Ldsflda) { this.AddUsedStaticFieldToRead(field); } yield return new OpCodeFieldInfoPart(opCode, startAddress, currentAddress, field); continue; case Code.Ldtoken: // can it be anything? token = ReadInt32(enumerator, ref currentAddress); var resolvedToken = module.ResolveToken(token, genericContext); var typeToken = resolvedToken as IType; if (typeToken != null) { this.AddUsedType(typeToken); yield return new OpCodeTypePart(opCode, startAddress, currentAddress, typeToken); continue; } var fieldMember = resolvedToken as IField; if (fieldMember != null) { this.AddUsedType(fieldMember.DeclaringType); yield return new OpCodeFieldInfoPart(opCode, startAddress, currentAddress, fieldMember); continue; } var methodMember = resolvedToken as IMethod; if (methodMember != null) { this.AddUsedType(methodMember.DeclaringType); yield return new OpCodeMethodInfoPart(opCode, startAddress, currentAddress, methodMember); continue; } yield return new OpCodeInt32Part(opCode, startAddress, currentAddress, token); continue; case Code.Newarr: case Code.Ldelem: case Code.Stelem: case Code.Ldelema: case Code.Box: case Code.Unbox: case Code.Unbox_Any: case Code.Castclass: case Code.Initobj: case Code.Isinst: case Code.Ldobj: case Code.Stobj: case Code.Constrained: case Code.Sizeof: case Code.Mkrefany: case Code.Refanyval: // read token, next token = ReadInt32(enumerator, ref currentAddress); var type = module.ResolveType(token, genericContext); this.AddGenericSpecializedType(type); if (code == Code.Box) { this.AddStructType(type); } this.AddUsedType(type); yield return new OpCodeTypePart(opCode, startAddress, currentAddress, type); continue; case Code.Switch: var ints = new List<int>(); var count = ReadInt32(enumerator, ref currentAddress); for (var i = 0; i < count; i++) { ints.Add(ReadInt32(enumerator, ref currentAddress)); } yield return new OpCodeLabelsPart(opCode, startAddress, currentAddress, ints.ToArray()); continue; default: yield return new OpCodePart(opCode, startAddress, currentAddress); continue; } } }