private void MethodResolver(MethodContext context) { if (context.Method == GetMethod <ResolveILTests>(nameof(BodyEmpty))) { byte[] assertToken = BitConverter.GetBytes(AssertTrue.MetadataToken); //{ // Assert.True(true); //} List <byte> il = new List <byte> { (byte)OpCodes.Ldc_I4_1.Value, (byte)OpCodes.Call.Value }; il.AddRange(assertToken); il.Add((byte)OpCodes.Ret.Value); context.ResolveIL(il); } else if (context.Method == GetMethod <ResolveILTests>(nameof(LocalVariable))) { byte[] assertToken = BitConverter.GetBytes(AssertTrue.MetadataToken); byte[] ceqInstruction = BitConverter.GetBytes(OpCodes.Ceq.Value).Reverse().ToArray(); //{ // short v1 = short.MaxValue; // short v2 = short.MaxValue; // Assert.True(v1+v2+1 == ushort.MaxValue); //} List <byte> il = new List <byte> { (byte)OpCodes.Ldc_I4.Value, 0xFF, 0x7F, 0x00, 0x00, //32767 (byte)OpCodes.Stloc_0.Value, (byte)OpCodes.Ldc_I4.Value, 0xFF, 0x7F, 0x00, 0x00, //32767 (byte)OpCodes.Stloc_1.Value, (byte)OpCodes.Ldloc_0.Value, (byte)OpCodes.Ldloc_1.Value, (byte)OpCodes.Add.Value, (byte)OpCodes.Ldc_I4_1.Value, (byte)OpCodes.Add.Value, (byte)OpCodes.Ldc_I4.Value, 0xFF, 0xFF, 0x00, 0x00, //65535 }; il.AddRange(ceqInstruction); il.Add((byte)OpCodes.Call.Value); il.AddRange(assertToken); il.Add((byte)OpCodes.Ret.Value); MethodBody methodBody = new MethodBody(il, context.Method.Module, typeof(int), typeof(int)); context.ResolveBody(methodBody); } }
private static void MethodResolver(MethodContext context) { if (context.Method.Name == "SimpleSum") { List <byte> newIl = new List <byte>(); newIl.Add((byte)OpCodes.Call.Value); newIl.AddRange(BitConverter.GetBytes(_getCurrentProcess.MetadataToken)); newIl.Add((byte)OpCodes.Call.Value); newIl.AddRange(BitConverter.GetBytes(_getterId.MetadataToken)); newIl.Add((byte)OpCodes.Ret.Value); MethodBody methodBody = new MethodBody(newIl.ToArray(), _getCurrentProcess.Module); context.ResolveBody(methodBody); } }
/// <summary> /// Resolve method by IL. /// </summary> /// <param name="il">IL instructions.</param> /// <param name="maxStack">Stack size to instrucitons.</param> public void ResolveIL(IEnumerable <byte> il, uint maxStack) { MethodBody = new MethodBody(il.ToArray(), maxStack); IsResolved = true; }
/// <summary> /// Resolve method by IL. /// </summary> /// <param name="il">IL instructions.</param> public void ResolveIL(IEnumerable <byte> il) { MethodBody = new MethodBody(il.ToArray()); IsResolved = true; }
internal MethodContext(MethodBase method) { MethodBody = new MethodBody(method); Method = method; }
/// <summary> /// Resolve method by MethodInfo. /// </summary> /// <param name="method">Body of new method.</param> public void ResolveMethod(MethodInfo method) { MethodBody = new MethodBody(method); IsResolved = true; }
/// <summary> /// Resolve method by MethodBody. /// </summary> /// <param name="methodBody">Body of new method.</param> public void ResolveBody(MethodBody methodBody) { MethodBody = methodBody; IsResolved = true; }
/// <summary> /// Wrap delegate to compileMethod from ICorJitCompiler. /// </summary> /// <param name="thisPtr">this parameter (pointer to CILJIT).</param> /// <param name="comp">(IN) - Pointer to ICorJitInfo.</param> /// <param name="info">(IN) - Pointer to CORINFO_METHOD_INFO.</param> /// <param name="flags">(IN) - Pointer to CorJitFlag.</param> /// <param name="nativeEntry">(OUT) - Pointer to NativeEntry.</param> /// <param name="nativeSizeOfCode">(OUT) - Size of NativeEntry.</param> private CorJitResult CompileMethod(IntPtr thisPtr, IntPtr comp, IntPtr info, uint flags, out IntPtr nativeEntry, out ulong nativeSizeOfCode) { if (thisPtr == default) { nativeEntry = IntPtr.Zero; nativeSizeOfCode = 0; return(0); } _compileTls ??= new CompileTls(); _compileTls.EnterCount++; try { MethodContext?methodContext = null; IntPtr sigAddress = IntPtr.Zero; IntPtr ilAddress = IntPtr.Zero; if (_compileTls.EnterCount == 1 && _methodResolvers != null) { IEnumerable <Delegate> resolvers = _methodResolvers.GetInvocationList(); if (resolvers.Any()) { MethodInfo methodInfo = new MethodInfo(info); lock (JitLock) { if (_framework.CEEInfoVTable == IntPtr.Zero) { _framework.ReadICorJitInfoVTable(comp); _hookManager.InjectHook(CEEInfo.ResolveTokenIndex, _resolveToken); _hookManager.InjectHook(CEEInfo.ConstructStringLiteralIndex, _constructStringLiteral); } } if (methodInfo.Module != null) { uint methodToken = CEEInfo.GetMethodDefFromMethod(methodInfo.MethodDesc); MethodBase methodFound = methodInfo.Module.ResolveMethod((int)methodToken); _tokenTls = new TokenTls { Root = methodFound }; methodContext = new MethodContext(methodFound); foreach (MethodResolverHandler resolver in resolvers) { resolver(methodContext); if (methodContext.IsResolved) { break; } } } if (methodContext != null && methodContext.IsResolved) { int ilLength; if (methodContext.Mode == MethodContext.ResolveMode.IL) { MethodBody methodBody = methodContext.MethodBody; ilLength = methodBody.IL.Length; ilAddress = methodBody.IL.ToPointer(); if (methodBody.HasLocalVariable) { byte[] signatureVariables = methodBody.GetSignatureVariables(); sigAddress = signatureVariables.ToPointer(); methodInfo.Locals.Signature = sigAddress + 1; methodInfo.Locals.Args = sigAddress + 3; methodInfo.Locals.NumArgs = (ushort)methodBody.LocalVariables.Count; } methodInfo.MaxStack = methodBody.MaxStackSize; } else { (ilAddress, ilLength) = PrepareIL(methodContext); if (methodInfo.MaxStack < 8) { methodInfo.MaxStack = 8; } } methodInfo.EHCount = methodContext.MethodBody.EHCount; methodInfo.ILCode = ilAddress; methodInfo.ILCodeSize = (uint)ilLength; } } } CorJitResult result = _framework.CompileMethod(thisPtr, comp, info, flags, out nativeEntry, out nativeSizeOfCode); if (ilAddress != IntPtr.Zero && methodContext !.Mode == MethodContext.ResolveMode.IL) { Marshal.FreeHGlobal(ilAddress); } if (sigAddress != IntPtr.Zero) { Marshal.FreeHGlobal(sigAddress); } if (methodContext?.Mode == MethodContext.ResolveMode.NATIVE) { Marshal.Copy(methodContext.NativeCode !, 0, nativeEntry, methodContext.NativeCode !.Length); } return(result); } finally { _compileTls.EnterCount--; } }
protected override void MethodResolver(MethodContext context) { if (context.Method.Name == "MapWithJitex") { MethodBody body = new MethodBody((MethodInfo)context.Method); //All operations on method IList <Operation> operations = body.ReadIL().ToList(); foreach (Operation operation in operations.Where(c => c.OpCode != OpCodes.Nop)) { if (operation.Instance is MethodInfo methodInfo && methodInfo.IsGenericMethod && methodInfo.GetGenericMethodDefinition() == MethodMap) { //Generic type passed: IMapper.Map<Type>(); Type typeDestination = methodInfo.GetGenericArguments().First(); //Variable passed by argument: IMapper.Map<Type>(variable); Operation sourceOperation = null; //Start block from Map call. Operation startMapper = null; //It's necessary find start operation of Mapper.Map call //A basic call will generate these operations: //IL_0000: ldsfld IMapper //IL_0005: ldarg.0 // this //IL_0006: ldfld Variable passed by argument //IL_000b: callvirt IMapper.Map<T>(obj) //IL_0010: ret //We are currently in IL_000b, so we need go until IL_0000. //A way to do this, is check the type of variable|field until find a IMapper. //If variable|field is typeof IMapper, that's start of operation block call, if not, is the variable|field passed by argument. for (int i = operation.Index - 1; i >= 0; i--) { Operation previousOperation = operations[i]; //Operation starts (IL_0000) if (previousOperation.Instance is FieldInfo field && field.FieldType == typeof(IMapper)) { startMapper = previousOperation; break; } //Field passed by argument in our case. //That can be a variable (ldloc), method (callvirt|call), ... if (previousOperation.OpCode.Name.StartsWith("ldfld")) { sourceOperation = previousOperation; } } //Store all properties to make bind. PropertyInfo[] sourceProperties = sourceOperation.Instance.FieldType.GetProperties(); PropertyInfo[] destionationProperties = typeDestination.GetProperties(); //To start bind, we need firstly instantiate our destiny variable. ConstructorInfo defaultConstructorDest = typeDestination.GetConstructor(Type.EmptyTypes); List <byte> ilToReplace = new List <byte> { (byte)OpCodes.Newobj.Value }; //TypeDestination variable = new TypeDestionation(); byte[] defaultCtor = BitConverter.GetBytes(defaultConstructorDest.MetadataToken); ilToReplace.AddRange(defaultCtor); foreach (PropertyInfo sourceProperty in sourceProperties) { //Bind only property with same name (default config to AutoMapper) PropertyInfo destProperty = destionationProperties.FirstOrDefault(p => p.Name == sourceProperty.Name); if (destProperty != null) { //Generate a simple get and set: //variable.Property1 = variablePasseedByArgument.Property1 //Load field (_person) passed by argument on IMapper.Map ilToReplace.Add((byte)OpCodes.Dup.Value); ilToReplace.Add((byte)OpCodes.Ldarg_0.Value); ilToReplace.Add((byte)OpCodes.Ldfld.Value); byte[] fieldToken = BitConverter.GetBytes(sourceOperation.MetadataToken.Value); ilToReplace.AddRange(fieldToken); //Load getter and setter MethodInfo getMethod = sourceProperty.GetGetMethod(); MethodInfo setMethod = destProperty.GetSetMethod(); byte[] getToken = BitConverter.GetBytes(getMethod.MetadataToken); byte[] setToken = BitConverter.GetBytes(setMethod.MetadataToken); //callvirt instance variablePasseedByArgument.Property1 (get) ilToReplace.Add((byte)OpCodes.Callvirt.Value); ilToReplace.AddRange(getToken); //callvirt instance variable.Property1 (set) ilToReplace.Add((byte)OpCodes.Callvirt.Value); ilToReplace.AddRange(setToken); } } //Replace operations from AutoMapper int endMapperIndex = startMapper.Offset; //All operations BEFORE IMapper.Map byte[] startIL = body.IL[..endMapperIndex];