public void TestEmitMethod() { var c = new ILEngineUnitTestModel(1); var cType = c.GetType(); var cMethod = cType.GetMethod(nameof(c.GetValue)); var expected = c.Value; var builder = new ILInstructionBuilder(); builder.Write(OpCodes.Ldarg_0); builder.Write(OpCodes.Call, cMethod.MetadataToken); builder.Write(OpCodes.Ret); var frame = ILStackFrameBuilder.Build(builder.Instructions); frame.SetResolver(this.GetType()); frame.Args = new object[] { c }; frame.Execute(); var ilMethod = new ILMethod(MethodBase.GetCurrentMethod().Name, expected.GetType()); ilMethod.AddParameters(new[] { cType }); ilMethod.AddInstructions(builder.Instructions.ToArray()); ilMethod.Module = this.GetType().Module; var method = ilMethod.Compile(); var actual = method.Invoke(null, new object[] { c }); Assert.IsTrue((int)actual == expected, $"Actual: {actual}\r\nExpected:{expected}"); }
public void BuildOpCodesTest() { var opCode1 = OpCodes.Ret; var opCodes = (new[] { opCode1 }).ToList(); var frame = ILStackFrameBuilder.Build(opCodes); Assert.IsTrue(frame.Stream.Count == 1); Assert.IsTrue(frame.Stream[0].OpCode == opCode1); }
public void BuildILInstructionsTest() { var opCode1 = OpCodes.Ret; var instruction = ILInstruction.Create(opCode1); var instructions = (new[] { instruction }).ToList(); var frame = ILStackFrameBuilder.Build(instructions); Assert.IsTrue(frame.Stream.Count == 1); Assert.IsTrue(frame.Stream[0].OpCode == opCode1); }
private void TestExecuteOpCodeFrame() { var opCode1 = OpCodes.Ldc_I4_1; var opCode2 = OpCodes.Ret; var opCodes = (new[] { opCode1, opCode2 }).ToList(); var frame = ILStackFrameBuilder.Build(opCodes); ILStackFrameBuilder.Execute(frame, 1); Assert.IsTrue(frame.Stream.Count == 2); Assert.IsTrue(frame.Stream[0].OpCode == opCode1); Assert.IsTrue(frame.Stream[1].OpCode == opCode2); var actual = frame.ReturnResult; Assert.IsNotNull(actual); var expected = 1; Assert.IsTrue((int)actual == expected, $"Actual:{actual}\r\nExpected:{expected}\r\n"); }
public void TestEmitSwitch() { var endSwitchInstruction = ILInstruction.Create(ILOpCodeValues.Nop); endSwitchInstruction.Label = 2; var addInstructions = new[] { ILInstruction.Create(ILOpCodeValues.Add), ILInstruction.Create(ILOpCodeValues.Br_S, endSwitchInstruction) }; var subInstructions = new[] { ILInstruction.Create(ILOpCodeValues.Sub), ILInstruction.Create(ILOpCodeValues.Br_S, endSwitchInstruction) }; addInstructions[0].Label = 0; subInstructions[0].Label = 1; var exceptionType = typeof(ArgumentOutOfRangeException); var ctor = exceptionType.GetConstructor(Type.EmptyTypes); var defaultInstuctions = new[] { ILInstruction.Create(ILOpCodeValues.Newobj, ctor.MetadataToken), ILInstruction.Create(ILOpCodeValues.Throw) }; var switchInstuction = ILInstruction.Create(ILOpCodeValues.Switch, new[] { addInstructions[0], subInstructions[0] }); var builder = new ILInstructionBuilder(); //var b= arg[b]; builder.Write(ILOpCodeValues.Ldarg_1); //var a= arg[1]; builder.Write(ILOpCodeValues.Ldarg_2); //switch(arg[0]) builder.Write(ILOpCodeValues.Ldarg_0); builder.Write(switchInstuction); //case default builder.Write(defaultInstuctions); //case 0: add builder.Write(addInstructions); //case 1: sub builder.Write(subInstructions); builder.Write(endSwitchInstruction); builder.Write(ILOpCodeValues.Ret); var frame = ILStackFrameBuilder.Build(builder.Instructions); frame.Args = new object[] { 0, 1, 2 }; frame.Execute(); var expected = 3; 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}"); expected = -1; frame.Args = new object[] { 1, 1, 2 }; frame.Execute(); 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, 1, 2 }; frame.Execute(); Assert.IsNotNull(frame.Exception, $"Executing switch failed to execute default case to and throw and exception."); Assert.IsInstanceOfType(frame.Exception, typeof(ArgumentOutOfRangeException), $"Frame failed to throw {nameof(ArgumentOutOfRangeException)}"); Assert.IsNull(frame.ReturnResult, $"Actual: {frame.ReturnResult}\r\nExpected: [null]"); //var type = BuildSwitchTestType(); //var switchMethod = type.GetMethod("SwitchTest"); //Assert.IsNotNull(switchMethod); //var instructions = ILInstructionReader.FromMethod(switchMethod); var ilMethod = new ILMethod(MethodBase.GetCurrentMethod().Name, expected.GetType()); ilMethod.AddParameters(new[] { typeof(int), typeof(int), typeof(int) }); ilMethod.AddInstructions(builder.Instructions.ToArray()); ilMethod.Module = exceptionType.Module; var method = ilMethod.Compile(); var actual = method.Invoke(null, new object[] { 0, 1, 2 }); expected = 3; Assert.IsTrue((int)actual == expected, $"Actual: {actual}\r\nExpected:{expected}"); actual = method.Invoke(null, new object[] { 1, 1, 2 }); expected = -1; Assert.IsTrue((int)actual == expected, $"Actual: {actual}\r\nExpected:{expected}"); Exception exception = null; try { actual = method.Invoke(null, new object[] { 2, 1, 2 }); } catch (TargetInvocationException ex) { exception = ex.InnerException; } Assert.IsNotNull(exception, $"Failed to catch argument exception"); Assert.IsInstanceOfType(exception, exceptionType); }
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}"); }