@@ -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+ ModifiedModuleReport ? modifiedModuleReport,
40+ }) => _populateScriptCaches (modifiedModuleReport: modifiedModuleReport);
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 [ModifiedModuleReport] .
110+ Future <void > initialize ({ ModifiedModuleReport ? modifiedModuleReport} ) async {
108111 _scriptCacheMemoizer = AsyncMemoizer <List <ScriptRef >>();
109- _scriptRefsById.clear ();
110- _serverPathToScriptRef.clear ();
111- _scriptIdToLibraryId.clear ();
112- _libraryIdToScriptRefs.clear ();
113112
114- _libraryHelper = LibraryHelper (this );
113+ // TODO(srujzs): We can invalidate these in a smarter way instead of
114+ // reinitializing when doing a hot reload, but these helpers recompute info
115+ // on demand later and therefore are not in the critical path.
115116 _classHelper = ClassHelper (this );
116117 _instanceHelper = InstanceHelper (this );
117118
119+ if (modifiedModuleReport != null ) {
120+ // Invalidate `_libraryHelper` as we use it populate any script caches.
121+ _libraryHelper.initialize (modifiedModuleReport: modifiedModuleReport);
122+ } else {
123+ _libraryHelper = LibraryHelper (this )..initialize ();
124+ _scriptRefsById.clear ();
125+ _serverPathToScriptRef.clear ();
126+ _scriptIdToLibraryId.clear ();
127+ _libraryIdToScriptRefs.clear ();
128+ }
129+
118130 final libraries = await _libraryHelper.libraryRefs;
119131 isolate.rootLib = await _libraryHelper.rootLib;
120132 isolate.libraries? .clear ();
121133 isolate.libraries? .addAll (libraries);
122134
123- final scripts = await scriptRefs;
135+ final scripts = await getScriptRefs (
136+ modifiedModuleReport: modifiedModuleReport,
137+ );
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 [modifiedModuleReport] is provided, only invalidates and
732+ /// recalculates caches for the modified libraries.
733+ ///
717734 /// Returns the list of scripts refs cached.
718- Future <List <ScriptRef >> _populateScriptCaches () {
735+ Future <List <ScriptRef >> _populateScriptCaches ({
736+ ModifiedModuleReport ? modifiedModuleReport,
737+ }) {
719738 return _scriptCacheMemoizer.runOnce (() async {
720739 final scripts =
721740 await globalToolConfiguration.loadStrategy
722741 .metadataProviderFor (appConnection.request.entrypointPath)
723742 .scripts;
743+ if (modifiedModuleReport != null ) {
744+ // Invalidate any script caches that were computed for the now invalid
745+ // libraries. They will get repopulated below.
746+ for (final libraryUri in modifiedModuleReport.modifiedLibraries) {
747+ final libraryRef = await _libraryHelper.libraryRefFor (libraryUri);
748+ final libraryId = libraryRef? .id;
749+ // If this was not a pre-existing library, nothing to invalidate.
750+ if (libraryId == null ) continue ;
751+ final scriptRefs = _libraryIdToScriptRefs.remove (libraryId);
752+ if (scriptRefs == null ) continue ;
753+ for (final scriptRef in scriptRefs) {
754+ final scriptId = scriptRef.id;
755+ final scriptUri = scriptRef.uri;
756+ if (scriptId != null && scriptUri != null ) {
757+ _scriptRefsById.remove (scriptId);
758+ _scriptIdToLibraryId.remove (scriptId);
759+ _serverPathToScriptRef.remove (
760+ DartUri (scriptUri, _root).serverPath,
761+ );
762+ }
763+ }
764+ }
765+ }
724766 // For all the non-dart: libraries, find their parts and create scriptRefs
725767 // for them.
726768 final userLibraries = _userLibraryUris (
727769 isolate.libraries ?? < LibraryRef > [],
728770 );
729771 for (final uri in userLibraries) {
772+ if (modifiedModuleReport? .modifiedLibraries.contains (uri) == false ) {
773+ continue ;
774+ }
730775 final parts = scripts[uri];
731776 final scriptRefs = [
732777 ScriptRef (uri: uri, id: createId ()),
0 commit comments