public unsafe int BuildForEnc(object pUpdatePE) { try { log.Write("Applying changes to {0}", _vsProject.DisplayName); Debug.Assert(_encService.EditSession != null); Debug.Assert(!_encService.EditSession.StoppedAtException); // Non-debuggable project has no changes. Debug.Assert(IsDebuggable); if (_changesApplied) { log.Write("Changes already applied to {0}, can't apply again", _vsProject.DisplayName); throw ExceptionUtilities.Unreachable; } // The debugger always calls GetENCBuildState right before BuildForEnc. Debug.Assert(_projectBeingEmitted != null); Debug.Assert(_lastEditSessionSummary == GetProjectAnalysisSummary(_projectBeingEmitted)); // The debugger should have called GetENCBuildState before calling BuildForEnc. // Unfortunately, there is no way how to tell the debugger that the changes were not significant, // so we'll to emit an empty delta. See bug 839558. Debug.Assert(_lastEditSessionSummary == ProjectAnalysisSummary.ValidInsignificantChanges || _lastEditSessionSummary == ProjectAnalysisSummary.ValidChanges); var updater = (IDebugUpdateInMemoryPE2)pUpdatePE; if (_committedBaseline == null) { var hr = MarshalPdbReader(updater, out _pdbReaderObjAsStream); if (hr != VSConstants.S_OK) { return hr; } _committedBaseline = EmitBaseline.CreateInitialBaseline(_metadata, GetBaselineEncDebugInfo); } // ISymUnmanagedReader can only be accessed from an MTA thread, // so dispatch it to one of thread pool threads, which are MTA. var emitTask = Task.Factory.SafeStartNew(EmitProjectDelta, CancellationToken.None, TaskScheduler.Default); Deltas delta; using (NonReentrantContext) { delta = emitTask.Result; if (delta == null) { // Non-fatal Watson has already been reported by the emit task return VSConstants.E_FAIL; } } var errorId = new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.EmitErrorId); // Clear diagnostics, in case the project was built before and failed due to errors. _diagnosticProvider.ClearDiagnostics(errorId, _projectBeingEmitted.Solution, _vsProject.Id, _documentsWithEmitError); if (!delta.EmitResult.Success) { var errors = delta.EmitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error); _documentsWithEmitError = _diagnosticProvider.ReportDiagnostics(errorId, _projectBeingEmitted.Solution, _vsProject.Id, errors); _encService.EditSession.LogEmitProjectDeltaErrors(errors.Select(e => e.Id)); return VSConstants.E_FAIL; } _documentsWithEmitError = ImmutableArray<DocumentId>.Empty; SetFileUpdates(updater, delta.LineEdits); updater.SetDeltaIL(delta.IL.Value, (uint)delta.IL.Value.Length); updater.SetDeltaPdb(SymUnmanagedStreamFactory.CreateStream(delta.Pdb.Stream)); updater.SetRemapMethods(delta.Pdb.UpdatedMethods, (uint)delta.Pdb.UpdatedMethods.Length); updater.SetDeltaMetadata(delta.Metadata.Bytes, (uint)delta.Metadata.Bytes.Length); _pendingBaseline = delta.EmitResult.Baseline; #if DEBUG fixed (byte* deltaMetadataPtr = &delta.Metadata.Bytes[0]) { var reader = new System.Reflection.Metadata.MetadataReader(deltaMetadataPtr, delta.Metadata.Bytes.Length); var moduleDef = reader.GetModuleDefinition(); log.DebugWrite("Gen {0}: MVID={1}, BaseId={2}, EncId={3}", moduleDef.Generation, reader.GetGuid(moduleDef.Mvid), reader.GetGuid(moduleDef.BaseGenerationId), reader.GetGuid(moduleDef.GenerationId)); } #endif return VSConstants.S_OK; } catch (Exception e) when (FatalError.ReportWithoutCrash(e)) { return VSConstants.E_FAIL; } }
public int StopDebuggingPE() { try { log.Write("Exit Debug Mode: project '{0}'", _vsProject.DisplayName); Debug.Assert(s_breakStateEnteredProjects.Count == 0); // Clear the solution stored while projects were entering break mode. // It should be cleared as soon as all tracked projects enter the break mode // but if the entering break mode fails for some projects we should avoid leaking the solution. Debug.Assert(s_breakStateEntrySolution == null); s_breakStateEntrySolution = null; // EnC service is global (per solution), but the debugger calls this for each project. // Avoid ending the debug session if it has already been ended. if (_encService.DebuggingSession != null) { _encService.OnBeforeDebuggingStateChanged(DebuggingState.Run, DebuggingState.Design); _encService.EndDebuggingSession(); LogEncSession(); s_encDebuggingSessionInfo = null; s_readOnlyDocumentTracker.Dispose(); s_readOnlyDocumentTracker = null; } if (_metadata != null) { _metadata.Dispose(); _metadata = null; s_debugStateProjectCount--; } else { // an error might have been reported: var errorId = new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId); _diagnosticProvider.ClearDiagnostics(errorId, _vsProject.Workspace.CurrentSolution, _vsProject.Id, documentIdOpt: null); } _activeMethods = null; _exceptionRegions = null; _committedBaseline = null; _activeStatementIds = null; _projectBeingEmitted = null; Debug.Assert((_pdbReaderObjAsStream == IntPtr.Zero) || (_pdbReader == null)); if (_pdbReader != null) { Marshal.ReleaseComObject(_pdbReader); _pdbReader = null; } // The HResult is ignored by the debugger. return VSConstants.S_OK; } catch (Exception e) when (FatalError.ReportWithoutCrash(e)) { return VSConstants.E_FAIL; } }