private void EmitInstructions(ControlAndDataFlowGraph<EnhancedBasicBlock<Instruction>, Instruction> cdfg) { Contract.Requires(cdfg != null); foreach (var block in cdfg.AllBlocks) { Contract.Assume(block != null); this.sourceEmitter.EmitLabel("l" + block.Offset.ToString("x4") + ":"); this.sourceEmitter.EmitNewLine(); bool first = true; this.previousInstruction = null; foreach (var instruction in block.Instructions) { Contract.Assume(instruction != null); if (first && this.catchHandlerOffsets.Contains(instruction.Operation.Offset+1)) { this.sourceEmitter.EmitString("originalException = exception;"); this.sourceEmitter.EmitNewLine(); } first = false; if (!this.EmitInstruction(instruction)) continue; if (instruction.Operation.OperationCode != OperationCode.Unaligned_) this.previousInstruction = instruction; this.sourceEmitter.EmitString(";"); this.sourceEmitter.EmitNewLine(); } } }
internal InstructionParser(SourceMethodBody sourceMethodBody) { Contract.Requires(sourceMethodBody != null); this.sourceMethodBody = sourceMethodBody; this.host = sourceMethodBody.host; Contract.Assume(this.host != null); this.ilMethodBody = sourceMethodBody.ilMethodBody; Contract.Assume(this.ilMethodBody != null); this.MethodDefinition = sourceMethodBody.MethodDefinition; this.nameTable = sourceMethodBody.nameTable; Contract.Assume(this.nameTable != null); this.sourceLocationProvider = sourceMethodBody.sourceLocationProvider; this.localScopeProvider = sourceMethodBody.localScopeProvider; this.options = sourceMethodBody.options; this.platformType = sourceMethodBody.platformType; Contract.Assume(this.platformType != null); this.numberOfAssignmentsToLocal = sourceMethodBody.numberOfAssignmentsToLocal; Contract.Assume(this.numberOfAssignmentsToLocal != null); this.numberOfReferencesToLocal = sourceMethodBody.numberOfReferencesToLocal; Contract.Assume(this.numberOfReferencesToLocal != null); this.gotosThatTarget = sourceMethodBody.gotosThatTarget; Contract.Assume(this.gotosThatTarget != null); this.cdfg = sourceMethodBody.cdfg; Contract.Assume(this.cdfg != null); this.bindingsThatMakeALastUseOfALocalVersion = sourceMethodBody.bindingsThatMakeALastUseOfALocalVersion; Contract.Assume(this.bindingsThatMakeALastUseOfALocalVersion != null); if (this.localScopeProvider != null) { var syncInfo = this.localScopeProvider.GetSynchronizationInformation(sourceMethodBody); if (syncInfo != null) { var syncPointFor = this.synchronizatonPointLocationFor = new Hashtable<SynchronizationPointLocation>(); IDocument doc = Dummy.Document; foreach (var loc in this.MethodDefinition.Locations) { doc = loc.Document; break; } foreach (var syncPoint in syncInfo.SynchronizationPoints) { Contract.Assume(syncPoint != null); var syncLoc = new SynchronizationPointLocation(doc, syncPoint); syncPointFor[syncPoint.SynchronizeOffset] = syncLoc; if (syncPoint.ContinuationMethod == null) syncPointFor[syncPoint.ContinuationOffset] = syncLoc; } } } }
/// <summary> /// /// </summary> internal static void FillInTypes(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg) { Contract.Requires(host != null); Contract.Requires(cfg != null); var stack = new Stack <Instruction>(cfg.MethodBody.MaxStack, new List <Instruction>(0)); var numberOfBlocks = cfg.BlockFor.Count; var blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); var blocksAlreadyVisited = new SetOfObjects(numberOfBlocks); var inferencer = new TypeInferencer <BasicBlock, Instruction>(host, cfg, stack, blocksToVisit, blocksAlreadyVisited); foreach (var root in cfg.RootBlocks) { blocksToVisit.Enqueue(root); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } //At this point, all reachable code blocks have had their types inferred. Now look for unreachable blocks. foreach (var block in cfg.AllBlocks) { if (blocksAlreadyVisited.Contains(block)) { continue; } blocksToVisit.Enqueue(block); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); this.sourceEmitterOutput.WriteLine(MemberHelper.GetMethodSignature(methodBody.MethodDefinition, NameFormattingOptions.Signature | NameFormattingOptions.ReturnType | NameFormattingOptions.ParameterModifiers | NameFormattingOptions.ParameterName)); sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) { PrintScopes(methodBody); } else { PrintLocals(methodBody.LocalVariables); } this.cdfg = ControlAndDataFlowGraph <AiBasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); this.cfgQueries = new ControlGraphQueries <AiBasicBlock <Instruction>, Instruction>(this.cdfg); SingleAssigner <AiBasicBlock <Instruction>, Instruction> .GetInSingleAssignmentForm(host.NameTable, this.cdfg, this.cfgQueries, this.pdbReader); this.valueMappings = new ValueMappings <Instruction>(this.host.PlatformType, new Z3Wrapper.Wrapper(host.PlatformType)); AbstractInterpreter <AiBasicBlock <Instruction>, Instruction> .InterpretUsingAbstractValues(this.cdfg, this.cfgQueries, this.valueMappings); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); this.sourceEmitterOutput.WriteLine(MemberHelper.GetMethodSignature(methodBody.MethodDefinition, NameFormattingOptions.Signature|NameFormattingOptions.ReturnType|NameFormattingOptions.ParameterModifiers|NameFormattingOptions.ParameterName)); sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) PrintScopes(methodBody); else PrintLocals(methodBody.LocalVariables); this.cdfg = ControlAndDataFlowGraph<AiBasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); this.cfgQueries = new ControlGraphQueries<AiBasicBlock<Instruction>, Instruction>(this.cdfg); SingleAssigner<AiBasicBlock<Instruction>, Instruction>.GetInSingleAssignmentForm(host.NameTable, this.cdfg, this.cfgQueries, this.pdbReader); this.valueMappings = new ValueMappings<Instruction>(this.host.PlatformType, new Z3Wrapper.Wrapper(host.PlatformType)); AbstractInterpreter<AiBasicBlock<Instruction>, Instruction>.InterpretUsingAbstractValues(this.cdfg, this.cfgQueries, this.valueMappings); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
public void RunOnControlFlowGraph(ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> cfg, BasicBlock <Instruction> entryBlock) { stateAbstraction = StateInterpreter.StateAbstraction; ControlFlowGraph = cfg; // factor this out into a static method // CFG only gives us successors, but we want predecessors too. So we stash those in a dictionary foreach (BasicBlock <Instruction> block in cfg.AllBlocks) { foreach (BasicBlock <Instruction> successor in cfg.SuccessorsFor(block)) { ISet <BasicBlock <Instruction> > predecessorsOfSuccessor; if (!predecessorsByBlock.TryGetValue(successor, out predecessorsOfSuccessor)) { predecessorsOfSuccessor = new HashSet <BasicBlock <Instruction> >(); predecessorsByBlock[successor] = predecessorsOfSuccessor; } predecessorsOfSuccessor.Add(block); } } this.entryBlock = entryBlock; // This needn't actually be true. //Contract.Assert(PredecessorsOfBlock(entryBlock).Count() == 0); // We still might want to assert something like: "the entry block dominates all blocks reachable from it"? Run(); }
/// <summary> /// Allocates a metadata (IL) representation along with a source level representation of the body of a method or of a property/event accessor. /// </summary> /// <param name="ilMethodBody">A method body whose IL operations should be decompiled into a block of statements that will be the /// result of the Block property of the resulting source method body.</param> /// <param name="host">An object representing the application that is hosting the converter. It is used to obtain access to some global /// objects and services such as the shared name table and the table for interning references.</param> /// <param name="sourceLocationProvider">An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.</param> /// <param name="localScopeProvider">An object that can provide information about the local scopes of a method.</param> /// <param name="options">Set of options that control decompilation.</param> public SourceMethodBody(IMethodBody ilMethodBody, IMetadataHost host, ISourceLocationProvider /*?*/ sourceLocationProvider, ILocalScopeProvider /*?*/ localScopeProvider, DecompilerOptions options = DecompilerOptions.None) : base(host, sourceLocationProvider, localScopeProvider) { Contract.Requires(ilMethodBody != null); Contract.Requires(host != null); this.ilMethodBody = ilMethodBody; this.host = host; this.nameTable = host.NameTable; this.sourceLocationProvider = sourceLocationProvider; this.pdbReader = sourceLocationProvider as PdbReader; this.localScopeProvider = localScopeProvider; this.options = options; this.platformType = ilMethodBody.MethodDefinition.ContainingTypeDefinition.PlatformType; if (IteratorHelper.EnumerableIsNotEmpty(ilMethodBody.LocalVariables)) { this.LocalsAreZeroed = ilMethodBody.LocalsAreZeroed; } else { this.LocalsAreZeroed = true; } this.MethodDefinition = ilMethodBody.MethodDefinition; this.privateHelperFieldsToRemove = null; this.privateHelperMethodsToRemove = null; this.privateHelperTypesToRemove = null; this.cdfg = ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(host, ilMethodBody, localScopeProvider); }
public override void Visit(IMethodBody methodBody) { Console.WriteLine(); Console.WriteLine("=========================="); Console.WriteLine("{0}", MemberHelper.GetMemberSignature(methodBody.MethodDefinition, NameFormattingOptions.DocumentationId)); var cdfg = ControlAndDataFlowGraph <EnhancedBasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(this.host, methodBody, this.pdbReader); var cfgQueries = new ControlGraphQueries <EnhancedBasicBlock <Instruction>, Instruction>(cdfg); var numberOfBlocks = cdfg.BlockFor.Count; Console.WriteLine("# blocks: {0}", numberOfBlocks); Console.WriteLine("CFG"); foreach (var block in cdfg.AllBlocks) { Console.WriteLine("{0:X}, Successors: {1}", block.Offset, Offsets(cdfg.SuccessorsFor(block))); } Dictionary <EnhancedBasicBlock <Instruction>, List <EnhancedBasicBlock <Instruction> > > dominators = new Dictionary <EnhancedBasicBlock <Instruction>, List <EnhancedBasicBlock <Instruction> > >(); foreach (var b in cdfg.AllBlocks) { var dom = new List <EnhancedBasicBlock <Instruction> >(); foreach (var c in cdfg.AllBlocks) { if (cfgQueries.Dominates(c, b)) { dom.Add(c); } } dominators.Add(b, dom); } var surroundingLoops = LoopFinder.GetLoopInformation(cdfg, cfgQueries, methodBody); Console.WriteLine("\nLoop information"); foreach (var b in cdfg.AllBlocks) { List <EnhancedBasicBlock <Instruction> > loops; if (surroundingLoops.TryGetValue(b, out loops)) { Console.WriteLine("{0:X}: ({1} loop{3}) {2}", b.Offset, loops.Count(), String.Join(",", loops.Select(l => String.Format("{0:X}", l.Offset))), loops.Count() > 1 ? "s" : "" ); } else { //Console.WriteLine("{0:X} is not contained in a loop", b.Offset); } } return; }
public override IMethodBody Rewrite(IMethodBody methodBody) { this.cdfg = ControlAndDataFlowGraph<BasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(this.host, methodBody); this.ilGenerator = new ILGenerator(host, methodBody.MethodDefinition); var numberOfBlocks = this.cdfg.BlockFor.Count; this.labelFor = new Hashtable<ILGeneratorLabel>(numberOfBlocks); this.counterFieldsForCurrentMethod = new NestedTypeDefinition() { BaseClasses = new List<ITypeReference>(1) { this.host.PlatformType.SystemObject }, ContainingTypeDefinition = methodBody.MethodDefinition.ContainingTypeDefinition, Fields = new List<IFieldDefinition>((int)numberOfBlocks*2), Methods = new List<IMethodDefinition>(1), InternFactory = this.host.InternFactory, IsBeforeFieldInit = true, IsClass = true, IsSealed = true, IsAbstract = true, Name = this.host.NameTable.GetNameFor(methodBody.MethodDefinition.Name+"_Counters"+methodBody.MethodDefinition.InternedKey), Visibility = TypeMemberVisibility.Assembly, }; this.fieldOffsets = new List<uint>((int)numberOfBlocks*2); foreach (var exceptionInfo in methodBody.OperationExceptionInformation) { this.ilGenerator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType, this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset), this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset), exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null); } if (this.pdbReader == null) { foreach (var localDef in methodBody.LocalVariables) this.ilGenerator.AddVariableToCurrentScope(localDef); } else { foreach (var ns in this.pdbReader.GetNamespaceScopes(methodBody)) { foreach (var uns in ns.UsedNamespaces) this.ilGenerator.UseNamespace(uns.NamespaceName.Value); } this.scopeEnumerator = this.pdbReader.GetLocalScopes(methodBody).GetEnumerator(); this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext(); } foreach (var block in this.cdfg.AllBlocks) this.InstrumentBlock(block); while (this.scopeStack.Count > 0) { this.ilGenerator.EndScope(); this.scopeStack.Pop(); } this.ilGenerator.AdjustBranchSizesToBestFit(); this.InjectMethodToDumpCounters(); return new ILGeneratorMethodBody(this.ilGenerator, methodBody.LocalsAreZeroed, (ushort)(methodBody.MaxStack+2), methodBody.MethodDefinition, methodBody.LocalVariables, IteratorHelper.GetSingletonEnumerable((ITypeDefinition)this.counterFieldsForCurrentMethod)); }
/// <summary> /// /// </summary> /// <param name="cdfg"></param> /// <param name="ilGenerator"></param> /// <param name="localScopeProvider"></param> /// <param name="sourceLocationProvider"></param> public ControlFlowToMethodBodyConverter(ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ILGenerator ilGenerator, ILocalScopeProvider /*?*/ localScopeProvider, ISourceLocationProvider /*?*/ sourceLocationProvider) { Contract.Requires(cdfg != null); Contract.Requires(ilGenerator != null); this.cdfg = cdfg; this.ilGenerator = ilGenerator; this.localScopeProvider = localScopeProvider; this.sourceLocationProvider = sourceLocationProvider; }
/// <summary> /// /// </summary> /// <param name="host"></param> /// <param name="cdfg"></param> /// <param name="localScopeProvider"></param> /// <param name="sourceLocationProvider"></param> public StackEliminator(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ILocalScopeProvider /*?*/ localScopeProvider, ISourceLocationProvider /*?*/ sourceLocationProvider) { Contract.Requires(host != null); Contract.Requires(cdfg != null); this.host = host; this.localScopeProvider = localScopeProvider; this.sourceLocationProvider = sourceLocationProvider; this.cdfg = cdfg; }
internal ILConverter(ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ILGenerator ilGenerator, ILocalScopeProvider /*?*/ localScopeProvider, ISourceLocationProvider /*?*/ sourceLocationProvider) : base(cdfg, ilGenerator, localScopeProvider, sourceLocationProvider) { Contract.Requires(cdfg != null); Contract.Requires(ilGenerator != null); this.localFor = new Hashtable <object, GeneratorLocal>(); this.redundantLocals = new SetOfObjects(); this.storesThatShouldBecomePops = new SetOfObjects(); this.useCount = new Dictionary <ILocalDefinition, int>(); }
/// <summary> /// Changes a control flow graph from SSA form to a version where the SSA variables are unified into the smallest number of locals. /// This is somewhat like register allocation where the number of registers can grow as large as needed, but registers are typed. /// </summary> /// <param name="host"></param> /// <param name="cdfg"></param> /// <param name="cfgQueries"></param> public MultipleAssigner(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ControlGraphQueries <BasicBlock, Instruction> cfgQueries) { Contract.Requires(host != null); Contract.Requires(cdfg != null); Contract.Requires(cfgQueries != null); this.host = host; this.cdfg = cdfg; this.cfgQueries = cfgQueries; this.unifiedLocalFor = new Hashtable <object, GeneratorLocal>(); this.availableLocalsFor = new MultiHashtable <GeneratorLocal>(); }
public void RunOnMethod(IMethodDefinition methodDefinition, IMetadataHost host) { ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> cfg = ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(host, methodDefinition.Body); // Note: we assume the first root block is the entrypoint of the function (and not, say, an exception handler // This may not be warranted; should perhaps check IL offset? BasicBlock <Instruction> entryBlock = cfg.RootBlocks.First(); RunOnControlFlowGraph(cfg, entryBlock); }
/// <summary> /// /// </summary> /// <param name="host"></param> /// <param name="cdfg"></param> /// <param name="cfgQueries"></param> /// <param name="localScopeProvider"></param> /// <param name="sourceLocationProvider"></param> public LocalMinimizer(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ControlGraphQueries <BasicBlock, Instruction> cfgQueries, ILocalScopeProvider /*?*/ localScopeProvider, ISourceLocationProvider /*?*/ sourceLocationProvider) { Contract.Requires(host != null); Contract.Requires(cdfg != null); Contract.Requires(cfgQueries != null); this.host = host; this.localScopeProvider = localScopeProvider; this.sourceLocationProvider = sourceLocationProvider; this.cdfg = cdfg; this.cfgQueries = cfgQueries; }
private DataFlowInferencer(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg) { Contract.Requires(host != null); Contract.Requires(cdfg != null); var numberOfBlocks = cdfg.BlockFor.Count; this.platformType = host.PlatformType; this.cdfg = cdfg; this.operandStackSetupInstructions = new List <Instruction>(cdfg.MethodBody.MaxStack); this.stack = new Stack <Instruction>(cdfg.MethodBody.MaxStack, this.operandStackSetupInstructions); this.blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); this.blocksAlreadyVisited = new SetOfObjects(numberOfBlocks);; this.internFactory = host.InternFactory; }
private TypeInferencer(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg, Stack <Instruction> stack, Queue <BasicBlock> blocksToVisit, SetOfObjects blocksAlreadyVisited) { Contract.Requires(host != null); Contract.Requires(cfg != null); Contract.Requires(stack != null); Contract.Requires(blocksToVisit != null); Contract.Requires(blocksAlreadyVisited != null); this.platformType = host.PlatformType; this.cfg = cfg; this.stack = stack; this.blocksToVisit = blocksToVisit; this.blocksAlreadyVisited = blocksAlreadyVisited; this.internFactory = host.InternFactory; }
public override void Visit(IMethodBody methodBody) { var method = methodBody.MethodDefinition; this.currentMethod = method; if (methodBody.Operations != null) { var cdfg = ControlAndDataFlowGraph <EnhancedBasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(this.host, methodBody, this.pdbReader); var cfgQueries = new ControlGraphQueries <EnhancedBasicBlock <Instruction>, Instruction>(cdfg); this.FindObjectSourcesWithoutSinks(method, cdfg); } return; }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) PrintScopes(methodBody); else PrintLocals(methodBody.LocalVariables); this.cdfg = ControlAndDataFlowGraph<BasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
/// <summary> /// /// </summary> internal static void FillInTypes(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg) { Contract.Requires(host != null); Contract.Requires(cfg != null); var stack = new Stack <Instruction>(cfg.MethodBody.MaxStack, new List <Instruction>(0)); var numberOfBlocks = cfg.BlockFor.Count; var blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); var blocksAlreadyVisited = new SetOfObjects(numberOfBlocks); var inferencer = new TypeInferencer <BasicBlock, Instruction>(host, cfg, stack, blocksToVisit, blocksAlreadyVisited); foreach (var root in cfg.RootBlocks) { blocksToVisit.Enqueue(root); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) { PrintScopes(methodBody); } else { PrintLocals(methodBody.LocalVariables); } this.cdfg = ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
private void AdjustStackForRet(ControlAndDataFlowGraph<EnhancedBasicBlock<Instruction>, Instruction> cdfg) { Contract.Requires(cdfg != null); //If ret is unreachable, the stack may already be empty. if (cdfg.MethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void && this.operandStack.Count > 0) this.operandStack.Pop(); }
private void EmitLocalDefinitions(ControlAndDataFlowGraph<EnhancedBasicBlock<Instruction>, Instruction> cdfg) { Contract.Requires(cdfg != null); bool thereWereLocalsVariables = false; foreach (var methodLocal in cdfg.MethodBody.LocalVariables) { Contract.Assume(methodLocal != null); this.EmitTypeReference(methodLocal.Type, storageLocation: true); if (methodLocal.IsReference) this.sourceEmitter.EmitString("*"); this.sourceEmitter.EmitString(" "); this.EmitLocalReference(methodLocal); this.sourceEmitter.EmitString(";"); this.sourceEmitter.EmitNewLine(); thereWereLocalsVariables = true; } if (thereWereLocalsVariables) this.sourceEmitter.EmitNewLine(); if (this.mayThrowException) { this.sourceEmitter.EmitString("uintptr_t exception;"); this.sourceEmitter.EmitNewLine(); this.sourceEmitter.EmitString("uintptr_t originalException;"); this.sourceEmitter.EmitNewLine(); this.sourceEmitter.EmitString("uint32_t throwOffset;"); this.sourceEmitter.EmitNewLine(); this.mayThrowException = false; } if (this.generateOverflowCheckTemp) { this.sourceEmitter.EmitString("int32_t overflowFlag;"); this.sourceEmitter.EmitNewLine(); this.generateOverflowCheckTemp = false; } if (this.needsTempForArrayElementAddress) { this.sourceEmitter.EmitString("uintptr_t element_address;"); this.sourceEmitter.EmitNewLine(); this.generateOverflowCheckTemp = false; } if (this.hasCallVirt) { this.sourceEmitter.EmitString("void ** virtualPtr;"); this.sourceEmitter.EmitNewLine(); this.hasCallVirt = false; } foreach (var temp in this.temps) this.EmitTemp(temp); this.sourceEmitter.EmitNewLine(); }
public override IMethodBody Rewrite(IMethodBody methodBody) { this.cdfg = ControlAndDataFlowGraph <BasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(this.host, methodBody); this.ilGenerator = new ILGenerator(host, methodBody.MethodDefinition); var numberOfBlocks = this.cdfg.BlockFor.Count; this.labelFor = new Hashtable <ILGeneratorLabel>(numberOfBlocks); this.counterFieldsForCurrentMethod = new NestedTypeDefinition() { BaseClasses = new List <ITypeReference>(1) { this.host.PlatformType.SystemObject }, ContainingTypeDefinition = methodBody.MethodDefinition.ContainingTypeDefinition, Fields = new List <IFieldDefinition>((int)numberOfBlocks * 2), Methods = new List <IMethodDefinition>(1), InternFactory = this.host.InternFactory, IsBeforeFieldInit = true, IsClass = true, IsSealed = true, IsAbstract = true, Name = this.host.NameTable.GetNameFor(methodBody.MethodDefinition.Name + "_Counters" + methodBody.MethodDefinition.InternedKey), Visibility = TypeMemberVisibility.Assembly, }; this.fieldOffsets = new List <uint>((int)numberOfBlocks * 2); foreach (var exceptionInfo in methodBody.OperationExceptionInformation) { this.ilGenerator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType, this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset), this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset), exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null); } if (this.pdbReader == null) { foreach (var localDef in methodBody.LocalVariables) { this.ilGenerator.AddVariableToCurrentScope(localDef); } } else { foreach (var ns in this.pdbReader.GetNamespaceScopes(methodBody)) { foreach (var uns in ns.UsedNamespaces) { this.ilGenerator.UseNamespace(uns.NamespaceName.Value); } } this.scopeEnumerator = this.pdbReader.GetLocalScopes(methodBody).GetEnumerator(); this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext(); } foreach (var block in this.cdfg.AllBlocks) { this.InstrumentBlock(block); } while (this.scopeStack.Count > 0) { this.ilGenerator.EndScope(); this.scopeStack.Pop(); } this.ilGenerator.AdjustBranchSizesToBestFit(); this.InjectMethodToDumpCounters(); return(new ILGeneratorMethodBody(this.ilGenerator, methodBody.LocalsAreZeroed, (ushort)(methodBody.MaxStack + 2), methodBody.MethodDefinition, methodBody.LocalVariables, IteratorHelper.GetSingletonEnumerable((ITypeDefinition)this.counterFieldsForCurrentMethod))); }
/// <summary> /// /// </summary> internal static void SetupDataFlow(IMetadataHost host, IMethodBody methodBody, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg) { Contract.Requires(host != null); Contract.Requires(methodBody != null); Contract.Requires(cdfg != null); var dataFlowInferencer = new DataFlowInferencer <BasicBlock, Instruction>(host, cdfg); dataFlowInferencer.SetupDataFlowFor(methodBody); }
public bool AnalyzeMethods() { foreach (INamedTypeDefinition t in PrimaryModule.GetAllTypes()) { if (t.IsClass && t.Methods.Count() > 0 && !t.Name.Value.StartsWith("<")) { Environment.Message("Class {0} has {1} members, {2} methods.", t.Name.Value, t.Members.Count(), t.Methods.Count()); List <IMethodDefinition> methods = t.Methods.ToList(); foreach (IMethodDefinition m in methods) { ControlAndDataFlowGraph <EnhancedBasicBlock <Instruction>, Instruction> cdfg = ControlAndDataFlowGraph <EnhancedBasicBlock <Instruction>, Instruction> .GetControlAndDataFlowGraphFor(MetadataReaderHost, m.Body); ControlGraphQueries <EnhancedBasicBlock <Instruction>, Instruction> query = new ControlGraphQueries <EnhancedBasicBlock <Instruction>, Instruction>(cdfg); Environment.Message(" Method {0} has visibility {3}, {1} parameters, {2} local variables in body, {4} total basic blocks or nodes and {5} successor edges in CFG.\n", m.Name.Value, m.ParameterCount, m.Body.LocalVariables.Count(), m.Visibility.ToString(), cdfg.AllBlocks.Count, cdfg.SuccessorEdges.Count); } } } return(true); }
private void CreateTempsForOperandStack(ControlAndDataFlowGraph<EnhancedBasicBlock<Instruction>, Instruction> cdfg) { Contract.Requires(cdfg != null); foreach (var block in cdfg.AllBlocks) { Contract.Assume(block != null); this.InitializeOperandStack(block); foreach (var instruction in block.Instructions) { Contract.Assume(instruction != null); switch (instruction.Operation.OperationCode) { case OperationCode.Add: case OperationCode.And: case OperationCode.Ceq: case OperationCode.Cgt: case OperationCode.Cgt_Un: case OperationCode.Clt: case OperationCode.Clt_Un: case OperationCode.Mul: case OperationCode.Or: case OperationCode.Shl: case OperationCode.Shr: case OperationCode.Shr_Un: case OperationCode.Sub: case OperationCode.Xor: this.AdjustStackForBinaryOperation(instruction); break; case OperationCode.Add_Ovf: case OperationCode.Add_Ovf_Un: case OperationCode.Mul_Ovf: case OperationCode.Mul_Ovf_Un: case OperationCode.Sub_Ovf: case OperationCode.Sub_Ovf_Un: this.AdjustStackForBinaryOperation(instruction); this.generateOverflowCheckTemp = true; this.mayThrowException = true; break; case OperationCode.Arglist: case OperationCode.Ldarg: case OperationCode.Ldarg_0: case OperationCode.Ldarg_1: case OperationCode.Ldarg_2: case OperationCode.Ldarg_3: case OperationCode.Ldarg_S: case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: case OperationCode.Ldsfld: case OperationCode.Ldarga: case OperationCode.Ldarga_S: case OperationCode.Ldsflda: case OperationCode.Ldloca: case OperationCode.Ldloca_S: case OperationCode.Ldftn: case OperationCode.Ldc_I4: case OperationCode.Ldc_I4_0: case OperationCode.Ldc_I4_1: case OperationCode.Ldc_I4_2: case OperationCode.Ldc_I4_3: case OperationCode.Ldc_I4_4: case OperationCode.Ldc_I4_5: case OperationCode.Ldc_I4_6: case OperationCode.Ldc_I4_7: case OperationCode.Ldc_I4_8: case OperationCode.Ldc_I4_M1: case OperationCode.Ldc_I4_S: case OperationCode.Ldc_I8: case OperationCode.Ldc_R4: case OperationCode.Ldc_R8: case OperationCode.Ldnull: case OperationCode.Ldstr: case OperationCode.Ldtoken: case OperationCode.Sizeof: this.PushTempForSlotAndAssociateWithInstruction(instruction); break; case OperationCode.Array_Addr: case OperationCode.Array_Get: this.AdjustStackForArrayAddr(instruction); break; case OperationCode.Array_Create: case OperationCode.Array_Create_WithLowerBound: case OperationCode.Newarr: this.AdjustStackForArrayCreate(instruction); this.mayThrowException = true; break; case OperationCode.Array_Set: this.AdjustStackForArraySet(instruction); break; case OperationCode.Beq: case OperationCode.Beq_S: case OperationCode.Bge: case OperationCode.Bge_S: case OperationCode.Bge_Un: case OperationCode.Bge_Un_S: case OperationCode.Bgt: case OperationCode.Bgt_S: case OperationCode.Bgt_Un: case OperationCode.Bgt_Un_S: case OperationCode.Ble: case OperationCode.Ble_S: case OperationCode.Ble_Un: case OperationCode.Ble_Un_S: case OperationCode.Blt: case OperationCode.Blt_S: case OperationCode.Blt_Un: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un: case OperationCode.Bne_Un_S: this.AdjustStackForBinaryVoidOperation(); break; case OperationCode.Cpobj: case OperationCode.Stind_I: case OperationCode.Stind_I1: case OperationCode.Stind_I2: case OperationCode.Stind_I4: case OperationCode.Stind_I8: case OperationCode.Stind_R4: case OperationCode.Stind_R8: case OperationCode.Stind_Ref: case OperationCode.Stobj: this.AdjustStackForBinaryVoidOperation(); this.mayThrowException = true; break; case OperationCode.Box: case OperationCode.Castclass: case OperationCode.Ckfinite: case OperationCode.Ldind_I: case OperationCode.Ldind_I1: case OperationCode.Ldind_I2: case OperationCode.Ldind_I4: case OperationCode.Ldind_I8: case OperationCode.Ldind_R4: case OperationCode.Ldind_R8: case OperationCode.Ldind_Ref: case OperationCode.Ldind_U1: case OperationCode.Ldind_U2: case OperationCode.Ldind_U4: case OperationCode.Ldobj: case OperationCode.Ldflda: case OperationCode.Ldfld: case OperationCode.Ldlen: case OperationCode.Localloc: case OperationCode.Refanytype: case OperationCode.Refanyval: case OperationCode.Unbox: case OperationCode.Unbox_Any: this.AdjustStackForUnaryOperation(instruction); this.mayThrowException = true; break; case OperationCode.Conv_Ovf_I: case OperationCode.Conv_Ovf_I_Un: case OperationCode.Conv_Ovf_I1: case OperationCode.Conv_Ovf_I1_Un: case OperationCode.Conv_Ovf_I2: case OperationCode.Conv_Ovf_I2_Un: case OperationCode.Conv_Ovf_I4: case OperationCode.Conv_Ovf_I4_Un: case OperationCode.Conv_Ovf_I8: case OperationCode.Conv_Ovf_I8_Un: case OperationCode.Conv_Ovf_U: case OperationCode.Conv_Ovf_U_Un: case OperationCode.Conv_Ovf_U1: case OperationCode.Conv_Ovf_U1_Un: case OperationCode.Conv_Ovf_U2: case OperationCode.Conv_Ovf_U2_Un: case OperationCode.Conv_Ovf_U4: case OperationCode.Conv_Ovf_U4_Un: case OperationCode.Conv_Ovf_U8: case OperationCode.Conv_Ovf_U8_Un: this.AdjustStackForUnaryOperation(instruction); this.generateOverflowCheckTemp = true; this.mayThrowException = true; break; case OperationCode.Brfalse: case OperationCode.Brfalse_S: case OperationCode.Brtrue: case OperationCode.Brtrue_S: case OperationCode.Endfilter: case OperationCode.Initobj: case OperationCode.Pop: case OperationCode.Starg: case OperationCode.Starg_S: case OperationCode.Stloc: case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: case OperationCode.Stloc_S: case OperationCode.Stsfld: case OperationCode.Switch: this.AdjustStackForUnaryVoidOperation(); break; case OperationCode.Call: this.AdjustStackForCall(instruction); this.mayThrowException = true; break; case OperationCode.Callvirt: this.AdjustStackForCall(instruction); this.mayThrowException = true; this.hasCallVirt = true; break; case OperationCode.Calli: this.AdjustStackForCalli(instruction); this.mayThrowException = true; break; case OperationCode.Conv_I: case OperationCode.Conv_I1: case OperationCode.Conv_I2: case OperationCode.Conv_I4: case OperationCode.Conv_I8: case OperationCode.Conv_R_Un: case OperationCode.Conv_R4: case OperationCode.Conv_R8: case OperationCode.Conv_U: case OperationCode.Conv_U1: case OperationCode.Conv_U2: case OperationCode.Conv_U4: case OperationCode.Conv_U8: case OperationCode.Isinst: case OperationCode.Mkrefany: case OperationCode.Neg: case OperationCode.Not: this.AdjustStackForUnaryOperation(instruction); break; case OperationCode.Cpblk: case OperationCode.Initblk: this.AdjustStackForTernaryVoidOperation(); this.mayThrowException = true; break; case OperationCode.Dup: this.AdjustStackForDup(instruction); break; case OperationCode.Div: case OperationCode.Div_Un: case OperationCode.Rem: case OperationCode.Rem_Un: case OperationCode.Ldelema: this.AdjustStackForBinaryOperation(instruction); this.mayThrowException = true; break; case OperationCode.Ldelem: case OperationCode.Ldelem_I: case OperationCode.Ldelem_I1: case OperationCode.Ldelem_I2: case OperationCode.Ldelem_I4: case OperationCode.Ldelem_I8: case OperationCode.Ldelem_R4: case OperationCode.Ldelem_R8: case OperationCode.Ldelem_Ref: case OperationCode.Ldelem_U1: case OperationCode.Ldelem_U2: case OperationCode.Ldelem_U4: this.AdjustStackForBinaryOperation(instruction); this.mayThrowException = true; this.needsTempForArrayElementAddress = true; break; case OperationCode.Ldvirtftn: this.AdjustStackForUnaryOperation(instruction); this.mayThrowException = true; this.hasCallVirt = true; break; case OperationCode.Leave: case OperationCode.Leave_S: this.AdjustStackForLeave(); break; case OperationCode.Newobj: this.AdjustStackForNewObject(instruction); this.mayThrowException = true; break; case OperationCode.Ret: this.AdjustStackForRet(cdfg); break; case OperationCode.Stelem: case OperationCode.Stelem_I: case OperationCode.Stelem_I1: case OperationCode.Stelem_I2: case OperationCode.Stelem_I4: case OperationCode.Stelem_I8: case OperationCode.Stelem_R4: case OperationCode.Stelem_R8: case OperationCode.Stelem_Ref: this.AdjustStackForTernaryVoidOperation(); this.mayThrowException = true; this.needsTempForArrayElementAddress = true; break; case OperationCode.Stfld: this.AdjustStackForBinaryVoidOperation(); this.mayThrowException = true; break; case OperationCode.Throw: this.AdjustStackForUnaryVoidOperation(); this.mayThrowException = true; break; } } } }