public void TestCompilerAssembler()
        {
            JitAction action = new JitAction();
            Compiler c = action.GetCompiler();
            Assert.IsNotNull(c);
            Assert.AreSame(c, action.GetCompiler());

            Assembler a = action.GetAssembler();
        }
        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;
        }