Beispiel #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));
        }
        private object GetInvocationTarget(MethodBody body, Instruction callInstruction, object outerTarget)
        {
            var instructions = body.Instructions.ToList();
            var index        = instructions.IndexOf(callInstruction);

            instructions.RemoveRange(index, instructions.Count - index);
            instructions.Add(Instruction.Create(OpCodes.Pop));
            instructions.Add(Instruction.Create(OpCodes.Ret));

            // Gets the parameters used by the instructions.
            TypeReference[] parameterTypes = _parameterDeducer.GetParameters(body.Method, instructions);

            object arg = _instructionsCompiler
                         .Compile <object>(parameterTypes, instructions, new VariableDefinition[0])
                         .Invoke(new[] { outerTarget });

            return(arg);
        }