public void TestCompileCaching() { JitAction action = new JitAction(); Compiler c = action.GetCompiler(); c.Ret(); Assert.AreEqual(IntPtr.Zero, action.CompiledAddress); Assert.IsFalse(action.IsCompiled); action.Compile(); Assert.AreNotEqual(IntPtr.Zero, action.CompiledAddress); Assert.IsTrue(action.IsCompiled); IntPtr ptr1 = action.CompiledAddress; action.Compile(); Assert.AreEqual(ptr1, action.CompiledAddress); }
private JitAction<int> GenerateCode() { //Action<bool> sample = // throwException => // { // try // { // Console.WriteLine(0); // if (throwException) // throw new Exception("1"); // } // catch (Exception e) // { // Console.WriteLine(e.Message); // } // finally // { // Console.WriteLine(2); // } // }; JitFunction<IntPtr> getInstructionPointer = new JitFunction<IntPtr>(hints: FunctionHints.Naked); { Assembler assembler = getInstructionPointer.GetAssembler(); assembler.Mov(Register.nax, Register.nbp); assembler.Ret(); getInstructionPointer.Compile(); } JitAction<int> testMethod = new JitAction<int>(); unsafe { _threadData = (ThreadData*)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ThreadData))); Marshal.StructureToPtr(new ThreadData(), (IntPtr)_threadData, false); Compiler c = testMethod.GetCompiler(); c.Logger = new FileLogger(Console.Error); // arguments GPVar argThrowException = c.ArgGP(0); // special variables GPVar currentException = c.NewGP(); GPVar nextException = c.NewGP(); GPVar position = c.NewGP(); // special prolog GPVar varMethodData = c.NewGP(); GPVar varThreadData = c.NewGP(); c.Mov(varThreadData, (IntPtr)_threadData); // labels Label leaveTry = c.DefineLabel(); Label enterCatch = c.DefineLabel(); Label leaveCatch = c.DefineLabel(); Label enterFinally = c.DefineLabel(); Label leaveFinally = c.DefineLabel(); Label enterThrowHandler = c.DefineLabel(); Label enterRethrowHandler = c.DefineLabel(); Label enterLeaveHandler = c.DefineLabel(); Label enterEndFinallyHandler = c.DefineLabel(); Label retLabel = c.DefineLabel(); // try c.Comment("Enter try"); GenerateWriteLine(c, (Imm)0); c.Test(argThrowException, argThrowException); c.Jz(leaveTry, Hint.Taken); GenerateNewException(c, nextException, (Imm)1); c.Call(getInstructionPointer, position); c.Jmp(enterThrowHandler); c.MarkLabel(leaveTry); c.Jmp(enterLeaveHandler); // catch c.Comment("Enter catch"); c.MarkLabel(enterCatch); GPVar varErrorCode = c.NewGP(); GenerateLoadCurrentException(c, varErrorCode, varThreadData); GenerateLoadExceptionMessage(c, varErrorCode, varErrorCode); GenerateWriteLine(c, varErrorCode); c.Xor(varErrorCode, varErrorCode); c.Mov(Mem.sysint_ptr(varThreadData, ThreadData_ExceptionDataOffset), varErrorCode); c.MarkLabel(leaveCatch); c.Jmp(enterLeaveHandler); // finally c.Comment("Enter finally"); c.MarkLabel(enterFinally); GenerateWriteLine(c, (Imm)2); c.MarkLabel(leaveFinally); c.Jmp(enterEndFinallyHandler); //// special epilog (throw and leave implementations) //c.Jmp(retLabel); c.Comment("Handler for 'throw' instructions"); c.MarkLabel(enterThrowHandler); c.Mov(Mem.sysint_ptr(varThreadData, ThreadData_ExceptionDataOffset), nextException); c.Jmp(enterCatch); c.Comment("Handler for 'rethrow' instructions"); c.MarkLabel(enterRethrowHandler); // rethrow is not implemented and not currently used c.Int3(); c.Comment("Handler for 'leave' instructions"); c.MarkLabel(enterLeaveHandler); c.Jmp(enterFinally); //c.Mov(Mem.sysint_ptr(varThreadData, ThreadData_ExceptionDataOffset), 0); //throw new NotImplementedException("TODO: check for a finally block"); //c.Jmp(leaveTarget); c.Comment("Handler for 'endfinally' instructions"); c.MarkLabel(enterEndFinallyHandler); GenerateLoadCurrentException(c, currentException, varThreadData); c.Test(currentException, currentException); c.Jnz(enterRethrowHandler, Hint.NotTaken); c.Jmp(retLabel); // return c.Comment("Return"); c.MarkLabel(retLabel); c.Ret(); testMethod.Compile(); } return testMethod; }