private void BuildASTInternal() { var workList = new Stack <CILBlock>(); this.PopulateBeginStates(workList); var visited = new HashSet <CILBlock>(); while (workList.Count > 0) { CILBlock block = workList.Pop(); if (visited.Contains(block)) { continue; } visited.Add(block); Debug.Assert(this.blockStates.ContainsKey(block)); BlockState state = this.blockStates[block]; Debug.Assert(state.ASTTree == null); ILASTTree tree = this.BuildAST(block.Content, state.BeginStack); ILASTVariable[] remains = tree.StackRemains; state.ASTTree = tree; this.blockStates[block] = state; // Propagate stack states foreach (CILBlock successor in block.Targets) { if (!this.blockStates.TryGetValue(successor, out BlockState successorState)) { var blockVars = new ILASTVariable[remains.Length]; for (int i = 0; i < blockVars.Length; i++) { blockVars[i] = new ILASTVariable { Name = string.Format("ph_{0:x2}_{1:x2}", successor.Id, i), Type = remains[i].Type, VariableType = ILASTVariableType.PhiVar } } ; successorState = new BlockState { BeginStack = blockVars }; this.blockStates[successor] = successorState; } else { if (successorState.BeginStack.Length != remains.Length) { throw new InvalidProgramException("Inconsistent stack depth."); } } workList.Push(successor); } } }
private ILASTTree BuildAST(CILInstrList instrs, ILASTVariable[] beginStack) { var tree = new ILASTTree(); var evalStack = new Stack <ILASTVariable>(beginStack); Func <int, IILASTNode[]> popArgs = numArgs => { var args = new IILASTNode[numArgs]; for (int i = numArgs - 1; i >= 0; i--) { args[i] = evalStack.Pop(); } return(args); }; var prefixes = new List <Instruction>(); foreach (Instruction instr in instrs) { if (instr.OpCode.OpCodeType == OpCodeType.Prefix) { prefixes.Add(instr); continue; } int pushes, pops; ILASTExpression expr; if (instr.OpCode.Code == Code.Dup) { pushes = pops = 1; ILASTVariable arg = evalStack.Peek(); expr = new ILASTExpression { ILCode = Code.Dup, Operand = null, Arguments = new IILASTNode[] { arg } }; } else { instr.CalculateStackUsage(this.method.ReturnType.ElementType != ElementType.Void, out pushes, out pops); Debug.Assert(pushes == 0 || pushes == 1); if (pops == -1) { evalStack.Clear(); pops = 0; } expr = new ILASTExpression { ILCode = instr.OpCode.Code, Operand = instr.Operand, Arguments = popArgs(pops) }; if (expr.Operand is Instruction || expr.Operand is Instruction[]) { this.instrReferences.Add(expr); } } expr.CILInstr = instr; if (prefixes.Count > 0) { expr.Prefixes = prefixes.ToArray(); prefixes.Clear(); } if (pushes == 1) { var variable = new ILASTVariable { Name = string.Format("s_{0:x4}", instr.Offset), VariableType = ILASTVariableType.StackVar }; evalStack.Push(variable); tree.Add(new ILASTAssignment { Variable = variable, Value = expr }); } else { tree.Add(expr); } } tree.StackRemains = evalStack.Reverse().ToArray(); return(tree); }
static void TransformSTELEM(ILASTExpression expr, ModuleDef module, ITypeDefOrRef type, ILASTTree tree, ref int index) { var array = module.CorLibTypes.GetTypeRef("System", "Array"); var setValSig = MethodSig.CreateInstance(module.CorLibTypes.Void, module.CorLibTypes.Object, module.CorLibTypes.Int32); var setValRef = new MemberRefUser(module, "SetValue", setValSig, array); ILASTVariable tmpVar1, tmpVar2; if (expr.Arguments[1] is ILASTVariable) { tmpVar1 = (ILASTVariable)expr.Arguments[1]; } else { tmpVar1 = new ILASTVariable { Name = string.Format("arr_{0:x4}_1", expr.CILInstr.Offset), VariableType = ILASTVariableType.StackVar }; tree.Insert(index++, new ILASTAssignment { Variable = tmpVar1, Value = (ILASTExpression)expr.Arguments[1] }); } if (expr.Arguments[2] is ILASTVariable) { tmpVar2 = (ILASTVariable)expr.Arguments[2]; } else { tmpVar2 = new ILASTVariable { Name = string.Format("arr_{0:x4}_2", expr.CILInstr.Offset), VariableType = ILASTVariableType.StackVar }; tree.Insert(index++, new ILASTAssignment { Variable = tmpVar2, Value = (ILASTExpression)expr.Arguments[2] }); } if (type.IsPrimitive) { var elem = new ILASTExpression { ILCode = Code.Box, Operand = type, Arguments = new[] { tmpVar2 } }; expr.Arguments[2] = tmpVar1; expr.Arguments[1] = elem; } else { expr.Arguments[2] = tmpVar1; expr.Arguments[1] = tmpVar2; } expr.ILCode = Code.Call; expr.Operand = setValRef; }