private static MethodInfo GetCustomFunc <T1, T2, T3>(Func <T1, T2, T3> target) { var method = target.Method; var body = method.GetMethodBody(); var locals = body.LocalVariables.OrderBy(x => x.LocalIndex).ToList(); var resolver = new ILInstructionResolver(method); switch (method.Name) { case nameof(TestMethods.Add_Ovf): case nameof(TestMethods.Add_Ovf_Un): { var instructions = ILInstructionReader.FromMethod(method); var parsed = Enum.TryParse <ILOpCodeValues>(method.Name, out ILOpCodeValues result); var opCode = OpCodeLookup.GetILOpcode((int)result); instructions[2] = new ILInstruction() { OpCode = opCode }; var compiled = ILEngineOpCodeTestMethodCompiler.CompileMethod(opCode, method, (gen) => { locals.ForEach(x => gen.DeclareLocal(x.LocalType)); instructions.ForEach(x => x.Emit(gen, resolver)); }); return(method); } default: throw new NotImplementedException(); } }
private ILOpCodeValues[] RunAndTest <T>(MethodInfo method, T expected, object[] parameters, Func <T, T, bool> comparer) { var result = ILInstructionReader .FromMethod(method) .Select(x => (ILOpCodeValues)x.OpCode.Value).ToArray(); bool invokedResult = false; Exception caughtCompiled = null; T invocationResult = default; try { invocationResult = (T)method.Invoke(null, parameters); invokedResult = comparer(expected, invocationResult); } catch (Exception ex) { caughtCompiled = ex.InnerException; } var engineResult = false; Exception caughtEngine = null; try { var frame = new TStackFrame(); frame.CopyFrom(method); frame.Args = parameters; engine.ExecuteFrame(frame); //var actualEngine = engine.ExecuteTyped<T>(method, parameters); if (!(frame.ReturnResult is T tresult)) { if (frame.ReturnResult is IConvertible tConvertible) { frame.ReturnResult = Convert.ChangeType(tConvertible, typeof(T)); } else { frame.ReturnResult = (T)frame.ReturnResult; } } var actualEngine = (T)frame.ReturnResult; engineResult = comparer(expected, actualEngine); } catch (Exception ex) { caughtEngine = ex; } if (caughtCompiled is null && caughtEngine is null) { Assert.IsTrue(invokedResult == engineResult); }
void TestFromMethod(Func <MethodInfo> mResolver, OperandType operandType) { var method = mResolver(); Assert.IsNotNull(method, "Failed to resolve test method"); var expected = method.Invoke(null, Type.EmptyTypes); var instructions = ILInstructionReader.FromMethod(method); var frame = Build(instructions); frame.CopyFrom(method); ExecuteAndAssertResult(frame, expected, operandType); }
public void TestReadInlineBrTarget() { var builder = new ILInstructionBuilder(); builder.Write(ILInstruction.Create(ILOpCodeValues.Br, 0)); builder.Write(ILOpCodeValues.Ldc_I8, 1L); builder.Write(ILOpCodeValues.Ret); var ilMethod = new Models.ILMethod(MethodBase.GetCurrentMethod().Name, typeof(long)); ilMethod.AddInstructions(builder.Instructions.ToArray()); var method = ilMethod.Compile(); var expected = method.Invoke(null, Type.EmptyTypes); var instructions = ILInstructionReader.FromMethod(method); ExecuteAndAssertResult(instructions, expected, OperandType.InlineBrTarget); }
public void ExecuteTest() { var frame = new ILStackFrameWithDiagnostics(); Action empty = () => { }; var instructions = ILInstructionReader.FromMethod(empty.Method); frame.Stream = instructions; frame.SetResolver(empty.Method); frame.Execute(); Assert.IsNull(frame.ReturnResult); Assert.IsNull(frame.Exception); Assert.IsTrue(frame.Module.MetadataToken == empty.Method.Module.MetadataToken); var thisType = this.GetType(); var testMethod = thisType.GetMethod(nameof(ExecuteTest)); Assert.IsNotNull(testMethod); var methodSigToken = testMethod.GetMethodBody().LocalSignatureMetadataToken; Assert.IsTrue(methodSigToken >0); var resolvedSig = frame.ResolveSignatureToken(methodSigToken); Assert.IsNotNull(resolvedSig); Assert.IsTrue(resolvedSig.Length > 0); frame.Execute(1); Assert.IsNull(frame.ReturnResult); Assert.IsNull(frame.Exception); Action sleepToLong = () => System.Threading.Thread.Sleep(4000); instructions = ILInstructionReader.FromMethod(sleepToLong.Method); frame.Stream = instructions; frame.Execute(1); Assert.IsNull(frame.ReturnResult); Assert.IsNotNull(frame.Exception); Assert.IsInstanceOfType(frame.Exception, typeof(ActionTimeoutException)); Action throwException = () => throw new ArgumentException(nameof(throwException)); instructions = ILInstructionReader.FromMethod(throwException.Method); frame.Stream = instructions; frame.Execute(1); Assert.IsNull(frame.ReturnResult); Assert.IsNotNull(frame.Exception); Assert.IsInstanceOfType(frame.Exception, typeof(ArgumentException)); }
protected ILOpCodeValues[] CompileAndRun <T>(OpCode opCode, MethodInfo srcMethod, T expected, object[] parameters, Func <T, T, bool> comparer) { var methodParameters = srcMethod.GetParameters(); var body = srcMethod.GetMethodBody(); var locals = body.LocalVariables.OrderBy(x => x.LocalIndex).ToList(); var parameterTypes = methodParameters.Select(x => x.ParameterType).ToArray(); var instructions = ILInstructionReader.FromMethod(srcMethod); if (opCode != OpCodes.Arglist) { Assert.IsTrue(instructions.Any(x => x.OpCode == opCode), $"Opcode {opCode} missing from compiled method"); } var result = ILInstructionReader .FromMethod(srcMethod) .Select(x => (ILOpCodeValues)x.OpCode.Value).ToArray(); var resolver = new ILInstructionResolver(srcMethod); Action <ILGenerator> emitAction = (gen) => { locals.ForEach(x => gen.DeclareLocal(x.LocalType)); instructions.ForEach(x => x.Emit(gen, resolver)); }; MethodInfo method = null; try { method = ILEngineOpCodeTestMethodCompiler.CompileMethod(opCode, typeof(T), parameterTypes, emitAction); } catch (Exception ex) { Assert.Fail("Failed to compile method:", ex.Message); return(null); } return(RunAndTest <T>(method, expected, parameters, comparer)); }
public void TestEmitCompiledSwitch() { var compiledType = BuildSwitchTestType(); var compiledMethod = compiledType.GetMethod("SwitchTest"); Assert.IsNotNull(compiledMethod); var compiledInstructions = ILInstructionReader.FromMethod(compiledMethod).ToArray(); //TODO: auto label read instructions. //mark default case jump target compiledInstructions[7].Label = 0; //set default case jump target compiledInstructions[2].Arg = compiledInstructions[7]; // set break target; compiledInstructions[8].Label = 1; //set jump targets for switch breaks statements compiledInstructions[4].Arg = compiledInstructions[6].Arg = compiledInstructions[8]; //mark switch jump targets; compiledInstructions[3].Label = 2; compiledInstructions[5].Label = 3; //set switch jump targets = compiledInstructions[1].Arg = new[] { compiledInstructions[3], compiledInstructions[5] }; var builder = new ILInstructionBuilder(); builder.Write(compiledInstructions.ToArray()); //TODO: implement auto fixup of instuctions. var frame = ILStackFrameBuilder.Build(builder.Instructions); frame.Args = new object[] { 1 }; frame.Reset(); int Position = -1; var jumpTable = frame.Stream.ToDictionary(x => (int)x.ByteIndex, x => ++ Position); frame.Execute(); var expected = 1; Assert.IsNull(frame.Exception, $"Executing switch: add throw an exception {frame?.Exception}"); Assert.IsTrue(frame.Stack.Count == 0, "Stack was not cleared executing switch: add"); Assert.IsTrue((int)frame.ReturnResult == expected, $"Actual: {frame.ReturnResult}\r\nExpected: {expected}"); frame.Args = new object[] { 0 }; frame.Execute(); expected = 0; Assert.IsNull(frame.Exception, $"Executing switch: add throw an exception {frame?.Exception}"); Assert.IsTrue(frame.Stack.Count == 0, "Stack was not cleared executing switch: add"); Assert.IsTrue((int)frame.ReturnResult == expected, $"Actual: {frame.ReturnResult}\r\nExpected: {expected}"); frame.Args = new object[] { 2 }; frame.Execute(); expected = 2; Assert.IsNull(frame.Exception, $"Executing switch: add throw an exception {frame?.Exception}"); Assert.IsTrue(frame.Stack.Count == 0, "Stack was not cleared executing switch: add"); Assert.IsTrue((int)frame.ReturnResult == expected, $"Actual: {frame.ReturnResult}\r\nExpected: {expected}"); }
public ILSearchResult(MethodInfo method) { Method = method; this.Instructions = ILInstructionReader.FromMethod(method); }