[dart2wasm] Add support for testing dart2wasm with JSC
JSC only supports `print()` but not `console.log()`.
=> The changes to `printToConsole()` are therefore extended
to check for `console.log()` as well as `print()`.
=> This is extending it to a broader subset of dart2js's print
Change-Id: I7efa697477aa60e473d01716b104fc1526035c67
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347283
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/pkg/dart2wasm/bin/run_wasm.js b/pkg/dart2wasm/bin/run_wasm.js
index cf6096f..f6886bb 100644
--- a/pkg/dart2wasm/bin/run_wasm.js
+++ b/pkg/dart2wasm/bin/run_wasm.js
@@ -11,6 +11,14 @@
// -- /abs/path/to/<dart_module>.mjs <dart_module>.wasm [<ffi_module>.wasm] \
// [-- Dart commandline arguments...]
//
+// Run as follows on JSC:
+//
+// $> export JSC_useWebAssemblyTypedFunctionReferences=1
+// $> export JSC_useWebAssemblyExtendedConstantExpressions=1
+// $> export JSC_useWebAssemblyGC=1
+// $> jsc run_wasm.js -- <dart_module>.ms <dart_module>.wasm \
+// [-- Dart commandline arguments...]
+//
// Run as follows on JSShell:
//
// $> js run_wasm.js \
@@ -36,6 +44,19 @@
const wasmArg = 1;
const ffiArg = 2;
+// This script is intended to be used by D8, JSShell or JSC. We distinguish
+// them by the functions they offer to read files:
+//
+// Engine | Shell | FileRead | Arguments
+// --------------------------------------------------------------
+// V8 | D8 | readbuffer | arguments (arg0 arg1)
+// JavaScriptCore | JSC | readFile | arguments (arg0 arg1)
+// SpiderMonkey | JSShell | readRelativeToScript | scriptArgs (-- arg0 arg1)
+//
+const isD8 = (typeof readbuffer === "function");
+const isJSC = (typeof readFile === "function");
+const isJSShell = (typeof readRelativeToScript === "function");
+
// d8's `setTimeout` doesn't work as expected (it doesn't wait before calling
// the callback), and d8 also doesn't have `setInterval` and `queueMicrotask`.
// So we define our own event loop with these functions.
@@ -282,10 +303,16 @@
}
async function eventLoop(action) {
+ if (isJSC) asyncTestStart(1);
while (action) {
try {
await action();
} catch (e) {
+ // JSC doesn't report/print uncaught async exceptions for some reason.
+ if (isJSC) {
+ print('Error: ' + e);
+ print('Stack: ' + e.stack);
+ }
if (typeof onerror == "function") {
onerror(e, null, -1);
} else {
@@ -294,6 +321,7 @@
}
action = nextEvent();
}
+ if (isJSC) asyncTestPassed();
}
// Global properties. "self" refers to the global object, so adding a
@@ -315,17 +343,11 @@
self.dartUseDateNowForTicks = true;
})(this, []);
-
-// This script is intended to be used by either D8 or JSShell. We distinguish
-// the two by seeing whether the global `arguments` exists (D8 uses `arguments`
-// and JsShell uses `scriptArgs`).
-var isD8 = (typeof arguments != "undefined");
-
// We would like this itself to be a ES module rather than a script, but
// unfortunately d8 does not return a failed error code if an unhandled
// exception occurs asynchronously in an ES module.
const main = async () => {
- var args = isD8 ? arguments : scriptArgs;
+ var args = (isD8 || isJSC) ? arguments : scriptArgs;
var dartArgs = [];
const argsSplit = args.indexOf("--");
if (argsSplit != -1) {
@@ -336,7 +358,14 @@
const dart2wasm = await import(args[jsRuntimeArg]);
function compile(filename) {
// Create a Wasm module from the binary wasm file.
- var bytes = isD8 ? readbuffer(filename) : readRelativeToScript(filename, "binary") ;
+ var bytes;
+ if (isJSC) {
+ bytes = readFile(filename, "binary");
+ } else if (isD8) {
+ bytes = readbuffer(filename);
+ } else {
+ bytes = readRelativeToScript(filename, "binary");
+ }
return new WebAssembly.Module(bytes);
}
diff --git a/pkg/dart2wasm/lib/js/runtime_blob.dart b/pkg/dart2wasm/lib/js/runtime_blob.dart
index dc59d21..a050b61 100644
--- a/pkg/dart2wasm/lib/js/runtime_blob.dart
+++ b/pkg/dart2wasm/lib/js/runtime_blob.dart
@@ -67,6 +67,20 @@
''';
const jsRuntimeBlobPart3 = r'''
+ // Prints to the console
+ function printToConsole(value) {
+ if (typeof console == "object" && typeof console.log != "undefined") {
+ console.log(value);
+ return;
+ }
+ if (typeof print == "function") {
+ print(value);
+ return;
+ }
+
+ throw "Unable to print message: " + js;
+ }
+
// Converts a Dart List to a JS array. Any Dart objects will be converted, but
// this will be cheap for JSValues.
function arrayFromDartList(constructor, list) {
@@ -96,7 +110,7 @@
}
if (WebAssembly.String === undefined) {
- console.log("WebAssembly.String is undefined, adding polyfill");
+ printToConsole("WebAssembly.String is undefined, adding polyfill");
WebAssembly.String = {
"charCodeAt": (s, i) => s.charCodeAt(i),
"compare": (s1, s2) => {
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index 1df9816..346539f 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -868,6 +868,7 @@
case Compiler.dart2wasm:
return const [
Runtime.none,
+ Runtime.jsc,
Runtime.jsshell,
Runtime.d8,
Runtime.chrome,
@@ -980,6 +981,7 @@
static const flutter = Runtime._('flutter');
static const dartPrecompiled = Runtime._('dart_precompiled');
static const d8 = Runtime._('d8');
+ static const jsc = Runtime._('jsc');
static const jsshell = Runtime._('jsshell');
static const firefox = Runtime._('firefox');
static const chrome = Runtime._('chrome');
@@ -998,6 +1000,7 @@
flutter,
dartPrecompiled,
d8,
+ jsc,
jsshell,
firefox,
chrome,
@@ -1035,7 +1038,7 @@
bool get isSafari => name.startsWith("safari");
/// Whether this runtime is a command-line JavaScript environment.
- bool get isJSCommandLine => const [d8, jsshell].contains(this);
+ bool get isJSCommandLine => const [d8, jsc, jsshell].contains(this);
/// If the runtime doesn't support `Window.open`, we use iframes instead.
bool get requiresIFrame => !const [ie11, ie10].contains(this);
@@ -1063,6 +1066,9 @@
case chromeOnAndroid:
return Compiler.dart2js;
+ case jsc:
+ return Compiler.dart2wasm;
+
case none:
// If we aren't running it, we probably just want to analyze it.
return Compiler.dart2analyzer;
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 0e7e0f2..d07b1f1 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -610,11 +610,12 @@
final filename = artifact!.filename;
final args = testFile.dartOptions;
final isD8 = runtimeConfiguration is D8RuntimeConfiguration;
+ final isJSC = runtimeConfiguration is JSCRuntimeConfiguration;
return [
if (isD8) '--turboshaft-wasm',
if (isD8) '--experimental-wasm-imported-strings',
'pkg/dart2wasm/bin/run_wasm.js',
- if (isD8) '--',
+ if (isD8 || isJSC) '--',
'${filename.substring(0, filename.lastIndexOf('.'))}.mjs',
filename,
...testFile.sharedObjects
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 1cbe554..c118203 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -87,8 +87,9 @@
help: '''Where the tests should be run.
vm: Run Dart code on the standalone Dart VM.
dart_precompiled: Run a precompiled snapshot on the VM without a JIT.
-d8: Run JavaScript from the command line using v8.
-jsshell: Run JavaScript from the command line using Firefox js-shell.
+d8: Run JavaScript from the command line using Chrome's v8.
+jsc: Run JavaScript from the command line using Safari/WebKit's jsc.
+jsshell: Run JavaScript from the command line using Firefox's js-shell.
firefox:
chrome:
diff --git a/pkg/test_runner/lib/src/runtime_configuration.dart b/pkg/test_runner/lib/src/runtime_configuration.dart
index 0b42637..643b75f 100644
--- a/pkg/test_runner/lib/src/runtime_configuration.dart
+++ b/pkg/test_runner/lib/src/runtime_configuration.dart
@@ -31,6 +31,9 @@
// TODO(ahe): Replace this with one or more browser runtimes.
return DummyRuntimeConfiguration();
+ case Runtime.jsc:
+ return JSCRuntimeConfiguration(configuration.compiler);
+
case Runtime.jsshell:
return JsshellRuntimeConfiguration(configuration.compiler);
@@ -144,6 +147,15 @@
return d8;
}
+ String get jscFileName {
+ final d8Dir = Repository.dir.append('third_party/jsc');
+ final d8Path = d8Dir.append(
+ '${Platform.operatingSystem}/${Architecture.host}/jsc$executableExtension');
+ final d8 = d8Path.toNativePath();
+ TestUtils.ensureExists(d8, _configuration);
+ return d8;
+ }
+
String get jsShellFileName {
var executable = 'jsshell$executableExtension';
var jsshellDir = Repository.uri.resolve("tools/testing/bin").path;
@@ -218,6 +230,35 @@
}
}
+/// Safari/WebKit/JavaScriptCore-based development shell (jsc).
+class JSCRuntimeConfiguration extends CommandLineJavaScriptRuntime {
+ final Compiler compiler;
+
+ JSCRuntimeConfiguration(this.compiler) : super('jsc');
+
+ @override
+ List<Command> computeRuntimeCommands(
+ CommandArtifact? artifact,
+ List<String> arguments,
+ Map<String, String> environmentOverrides,
+ List<String> extraLibs,
+ bool isCrashExpected) {
+ checkArtifact(artifact!);
+ if (compiler != Compiler.dart2wasm) {
+ throw 'No test runner setup for jsc + dart2js yet';
+ }
+ final environment = {
+ ...environmentOverrides,
+ 'JSC_useWebAssemblyTypedFunctionReferences': '1',
+ 'JSC_useWebAssemblyExtendedConstantExpression': '1',
+ 'JSC_useWebAssemblyGC': '1',
+ };
+ return [
+ Dart2WasmCommandLineCommand(moniker, jscFileName, arguments, environment)
+ ];
+ }
+}
+
/// Firefox/SpiderMonkey-based development shell (jsshell).
class JsshellRuntimeConfiguration extends CommandLineJavaScriptRuntime {
final Compiler compiler;
diff --git a/sdk/lib/_internal/wasm/lib/print_patch.dart b/sdk/lib/_internal/wasm/lib/print_patch.dart
index f7ee492..3dca9f4 100644
--- a/sdk/lib/_internal/wasm/lib/print_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/print_patch.dart
@@ -6,4 +6,4 @@
@patch
void printToConsole(String line) =>
- JS<void>('s => console.log(stringFromDartString(s))');
+ JS<void>('s => printToConsole(stringFromDartString(s))');
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index be531ec..9fca581 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -451,7 +451,7 @@
"timeout": 240
}
},
- "dart2wasm-(linux|mac|win)-(d8|jsshell|chrome|firefox)": {
+ "dart2wasm-(linux|mac|win)-(d8|jsshell|jsc|chrome|firefox)": {
"options": {
"host-checked": true,
"dart2wasm-options": [
@@ -460,7 +460,7 @@
"timeout": 240
}
},
- "dart2wasm-(linux|mac|win)-optimized-(d8|jsshell|chrome|firefox)": {
+ "dart2wasm-(linux|mac|win)-optimized-(d8|jsshell|jsc|chrome|firefox)": {
"options": {
"dart2wasm-options": [
"--optimize"
@@ -469,7 +469,7 @@
"timeout": 240
}
},
- "dart2wasm-(linux|mac|win)-jscm-(d8|jsshell|chrome|firefox)": {
+ "dart2wasm-(linux|mac|win)-jscm-(d8|jsshell|jsc|chrome|firefox)": {
"options": {
"dart2wasm-options": [
"--no-optimize",