@@ -13,6 +13,7 @@ import 'package:dwds/src/debugging/execution_context.dart';
13
13
import 'package:dwds/src/debugging/instance.dart' ;
14
14
import 'package:dwds/src/debugging/libraries.dart' ;
15
15
import 'package:dwds/src/debugging/location.dart' ;
16
+ import 'package:dwds/src/debugging/metadata/provider.dart' ;
16
17
import 'package:dwds/src/debugging/remote_debugger.dart' ;
17
18
import 'package:dwds/src/loaders/ddc_library_bundle.dart' ;
18
19
import 'package:dwds/src/readers/asset_reader.dart' ;
@@ -34,7 +35,9 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
34
35
class AppInspector implements AppInspectorInterface {
35
36
var _scriptCacheMemoizer = AsyncMemoizer <List <ScriptRef >>();
36
37
37
- Future <List <ScriptRef >> get scriptRefs => _populateScriptCaches ();
38
+ Future <List <ScriptRef >> getScriptRefs ({
39
+ ModifiedModuleReport ? modifiedModuleReport,
40
+ }) => _populateScriptCaches (modifiedModuleReport: modifiedModuleReport);
38
41
39
42
final _logger = Logger ('AppInspector' );
40
43
@@ -103,24 +106,35 @@ class AppInspector implements AppInspectorInterface {
103
106
104
107
/// Reset all caches and recompute any mappings.
105
108
///
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 {
108
111
_scriptCacheMemoizer = AsyncMemoizer <List <ScriptRef >>();
109
- _scriptRefsById.clear ();
110
- _serverPathToScriptRef.clear ();
111
- _scriptIdToLibraryId.clear ();
112
- _libraryIdToScriptRefs.clear ();
113
112
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.
115
116
_classHelper = ClassHelper (this );
116
117
_instanceHelper = InstanceHelper (this );
117
118
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
+
118
130
final libraries = await _libraryHelper.libraryRefs;
119
131
isolate.rootLib = await _libraryHelper.rootLib;
120
132
isolate.libraries? .clear ();
121
133
isolate.libraries? .addAll (libraries);
122
134
123
- final scripts = await scriptRefs;
135
+ final scripts = await getScriptRefs (
136
+ modifiedModuleReport: modifiedModuleReport,
137
+ );
124
138
125
139
await DartUri .initialize ();
126
140
DartUri .recordAbsoluteUris (libraries.map ((lib) => lib.uri).nonNulls);
@@ -583,7 +597,7 @@ class AppInspector implements AppInspectorInterface {
583
597
/// All the scripts in the isolate.
584
598
@override
585
599
Future <ScriptList > getScripts () async {
586
- return ScriptList (scripts: await scriptRefs );
600
+ return ScriptList (scripts: await getScriptRefs () );
587
601
}
588
602
589
603
/// Calls the Chrome Runtime.getProperties API for the object with [objectId] .
@@ -714,19 +728,50 @@ class AppInspector implements AppInspectorInterface {
714
728
///
715
729
/// This will get repopulated on restarts and reloads.
716
730
///
731
+ /// If [modifiedModuleReport] is provided, only invalidates and
732
+ /// recalculates caches for the modified libraries.
733
+ ///
717
734
/// Returns the list of scripts refs cached.
718
- Future <List <ScriptRef >> _populateScriptCaches () {
735
+ Future <List <ScriptRef >> _populateScriptCaches ({
736
+ ModifiedModuleReport ? modifiedModuleReport,
737
+ }) {
719
738
return _scriptCacheMemoizer.runOnce (() async {
720
739
final scripts =
721
740
await globalToolConfiguration.loadStrategy
722
741
.metadataProviderFor (appConnection.request.entrypointPath)
723
742
.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
+ }
724
766
// For all the non-dart: libraries, find their parts and create scriptRefs
725
767
// for them.
726
768
final userLibraries = _userLibraryUris (
727
769
isolate.libraries ?? < LibraryRef > [],
728
770
);
729
771
for (final uri in userLibraries) {
772
+ if (modifiedModuleReport? .modifiedLibraries.contains (uri) == false ) {
773
+ continue ;
774
+ }
730
775
final parts = scripts[uri];
731
776
final scriptRefs = [
732
777
ScriptRef (uri: uri, id: createId ()),
0 commit comments