Revert "[ VM / DartDev ] Launch DartDev in an isolate within a single main Dart process"

This reverts commit ffe258d2d4.

Reason for revert: Failures on bots

Original change's description:
> [ VM / DartDev ] Launch DartDev in an isolate within a single main Dart process
> 
> This CL changes how DartDev is run and how the run command handles executing a Dart program (will port additional commands in a separate CL). Rather than using DartDev to spawn a child process to run user code, the VM will instead launch a DartDev isolate after doing some VM options processing. DartDev will communicate information like exit codes and script/arg pairs with the VM via isolate ports. Once DartDev runs to completion and notifies the VM that a script should be run, the VM will move on to spawning another isolate with user code and continue executing in the same VM process.
> 
> By moving DartDev into an isolate within the same process that user code will eventually run in we're able to resolve the following issues that arose due to signal handling and IPC issues:
> 
> VM hangs when --enable-vm-service is supplied and there are compile time errors (https://github.com/dart-lang/sdk/issues/42630)
> Dart daemon spinning in exit code handler / zombie Dart processes (https://github.com/dart-lang/sdk/issues/41978)
> Signal handling in children of 'dartdev run' is problematic (https://github.com/dart-lang/sdk/issues/41978)
> 
> Change-Id: I1c6b1425831b691ad20284716aa80f817dbaf607
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152588
> Commit-Queue: Ben Konyi <bkonyi@google.com>
> Reviewed-by: Siva Annamalai <asiva@google.com>
> Reviewed-by: Ryan Macnak <rmacnak@google.com>

TBR=bkonyi@google.com,rmacnak@google.com,asiva@google.com

Change-Id: Idb1d24a4524bdc3ccfb199a82710f3c0d9db539a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154702
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Ben Konyi 2020-07-16 19:50:57 +00:00 committed by commit-bot@chromium.org
parent 90c683018f
commit 3849b5061c
37 changed files with 488 additions and 802 deletions

View file

@ -61,10 +61,7 @@ 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",
"utils/dds:dds",
]
deps += [ "utils/dartdev:dartdev" ]
}
}

View file

@ -2,12 +2,18 @@
// 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:async';
import 'dart:isolate';
import 'dart:io';
import 'package:dartdev/dartdev.dart';
import 'package:pedantic/pedantic.dart' show unawaited;
/// The entry point for dartdev.
Future<void> main(List<String> args, SendPort port) async {
await runDartdev(args, port);
Future<void> main(List<String> 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);
}

View file

@ -3,7 +3,6 @@
// 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';
@ -22,13 +21,11 @@ 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<void> runDartdev(List<String> args, SendPort port) async {
VmInteropHandler.initialize(port);
Future<void> runDartdev(List<String> args) async {
final stopwatch = Stopwatch();
int result;
@ -71,12 +68,6 @@ Future<void> runDartdev(List<String> args, SendPort port) 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 {
@ -88,12 +79,6 @@ Future<void> runDartdev(List<String> args, SendPort port) 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) {
@ -148,7 +133,7 @@ Future<void> runDartdev(List<String> args, SendPort port) async {
analytics.enabled = true;
}
analytics.close();
VmInteropHandler.exit(exitCode);
io.exit(exitCode);
}
}
@ -181,11 +166,6 @@ class DartdevRunner<int> 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());
@ -212,7 +192,7 @@ class DartdevRunner<int> extends CommandRunner {
io.stderr.writeln(
"Error when reading '$firstArg': No such file or directory.");
// This is the exit code used by the frontend.
VmInteropHandler.exit(254);
io.exit(254);
}
}

View file

@ -73,7 +73,7 @@ class AnalyzeCommand extends DartdevCommand<int> {
});
await analysisCompleter.future;
await server.dispose();
progress.finish(showTiming: true);
errors.sort();

View file

@ -4,20 +4,18 @@
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<int> {
static bool launchDds = false;
@override
final ArgParser argParser = ArgParser.allowAnything();
@ -62,19 +60,21 @@ Run a Dart file.''');
// The command line arguments after 'run'
var args = argResults.arguments.toList();
var argsContainFile = false;
var argsContainFileOrHelp = false;
for (var arg in args) {
// The arg.contains('.') matches a file name pattern, i.e. some 'foo.dart'
if (arg.contains('.')) {
argsContainFile = true;
} else if (arg == '--help' || arg == '-h' || arg == 'help') {
printUsage();
return 0;
if (arg.contains('.') ||
arg == '--help' ||
arg == '-h' ||
arg == 'help') {
argsContainFileOrHelp = true;
break;
}
}
final cwd = Directory.current;
if (!argsContainFile && cwd.existsSync()) {
if (!argsContainFileOrHelp && cwd.existsSync()) {
var foundImplicitFileToRun = false;
var cwdName = cwd.name;
for (var entity in cwd.listSync(followLinks: false)) {
@ -100,8 +100,6 @@ 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;
}
}
@ -119,43 +117,213 @@ Run a Dart file.''');
// service intermediary which implements the VM service protocol and
// provides non-VM specific extensions (e.g., log caching, client
// synchronization).
_DebuggingSession debugSession;
if (launchDds) {
debugSession = _DebuggingSession();
await debugSession.start();
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;
}
final script = Directory.current.uri
.resolve(args.firstWhere((e) => !e.startsWith('-')))
.toFilePath();
final runArgs = args.length == 1 ? <String>[] : args.sublist(1);
VmInteropHandler.run(script, runArgs);
return 0;
}
}
class _DebuggingSession {
Future<void> 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<void>();
StreamSubscription sub;
sub = process.stderr.transform(utf8.decoder).listen((event) {
if (event == 'DDS started') {
sub.cancel();
completer.complete();
_DebuggingSession(this._runCommand, List<String> 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;
}
});
}
await completer.future;
// 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<int> 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;
});
}
Future<Uri> _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<void> _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<void> _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<String> _args;
final Completer<void> _ddsCompleter = Completer();
final RunCommand _runCommand;
}

View file

@ -52,9 +52,6 @@ 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) =>

View file

@ -1,40 +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.
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<String> args) {
assert(_port != null);
if (_port == null) return;
final message = List<dynamic>.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<dynamic>.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;
}

View file

@ -79,51 +79,13 @@ void help() {
var result = p.runSync('--help', ['--verbose']);
expect(result.exitCode, 0);
expect(result.stdout, isEmpty);
expect(result.stderr,
contains('The following options are only used for VM development'));
expect(result.stdout, contains('migrate '));
});
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 [<vm-flags>] <command|dart-file> [<arguments>]'));
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 '));
});

View file

@ -55,6 +55,7 @@ class TestProject {
String workingDir,
}) {
var arguments = [
absolutePathToDartdevFile,
command,
if (command == 'migrate')
// TODO(srawlins): Enable `pub outdated` in tests.
@ -63,6 +64,7 @@ class TestProject {
];
arguments.add('--disable-dartdev-analytics');
return Process.runSync(
Platform.resolvedExecutable,
arguments,

View file

@ -1,18 +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.
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<void> main(List<String> args) async {
if (args.isEmpty) return;
final remoteVmServiceUri = Uri.parse(args.first);
await DartDevelopmentService.startDartDevelopmentService(remoteVmServiceUri);
stderr.write('DDS started');
}

View file

@ -30,26 +30,12 @@ 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.

View file

@ -85,6 +85,7 @@ class _RunningIsolate {
if (_resumeApprovalsByName.isEmpty) {
return false;
}
// If all the required approvals are present, we should resume.
return _resumeApprovalsByName.containsAll(requiredClientApprovals);
}

View file

@ -86,7 +86,7 @@ class _StreamManager {
Future<void> listen() async {
// The _IsolateManager requires information from both the Debug and
// Isolate streams, so they must always be subscribed to by DDS.
for (final stream in ddsCoreStreams.where((e) => e != kDebugStream)) {
for (final stream in ddsCoreStreams) {
await streamListen(null, stream);
}
dds._vmServiceClient.registerMethod(
@ -117,15 +117,12 @@ class _StreamManager {
) async {
assert(stream != null && stream.isNotEmpty);
if (!streamListeners.containsKey(stream)) {
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');
}
// 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)) {
@ -145,18 +142,16 @@ class _StreamManager {
/// send a `streamCancel` request for `stream` to the VM service.
Future<void> streamCancel(
_DartDevelopmentServiceClient client,
String stream, {
bool cancelCoreStream = false,
}) async {
String stream,
) async {
assert(stream != null && stream.isNotEmpty);
final listeners = streamListeners[stream];
if (client != null && (listeners == null || !listeners.contains(client))) {
if (listeners == null || !listeners.contains(client)) {
throw kStreamNotSubscribedException;
}
listeners.remove(client);
// Don't cancel streams DDS needs to function.
if (listeners.isEmpty &&
(!ddsCoreStreams.contains(stream) || cancelCoreStream)) {
if (listeners.isEmpty && !ddsCoreStreams.contains(stream)) {
streamListeners.remove(stream);
// Ensure the VM service hasn't shutdown.
if (dds._vmServiceClient.isClosed) {

View file

@ -103,10 +103,6 @@ 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');

View file

@ -13,7 +13,6 @@ main(List<String> args) async {
LeakFinder heapHelper = new LeakFinder();
heapHelper.start([
"--disable-dart-dev",
"--enable-asserts",
Platform.script.resolve("incremental_dart2js_tester.dart").toString(),
"--addDebugBreaks",

View file

@ -56,7 +56,6 @@ benchmark
besides
beta
bigger
bkonyi
blah
blindly
blocked
@ -130,7 +129,6 @@ dash
dashes
day
db
dds
debugger
decrease
decrements
@ -504,7 +502,6 @@ slight
smoke
somehow
spans
spawn
spell
spellcheck
spelled

View file

@ -453,7 +453,6 @@ main() {
"--pause-isolates-on-exit",
"--enable-vm-service:0",
"--disable-service-auth-codes",
"--disable-dart-dev",
list.path
]);
@ -580,7 +579,6 @@ main() {
"--pause-isolates-on-exit",
"--enable-vm-service:0",
"--disable-service-auth-codes",
"--disable-dart-dev",
list.path
]);
@ -660,7 +658,6 @@ 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);
@ -920,7 +917,6 @@ main() {
"--pause-isolates-on-start",
"--enable-vm-service:0",
"--disable-service-auth-codes",
"--disable-dart-dev",
scriptOrDill.path
]);

View file

@ -878,8 +878,6 @@ dart_executable("dart") {
}
extra_sources = [
"builtin.cc",
"dartdev_isolate.cc",
"dartdev_isolate.h",
"dfe.cc",
"dfe.h",
"gzip.cc",

View file

@ -15,6 +15,8 @@ builtin_impl_sources = [
"crypto_linux.cc",
"crypto_macos.cc",
"crypto_win.cc",
"dartdev_utils.cc",
"dartdev_utils.h",
"dartutils.cc",
"dartutils.h",
"directory.cc",

View file

@ -1,261 +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_isolate.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include <functional>
#include <memory>
#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<char*[], void (*)(char*[])>
DartDevIsolate::DartDevRunner::argv_ =
std::unique_ptr<char*[], void (*)(char**)>(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<uword>(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<const char**>(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<char*[], void (*)(char**)>(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<DartDevRunner*>(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<char**>(&error));
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

View file

@ -1,99 +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_ISOLATE_H_
#define RUNTIME_BIN_DARTDEV_ISOLATE_H_
#if !defined(DART_PRECOMPILED_RUNTIME)
#include <memory>
#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<char*[], void (*)(char**)> 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_

View file

@ -0,0 +1,53 @@
// 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 <memory>
#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

View file

@ -0,0 +1,32 @@
// 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_

View file

@ -12,9 +12,11 @@
#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"
@ -66,29 +68,6 @@ 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);

View file

@ -55,8 +55,6 @@ 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_; }
@ -82,8 +80,6 @@ class CommandLineOptions {
}
}
Dart_Handle CreateRuntimeOptions();
void operator delete(void* pointer) { abort(); }
private:

View file

@ -5,13 +5,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#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 "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"
@ -28,10 +31,6 @@
#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"
@ -75,6 +74,30 @@ 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)) { \
@ -380,15 +403,6 @@ 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();
@ -923,8 +937,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] = dart_options->CreateRuntimeOptions(); // args
isolate_args[0] = main_closure; // entryPoint
isolate_args[1] = CreateRuntimeOptions(dart_options); // args
Dart_Handle isolate_lib =
Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
@ -993,7 +1007,7 @@ static Dart_GetVMServiceAssetsArchive GetVMServiceAssetsArchiveCallback = NULL;
#endif // !defined(PRODUCT)
void main(int argc, char** argv) {
char* script_name = nullptr;
char* script_name;
const int EXTRA_VM_ARGUMENTS = 10;
CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
CommandLineOptions dart_options(argc + EXTRA_VM_ARGUMENTS);
@ -1083,6 +1097,9 @@ 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()) {
@ -1093,28 +1110,19 @@ void main(int argc, char** argv) {
Loader::InitOnce();
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 (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);
}
if (Options::gen_snapshot_kind() == kAppJIT) {
@ -1147,18 +1155,16 @@ 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)
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();
}
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
@ -1198,29 +1204,10 @@ 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)
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");
}
// 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.
@ -1236,9 +1223,6 @@ 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) {

View file

@ -9,7 +9,7 @@
#include <string.h>
#include "bin/abi_version.h"
#include "bin/dartdev_isolate.h"
#include "bin/dartdev_utils.h"
#include "bin/error_exit.h"
#include "bin/options.h"
#include "bin/platform.h"
@ -35,6 +35,9 @@ 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<const char*> Options::enabled_experiments_ =
@ -378,17 +381,27 @@ 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<char*>(tmp.get()), ",", &save_ptr);
while (token != NULL) {
enabled_experiments_.Add(Utils::StrDup(token));
enabled_experiments_.Add(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,
@ -463,11 +476,17 @@ 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.
@ -484,31 +503,24 @@ 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 = !DartDevIsolate::ShouldParseCommand(argv[i]);
bool implicitly_use_dart_dev = false;
#else
bool is_potential_file_path = true;
#endif // !defined(DART_PRECOMPILED_RUNTIME)
bool is_potential_file_path = !DartDevUtils::ShouldParseCommand(argv[i]);
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++;
}
#if !defined(DART_PRECOMPILED_RUNTIME)
else { // NOLINT
DartDevIsolate::set_should_run_dart_dev(true);
} else {
ResolveDartDevSnapshotPath(argv[i], script_name);
}
// 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
@ -518,13 +530,10 @@ int Options::ParseArguments(int argc,
implicitly_use_dart_dev = true;
dart_options->AddArgument("run");
}
#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);
} else if (!Options::disable_dart_dev() &&
((Options::help_option() && !Options::verbose_option()) ||
(argc == 1)) &&
DartDevUtils::TryResolveDartDevSnapshotPath(script_name)) {
// Let DartDev handle the default help message.
dart_options->AddArgument("help");
return 0;
@ -532,7 +541,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.
DartDevIsolate::set_should_run_dart_dev(true);
ResolveDartDevSnapshotPath(argv[i], script_name);
if (enable_dartdev_analytics) {
dart_options->AddArgument("--enable-analytics");
@ -545,19 +554,55 @@ int Options::ParseArguments(int argc,
return -1;
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
const char** vm_argv = temp_vm_options.arguments();
int vm_argc = temp_vm_options.count();
vm_options->AddArguments(vm_argv, vm_argc);
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<const char**>(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.
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 !defined(DART_PRECOMPILED_RUNTIME)
if (!enabled_experiments_.is_empty() &&
!(Options::disable_dart_dev() || run_script)) {
const char* kEnableExperiment = "--enable-experiment=";
intptr_t num_experiments = enabled_experiments_.length();
int option_size = strlen(kEnableExperiment);
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);
@ -570,34 +615,24 @@ int Options::ParseArguments(int argc,
++option_size;
char* enabled_experiments_arg = new char[option_size];
int offset =
snprintf(enabled_experiments_arg, option_size, "%s", kEnableExperiment);
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);
free(const_cast<char*>(flag));
ASSERT(offset < option_size);
}
DartDevIsolate::set_should_run_dart_dev(true);
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.

View file

@ -18,11 +18,7 @@ class _HtmlWebSocket implements CommonWebSocket {
void connect(String address, void onOpen(), void onMessage(dynamic data),
void onError(), void onClose()) {
// 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 = new WebSocket(address);
_webSocket.onClose.listen((CloseEvent) => onClose());
_webSocket.onError.listen((Event) => onError());
_webSocket.onOpen.listen((Event) => onOpen());

View file

@ -1117,9 +1117,6 @@ 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;

View file

@ -47,7 +47,6 @@ declare_args() {
# ........analysis_server.dart.snapshot
# ........dart2js.dart.snapshot
# ........dartanalyzer.dart.snapshot
# ........dds.dart.snapshot
# ........dartdev.dart.snapshot
# ........dartdoc.dart.snapshot
# ........dartfmt.dart.snapshot
@ -134,10 +133,6 @@ _platform_sdk_snapshots = [
"dartfmt",
"../utils/dartfmt",
],
[
"dds",
"../utils/dds:generate_dds_snapshot",
],
[
"pub",
"../utils/pub",
@ -187,10 +182,6 @@ _full_sdk_snapshots = [
"dartfmt",
"../utils/dartfmt",
],
[
"dds",
"../utils/dds:generate_dds_snapshot",
],
[
"kernel_worker",
"../utils/bazel:kernel_worker",

View file

@ -354,41 +354,14 @@ 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;

View file

@ -4,6 +4,8 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
import 'package:path/path.dart' as p;
import 'package:expect/expect.dart';
Future<void> main() async {

View file

@ -4,6 +4,8 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
import 'package:path/path.dart' as p;
import 'package:expect/expect.dart';
Future<void> main() async {

View file

@ -4,6 +4,8 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
import 'package:path/path.dart' as p;
import 'package:expect/expect.dart';
Future<void> main() async {

View file

@ -4,6 +4,8 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
import 'package:path/path.dart' as p;
import 'package:expect/expect.dart';
Future<void> main() async {

View file

@ -17,6 +17,14 @@ 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" ]
}
@ -31,6 +39,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
inputs = dartdev_files + dartfix_files + dds_files
output = "$root_gen_dir/dartdev.dart.snapshot"
}

View file

@ -1,30 +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.
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"
}