[dart2wasm] Update built-in string imports according to the latest spec

Spec: https://github.com/WebAssembly/js-string-builtins

Change-Id: Idb387e6dd27b203ddca52291c44fb2aa15ee75cf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357560
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Ömer Sinan Ağacan 2024-03-19 08:20:59 +00:00 committed by Commit Queue
parent ef07a17210
commit 44c2e17600
3 changed files with 76 additions and 42 deletions

View file

@ -363,8 +363,20 @@ const main = async () => {
}
const dart2wasm = await import(args[jsRuntimeArg]);
function compile(filename) {
// Create a Wasm module from the binary wasm file.
/// Returns whether the `js-string` built-in is supported.
function detectImportedStrings() {
let bytes = [
0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0,
0, 2, 23, 1, 14, 119, 97, 115, 109, 58, 106, 115, 45,
115, 116, 114, 105, 110, 103, 4, 99, 97, 115, 116, 0, 0
];
return !WebAssembly.validate(
new Uint8Array(bytes), {builtins: ['js-string']});
}
function compile(filename, withJsStringBuiltins) {
// Create a Wasm module from the binary Wasm file.
var bytes;
if (isJSC) {
bytes = readFile(filename, "binary");
@ -373,11 +385,10 @@ const main = async () => {
} else {
bytes = readRelativeToScript(filename, "binary");
}
return new WebAssembly.Module(bytes);
}
function instantiate(filename, imports) {
return new WebAssembly.Instance(compile(filename), imports);
return WebAssembly.compile(
bytes,
withJsStringBuiltins ? {builtins: ['js-string']} : {}
);
}
globalThis.window ??= globalThis;
@ -386,14 +397,17 @@ const main = async () => {
// Is an FFI module specified?
if (args.length > 2) {
// instantiate FFI module
var ffiInstance = instantiate(args[ffiArg], {});
// Make its exports available as imports under the 'ffi' module name
// Instantiate FFI module.
var ffiInstance = await WebAssembly.instantiate(await compile(args[ffiArg], false), {});
// Make its exports available as imports under the 'ffi' module name.
importObject.ffi = ffiInstance.exports;
}
// Instantiate the Dart module, importing from the global scope.
var dartInstance = await dart2wasm.instantiate(Promise.resolve(compile(args[wasmArg])), Promise.resolve(importObject));
var dartInstance = await dart2wasm.instantiate(
compile(args[wasmArg], detectImportedStrings()),
Promise.resolve(importObject),
);
// Call `main`. If tasks are placed into the event loop (by scheduling tasks
// explicitly or awaiting Futures), these will automatically keep the script

View file

@ -113,22 +113,6 @@ const jsRuntimeBlobPart3 = r'''
return wrapped;
}
if (WebAssembly.String === undefined) {
WebAssembly.String = {
"charCodeAt": (s, i) => s.charCodeAt(i),
"compare": (s1, s2) => {
if (s1 < s2) return -1;
if (s1 > s2) return 1;
return 0;
},
"concat": (s1, s2) => s1 + s2,
"equals": (s1, s2) => s1 === s2,
"fromCharCode": (i) => String.fromCharCode(i),
"length": (s) => s.length,
"substring": (s, a, b) => s.substring(a, b),
};
}
// Imports
const dart2wasm = {
''';
@ -150,9 +134,25 @@ const jsRuntimeBlobPart5 = r'''
Array: Array,
Reflect: Reflect,
};
const jsStringPolyfill = {
"charCodeAt": (s, i) => s.charCodeAt(i),
"compare": (s1, s2) => {
if (s1 < s2) return -1;
if (s1 > s2) return 1;
return 0;
},
"concat": (s1, s2) => s1 + s2,
"equals": (s1, s2) => s1 === s2,
"fromCharCode": (i) => String.fromCharCode(i),
"length": (s) => s.length,
"substring": (s, a, b) => s.substring(a, b),
};
dartInstance = await WebAssembly.instantiate(await modulePromise, {
...baseImports,
...(await importObjectPromise),
"wasm:js-string": jsStringPolyfill,
});
return dartInstance;

View file

@ -81,7 +81,8 @@ final class JSStringImpl implements String {
@override
String operator +(String other) {
if (other is JSStringImpl) {
return JSStringImpl(_jsConcat(toExternRef, other.toExternRef));
return JSStringImpl(
_jsStringConcatImport(toExternRef, other.toExternRef));
}
// TODO(joshualitt): Refactor `string_patch.dart` so we can directly
@ -712,32 +713,51 @@ bool _jsIdentical(WasmExternRef? ref1, WasmExternRef? ref2) =>
js.JS<bool>('Object.is', ref1, ref2);
@pragma("wasm:prefer-inline")
int _jsCharCodeAt(WasmExternRef? stringRef, int index) => js
.JS<WasmI32>(
'WebAssembly.String.charCodeAt', stringRef, WasmI32.fromInt(index))
.toIntUnsigned();
WasmExternRef _jsConcat(WasmExternRef? s1, WasmExternRef? s2) =>
js.JS<WasmExternRef>('WebAssembly.String.concat', s1, s2);
int _jsCharCodeAt(WasmExternRef? stringRef, int index) =>
_jsStringCharCodeAtImport(stringRef, WasmI32.fromInt(index))
.toIntUnsigned();
@pragma("wasm:prefer-inline")
WasmExternRef _jsSubstring(
WasmExternRef? stringRef, int startIndex, int endIndex) =>
js.JS<WasmExternRef>('WebAssembly.String.substring', stringRef,
WasmI32.fromInt(startIndex), WasmI32.fromInt(endIndex));
_jsStringSubstringImport(
stringRef, WasmI32.fromInt(startIndex), WasmI32.fromInt(endIndex));
@pragma("wasm:prefer-inline")
int _jsLength(WasmExternRef? stringRef) =>
js.JS<WasmI32>('WebAssembly.String.length', stringRef).toIntUnsigned();
_jsStringLengthImport(stringRef).toIntUnsigned();
@pragma("wasm:prefer-inline")
bool _jsEquals(WasmExternRef? s1, WasmExternRef? s2) =>
js.JS<WasmI32>('WebAssembly.String.equals', s1, s2).toBool();
_jsStringEqualsImport(s1, s2).toBool();
@pragma("wasm:prefer-inline")
int _jsCompare(WasmExternRef? s1, WasmExternRef? s2) =>
js.JS<WasmI32>('WebAssembly.String.compare', s1, s2).toIntSigned();
_jsStringCompareImport(s1, s2).toIntSigned();
@pragma("wasm:prefer-inline")
WasmExternRef _jsFromCharCode(int charCode) => js.JS<WasmExternRef>(
'WebAssembly.String.fromCharCode', WasmI32.fromInt(charCode));
WasmExternRef _jsFromCharCode(int charCode) =>
_jsStringFromCharCodeImport(WasmI32.fromInt(charCode));
@pragma("wasm:import", "wasm:js-string.charCodeAt")
external WasmI32 _jsStringCharCodeAtImport(WasmExternRef? s, WasmI32 index);
@pragma("wasm:import", "wasm:js-string.compare")
external WasmI32 _jsStringCompareImport(WasmExternRef? s1, WasmExternRef? s2);
@pragma("wasm:import", "wasm:js-string.concat")
external WasmExternRef _jsStringConcatImport(
WasmExternRef? s1, WasmExternRef? s2);
@pragma("wasm:import", "wasm:js-string.equals")
external WasmI32 _jsStringEqualsImport(WasmExternRef? s1, WasmExternRef? s2);
@pragma("wasm:import", "wasm:js-string.fromCharCode")
external WasmExternRef _jsStringFromCharCodeImport(WasmI32 c);
@pragma("wasm:import", "wasm:js-string.length")
external WasmI32 _jsStringLengthImport(WasmExternRef? s);
@pragma("wasm:import", "wasm:js-string.substring")
external WasmExternRef _jsStringSubstringImport(
WasmExternRef? s, WasmI32 startIndex, WasmI32 endIndex);