public ILStack Clone() { ILStack clone = new ILStack(); foreach(Slot s in this.Items) { clone.Items.Add(new Slot(s.PushedBy, s.Type)); } return clone; }
public void StackAnalysis(List<Instruction> body, MethodDefinition methodDef) { Queue<Instruction> agenda = new Queue<Instruction>(); // Add known states stackBefore[body[0]] = new ILStack(); agenda.Enqueue(body[0]); if(methodDef.Body.HasExceptionHandlers) { foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { stackBefore[ex.TryStart] = new ILStack(); agenda.Enqueue(ex.TryStart); ILStack stack = new ILStack(); stack.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); stackBefore[ex.HandlerStart] = stack; agenda.Enqueue(ex.HandlerStart); } } // Process agenda while(agenda.Count > 0) { Instruction inst = agenda.Dequeue(); // What is the effect of the instruction on the stack? ILStack newStack = stackBefore[inst].Clone(); int popCount = inst.GetPopCount(); if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all List<TypeReference> typeArgs = new List<TypeReference>(); for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { typeArgs.Add(newStack.Items[i].Type); } TypeReference type; try { type = inst.GetTypeInternal(methodDef, typeArgs); } catch { type = MyRocks.TypeObject; } if (popCount > 0) { newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); } int pushCount = inst.GetPushCount(); for (int i = 0; i < pushCount; i++) { newStack.Items.Add(new ILStack.Slot(inst, type)); } // Apply the state to any successors List<Instruction> branchTargets = new List<Instruction>(); if (inst.OpCode.CanFallThough()) { branchTargets.Add(inst.Next); } if (inst.OpCode.IsBranch()) { if (inst.Operand is Instruction[]) { branchTargets.AddRange((Instruction[])inst.Operand); } else { branchTargets.Add((Instruction)inst.Operand); } } foreach (Instruction branchTarget in branchTargets) { ILStack nextStack; if (stackBefore.TryGetValue(branchTarget, out nextStack)) { // TODO: Compare stacks } else { stackBefore[branchTarget] = newStack; agenda.Enqueue(branchTarget); } } } }