private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
        {
            DynValue tail = m_ValueStack.Peek(0);

            if (tail.Type == DataType.TailCallRequest)
            {
                m_ValueStack.Pop();                 // discard tail call request

                TailCallData tcd = tail.TailCallData;

                m_ValueStack.Push(tcd.Function);

                for (int ii = 0; ii < tcd.Args.Length; ii++)
                {
                    m_ValueStack.Push(tcd.Args[ii]);
                }

                return(Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation, false, null, tcd.ErrorHandlerBeforeUnwind));
            }
            else if (tail.Type == DataType.YieldRequest)
            {
                m_SavedInstructionPtr = instructionPtr;
                return(YIELD_SPECIAL_TRAP);
            }


            return(instructionPtr);
        }
Exemple #2
0
        /// <summary>
        /// Rewrite a tail recursive (but not using .NET tail recursion)
        /// function of the form myFunc(argument, accumulator) into a
        /// tail-recursive (with .NET tail recursion) form of same
        /// </summary>
        /// <typeparam name="A">The type of the argument to a simple recursive form of the function</typeparam>
        /// <typeparam name="R">The type of the result of the function</typeparam>
        /// <param name="nonTailRecursive">A function with a tail call, where
        /// the first argument is the argument to the non-tail-recursive
        /// form of the function, and the second is an accumulator for the
        /// result</param>
        /// <returns></returns>
        public static Func <A, R, R> Rewrite <A, R>(object self, Func <A, R, R> nonTailRecursive)
        {
            MethodInfo         methodInfo         = nonTailRecursive.Method;
            string             assembly           = methodInfo.DeclaringType.Assembly.Location;
            string             assemblyExt        = System.IO.Path.GetExtension(assembly);
            string             tempFileName       = System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), assemblyExt);
            AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(assembly);
            TypeDefinition     typeDefinition     = assemblyDefinition.MainModule.GetType(methodInfo.DeclaringType.FullName);

            assemblyDefinition.Name            = new AssemblyNameDefinition("Rewritten", new Version(1, 0));
            assemblyDefinition.MainModule.Name = System.IO.Path.GetFileName(tempFileName);
            typeDefinition.Name      = "RewrittenType";
            typeDefinition.Namespace = "RewrittenNamespace";
            //MethodDefinition recursiveCall = new MethodDefinition()
            MethodDefinition definition      = typeDefinition.Methods.Single(m => m.Name == methodInfo.Name);
            MethodReference  methodReference = assemblyDefinition.MainModule.Import(methodInfo);
            ILProcessor      ilProcessor     = definition.Body.GetILProcessor();

            definition.Body.SimplifyMacros();
            TailCallData tailCallData = TryFindTailCall(definition.Body.Instructions, definition);

            while (tailCallData != null)
            {
                // rewrite as tail call
                // Step 1: Remove stloc/ldloc/br.s instructions before ret instruction
                for (var index = tailCallData.RetIndex - 1; index > tailCallData.CallIndex; index--)
                {
                    ilProcessor.Remove(definition.Body.Instructions[index]);
                }
                // Step 2: Rewrite any stloc/br "returns" as proper rets
                foreach (var otherExit in tailCallData.OtherExits)
                {
                    ilProcessor.Replace(otherExit.BrInstruction, Instruction.Create(OpCodes.Ret));
                    ilProcessor.Remove(otherExit.StlocInstruction);
                }

                // Step 3: Insert "tail" IL instruction before call
                ilProcessor.InsertBefore(tailCallData.CallInstruction, ilProcessor.Create(OpCodes.Tail));

                // any more?
                tailCallData = TryFindTailCall(definition.Body.Instructions, definition);
            }
            definition.Body.OptimizeMacros();
            assemblyDefinition.Write(tempFileName);
            Assembly   rewrittenAssembly = Assembly.LoadFile(tempFileName);
            Type       rewrittenType     = rewrittenAssembly.GetType(definition.DeclaringType.FullName);
            MethodInfo rewrittenMethod   = rewrittenType.GetMethod(
                definition.Name,
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static,
                null,
                new[] { typeof(A), typeof(R) },
                null);
            Expression instance = self != null?Expression.Constant(self) : null;

            Func <A, R, R> result = (Func <A, R, R>)Delegate.CreateDelegate(typeof(Func <A, R, R>), rewrittenMethod);

            return(result);
        }
Exemple #3
0
 private static TailCallData TryFindTailCall(Mono.Collections.Generic.Collection <Instruction> instructions, MethodDefinition method)
 {
     foreach (var item in instructions.Select((instruction, index) => new { instruction, index }))
     {
         TailCallData tailCallData = TryGetTailCallData(item.index, method);
         if (tailCallData != null)
         {
             return(tailCallData);
         }
     }
     return(null);
 }