private void BuildPhiNodes() { foreach (KeyValuePair <CILBlock, BlockState> statePair in this.blockStates) { CILBlock block = statePair.Key; BlockState state = statePair.Value; // source count = 0 => eh handlers begin state, having ex object if (block.Sources.Count == 0 && state.BeginStack.Length > 0) { Debug.Assert(state.BeginStack.Length == 1); var phi = new ILASTPhi { Variable = state.BeginStack[0], SourceVariables = new[] { state.BeginStack[0] } }; state.ASTTree.Insert(0, phi); } else if (state.BeginStack.Length > 0) { for (int varIndex = 0; varIndex < state.BeginStack.Length; varIndex++) { var phi = new ILASTPhi { Variable = state.BeginStack[varIndex] }; phi.SourceVariables = new ILASTVariable[block.Sources.Count]; for (int i = 0; i < phi.SourceVariables.Length; i++) { phi.SourceVariables[i] = this.blockStates[block.Sources[i]].ASTTree.StackRemains[varIndex]; } // reverse phi nodes => pop in correct order state.ASTTree.Insert(0, phi); } } } }
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 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); } }