Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for finer-grained kernel libraries for incremental hot-reload #34001

Closed
aam opened this issue Jul 27, 2018 · 8 comments
Closed

Allow for finer-grained kernel libraries for incremental hot-reload #34001

aam opened this issue Jul 27, 2018 · 8 comments
Assignees
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. vm-hot-reload

Comments

@aam
Copy link
Contributor

aam commented Jul 27, 2018

Currently as part of hot reload flow, even small incremental changes result in full kernel libraries being generated and sent from frontend to VM.
Further, even well-encapsulated changes to method bodies result in complete library chain from the main-method library down to the library with the change will get generated and set from frontend to VM.

This issue tracks improvements to address these deficiencies.

Initial plan to address this is to prototype diff-logic as part of frontend-server that is used as a intermediary between VM and compiler, evaluate performance and complexity, then based on evaluation results move that into compiler itself.

cc @peter-ahe-google @a-siva

@aam aam added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. vm-hot-reload labels Jul 27, 2018
@aam aam self-assigned this Jul 27, 2018
@aam
Copy link
Contributor Author

aam commented Oct 3, 2018

With https://dart-review.googlesource.com/c/sdk/+/77722 I'm seeing some improvements in size of kernel file, number of classes reloaded by VM for flutter gallery:

Change New libraries count Old libraries count New kernel file size(bytes) Old kernel file size(bytes)
current flutter benchmark) app.dart:131 "Flutter Gallery" -> "Updated Flutter Gallery" 1 2 9,675 10,400
scales.dart:34 "1.0" -> "1.1" 1 4 2,302 36,764
widgets.dart:131 "6.0" -> "5.0" 8 53 122,931 629,972

Peter, if you have a chance can you please take a look at the patch's changes. Does it align with what you had in mind for minimizing incremental kernel file?
Changes to incremental_compiler.dart(_hasSameContent) are very naive, so if overall this reduction makes sense as a first step, I will be looking for suggestions on how to do "only-changed-libraries" check correctly.

cc'ing @jensjoha @kmillikin since this was mentioned recently in context of flutter test improvements.

@aam
Copy link
Contributor Author

aam commented Oct 5, 2018

It looks like vm would benefit from having information about libraries that transitively depend on changed library. Basic list of uris would be sufficient as vm simply need to know what compiled code it needs to drop since all of that compiled code would be invalidated by changed dependency.
Question is what would be the best way to communicate that list of dependents for a given changed set of libraries? Should we put this information into metadata for the incrementally produced kernel file? Should we put somehow truncated versions of dependent libraries?

Oh, and assumption is that this dependents information is readily available in the compiler, it's just a matter of serializing and passing it out to vm via incremental kernel file.

@jensjoha
Copy link
Contributor

jensjoha commented Mar 2, 2020

In https://dart-review.googlesource.com/c/sdk/+/77722 you update the VM to handle only sending over the single/few changed library/libraries in these cases.

I'm working on allowing the incremental compiler do less work in some circumstances. This will naturally also enable us to serialize less. Doing so - so far - has seemed to work fine without any VM changes. Is this expected or have I just been "lucky" so far?

@jensjoha
Copy link
Contributor

jensjoha commented Mar 2, 2020

Maybe a little context:

I'm adding an experimental invalidation feature to the incremental compiler so - that if the structure/outline of the changed files doesn't change - we only re-compile those files (modulo mixins).
For instance, changing stuff slightly inside the build method on class Text in flutter without this change gives a result along the lines of

Compiler message:
computeDelta took 2024 ms
Performing hot reload...
Reloaded 334 of 646 libraries in 3,127ms.

whereas with this feature it gives a result along the lines of

Compiler message:
computeDelta took 34 ms
Performing hot reload...
Reloaded 1 of 646 libraries in 262ms.

I have not modified the VM at it seems to work fine.

(Note that the example above was picked as a 'bad case' for the 'transitively invalidate everything' standard mode of operating and as a working case for the new thing, so it's not always going to give a 10x speedup).

@aam
Copy link
Contributor Author

aam commented Mar 2, 2020

Yes I believe you can get lucky and get smaller incremental kernel files loaded by vm without causing further problems in running program, but generally speaking we need to drop and recompile unoptimized code for indirectly-dependent libraries even in case when change to the library is limited to method's implementation.

cc @rmacnak-google

@jensjoha
Copy link
Contributor

jensjoha commented Mar 6, 2020

Yes I believe you can get lucky and get smaller incremental kernel files loaded by vm without causing further problems in running program, but generally speaking we need to drop and recompile unoptimized code for indirectly-dependent libraries even in case when change to the library is limited to method's implementation.

cc @rmacnak-google

And how much work would it be to do something like that? (can the VM track that down itself? Or should it be included somehow?)

By recompiling experimentally, and only outputting the single library I get reload times like this:

Initializing hot reload...                                              
Reloaded 1 of 647 libraries in 411ms.

Performing hot reload...                                                
Reloaded 1 of 647 libraries in 271ms.

Performing hot reload...                                                
Reloaded 1 of 647 libraries in 257ms.

Performing hot reload...                                                
Reloaded 1 of 647 libraries in 234ms.

Performing hot reload...                                                
Reloaded 1 of 647 libraries in 239ms.

But by recompiling experimentally, and outputting the same libraries as I normally would I get reload times like this:

Performing hot reload...                                                
Reloaded 334 of 647 libraries in 1,317ms.

Performing hot reload...                                                
Reloaded 334 of 647 libraries in 1,196ms.

Performing hot reload...                                                
Reloaded 334 of 647 libraries in 1,256ms.

Performing hot reload...                                                
Reloaded 334 of 647 libraries in 1,188ms.

Performing hot reload...                                                
Reloaded 334 of 647 libraries in 1,183ms.

@aam
Copy link
Contributor Author

aam commented Mar 6, 2020

And how much work would it be to do something like that? (can the VM track that down itself? Or should it be included somehow?)

VM should be able to build closure over import-libraries itself - the way how I prototyped this on https://dart-review.googlesource.com/c/sdk/+/77722 seems to show that. Seems to be trivial to extract that out of that cl to pair with what you built.

Interesting question would be to see where the savings are coming from by running flutter engine/dart with '--trace-reload', '--trace-reload-verbose'(added to kDartLanguageArgs in engine/src/flutter/runtime/dart_vm.cc). Is it in reduced size of the kernel file and reduced read/transfer/write time or is it in amount of recompilation that dart vm does or somewhere else.

That would be awesome if we could manage this as a first step. Further it would be great to come up with a way to serialize/deserialize just a single method which body was updated rather than the whole library. Not sure how hard would be to use existing kernel file format for that(given that it has a rigid structure of library-class-method).

@jensjoha
Copy link
Contributor

I've got numbers...

I've found that --trace-reload-verbose gave too much output (and didn't provide actual timings) so I applied a few other patches (pasted at the bottom) and got these numbers (all in ms):

Original

  Run 1 Run 2 Run 3
Compilation 2475 2272 2254
Write dill 270 232 254
VM reload 243 276 327
Flutter reports 3799 3560 3590
Unaccounted for 811 780 755

From a verbose run I extracted this

[ +478 ms] DevFS: Sync finished
--
[        ] Synced 13.5MB.
[...]
[   +8 ms] Result: {type: Isolate [...]
[   +7 ms] Sending to VM service [...]
[   +2 ms] Result: {type: FlutterViewList [...]
[ +206 ms] Result: {type: _extensionType, method: ext.flutter.reassemble}

So that accounts for ~700 ms of the otherwise unaccounted for time.

Better compilation, same serialization

  Run 1 Run 2 Run 3
Compilation 48 41 43
Write dill 260 229 263
VM reload 283 313 316
Flutter reports 1387 1379 1467
Unaccounted for 796 796 845

A verbose run gave basically the same data as above, so would account for ~700 ms of the otherwise unaccounted for time.

Better compilation, better serialization

  Run 1 Run 2 Run 3
Compilation 50 35 36
Write dill 1 8 1
VM reload 96 125 86
Flutter reports 320 363 286
Unaccounted for 173 195 163

From a verbose run I extracted this

[   +8 ms] DevFS: Sync finished
--
[        ] Synced 0.0MB.
[...]
[  +13 ms] Result: {type: Isolate [...]
[   +6 ms] Sending to VM service [...]
[   +8 ms] Result: {type: FlutterViewList [...]
[ +126 ms] Result: {type: _extensionType, method: ext.flutter.reassemble}

So that accounts for ~160 ms of the otherwise unaccounted for time.

Further it would be great to come up with a way to serialize/deserialize just a single method which body was updated rather than the whole library. Not sure how hard would be to use existing kernel file format for that(given that it has a rigid structure of library-class-method).

From the compiler side that's probably not very likely to happen, we compile whole libraries. One could, I suppose, imagine that we could compile a whole library, find out which body had changed and then only send that, but I'm not sure that would be worth it... Also it would leave offsets in an inconsistent state for all "old" code in that library (technically only the code textually after the change, but still).

Patches applied:

diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc
index 0a63ed80d..fe1b67978 100644
--- a/runtime/dart_vm.cc
+++ b/runtime/dart_vm.cc
@@ -61,6 +61,8 @@ static const char* kDartLanguageArgs[] = {
     "--enable_mirrors=false",
     "--background_compilation",
     "--causal_async_stacks",
+    "--trace-reload",
+    // "--trace-reload-verbose",
     // clang-format on
 };

and

diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index add6b9a888..cba6f241d6 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -478,6 +478,7 @@ class FrontendCompiler implements CompilerInterface {
 
     KernelCompilationResults results;
     IncrementalSerializer incrementalSerializer;
+    Stopwatch stopwatch = new Stopwatch()..start();
     if (options['incremental']) {
       _compilerOptions.environmentDefines =
           _compilerOptions.target.updateEnvironmentDefines(environmentDefines);
@@ -493,10 +494,14 @@ class FrontendCompiler implements CompilerInterface {
           _generator.getClassHierarchy(),
           _generator.getCoreTypes(),
           component.uriToSource.keys);
+      stderr.writeln("Compiled in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
 
       incrementalSerializer = _generator.incrementalSerializer;
       _component = component;
       _component.computeCanonicalNames();
+      stderr.writeln("computed canonical names in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
     } else {
       if (options['link-platform']) {
         // TODO(aam): Remove linkedDependencies once platform is directly embedded
@@ -514,9 +519,14 @@ class FrontendCompiler implements CompilerInterface {
           environmentDefines: environmentDefines,
           enableAsserts: options['enable-asserts'],
           useProtobufTreeShaker: options['protobuf-tree-shaker']));
+
+      stderr.writeln("Non-incremental compile in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
     }
     if (results.component != null) {
       transformer?.transform(results.component);
+      stderr.writeln("(Extra) tranformer in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
 
       if (_compilerOptions.target.name == 'dartdevc') {
         await writeJavascriptBundle(
@@ -527,6 +537,9 @@ class FrontendCompiler implements CompilerInterface {
             incrementalSerializer: incrementalSerializer);
       }
 
+      stderr.writeln("Wrote dill file in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
+
       _outputStream.writeln(boundaryKey);
       await _outputDependenciesDelta(results.compiledSources);
       _outputStream
@@ -538,6 +551,8 @@ class FrontendCompiler implements CompilerInterface {
       }
 
       _kernelBinaryFilename = _kernelBinaryFilenameIncremental;
+
+      stderr.writeln("Whatever end stuff in ${stopwatch.elapsedMilliseconds} ms");
     } else
       _outputStream.writeln(boundaryKey);
     return errors.isEmpty;
@@ -832,6 +847,7 @@ class FrontendCompiler implements CompilerInterface {
 
   @override
   Future<Null> recompileDelta({String entryPoint}) async {
+    Stopwatch stopwatch = new Stopwatch()..start();
     final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     await invalidateIfInitializingFromDill();
@@ -840,9 +856,15 @@ class FrontendCompiler implements CompilerInterface {
     }
     errors.clear();
 
+    stderr.writeln("Initialized something for delta in ${stopwatch.elapsedMilliseconds} ms");
+    stopwatch.reset();
     Component deltaProgram = await _generator.compile(entryPoint: _mainSource);
+    stderr.writeln("Compiled delta in ${stopwatch.elapsedMilliseconds} ms");
+    stopwatch.reset();
     if (deltaProgram != null && transformer != null) {
       transformer.transform(deltaProgram);
+      stderr.writeln("Transformed delta in ${stopwatch.elapsedMilliseconds} ms");
+      stopwatch.reset();
     }
 
     KernelCompilationResults results = KernelCompilationResults(
@@ -859,12 +881,17 @@ class FrontendCompiler implements CompilerInterface {
       await writeDillFile(results, _kernelBinaryFilename,
           incrementalSerializer: _generator.incrementalSerializer);
     }
+    stderr.writeln("Wrote output delta in ${stopwatch.elapsedMilliseconds} ms");
+    stopwatch.reset();
 
     _outputStream.writeln(boundaryKey);
     await _outputDependenciesDelta(results.compiledSources);
     _outputStream
         .writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
     _kernelBinaryFilename = _kernelBinaryFilenameIncremental;
+
+    stderr.writeln("Final something for delta in ${stopwatch.elapsedMilliseconds} ms");
+    stopwatch.reset();
   }
 
   @override
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 5652c1a64a..aa95617f61 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -559,6 +559,10 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
                                        intptr_t kernel_buffer_size) {
   TIMELINE_SCOPE(Reload);
 
+  int64_t __timing_reload_start = OS::GetCurrentTimeMicros();
+  TIR_Print("IsolateGroupReloadContext::Reload starts: %ld\n",
+            __timing_reload_start);
+
   Thread* thread = Thread::Current();
 
   // All isolates have the same sources, so all of them have the same libraries.
@@ -612,6 +616,11 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
         did_kernel_compilation = true;
         if (error != nullptr) {
           TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
+          int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+          int64_t __timing_reload_diff =
+              __timing_reload_here - __timing_reload_start;
+          TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+                    __timing_reload_diff);
           const auto& error_str = String::Handle(Z, String::New(error));
           free(error);
           const ApiError& error = ApiError::Handle(Z, ApiError::New(error_str));
@@ -710,10 +719,18 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
       AcceptCompilation(thread);
     }
     TIR_Print("---- SKIPPING RELOAD (No libraries were modified)\n");
+    int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+    int64_t __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+    TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+              __timing_reload_diff);
     return false;
   }
 
   TIR_Print("---- STARTING RELOAD\n");
+  int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+  int64_t __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+  TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+            __timing_reload_diff);
 
   intptr_t number_of_isolates = 0;
   isolate_group_->ForEachIsolate(
@@ -794,6 +811,10 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
 
   if (load_errors > 0) {
     TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
+    int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+    int64_t __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+    TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+              __timing_reload_diff);
 
     const auto& error = Error::Cast(result);
     AddReasonForCancelling(new Aborted(Z, error));
@@ -806,6 +827,10 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
   } else {
     ASSERT(!reload_skipped_ && !reload_finalized_);
     TIR_Print("---- LOAD SUCCEEDED\n");
+    int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+    int64_t __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+    TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+              __timing_reload_diff);
 
     ForEachIsolate([&](Isolate* isolate) {
       isolate->reload_context()->ReloadPhase3FinalizeLoading();
@@ -820,6 +845,11 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
 
     if (!FLAG_reload_force_rollback && !HasReasonsForCancelling()) {
       TIR_Print("---- COMMITTING RELOAD\n");
+      int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+      int64_t __timing_reload_diff =
+          __timing_reload_here - __timing_reload_start;
+      TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+                __timing_reload_diff);
       ForEachIsolate([&](Isolate* isolate) {
         isolate->reload_context()->ReloadPhase4CommitPrepare();
       });
@@ -897,9 +927,18 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
         isolate->reload_context()->ReloadPhase4CommitFinish();
       });
       TIR_Print("---- DONE COMMIT\n");
+      __timing_reload_here = OS::GetCurrentTimeMicros();
+      __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+      TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+                __timing_reload_diff);
       isolate_group_->set_last_reload_timestamp(reload_timestamp_);
     } else {
       TIR_Print("---- ROLLING BACK");
+      int64_t __timing_reload_here = OS::GetCurrentTimeMicros();
+      int64_t __timing_reload_diff =
+          __timing_reload_here - __timing_reload_start;
+      TIR_Print("---- TIMING: %ld; diff %ld\n", __timing_reload_here,
+                __timing_reload_diff);
       DiscardSavedClassTable(/*is_rollback=*/true);
       ForEachIsolate([&](Isolate* isolate) {
         isolate->reload_context()->ReloadPhase4Rollback();
@@ -957,6 +996,11 @@ bool IsolateGroupReloadContext::Reload(bool force_reload,
     isolateIndex++;
   });
 
+  __timing_reload_here = OS::GetCurrentTimeMicros();
+  __timing_reload_diff = __timing_reload_here - __timing_reload_start;
+  TIR_Print("---- All done! TIMING: %ld; diff %ld\n", __timing_reload_here,
+            __timing_reload_diff);
+
   return success;
 }
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index d15e41eed7..fa9afda862 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6480,7 +6480,7 @@ void Function::SwitchToLazyCompiledUnoptimizedCode() const {
   ASSERT(thread->IsMutatorThread());
 
   const Code& current_code = Code::Handle(zone, CurrentCode());
-  TIR_Print("Disabling optimized code for %s\n", ToCString());
+  // TIR_Print("Disabling optimized code for %s\n", ToCString());
   current_code.DisableDartCode();
 
   const Code& unopt_code = Code::Handle(zone, unoptimized_code());
@@ -6496,7 +6496,7 @@ void Function::SwitchToLazyCompiledUnoptimizedCode() const {
     return;
   }
 
-  TIR_Print("Switched to unoptimized code for %s\n", ToCString());
+  // TIR_Print("Switched to unoptimized code for %s\n", ToCString());
 
   AttachCode(unopt_code);
   unopt_code.Enable();
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index b3c70c1112..a8e2f2a189 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -304,7 +304,7 @@ void Class::CopyCanonicalConstants(const Class& old_cls) const {
   if (old_constants.IsNull() || old_constants.Length() == 0) {
     return;
   }
-  TIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
+  VTIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
             old_constants.Length(), ToCString());
   set_constants(old_constants);
 }
@@ -733,7 +733,7 @@ void Class::CheckReload(const Class& replacement,
       return;  // No reason to check other properties.
     }
     ASSERT(replacement.is_finalized());
-    TIR_Print("Finalized replacement class for %s\n", ToCString());
+    VTIR_Print("Finalized replacement class for %s\n", ToCString());
   }
 
   if (is_finalized() && is_const() && (constants() != Array::null()) &&
@@ -801,7 +801,7 @@ void Class::CheckReload(const Class& replacement,
   if (is_prefinalized()) {
     if (!CanReloadPreFinalized(replacement, context)) return;
   }
-  TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n", ToCString(),
+  VTIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n", ToCString(),
             id(), replacement.id());
 }

dart-bot pushed a commit that referenced this issue Apr 28, 2020
The idea behind this is that the incremental compiler can now
(currently experimentally) recompile less if the outline didn't change.
This also mean that it can output less (e.g. only the changed library).
This change should make sure that the VM still invalidates everything
it needs to.

See also:
#34001
https://dart-review.googlesource.com/c/sdk/+/77722

Change-Id: I8d04bb86d2a27dd2706ec83f53fa98453eb41ce1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144299
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
dart-bot pushed a commit that referenced this issue Apr 28, 2020
This reverts commit 8e90d2b.

Reason for revert: Causes test failures on reload/reload-rollback bots.

Original change's description:
> [VM] Mark all indirectly dependent code dirty on hot reload
> 
> The idea behind this is that the incremental compiler can now
> (currently experimentally) recompile less if the outline didn't change.
> This also mean that it can output less (e.g. only the changed library).
> This change should make sure that the VM still invalidates everything
> it needs to.
> 
> See also:
> #34001
> https://dart-review.googlesource.com/c/sdk/+/77722
> 
> Change-Id: I8d04bb86d2a27dd2706ec83f53fa98453eb41ce1
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144299
> Commit-Queue: Jens Johansen <jensj@google.com>
> Reviewed-by: Alexander Aprelev <aam@google.com>
> Reviewed-by: Ryan Macnak <rmacnak@google.com>

TBR=kustermann@google.com,aam@google.com,rmacnak@google.com,jensj@google.com

Change-Id: I5158447943c5dab18f4ed433f3709e6ee403606a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144822
Reviewed-by: Tess Strickland <sstrickl@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
dart-bot pushed a commit that referenced this issue Apr 30, 2020
The idea behind this is that the incremental compiler can now
(currently experimentally) recompile less if the outline didn't change.
This also mean that it can output less (e.g. only the changed library).
This change should make sure that the VM still invalidates everything
it needs to.

See also:
#34001
https://dart-review.googlesource.com/c/sdk/+/77722

This reverts commit 4305061
(and fixed the issue).

Change-Id: I0815635eff6df76edf95de686aefd1800e0a8a0a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144824
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
@aam aam closed this as completed May 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. vm-hot-reload
Projects
None yet
Development

No branches or pull requests

2 participants