@@ -13,6 +13,7 @@ import 'package:dwds/src/debugging/execution_context.dart';
1313import 'package:dwds/src/debugging/instance.dart' ;
1414import 'package:dwds/src/debugging/libraries.dart' ;
1515import 'package:dwds/src/debugging/location.dart' ;
16+ import 'package:dwds/src/debugging/metadata/provider.dart' ;
1617import 'package:dwds/src/debugging/remote_debugger.dart' ;
1718import 'package:dwds/src/loaders/ddc_library_bundle.dart' ;
1819import 'package:dwds/src/readers/asset_reader.dart' ;
@@ -34,7 +35,9 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
3435class AppInspector implements AppInspectorInterface {
3536 var _scriptCacheMemoizer = AsyncMemoizer <List <ScriptRef >>();
3637
37- Future <List <ScriptRef >> get scriptRefs => _populateScriptCaches ();
38+ Future <List <ScriptRef >> getScriptRefs ([
39+ InvalidatedModuleReport ? invalidatedModuleReport,
40+ ]) => _populateScriptCaches (invalidatedModuleReport);
3841
3942 final _logger = Logger ('AppInspector' );
4043
@@ -103,24 +106,35 @@ class AppInspector implements AppInspectorInterface {
103106
104107 /// Reset all caches and recompute any mappings.
105108 ///
106- /// Should be called across hot reloads.
107- Future <void > initialize () async {
109+ /// Should be called across hot reloads with a valid [invalidatedModuleReport] .
110+ Future <void > initialize ([
111+ InvalidatedModuleReport ? invalidatedModuleReport,
112+ ]) async {
108113 _scriptCacheMemoizer = AsyncMemoizer <List <ScriptRef >>();
109- _scriptRefsById.clear ();
110- _serverPathToScriptRef.clear ();
111- _scriptIdToLibraryId.clear ();
112- _libraryIdToScriptRefs.clear ();
113114
114- _libraryHelper = LibraryHelper (this );
115+ // TODO(srujzs): We can invalidate these in a smarter way instead of
116+ // reinitializing when doing a hot reload, but these helpers recompute info
117+ // on demand and therefore are not in the critical path.
115118 _classHelper = ClassHelper (this );
116119 _instanceHelper = InstanceHelper (this );
117120
121+ if (invalidatedModuleReport != null ) {
122+ // Invalidate `_libraryHelper` as we use it populate any script caches.
123+ _libraryHelper.invalidate (invalidatedModuleReport);
124+ } else {
125+ _libraryHelper = LibraryHelper (this );
126+ _scriptRefsById.clear ();
127+ _serverPathToScriptRef.clear ();
128+ _scriptIdToLibraryId.clear ();
129+ _libraryIdToScriptRefs.clear ();
130+ }
131+
118132 final libraries = await _libraryHelper.libraryRefs;
119133 isolate.rootLib = await _libraryHelper.rootLib;
120134 isolate.libraries? .clear ();
121135 isolate.libraries? .addAll (libraries);
122136
123- final scripts = await scriptRefs ;
137+ final scripts = await getScriptRefs (invalidatedModuleReport) ;
124138
125139 await DartUri .initialize ();
126140 DartUri .recordAbsoluteUris (libraries.map ((lib) => lib.uri).nonNulls);
@@ -583,7 +597,7 @@ class AppInspector implements AppInspectorInterface {
583597 /// All the scripts in the isolate.
584598 @override
585599 Future <ScriptList > getScripts () async {
586- return ScriptList (scripts: await scriptRefs );
600+ return ScriptList (scripts: await getScriptRefs () );
587601 }
588602
589603 /// Calls the Chrome Runtime.getProperties API for the object with [objectId] .
@@ -714,19 +728,50 @@ class AppInspector implements AppInspectorInterface {
714728 ///
715729 /// This will get repopulated on restarts and reloads.
716730 ///
731+ /// If [invalidatedModuleReport] is provided, only invalidates and
732+ /// recalculates caches for the invalidated libraries.
733+ ///
717734 /// Returns the list of scripts refs cached.
718- Future <List <ScriptRef >> _populateScriptCaches () {
735+ Future <List <ScriptRef >> _populateScriptCaches ([
736+ InvalidatedModuleReport ? invalidatedModuleReport,
737+ ]) {
719738 return _scriptCacheMemoizer.runOnce (() async {
720739 final scripts =
721740 await globalToolConfiguration.loadStrategy
722741 .metadataProviderFor (appConnection.request.entrypointPath)
723742 .scripts;
743+ final invalidatedLibraries = invalidatedModuleReport? .deletedLibraries
744+ .union (invalidatedModuleReport.reloadedLibraries);
745+ if (invalidatedLibraries != null ) {
746+ for (final libraryUri in invalidatedLibraries) {
747+ final libraryRef = await _libraryHelper.libraryRefFor (libraryUri);
748+ final libraryId = libraryRef? .id;
749+ if (libraryId == null ) continue ;
750+ final scriptRefs = _libraryIdToScriptRefs.remove (libraryId);
751+ if (scriptRefs == null ) continue ;
752+ for (final scriptRef in scriptRefs) {
753+ final scriptId = scriptRef.id;
754+ final scriptUri = scriptRef.uri;
755+ if (scriptId != null && scriptUri != null ) {
756+ _scriptRefsById.remove (scriptId);
757+ _scriptIdToLibraryId.remove (scriptId);
758+ _serverPathToScriptRef.remove (
759+ DartUri (scriptUri, _root).serverPath,
760+ );
761+ }
762+ }
763+ }
764+ }
724765 // For all the non-dart: libraries, find their parts and create scriptRefs
725766 // for them.
726767 final userLibraries = _userLibraryUris (
727768 isolate.libraries ?? < LibraryRef > [],
728769 );
729770 for (final uri in userLibraries) {
771+ if (invalidatedLibraries != null &&
772+ ! invalidatedLibraries.contains (uri)) {
773+ continue ;
774+ }
730775 final parts = scripts[uri];
731776 final scriptRefs = [
732777 ScriptRef (uri: uri, id: createId ()),
0 commit comments