[dart2js] add helper script for faster iteration.
This script calls dart2js repeatedly with the same arguments, but
triggers a hot reload on every run (initiated by entering a new line
on stdin).
Change-Id: Ibdad8ad06c92de7e9b9c23a48e8ce5747ef426c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322570
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
diff --git a/pkg/compiler/tool/hot_reload_launcher.dart b/pkg/compiler/tool/hot_reload_launcher.dart
new file mode 100644
index 0000000..c16c595
--- /dev/null
+++ b/pkg/compiler/tool/hot_reload_launcher.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Helper script to run keep dart2js in memory and trigger a hot-reload between
+/// runs. This can speed up iterating on compiler changes, while still working
+/// with the compiler sources.
+///
+/// Usage: launch with a special VM flag to enable the vm service, which adds
+/// the necessary mechanism to support hot reloads, and passing all arguments
+/// that will be forwarded to dart2js:
+///
+/// ```
+/// out/ReleaseX64/dart --disable-dart-dev --enable-vm-service \
+/// pkg/compiler/tool/hot_reload_launcher.dart <dart2js-args>
+/// ```
+///
+/// This will do one compile immediately. After it completes, the process will
+/// wait for additional input. On every new-line entered (text is ignored), it
+/// will trigger a hot reload to refresh the compiler, then reexecute the
+/// compiler with the exact same args provided upfront.
+import 'dart:developer';
+import 'package:vm_service/vm_service_io.dart' as vm_service_io;
+
+import 'dart:io' as io;
+
+import 'package:compiler/src/dart2js.dart' as p;
+
+int iteration = 0;
+
+main(List<String> args) async {
+ try {
+ if (io.Platform.isLinux) {
+ // Calculate how long it took for the process to reach main, this gives us
+ // an estimate of how long it takes to compile dart2js and load it.
+ final result = io.Process.runSync(
+ 'ps', ['--pid', '${io.pid}', '-D', '%F %T', '-o', 'lstart=']);
+ final startTimeString = (result.stdout as String).trim();
+ final startTime = DateTime.parse(startTimeString);
+ final currentTime = DateTime.now();
+ final diff = currentTime.difference(startTime).inMilliseconds;
+ print('${'--' * 20} (compiler loaded: ${diff}ms)');
+ }
+ } catch (e) {
+ print('Warning: couldn\'t compute load time [$e]');
+ }
+ final info =
+ await Service.controlWebServer(enable: true, silenceOutput: true);
+ final observatoryUri = info.serverUri;
+ if (observatoryUri == null) {
+ print('Error: VM service not found. Make sure to invoke the '
+ 'Dart VM with the `--enable-vm-service` flag');
+ io.exit(1);
+ }
+ final wsUri = 'ws://${observatoryUri.authority}${observatoryUri.path}ws';
+ final vmService = await vm_service_io.vmServiceConnectUri(wsUri);
+ final vm = await vmService.getVM();
+ final id =
+ vm.isolates!.firstWhere((isolate) => !isolate.isSystemIsolate!).id!;
+
+ // Override exitFunc to prevent the defualt behavior (a process exit).
+ p.exitFunc = (code) {
+ throw "Exit with code $code";
+ };
+
+ Stopwatch watch = Stopwatch()..start();
+ while (true) {
+ print('${'--' * 20} (iteration: $iteration, '
+ 'rebuild time: ${watch.elapsedMilliseconds}ms)');
+ iteration++;
+ try {
+ await p.compilerMain(args);
+ } catch (e, s) {
+ print('$e\n$s');
+ }
+ print('${'--' * 20} (done, please <enter> to compile again) ');
+ var line = io.stdin.readLineSync();
+ if (line == null) break;
+ watch.reset();
+ vmService.reloadSources(id);
+ }
+}