private void BuildASTInternal() { var workList = new Stack <CILBlock>(); PopulateBeginStates(workList); var visited = new HashSet <CILBlock>(); while (workList.Count > 0) { var block = workList.Pop(); if (visited.Contains(block)) { continue; } visited.Add(block); Debug.Assert(blockStates.ContainsKey(block)); var state = blockStates[block]; Debug.Assert(state.ASTTree == null); var tree = BuildAST(block.Content, state.BeginStack); var remains = tree.StackRemains; state.ASTTree = tree; blockStates[block] = state; // Propagate stack states foreach (var successor in block.Targets) { BlockState successorState; if (!blockStates.TryGetValue(successor, out successorState)) { var blockVars = new ILASTVariable[remains.Length]; for (var 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 }; blockStates[successor] = successorState; } else { if (successorState.BeginStack.Length != remains.Length) { throw new InvalidProgramException("Inconsistent stack depth."); } } workList.Push(successor); } } }
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; }
public IRVariable ResolveVRegister(ILASTVariable variable) { if (variable.VariableType == ILASTVariableType.ExceptionVar) { return(this.ResolveExceptionVar((ExceptionHandler)variable.Annotation)); } if (this.varMap.TryGetValue(variable, out IRVariable vReg)) { return(vReg); } vReg = this.AllocateVRegister(variable.Type); this.varMap[variable] = vReg; return(vReg); }
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); }
private void PopulateBeginStates(Stack <CILBlock> workList) { for (int i = 0; i < this.body.ExceptionHandlers.Count; i++) { ExceptionHandler eh = this.body.ExceptionHandlers[i]; this.blockStates[this.blockHeaders[eh.TryStart]] = new BlockState { BeginStack = new ILASTVariable[0] }; CILBlock handlerBlock = this.blockHeaders[eh.HandlerStart]; workList.Push(handlerBlock); if (eh.HandlerType == ExceptionHandlerType.Fault || eh.HandlerType == ExceptionHandlerType.Finally) { this.blockStates[handlerBlock] = new BlockState { BeginStack = new ILASTVariable[0] }; } else { var type = TypeInference.ToASTType(eh.CatchType.ToTypeSig()); // Do not process overlapped handler blocks twice if (!this.blockStates.ContainsKey(handlerBlock)) { var exVar = new ILASTVariable { Name = string.Format("ex_{0:x2}", i), Type = type, VariableType = ILASTVariableType.ExceptionVar, Annotation = eh }; this.blockStates[handlerBlock] = new BlockState { BeginStack = new[] { exVar } }; } else { Debug.Assert(this.blockStates[handlerBlock].BeginStack.Length == 1); } if (eh.FilterStart != null) { var filterVar = new ILASTVariable { Name = string.Format("ef_{0:x2}", i), Type = type, VariableType = ILASTVariableType.FilterVar, Annotation = eh }; CILBlock filterBlock = this.blockHeaders[eh.FilterStart]; workList.Push(filterBlock); this.blockStates[filterBlock] = new BlockState { BeginStack = new[] { filterVar } }; } } } this.blockStates[this.basicBlocks[0]] = new BlockState { BeginStack = new ILASTVariable[0] }; workList.Push(this.basicBlocks[0]); foreach (CILBlock block in this.basicBlocks) { if (block.Sources.Count > 0) { continue; } if (workList.Contains(block)) { continue; } this.blockStates[block] = new BlockState { BeginStack = new ILASTVariable[0] }; workList.Push(block); } }
private IRInstrList Translate(BasicBlock <ILASTTree> block) { this.Block = block; this.Instructions = new IRInstrList(); bool seenJump = false; foreach (IILASTStatement st in block.Content) { if (st is ILASTPhi) { ILASTVariable variable = ((ILASTPhi)st).Variable; this.Instructions.Add(new IRInstruction(IROpCode.POP) { Operand1 = this.Context.ResolveVRegister(variable), ILAST = st }); } else if (st is ILASTAssignment assignment) { IIROperand valueVar = this.Translate(assignment.Value); this.Instructions.Add(new IRInstruction(IROpCode.MOV) { Operand1 = this.Context.ResolveVRegister(assignment.Variable), Operand2 = valueVar, ILAST = st }); } else if (st is ILASTExpression expr) { var opCode = expr.ILCode.ToOpCode(); if (!seenJump && (opCode.FlowControl == FlowControl.Cond_Branch || opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Return || opCode.FlowControl == FlowControl.Throw)) { // Add stack remain before jumps foreach (ILASTVariable remain in block.Content.StackRemains) { this.Instructions.Add(new IRInstruction(IROpCode.PUSH) { Operand1 = this.Context.ResolveVRegister(remain), ILAST = st }); } seenJump = true; } this.Translate((ILASTExpression)st); } else { throw new NotSupportedException(); } } Debug.Assert(seenJump); IRInstrList ret = this.Instructions; this.Instructions = null; return(ret); }