diff --git a/pkg/dart2wasm/bin/run_wasm.js b/pkg/dart2wasm/bin/run_wasm.js index cf6096febaa..f6886bb7ce4 100644 --- a/pkg/dart2wasm/bin/run_wasm.js +++ b/pkg/dart2wasm/bin/run_wasm.js @@ -11,6 +11,14 @@ // -- /abs/path/to/.mjs .wasm [.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 -- .ms .wasm \ +// [-- Dart commandline arguments...] +// // Run as follows on JSShell: // // $> js run_wasm.js \ @@ -36,6 +44,19 @@ const jsRuntimeArg = 0; 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 @@ const ffiArg = 2; } 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 @@ const ffiArg = 2; } action = nextEvent(); } + if (isJSC) asyncTestPassed(); } // Global properties. "self" refers to the global object, so adding a @@ -315,17 +343,11 @@ const ffiArg = 2; 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 main = async () => { 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 dc59d215703..a050b61d385 100644 --- a/pkg/dart2wasm/lib/js/runtime_blob.dart +++ b/pkg/dart2wasm/lib/js/runtime_blob.dart @@ -67,6 +67,20 @@ const jsRuntimeBlobPart2JSCM = r''' '''; 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 @@ const jsRuntimeBlobPart3 = r''' } 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 1df9816157a..346539fdc37 100644 --- a/pkg/smith/lib/configuration.dart +++ b/pkg/smith/lib/configuration.dart @@ -868,6 +868,7 @@ class Compiler extends NamedEnum { case Compiler.dart2wasm: return const [ Runtime.none, + Runtime.jsc, Runtime.jsshell, Runtime.d8, Runtime.chrome, @@ -980,6 +981,7 @@ class Runtime extends NamedEnum { 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 @@ class Runtime extends NamedEnum { flutter, dartPrecompiled, d8, + jsc, jsshell, firefox, chrome, @@ -1035,7 +1038,7 @@ class Runtime extends NamedEnum { 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 @@ class Runtime extends NamedEnum { 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 0e7e0f2b4cd..d07b1f1f288 100644 --- a/pkg/test_runner/lib/src/compiler_configuration.dart +++ b/pkg/test_runner/lib/src/compiler_configuration.dart @@ -610,11 +610,12 @@ class Dart2WasmCompilerConfiguration extends CompilerConfiguration { 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 1cbe554cd02..c11820384ad 100644 --- a/pkg/test_runner/lib/src/options.dart +++ b/pkg/test_runner/lib/src/options.dart @@ -87,8 +87,9 @@ fasta: Compile using CFE for errors, but do not run. 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 0b426378bdb..643b75f227b 100644 --- a/pkg/test_runner/lib/src/runtime_configuration.dart +++ b/pkg/test_runner/lib/src/runtime_configuration.dart @@ -31,6 +31,9 @@ abstract class RuntimeConfiguration { // 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 @@ abstract class RuntimeConfiguration { 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 @@ class D8RuntimeConfiguration extends CommandLineJavaScriptRuntime { } } +/// Safari/WebKit/JavaScriptCore-based development shell (jsc). +class JSCRuntimeConfiguration extends CommandLineJavaScriptRuntime { + final Compiler compiler; + + JSCRuntimeConfiguration(this.compiler) : super('jsc'); + + @override + List computeRuntimeCommands( + CommandArtifact? artifact, + List arguments, + Map environmentOverrides, + List 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 f7ee492a3a2..3dca9f48d0f 100644 --- a/sdk/lib/_internal/wasm/lib/print_patch.dart +++ b/sdk/lib/_internal/wasm/lib/print_patch.dart @@ -6,4 +6,4 @@ part of "internal_patch.dart"; @patch void printToConsole(String line) => - JS('s => console.log(stringFromDartString(s))'); + JS('s => printToConsole(stringFromDartString(s))'); diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index be531eca7c4..9fca581c4c0 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",