public static void BuildAST(MethodDef method, CilBody body, ScopeBlock scope) { var builder = new ILASTBuilder(method, body, scope); var basicBlocks = scope.GetBasicBlocks().Cast <CILBlock>().ToList(); builder.BuildAST(); }
private void SearchForHandlers(ScopeBlock scope, ExceptionHandler eh, ref IBasicBlock handler, ref IBasicBlock filter) { if (scope.ExceptionHandler == eh) { if (scope.Type == ScopeType.Handler) { handler = scope.GetBasicBlocks().First(); } else if (scope.Type == ScopeType.Filter) { filter = scope.GetBasicBlocks().First(); } } foreach (var child in scope.Children) { SearchForHandlers(child, eh, ref handler, ref filter); } }
private void AddTryStart(IRTransformer tr) { var tryStartInstrs = new List <IRInstruction>(); for (int i = 0; i < this.thisScopes.Length; i++) { ScopeBlock scope = this.thisScopes[i]; if (scope.Type != ScopeType.Try) { continue; } if (scope.GetBasicBlocks().First() != tr.Block) { continue; } // Search for handler/filter IBasicBlock handler = null, filter = null; this.SearchForHandlers(tr.RootScope, scope.ExceptionHandler, ref handler, ref filter); Debug.Assert(handler != null && (scope.ExceptionHandler.HandlerType != ExceptionHandlerType.Filter || filter != null)); // Add instructions tryStartInstrs.Add(new IRInstruction(IROpCode.PUSH, new IRBlockTarget(handler))); IIROperand tryOperand = null; int ehType; if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Catch) { tryOperand = IRConstant.FromI4((int)tr.VM.Data.GetId(scope.ExceptionHandler.CatchType)); ehType = tr.VM.Runtime.RTFlags.EH_CATCH; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Filter) { tryOperand = new IRBlockTarget(filter); ehType = tr.VM.Runtime.RTFlags.EH_FILTER; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Fault) { ehType = tr.VM.Runtime.RTFlags.EH_FAULT; } else if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Finally) { ehType = tr.VM.Runtime.RTFlags.EH_FINALLY; } else { throw new InvalidProgramException(); } tryStartInstrs.Add(new IRInstruction(IROpCode.TRY, IRConstant.FromI4(ehType), tryOperand) { Annotation = new EHInfo(scope.ExceptionHandler) }); } tr.Instructions.InsertRange(0, tryStartInstrs); }
private ILASTBuilder(MethodDef method, CilBody body, ScopeBlock scope) { this.method = method; this.body = body; this.scope = scope; this.basicBlocks = scope.GetBasicBlocks().Cast <CILBlock>().ToList(); this.blockHeaders = this.basicBlocks.ToDictionary(block => block.Content[0], block => block); this.blockStates = new Dictionary <CILBlock, BlockState>(); this.instrReferences = new List <ILASTExpression>(); Debug.Assert(this.basicBlocks.Count > 0); }
public void Transform(IRTransformer tr) { this.thisScopes = tr.RootScope.SearchBlock(tr.Block); this.AddTryStart(tr); if (this.thisScopes[this.thisScopes.Length - 1].Type == ScopeType.Handler) { ScopeBlock tryScope = this.SearchForTry(tr.RootScope, this.thisScopes[this.thisScopes.Length - 1].ExceptionHandler); ScopeBlock[] scopes = tr.RootScope.SearchBlock(tryScope.GetBasicBlocks().First()); this.thisScopes = scopes.TakeWhile(s => s != tryScope).ToArray(); } tr.Instructions.VisitInstrs(this.VisitInstr, tr); }
public void AddMethod(MethodDef method, ScopeBlock rootScope) { ILBlock entry = null; foreach (ILBlock block in rootScope.GetBasicBlocks()) { if (block.Id == 0) { entry = block; } basicBlocks.Add(Tuple.Create(method, block)); } Debug.Assert(entry != null); methodMap[method] = Tuple.Create(rootScope, entry); }
void ComputeBlockKeys(ScopeBlock rootScope) { var blocks = rootScope.GetBasicBlocks().OfType <ILBlock>().ToList(); uint id = 1; Keys = blocks.ToDictionary( block => block, block => new BlockKey { Entry = id++, Exit = id++ }); var ehMap = MapEHs(rootScope); bool updated; do { updated = false; BlockKey key; key = Keys[blocks[0]]; key.Entry = 0xfffffffe; Keys[blocks[0]] = key; key = Keys[blocks[blocks.Count - 1]]; key.Exit = 0xfffffffd; Keys[blocks[blocks.Count - 1]] = key; // Update the state ids with the maximum id foreach (var block in blocks) { key = Keys[block]; if (block.Sources.Count > 0) { uint newEntry = block.Sources.Select(b => Keys[(ILBlock)b].Exit).Max(); if (key.Entry != newEntry) { key.Entry = newEntry; updated = true; } } if (block.Targets.Count > 0) { uint newExit = block.Targets.Select(b => Keys[(ILBlock)b].Entry).Max(); if (key.Exit != newExit) { key.Exit = newExit; updated = true; } } Keys[block] = key; } // Match finally enter = finally exit = try end exit // Match filter start = 0xffffffff MatchHandlers(ehMap, ref updated); } while (updated); // Replace id with actual values var idMap = new Dictionary <uint, uint>(); idMap[0xffffffff] = 0; idMap[0xfffffffe] = methodInfo.EntryKey; idMap[0xfffffffd] = methodInfo.ExitKey; foreach (var block in blocks) { var key = Keys[block]; uint entryId = key.Entry; if (!idMap.TryGetValue(entryId, out key.Entry)) { key.Entry = idMap[entryId] = (byte)runtime.Descriptor.Random.Next(); } uint exitId = key.Exit; if (!idMap.TryGetValue(exitId, out key.Exit)) { key.Exit = idMap[exitId] = (byte)runtime.Descriptor.Random.Next(); } Keys[block] = key; } }
void MapEHsInternal(ScopeBlock scope, EHMap map) { if (scope.Type == ScopeType.Filter) { map.Starts.Add((ILBlock)scope.GetBasicBlocks().First()); } else if (scope.Type != ScopeType.None) { if (scope.ExceptionHandler.HandlerType == ExceptionHandlerType.Finally) { FinallyInfo info; if (!map.Finally.TryGetValue(scope.ExceptionHandler, out info)) { map.Finally[scope.ExceptionHandler] = info = new FinallyInfo(); } if (scope.Type == ScopeType.Try) { // Try End Next var scopeBlocks = new HashSet <IBasicBlock>(scope.GetBasicBlocks()); foreach (ILBlock block in scopeBlocks) { if ((block.Flags & BlockFlags.ExitEHLeave) != 0 && (block.Targets.Count == 0 || block.Targets.Any(target => !scopeBlocks.Contains(target)))) { foreach (var target in block.Targets) { info.TryEndNexts.Add((ILBlock)target); } } } } else if (scope.Type == ScopeType.Handler) { // Finally End IEnumerable <IBasicBlock> candidates; if (scope.Children.Count > 0) { // Only ScopeType None can endfinally candidates = scope.Children .Where(s => s.Type == ScopeType.None) .SelectMany(s => s.GetBasicBlocks()); } else { candidates = scope.Content; } foreach (ILBlock block in candidates) { if ((block.Flags & BlockFlags.ExitEHReturn) != 0 && block.Targets.Count == 0) { info.FinallyEnds.Add(block); } } } } if (scope.Type == ScopeType.Handler) { map.Starts.Add((ILBlock)scope.GetBasicBlocks().First()); } } foreach (var child in scope.Children) { MapEHsInternal(child, map); } }