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(); } }
/// <summary> /// Generates method body that calls another method. /// Used for wrapping a method call into a method, e.g. an entry point. /// </summary> internal static MethodBody GenerateMethodBody( PEModuleBuilder moduleBuilder, MethodSymbol routine, Action<ILBuilder> builder, VariableSlotAllocator variableSlotAllocatorOpt, DiagnosticBag diagnostics, bool emittingPdb) { var compilation = moduleBuilder.Compilation; var localSlotManager = new LocalSlotManager(variableSlotAllocatorOpt); var optimizations = compilation.Options.OptimizationLevel; DebugDocumentProvider debugDocumentProvider = null; if (emittingPdb) { debugDocumentProvider = (path, basePath) => moduleBuilder.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile); } ILBuilder il = new ILBuilder(moduleBuilder, localSlotManager, optimizations); try { Cci.AsyncMethodBodyDebugInfo asyncDebugInfo = null; builder(il); // il.Realize(); // var localVariables = il.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 (moduleBuilder.SaveTestData) //{ // moduleBuilder.SetMethodTestData(method, builder.GetSnapshot()); //} // Only compiler-generated MoveNext methods have iterator scopes. See if this is one. var stateMachineHoistedLocalScopes = default(ImmutableArray<Cci.StateMachineHoistedLocalScope>); //if (isStateMachineMoveNextMethod) //{ // stateMachineHoistedLocalScopes = builder.GetHoistedLocalScopes(); //} var stateMachineHoistedLocalSlots = default(ImmutableArray<EncHoistedLocalInfo>); var stateMachineAwaiterSlots = default(ImmutableArray<Cci.ITypeReference>); //if (optimizations == OptimizationLevel.Debug && stateMachineTypeOpt != null) //{ // Debug.Assert(method.IsAsync || method.IsIterator); // GetStateMachineSlotDebugInfo(moduleBuilder, moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), variableSlotAllocatorOpt, diagnosticsForThisMethod, out stateMachineHoistedLocalSlots, out stateMachineAwaiterSlots); // Debug.Assert(!diagnostics.HasAnyErrors()); //} return new MethodBody( il.RealizedIL, il.MaxStack, (Cci.IMethodDefinition)routine.PartialDefinitionPart ?? routine, variableSlotAllocatorOpt?.MethodId ?? new DebugId(0, moduleBuilder.CurrentGenerationOrdinal), localVariables, il.RealizedSequencePoints, debugDocumentProvider, il.RealizedExceptionHandlers, il.GetAllScopes(), il.HasDynamicLocal, null, // importScopeOpt, ImmutableArray<LambdaDebugInfo>.Empty, // lambdaDebugInfo, ImmutableArray<ClosureDebugInfo>.Empty, // closureDebugInfo, null, //stateMachineTypeOpt?.Name, stateMachineHoistedLocalScopes, stateMachineHoistedLocalSlots, stateMachineAwaiterSlots, asyncDebugInfo); } finally { // Basic blocks contain poolable builders for IL and sequence points. Free those back // to their pools. il.FreeBasicBlocks(); //// Remember diagnostics. //diagnostics.AddRange(diagnosticsForThisMethod); //diagnosticsForThisMethod.Free(); } }