Skip to content

Commit 47a0284

Browse files
authored
Remove TextDecoderWrapper (#16448)
* Remove TextDecoderWrapper, and optimize performance of shared->unshared conversions via compile time analysis, and optimize generated code size. * eslint * Rebaseline test_minimal_runtime_code_size_hello_wasm_worker
1 parent de4cb65 commit 47a0284

File tree

5 files changed

+35
-45
lines changed

5 files changed

+35
-45
lines changed

src/parseTools.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,3 +1205,23 @@ function runtimeKeepalivePop() {
12051205
if (MINIMAL_RUNTIME || (EXIT_RUNTIME == 0 && USE_PTHREADS == 0)) return '';
12061206
return 'runtimeKeepalivePop();';
12071207
}
1208+
1209+
// Some web functions like TextDecoder.decode() may not work with a view of a
1210+
// SharedArrayBuffer, see https://github.com/whatwg/encoding/issues/172
1211+
// To avoid that, this function allows obtaining an unshared copy of an
1212+
// ArrayBuffer.
1213+
function getUnsharedTextDecoderView(heap, start, end) {
1214+
const shared = `${heap}.slice(${start}, ${end})`;
1215+
const unshared = `${heap}.subarray(${start}, ${end})`;
1216+
1217+
// No need to worry about this in non-shared memory builds
1218+
if (!SHARED_MEMORY) return unshared;
1219+
1220+
// If asked to get an unshared view to what we know will be a shared view, or if in -Oz,
1221+
// then unconditionally do a .slice() for smallest code size.
1222+
if (SHRINK_LEVEL == 2 || heap == 'HEAPU8') return shared;
1223+
1224+
// Otherwise, generate a runtime type check: must do a .slice() if looking at a SAB,
1225+
// or can use .subarray() otherwise.
1226+
return `${heap}.buffer instanceof SharedArrayBuffer ? ${shared} : ${unshared}`;
1227+
}

src/runtime_strings.js

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,14 @@
66

77
// runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime.
88

9-
// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
10-
// a copy of that string as a Javascript String object.
11-
12-
#if SHARED_MEMORY && TEXTDECODER
13-
/**
14-
* UTF8Decoder.decode may not work with a view of a SharedArrayBuffer, see
15-
* https://github.com/whatwg/encoding/issues/172
16-
* To avoid that, we wrap around it and add a copy into a normal ArrayBuffer,
17-
* which can still be much faster than creating a string character by
18-
* character.
19-
* @constructor
20-
*/
21-
function TextDecoderWrapper(encoding) {
22-
var textDecoder = new TextDecoder(encoding);
23-
this.decode = (data) => {
24-
#if ASSERTIONS
25-
assert(data instanceof Uint8Array);
26-
#endif
27-
// While we compile with pthreads, this method can be called on side buffers
28-
// as well, such as the stdout buffer in the filesystem code. Only copy when
29-
// we have to.
30-
return textDecoder.decode(data.buffer instanceof SharedArrayBuffer ? new Uint8Array(data) : data);
31-
};
32-
}
33-
#endif
34-
359
#if TEXTDECODER == 2
36-
var UTF8Decoder = new TextDecoder{{{ SHARED_MEMORY ? 'Wrapper' : ''}}}('utf8');
10+
var UTF8Decoder = new TextDecoder('utf8');
3711
#elif TEXTDECODER == 1
38-
var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder{{{ SHARED_MEMORY ? 'Wrapper' : ''}}}('utf8') : undefined;
12+
var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined;
3913
#endif
4014

15+
// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
16+
// a copy of that string as a Javascript String object.
4117
/**
4218
* heapOrArray is either a regular array, or a JavaScript typed array view.
4319
* @param {number} idx
@@ -58,11 +34,11 @@ function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
5834
#endif // TEXTDECODER
5935

6036
#if TEXTDECODER == 2
61-
return UTF8Decoder.decode(heapOrArray.buffer ? heapOrArray.subarray(idx, endPtr) : new Uint8Array(heapOrArray.slice(idx, endPtr)));
37+
return UTF8Decoder.decode(heapOrArray.buffer ? {{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}} : new Uint8Array(heapOrArray.slice(idx, endPtr)));
6238
#else // TEXTDECODER == 2
6339
#if TEXTDECODER
6440
if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
65-
return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
41+
return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}});
6642
} else {
6743
#endif // TEXTDECODER
6844
var str = '';
@@ -133,7 +109,7 @@ function UTF8ToString(ptr, maxBytesToRead) {
133109
if (!ptr) return '';
134110
var maxPtr = ptr + maxBytesToRead;
135111
for (var end = ptr; !(end >= maxPtr) && HEAPU8[end];) ++end;
136-
return UTF8Decoder.decode(HEAPU8.subarray(ptr, end));
112+
return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'end') }}});
137113
#else
138114
return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';
139115
#endif

src/runtime_strings_extra.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ function stringToAscii(str, outPtr) {
3232
// a copy of that string as a Javascript String object.
3333

3434
#if TEXTDECODER == 2
35-
var UTF16Decoder = new TextDecoder{{{ SHARED_MEMORY ? 'Wrapper' : ''}}}('utf-16le');
35+
var UTF16Decoder = new TextDecoder('utf-16le');
3636
#elif TEXTDECODER == 1
37-
var UTF16Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder{{{ SHARED_MEMORY ? 'Wrapper' : ''}}}('utf-16le') : undefined;
37+
var UTF16Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf-16le') : undefined;
3838
#endif
3939

4040
function UTF16ToString(ptr, maxBytesToRead) {
@@ -55,7 +55,7 @@ function UTF16ToString(ptr, maxBytesToRead) {
5555
#if TEXTDECODER != 2
5656
if (endPtr - ptr > 32 && UTF16Decoder) {
5757
#endif // TEXTDECODER != 2
58-
return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));
58+
return UTF16Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'endPtr') }}});
5959
#if TEXTDECODER != 2
6060
} else {
6161
#endif // TEXTDECODER != 2

tests/code_size/hello_wasm_worker_wasm.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
var b = Module;
22

3-
var c = b.$ww;
4-
5-
new function(a) {
6-
new TextDecoder(a);
7-
}("utf8");
8-
9-
var e, f;
3+
var c = b.$ww, e, f;
104

115
e = b.mem || new WebAssembly.Memory({
126
initial: 256,
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 737,
33
"a.html.gz": 433,
4-
"a.js": 813,
5-
"a.js.gz": 501,
4+
"a.js": 765,
5+
"a.js.gz": 475,
66
"a.wasm": 1792,
77
"a.wasm.gz": 989,
8-
"total": 3342,
9-
"total_gz": 1923
8+
"total": 3294,
9+
"total_gz": 1897
1010
}

0 commit comments

Comments
 (0)