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