Ejemplo n.º 1
0
 public MethodBody(
     byte[] ilBits,
     ushort maxStack,
     Cci.IMethodDefinition parent,
     ImmutableArray <LocalDefinition> locals,
     SequencePointList sequencePoints,
     DebugDocumentProvider debugDocumentProvider,
     ImmutableArray <Cci.ExceptionHandlerRegion> exceptionHandlers,
     ImmutableArray <LocalScope> localScopes,
     Cci.CustomDebugInfoKind customDebugInfoKind,
     bool hasDynamicLocalVariables,
     ImmutableArray <NamespaceScope> namespaceScopes = default(ImmutableArray <NamespaceScope>),
     string iteratorClassName = null,
     ImmutableArray <LocalScope> iteratorScopes        = default(ImmutableArray <LocalScope>),
     Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo = null)
 {
     this.ilBits = ilBits;
     this.asyncMethodDebugInfo = asyncMethodDebugInfo;
     this.maxStack             = maxStack;
     this.parent                   = parent;
     this.locals                   = locals;
     this.sequencePoints           = sequencePoints;
     this.debugDocumentProvider    = debugDocumentProvider;
     this.exceptionHandlers        = exceptionHandlers;
     this.localScopes              = localScopes;
     this.customDebugInfoKind      = customDebugInfoKind;
     this.hasDynamicLocalVariables = hasDynamicLocalVariables;
     this.namespaceScopes          = namespaceScopes.IsDefault ? ImmutableArray <NamespaceScope> .Empty : namespaceScopes;
     this.iteratorClassName        = iteratorClassName;
     this.iteratorScopes           = iteratorScopes.IsDefault ? ImmutableArray <LocalScope> .Empty : iteratorScopes;
 }
Ejemplo n.º 2
0
 public MethodBody(
     byte[] ilBits,
     ushort maxStack,
     Cci.IMethodDefinition parent,
     ImmutableArray<LocalDefinition> locals,
     SequencePointList sequencePoints,
     DebugDocumentProvider debugDocumentProvider,
     ImmutableArray<Cci.ExceptionHandlerRegion> exceptionHandlers,
     ImmutableArray<LocalScope> localScopes,
     Cci.CustomDebugInfoKind customDebugInfoKind,
     bool hasDynamicLocalVariables,
     ImmutableArray<NamespaceScope> namespaceScopes = default(ImmutableArray<NamespaceScope>),
     string iteratorClassName = null,
     ImmutableArray<LocalScope> iteratorScopes = default(ImmutableArray<LocalScope>),
     Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo = null)
 {
     this.ilBits = ilBits;
     this.asyncMethodDebugInfo = asyncMethodDebugInfo;
     this.maxStack = maxStack;
     this.parent = parent;
     this.locals = locals;
     this.sequencePoints = sequencePoints;
     this.debugDocumentProvider = debugDocumentProvider;
     this.exceptionHandlers = exceptionHandlers;
     this.localScopes = localScopes;
     this.customDebugInfoKind = customDebugInfoKind;
     this.hasDynamicLocalVariables = hasDynamicLocalVariables;
     this.namespaceScopes = namespaceScopes.IsDefault ? ImmutableArray<NamespaceScope>.Empty : namespaceScopes;
     this.iteratorClassName = iteratorClassName;
     this.iteratorScopes = iteratorScopes.IsDefault ? ImmutableArray<LocalScope>.Empty : iteratorScopes;
 }
        private void SerializeAsyncMethodSteppingInfo(AsyncMethodBodyDebugInfo asyncInfo, MethodDefinitionHandle moveNextMethod)
        {
            Debug.Assert(asyncInfo.ResumeOffsets.Length == asyncInfo.YieldOffsets.Length);
            Debug.Assert(asyncInfo.CatchHandlerOffset >= -1);

            var writer = new BlobBuilder();

            writer.WriteUInt32((uint)((long)asyncInfo.CatchHandlerOffset + 1));

            for (int i = 0; i < asyncInfo.ResumeOffsets.Length; i++)
            {
                writer.WriteUInt32((uint)asyncInfo.YieldOffsets[i]);
                writer.WriteUInt32((uint)asyncInfo.ResumeOffsets[i]);
                writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(moveNextMethod));
            }

            _debugMetadataOpt.AddCustomDebugInformation(
                parent: moveNextMethod,
                kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob),
                value: _debugMetadataOpt.GetOrAddBlob(writer));
        }
Ejemplo n.º 4
0
        private void SerializeAsyncMethodSteppingInfo(AsyncMethodBodyDebugInfo asyncInfo, int moveNextMethodRid)
        {
            Debug.Assert(asyncInfo.ResumeOffsets.Length == asyncInfo.YieldOffsets.Length);
            Debug.Assert(asyncInfo.CatchHandlerOffset >= -1);

            var writer = new BlobBuilder();

            writer.WriteUInt32((uint)((long)asyncInfo.CatchHandlerOffset + 1));

            for (int i = 0; i < asyncInfo.ResumeOffsets.Length; i++)
            {
                writer.WriteUInt32((uint)asyncInfo.YieldOffsets[i]);
                writer.WriteUInt32((uint)asyncInfo.ResumeOffsets[i]);
                writer.WriteCompressedInteger((uint)moveNextMethodRid);
            }

            _customDebugInformationTable.Add(new CustomDebugInformationRow
            {
                Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.MethodDef, moveNextMethodRid),
                Kind   = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob),
                Value  = _debugHeapsOpt.GetBlobIndex(writer),
            });
        }
Ejemplo n.º 5
0
        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();
            }
        }
Ejemplo n.º 6
0
        public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter)
        {
            Debug.Assert(_metadataWriter != null);

            bool isIterator    = methodBody.StateMachineTypeName != null;
            bool emitDebugInfo = isIterator || methodBody.HasAnySequencePoints;

            if (!emitDebugInfo)
            {
                return;
            }

            uint methodToken = _metadataWriter.GetMethodToken(methodBody.MethodDefinition);

            OpenMethod(methodToken);

            var localScopes = methodBody.LocalScopes;

            // CCI originally didn't have the notion of the default scope that is open
            // when a method is opened. In order to reproduce CSC PDBs, this must be added. Otherwise
            // a seemingly unnecessary scope that contains only other scopes is put in the PDB.
            if (localScopes.Length > 0)
            {
                this.DefineScopeLocals(localScopes[0], localSignatureToken);
            }

            // NOTE: This is an attempt to match Dev10's apparent behavior.  For iterator methods (i.e. the method
            // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal
            // custom debug info (e.g. there will be no information about the usings that were in scope).
            if (!isIterator)
            {
                IMethodDefinition forwardToMethod;
                if (customDebugInfoWriter.ShouldForwardNamespaceScopes(Context, methodBody, methodToken, out forwardToMethod))
                {
                    if (forwardToMethod != null)
                    {
                        UsingNamespace("@" + _metadataWriter.GetMethodToken(forwardToMethod), methodBody.MethodDefinition);
                    }
                    // otherwise, the forwarding is done via custom debug info
                }
                else
                {
                    this.DefineNamespaceScopes(methodBody);
                }
            }

            DefineLocalScopes(localScopes, localSignatureToken);

            EmitSequencePoints(methodBody.GetSequencePoints());

            AsyncMethodBodyDebugInfo asyncDebugInfo = methodBody.AsyncDebugInfo;

            if (asyncDebugInfo != null)
            {
                SetAsyncInfo(
                    methodToken,
                    _metadataWriter.GetMethodToken(asyncDebugInfo.KickoffMethod),
                    asyncDebugInfo.CatchHandlerOffset,
                    asyncDebugInfo.YieldOffsets,
                    asyncDebugInfo.ResumeOffsets);
            }

            var compilationOptions = Context.ModuleBuilder.CommonCompilation.Options;

            // We need to avoid emitting CDI DynamicLocals = 5 and EditAndContinueLocalSlotMap = 6 for files processed by WinMDExp until
            // bug #1067635 is fixed and available in SDK.
            bool suppressNewCustomDebugInfo = !compilationOptions.ExtendedCustomDebugInformation ||
                                              (compilationOptions.OutputKind == OutputKind.WindowsRuntimeMetadata);

            bool emitEncInfo = compilationOptions.EnableEditAndContinue && !_metadataWriter.IsFullMetadata;

            bool emitExternNamespaces;

            byte[] blob = customDebugInfoWriter.SerializeMethodDebugInfo(Context, methodBody, methodToken, emitEncInfo, suppressNewCustomDebugInfo, out emitExternNamespaces);
            if (blob != null)
            {
                DefineCustomMetadata("MD2", blob);
            }

            if (emitExternNamespaces)
            {
                this.DefineAssemblyReferenceAliases();
            }

            // TODO: it's not clear why we are closing a scope here with IL length:
            CloseScope(methodBody.IL.Length);

            CloseMethod();
        }
Ejemplo n.º 7
0
        /// <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();
            }
        }
Ejemplo n.º 8
0
        public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter)
        {
            Debug.Assert(peWriter != null);

            bool isIterator    = methodBody.IteratorClassName != null;
            bool emitDebugInfo = isIterator || methodBody.HasAnyLocations;

            if (!emitDebugInfo)
            {
                return;
            }

            uint methodToken = peWriter.GetMethodToken(methodBody.MethodDefinition);

            OpenMethod(methodToken);

            var localScopes = methodBody.LocalScopes;

            // CCI originally didn't have the notion of the default scope that is open
            // when a method is opened. In order to reproduce CSC PDBs, this must be added. Otherwise
            // a seemingly unnecessary scope that contains only other scopes is put in the PDB.
            if (localScopes.Length > 0)
            {
                this.DefineScopeLocals(localScopes[0], localSignatureToken);
            }

            // NOTE: This is an attempt to match Dev10's apparent behavior.  For iterator methods (i.e. the method
            // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal
            // custom debug info (e.g. there will be no information about the usings that were in scope).
            if (!isIterator)
            {
                IMethodDefinition forwardToMethod;
                if (customDebugInfoWriter.ShouldForwardNamespaceScopes(methodBody, methodToken, out forwardToMethod))
                {
                    if (forwardToMethod != null)
                    {
                        string usingString = "@" + peWriter.GetMethodToken(forwardToMethod);
                        Debug.Assert(!peWriter.IsUsingStringTooLong(usingString));
                        UsingNamespace(usingString, methodBody.MethodDefinition.Name);
                    }

                    // otherwise, the forwarding is done via custom debug info
                }
                else
                {
                    this.DefineNamespaceScopes(methodBody);
                }
            }

            DefineLocalScopes(localScopes, localSignatureToken);

            EmitSequencePoints(methodBody.GetSequencePoints());

            AsyncMethodBodyDebugInfo asyncDebugInfo = methodBody.AsyncMethodDebugInfo;

            if (asyncDebugInfo != null)
            {
                SetAsyncInfo(
                    methodToken,
                    peWriter.GetMethodToken(asyncDebugInfo.KickoffMethod),
                    asyncDebugInfo.CatchHandlerOffset,
                    asyncDebugInfo.YieldOffsets,
                    asyncDebugInfo.ResumeOffsets);
            }

            var module = peWriter.Context.Module;

            bool emitExternNamespaces;

            byte[] blob = customDebugInfoWriter.SerializeMethodDebugInfo(module, methodBody, methodToken, out emitExternNamespaces);
            if (blob != null)
            {
                DefineCustomMetadata("MD2", blob);
            }

            if (emitExternNamespaces)
            {
                this.DefineExternAliases(module);
            }

            // TODO: it's not clear why we are closing a scope here with IL length:
            CloseScope((uint)methodBody.IL.Length);

            CloseMethod();
        }
        private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, StandaloneSignatureHandle localSignatureHandleOpt, ref LocalVariableHandle lastLocalVariableHandle, ref LocalConstantHandle lastLocalConstantHandle)
        {
            if (bodyOpt == null)
            {
                _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle));
                return;
            }

            bool isIterator    = bodyOpt.StateMachineTypeName != null;
            bool emitDebugInfo = isIterator || bodyOpt.HasAnySequencePoints;

            if (!emitDebugInfo)
            {
                _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle));
                return;
            }

            MethodDefinitionHandle methodHandle = MetadataTokens.MethodDefinitionHandle(methodRid);

            IImportScope      bodyImportScope   = bodyOpt.ImportScope;
            ImportScopeHandle importScopeHandle = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : default(ImportScopeHandle);

            // documents & sequence points:
            ArrayBuilder <Cci.SequencePoint> sequencePoints = ArrayBuilder <Cci.SequencePoint> .GetInstance();

            bodyOpt.GetSequencePoints(sequencePoints);
            BlobHandle sequencePointsBlob = SerializeSequencePoints(localSignatureHandleOpt, sequencePoints.ToImmutableAndFree(), _documentIndex, out DocumentHandle singleDocumentHandle);

            _debugMetadataOpt.AddMethodDebugInformation(document: singleDocumentHandle, sequencePoints: sequencePointsBlob);

            // Unlike native PDB we don't emit an empty root scope.
            // scopes are already ordered by StartOffset ascending then by EndOffset descending (the longest scope first).

            if (bodyOpt.LocalScopes.Length == 0)
            {
                // TODO: the compiler should produce a scope for each debuggable method
                _debugMetadataOpt.AddLocalScope(
                    method: methodHandle,
                    importScope: importScopeHandle,
                    variableList: NextHandle(lastLocalVariableHandle),
                    constantList: NextHandle(lastLocalConstantHandle),
                    startOffset: 0,
                    length: bodyOpt.IL.Length);
            }
            else
            {
                foreach (LocalScope scope in bodyOpt.LocalScopes)
                {
                    _debugMetadataOpt.AddLocalScope(
                        method: methodHandle,
                        importScope: importScopeHandle,
                        variableList: NextHandle(lastLocalVariableHandle),
                        constantList: NextHandle(lastLocalConstantHandle),
                        startOffset: scope.StartOffset,
                        length: scope.Length);

                    foreach (ILocalDefinition local in scope.Variables)
                    {
                        Debug.Assert(local.SlotIndex >= 0);

                        lastLocalVariableHandle = _debugMetadataOpt.AddLocalVariable(
                            attributes: local.PdbAttributes,
                            index: local.SlotIndex,
                            name: _debugMetadataOpt.GetOrAddString(local.Name));

                        SerializeLocalInfo(local, lastLocalVariableHandle);
                    }

                    foreach (ILocalDefinition constant in scope.Constants)
                    {
                        CodeAnalysis.CodeGen.MetadataConstant mdConstant = constant.CompileTimeValue;
                        Debug.Assert(mdConstant != null);

                        lastLocalConstantHandle = _debugMetadataOpt.AddLocalConstant(
                            name: _debugMetadataOpt.GetOrAddString(constant.Name),
                            signature: SerializeLocalConstantSignature(constant));

                        SerializeLocalInfo(constant, lastLocalConstantHandle);
                    }
                }
            }

            AsyncMethodBodyDebugInfo asyncDebugInfo = bodyOpt.AsyncDebugInfo;

            if (asyncDebugInfo != null)
            {
                _debugMetadataOpt.AddStateMachineMethod(
                    moveNextMethod: methodHandle,
                    kickoffMethod: GetMethodDefinitionHandle(asyncDebugInfo.KickoffMethod));

                SerializeAsyncMethodSteppingInfo(asyncDebugInfo, methodHandle);
            }

            SerializeStateMachineLocalScopes(bodyOpt, methodHandle);

            // delta doesn't need this information - we use information recorded by previous generation emit
            if (Context.Module.CommonCompilation.Options.EnableEditAndContinue && IsFullMetadata)
            {
                SerializeEncMethodDebugInformation(bodyOpt, methodHandle);
            }
        }