示例#1
0
        /// <summary>
        /// Decompiles an expression that's on the stack at the specified
        /// instruction in the specified method. This is done by reversing from the
        /// specified instruction until the stack should be empty. The instructions
        /// can then be replayed from that point.
        /// </summary>
        /// <param name="body">The body.</param>
        /// <param name="instruction">The instruction.</param>
        /// <param name="target">The target of the method, if any.</param>
        /// <param name="expectedStackSize">The number of objects expected to be on the stack when we get to the instruction.</param>
        /// <param name="stackEntriesToSkip">The number of stack entries to skip.</param>
        /// <returns>
        /// The compiled expression.
        /// </returns>
        public TExpression Decompile(MethodBody body, Instruction instruction, object target, int expectedStackSize, int stackEntriesToSkip)
        {
            ArgumentChecker.Assert <ArgumentException>(
                stackEntriesToSkip < expectedStackSize,
                "Cannot skip more elements than there are on the stack",
                nameof(stackEntriesToSkip));

            BitArray includedInstructions = new BitArray(body.Instructions.Count);

            if (IncludeInstructionsUntilStackEmpty(body, instruction, includedInstructions, expectedStackSize))
            {
                List <Instruction> instructions = body.Instructions
                                                  .Where((t, i) => includedInstructions[i])
                                                  .ToList();

                List <VariableDefinition> variables      = body.Variables.ToList();
                VariableDefinition        resultVariable = new VariableDefinition(body.Method.Module.Import(typeof(TExpression)));
                variables.Add(resultVariable);

                for (int i = 0; i < expectedStackSize; ++i)
                {
                    if (i == stackEntriesToSkip)
                    {
                        instructions.Add(Instruction.Create(OpCodes.Stloc, resultVariable));
                    }
                    else
                    {
                        instructions.Add(Instruction.Create(OpCodes.Pop));
                    }
                }

                instructions.Add(Instruction.Create(OpCodes.Ldloc, resultVariable));

                // Gets the parameters used by the instructions.
                TypeReference[] parameterTypes         = _parameterDeducer.GetParameters(body.Method, instructions);
                Type[]          resolvedParameterTypes = parameterTypes.Select(_typeResolver.Resolve).ToArray();

                // TODO: pass only the used variables instead of Body.Variables.
                // Currently, this is bugged so body.Variables is used. The additional
                // variables are not really an issue.
                ICompiledMethod <TExpression> method = _instructionsCompiler.Compile <TExpression>(
                    parameterTypes, instructions, variables);

                // Try to construct the arguments required by the instructions.
                object[] arguments = _argumentGenerator.GetArguments(resolvedParameterTypes, target).ToArray();

                return(method.Invoke(arguments));
            }

            return(default(TExpression));
        }
示例#2
0
        protected List <ICompiledMethod> CompileMethod(MethodDefinition initialMethod)
        {
            Dictionary <MethodReference, string> visitedMethods = new Dictionary <MethodReference, string>();
            List <ICompiledMethod> methods   = new List <ICompiledMethod>();
            ICompiledMethod        initialCm = AccCIL.JIT(this.Compiler, initialMethod);

            methods.Add(initialCm);
            visitedMethods.Add(initialMethod, null);

            Queue <ICompiledMethod> work = new Queue <ICompiledMethod>();

            work.Enqueue(initialCm);

            while (work.Count > 0)
            {
                ICompiledMethod cur   = work.Dequeue();
                var             calls = from x in cur.Method.FlatInstructionList
                                        let code = x.Instruction.OpCode.Code
                                                   where code == Mono.Cecil.Cil.Code.Call || code == Mono.Cecil.Cil.Code.Calli || code == Mono.Cecil.Cil.Code.Callvirt
                                                   select((Mono.Cecil.MethodReference) x.Instruction.Operand);

                foreach (MethodReference mr in calls)
                {
                    if (visitedMethods.ContainsKey(mr))
                    {
                        continue;
                    }

                    visitedMethods.Add(mr, null);

                    if (m_functionFilter(initialMethod, cur.Method.Method, mr))
                    {
                        MethodDefinition md = AccCIL.FindMethod(mr);
                        if (md == null)
                        {
                            throw new Exception("Unable to locate the method " + mr.DeclaringType.FullName + "::" + mr.Name + " in assembly " + mr.DeclaringType.Module.Assembly.Name.FullName);
                        }
                        ICompiledMethod cm = AccCIL.JIT(this.Compiler, md);
                        work.Enqueue(cm);
                        methods.Add(cm);
                    }
                }
            }

            return(methods);
        }