/// <summary> /// Create a SequencePointList with the raw sequence points from an ArrayBuilder. /// A linked list of instances for each syntax tree is created (almost always of length one). /// </summary> public static SequencePointList Create(ArrayBuilder<RawSequencePoint> seqPointBuilder, ILBuilder builder) { if (seqPointBuilder.Count == 0) { return SequencePointList.s_empty; } SequencePointList first = null, current = null; int totalPoints = seqPointBuilder.Count; int last = 0; for (int i = 1; i <= totalPoints; ++i) { if (i == totalPoints || seqPointBuilder[i].SyntaxTree != seqPointBuilder[i - 1].SyntaxTree) { // Create a new list SequencePointList next = new SequencePointList(seqPointBuilder[i - 1].SyntaxTree, GetSubArray(seqPointBuilder, last, i - last, builder)); last = i; // Link together with any additional. if (current == null) { first = current = next; } else { current._next = next; current = next; } } } return first; }
public CodeGenerator( MethodSymbol method, BoundStatement boundBody, ILBuilder builder, PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool emittingPdb) { Debug.Assert((object)method != null); Debug.Assert(boundBody != null); Debug.Assert(builder != null); Debug.Assert(moduleBuilder != null); Debug.Assert(diagnostics != null); _method = method; _boundBody = boundBody; _builder = builder; _module = moduleBuilder; _diagnostics = diagnostics; if (!method.GenerateDebugInfo) { // Always optimize synthesized methods that don't contain user code. // // Specifically, always optimize synthesized explicit interface implementation methods // (aka bridge methods) with by-ref returns because peverify produces errors if we // return a ref local (which the return local will be in such cases). _ilEmitStyle = ILEmitStyle.Release; } else { if (optimizations == OptimizationLevel.Debug) { _ilEmitStyle = ILEmitStyle.Debug; } else { _ilEmitStyle = IsDebugPlus() ? ILEmitStyle.DebugFriendlyRelease : ILEmitStyle.Release; } } // Emit sequence points unless // - the PDBs are not being generated // - debug information for the method is not generated since the method does not contain // user code that can be stepped through, or changed during EnC. // // This setting only affects generating PDB sequence points, it shall not affect generated IL in any way. _emitPdbSequencePoints = emittingPdb && method.GenerateDebugInfo; _boundBody = Optimizer.Optimize( boundBody, debugFriendly: _ilEmitStyle != ILEmitStyle.Release, stackLocals: out _stackLocals); _methodBodySyntaxOpt = (method as SourceMethodSymbol)?.BodySyntax; }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { if (_place == null) { // unoptimized locals return new BoundIndirectVariablePlace(new BoundLiteral(this.Name), access); } else { return new BoundLocalPlace(_place, access, thint); } }
private CodeGenerator(MethodSymbol method, BoundStatement block, ILBuilder builder, PEModuleBuilder module, DiagnosticBag diagnostics, bool optimize, bool emitSequencePoints) { this.method = method; this.block = block; this.builder = builder; this.module = module; this.diagnostics = diagnostics; this.noOptimizations = !optimize; this.debugInformationKind = module.Compilation.Options.DebugInformationKind; if (!this.debugInformationKind.IsValid()) { this.debugInformationKind = DebugInformationKind.None; } // Special case: always optimize synthesized explicit interface implementation methods // (aka bridge methods) with by-ref returns because peverify produces errors if we // return a ref local (which the return local will be in such cases). if (this.noOptimizations && method.ReturnType is ByRefReturnErrorTypeSymbol) { Debug.Assert(method is SynthesizedExplicitImplementationMethod); this.noOptimizations = false; } this.emitSequencePoints = emitSequencePoints; if (!this.noOptimizations) { this.block = Optimizer.Optimize(block, out stackLocals); } Debug.Assert((object)method != null); Debug.Assert(block != null); Debug.Assert(builder != null); Debug.Assert(module != null); var asSourceMethod = method as SourceMethodSymbol; if ((object)asSourceMethod != null) { methodBlockSyntax = asSourceMethod.BlockSyntax; } }
private CodeGenerator( MethodSymbol method, BoundStatement block, ILBuilder builder, PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool emittingPdbs) { this.method = method; this.block = block; this.builder = builder; this.module = moduleBuilder; this.diagnostics = diagnostics; // Always optimize synthesized methods that don't contain user code. // // Specifically, always optimize synthesized explicit interface implementation methods // (aka bridge methods) with by-ref returns because peverify produces errors if we // return a ref local (which the return local will be in such cases). this.optimizations = method.GenerateDebugInfo ? optimizations : OptimizationLevel.Release; // Emit sequence points unless // - the PDBs are not being generated // - debug information for the method is not generated since the method does not contain // user code that can be stepped thru, or changed during EnC. // // This setting only affects generating PDB sequence points, it shall not affect generated IL in any way. this.emitPdbSequencePoints = emittingPdbs && method.GenerateDebugInfo; if (this.optimizations == OptimizationLevel.Release) { this.block = Optimizer.Optimize(block, out stackLocals); } Debug.Assert((object)method != null); Debug.Assert(block != null); Debug.Assert(builder != null); Debug.Assert(moduleBuilder != null); var asSourceMethod = method as SourceMethodSymbol; if ((object)asSourceMethod != null) { methodBlockSyntax = asSourceMethod.BlockSyntax; } }
internal SwitchIntegralJumpTableEmitter( ILBuilder builder, KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, Cci.PrimitiveTypeCode keyTypeCode, LocalOrParameter key) { this.builder = builder; this.key = key; this.keyTypeCode = keyTypeCode; this.fallThroughLabel = fallThroughLabel; // Sort the switch case labels, see comments below for more details. Debug.Assert(caseLabels.Length > 0); Array.Sort(caseLabels, CompareIntegralSwitchLabels); sortedCaseLabels = ImmutableArray.Create(caseLabels); }
internal SwitchStringJumpTableEmitter( ILBuilder builder, LocalOrParameter key, KeyValuePair<ConstantValue, object>[] caseLabels, object fallThroughLabel, LocalDefinition keyHash, EmitStringCompareAndBranch emitStringCondBranchDelegate, GetStringHashCode computeStringHashcodeDelegate) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(emitStringCondBranchDelegate != null); _builder = builder; _key = key; _caseLabels = caseLabels; _fallThroughLabel = fallThroughLabel; _keyHash = keyHash; _emitStringCondBranchDelegate = emitStringCondBranchDelegate; _computeStringHashcodeDelegate = computeStringHashcodeDelegate; }
public ExceptionHandlerLeaderBlock(ILBuilder builder, ExceptionHandlerScope enclosingHandler, BlockType type) : base(builder, enclosingHandler) { _type = type; }
internal abstract IPlace Place(ILBuilder il);
internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics, bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray<NamespaceScope> namespaceScopes) { // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings. Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened"); bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync; var module = compilationState.ModuleBuilder; var compilation = module.Compilation; var localSlotManager = module.CreateLocalSlotManager(method); ILBuilder builder = new ILBuilder(module, localSlotManager, optimize); DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); try { AsyncMethodBodyDebugInfo asyncDebugInfo = null; if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method? { CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints); } else { int asyncCatchHandlerOffset; ImmutableArray<int> asyncYieldPoints; ImmutableArray<int> asyncResumePoints; CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints, out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints); } var localVariables = builder.LocalSlotManager.LocalsInOrder(); if (localVariables.Length > 0xFFFE) { diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First()); } if (diagnosticsForThisMethod.HasAnyErrors()) { // we are done here. Since there were errors we should not emit anything. return null; } // We will only save the IL builders when running tests. if (module.SaveTestData) { module.SetMethodTestData(method, builder.GetSnapshot()); } // Only compiler-generated MoveNext methods have iterator scopes. See if this is one. bool hasIteratorScopes = method.Locations.IsEmpty && method.Name == "MoveNext" && (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) || method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol)); var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray<LocalScope>.Empty; var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method); return new MethodBody( builder.RealizedIL, builder.MaxStack, method, localVariables, builder.RealizedSequencePoints, debugDocumentProvider, builder.RealizedExceptionHandlers, builder.GetAllScopes(), Microsoft.Cci.CustomDebugInfoKind.CSharpStyle, builder.HasDynamicLocal, namespaceScopes, (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName, iteratorScopes, asyncMethodDebugInfo: asyncDebugInfo ); } finally { // Basic blocks contain poolable builders for IL and sequence points. Free those back // to their pools. builder.FreeBasicBlocks(); // Remember diagnostics. diagnostics.AddRange(diagnosticsForThisMethod); diagnosticsForThisMethod.Free(); } }
internal void Initialize(ILBuilder builder) { this.builder = builder; this.FirstILMarker = -1; this.LastILMarker = -1; }
public void EmitStore(ILBuilder il) => il.EmitLocalStore(_def);
private static void DumpBasicBlockIL(ILBuilder.BasicBlock block, StringBuilder sb) { var instrCnt = (int)block.RegularInstructionsLength; if (instrCnt != 0) { byte[] il = block.RegularInstructions.Buffer; new ILBuilderVisualizer(block.builder.module).DumpILBlock(il, instrCnt, sb, SpecializedCollections.EmptyArray<ILVisualizer.HandlerSpan>(), block.Start); } if (block.BranchCode != ILOpCode.Nop) { sb.Append(string.Format(" IL_{0:x4}:", block.RegularInstructionsLength + block.Start)); sb.Append(string.Format(" {0,-10}", GetInstructionName(block.BranchCode))); if (block.BranchCode.IsBranchToLabel()) { var branchBlock = block.BranchBlock; if (branchBlock == null) { // this happens if label is not yet marked. sb.Append(" <unmarked label>"); } else { sb.Append(string.Format(" IL_{0:x4}", branchBlock.Start)); } } sb.AppendLine(); } }
public MethodData(ILBuilder ilBuilder, IMethodSymbol method) { this.ILBuilder = ilBuilder; this.Method = method; }
public ExceptionHandlerLeaderBlock(ILBuilder builder, ExceptionHandlerScope enclosingHandler, BlockType type) : base(builder, enclosingHandler) { this.type = type; }
public SwitchBlock(ILBuilder builder, ExceptionHandlerScope enclosingHandler) : base(builder, enclosingHandler) { this.SetBranchCode(ILOpCode.Switch); }
public BasicBlockWithHandlerScope(ILBuilder builder, ExceptionHandlerScope enclosingHandler) : base(builder) { this.enclosingHandler = enclosingHandler; }
internal BasicBlock(ILBuilder builder) { Debug.Assert(BitConverter.IsLittleEndian); Initialize(builder); }
private static OffsetAndSpan[] GetSubArray(ArrayBuilder <RawSequencePoint> seqPointBuilder, int start, int length, ILBuilder builder) { OffsetAndSpan[] result = new OffsetAndSpan[length]; for (int i = 0; i < result.Length; i++) { RawSequencePoint point = seqPointBuilder[i + start]; int ilOffset = builder.GetILOffsetFromMarker(point.ILMarker); Debug.Assert(ilOffset >= 0); result[i] = new OffsetAndSpan(ilOffset, point.Span); } return(result); }
internal static string LocalSignatureToString( ILBuilder builder, Func<Cci.ILocalDefinition, LocalInfo> mapLocal = null) { var sb = new StringBuilder(); if (mapLocal == null) { mapLocal = local => new LocalInfo(local.Name, local.Type, local.IsPinned, local.IsReference); } var locals = builder.LocalSlotManager.LocalsInOrder().SelectAsArray(mapLocal); var visualizer = new ILBuilderVisualizer(builder.module); visualizer.VisualizeHeader(sb, -1, -1, locals); return sb.ToString(); }
public static void Run(MethodSymbol method, BoundStatement block, ILBuilder builder, PEModuleBuilder module, DiagnosticBag diagnostics, bool optimize, bool emitSequencePoints, out int asyncCatchHandlerOffset, out ImmutableArray<int> asyncYieldPoints, out ImmutableArray<int> asyncResumePoints) { CodeGenerator generator = new CodeGenerator(method, block, builder, module, diagnostics, optimize, emitSequencePoints); generator.Generate(); if (!diagnostics.HasAnyErrors()) { builder.Realize(); } asyncCatchHandlerOffset = (generator.asyncCatchHandlerOffset < 0) ? -1 : generator.builder.GetILOffsetFromMarker(generator.asyncCatchHandlerOffset); ArrayBuilder<int> yieldPoints = generator.asyncYieldPoints; ArrayBuilder<int> resumePoints = generator.asyncResumePoints; if (yieldPoints == null) { asyncYieldPoints = ImmutableArray<int>.Empty; asyncResumePoints = ImmutableArray<int>.Empty; } else { var yieldPointBuilder = ArrayBuilder<int>.GetInstance(); var resumePointBuilder = ArrayBuilder<int>.GetInstance(); int n = yieldPoints.Count; for (int i = 0; i < n; i++) { int yieldOffset = generator.builder.GetILOffsetFromMarker(yieldPoints[i]); int resumeOffset = generator.builder.GetILOffsetFromMarker(resumePoints[i]); Debug.Assert(resumeOffset >= 0); // resume marker should always be reachable from dispatch // yield point may not be reachable if the whole // await is not reachable; we just ignore such awaits if (yieldOffset > 0) { yieldPointBuilder.Add(yieldOffset); resumePointBuilder.Add(resumeOffset); } } asyncYieldPoints = yieldPointBuilder.ToImmutableAndFree(); asyncResumePoints = resumePointBuilder.ToImmutableAndFree(); yieldPoints.Free(); resumePoints.Free(); } }
private static string BasicBlockToString(ILBuilder.BasicBlock block) { StringBuilder sb = new StringBuilder(); DumpBlockIL(block, sb); return sb.ToString(); }
internal SwitchBlock CreateSwitchBlock(ILBuilder builder) { var scope = (LocalScopeInfo)CurrentScope; return(scope.CreateSwitchBlock(builder)); }
public void EmitStorePrepare(ILBuilder il) { }
/// <remarks> /// Invoked via Reflection from <see cref="ILBuilder.GetDebuggerDisplay()"/> /// </remarks> internal static string ILBuilderToString( ILBuilder builder, Func<Cci.ILocalDefinition, LocalInfo> mapLocal = null, IReadOnlyDictionary<int, string> markers = null) { var sb = new StringBuilder(); var ilStream = builder.RealizedIL; if (mapLocal == null) { mapLocal = local => new LocalInfo(local.Name, local.Type, local.IsPinned, local.IsReference); } var locals = builder.LocalSlotManager.LocalsInOrder().SelectAsArray(mapLocal); var visualizer = new ILBuilderVisualizer(builder.module); if (ilStream != null) { visualizer.DumpMethod(sb, builder.MaxStack, ilStream, locals, GetHandlerSpans(builder.RealizedExceptionHandlers), markers); } else { sb.AppendLine("{"); visualizer.VisualizeHeader(sb, 0, builder.MaxStack, locals); // serialize blocks as-is var current = builder.leaderBlock; while (current != null) { DumpBlockIL(current, sb); current = current.NextBlock; } sb.AppendLine("}"); } return sb.ToString(); }
public virtual void CloseScope(ILBuilder builder) { }
private static void DumpBlockIL(ILBuilder.BasicBlock block, StringBuilder sb) { var switchBlock = block as ILBuilder.SwitchBlock; if (switchBlock != null) { DumpSwitchBlockIL(switchBlock, sb); } else { DumpBasicBlockIL(block, sb); } }
public virtual void FinishFilterCondition(ILBuilder builder) { throw ExceptionUtilities.Unreachable; }
private static void DumpSwitchBlockIL(ILBuilder.SwitchBlock block, StringBuilder sb) { byte[] il = block.RegularInstructions.Buffer; new ILBuilderVisualizer(block.builder.module).DumpILBlock(il, (int)block.RegularInstructionsLength, sb, SpecializedCollections.EmptyArray<ILVisualizer.HandlerSpan>(), block.Start); // switch (N, t1, t2... tN) // IL ==> ILOpCode.Switch < unsigned int32 > < int32 >... < int32 > sb.Append(string.Format(" IL_{0:x4}:", block.RegularInstructionsLength + block.Start)); sb.Append(string.Format(" {0,-10}", GetInstructionName(block.BranchCode))); sb.Append(string.Format(" IL_{0:x4}:", block.BranchesCount)); var blockBuilder = ArrayBuilder<ILBuilder.BasicBlock>.GetInstance(); block.GetBranchBlocks(blockBuilder); foreach (var branchBlock in blockBuilder) { if (branchBlock == null) { // this happens if label is not yet marked. sb.Append(" <unmarked label>"); } else { sb.Append(string.Format(" IL_{0:x4}", branchBlock.Start)); } } blockBuilder.Free(); sb.AppendLine(); }
internal void FinishFilterCondition(ILBuilder builder) { CurrentScope.FinishFilterCondition(builder); }
internal override IPlace Place(ILBuilder il) { var fldplace = BoundReference as BoundFieldPlace; if (fldplace != null) { Debug.Assert(fldplace.Field != null); var instanceplace = (fldplace.Instance as BoundReferenceExpression)?.Place(il); if (instanceplace != null || (fldplace.Instance == null && fldplace.Field.IsStatic)) return new FieldPlace(instanceplace, fldplace.Field); } return null; }
public override void CloseScope(ILBuilder builder) { Debug.Assert(LeaderBlock != null); }
internal void ClosingScope(ILBuilder builder) { CurrentScope.ClosingScope(builder); }
internal override IPlace Place(ILBuilder il) => this.Variable.Place(il);
public static SequencePointList Create(ArrayBuilder <RawSequencePoint> seqPointBuilder, ILBuilder builder) { if (seqPointBuilder.Count == 0) { return(SequencePointList.s_empty); } SequencePointList first = null, current = null; int totalPoints = seqPointBuilder.Count; int last = 0; for (int i = 1; i <= totalPoints; ++i) { if (i == totalPoints || seqPointBuilder[i].SyntaxTree != seqPointBuilder[i - 1].SyntaxTree) { // Create a new list SequencePointList next = new SequencePointList(seqPointBuilder[i - 1].SyntaxTree, GetSubArray(seqPointBuilder, last, i - last, builder)); last = i; // Link together with any additional. if (current == null) { first = current = next; } else { current._next = next; current = next; } } } return(first); }
internal override IPlace Place(ILBuilder il) => null;
public void EmitLoadTarget(ILBuilder il) { this.Place.EmitLoad(il); il.EmitOpCode(ILOpCode.Ldfld); il.EmitSymbolToken(_factory._cg.Module, _factory._cg.Diagnostics, _target, null); }
private static OffsetAndSpan[] GetSubArray(ArrayBuilder<RawSequencePoint> seqPointBuilder, int start, int length, ILBuilder builder) { OffsetAndSpan[] result = new OffsetAndSpan[length]; for (int i = 0; i < result.Length; i++) { RawSequencePoint point = seqPointBuilder[i + start]; int ilOffset = builder.GetILOffsetFromMarker(point.ILMarker); Debug.Assert(ilOffset >= 0); result[i] = new OffsetAndSpan(ilOffset, point.Span); } return result; }
public static void Run(MethodSymbol method, BoundStatement block, ILBuilder builder, PEModuleBuilder module, DiagnosticBag diagnostics, bool optimize, bool emitSequencePoints) { CodeGenerator generator = new CodeGenerator(method, block, builder, module, diagnostics, optimize, emitSequencePoints); generator.Generate(); Debug.Assert(generator.asyncCatchHandlerOffset < 0); Debug.Assert(generator.asyncYieldPoints == null); Debug.Assert(generator.asyncResumePoints == null); if (!diagnostics.HasAnyErrors()) { builder.Realize(); } }