Skip to content

Commit d197947

Browse files
committed
Invalidate deleted modules and libraries and process reloaded modules and libraries in provider
1 parent 2172ba7 commit d197947

File tree

14 files changed

+359
-185
lines changed

14 files changed

+359
-185
lines changed

dwds/lib/src/debugging/metadata/module_metadata.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ class ModuleMetadata {
103103
///
104104
/// Used as a name of the js module created by the compiler and
105105
/// as key to store and load modules in the debugger and the browser
106-
// TODO(srujzs): Remove once https://github.com/dart-lang/sdk/issues/59618 is
107-
// resolved.
108106
final String name;
109107

110108
/// Name of the function enclosing the module

dwds/lib/src/debugging/metadata/provider.dart

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ class MetadataProvider {
1515
final AssetReader _assetReader;
1616
final _logger = Logger('MetadataProvider');
1717
final String entrypoint;
18-
final List<String> _libraries = [];
18+
final Set<String> _libraries = {};
1919
final Map<String, String> _scriptToModule = {};
2020
final Map<String, String> _moduleToSourceMap = {};
2121
final Map<String, String> _modulePathToModule = {};
2222
final Map<String, String> _moduleToModulePath = {};
23+
final Map<String, Set<String>> _moduleToLibraries = {};
2324
final Map<String, List<String>> _scripts = {};
2425
final _metadataMemoizer = AsyncMemoizer();
25-
// Whether to use the `name` provided in the module metadata.
26-
final bool _useModuleName;
2726

2827
/// Implicitly imported libraries in any DDC component.
2928
///
@@ -66,11 +65,7 @@ class MetadataProvider {
6665
'dart:ui',
6766
];
6867

69-
MetadataProvider(
70-
this.entrypoint,
71-
this._assetReader, {
72-
required bool useModuleName,
73-
}) : _useModuleName = useModuleName;
68+
MetadataProvider(this.entrypoint, this._assetReader);
7469

7570
/// A sound null safety mode for the whole app.
7671
///
@@ -81,17 +76,17 @@ class MetadataProvider {
8176
return true;
8277
}
8378

84-
/// A list of all libraries in the Dart application.
79+
/// A set of all libraries in the Dart application.
8580
///
8681
/// Example:
8782
///
88-
/// [
83+
/// {
8984
/// dart:web_gl,
9085
/// dart:math,
9186
/// org-dartlang-app:///web/main.dart
92-
/// ]
87+
/// }
9388
///
94-
Future<List<String>> get libraries async {
89+
Future<Set<String>> get libraries async {
9590
await _initialize();
9691
return _libraries;
9792
}
@@ -118,9 +113,6 @@ class MetadataProvider {
118113
/// org-dartlang-app:///web/main.dart :
119114
/// web/main
120115
/// }
121-
///
122-
/// If [_useModuleName] is false, the values will be the module paths instead
123-
/// of the name except for 'dart_sdk'.
124116
Future<Map<String, String>> get scriptToModule async {
125117
await _initialize();
126118
return _scriptToModule;
@@ -134,9 +126,6 @@ class MetadataProvider {
134126
/// org-dartlang-app:///web/main.dart :
135127
/// web/main.ddc.js.map
136128
/// }
137-
///
138-
/// If [_useModuleName] is false, the keys will be the module paths instead of
139-
/// the name.
140129
Future<Map<String, String>> get moduleToSourceMap async {
141130
await _initialize();
142131
return _moduleToSourceMap;
@@ -150,9 +139,6 @@ class MetadataProvider {
150139
/// web/main.ddc.js :
151140
/// web/main
152141
/// }
153-
///
154-
/// If [_useModuleName] is false, the values will be the module paths instead
155-
/// of the name, making this an identity map.
156142
Future<Map<String, String>> get modulePathToModule async {
157143
await _initialize();
158144
return _modulePathToModule;
@@ -166,9 +152,6 @@ class MetadataProvider {
166152
/// web/main
167153
/// web/main.ddc.js :
168154
/// }
169-
///
170-
/// If [_useModuleName] is false, the keys will be the module paths instead of
171-
/// the name, making this an identity map.
172155
Future<Map<String, String>> get moduleToModulePath async {
173156
await _initialize();
174157
return _moduleToModulePath;
@@ -182,67 +165,108 @@ class MetadataProvider {
182165
/// web/main,
183166
/// web/foo/bar
184167
/// ]
185-
///
186-
/// If [_useModuleName] is false, this will be the set of module paths
187-
/// instead.
188168
Future<List<String>> get modules async {
189169
await _initialize();
190170
return _moduleToModulePath.keys.toList();
191171
}
192172

193-
Future<void> _initialize() async {
194-
await _metadataMemoizer.runOnce(() async {
195-
// The merged metadata resides next to the entrypoint.
196-
// Assume that <name>.bootstrap.js has <name>.ddc_merged_metadata
197-
if (entrypoint.endsWith('.bootstrap.js')) {
198-
_logger.info('Loading debug metadata...');
199-
final serverPath = entrypoint.replaceAll(
200-
'.bootstrap.js',
201-
'.ddc_merged_metadata',
202-
);
203-
final merged = await _assetReader.metadataContents(serverPath);
204-
if (merged != null) {
205-
_addSdkMetadata();
206-
for (final contents in merged.split('\n')) {
207-
try {
208-
if (contents.isEmpty ||
209-
contents.startsWith('// intentionally empty:')) {
210-
continue;
211-
}
212-
final moduleJson = json.decode(contents);
213-
final metadata = ModuleMetadata.fromJson(
214-
moduleJson as Map<String, dynamic>,
215-
);
173+
Future<Map<String, ModuleMetadata>?> _processMetadata(bool hotReload) async {
174+
final modules = hotReload ? <String, ModuleMetadata>{} : null;
175+
// The merged metadata resides next to the entrypoint.
176+
// Assume that <name>.bootstrap.js has <name>.ddc_merged_metadata
177+
if (entrypoint.endsWith('.bootstrap.js')) {
178+
_logger.info('Loading debug metadata...');
179+
final serverPath = entrypoint.replaceAll(
180+
'.bootstrap.js',
181+
'.ddc_merged_metadata',
182+
);
183+
final merged = await _assetReader.metadataContents(serverPath);
184+
if (merged != null) {
185+
// We can't hot reload the SDK yet, so no need to invalidate this data.
186+
if (!hotReload) _addSdkMetadata();
187+
for (final contents in merged.split('\n')) {
188+
try {
189+
if (contents.isEmpty ||
190+
contents.startsWith('// intentionally empty:')) {
191+
continue;
192+
}
193+
final moduleJson = json.decode(contents);
194+
final metadata = ModuleMetadata.fromJson(
195+
moduleJson as Map<String, dynamic>,
196+
);
197+
final moduleName = metadata.name;
198+
if (hotReload) {
199+
modules?[moduleName] = metadata;
200+
} else {
216201
_addMetadata(metadata);
217-
final moduleName =
218-
_useModuleName ? metadata.name : metadata.moduleUri;
219-
_logger.fine('Loaded debug metadata for module: $moduleName');
220-
} catch (e) {
221-
_logger.warning('Failed to read metadata: $e');
222-
rethrow;
223202
}
203+
_logger.fine('Loaded debug metadata for module: $moduleName');
204+
} catch (e) {
205+
_logger.warning('Failed to read metadata: $e');
206+
rethrow;
224207
}
225208
}
226209
}
227-
});
210+
}
211+
return modules;
212+
}
213+
214+
Future<void> _initialize() async {
215+
await _metadataMemoizer.runOnce(() => _processMetadata(false));
216+
}
217+
218+
Future<void> reinitializeAfterReload(Set<String> reloadedModules) async {
219+
final modules = (await _processMetadata(true))!;
220+
final invalidatedLibraries = <String>{};
221+
void invalidateLibrary(String libraryImportUri) {
222+
invalidatedLibraries.add(libraryImportUri);
223+
_libraries.remove(libraryImportUri);
224+
_scriptToModule.remove(libraryImportUri);
225+
_scripts[libraryImportUri]?.forEach(_scriptToModule.remove);
226+
_scripts.remove(libraryImportUri);
227+
}
228+
229+
final deletedModules = <String>{};
230+
final invalidatedModules = <String>{};
231+
for (final module in _moduleToLibraries.keys) {
232+
final deletedModule = !modules.containsKey(module);
233+
final invalidatedModule = reloadedModules.contains(module);
234+
assert(!(deletedModule && invalidatedModule));
235+
// If the module was either deleted or reloaded, invalidate all previous
236+
// information both about the module and its libraries.
237+
if (deletedModule || invalidatedModule) {
238+
_modulePathToModule.remove(module);
239+
_moduleToLibraries[module]?.forEach(invalidateLibrary);
240+
_moduleToModulePath.remove(module);
241+
_moduleToSourceMap.remove(module);
242+
}
243+
if (deletedModule) deletedModules.add(module);
244+
}
245+
for (final module in reloadedModules) {
246+
_addMetadata(modules[module]!);
247+
}
248+
// The libraries that were removed from the program or those that we
249+
// invalidated but were never added again.
250+
final deletedLibraries = invalidatedLibraries.where(
251+
(library) => !_libraries.contains(library),
252+
);
228253
}
229254

230255
void _addMetadata(ModuleMetadata metadata) {
231256
final modulePath = stripLeadingSlashes(metadata.moduleUri);
232257
final sourceMapPath = stripLeadingSlashes(metadata.sourceMapUri);
233-
// DDC library bundle module format does not provide names for library
234-
// bundles, and therefore we use the URI instead to represent a library
235-
// bundle.
236-
final moduleName = _useModuleName ? metadata.name : modulePath;
258+
final moduleName = metadata.name;
237259

238260
_moduleToSourceMap[moduleName] = sourceMapPath;
239261
_modulePathToModule[modulePath] = moduleName;
240262
_moduleToModulePath[moduleName] = modulePath;
241263

264+
final moduleLibraries = <String>{};
242265
for (final library in metadata.libraries.values) {
243266
if (library.importUri.startsWith('file:/')) {
244267
throw AbsoluteImportUriException(library.importUri);
245268
}
269+
moduleLibraries.add(library.importUri);
246270
_libraries.add(library.importUri);
247271
_scripts[library.importUri] = [];
248272

@@ -254,6 +278,7 @@ class MetadataProvider {
254278
_scriptToModule[partPath] = moduleName;
255279
}
256280
}
281+
_moduleToLibraries[moduleName] = moduleLibraries;
257282
}
258283

259284
void _addSdkMetadata() {
@@ -264,7 +289,8 @@ class MetadataProvider {
264289
_scripts[lib] = [];
265290
// TODO(srujzs): It feels weird that we add this mapping to only this map
266291
// and not any of the other module maps. We should maybe handle this
267-
// differently.
292+
// differently. This will become relevant if we ever support hot reload
293+
// for the Dart SDK.
268294
_scriptToModule[lib] = moduleName;
269295
}
270296
}

0 commit comments

Comments
 (0)