[vm] Introduce --script_uri_override to support Platform.script in dart run -r

If a script uses `Platform.script` running it with as `dart
<script.dart>` and `dart run <script.dart>` would give the correct
script ("<script.dart>"), but running it with `dart run -r
<script.dart>` would report a dill file in the temp directory which is
not only surprising, but also breaking and for instance running the CFEs
strong_suite.dart via `dart run -r` didn't work.

This CL introduces --script_uri_override to the VM and makes the
resident compiler setup pass it so that when running `dart run -r
<script.dart>`, even though the vm is actually launched from a dill file
that resides in temp, `Platform.script` will actually return
`<script.dart>` - and running the CFEs strong_suite.dart via `dart run
-r` now actually works.

Tested: Added pkg/dartdev/test/commands/run_test.dart and manual testing.
Change-Id: Ia65c01834485fe06af63584baf0448dd5b9ffdb4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510343
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen
2026-06-11 06:34:20 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent f3d47ab020
commit b32e313620
6 changed files with 152 additions and 12 deletions
+4
View File
@@ -550,6 +550,7 @@ See https://dart.dev/to/package-descriptors for more details.''', verbose) {
log.stderr(e.message);
return errorExitCode;
}
DartExecutableWithPackageConfig executableOriginal = executable;
if (useResidentCompiler) {
final File? residentCompilerInfoFile =
@@ -616,6 +617,9 @@ See https://dart.dev/to/package-descriptors for more details.''', verbose) {
packageConfigOverride:
args.option('packages') ?? executable.packageConfig,
useExecProcess: true,
scriptUriOverride: identical(executable, executableOriginal)
? null
: executableOriginal.executable,
);
return 0;
}
@@ -34,6 +34,11 @@ abstract class VmInteropHandler {
// See https://github.com/dart-lang/sdk/issues/53576
bool markMainIsolateAsSystemIsolate = false,
bool useExecProcess = false,
/// When [useExecProcess] pass this path to signal that it originates from
/// another file. Used for launching from a dill file while behaving as if
/// launched directly from a dart file.
String? scriptUriOverride,
}) {
List<String> argsList;
if (useExecProcess && Platform.isWindows) {
@@ -45,6 +50,12 @@ abstract class VmInteropHandler {
// Escape paths that may contain spaces
script = '"$script"';
}
if (scriptUriOverride != null &&
scriptUriOverride.contains(' ') &&
!scriptUriOverride.contains('"')) {
// Escape paths that may contain spaces
scriptUriOverride = '"$scriptUriOverride"';
}
argsList = [
for (int i = 0; i < args.length; i++) _windowsArgumentEscape(args[i]),
];
@@ -57,6 +68,7 @@ abstract class VmInteropHandler {
final message = <dynamic>[
useExecProcess ? _kResultRunExec : _kResultRun,
script,
if (useExecProcess) scriptUriOverride,
packageConfigOverride,
markMainIsolateAsSystemIsolate,
argsList,
+89
View File
@@ -972,6 +972,95 @@ Future<void> main() async {
expect(result.exitCode, 0);
});
test(
'resident compiler invocation has working Platform.script',
() async {
p = project(name: 'foo');
p.file('pubspec.yaml', '''
name: foo
environment:
sdk: '>=2.12.0<3.0.0'
''');
p.file('bin/script1.dart', r'''
import "dart:io";
import "dart:isolate";
Future<void> main() async {
print("Script1: ${Platform.script}");
var exitPort = ReceivePort();
var isolate = await Isolate.spawn(
entryPoint,
"",
onExit: exitPort.sendPort,
);
await exitPort.first;
exitPort = ReceivePort();
await Isolate.spawnUri(
Uri.parse("script2.dart"),
[],
"",
onExit: exitPort.sendPort,
);
await exitPort.first;
}
void entryPoint(String arg) {
print(" -> ${Platform.script}");
}
''');
p.file('bin/script2.dart', r'''
import "dart:io";
import "dart:isolate";
Future<void> main() async {
print("Script2: ${Platform.script}");
var exitPort = ReceivePort();
var isolate = await Isolate.spawn(
entryPoint,
"",
onExit: exitPort.sendPort,
);
await exitPort.first;
}
void entryPoint(String arg) {
print(" -> ${Platform.script}");
}
''');
var script1 = File(path.join(p.dir.path, 'bin/script1.dart'));
expect(script1.existsSync(), true);
var script2 = File(path.join(p.dir.path, 'bin/script2.dart'));
expect(script2.existsSync(), true);
ProcessResult pubGetResult = await p.run(['pub', 'get']);
expect(pubGetResult.stderr, isEmpty);
expect(pubGetResult.exitCode, 0);
ProcessResult result = await p.run([
'run',
'--resident',
'--$residentCompilerInfoFileOption=$serverInfoFile',
'bin/script1.dart',
]);
String stdout = result.stdout.toString().trim();
expect(
stdout,
'''
Script1: ${script1.uri}
-> ${script1.uri}
Script2: ${script2.uri}
-> ${script2.uri}
'''
.trim(),
);
expect(result.stderr, isEmpty);
expect(result.exitCode, 0);
},
);
test(
'passing --resident is a prerequisite for passing --resident-compiler-info-file',
() async {
+40 -9
View File
@@ -606,33 +606,48 @@ class DartDev {
Syslog::PrintErr("Unable to locate the Dart VM executable");
Platform::Exit(kErrorExitCode);
}
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
// scriptUriOverride.
auto item2 = GetArrayItem(message, 2);
ASSERT(item2->type == Dart_CObject_kString ||
item2->type == Dart_CObject_kNull);
// packageConfigOverride.
auto item3 = GetArrayItem(message, 3);
ASSERT(item3->type == Dart_CObject_kString ||
item3->type == Dart_CObject_kNull);
package_config_override_ = nullptr;
if (item2->type == Dart_CObject_kString) {
package_config_override_ = Utils::StrDup(item2->value.as_string);
if (item3->type == Dart_CObject_kString) {
package_config_override_ = Utils::StrDup(item3->value.as_string);
}
intptr_t num_vm_options = dart_vm_options_->count();
const char** vm_options = dart_vm_options_->arguments();
ASSERT(GetArrayItem(message, 4)->type == Dart_CObject_kArray);
Dart_CObject* args = GetArrayItem(message, 4);
// markMainIsolateAsSystemIsolate
auto item4 = GetArrayItem(message, 4);
ASSERT(item4->type == Dart_CObject_kBool);
const bool mark_main_isolate_as_system_isolate = item4->value.as_bool;
// argsList
ASSERT(GetArrayItem(message, 5)->type == Dart_CObject_kArray);
Dart_CObject* args = GetArrayItem(message, 5);
intptr_t argc = args->value.as_array.length;
Dart_CObject** dart_args = args->value.as_array.values;
auto item3 = GetArrayItem(message, 3);
ASSERT(item3->type == Dart_CObject_kBool);
const bool mark_main_isolate_as_system_isolate = item3->value.as_bool;
auto deleter = [](char** args) {
for (intptr_t i = 0; i < argc_; ++i) {
free(args[i]);
}
delete[] args;
};
intptr_t num_vm_options = dart_vm_options_->count();
const char** vm_options = dart_vm_options_->arguments();
// Total count of arguments to be passed to the script being execed.
if (mark_main_isolate_as_system_isolate) {
argc_ = argc + num_vm_options + 5;
@@ -642,6 +657,9 @@ class DartDev {
if (package_config_override_ != nullptr) {
argc_++;
}
if (item2->type == Dart_CObject_kString) {
argc_++;
}
// Array of arguments to be passed to the script being execed.
argv_ = std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_ + 1],
@@ -697,6 +715,19 @@ class DartDev {
argv_[idx++] = Utils::SCreate("--packages=%s", package_config_override_);
#endif
}
if (item2->value.as_string != nullptr) {
#if defined(DART_HOST_OS_WINDOWS)
char* script_uri_override =
Utils::SCreate("--script_uri_override=%s", item2->value.as_string);
argv_[idx++] = StringUtilsWin::ArgumentEscape(script_uri_override);
free(script_uri_override);
#else
argv_[idx++] =
Utils::SCreate("--script_uri_override=%s", item2->value.as_string);
#endif
}
// Copy in name of the script to run.
argv_[idx++] = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
// Copy in the dart options that need to be passed to the script.
+6 -3
View File
@@ -690,9 +690,12 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
PathSanitizer packages_config_sanitizer(packages_config);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
auto isolate_group_data =
new IsolateGroupData(script_uri, asset_resolution_base, packages_config,
app_snapshot, isolate_run_app_snapshot);
auto isolate_group_data = new IsolateGroupData(
is_main_isolate && Options::script_uri_override() != nullptr
? Options::script_uri_override()
: script_uri,
asset_resolution_base, packages_config, app_snapshot,
isolate_run_app_snapshot);
if (kernel_buffer != nullptr) {
isolate_group_data->SetKernelBufferNewlyOwned(kernel_buffer,
kernel_buffer_size);
+1
View File
@@ -31,6 +31,7 @@ namespace bin {
V(executable_name, executable_name) \
V(resolved_executable_name, resolved_executable_name) \
V(load_module_snapshot, load_module_snapshot) \
V(script_uri_override, script_uri_override) \
/* The purpose of these flags is documented in */ \
/* pkg/dartdev/lib/src/commands/compilation_server.dart. */ \
V(resident_server_info_file, resident_server_info_file_path) \