From 157ebfe50f399c59a20d603acdf5143ceaa4cccf Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 21 Jul 2020 16:23:18 +0000 Subject: [PATCH] Reland "[ VM / DartDev ] Launch DartDev in an isolate within a single main Dart process" This reverts commit 7e373831ceb4dd0c57fb06e1a6f3e9c4fd5e01c8. Change-Id: Ib94d793a5753ec6352cd9a65e35f726a63336368 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154830 Reviewed-by: Siva Annamalai --- BUILD.gn | 23 +- pkg/dartdev/bin/dartdev.dart | 14 +- pkg/dartdev/lib/dartdev.dart | 26 +- pkg/dartdev/lib/src/commands/analyze.dart | 2 +- pkg/dartdev/lib/src/commands/run.dart | 254 +++-------------- pkg/dartdev/lib/src/sdk.dart | 3 + pkg/dartdev/lib/src/vm_interop_handler.dart | 40 +++ pkg/dartdev/test/commands/flag_test.dart | 40 ++- pkg/dartdev/test/utils.dart | 2 - pkg/dds/bin/dds.dart | 18 ++ pkg/dds/lib/src/client_manager.dart | 14 + pkg/dds/lib/src/isolate_manager.dart | 1 - pkg/dds/lib/src/stream_manager.dart | 25 +- pkg/front_end/test/hot_reload_e2e_test.dart | 4 + .../test/incremental_compiler_leak_test.dart | 1 + .../test/spell_checking_list_tests.txt | 3 + pkg/vm/test/incremental_compiler_test.dart | 4 + runtime/bin/BUILD.gn | 2 + runtime/bin/builtin_impl_sources.gni | 2 - runtime/bin/dartdev_isolate.cc | 262 ++++++++++++++++++ runtime/bin/dartdev_isolate.h | 99 +++++++ runtime/bin/dartdev_utils.cc | 53 ---- runtime/bin/dartdev_utils.h | 32 --- runtime/bin/dartutils.cc | 25 +- runtime/bin/dartutils.h | 4 + runtime/bin/main.cc | 138 +++++---- runtime/bin/main_options.cc | 172 +++++------- runtime/observatory/lib/service_html.dart | 6 +- runtime/vm/service.cc | 3 + sdk/BUILD.gn | 9 + .../_internal/vm/bin/vmservice_server.dart | 27 ++ .../regress_41329_absolute_test.dart | 2 - .../regress_41329_relative_test.dart | 2 - .../regress_41329_absolute_test.dart | 2 - .../regress_41329_relative_test.dart | 2 - utils/dartdev/BUILD.gn | 10 +- utils/dds/BUILD.gn | 30 ++ 37 files changed, 838 insertions(+), 518 deletions(-) create mode 100644 pkg/dartdev/lib/src/vm_interop_handler.dart create mode 100644 pkg/dds/bin/dds.dart create mode 100644 runtime/bin/dartdev_isolate.cc create mode 100644 runtime/bin/dartdev_isolate.h delete mode 100644 runtime/bin/dartdev_utils.cc delete mode 100644 runtime/bin/dartdev_utils.h create mode 100644 utils/dds/BUILD.gn diff --git a/BUILD.gn b/BUILD.gn index 88dc2ca83a2..41563a1b3d0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -61,7 +61,10 @@ group("runtime") { # TODO(bkonyi): this dep causes a segfault on Android XARM_X64 builds. # See issue #41776. if (dart_target_arch != "arm") { - deps += [ "utils/dartdev:dartdev" ] + deps += [ + "utils/dartdev:dartdev", + "utils/dds:dds", + ] } } @@ -159,9 +162,7 @@ if (is_fuchsia) { data_deps = [ "runtime/bin:dart" ] manifest = "build/fuchsia/dart.cmx" - resource_files = [ - ".packages", - ] + resource_files = [ ".packages" ] resource_dirs = [ "tests/standalone", "pkg/async_helper", @@ -178,13 +179,15 @@ if (is_fuchsia) { resources = [] foreach(file, resource_files) { - resources += [{ - path = file - dest = "data/" + file - }] + resources += [ + { + path = file + dest = "data/" + file + }, + ] } - resources += exec_script( - "tools/fuchsia/find_resources.py", resource_dirs, "json") + resources += + exec_script("tools/fuchsia/find_resources.py", resource_dirs, "json") } fuchsia_package("dart_sdk_fuchsia_test_package") { diff --git a/pkg/dartdev/bin/dartdev.dart b/pkg/dartdev/bin/dartdev.dart index 1a314e6081a..4e0f939a5b8 100644 --- a/pkg/dartdev/bin/dartdev.dart +++ b/pkg/dartdev/bin/dartdev.dart @@ -2,18 +2,12 @@ // 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. -import 'dart:io'; +import 'dart:async'; +import 'dart:isolate'; import 'package:dartdev/dartdev.dart'; -import 'package:pedantic/pedantic.dart' show unawaited; /// The entry point for dartdev. -Future main(List args) async { - // Ignore SIGINT to ensure DartDev doesn't exit before any of its - // spawned children. Draining the stream returned by watch() effectively - // sends the signals to the void. - // - // See https://github.com/dart-lang/sdk/issues/42092 for context. - unawaited(ProcessSignal.sigint.watch().drain()); - await runDartdev(args); +Future main(List args, SendPort port) async { + await runDartdev(args, port); } diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart index 86494c7bd02..b21d5abcd17 100644 --- a/pkg/dartdev/lib/dartdev.dart +++ b/pkg/dartdev/lib/dartdev.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:io' as io; +import 'dart:isolate'; import 'package:analyzer/src/dart/analysis/experiments.dart'; import 'package:args/args.dart'; @@ -21,11 +22,13 @@ import 'src/commands/run.dart'; import 'src/commands/test.dart'; import 'src/core.dart'; import 'src/experiments.dart'; +import 'src/vm_interop_handler.dart'; /// This is typically called from bin/, but given the length of the method and /// analytics logic, it has been moved here. Also note that this method calls /// [io.exit(code)] directly. -Future runDartdev(List args) async { +Future runDartdev(List args, SendPort port) async { + VmInteropHandler.initialize(port); final stopwatch = Stopwatch(); int result; @@ -68,6 +71,12 @@ Future runDartdev(List args) async { io.exit(0); } + // --launch-dds is provided by the VM if the VM service is to be enabled. In + // that case, we need to launch DDS as well. + // TODO(bkonyi): add support for pub run (#42726) + if (args.contains('--launch-dds')) { + RunCommand.launchDds = true; + } String commandName; try { @@ -79,6 +88,12 @@ Future runDartdev(List args) async { args = List.from(args)..remove('--disable-dartdev-analytics'); } + // Run also can't be called with '--launch-dds', remove it if it's + // contained in args. + if (args.contains('--launch-dds')) { + args = List.from(args)..remove('--launch-dds'); + } + // Before calling to run, send the first ping to analytics to have the first // ping, as well as the command itself, running in parallel. if (analytics.enabled) { @@ -133,7 +148,7 @@ Future runDartdev(List args) async { analytics.enabled = true; } analytics.close(); - io.exit(exitCode); + VmInteropHandler.exit(exitCode); } } @@ -166,6 +181,11 @@ class DartdevRunner extends CommandRunner { help: 'Disable anonymous analytics for this `dart *` run', hide: true); + // Another hidden flag used by the VM to indicate that DDS should be + // launched. Should be removed for all commands other than `run`. + argParser.addFlag('launch-dds', + negatable: false, hide: true, help: 'Launch DDS.'); + addCommand(AnalyzeCommand()); addCommand(CreateCommand(verbose: verbose)); addCommand(CompileCommand()); @@ -192,7 +212,7 @@ class DartdevRunner extends CommandRunner { io.stderr.writeln( "Error when reading '$firstArg': No such file or directory."); // This is the exit code used by the frontend. - io.exit(254); + VmInteropHandler.exit(254); } } diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart index 57d83a5aa43..e78e8811830 100644 --- a/pkg/dartdev/lib/src/commands/analyze.dart +++ b/pkg/dartdev/lib/src/commands/analyze.dart @@ -73,7 +73,7 @@ class AnalyzeCommand extends DartdevCommand { }); await analysisCompleter.future; - + await server.dispose(); progress.finish(showTiming: true); errors.sort(); diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart index 6ba76e09fa8..96493774de6 100644 --- a/pkg/dartdev/lib/src/commands/run.dart +++ b/pkg/dartdev/lib/src/commands/run.dart @@ -4,18 +4,20 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:args/args.dart'; -import 'package:dds/dds.dart'; import 'package:path/path.dart'; import '../core.dart'; import '../experiments.dart'; import '../sdk.dart'; import '../utils.dart'; +import '../vm_interop_handler.dart'; class RunCommand extends DartdevCommand { + static bool launchDds = false; @override final ArgParser argParser = ArgParser.allowAnything(); @@ -60,21 +62,19 @@ Run a Dart file.'''); // The command line arguments after 'run' var args = argResults.arguments.toList(); - var argsContainFileOrHelp = false; + var argsContainFile = false; for (var arg in args) { // The arg.contains('.') matches a file name pattern, i.e. some 'foo.dart' - if (arg.contains('.') || - arg == '--help' || - arg == '-h' || - arg == 'help') { - argsContainFileOrHelp = true; - break; + if (arg.contains('.')) { + argsContainFile = true; + } else if (arg == '--help' || arg == '-h' || arg == 'help') { + printUsage(); + return 0; } } final cwd = Directory.current; - - if (!argsContainFileOrHelp && cwd.existsSync()) { + if (!argsContainFile && cwd.existsSync()) { var foundImplicitFileToRun = false; var cwdName = cwd.name; for (var entity in cwd.listSync(followLinks: false)) { @@ -100,6 +100,8 @@ Run a Dart file.'''); 'Could not find the implicit file to run: ' 'bin$separator$cwdName.dart.', ); + // Error exit code, as defined in runtime/bin/error_exit.h + return 255; } } @@ -117,213 +119,43 @@ Run a Dart file.'''); // service intermediary which implements the VM service protocol and // provides non-VM specific extensions (e.g., log caching, client // synchronization). - if (args.any((element) => - element.startsWith('--observe') || - element.startsWith('--enable-vm-service'))) { - return await _DebuggingSession(this, args).start(); - } else { - // Starting in ProcessStartMode.inheritStdio mode means the child process - // can detect support for ansi chars. - final process = await Process.start( - sdk.dart, ['--disable-dart-dev', ...args], - mode: ProcessStartMode.inheritStdio); - return process.exitCode; + _DebuggingSession debugSession; + if (launchDds) { + debugSession = _DebuggingSession(); + await debugSession.start(); } + + final script = Directory.current.uri + .resolve(args.firstWhere((e) => !e.startsWith('-'))) + .toFilePath(); + final runArgs = args.length == 1 ? [] : args.sublist(1); + VmInteropHandler.run(script, runArgs); + return 0; } } class _DebuggingSession { - _DebuggingSession(this._runCommand, List args) - : _args = args.toList() { - // Process flags that are meant to configure the VM service HTTP server or - // dump VM service connection information to a file. Since the VM service - // clients won't actually be connecting directly to the service, we'll make - // DDS appear as if it is the actual VM service. - for (final arg in _args) { - final isObserve = arg.startsWith('--observe'); - if (isObserve || arg.startsWith('--enable-vm-service')) { - if (isObserve) { - _observe = true; - } - if (arg.contains('=') || arg.contains(':')) { - // These flags can be provided by the embedder so we need to check for - // both `=` and `:` separators. - final observatoryBindInfo = - (arg.contains('=') ? arg.split('=') : arg.split(':'))[1] - .split('/'); - _port = int.tryParse(observatoryBindInfo.first) ?? 0; - if (observatoryBindInfo.length > 1) { - try { - _bindAddress = Uri.http(observatoryBindInfo[1], ''); - } on FormatException { - // TODO(bkonyi): log invalid parse? The VM service just ignores - // bad input flags. - // Ignore. - } - } - } - } else if (arg.startsWith('--write-service-info=')) { - try { - final split = arg.split('='); - if (split[1].isNotEmpty) { - _serviceInfoUri = Uri.parse(split[1]); - } else { - _runCommand.usageException( - 'Invalid URI argument to --write-service-info: "${split[1]}"'); - } - } on FormatException { - // TODO(bkonyi): log invalid parse? The VM service just ignores bad - // input flags. - // Ignore. - } - } else if (arg == '--disable-service-auth-codes') { - _disableServiceAuthCodes = true; + Future start() async { + final serviceInfo = await Service.getInfo(); + final process = await Process.start( + sdk.dart, + [ + if (dirname(sdk.dart).endsWith('bin')) + sdk.ddsSnapshot + else + absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'), + serviceInfo.serverUri.toString() + ], + mode: ProcessStartMode.detachedWithStdio); + final completer = Completer(); + StreamSubscription sub; + sub = process.stderr.transform(utf8.decoder).listen((event) { + if (event == 'DDS started') { + sub.cancel(); + completer.complete(); } - } - - // Strip --observe and --write-service-info from the arguments as we'll be - // providing our own. - _args.removeWhere( - (arg) => - arg.startsWith('--observe') || - arg.startsWith('--enable-vm-service') || - arg.startsWith('--write-service-info'), - ); - } - - FutureOr start() async { - // Output the service information for the target process to a temporary - // file so we can avoid scraping stderr for the service URI. - final serviceInfoDir = - await Directory.systemTemp.createTemp('dart_service'); - final serviceInfoUri = serviceInfoDir.uri.resolve('service_info.json'); - final serviceInfoFile = await File.fromUri(serviceInfoUri).create(); - - // Start using ProcessStartMode.normal and forward stdio manually as we - // need to filter the true VM service URI and replace it with the DDS URI. - _process = await Process.start( - sdk.dart, - [ - '--disable-dart-dev', - // We don't care which port the VM service binds to. - _observe ? '--observe=0' : '--enable-vm-service=0', - '--write-service-info=$serviceInfoUri', - ..._args, - ], - ); - _forwardAndFilterStdio(_process); - - // Start DDS once the VM service has finished starting up. - await Future.any([ - _waitForRemoteServiceUri(serviceInfoFile).then(_startDDS), - _process.exitCode, - ]); - - return _process.exitCode.then((exitCode) async { - // Shutdown DDS if it was started and wait for the process' stdio streams - // to close so we don't truncate program output. - await Future.wait([ - if (_dds != null) _dds.shutdown(), - _stderrDone, - _stdoutDone, - ]); - return exitCode; }); + + await completer.future; } - - Future _waitForRemoteServiceUri(File serviceInfoFile) async { - // Wait for VM service to write its connection info to disk. - while (await serviceInfoFile.length() <= 5) { - await Future.delayed(const Duration(milliseconds: 50)); - } - final serviceInfoStr = await serviceInfoFile.readAsString(); - return Uri.parse(jsonDecode(serviceInfoStr)['uri']); - } - - Future _startDDS(Uri remoteVmServiceUri) async { - _dds = await DartDevelopmentService.startDartDevelopmentService( - remoteVmServiceUri, - serviceUri: _bindAddress.replace(port: _port), - enableAuthCodes: !_disableServiceAuthCodes, - ); - if (_serviceInfoUri != null) { - // Output the service connection information. - await File.fromUri(_serviceInfoUri).writeAsString( - json.encode({ - 'uri': _dds.uri.toString(), - }), - ); - } - _ddsCompleter.complete(); - } - - void _forwardAndFilterStdio(Process process) { - // Since VM service clients cannot connect to the real VM service once DDS - // has started, replace all instances of the real VM service's URI with the - // DDS URI. Clients should only know that they are connected to DDS if they - // explicitly request that information via the protocol. - String filterObservatoryUri(String msg) { - if (_dds == null) { - return msg; - } - if (msg.contains('Observatory listening on') || - msg.contains('Connect to Observatory at')) { - // Search for the VM service URI in the message and replace it. - msg = msg.replaceFirst( - RegExp(r'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.' - r'[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)'), - _dds.uri.toString(), - ); - } - return msg; - } - - // Wait for DDS to start before handling any stdio events from the target - // to ensure we don't let any unfiltered messages slip through. - // TODO(bkonyi): consider filtering on bytes rather than decoding the UTF8. - _stderrDone = process.stderr - .transform(const Utf8Decoder(allowMalformed: true)) - .listen((event) async { - await _waitForDDS(); - stderr.write(filterObservatoryUri(event)); - }).asFuture(); - - _stdoutDone = process.stdout - .transform(const Utf8Decoder(allowMalformed: true)) - .listen((event) async { - await _waitForDDS(); - stdout.write(filterObservatoryUri(event)); - }).asFuture(); - - stdin.listen( - (event) async { - await _waitForDDS(); - process.stdin.add(event); - }, - ); - } - - Future _waitForDDS() async { - if (!_ddsCompleter.isCompleted) { - // No need to wait for DDS if the process has already exited. - await Future.any([ - _ddsCompleter.future, - _process.exitCode, - ]); - } - } - - Uri _bindAddress = Uri.http('127.0.0.1', ''); - bool _disableServiceAuthCodes = false; - DartDevelopmentService _dds; - bool _observe = false; - int _port = 8181; - Process _process; - Uri _serviceInfoUri; - Future _stderrDone; - Future _stdoutDone; - - final List _args; - final Completer _ddsCompleter = Completer(); - final RunCommand _runCommand; } diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart index 8481714d327..537089fbe11 100644 --- a/pkg/dartdev/lib/src/sdk.dart +++ b/pkg/dartdev/lib/src/sdk.dart @@ -52,6 +52,9 @@ class Sdk { String get dartfmt => path.absolute(sdkPath, 'bin', _binName('dartfmt')); + String get ddsSnapshot => + path.absolute(sdkPath, 'bin', 'snapshots', 'dds.dart.snapshot'); + String get pub => path.absolute(sdkPath, 'bin', _binName('pub')); static String _binName(String base) => diff --git a/pkg/dartdev/lib/src/vm_interop_handler.dart b/pkg/dartdev/lib/src/vm_interop_handler.dart new file mode 100644 index 00000000000..3a8fea97f24 --- /dev/null +++ b/pkg/dartdev/lib/src/vm_interop_handler.dart @@ -0,0 +1,40 @@ +// Copyright (c) 2020, 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. + +import 'dart:isolate'; + +/// Contains methods used to communicate DartDev results back to the VM. +abstract class VmInteropHandler { + /// Initializes [VmInteropHandler] to utilize [port] to communicate with the + /// VM. + static void initialize(SendPort port) => _port = port; + + /// Notifies the VM to run [script] with [args] upon DartDev exit. + static void run(String script, List args) { + assert(_port != null); + if (_port == null) return; + final message = List.filled(3, null) + ..[0] = _kResultRun + ..[1] = script + ..[2] = args; + _port.send(message); + } + + /// Notifies the VM that DartDev has completed running. If provided a + /// non-zero [exitCode], the VM will terminate with the given exit code. + static void exit(int exitCode) { + assert(_port != null); + if (_port == null) return; + final message = List.filled(2, null) + ..[0] = _kResultExit + ..[1] = exitCode; + _port.send(message); + } + + // Note: keep in sync with runtime/bin/dartdev_isolate.h + static const int _kResultRun = 1; + static const int _kResultExit = 2; + + static SendPort _port; +} diff --git a/pkg/dartdev/test/commands/flag_test.dart b/pkg/dartdev/test/commands/flag_test.dart index 748240f5e25..90a904086d8 100644 --- a/pkg/dartdev/test/commands/flag_test.dart +++ b/pkg/dartdev/test/commands/flag_test.dart @@ -79,13 +79,51 @@ void help() { var result = p.runSync('--help', ['--verbose']); expect(result.exitCode, 0); - expect(result.stdout, contains('migrate ')); + expect(result.stdout, isEmpty); + expect(result.stderr, + contains('The following options are only used for VM development')); }); test('--help -v', () { p = project(); var result = p.runSync('--help', ['-v']); + expect(result.exitCode, 0); + expect(result.stdout, isEmpty); + expect(result.stderr, + contains('The following options are only used for VM development')); + }); + + test('help', () { + p = project(); + var result = p.runSync('help', []); + + expect(result.exitCode, 0); + expect(result.stderr, isEmpty); + expect(result.stdout, contains(DartdevRunner.dartdevDescription)); + expect(result.stdout, + contains('Usage: dart [] []')); + expect(result.stdout, contains('Global options:')); + expect(result.stdout, contains('Available commands:')); + expect(result.stdout, contains('analyze ')); + expect(result.stdout, contains('create ')); + expect(result.stdout, contains('compile ')); + expect(result.stdout, contains('format ')); + expect(result.stdout, contains('migrate ')); + }); + + test('help --verbose', () { + p = project(); + var result = p.runSync('help', ['--verbose']); + + expect(result.exitCode, 0); + expect(result.stdout, contains('migrate ')); + }); + + test('help -v', () { + p = project(); + var result = p.runSync('help', ['-v']); + expect(result.exitCode, 0); expect(result.stdout, contains('migrate ')); }); diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart index 7fd5c7361d5..513f2dc1d5b 100644 --- a/pkg/dartdev/test/utils.dart +++ b/pkg/dartdev/test/utils.dart @@ -55,7 +55,6 @@ class TestProject { String workingDir, }) { var arguments = [ - absolutePathToDartdevFile, command, if (command == 'migrate') // TODO(srawlins): Enable `pub outdated` in tests. @@ -64,7 +63,6 @@ class TestProject { ]; arguments.add('--disable-dartdev-analytics'); - return Process.runSync( Platform.resolvedExecutable, arguments, diff --git a/pkg/dds/bin/dds.dart b/pkg/dds/bin/dds.dart new file mode 100644 index 00000000000..476e84b4a82 --- /dev/null +++ b/pkg/dds/bin/dds.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2020, 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. + +import 'dart:io'; + +import 'package:dds/dds.dart'; + +/// A simple program which starts a [DartDevelopmentService] instance with a +/// basic configuration. +/// +/// Takes the VM service URI as its single argument. +Future main(List args) async { + if (args.isEmpty) return; + final remoteVmServiceUri = Uri.parse(args.first); + await DartDevelopmentService.startDartDevelopmentService(remoteVmServiceUri); + stderr.write('DDS started'); +} diff --git a/pkg/dds/lib/src/client_manager.dart b/pkg/dds/lib/src/client_manager.dart index 8527636096a..43040006283 100644 --- a/pkg/dds/lib/src/client_manager.dart +++ b/pkg/dds/lib/src/client_manager.dart @@ -30,12 +30,26 @@ class _ClientManager { ); clients.add(client); client.listen().then((_) => removeClient(client)); + if (clients.length == 1) { + dds.isolateManager.initialize().then((_) { + dds.streamManager.streamListen( + null, + _StreamManager.kDebugStream, + ); + }); + } } /// Cleanup state for a disconnected client. void removeClient(_DartDevelopmentServiceClient client) { _clearClientName(client); clients.remove(client); + if (clients.isEmpty) { + dds.streamManager.streamCancel( + null, + _StreamManager.kDebugStream, + ); + } } /// Cleanup clients on DDS shutdown. diff --git a/pkg/dds/lib/src/isolate_manager.dart b/pkg/dds/lib/src/isolate_manager.dart index 1ebc9f7c794..f7fec895cff 100644 --- a/pkg/dds/lib/src/isolate_manager.dart +++ b/pkg/dds/lib/src/isolate_manager.dart @@ -85,7 +85,6 @@ class _RunningIsolate { if (_resumeApprovalsByName.isEmpty) { return false; } - // If all the required approvals are present, we should resume. return _resumeApprovalsByName.containsAll(requiredClientApprovals); } diff --git a/pkg/dds/lib/src/stream_manager.dart b/pkg/dds/lib/src/stream_manager.dart index ea8aeaa9ad2..57048956480 100644 --- a/pkg/dds/lib/src/stream_manager.dart +++ b/pkg/dds/lib/src/stream_manager.dart @@ -117,12 +117,15 @@ class _StreamManager { ) async { assert(stream != null && stream.isNotEmpty); if (!streamListeners.containsKey(stream)) { - // This will return an RPC exception if the stream doesn't exist. This - // will throw and the exception will be forwarded to the client. - final result = await dds._vmServiceClient.sendRequest('streamListen', { - 'streamId': stream, - }); - assert(result['type'] == 'Success'); + if ((stream == kDebugStream && client == null) || + stream != kDebugStream) { + // This will return an RPC exception if the stream doesn't exist. This + // will throw and the exception will be forwarded to the client. + final result = await dds._vmServiceClient.sendRequest('streamListen', { + 'streamId': stream, + }); + assert(result['type'] == 'Success'); + } streamListeners[stream] = <_DartDevelopmentServiceClient>[]; } if (streamListeners[stream].contains(client)) { @@ -142,16 +145,18 @@ class _StreamManager { /// send a `streamCancel` request for `stream` to the VM service. Future streamCancel( _DartDevelopmentServiceClient client, - String stream, - ) async { + String stream, { + bool cancelCoreStream = false, + }) async { assert(stream != null && stream.isNotEmpty); final listeners = streamListeners[stream]; - if (listeners == null || !listeners.contains(client)) { + if (client != null && (listeners == null || !listeners.contains(client))) { throw kStreamNotSubscribedException; } listeners.remove(client); // Don't cancel streams DDS needs to function. - if (listeners.isEmpty && !ddsCoreStreams.contains(stream)) { + if (listeners.isEmpty && + (!ddsCoreStreams.contains(stream) || cancelCoreStream)) { streamListeners.remove(stream); // Ensure the VM service hasn't shutdown. if (dds._vmServiceClient.isClosed) { diff --git a/pkg/front_end/test/hot_reload_e2e_test.dart b/pkg/front_end/test/hot_reload_e2e_test.dart index d58ec7fd9e3..939d3a077bc 100644 --- a/pkg/front_end/test/hot_reload_e2e_test.dart +++ b/pkg/front_end/test/hot_reload_e2e_test.dart @@ -103,6 +103,10 @@ abstract class TestCase { '--enable-vm-service=0', // Note: use 0 to avoid port collisions. '--pause_isolates_on_start', '--disable-service-auth-codes', + // TODO(bkonyi): The service isolate starts before DartDev has a chance + // to spawn DDS. We should suppress the Observatory message until DDS + // starts (#42727). + '--disable-dart-dev', outputUri.toFilePath() ]; vmArgs.add('$reloadCount'); diff --git a/pkg/front_end/test/incremental_compiler_leak_test.dart b/pkg/front_end/test/incremental_compiler_leak_test.dart index 03f68dd2e5d..326c2e2fa8c 100644 --- a/pkg/front_end/test/incremental_compiler_leak_test.dart +++ b/pkg/front_end/test/incremental_compiler_leak_test.dart @@ -13,6 +13,7 @@ main(List args) async { LeakFinder heapHelper = new LeakFinder(); heapHelper.start([ + "--disable-dart-dev", "--enable-asserts", Platform.script.resolve("incremental_dart2js_tester.dart").toString(), "--addDebugBreaks", diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt index f0572ddd62e..52494a6c17d 100644 --- a/pkg/front_end/test/spell_checking_list_tests.txt +++ b/pkg/front_end/test/spell_checking_list_tests.txt @@ -56,6 +56,7 @@ benchmark besides beta bigger +bkonyi blah blindly blocked @@ -129,6 +130,7 @@ dash dashes day db +dds debugger decrease decrements @@ -502,6 +504,7 @@ slight smoke somehow spans +spawn spell spellcheck spelled diff --git a/pkg/vm/test/incremental_compiler_test.dart b/pkg/vm/test/incremental_compiler_test.dart index f65ffa6a93f..59416a2f60e 100644 --- a/pkg/vm/test/incremental_compiler_test.dart +++ b/pkg/vm/test/incremental_compiler_test.dart @@ -453,6 +453,7 @@ main() { "--pause-isolates-on-exit", "--enable-vm-service:0", "--disable-service-auth-codes", + "--disable-dart-dev", list.path ]); @@ -579,6 +580,7 @@ main() { "--pause-isolates-on-exit", "--enable-vm-service:0", "--disable-service-auth-codes", + "--disable-dart-dev", list.path ]); @@ -658,6 +660,7 @@ main() { '--enable-vm-service=0', // Note: use 0 to avoid port collisions. '--pause_isolates_on_start', '--disable-service-auth-codes', + '--disable-dart-dev', outputFile.path ]; final vm = await Process.start(Platform.resolvedExecutable, vmArgs); @@ -917,6 +920,7 @@ main() { "--pause-isolates-on-start", "--enable-vm-service:0", "--disable-service-auth-codes", + "--disable-dart-dev", scriptOrDill.path ]); diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn index 09b5bd3f414..609fa4210e4 100644 --- a/runtime/bin/BUILD.gn +++ b/runtime/bin/BUILD.gn @@ -878,6 +878,8 @@ dart_executable("dart") { } extra_sources = [ "builtin.cc", + "dartdev_isolate.cc", + "dartdev_isolate.h", "dfe.cc", "dfe.h", "gzip.cc", diff --git a/runtime/bin/builtin_impl_sources.gni b/runtime/bin/builtin_impl_sources.gni index fe0251fde2d..90790d3682b 100644 --- a/runtime/bin/builtin_impl_sources.gni +++ b/runtime/bin/builtin_impl_sources.gni @@ -15,8 +15,6 @@ builtin_impl_sources = [ "crypto_linux.cc", "crypto_macos.cc", "crypto_win.cc", - "dartdev_utils.cc", - "dartdev_utils.h", "dartutils.cc", "dartutils.h", "directory.cc", diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc new file mode 100644 index 00000000000..f87dc6fac72 --- /dev/null +++ b/runtime/bin/dartdev_isolate.cc @@ -0,0 +1,262 @@ +// Copyright (c) 2020, 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. + +#include "bin/dartdev_isolate.h" + +#if !defined(DART_PRECOMPILED_RUNTIME) + +#include +#include + +#include "bin/directory.h" +#include "bin/error_exit.h" +#include "bin/exe_utils.h" +#include "bin/file.h" +#include "bin/lockers.h" +#include "bin/platform.h" +#include "bin/process.h" +#include "include/dart_embedder_api.h" +#include "platform/utils.h" + +#define CHECK_RESULT(result) \ + if (Dart_IsError(result)) { \ + ProcessError(Dart_GetError(result), kErrorExitCode); \ + if (send_port_id != ILLEGAL_PORT) { \ + Dart_CloseNativePort(send_port_id); \ + } \ + Dart_ExitScope(); \ + Dart_ExitIsolate(); \ + return; \ + } + +namespace dart { +namespace bin { + +DartDevIsolate::DartDevRunner DartDevIsolate::runner_ = + DartDevIsolate::DartDevRunner(); +bool DartDevIsolate::should_run_dart_dev_ = false; +Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor(); +DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ = + DartDevIsolate::DartDev_Result_Unknown; +char** DartDevIsolate::DartDevRunner::script_ = nullptr; +std::unique_ptr + DartDevIsolate::DartDevRunner::argv_ = + std::unique_ptr(nullptr, [](char**) {}); +intptr_t DartDevIsolate::DartDevRunner::argc_ = 0; + +bool DartDevIsolate::ShouldParseCommand(const char* script_uri) { + // If script_uri is not a file path or of a known URI scheme, we can assume + // that this is a DartDev command. + return (!File::ExistsUri(nullptr, script_uri) && + (strncmp(script_uri, "http://", 7) != 0) && + (strncmp(script_uri, "https://", 8) != 0) && + (strncmp(script_uri, "file://", 7) != 0) && + (strncmp(script_uri, "package:", 8) != 0) && + (strncmp(script_uri, "google3://", 10) != 0)); +} + +const char* DartDevIsolate::TryResolveDartDevSnapshotPath() { + // |dir_prefix| includes the last path seperator. + auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName(); + + // First assume we're in dart-sdk/bin. + char* snapshot_path = + Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get()); + if (File::Exists(nullptr, snapshot_path)) { + return snapshot_path; + } + free(snapshot_path); + + // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/* + // directories. Try to use a snapshot rom a previously built SDK. + snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get()); + if (File::Exists(nullptr, snapshot_path)) { + return snapshot_path; + } + free(snapshot_path); + + Syslog::PrintErr("Could not find DartDev snapshot.\n"); + return nullptr; +} + +void DartDevIsolate::DartDevRunner::Run( + Dart_IsolateGroupCreateCallback create_isolate, + const char* packages_file, + char** script, + CommandLineOptions* dart_options) { + create_isolate_ = create_isolate; + dart_options_ = dart_options; + packages_file_ = packages_file; + script_ = script; + + MonitorLocker locker(monitor_); + int result = Thread::Start("DartDev Runner", RunCallback, + reinterpret_cast(this)); + if (result != 0) { + FATAL1("Failed to start DartDev thread: %d", result); + } + monitor_->WaitMicros(Monitor::kNoTimeout); + + if (result_ == DartDevIsolate::DartDev_Result_Run) { + // Clear the DartDev dart_options and replace them with the processed + // options provided by DartDev. + dart_options_->Reset(); + for (intptr_t i = 0; i < argc_; ++i) { + dart_options_->AddArguments(const_cast(argv_.get()), argc_); + } + } +} + +static Dart_CObject* GetArrayItem(Dart_CObject* message, intptr_t index) { + return message->value.as_array.values[index]; +} + +void DartDevIsolate::DartDevRunner::DartDevResultCallback( + Dart_Port dest_port_id, + Dart_CObject* message) { + ASSERT(message->type == Dart_CObject_kArray); + int32_t type = GetArrayItem(message, 0)->value.as_int32; + switch (type) { + case DartDevIsolate::DartDev_Result_Run: { + result_ = DartDevIsolate::DartDev_Result_Run; + ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString); + if (*script_ != nullptr) { + free(*script_); + } + *script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string); + ASSERT(GetArrayItem(message, 2)->type == Dart_CObject_kArray); + Dart_CObject* args = GetArrayItem(message, 2); + argc_ = args->value.as_array.length; + Dart_CObject** dart_args = args->value.as_array.values; + + auto deleter = [](char** args) { + for (intptr_t i = 0; i < argc_; ++i) { + free(args[i]); + } + delete[] args; + }; + + argv_ = + std::unique_ptr(new char*[argc_], deleter); + for (intptr_t i = 0; i < argc_; ++i) { + argv_[i] = Utils::StrDup(dart_args[i]->value.as_string); + } + break; + } + case DartDevIsolate::DartDev_Result_Exit: { + ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32); + int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32; + + // If we're given a non-zero exit code, DartDev is signaling for us to + // shutdown. + if (dartdev_exit_code != 0) { + Process::SetGlobalExitCode(dartdev_exit_code); + } + + // If DartDev hasn't signaled for us to do anything else, we can assume + // there's nothing else for the VM to run and that we can exit. + if (result_ == DartDevIsolate::DartDev_Result_Unknown) { + result_ = DartDevIsolate::DartDev_Result_Exit; + } + + // DartDev is done processing the command. Unblock the main thread and + // continue the launch procedure. + DartDevRunner::monitor_->Notify(); + break; + } + default: + UNREACHABLE(); + } +} + +void DartDevIsolate::DartDevRunner::RunCallback(uword args) { + MonitorLocker locker_(DartDevRunner::monitor_); + DartDevRunner* runner = reinterpret_cast(args); + const char* dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath(); + if (dartdev_path == nullptr) { + ProcessError("Failed to find DartDev snapshot.", kErrorExitCode); + return; + } + Dart_IsolateFlags flags; + Dart_IsolateFlagsInitialize(&flags); + char* error; + Dart_Isolate dartdev_isolate = runner->create_isolate_( + dartdev_path, "dartdev", nullptr, runner->packages_file_, &flags, + NULL /* callback_data */, const_cast(&error)); + free(const_cast(dartdev_path)); + + if (dartdev_isolate == nullptr) { + ProcessError(error, kErrorExitCode); + return; + } + + Dart_EnterIsolate(dartdev_isolate); + Dart_EnterScope(); + + // Retrieve the DartDev entrypoint. + Dart_Port send_port_id = ILLEGAL_PORT; + Dart_Handle root_lib = Dart_RootLibrary(); + Dart_Handle main_closure = + Dart_GetField(root_lib, Dart_NewStringFromCString("main")); + CHECK_RESULT(main_closure); + + if (!Dart_IsClosure(main_closure)) { + ProcessError("Unable to find 'main' in root library 'dartdev'", + kErrorExitCode); + Dart_ExitScope(); + Dart_ExitIsolate(); + return; + } + + // Create a SendPort that DartDev can use to communicate its results over. + send_port_id = Dart_NewNativePort("dartdev", DartDevResultCallback, false); + ASSERT(send_port_id != ILLEGAL_PORT); + Dart_Handle send_port = Dart_NewSendPort(send_port_id); + CHECK_RESULT(send_port); + + const intptr_t kNumIsolateArgs = 7; + Dart_Handle isolate_args[kNumIsolateArgs]; + isolate_args[0] = Dart_Null(); // parentPort + isolate_args[1] = main_closure; // entryPoint + isolate_args[2] = runner->dart_options_->CreateRuntimeOptions(); // args + isolate_args[3] = send_port; // message + isolate_args[4] = Dart_True(); // isSpawnUri + isolate_args[5] = Dart_Null(); // controlPort + isolate_args[6] = Dart_Null(); // capabilities + + Dart_Handle isolate_lib = + Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate")); + Dart_Handle result = + Dart_Invoke(isolate_lib, Dart_NewStringFromCString("_startIsolate"), + kNumIsolateArgs, isolate_args); + CHECK_RESULT(result); + CHECK_RESULT(Dart_RunLoop()); + + Dart_CloseNativePort(send_port_id); + + Dart_ExitScope(); + Dart_ShutdownIsolate(); +} + +void DartDevIsolate::DartDevRunner::ProcessError(const char* msg, + int32_t exit_code) { + Syslog::PrintErr("%s\n", msg); + Process::SetGlobalExitCode(exit_code); + result_ = DartDevIsolate::DartDev_Result_Exit; + DartDevRunner::monitor_->Notify(); +} + +DartDevIsolate::DartDev_Result DartDevIsolate::RunDartDev( + Dart_IsolateGroupCreateCallback create_isolate, + const char* packages_file, + char** script, + CommandLineOptions* dart_options) { + runner_.Run(create_isolate, packages_file, script, dart_options); + return runner_.result(); +} + +#endif // if !defined(DART_PRECOMPILED_RUNTIME) + +} // namespace bin +} // namespace dart diff --git a/runtime/bin/dartdev_isolate.h b/runtime/bin/dartdev_isolate.h new file mode 100644 index 00000000000..e2ade66c7fa --- /dev/null +++ b/runtime/bin/dartdev_isolate.h @@ -0,0 +1,99 @@ +// Copyright (c) 2020, 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. + +#ifndef RUNTIME_BIN_DARTDEV_ISOLATE_H_ +#define RUNTIME_BIN_DARTDEV_ISOLATE_H_ + +#if !defined(DART_PRECOMPILED_RUNTIME) + +#include + +#include "bin/thread.h" +#include "include/dart_api.h" +#include "include/dart_native_api.h" +#include "platform/globals.h" + +namespace dart { +namespace bin { + +class CommandLineOptions; + +class DartDevIsolate { + public: + // Note: keep in sync with pkg/dartdev/lib/vm_interop_handler.dart + typedef enum { + DartDev_Result_Unknown = -1, + DartDev_Result_Run = 1, + DartDev_Result_Exit = 2, + } DartDev_Result; + + // Returns true if there does not exist a file at |script_uri| or the URI is + // not an HTTP resource. + static bool ShouldParseCommand(const char* script_uri); + + static void set_should_run_dart_dev(bool enable) { + should_run_dart_dev_ = enable; + } + + static bool should_run_dart_dev() { return should_run_dart_dev_; } + + // Starts a DartDev instance in a new isolate and runs it to completion. + // + // Returns true if the VM should run the result in `script`, in which case + // `script` and `dart_options` will have been repopulated with the correct + // values. + static DartDev_Result RunDartDev( + Dart_IsolateGroupCreateCallback create_isolate, + const char* packages_file, + char** script, + CommandLineOptions* dart_options); + + protected: + class DartDevRunner { + public: + DartDevRunner() {} + + void Run(Dart_IsolateGroupCreateCallback create_isolate, + const char* packages_file, + char** script, + CommandLineOptions* dart_options); + + DartDev_Result result() const { return result_; } + + private: + static void DartDevResultCallback(Dart_Port dest_port_id, + Dart_CObject* message); + static void RunCallback(uword arg); + static void ProcessError(const char* msg, int32_t exit_code); + + static DartDev_Result result_; + static char** script_; + static std::unique_ptr argv_; + static intptr_t argc_; + + Dart_IsolateGroupCreateCallback create_isolate_; + CommandLineOptions* dart_options_; + const char* packages_file_; + static Monitor* monitor_; + + DISALLOW_ALLOCATION(); + }; + + private: + // Attempts to find the DartDev snapshot. If the snapshot cannot be found, + // the VM will shutdown. + static const char* TryResolveDartDevSnapshotPath(); + + static DartDevRunner runner_; + static bool should_run_dart_dev_; + + DISALLOW_ALLOCATION(); + DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevIsolate); +}; + +} // namespace bin +} // namespace dart + +#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // RUNTIME_BIN_DARTDEV_ISOLATE_H_ diff --git a/runtime/bin/dartdev_utils.cc b/runtime/bin/dartdev_utils.cc deleted file mode 100644 index 3f14bc45ab7..00000000000 --- a/runtime/bin/dartdev_utils.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020, 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. - -#include "bin/dartdev_utils.h" - -#include - -#include "bin/directory.h" -#include "bin/exe_utils.h" -#include "bin/file.h" -#include "platform/utils.h" - -namespace dart { -namespace bin { - -bool DartDevUtils::ShouldParseCommand(const char* script_uri) { - // If script_uri is not a file path or of a known URI scheme, we can assume - // that this is a DartDev command. - return (!File::ExistsUri(nullptr, script_uri) && - (strncmp(script_uri, "http://", 7) != 0) && - (strncmp(script_uri, "https://", 8) != 0) && - (strncmp(script_uri, "file://", 7) != 0) && - (strncmp(script_uri, "package:", 8) != 0) && - (strncmp(script_uri, "google3://", 10) != 0)); -} - -bool DartDevUtils::TryResolveDartDevSnapshotPath(char** script_name) { - // |dir_prefix| includes the last path seperator. - auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName(); - - // First assume we're in dart-sdk/bin. - char* snapshot_path = - Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get()); - if (File::Exists(nullptr, snapshot_path)) { - *script_name = snapshot_path; - return true; - } - free(snapshot_path); - - // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/* - // directories. Try to use a snapshot from a previously built SDK. - snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get()); - if (File::Exists(nullptr, snapshot_path)) { - *script_name = snapshot_path; - return true; - } - free(snapshot_path); - return false; -} - -} // namespace bin -} // namespace dart diff --git a/runtime/bin/dartdev_utils.h b/runtime/bin/dartdev_utils.h deleted file mode 100644 index e388d1e9651..00000000000 --- a/runtime/bin/dartdev_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2020, 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. - -#ifndef RUNTIME_BIN_DARTDEV_UTILS_H_ -#define RUNTIME_BIN_DARTDEV_UTILS_H_ - -#include "platform/globals.h" - -namespace dart { -namespace bin { - -class DartDevUtils { - public: - // Returns true if there does not exist a file at |script_uri| or the URI is - // not an HTTP resource. - static bool ShouldParseCommand(const char* script_uri); - - // Returns true if we were successfully able to find the DartDev snapshot. - // Returns false if we were unable to find the snapshot, in which case the - // VM should exit. - static bool TryResolveDartDevSnapshotPath(char** script_name); - - private: - DISALLOW_ALLOCATION(); - DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevUtils); -}; - -} // namespace bin -} // namespace dart - -#endif // RUNTIME_BIN_DARTDEV_UTILS_H_ diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc index 972a07b70cd..a47775c153a 100644 --- a/runtime/bin/dartutils.cc +++ b/runtime/bin/dartutils.cc @@ -12,11 +12,9 @@ #include "bin/namespace.h" #include "bin/platform.h" #include "bin/utils.h" - #include "include/dart_api.h" #include "include/dart_native_api.h" #include "include/dart_tools_api.h" - #include "platform/assert.h" #include "platform/globals.h" #include "platform/memory_sanitizer.h" @@ -68,6 +66,29 @@ static bool IsWindowsHost() { #endif // defined(HOST_OS_WINDOWS) } +Dart_Handle CommandLineOptions::CreateRuntimeOptions() { + Dart_Handle string_type = DartUtils::GetDartType("dart:core", "String"); + if (Dart_IsError(string_type)) { + return string_type; + } + Dart_Handle dart_arguments = + Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), count_); + if (Dart_IsError(dart_arguments)) { + return dart_arguments; + } + for (int i = 0; i < count_; i++) { + Dart_Handle argument_value = DartUtils::NewString(GetArgument(i)); + if (Dart_IsError(argument_value)) { + return argument_value; + } + Dart_Handle result = Dart_ListSetAt(dart_arguments, i, argument_value); + if (Dart_IsError(result)) { + return result; + } + } + return dart_arguments; +} + int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) { int64_t value = 0; Dart_Handle result = Dart_IntegerToInt64(value_obj, &value); diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h index 23122adf2cb..65ed5ae762d 100644 --- a/runtime/bin/dartutils.h +++ b/runtime/bin/dartutils.h @@ -55,6 +55,8 @@ class CommandLineOptions { arguments_ = NULL; } + void Reset() { count_ = 0; } + int count() const { return count_; } int max_count() const { return max_count_; } const char** arguments() const { return arguments_; } @@ -80,6 +82,8 @@ class CommandLineOptions { } } + Dart_Handle CreateRuntimeOptions(); + void operator delete(void* pointer) { abort(); } private: diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc index c2303d37948..d4ac70f6a90 100644 --- a/runtime/bin/main.cc +++ b/runtime/bin/main.cc @@ -5,16 +5,13 @@ #include #include #include -#include -#include "include/bin/dart_io_api.h" -#include "include/dart_api.h" -#include "include/dart_embedder_api.h" -#include "include/dart_tools_api.h" +#include #include "bin/builtin.h" #include "bin/console.h" #include "bin/crashpad.h" +#include "bin/dartdev_isolate.h" #include "bin/dartutils.h" #include "bin/dfe.h" #include "bin/error_exit.h" @@ -31,6 +28,10 @@ #include "bin/thread.h" #include "bin/utils.h" #include "bin/vmservice_impl.h" +#include "include/bin/dart_io_api.h" +#include "include/dart_api.h" +#include "include/dart_embedder_api.h" +#include "include/dart_tools_api.h" #include "platform/globals.h" #include "platform/growable_array.h" #include "platform/hashmap.h" @@ -74,30 +75,6 @@ static Dart_Isolate main_isolate = NULL; static void ReadFile(const char* filename, uint8_t** buffer, intptr_t* size); -static Dart_Handle CreateRuntimeOptions(CommandLineOptions* options) { - int options_count = options->count(); - Dart_Handle string_type = DartUtils::GetDartType("dart:core", "String"); - if (Dart_IsError(string_type)) { - return string_type; - } - Dart_Handle dart_arguments = - Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), options_count); - if (Dart_IsError(dart_arguments)) { - return dart_arguments; - } - for (int i = 0; i < options_count; i++) { - Dart_Handle argument_value = DartUtils::NewString(options->GetArgument(i)); - if (Dart_IsError(argument_value)) { - return argument_value; - } - Dart_Handle result = Dart_ListSetAt(dart_arguments, i, argument_value); - if (Dart_IsError(result)) { - return result; - } - } - return dart_arguments; -} - #define SAVE_ERROR_AND_EXIT(result) \ *error = Utils::StrDup(Dart_GetError(result)); \ if (Dart_IsCompilationError(result)) { \ @@ -405,6 +382,15 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, CHECK_RESULT(result); } + // Disable pausing the DartDev isolate on start and exit. + const char* isolate_name = nullptr; + result = Dart_StringToCString(Dart_DebugName(), &isolate_name); + CHECK_RESULT(result); + if (strstr(isolate_name, "dartdev") != nullptr) { + Dart_SetShouldPauseOnStart(false); + Dart_SetShouldPauseOnExit(false); + } + // Make the isolate runnable so that it is ready to handle messages. Dart_ExitScope(); Dart_ExitIsolate(); @@ -941,8 +927,8 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) { // initial startup message. const intptr_t kNumIsolateArgs = 2; Dart_Handle isolate_args[kNumIsolateArgs]; - isolate_args[0] = main_closure; // entryPoint - isolate_args[1] = CreateRuntimeOptions(dart_options); // args + isolate_args[0] = main_closure; // entryPoint + isolate_args[1] = dart_options->CreateRuntimeOptions(); // args Dart_Handle isolate_lib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate")); @@ -1011,7 +997,7 @@ static Dart_GetVMServiceAssetsArchive GetVMServiceAssetsArchiveCallback = NULL; #endif // !defined(PRODUCT) void main(int argc, char** argv) { - char* script_name; + char* script_name = nullptr; const int EXTRA_VM_ARGUMENTS = 10; CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS); CommandLineOptions dart_options(argc + EXTRA_VM_ARGUMENTS); @@ -1101,9 +1087,6 @@ void main(int argc, char** argv) { } } - // At this point, script_name now points to either a script or a snapshot - // determined by DartDevUtils above. - DartUtils::SetEnvironment(Options::environment()); if (Options::suppress_core_dump()) { @@ -1114,19 +1097,28 @@ void main(int argc, char** argv) { Loader::InitOnce(); - if (app_snapshot == nullptr) { - // For testing purposes we add a flag to debug-mode to use the - // in-memory ELF loader. - const bool force_load_elf_from_memory = - false DEBUG_ONLY(|| Options::force_load_elf_from_memory()); - app_snapshot = - Snapshot::TryReadAppSnapshot(script_name, force_load_elf_from_memory); - } - if (app_snapshot != nullptr) { - vm_run_app_snapshot = true; - app_snapshot->SetBuffers(&vm_snapshot_data, &vm_snapshot_instructions, - &app_isolate_snapshot_data, - &app_isolate_snapshot_instructions); + auto try_load_snapshots_lambda = [&](void) -> void { + if (app_snapshot == nullptr) { + // For testing purposes we add a flag to debug-mode to use the + // in-memory ELF loader. + const bool force_load_elf_from_memory = + false DEBUG_ONLY(|| Options::force_load_elf_from_memory()); + app_snapshot = + Snapshot::TryReadAppSnapshot(script_name, force_load_elf_from_memory); + } + if (app_snapshot != nullptr) { + vm_run_app_snapshot = true; + app_snapshot->SetBuffers(&vm_snapshot_data, &vm_snapshot_instructions, + &app_isolate_snapshot_data, + &app_isolate_snapshot_instructions); + } + }; + + // At this point, script_name now points to a script if DartDev is disabled + // or a valid file path was provided as the first non-flag argument. + // Otherwise, script_name can be NULL if DartDev should be run. + if (script_name != nullptr) { + try_load_snapshots_lambda(); } if (Options::gen_snapshot_kind() == kAppJIT) { @@ -1159,16 +1151,18 @@ void main(int argc, char** argv) { // Note: must read platform only *after* VM flags are parsed because // they might affect how the platform is loaded. #if !defined(DART_PRECOMPILED_RUNTIME) - dfe.Init(Options::target_abi_version()); - uint8_t* application_kernel_buffer = NULL; - intptr_t application_kernel_buffer_size = 0; - dfe.ReadScript(script_name, &application_kernel_buffer, - &application_kernel_buffer_size); - if (application_kernel_buffer != NULL) { - // Since we loaded the script anyway, save it. - dfe.set_application_kernel_buffer(application_kernel_buffer, - application_kernel_buffer_size); - Options::dfe()->set_use_dfe(); + if (script_name != nullptr) { + dfe.Init(Options::target_abi_version()); + uint8_t* application_kernel_buffer = NULL; + intptr_t application_kernel_buffer_size = 0; + dfe.ReadScript(script_name, &application_kernel_buffer, + &application_kernel_buffer_size); + if (application_kernel_buffer != NULL) { + // Since we loaded the script anyway, save it. + dfe.set_application_kernel_buffer(application_kernel_buffer, + application_kernel_buffer_size); + Options::dfe()->set_use_dfe(); + } } #endif @@ -1208,10 +1202,29 @@ void main(int argc, char** argv) { &ServiceStreamCancelCallback); Dart_SetFileModifiedCallback(&FileModifiedCallback); Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); + bool ran_dart_dev = false; + bool should_run_user_program = true; +#if !defined(DART_PRECOMPILED_RUNTIME) + if (DartDevIsolate::should_run_dart_dev() && !Options::disable_dart_dev() && + Options::gen_snapshot_kind() == SnapshotKind::kNone) { + DartDevIsolate::DartDev_Result dartdev_result = DartDevIsolate::RunDartDev( + CreateIsolateGroupAndSetup, Options::packages_file(), &script_name, + &dart_options); + ASSERT(dartdev_result != DartDevIsolate::DartDev_Result_Unknown); + ran_dart_dev = true; + should_run_user_program = + (dartdev_result == DartDevIsolate::DartDev_Result_Run); + if (should_run_user_program) { + try_load_snapshots_lambda(); + } + } +#endif // !defined(DART_PRECOMPILED_RUNTIME) - // Run the main isolate until we aren't told to restart. - while (RunMainIsolate(script_name, &dart_options)) { - Syslog::PrintErr("Restarting VM\n"); + if (should_run_user_program) { + // Run the main isolate until we aren't told to restart. + while (RunMainIsolate(script_name, &dart_options)) { + Syslog::PrintErr("Restarting VM\n"); + } } // Terminate process exit-code handler. @@ -1227,6 +1240,9 @@ void main(int argc, char** argv) { delete app_snapshot; free(app_script_uri); + if (ran_dart_dev && script_name != nullptr) { + free(script_name); + } // Free copied argument strings if converted. if (argv_converted) { diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc index 816c2994d23..4398c1f3265 100644 --- a/runtime/bin/main_options.cc +++ b/runtime/bin/main_options.cc @@ -9,7 +9,7 @@ #include #include "bin/abi_version.h" -#include "bin/dartdev_utils.h" +#include "bin/dartdev_isolate.h" #include "bin/error_exit.h" #include "bin/options.h" #include "bin/platform.h" @@ -35,9 +35,6 @@ static const char* kSnapshotKindNames[] = { NULL, }; -static const char* kEnableExperiment1 = "--enable-experiment"; -static const char* kEnableExperiment2 = "--enable_experiment"; - SnapshotKind Options::gen_snapshot_kind_ = kNone; bool Options::enable_vm_service_ = false; MallocGrowableArray Options::enabled_experiments_ = @@ -381,27 +378,17 @@ bool Options::ProcessEnableExperimentOption(const char* arg, return false; } vm_options->AddArgument(arg); - Utils::CStringUniquePtr tmp = Utils::CreateCStringUniquePtr( - Utils::StrDup(value)); + Utils::CStringUniquePtr tmp = + Utils::CreateCStringUniquePtr(Utils::StrDup(value)); char* save_ptr; // Needed for strtok_r. char* token = strtok_r(const_cast(tmp.get()), ",", &save_ptr); while (token != NULL) { - enabled_experiments_.Add(token); + enabled_experiments_.Add(Utils::StrDup(token)); token = strtok_r(NULL, ",", &save_ptr); } return true; } -static void ResolveDartDevSnapshotPath(const char* script, - char** snapshot_path) { - if (!DartDevUtils::TryResolveDartDevSnapshotPath(snapshot_path)) { - Syslog::PrintErr( - "Could not find DartDev snapshot and '%s' is not a valid script.\n", - script); - Platform::Exit(kErrorExitCode); - } -} - int Options::ParseArguments(int argc, char** argv, bool vm_run_app_snapshot, @@ -476,17 +463,11 @@ int Options::ParseArguments(int argc, } } - if (!Options::disable_dart_dev()) { - // Don't start the VM service for the DartDev process. Without doing a - // second pass over the argument list to explicitly check for - // --disable-dart-dev, this is the earliest we can assume we know whether - // or not we're running with DartDev enabled. - vm_service_server_port_ = INVALID_VM_SERVICE_SERVER_PORT; - vm_service_server_ip_ = DEFAULT_VM_SERVICE_SERVER_IP; - } - #if !defined(DART_PRECOMPILED_RUNTIME) Options::dfe()->set_use_dfe(); +#else + // DartDev is not supported in AOT. + Options::disable_dart_dev_ = true; #endif // !defined(DART_PRECOMPILED_RUNTIME) if (Options::deterministic()) { // Both an embedder and VM flag. @@ -503,24 +484,31 @@ int Options::ParseArguments(int argc, // The arguments to the VM are at positions 1 through i-1 in argv. Platform::SetExecutableArguments(i, argv); - bool implicitly_use_dart_dev = false; bool run_script = false; int script_or_cmd_index = -1; + // Get the script name. if (i < argc) { +#if !defined(DART_PRECOMPILED_RUNTIME) // If the script name is a valid file or a URL, we'll run the script // directly. Otherwise, this might be a DartDev command and we need to try // to find the DartDev snapshot so we can forward the command and its // arguments. - bool is_potential_file_path = !DartDevUtils::ShouldParseCommand(argv[i]); + bool is_potential_file_path = !DartDevIsolate::ShouldParseCommand(argv[i]); + bool implicitly_use_dart_dev = false; +#else + bool is_potential_file_path = true; +#endif // !defined(DART_PRECOMPILED_RUNTIME) script_or_cmd_index = i; if (Options::disable_dart_dev() || (is_potential_file_path && !enable_vm_service_)) { *script_name = Utils::StrDup(argv[i]); run_script = true; i++; - } else { - ResolveDartDevSnapshotPath(argv[i], script_name); + } +#if !defined(DART_PRECOMPILED_RUNTIME) + else { // NOLINT + DartDevIsolate::set_should_run_dart_dev(true); } // Handle the special case where the user is running a Dart program without // using a DartDev command and wants to use the VM service. Here we'll run @@ -530,10 +518,13 @@ int Options::ParseArguments(int argc, implicitly_use_dart_dev = true; dart_options->AddArgument("run"); } - } else if (!Options::disable_dart_dev() && - ((Options::help_option() && !Options::verbose_option()) || - (argc == 1)) && - DartDevUtils::TryResolveDartDevSnapshotPath(script_name)) { +#endif // !defined(DART_PRECOMPILED_RUNTIME) + } +#if !defined(DART_PRECOMPILED_RUNTIME) + else if (!Options::disable_dart_dev() && // NOLINT + ((Options::help_option() && !Options::verbose_option()) || + (argc == 1))) { + DartDevIsolate::set_should_run_dart_dev(true); // Let DartDev handle the default help message. dart_options->AddArgument("help"); return 0; @@ -541,7 +532,7 @@ int Options::ParseArguments(int argc, (enable_dartdev_analytics || disable_dartdev_analytics)) { // The analytics flags are a special case as we don't have a target script // or DartDev command but we still want to launch DartDev. - ResolveDartDevSnapshotPath(argv[i], script_name); + DartDevIsolate::set_should_run_dart_dev(true); if (enable_dartdev_analytics) { dart_options->AddArgument("--enable-analytics"); @@ -550,89 +541,68 @@ int Options::ParseArguments(int argc, dart_options->AddArgument("--disable-analytics"); } return 0; - } else { - return -1; } +#endif // !defined(DART_PRECOMPILED_RUNTIME) + else { // NOLINT + return -1; + } const char** vm_argv = temp_vm_options.arguments(); int vm_argc = temp_vm_options.count(); - if (Options::disable_dart_dev() || run_script) { - // Only populate the VM options if we're not running with DartDev. - vm_options->AddArguments(vm_argv, vm_argc); - } else if (implicitly_use_dart_dev) { - // If we're using DartDev implicitly (e.g., dart --observe foo.dart), we - // want to forward all the VM arguments to the spawned process to ensure - // the program behaves as the user expects even though we're running - // through DartDev without their knowledge. - dart_options->AddArguments(const_cast(argv + 1), - script_or_cmd_index - 1); - } else if (i > 1) { - // If we're running with DartDev, we're going to ignore the VM options for - // this VM instance and print a warning. + vm_options->AddArguments(vm_argv, vm_argc); - int num_experiment_flags = 0; - if (!enabled_experiments_.is_empty()) { - for (intptr_t j = 1; j < script_or_cmd_index; ++j) { - if ((strstr(argv[j], kEnableExperiment1) != nullptr) || - (strstr(argv[j], kEnableExperiment2) != nullptr)) { - ++num_experiment_flags; - } - } - } - if (num_experiment_flags + 1 != script_or_cmd_index) { - Syslog::PrintErr( - "Warning: The following flags were passed as VM options and are " - "being " - "ignored:\n\n"); - for (int j = 1; j < script_or_cmd_index; ++j) { - if ((strstr(argv[j], kEnableExperiment1) == nullptr) && - (strstr(argv[j], kEnableExperiment2) == nullptr)) { - Syslog::PrintErr(" %s\n", argv[j]); - } - } - Syslog::PrintErr( - "\nThese flags should be passed after the dart command (e.g., 'dart " - "run --enable-asserts foo.dart' instead of 'dart --enable-asserts " - "run " - "foo.dart').\n\n"); - } - } - - if (!enabled_experiments_.is_empty() && - !(Options::disable_dart_dev() || run_script)) { +#if !defined(DART_PRECOMPILED_RUNTIME) + if (!enabled_experiments_.is_empty()) { intptr_t num_experiments = enabled_experiments_.length(); - int option_size = strlen(kEnableExperiment1) + 1; - for (intptr_t i = 0; i < num_experiments; ++i) { - const char* flag = enabled_experiments_.At(i); - option_size += strlen(flag); - if (i + 1 != num_experiments) { - // Account for comma if there's more experiments to add. - ++option_size; + if (!(Options::disable_dart_dev() || run_script)) { + const char* kEnableExperiment = "--enable-experiment="; + int option_size = strlen(kEnableExperiment); + for (intptr_t i = 0; i < num_experiments; ++i) { + const char* flag = enabled_experiments_.At(i); + option_size += strlen(flag); + if (i + 1 != num_experiments) { + // Account for comma if there's more experiments to add. + ++option_size; + } + } + // Make room for null terminator + ++option_size; + + char* enabled_experiments_arg = new char[option_size]; + int offset = snprintf(enabled_experiments_arg, option_size, "%s", + kEnableExperiment); + for (intptr_t i = 0; i < num_experiments; ++i) { + const char* flag = enabled_experiments_.At(i); + const char* kFormat = (i + 1 != num_experiments) ? "%s," : "%s"; + offset += snprintf(enabled_experiments_arg + offset, + option_size - offset, kFormat, flag); + free(const_cast(flag)); + ASSERT(offset < option_size); + } + DartDevIsolate::set_should_run_dart_dev(true); + dart_options->AddArgument(enabled_experiments_arg); + } else { + for (intptr_t i = 0; i < num_experiments; ++i) { + free(const_cast(enabled_experiments_.At(i))); } } - // Make room for null terminator - ++option_size; - - char* enabled_experiments_arg = new char[option_size]; - int offset = snprintf(enabled_experiments_arg, option_size, - "%s=", kEnableExperiment1); - for (intptr_t i = 0; i < num_experiments; ++i) { - const char* flag = enabled_experiments_.At(i); - const char* kFormat = (i + 1 != num_experiments) ? "%s," : "%s"; - offset += snprintf(enabled_experiments_arg + offset, option_size - offset, - kFormat, flag); - ASSERT(offset < option_size); - } - dart_options->AddArgument(enabled_experiments_arg); } +#endif // !defined(DART_PRECOMPILED_RUNTIME) // Parse out options to be passed to dart main. while (i < argc) { + if (!run_script) { + OptionProcessor::TryProcess(argv[i], vm_options); + } dart_options->AddArgument(argv[i]); i++; } + if (!Options::disable_dart_dev() && enable_vm_service_) { + dart_options->AddArgument("--launch-dds"); + } + // Verify consistency of arguments. // snapshot_depfile is an alias for depfile. Passing them both is an error. diff --git a/runtime/observatory/lib/service_html.dart b/runtime/observatory/lib/service_html.dart index ddc42f5d2d3..60f552cdda9 100644 --- a/runtime/observatory/lib/service_html.dart +++ b/runtime/observatory/lib/service_html.dart @@ -18,7 +18,11 @@ class _HtmlWebSocket implements CommonWebSocket { void connect(String address, void onOpen(), void onMessage(dynamic data), void onError(), void onClose()) { - _webSocket = new WebSocket(address); + // The VM service will attempt to redirect our websocket connection request + // to DDS, but the dart:html WebSocket doesn't follow redirects. If the + // 'implicit-redirect' protocol is provided, the VM service will manually + // forward traffic to DDS. + _webSocket = new WebSocket(address, ['implicit-redirect']); _webSocket.onClose.listen((CloseEvent) => onClose()); _webSocket.onError.listen((Event) => onError()); _webSocket.onOpen.listen((Event) => onOpen()); diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 76d70a5dc13..1cf9639cc76 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -1117,6 +1117,9 @@ void Service::HandleEvent(ServiceEvent* event) { } // Ignore events when no one is listening to the event stream. return; + } else if (event->stream_info() != NULL && + FLAG_warn_on_pause_with_no_debugger && event->IsPause()) { + ReportPauseOnConsole(event); } if (!ServiceIsolate::IsRunning()) { return; diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 580713c0036..a032fcdd510 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -47,6 +47,7 @@ declare_args() { # ........analysis_server.dart.snapshot # ........dart2js.dart.snapshot # ........dartanalyzer.dart.snapshot +# ........dds.dart.snapshot # ........dartdev.dart.snapshot # ........dartdoc.dart.snapshot # ........dartfmt.dart.snapshot @@ -133,6 +134,10 @@ _platform_sdk_snapshots = [ "dartfmt", "../utils/dartfmt", ], + [ + "dds", + "../utils/dds:generate_dds_snapshot", + ], [ "pub", "../utils/pub", @@ -182,6 +187,10 @@ _full_sdk_snapshots = [ "dartfmt", "../utils/dartfmt", ], + [ + "dds", + "../utils/dds:generate_dds_snapshot", + ], [ "kernel_worker", "../utils/bazel:kernel_worker", diff --git a/sdk/lib/_internal/vm/bin/vmservice_server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart index 9857cd653fb..68e18a3fc58 100644 --- a/sdk/lib/_internal/vm/bin/vmservice_server.dart +++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart @@ -354,14 +354,41 @@ class Server { final String path = result; if (path == WEBSOCKET_PATH) { + final subprotocols = request.headers['sec-websocket-protocol']; if (acceptNewWebSocketConnections) { WebSocketTransformer.upgrade(request, + protocolSelector: + subprotocols == null ? null : (_) => 'implicit-redirect', compression: CompressionOptions.compressionOff) .then((WebSocket webSocket) { WebSocketClient(webSocket, _service); }); } else { // Forward the websocket connection request to DDS. + // The Javascript WebSocket implementation doesn't like websocket + // connection requests being redirected. Instead of redirecting, we'll + // just forward the connection manually if 'implicit-redirect' is + // provided as a protocol. + if (subprotocols != null) { + if (subprotocols.contains('implicit-redirect')) { + WebSocketTransformer.upgrade(request, + protocolSelector: (_) => 'implicit-redirect', + compression: CompressionOptions.compressionOff) + .then((WebSocket webSocket) async { + final ddsWs = await WebSocket.connect( + _service.ddsUri!.replace(scheme: 'ws').toString()); + ddsWs.addStream(webSocket); + webSocket.addStream(ddsWs); + webSocket.done.then((_) { + ddsWs.close(); + }); + ddsWs.done.then((_) { + webSocket.close(); + }); + }); + return; + } + } request.response.redirect(_service.ddsUri!); } return; diff --git a/tests/standalone/regress_41329_absolute_test.dart b/tests/standalone/regress_41329_absolute_test.dart index cc2a40260bd..e35e126cb1c 100644 --- a/tests/standalone/regress_41329_absolute_test.dart +++ b/tests/standalone/regress_41329_absolute_test.dart @@ -4,8 +4,6 @@ import 'dart:io'; -import 'package:async_helper/async_helper.dart'; -import 'package:path/path.dart' as p; import 'package:expect/expect.dart'; Future main() async { diff --git a/tests/standalone/regress_41329_relative_test.dart b/tests/standalone/regress_41329_relative_test.dart index cc2a40260bd..e35e126cb1c 100644 --- a/tests/standalone/regress_41329_relative_test.dart +++ b/tests/standalone/regress_41329_relative_test.dart @@ -4,8 +4,6 @@ import 'dart:io'; -import 'package:async_helper/async_helper.dart'; -import 'package:path/path.dart' as p; import 'package:expect/expect.dart'; Future main() async { diff --git a/tests/standalone_2/regress_41329_absolute_test.dart b/tests/standalone_2/regress_41329_absolute_test.dart index cc2a40260bd..e35e126cb1c 100644 --- a/tests/standalone_2/regress_41329_absolute_test.dart +++ b/tests/standalone_2/regress_41329_absolute_test.dart @@ -4,8 +4,6 @@ import 'dart:io'; -import 'package:async_helper/async_helper.dart'; -import 'package:path/path.dart' as p; import 'package:expect/expect.dart'; Future main() async { diff --git a/tests/standalone_2/regress_41329_relative_test.dart b/tests/standalone_2/regress_41329_relative_test.dart index cc2a40260bd..e35e126cb1c 100644 --- a/tests/standalone_2/regress_41329_relative_test.dart +++ b/tests/standalone_2/regress_41329_relative_test.dart @@ -4,8 +4,6 @@ import 'dart:io'; -import 'package:async_helper/async_helper.dart'; -import 'package:path/path.dart' as p; import 'package:expect/expect.dart'; Future main() async { diff --git a/utils/dartdev/BUILD.gn b/utils/dartdev/BUILD.gn index 45a52ca87c3..68a779e905c 100644 --- a/utils/dartdev/BUILD.gn +++ b/utils/dartdev/BUILD.gn @@ -17,14 +17,6 @@ dartfix_files = exec_script("../../tools/list_dart_files.py", rebase_path("../../pkg/dartfix"), ], "list lines") - -dds_files = exec_script("../../tools/list_dart_files.py", - [ - "absolute", - rebase_path("../../pkg/dds"), - ], - "list lines") - group("dartdev") { deps = [ ":copy_dartdev_snapshot" ] } @@ -39,6 +31,6 @@ copy("copy_dartdev_snapshot") { application_snapshot("generate_dartdev_snapshot") { main_dart = "../../pkg/dartdev/bin/dartdev.dart" training_args = [ "--help" ] - inputs = dartdev_files + dartfix_files + dds_files + inputs = dartdev_files + dartfix_files output = "$root_gen_dir/dartdev.dart.snapshot" } diff --git a/utils/dds/BUILD.gn b/utils/dds/BUILD.gn new file mode 100644 index 00000000000..001e710af1c --- /dev/null +++ b/utils/dds/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright (c) 2020, 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. + +import("../application_snapshot.gni") + +dds_files = exec_script("../../tools/list_dart_files.py", + [ + "absolute", + rebase_path("../../pkg/dds"), + ], + "list lines") + +group("dds") { + deps = [ ":copy_dds_snapshot" ] +} + +copy("copy_dds_snapshot") { + visibility = [ ":dds" ] + deps = [ ":generate_dds_snapshot" ] + sources = [ "$root_gen_dir/dds.dart.snapshot" ] + outputs = [ "$root_out_dir/dds.dart.snapshot" ] +} + +application_snapshot("generate_dds_snapshot") { + main_dart = "../../pkg/dds/bin/dds.dart" + training_args = [] + inputs = dds_files + output = "$root_gen_dir/dds.dart.snapshot" +}