예제 #1
0
        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}");
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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");
        }
예제 #5
0
        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);
        }
예제 #6
0
        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}");
        }