static void CalculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) { instr.CalculateStackUsage(false, out pushes, out pops); }
bool EmulateToReturn(int index, Instruction lastInstr) { int pushes, pops; lastInstr.CalculateStackUsage(false, out pushes, out pops); instructionEmulator.Pop(pops); returnValue = null; if (pushes != 0) { returnValue = new UnknownValue(); instructionEmulator.SetProtected(returnValue); instructionEmulator.Push(returnValue); } if (!EmulateInstructions(ref index, true)) return false; if (index >= methodToInline.Body.Instructions.Count) return false; if (methodToInline.Body.Instructions[index].OpCode.Code != Code.Ret) return false; if (returnValue != null) { if (instructionEmulator.Pop() != returnValue) return false; } return instructionEmulator.StackSize() == 0; }
/// <summary> /// Traces the arguments of the specified call instruction. /// </summary> /// <param name="instr">The call instruction.</param> /// <returns>The indexes of the begin instruction of arguments.</returns> /// <exception cref="System.ArgumentException">The specified call instruction is invalid.</exception> /// <exception cref="InvalidMethodException">The method body is invalid.</exception> public int[] TraceArguments(Instruction instr) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj) throw new ArgumentException("Invalid call instruction.", "instr"); int push, pop; instr.CalculateStackUsage(out push, out pop); // pop is number of arguments if (pop == 0) return new int[0]; int instrIndex = offset2index[instr.Offset]; int argCount = pop; int targetStack = BeforeStackDepths[instrIndex] - argCount; // Find the begin instruction of method call int beginInstrIndex = -1; var seen = new HashSet<uint>(); var working = new Queue<int>(); working.Enqueue(offset2index[instr.Offset] - 1); while (working.Count > 0) { int index = working.Dequeue(); while (index >= 0) { if (BeforeStackDepths[index] == targetStack) break; if (fromInstrs.ContainsKey(index)) foreach (Instruction fromInstr in fromInstrs[index]) { if (!seen.Contains(fromInstr.Offset)) { seen.Add(fromInstr.Offset); working.Enqueue(offset2index[fromInstr.Offset]); } } index--; } if (index < 0) return null; if (beginInstrIndex == -1) beginInstrIndex = index; else if (beginInstrIndex != index) return null; } // Trace the index of arguments seen.Clear(); var working2 = new Queue<Tuple<int, Stack<int>>>(); working2.Clear(); working2.Enqueue(Tuple.Create(beginInstrIndex, new Stack<int>())); int[] ret = null; while (working2.Count > 0) { Tuple<int, Stack<int>> tuple = working2.Dequeue(); int index = tuple.Item1; Stack<int> evalStack = tuple.Item2; while (index != instrIndex && index < method.Body.Instructions.Count) { Instruction currentInstr = Instructions[index]; currentInstr.CalculateStackUsage(out push, out pop); int stackUsage = pop - push; if (stackUsage < 0) { Debug.Assert(stackUsage == -1); // i.e. push evalStack.Push(index); } else { if (evalStack.Count < stackUsage) return null; for (int i = 0; i < stackUsage; i++) evalStack.Pop(); } object instrOperand = currentInstr.Operand; if (currentInstr.Operand is Instruction) { int targetIndex = offset2index[((Instruction)currentInstr.Operand).Offset]; if (currentInstr.OpCode.FlowControl == FlowControl.Branch) index = targetIndex; else { working2.Enqueue(Tuple.Create(targetIndex, new Stack<int>(evalStack))); index++; } } else if (currentInstr.Operand is Instruction[]) { foreach (Instruction targetInstr in (Instruction[])currentInstr.Operand) working2.Enqueue(Tuple.Create(offset2index[targetInstr.Offset], new Stack<int>(evalStack))); index++; } else index++; } if (evalStack.Count != argCount) return null; if (ret != null && !evalStack.SequenceEqual(ret)) return null; ret = evalStack.ToArray(); } if (ret == null) return ret; Array.Reverse(ret); return ret; }
bool VerifyValidArgs(Instruction instr) { int pushes, pops; instr.CalculateStackUsage(out pushes, out pops); if (pops < 0) return false; bool retVal; Value val2, val1; switch (pops) { case 0: return true; case 1: val1 = instructionEmulator.Pop(); retVal = VerifyValidArg(val1); instructionEmulator.Push(val1); return retVal; case 2: val2 = instructionEmulator.Pop(); val1 = instructionEmulator.Pop(); retVal = VerifyValidArg(val2) && VerifyValidArg(val1); instructionEmulator.Push(val1); instructionEmulator.Push(val2); return retVal; } return false; }
void UpdateStack(Instruction instr) { int pushes, pops; instr.CalculateStackUsage(out pushes, out pops); if (pops == -1) valueStack.Clear(); else { valueStack.Pop(pops); valueStack.Push(pushes); } }
void Emulate_Call(Instruction instr, IMethod method) { int pushes, pops; instr.CalculateStackUsage(out pushes, out pops); valueStack.Pop(pops); if (pushes == 1) valueStack.Push(GetUnknownValue(method.MethodSig.GetRetType())); else valueStack.Push(pushes); }