porffor 0.57.18 → 0.57.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/assemble.js +382 -324
- package/compiler/builtins/annexb_string.js +10 -14
- package/compiler/builtins/string.ts +4 -4
- package/compiler/builtins_precompiled.js +118 -82
- package/compiler/codegen.js +55 -49
- package/compiler/encoding.js +22 -0
- package/compiler/wrap.js +5 -41
- package/foo.js +17 -1
- package/package.json +1 -1
- package/r.js +243 -0
- package/runtime/index.js +1 -1
package/compiler/assemble.js
CHANGED
@@ -1,61 +1,10 @@
|
|
1
1
|
import { Valtype, FuncType, ExportDesc, Section, Magic, Opcodes, PageSize, Reftype } from './wasmSpec.js';
|
2
|
-
import {
|
2
|
+
import { unsignedLEB128_length, signedLEB128_length } from './encoding.js';
|
3
3
|
import { importedFuncs } from './builtins.js';
|
4
4
|
import { log } from './log.js';
|
5
5
|
import './prefs.js';
|
6
6
|
|
7
|
-
const createSection = (type, data) => [
|
8
|
-
type,
|
9
|
-
...encodeVector(data)
|
10
|
-
];
|
11
|
-
|
12
|
-
const customSection = (name, data) => createSection(
|
13
|
-
Section.custom,
|
14
|
-
[ ...encodeString(name), ...data ]
|
15
|
-
);
|
16
|
-
|
17
|
-
const encodeNames = funcs => {
|
18
|
-
const encodeSection = (id, section) => [
|
19
|
-
id,
|
20
|
-
...unsignedLEB128(section.length),
|
21
|
-
...section
|
22
|
-
];
|
23
|
-
|
24
|
-
const moduleSection = encodeString('js'); // TODO: filename?
|
25
|
-
const functionsSection = encodeVector(
|
26
|
-
funcs.map(x => unsignedLEB128(x.asmIndex).concat(encodeString(x.name))),
|
27
|
-
);
|
28
|
-
const localsSection = encodeVector(
|
29
|
-
funcs.map(x => unsignedLEB128(x.asmIndex).concat(encodeVector(
|
30
|
-
Object.entries(x.locals).map(([name, local]) =>
|
31
|
-
unsignedLEB128(local.idx).concat(encodeString(name))
|
32
|
-
)
|
33
|
-
)))
|
34
|
-
);
|
35
|
-
|
36
|
-
return [
|
37
|
-
...encodeSection(0, moduleSection),
|
38
|
-
...encodeSection(1, functionsSection),
|
39
|
-
...encodeSection(2, localsSection),
|
40
|
-
];
|
41
|
-
};
|
42
|
-
|
43
7
|
export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
|
44
|
-
const types = [], typeCache = {};
|
45
|
-
|
46
|
-
const getType = (params, returns) => {
|
47
|
-
const hash = `${params.join(',')}_${returns.join(',')}`;
|
48
|
-
if (Prefs.optLog) log('assemble', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
|
49
|
-
if (typeCache[hash] !== undefined) return typeCache[hash];
|
50
|
-
|
51
|
-
const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
|
52
|
-
const idx = types.length;
|
53
|
-
|
54
|
-
types.push(type);
|
55
|
-
|
56
|
-
return typeCache[hash] = idx;
|
57
|
-
};
|
58
|
-
|
59
8
|
let t = performance.now();
|
60
9
|
const time = msg => {
|
61
10
|
if (!Prefs.profileAssemble) return;
|
@@ -64,71 +13,189 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
|
|
64
13
|
t = performance.now();
|
65
14
|
};
|
66
15
|
|
67
|
-
let importFuncs = []
|
16
|
+
let importFuncs = [];
|
17
|
+
globalThis.importDelta = 0;
|
68
18
|
if (!Prefs.treeshakeWasmImports || noTreeshake) {
|
69
19
|
importFuncs = Array.from(importedFuncs);
|
70
20
|
} else {
|
71
|
-
let imports = new Map();
|
72
|
-
|
73
21
|
// tree shake imports
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
22
|
+
const remap = new WeakMap();
|
23
|
+
for (let i = 0; i < funcs.length; i++) {
|
24
|
+
const f = funcs[i];
|
25
|
+
if (f.usesImports) for (let j = 0; j < f.wasm.length; j++) {
|
26
|
+
const x = f.wasm[j];
|
27
|
+
if (x[0] === Opcodes.call && x[1] < importedFuncs.length) {
|
28
|
+
const idx = x[1];
|
78
29
|
const func = importedFuncs[idx];
|
79
30
|
|
80
|
-
if (!
|
81
|
-
|
31
|
+
if (!remap.has(func)) {
|
32
|
+
remap.set(func, importFuncs.length);
|
33
|
+
importFuncs.push(func);
|
34
|
+
}
|
35
|
+
x[1] = remap.get(func);
|
82
36
|
}
|
83
37
|
}
|
84
38
|
}
|
85
39
|
|
86
|
-
|
87
|
-
|
40
|
+
globalThis.importDelta = importedFuncs.length - importFuncs.length;
|
41
|
+
}
|
42
|
+
|
43
|
+
if (Prefs.optLog) log('assemble', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
44
|
+
time('import treeshake');
|
45
|
+
|
46
|
+
// todo: this will just break if it is too small
|
47
|
+
let bufferSize = 1024 * 1024; // 1MB
|
48
|
+
let buffer = new Uint8Array(bufferSize);
|
49
|
+
let offset = 0;
|
50
|
+
|
51
|
+
const ensureBufferSize = added => {
|
52
|
+
if (offset + added >= bufferSize - 64) {
|
53
|
+
const newBuffer = new Uint8Array(bufferSize *= 2);
|
54
|
+
newBuffer.set(buffer);
|
55
|
+
buffer = null; // help gc
|
56
|
+
buffer = newBuffer;
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
60
|
+
const byte = byte => {
|
61
|
+
ensureBufferSize(1);
|
62
|
+
buffer[offset++] = byte;
|
63
|
+
};
|
64
|
+
|
65
|
+
const array = array => {
|
66
|
+
ensureBufferSize(array.length);
|
67
|
+
buffer.set(array, offset);
|
68
|
+
offset += array.length;
|
69
|
+
};
|
70
|
+
|
71
|
+
const unsigned = n => {
|
72
|
+
n |= 0;
|
73
|
+
if (n >= 0 && n <= 127) return byte(n);
|
74
|
+
|
75
|
+
do {
|
76
|
+
let x = n & 0x7f;
|
77
|
+
n >>>= 7;
|
78
|
+
if (n !== 0) {
|
79
|
+
x |= 0x80;
|
80
|
+
}
|
81
|
+
|
82
|
+
byte(x);
|
83
|
+
} while (n !== 0);
|
84
|
+
};
|
85
|
+
|
86
|
+
const signed = n => {
|
87
|
+
n |= 0;
|
88
|
+
if (n >= 0 && n <= 63) return byte(n);
|
89
|
+
|
90
|
+
while (true) {
|
91
|
+
let x = n & 0x7f;
|
92
|
+
n >>= 7;
|
93
|
+
|
94
|
+
if ((n === 0 && (x & 0x40) === 0) || (n === -1 && (x & 0x40) !== 0)) {
|
95
|
+
byte(x);
|
96
|
+
break;
|
97
|
+
} else {
|
98
|
+
x |= 0x80;
|
99
|
+
}
|
100
|
+
|
101
|
+
byte(x);
|
102
|
+
}
|
103
|
+
};
|
104
|
+
|
105
|
+
const ieee754 = n => {
|
106
|
+
ensureBufferSize(8);
|
107
|
+
array(new Uint8Array(new Float64Array([ n ]).buffer));
|
108
|
+
};
|
109
|
+
|
110
|
+
const string = str => {
|
111
|
+
unsigned(str.length);
|
112
|
+
for (let i = 0; i < str.length; i++) {
|
113
|
+
byte(str.charCodeAt(i));
|
114
|
+
}
|
115
|
+
};
|
116
|
+
|
117
|
+
const section = (id, bytes) => {
|
118
|
+
byte(id);
|
119
|
+
unsigned(bytes);
|
120
|
+
};
|
121
|
+
|
122
|
+
const unsignedPost = () => {
|
123
|
+
const o = offset;
|
124
|
+
offset += 5;
|
125
|
+
return n => {
|
126
|
+
const o2 = offset;
|
127
|
+
offset = o;
|
128
|
+
unsigned(n);
|
129
|
+
|
130
|
+
buffer.set(buffer.subarray(o + 5, o2), offset);
|
131
|
+
offset = o2 - (5 - (offset - o));
|
132
|
+
};
|
133
|
+
};
|
134
|
+
|
135
|
+
array(Magic, Magic.length);
|
136
|
+
time('setup');
|
137
|
+
|
138
|
+
const types = [], typeCache = new Map();
|
139
|
+
const getType = (params, returns) => {
|
140
|
+
const hash = `${params.join()}_${returns.join()}`;
|
141
|
+
if (typeCache.has(hash)) return typeCache.get(hash);
|
142
|
+
|
143
|
+
const type = [ FuncType, params.length, ...params, returns.length, ...returns ];
|
144
|
+
const idx = types.length;
|
145
|
+
|
146
|
+
types.push(type);
|
147
|
+
typeCache.set(hash, idx);
|
148
|
+
return idx;
|
149
|
+
};
|
150
|
+
|
151
|
+
// precache all types to be used
|
152
|
+
for (let i = 0; i < funcs.length; i++) {
|
153
|
+
const func = funcs[i];
|
154
|
+
getType(func.params, func.returns);
|
88
155
|
}
|
89
156
|
|
90
|
-
for (
|
91
|
-
|
157
|
+
for (let i = 0; i < importFuncs.length; i++) {
|
158
|
+
const func = importFuncs[i];
|
159
|
+
getType(func.params, func.returns);
|
92
160
|
}
|
93
161
|
|
94
|
-
|
162
|
+
for (let i = 0; i < tags.length; i++) {
|
163
|
+
const tag = tags[i];
|
164
|
+
getType(tag.params, tag.results);
|
165
|
+
}
|
95
166
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
167
|
+
section(Section.type, unsignedLEB128_length(types.length) + types.reduce((acc, x) => acc + x.length, 0));
|
168
|
+
unsigned(types.length);
|
169
|
+
for (let i = 0; i < types.length; i++) {
|
170
|
+
array(types[i]);
|
171
|
+
}
|
172
|
+
time('type section');
|
173
|
+
|
174
|
+
if (importFuncs.length > 0) {
|
175
|
+
section(Section.import, unsignedLEB128_length(importFuncs.length) + importFuncs.length * 5);
|
176
|
+
unsigned(importFuncs.length);
|
177
|
+
for (let i = 0; i < importFuncs.length; i++) {
|
178
|
+
const x = importFuncs[i];
|
179
|
+
byte(0); byte(1);
|
180
|
+
byte(x.import.charCodeAt(0));
|
181
|
+
byte(ExportDesc.func);
|
182
|
+
byte(getType(x.params, x.returns));
|
183
|
+
}
|
184
|
+
}
|
106
185
|
time('import section');
|
107
186
|
|
108
|
-
const
|
109
|
-
Section.func,
|
110
|
-
encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
|
111
|
-
);
|
112
|
-
time('func section');
|
187
|
+
const indirectFuncs = [], exportFuncs = [];
|
113
188
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
Section.element,
|
125
|
-
encodeVector([ [
|
126
|
-
0x00,
|
127
|
-
Opcodes.i32_const, 0, Opcodes.end,
|
128
|
-
...encodeVector(indirectFuncs.map(x => unsignedLEB128(x.asmIndex)))
|
129
|
-
] ])
|
130
|
-
);
|
131
|
-
time('element section');
|
189
|
+
section(Section.func, unsignedLEB128_length(funcs.length) + funcs.length);
|
190
|
+
unsigned(funcs.length);
|
191
|
+
for (let i = 0; i < funcs.length; i++) {
|
192
|
+
const x = funcs[i];
|
193
|
+
byte(getType(x.params, x.returns));
|
194
|
+
|
195
|
+
if (x.indirect) indirectFuncs.push(x);
|
196
|
+
if (x.export) exportFuncs.push(x);
|
197
|
+
}
|
198
|
+
time('func section');
|
132
199
|
|
133
200
|
if (pages.has('func lut')) {
|
134
201
|
if (data.addedFuncArgcLut) {
|
@@ -182,285 +249,276 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
|
|
182
249
|
}
|
183
250
|
time('func lut');
|
184
251
|
|
185
|
-
|
186
|
-
|
252
|
+
if (funcs.table) {
|
253
|
+
section(Section.table, unsignedLEB128_length(indirectFuncs.length) + 3);
|
254
|
+
byte(1); // table count
|
255
|
+
byte(Reftype.funcref); byte(0); // table type
|
256
|
+
unsigned(indirectFuncs.length); // table size
|
257
|
+
time('table section');
|
258
|
+
}
|
187
259
|
|
188
|
-
|
260
|
+
if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
|
261
|
+
const usesMemory = pages.size > 0;
|
262
|
+
if (usesMemory) {
|
263
|
+
const pageCount = Math.ceil((pages.size * pageSize) / PageSize);
|
264
|
+
section(Section.memory, unsignedLEB128_length(pageCount) + 2);
|
265
|
+
byte(1); // memory count
|
266
|
+
byte(0); // memory type
|
267
|
+
unsigned(pageCount); // memory size
|
268
|
+
time('memory section');
|
269
|
+
}
|
270
|
+
|
271
|
+
const usesTags = tags.length > 0;
|
272
|
+
if (usesTags) {
|
273
|
+
section(Section.tag, unsignedLEB128_length(tags.length) + tags.length * 2);
|
274
|
+
unsigned(tags.length);
|
275
|
+
for (let i = 0; i < tags.length; i++) {
|
276
|
+
const x = tags[i];
|
277
|
+
byte(0); // tag type
|
278
|
+
byte(getType(x.params, x.results)); // tag signature
|
279
|
+
}
|
280
|
+
time('tag section');
|
281
|
+
}
|
282
|
+
|
283
|
+
const globalsValues = Object.values(globals);
|
189
284
|
if (globalsValues.length > 0) {
|
190
|
-
|
285
|
+
section(Section.global, unsignedLEB128_length(globalsValues.length) + globalsValues.length * 4
|
286
|
+
+ globalsValues.reduce((acc, x) => acc + (x.type === Valtype.f64 ? 8 : signedLEB128_length(x.init ?? 0)), 0));
|
287
|
+
unsigned(globalsValues.length);
|
191
288
|
for (let i = 0; i < globalsValues.length; i++) {
|
192
|
-
const
|
193
|
-
|
194
|
-
switch (global.type) {
|
289
|
+
const x = globalsValues[i];
|
290
|
+
switch (x.type) {
|
195
291
|
case Valtype.i32:
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
292
|
+
byte(Valtype.i32);
|
293
|
+
byte(0x01);
|
294
|
+
byte(Opcodes.i32_const);
|
295
|
+
signed(x.init ?? 0);
|
200
296
|
break;
|
201
297
|
|
202
298
|
case Valtype.i64:
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
299
|
+
byte(Valtype.i64);
|
300
|
+
byte(0x01);
|
301
|
+
byte(Opcodes.i64_const);
|
302
|
+
signed(x.init ?? 0);
|
207
303
|
break;
|
208
304
|
|
209
305
|
case Valtype.f64:
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
306
|
+
byte(Valtype.f64);
|
307
|
+
byte(0x01);
|
308
|
+
byte(Opcodes.f64_const);
|
309
|
+
ieee754(x.init ?? 0);
|
214
310
|
break;
|
215
311
|
}
|
312
|
+
|
313
|
+
byte(Opcodes.end);
|
216
314
|
}
|
315
|
+
time('global section');
|
316
|
+
}
|
217
317
|
|
218
|
-
|
318
|
+
if (exportFuncs.length > 0 || usesMemory || usesTags) {
|
319
|
+
byte(Section.export);
|
320
|
+
const sizeOffset = offset, setSize = unsignedPost();
|
219
321
|
|
220
|
-
|
322
|
+
unsigned(exportFuncs.length + usesMemory + usesTags);
|
323
|
+
if (usesMemory) {
|
324
|
+
string('$');
|
325
|
+
byte(ExportDesc.mem); byte(0);
|
326
|
+
}
|
327
|
+
if (usesTags) {
|
328
|
+
string('0');
|
329
|
+
byte(ExportDesc.tag); byte(0);
|
330
|
+
}
|
221
331
|
|
222
|
-
|
223
|
-
|
332
|
+
for (let i = 0; i < exportFuncs.length; i++) {
|
333
|
+
const x = exportFuncs[i];
|
334
|
+
string(x.name === '#main' ? 'm' : x.name);
|
335
|
+
byte(ExportDesc.func);
|
336
|
+
unsigned(x.index - importDelta);
|
337
|
+
}
|
338
|
+
|
339
|
+
setSize(offset - sizeOffset - 5);
|
340
|
+
time('export section');
|
224
341
|
}
|
225
|
-
time('global section');
|
226
342
|
|
227
|
-
if (
|
343
|
+
if (funcs.table) {
|
344
|
+
section(Section.element, unsignedLEB128_length(indirectFuncs.length) + 5 + indirectFuncs.reduce((acc, x) => acc + unsignedLEB128_length(x.index - importDelta), 0));
|
345
|
+
byte(1); // table index
|
346
|
+
byte(0); // element type
|
347
|
+
byte(Opcodes.i32_const); byte(0); byte(Opcodes.end); // offset
|
228
348
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
// export first tag if used
|
248
|
-
if (tags.length !== 0) exports.unshift([ ...encodeString('0'), ExportDesc.tag, 0x00 ]);
|
249
|
-
time('tag section');
|
250
|
-
|
251
|
-
const exportSection = createSection(
|
252
|
-
Section.export,
|
253
|
-
encodeVector(exports)
|
254
|
-
);
|
255
|
-
time('export section');
|
256
|
-
|
257
|
-
let codeSection = [];
|
349
|
+
unsigned(indirectFuncs.length);
|
350
|
+
for (let i = 0; i < indirectFuncs.length; i++) {
|
351
|
+
const x = indirectFuncs[i];
|
352
|
+
unsigned(x.index - importDelta);
|
353
|
+
}
|
354
|
+
time('element section');
|
355
|
+
}
|
356
|
+
|
357
|
+
if (data.length > 0) {
|
358
|
+
section(Section.data_count, unsignedLEB128_length(data.length));
|
359
|
+
unsigned(data.length);
|
360
|
+
time('data count section');
|
361
|
+
}
|
362
|
+
|
363
|
+
byte(Section.code);
|
364
|
+
const codeSectionSizeOffset = offset, setCodeSectionSize = unsignedPost();
|
365
|
+
|
366
|
+
unsigned(funcs.length);
|
258
367
|
for (let i = 0; i < funcs.length; i++) {
|
368
|
+
const funcSizeOffset = offset, setFuncSize = unsignedPost();
|
369
|
+
|
259
370
|
const x = funcs[i];
|
260
371
|
const locals = Object.values(x.locals).sort((a, b) => a.idx - b.idx);
|
261
372
|
|
262
373
|
const paramCount = x.params.length;
|
263
|
-
let
|
374
|
+
let declCount = 0, lastType, typeCount = 0;
|
264
375
|
for (let i = paramCount; i <= locals.length; i++) {
|
265
376
|
const local = locals[i];
|
266
|
-
if (
|
267
|
-
unsignedLEB128_into(typeCount, localDecl);
|
268
|
-
localDecl.push(lastType);
|
269
|
-
typeCount = 0;
|
377
|
+
if (lastType && local?.type !== lastType) {
|
270
378
|
declCount++;
|
271
379
|
}
|
272
380
|
|
273
|
-
typeCount++;
|
274
381
|
lastType = local?.type;
|
275
382
|
}
|
383
|
+
unsigned(declCount);
|
276
384
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
o[1] > 127
|
286
|
-
) {
|
287
|
-
const n = o[1];
|
288
|
-
o = [ o[0] ];
|
289
|
-
unsignedLEB128_into(n, o);
|
290
|
-
}
|
291
|
-
|
292
|
-
// encode f64.const ops as ieee754 from raw number
|
293
|
-
if (o[0] === Opcodes.f64_const) {
|
294
|
-
const n = o[1];
|
295
|
-
o = ieee754_binary64(n);
|
296
|
-
if (o.length === 8) o.unshift(Opcodes.f64_const);
|
297
|
-
}
|
298
|
-
|
299
|
-
// encode call ops as unsigned leb128 from raw number
|
300
|
-
if ((o[0] === Opcodes.call /* || o[0] === Opcodes.return_call */) && o[1] >= importedFuncs.length) {
|
301
|
-
const n = o[1] - importDelta;
|
302
|
-
o = [ Opcodes.call ];
|
303
|
-
unsignedLEB128_into(n, o);
|
304
|
-
}
|
305
|
-
|
306
|
-
// encode call indirect ops as types from info
|
307
|
-
if (o[0] === Opcodes.call_indirect) {
|
308
|
-
o = [...o];
|
309
|
-
const params = [];
|
310
|
-
for (let i = 0; i < o[1]; i++) {
|
311
|
-
params.push(valtypeBinary, Valtype.i32);
|
312
|
-
}
|
313
|
-
|
314
|
-
let returns = [ valtypeBinary, Valtype.i32 ];
|
315
|
-
if (o.at(-1) === 'no_type_return') {
|
316
|
-
o.pop();
|
317
|
-
returns = [ valtypeBinary ];
|
318
|
-
}
|
319
|
-
|
320
|
-
o[1] = getType(params, returns);
|
321
|
-
}
|
385
|
+
lastType = undefined;
|
386
|
+
for (let i = paramCount; i <= locals.length; i++) {
|
387
|
+
const local = locals[i];
|
388
|
+
if (lastType && local?.type !== lastType) {
|
389
|
+
unsigned(typeCount);
|
390
|
+
byte(lastType);
|
391
|
+
typeCount = 0;
|
392
|
+
}
|
322
393
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
wasm.push(x);
|
327
|
-
}
|
394
|
+
typeCount++;
|
395
|
+
lastType = local?.type;
|
396
|
+
}
|
328
397
|
|
329
|
-
|
398
|
+
for (let i = 0; i < x.wasm.length; i++) {
|
399
|
+
let o = x.wasm[i];
|
400
|
+
const op = o[0];
|
401
|
+
|
402
|
+
// encode local/global ops as unsigned leb128 from raw number
|
403
|
+
if (
|
404
|
+
(op >= Opcodes.local_get && op <= Opcodes.global_set) &&
|
405
|
+
o[1] > 127
|
406
|
+
) {
|
407
|
+
byte(op);
|
408
|
+
unsigned(o[1]);
|
409
|
+
continue;
|
330
410
|
}
|
331
411
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
// encode local/global ops as unsigned leb128 from raw number
|
339
|
-
if (
|
340
|
-
(op >= Opcodes.local_get && op <= Opcodes.global_set) &&
|
341
|
-
o[1] > 127
|
342
|
-
) {
|
343
|
-
wasm.push(op);
|
344
|
-
unsignedLEB128_into(o[1], wasm);
|
345
|
-
continue;
|
346
|
-
}
|
412
|
+
// encode f64.const ops as ieee754 from raw number
|
413
|
+
if (op === Opcodes.f64_const) {
|
414
|
+
byte(op);
|
415
|
+
ieee754(o[1]);
|
416
|
+
continue;
|
417
|
+
}
|
347
418
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
419
|
+
// encode call ops as unsigned leb128 from raw number
|
420
|
+
if ((op === Opcodes.call /* || o[0] === Opcodes.return_call */) && o[1] >= importedFuncs.length) {
|
421
|
+
byte(op);
|
422
|
+
unsigned(o[1] - importDelta);
|
423
|
+
continue;
|
424
|
+
}
|
354
425
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
426
|
+
// encode call indirect ops as types from info
|
427
|
+
if (op === Opcodes.call_indirect) {
|
428
|
+
const params = [];
|
429
|
+
for (let i = 0; i < o[1]; i++) {
|
430
|
+
params.push(valtypeBinary, Valtype.i32);
|
360
431
|
}
|
361
432
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
}
|
368
|
-
|
369
|
-
let returns = [ valtypeBinary, Valtype.i32 ];
|
370
|
-
if (o.at(-1) === 'no_type_return') {
|
371
|
-
returns = [ valtypeBinary ];
|
372
|
-
}
|
373
|
-
|
374
|
-
wasm.push(op, getType(params, returns), o[2]);
|
375
|
-
continue;
|
376
|
-
}
|
433
|
+
byte(op);
|
434
|
+
byte(getType(params, [ valtypeBinary, Valtype.i32 ]));
|
435
|
+
byte(o[2]);
|
436
|
+
continue;
|
437
|
+
}
|
377
438
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
}
|
439
|
+
for (let j = 0; j < o.length; j++) {
|
440
|
+
const x = o[j];
|
441
|
+
if (x == null || !(x <= 0xff)) continue;
|
442
|
+
buffer[offset++] = x;
|
383
443
|
}
|
384
444
|
}
|
385
445
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
446
|
+
byte(Opcodes.end);
|
447
|
+
setFuncSize(offset - funcSizeOffset - 5);
|
448
|
+
}
|
449
|
+
|
450
|
+
setCodeSectionSize(offset - codeSectionSizeOffset - 5);
|
451
|
+
time('code section');
|
452
|
+
|
453
|
+
section(Section.data, unsignedLEB128_length(data.length) + data.reduce((acc, x) =>
|
454
|
+
acc + (x.page != null ? (3 + signedLEB128_length(pages.allocs.get(x.page) ?? (pages.get(x.page) * pageSize))) : 1)
|
455
|
+
+ unsignedLEB128_length(x.bytes.length) + x.bytes.length, 0));
|
456
|
+
|
457
|
+
unsigned(data.length);
|
458
|
+
for (let i = 0; i < data.length; i++) {
|
459
|
+
const x = data[i];
|
460
|
+
if (x.page != null) { // active
|
461
|
+
let offset = pages.allocs.get(x.page) ?? (pages.get(x.page) * pageSize);
|
462
|
+
if (offset === 0) offset = 16;
|
463
|
+
|
464
|
+
byte(0x00);
|
465
|
+
byte(Opcodes.i32_const);
|
466
|
+
signed(offset);
|
467
|
+
byte(Opcodes.end);
|
468
|
+
} else { // passive
|
469
|
+
byte(0x01);
|
399
470
|
}
|
400
471
|
|
401
|
-
|
472
|
+
unsigned(x.bytes.length);
|
473
|
+
array(x.bytes);
|
402
474
|
}
|
475
|
+
time('data section');
|
403
476
|
|
404
|
-
|
405
|
-
|
406
|
-
|
477
|
+
if (Prefs.d) {
|
478
|
+
byte(Section.custom);
|
479
|
+
const totalSizeOffset = offset, setTotalSize = unsignedPost();
|
480
|
+
string('name');
|
407
481
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
482
|
+
const section = (id, cb) => {
|
483
|
+
byte(id);
|
484
|
+
const sizeOffset = offset, setSize = unsignedPost();
|
485
|
+
cb();
|
486
|
+
setSize(offset - sizeOffset - 5);
|
487
|
+
};
|
413
488
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
dataSection.push(0x00, Opcodes.i32_const, ...signedLEB128(offset), Opcodes.end);
|
425
|
-
} else {
|
426
|
-
// type: passive
|
427
|
-
dataSection.push(0x01);
|
489
|
+
section(0, () => { // module
|
490
|
+
string('js'); // todo: filename?
|
491
|
+
});
|
492
|
+
|
493
|
+
section(1, () => { // funcs
|
494
|
+
unsigned(funcs.length);
|
495
|
+
for (let i = 0; i < funcs.length; i++) {
|
496
|
+
const x = funcs[i];
|
497
|
+
unsigned(x.index - importDelta);
|
498
|
+
string(x.name);
|
428
499
|
}
|
500
|
+
});
|
429
501
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
);
|
502
|
+
section(2, () => { // locals
|
503
|
+
unsigned(funcs.length);
|
504
|
+
for (let i = 0; i < funcs.length; i++) {
|
505
|
+
const x = funcs[i];
|
506
|
+
unsigned(x.index - importDelta);
|
507
|
+
|
508
|
+
const locals = Object.keys(x.locals);
|
509
|
+
unsigned(locals.length);
|
510
|
+
for (let j = 0; j < locals.length; j++) {
|
511
|
+
const name = locals[j];
|
512
|
+
unsigned(x.locals[name]);
|
513
|
+
string(name);
|
514
|
+
}
|
437
515
|
}
|
438
|
-
}
|
516
|
+
});
|
439
517
|
|
440
|
-
|
441
|
-
|
518
|
+
setTotalSize(offset - totalSizeOffset - 5);
|
519
|
+
time('name section');
|
442
520
|
}
|
443
521
|
|
444
|
-
|
445
|
-
|
446
|
-
unsignedLEB128(data.length)
|
447
|
-
);
|
448
|
-
time('data section');
|
449
|
-
|
450
|
-
return Uint8Array.from([
|
451
|
-
...Magic,
|
452
|
-
...typeSection,
|
453
|
-
...importSection,
|
454
|
-
...funcSection,
|
455
|
-
...tableSection,
|
456
|
-
...memorySection,
|
457
|
-
...tagSection,
|
458
|
-
...globalSection,
|
459
|
-
...exportSection,
|
460
|
-
...elementSection,
|
461
|
-
...dataCountSection,
|
462
|
-
...codeSection,
|
463
|
-
...dataSection,
|
464
|
-
...nameSection
|
465
|
-
]);
|
522
|
+
buffer = buffer.subarray(0, offset);
|
523
|
+
return buffer;
|
466
524
|
};
|