mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
[ddc] Reset all initialized consts on hot restart
Clear local caches storing const values in each module. Change-Id: I7766e92df6b8d1f91bad5fbb2addb8ace7763646 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347220 Reviewed-by: Mark Zhou <markzipan@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
39b7249915
commit
b811ab5b04
|
@ -519,8 +519,15 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
|
||||
moduleItems.addAll(afterClassDefItems);
|
||||
afterClassDefItems.clear();
|
||||
// Register the local const cache for this module so it can be cleared on a
|
||||
// hot restart.
|
||||
if (_constTableCache.isNotEmpty) {
|
||||
moduleItems.add(runtimeCall('moduleConstCaches.set(#, #)', [
|
||||
js_ast.string(_options.moduleName),
|
||||
_constTableCache.containerId
|
||||
]).toStatement());
|
||||
}
|
||||
_ticker?.logMs('Added table caches');
|
||||
|
||||
// Add all type hierarchy rules for the interface types used in this module.
|
||||
if (_options.newRuntimeTypes) {
|
||||
// TODO(nshahan) This is likely more information than the application
|
||||
|
|
|
@ -236,6 +236,13 @@ final List<Object> _cacheMaps = JS('!', '[]');
|
|||
@notNull
|
||||
final List<void Function()> resetFields = JS('', '[]');
|
||||
|
||||
/// A map of module ids (names) to the local const value cache in that module.
|
||||
///
|
||||
/// This is populated on module load and each cache is cleared during
|
||||
/// [hotRestart].
|
||||
@notNull
|
||||
final JSArray<Object?> moduleConstCaches = JS('!', 'new Map()');
|
||||
|
||||
/// A counter to track each time [hotRestart] is invoked. This is used to ensure
|
||||
/// that pending callbacks that were created on a previous iteration (e.g. a
|
||||
/// timer callback or a DOM callback) will not execute when they get invoked.
|
||||
|
@ -254,8 +261,16 @@ void hotRestart() {
|
|||
resetFields.clear();
|
||||
for (var m in _cacheMaps) JS('', '#.clear()', m);
|
||||
_cacheMaps.clear();
|
||||
// TODO(nshahan) Verify _nullComparisonSet isn't used with the new type system
|
||||
// and delete.
|
||||
JS('', '#.clear()', _nullComparisonSet);
|
||||
JS('', '#.clear()', constants);
|
||||
JS('', '#.clear()', constantLists);
|
||||
JS('', '#.clear()', constantSets);
|
||||
JS('', '#.clear()', constantMaps);
|
||||
|
||||
JS('', '#.forEach((value) => value.fill(void 0))', moduleConstCaches);
|
||||
|
||||
if (!_ddcDeferredLoading) {
|
||||
JS('', '#.clear()', deferredImports);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,22 @@ main() {
|
|||
// Read this static field first to avoid interference with other reset counts.
|
||||
var weakNullSafety = hasUnsoundNullSafety;
|
||||
|
||||
// TODO(42495) `Expect.throws` contains the use of a const that triggers an
|
||||
// extra field reset but consts are not correctly reset on hot restart so the
|
||||
// extra reset only appears once. Perform an initial Expect.throws here to
|
||||
// avoid confusion with the reset counts later.
|
||||
// The first call of `Expect.throws` involves type tests that initialize
|
||||
// values in the runtime type system that will read static fields. After
|
||||
// initialization fields are never read again (even after a hot restart)
|
||||
// so we perform the first call here before we start counting field resets.
|
||||
Expect.throws(() => throw 'foo');
|
||||
|
||||
var resetFieldCount = dart.resetFields.length;
|
||||
dart.hotRestart();
|
||||
|
||||
// Count the number of reset fields triggered by a call to `Expect.throws`
|
||||
// after every hot restart. This value is used as an offset in expectations
|
||||
// below.
|
||||
Expect.throws(() => throw 'foo');
|
||||
var expectThrowsResetFieldCount = dart.resetFields.length;
|
||||
Expect.equals(1, expectThrowsResetFieldCount);
|
||||
|
||||
dart.hotRestart();
|
||||
|
||||
// Set uninitialized static late fields. Avoid calling getters for these
|
||||
// statics to ensure they are reset even if they are never accessed.
|
||||
|
@ -62,12 +71,10 @@ main() {
|
|||
// Sound Null Safety - 6 total field resets:
|
||||
// - 3 write/resets for the actual uninitialized field writes.
|
||||
// - 3 reads/resets for the actual initialized field reads.
|
||||
var expectedResets =
|
||||
weakNullSafety ? resetFieldCount + 12 : resetFieldCount + 6;
|
||||
var expectedResets = weakNullSafety ? 12 : 6;
|
||||
Expect.equals(expectedResets, dart.resetFields.length);
|
||||
|
||||
dart.hotRestart();
|
||||
resetFieldCount = dart.resetFields.length;
|
||||
|
||||
// Late statics should throw on get when not initialized.
|
||||
Expect.throws(() => noInitializer);
|
||||
|
@ -95,12 +102,13 @@ main() {
|
|||
// Sound Null Safety - 6 total field resets:
|
||||
// - 3 write/resets for the actual uninitialized field writes.
|
||||
// - 3 reads/resets for the actual initialized field reads.
|
||||
expectedResets = weakNullSafety ? resetFieldCount + 12 : resetFieldCount + 6;
|
||||
expectedResets = weakNullSafety
|
||||
? expectThrowsResetFieldCount + 12
|
||||
: expectThrowsResetFieldCount + 6;
|
||||
Expect.equals(expectedResets, dart.resetFields.length);
|
||||
|
||||
dart.hotRestart();
|
||||
dart.hotRestart();
|
||||
resetFieldCount = dart.resetFields.length;
|
||||
|
||||
// Late statics should throw on get when not initialized.
|
||||
Expect.throws(() => noInitializer);
|
||||
|
@ -120,6 +128,8 @@ main() {
|
|||
// Sound Null Safety - 6 total field resets:
|
||||
// - 3 reads/resets for actual uninitialized field reads.
|
||||
// - 3 reads/resets for the actual initialized field reads.
|
||||
expectedResets = weakNullSafety ? resetFieldCount + 9 : resetFieldCount + 6;
|
||||
expectedResets = weakNullSafety
|
||||
? expectThrowsResetFieldCount + 9
|
||||
: expectThrowsResetFieldCount + 6;
|
||||
Expect.equals(expectedResets, dart.resetFields.length);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue