Skip to content

Commit 44c2e17

Browse files
osa1Commit Queue
authored andcommitted
[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 <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent ef07a17 commit 44c2e17

File tree

3 files changed

+76
-42
lines changed

3 files changed

+76
-42
lines changed

pkg/dart2wasm/bin/run_wasm.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,20 @@ const main = async () => {
363363
}
364364

365365
const dart2wasm = await import(args[jsRuntimeArg]);
366-
function compile(filename) {
367-
// Create a Wasm module from the binary wasm file.
366+
367+
/// Returns whether the `js-string` built-in is supported.
368+
function detectImportedStrings() {
369+
let bytes = [
370+
0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0,
371+
0, 2, 23, 1, 14, 119, 97, 115, 109, 58, 106, 115, 45,
372+
115, 116, 114, 105, 110, 103, 4, 99, 97, 115, 116, 0, 0
373+
];
374+
return !WebAssembly.validate(
375+
new Uint8Array(bytes), {builtins: ['js-string']});
376+
}
377+
378+
function compile(filename, withJsStringBuiltins) {
379+
// Create a Wasm module from the binary Wasm file.
368380
var bytes;
369381
if (isJSC) {
370382
bytes = readFile(filename, "binary");
@@ -373,11 +385,10 @@ const main = async () => {
373385
} else {
374386
bytes = readRelativeToScript(filename, "binary");
375387
}
376-
return new WebAssembly.Module(bytes);
377-
}
378-
379-
function instantiate(filename, imports) {
380-
return new WebAssembly.Instance(compile(filename), imports);
388+
return WebAssembly.compile(
389+
bytes,
390+
withJsStringBuiltins ? {builtins: ['js-string']} : {}
391+
);
381392
}
382393

383394
globalThis.window ??= globalThis;
@@ -386,14 +397,17 @@ const main = async () => {
386397

387398
// Is an FFI module specified?
388399
if (args.length > 2) {
389-
// instantiate FFI module
390-
var ffiInstance = instantiate(args[ffiArg], {});
391-
// Make its exports available as imports under the 'ffi' module name
400+
// Instantiate FFI module.
401+
var ffiInstance = await WebAssembly.instantiate(await compile(args[ffiArg], false), {});
402+
// Make its exports available as imports under the 'ffi' module name.
392403
importObject.ffi = ffiInstance.exports;
393404
}
394405

395406
// Instantiate the Dart module, importing from the global scope.
396-
var dartInstance = await dart2wasm.instantiate(Promise.resolve(compile(args[wasmArg])), Promise.resolve(importObject));
407+
var dartInstance = await dart2wasm.instantiate(
408+
compile(args[wasmArg], detectImportedStrings()),
409+
Promise.resolve(importObject),
410+
);
397411

398412
// Call `main`. If tasks are placed into the event loop (by scheduling tasks
399413
// explicitly or awaiting Futures), these will automatically keep the script

pkg/dart2wasm/lib/js/runtime_blob.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,6 @@ const jsRuntimeBlobPart3 = r'''
113113
return wrapped;
114114
}
115115
116-
if (WebAssembly.String === undefined) {
117-
WebAssembly.String = {
118-
"charCodeAt": (s, i) => s.charCodeAt(i),
119-
"compare": (s1, s2) => {
120-
if (s1 < s2) return -1;
121-
if (s1 > s2) return 1;
122-
return 0;
123-
},
124-
"concat": (s1, s2) => s1 + s2,
125-
"equals": (s1, s2) => s1 === s2,
126-
"fromCharCode": (i) => String.fromCharCode(i),
127-
"length": (s) => s.length,
128-
"substring": (s, a, b) => s.substring(a, b),
129-
};
130-
}
131-
132116
// Imports
133117
const dart2wasm = {
134118
''';
@@ -150,9 +134,25 @@ const jsRuntimeBlobPart5 = r'''
150134
Array: Array,
151135
Reflect: Reflect,
152136
};
137+
138+
const jsStringPolyfill = {
139+
"charCodeAt": (s, i) => s.charCodeAt(i),
140+
"compare": (s1, s2) => {
141+
if (s1 < s2) return -1;
142+
if (s1 > s2) return 1;
143+
return 0;
144+
},
145+
"concat": (s1, s2) => s1 + s2,
146+
"equals": (s1, s2) => s1 === s2,
147+
"fromCharCode": (i) => String.fromCharCode(i),
148+
"length": (s) => s.length,
149+
"substring": (s, a, b) => s.substring(a, b),
150+
};
151+
153152
dartInstance = await WebAssembly.instantiate(await modulePromise, {
154153
...baseImports,
155154
...(await importObjectPromise),
155+
"wasm:js-string": jsStringPolyfill,
156156
});
157157
158158
return dartInstance;

sdk/lib/_internal/wasm/lib/js_string.dart

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ final class JSStringImpl implements String {
8181
@override
8282
String operator +(String other) {
8383
if (other is JSStringImpl) {
84-
return JSStringImpl(_jsConcat(toExternRef, other.toExternRef));
84+
return JSStringImpl(
85+
_jsStringConcatImport(toExternRef, other.toExternRef));
8586
}
8687

8788
// TODO(joshualitt): Refactor `string_patch.dart` so we can directly
@@ -712,32 +713,51 @@ bool _jsIdentical(WasmExternRef? ref1, WasmExternRef? ref2) =>
712713
js.JS<bool>('Object.is', ref1, ref2);
713714

714715
@pragma("wasm:prefer-inline")
715-
int _jsCharCodeAt(WasmExternRef? stringRef, int index) => js
716-
.JS<WasmI32>(
717-
'WebAssembly.String.charCodeAt', stringRef, WasmI32.fromInt(index))
718-
.toIntUnsigned();
719-
720-
WasmExternRef _jsConcat(WasmExternRef? s1, WasmExternRef? s2) =>
721-
js.JS<WasmExternRef>('WebAssembly.String.concat', s1, s2);
716+
int _jsCharCodeAt(WasmExternRef? stringRef, int index) =>
717+
_jsStringCharCodeAtImport(stringRef, WasmI32.fromInt(index))
718+
.toIntUnsigned();
722719

723720
@pragma("wasm:prefer-inline")
724721
WasmExternRef _jsSubstring(
725722
WasmExternRef? stringRef, int startIndex, int endIndex) =>
726-
js.JS<WasmExternRef>('WebAssembly.String.substring', stringRef,
727-
WasmI32.fromInt(startIndex), WasmI32.fromInt(endIndex));
723+
_jsStringSubstringImport(
724+
stringRef, WasmI32.fromInt(startIndex), WasmI32.fromInt(endIndex));
728725

729726
@pragma("wasm:prefer-inline")
730727
int _jsLength(WasmExternRef? stringRef) =>
731-
js.JS<WasmI32>('WebAssembly.String.length', stringRef).toIntUnsigned();
728+
_jsStringLengthImport(stringRef).toIntUnsigned();
732729

733730
@pragma("wasm:prefer-inline")
734731
bool _jsEquals(WasmExternRef? s1, WasmExternRef? s2) =>
735-
js.JS<WasmI32>('WebAssembly.String.equals', s1, s2).toBool();
732+
_jsStringEqualsImport(s1, s2).toBool();
736733

737734
@pragma("wasm:prefer-inline")
738735
int _jsCompare(WasmExternRef? s1, WasmExternRef? s2) =>
739-
js.JS<WasmI32>('WebAssembly.String.compare', s1, s2).toIntSigned();
736+
_jsStringCompareImport(s1, s2).toIntSigned();
740737

741738
@pragma("wasm:prefer-inline")
742-
WasmExternRef _jsFromCharCode(int charCode) => js.JS<WasmExternRef>(
743-
'WebAssembly.String.fromCharCode', WasmI32.fromInt(charCode));
739+
WasmExternRef _jsFromCharCode(int charCode) =>
740+
_jsStringFromCharCodeImport(WasmI32.fromInt(charCode));
741+
742+
@pragma("wasm:import", "wasm:js-string.charCodeAt")
743+
external WasmI32 _jsStringCharCodeAtImport(WasmExternRef? s, WasmI32 index);
744+
745+
@pragma("wasm:import", "wasm:js-string.compare")
746+
external WasmI32 _jsStringCompareImport(WasmExternRef? s1, WasmExternRef? s2);
747+
748+
@pragma("wasm:import", "wasm:js-string.concat")
749+
external WasmExternRef _jsStringConcatImport(
750+
WasmExternRef? s1, WasmExternRef? s2);
751+
752+
@pragma("wasm:import", "wasm:js-string.equals")
753+
external WasmI32 _jsStringEqualsImport(WasmExternRef? s1, WasmExternRef? s2);
754+
755+
@pragma("wasm:import", "wasm:js-string.fromCharCode")
756+
external WasmExternRef _jsStringFromCharCodeImport(WasmI32 c);
757+
758+
@pragma("wasm:import", "wasm:js-string.length")
759+
external WasmI32 _jsStringLengthImport(WasmExternRef? s);
760+
761+
@pragma("wasm:import", "wasm:js-string.substring")
762+
external WasmExternRef _jsStringSubstringImport(
763+
WasmExternRef? s, WasmI32 startIndex, WasmI32 endIndex);

0 commit comments

Comments
 (0)