Skip to content

Commit 273a3fd

Browse files
authored
Optimise code size of addFunction. NFC (#24594)
I think there is more that could be done here - in particular, `setWasmTableEntry` is only used from `libaddfunction` and likely could be merged into it to unify data structures and updates - but for now just tackled some low-hanging fruits.
1 parent 32dfa06 commit 273a3fd

11 files changed

+59
-71
lines changed

src/lib/libaddfunction.js

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@
77
addToLibrary({
88
// This gives correct answers for everything less than 2^{14} = 16384
99
// I hope nobody is contemplating functions with 16384 arguments...
10-
$uleb128Encode: (n, target) => {
10+
$uleb128EncodeWithLen__internal: true,
11+
$uleb128EncodeWithLen: (arr) => {
12+
const n = arr.length;
1113
#if ASSERTIONS
1214
assert(n < 16384);
1315
#endif
14-
if (n < 128) {
15-
target.push(n);
16-
} else {
17-
target.push((n % 128) | 128, n >> 7);
18-
}
16+
// Note: this LEB128 length encoding produces extra byte for n < 128,
17+
// but we don't care as it's only used in a temporary representation.
18+
return [(n % 128) | 128, n >> 7, ...arr];
1919
},
2020
#if WASM_JS_TYPES
2121
// Converts a signature like 'vii' into a description of the wasm types, like
2222
// { parameters: ['i32', 'i32'], results: [] }.
23+
$sigToWasmTypes__internal: true,
2324
$sigToWasmTypes: (sig) => {
2425
#if ASSERTIONS && !WASM_BIGINT
2526
assert(!sig.includes('j'), 'i64 not permitted in function signatures when WASM_BIGINT is disabled');
@@ -49,49 +50,41 @@ addToLibrary({
4950
return type;
5051
},
5152
#endif
52-
$generateFuncType__deps: ['$uleb128Encode'],
53-
$generateFuncType: (sig, target) => {
54-
var sigRet = sig.slice(0, 1);
55-
var sigParam = sig.slice(1);
56-
var typeCodes = {
57-
'i': 0x7f, // i32
53+
$wasmTypeCodes__internal: true,
54+
// Note: using template literal here instead of plain object
55+
// because jsify serializes objects w/o quotes and Closure will then
56+
// incorrectly mangle the properties.
57+
$wasmTypeCodes: `{
58+
'i': 0x7f, // i32
5859
#if MEMORY64
59-
'p': 0x7e, // i64
60+
'p': 0x7e, // i64
6061
#else
61-
'p': 0x7f, // i32
62+
'p': 0x7f, // i32
6263
#endif
63-
'j': 0x7e, // i64
64-
'f': 0x7d, // f32
65-
'd': 0x7c, // f64
66-
'e': 0x6f, // externref
67-
};
68-
69-
// Parameters, length + signatures
70-
target.push(0x60 /* form: func */);
71-
uleb128Encode(sigParam.length, target);
72-
for (var paramType of sigParam) {
64+
'j': 0x7e, // i64
65+
'f': 0x7d, // f32
66+
'd': 0x7c, // f64
67+
'e': 0x6f, // externref
68+
}`,
69+
70+
$generateTypePack__internal: true,
71+
$generateTypePack__deps: ['$uleb128EncodeWithLen', '$wasmTypeCodes'],
72+
$generateTypePack: (types) => uleb128EncodeWithLen(Array.from(types, (type) => {
73+
var code = wasmTypeCodes[type];
7374
#if ASSERTIONS
74-
assert(paramType in typeCodes, `invalid signature char: ${paramType}`);
75+
assert(code, `invalid signature char: ${type}`);
7576
#endif
76-
target.push(typeCodes[paramType]);
77-
}
77+
return code;
78+
})),
7879

79-
// Return values, length + signatures
80-
// With no multi-return in MVP, either 0 (void) or 1 (anything else)
81-
if (sigRet == 'v') {
82-
target.push(0x00);
83-
} else {
84-
target.push(0x01, typeCodes[sigRet]);
85-
}
86-
},
8780
// Wraps a JS function as a wasm function with a given signature.
8881
#if !WASM2JS
8982
$convertJsFunctionToWasm__deps: [
90-
'$uleb128Encode',
83+
'$uleb128EncodeWithLen',
9184
#if WASM_JS_TYPES
9285
'$sigToWasmTypes',
9386
#endif
94-
'$generateFuncType'
87+
'$generateTypePack'
9588
],
9689
#endif
9790
$convertJsFunctionToWasm: (func, sig) => {
@@ -111,25 +104,23 @@ addToLibrary({
111104
return new WebAssembly.Function(sigToWasmTypes(sig), func);
112105
}
113106
#endif
114-
// The module is static, with the exception of the type section, which is
115-
// generated based on the signature passed in.
116-
var typeSectionBody = [
117-
0x01, // count: 1
118-
];
119-
generateFuncType(sig, typeSectionBody);
120107

121108
// Rest of the module is static
122-
var bytes = [
109+
var bytes = Uint8Array.of(
123110
0x00, 0x61, 0x73, 0x6d, // magic ("\0asm")
124111
0x01, 0x00, 0x00, 0x00, // version: 1
125112
0x01, // Type section code
126-
];
127-
// Write the overall length of the type section followed by the body
128-
uleb128Encode(typeSectionBody.length, bytes);
129-
bytes.push(...typeSectionBody);
130-
131-
// The rest of the module is static
132-
bytes.push(
113+
// The module is static, with the exception of the type section, which is
114+
// generated based on the signature passed in.
115+
...uleb128EncodeWithLen([
116+
0x01, // count: 1
117+
0x60 /* form: func */,
118+
// param types
119+
...generateTypePack(sig.slice(1)),
120+
// return types (for now only supporting [] if `void` and single [T] otherwise)
121+
...generateTypePack(sig[0] === 'v' ? '' : sig[0])
122+
]),
123+
// The rest of the module is static
133124
0x02, 0x07, // import section
134125
// (import "e" "f" (func 0 (type 0)))
135126
0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00,
@@ -140,7 +131,7 @@ addToLibrary({
140131

141132
// We can compile this wasm module synchronously because it is very small.
142133
// This accepts an import (at "e.f"), that it reroutes to an export (at "f")
143-
var module = new WebAssembly.Module(new Uint8Array(bytes));
134+
var module = new WebAssembly.Module(bytes);
144135
var instance = new WebAssembly.Instance(module, { 'e': { 'f': func } });
145136
var wrappedFunc = instance.exports['f'];
146137
return wrappedFunc;
@@ -158,17 +149,19 @@ addToLibrary({
158149
if (freeTableIndexes.length) {
159150
return freeTableIndexes.pop();
160151
}
161-
// Grow the table
152+
#if ASSERTIONS
162153
try {
163-
/** @suppress {checkTypes} */
164-
wasmTable.grow({{{ toIndexType('1') }}});
154+
#endif
155+
// Grow the table
156+
return wasmTable['grow']({{{ toIndexType('1') }}});
157+
#if ASSERTIONS
165158
} catch (err) {
166159
if (!(err instanceof RangeError)) {
167160
throw err;
168161
}
169162
throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.';
170163
}
171-
return {{{ from64Expr('wasmTable.length') }}} - 1;
164+
#endif
172165
},
173166

174167
$updateTableMap__deps: ['$getWasmTableEntry'],

src/lib/libexports.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@ addToLibrary({
1313
if (name[0] == '_') name = name.slice(1);
1414
var exportedFunc = wasmExports[name];
1515
if (exportedFunc) {
16-
// Record the created function pointer to each function object,
17-
// so that if the same function pointer is obtained several times,
18-
// the same address will be returned.
19-
exportedFunc.ptr ||= addFunction(exportedFunc);
20-
return exportedFunc.ptr;
16+
// Note: addFunction automatically caches the created function pointer.
17+
return addFunction(exportedFunc);
2118
}
2219
#if ASSERTIONS
2320
err(`No exported function found by name "{exportedFunc}"`);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8337
1+
8319
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
22420
1+
22389
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
11568
1+
11482
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
27314
1+
27075

test/other/codesize/test_codesize_minimal_O0.expected.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,8 +925,6 @@ Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
925925
'ASSERTIONS',
926926
'ccall',
927927
'cwrap',
928-
'uleb128Encode',
929-
'generateFuncType',
930928
'convertJsFunctionToWasm',
931929
'getEmptyTableSlot',
932930
'updateTableMap',
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6632
1+
6614
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
17683
1+
17652
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
54162
1+
54121
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
52212
1+
52171

0 commit comments

Comments
 (0)