/// <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); }