porffor 0.34.7 → 0.34.9
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 +53 -31
- package/compiler/builtins.js +9 -9
- package/compiler/builtins_objects.js +1 -2
- package/compiler/builtins_precompiled.js +230 -230
- package/compiler/codegen.js +257 -157
- package/compiler/decompile.js +1 -1
- package/compiler/precompile.js +3 -3
- package/compiler/wrap.js +3 -2
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/assemble.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Valtype, FuncType, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize, Reftype } from './wasmSpec.js';
|
2
|
-
import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64_into } from './encoding.js';
|
2
|
+
import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64, ieee754_binary64_into } from './encoding.js';
|
3
3
|
import { importedFuncs } from './builtins.js';
|
4
4
|
import { log } from './log.js';
|
5
5
|
import {} from './prefs.js';
|
@@ -72,6 +72,14 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
72
72
|
return typeCache[hash] = idx;
|
73
73
|
};
|
74
74
|
|
75
|
+
let t = performance.now();
|
76
|
+
const time = msg => {
|
77
|
+
if (!Prefs.profileAssemble) return;
|
78
|
+
|
79
|
+
console.log(`${' '.repeat(50)}\r[${(performance.now() - t).toFixed(2)}ms] ${msg}`);
|
80
|
+
t = performance.now();
|
81
|
+
};
|
82
|
+
|
75
83
|
let importFuncs = [], importDelta = 0;
|
76
84
|
if (optLevel < 1 || !Prefs.treeshakeWasmImports || noTreeshake) {
|
77
85
|
importFuncs = importedFuncs;
|
@@ -81,7 +89,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
81
89
|
// tree shake imports
|
82
90
|
for (const f of funcs) {
|
83
91
|
for (const inst of f.wasm) {
|
84
|
-
if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] < importedFuncs.length) {
|
92
|
+
if ((inst[0] === Opcodes.call /* || inst[0] === Opcodes.return_call */) && inst[1] < importedFuncs.length) {
|
85
93
|
const idx = inst[1];
|
86
94
|
const func = importedFuncs[idx];
|
87
95
|
|
@@ -102,6 +110,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
102
110
|
f.asmIndex = f.index - importDelta;
|
103
111
|
}
|
104
112
|
|
113
|
+
time('treeshake import funcs');
|
105
114
|
|
106
115
|
if (Prefs.optLog) log('assemble', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
107
116
|
|
@@ -109,11 +118,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
109
118
|
Section.import,
|
110
119
|
encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(typeof x.params === 'object' ? x.params : new Array(x.params).fill(valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
|
111
120
|
);
|
121
|
+
time('import section');
|
112
122
|
|
113
123
|
const funcSection = createSection(
|
114
124
|
Section.func,
|
115
125
|
encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
|
116
126
|
);
|
127
|
+
time('func section');
|
117
128
|
|
118
129
|
const nameSection = Prefs.d ? customSection('name', encodeNames(funcs)) : [];
|
119
130
|
|
@@ -121,6 +132,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
121
132
|
Section.table,
|
122
133
|
encodeVector([ [ Reftype.funcref, 0x00, ...unsignedLEB128(funcs.length) ] ])
|
123
134
|
);
|
135
|
+
time('table section');
|
124
136
|
|
125
137
|
const elementSection = !funcs.table ? [] : createSection(
|
126
138
|
Section.element,
|
@@ -130,12 +142,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
130
142
|
...encodeVector(funcs.map(x => unsignedLEB128(x.asmIndex)))
|
131
143
|
] ])
|
132
144
|
);
|
145
|
+
time('element section');
|
133
146
|
|
134
147
|
if (pages.has('func lut')) {
|
135
148
|
const offset = pages.get('func lut').ind * pageSize;
|
136
149
|
if (data.addedFuncArgcLut) {
|
137
150
|
// remove existing data
|
138
|
-
data = data.filter(x => x.
|
151
|
+
data = data.filter(x => x.page !== 'func lut');
|
139
152
|
}
|
140
153
|
|
141
154
|
// generate func lut data
|
@@ -149,8 +162,6 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
149
162
|
if (func.constr) argc -= 4;
|
150
163
|
if (!func.internal || func.typedParams) argc = Math.floor(argc / 2);
|
151
164
|
|
152
|
-
if (name.startsWith('#')) name = '';
|
153
|
-
|
154
165
|
bytes.push(argc % 256, (argc / 256 | 0) % 256);
|
155
166
|
|
156
167
|
// userland exposed .length
|
@@ -165,6 +176,8 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
165
176
|
if (func.constr) flags |= 0b10;
|
166
177
|
bytes.push(flags);
|
167
178
|
|
179
|
+
if (name.startsWith('#')) name = '';
|
180
|
+
|
168
181
|
// eg: __String_prototype_toLowerCase -> toLowerCase
|
169
182
|
if (name.startsWith('__')) name = name.split('_').pop();
|
170
183
|
|
@@ -182,8 +195,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
182
195
|
});
|
183
196
|
data.addedFuncArgcLut = true;
|
184
197
|
}
|
185
|
-
|
186
|
-
// const t0 = performance.now();
|
198
|
+
time('func lut');
|
187
199
|
|
188
200
|
// specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
|
189
201
|
const globalsValues = Object.values(globals);
|
@@ -225,17 +237,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
225
237
|
unsignedLEB128_into(data.length, globalSection);
|
226
238
|
globalSection = globalSection.concat(data);
|
227
239
|
}
|
228
|
-
|
229
|
-
// if (Prefs.profileCompiler) {
|
230
|
-
// const log = console.log;
|
231
|
-
// console.log = function () {
|
232
|
-
// log.apply(this, arguments);
|
233
|
-
// console.log = log;
|
234
|
-
// console.log(` a. assembled global section in ${(performance.now() - t0).toFixed(2)}ms\n`);
|
235
|
-
// };
|
236
|
-
// }
|
237
|
-
|
238
|
-
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, ...unsignedLEB128(x.asmIndex) ]);
|
240
|
+
time('global section');
|
239
241
|
|
240
242
|
if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
|
241
243
|
if (optLevel === 0) pages.set('O0 precaution', 0);
|
@@ -245,9 +247,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
245
247
|
Section.memory,
|
246
248
|
encodeVector([ [ 0x00, ...unsignedLEB128(Math.ceil((pages.size * pageSize) / PageSize)) ] ])
|
247
249
|
);
|
250
|
+
time('memory section');
|
251
|
+
|
252
|
+
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, ...unsignedLEB128(x.asmIndex) ]);
|
248
253
|
|
249
254
|
// export memory if used
|
250
255
|
if (usesMemory) exports.unshift([ ...encodeString('$'), ExportDesc.mem, 0x00 ]);
|
256
|
+
time('gen exports');
|
251
257
|
|
252
258
|
const tagSection = tags.length === 0 ? [] : createSection(
|
253
259
|
Section.tag,
|
@@ -256,16 +262,20 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
256
262
|
|
257
263
|
// export first tag if used
|
258
264
|
if (tags.length !== 0) exports.unshift([ ...encodeString('0'), ExportDesc.tag, 0x00 ]);
|
265
|
+
time('tag section');
|
259
266
|
|
260
267
|
const exportSection = createSection(
|
261
268
|
Section.export,
|
262
269
|
encodeVector(exports)
|
263
270
|
);
|
271
|
+
time('export section');
|
264
272
|
|
265
273
|
const codeSection = createSection(
|
266
274
|
Section.code,
|
267
275
|
encodeVector(funcs.map(x => {
|
268
|
-
|
276
|
+
// time(x.name);
|
277
|
+
const locals = Object.values(x.locals).sort((a, b) => a.idx - b.idx).slice(x.params.length);
|
278
|
+
// time(' locals gen');
|
269
279
|
|
270
280
|
let localDecl = [], typeCount = 0, lastType;
|
271
281
|
for (let i = 0; i < locals.length; i++) {
|
@@ -280,8 +290,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
280
290
|
}
|
281
291
|
|
282
292
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
283
|
-
|
284
|
-
// todo: move const, call transforms here too?
|
293
|
+
// time(' localDecl gen');
|
285
294
|
|
286
295
|
const makeAssembled = Prefs.d;
|
287
296
|
let wasm = [], wasmNonFlat = [];
|
@@ -290,30 +299,32 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
290
299
|
|
291
300
|
// encode local/global ops as unsigned leb128 from raw number
|
292
301
|
if (
|
293
|
-
(o[0] === Opcodes.local_get || o[0] === Opcodes.local_set || o[0] === Opcodes.local_tee || o[0] === Opcodes.global_get || o[0] === Opcodes.global_set) &&
|
302
|
+
// (o[0] === Opcodes.local_get || o[0] === Opcodes.local_set || o[0] === Opcodes.local_tee || o[0] === Opcodes.global_get || o[0] === Opcodes.global_set) &&
|
303
|
+
(o[0] >= Opcodes.local_get && o[0] <= Opcodes.global_set) &&
|
294
304
|
o[1] > 127
|
295
305
|
) {
|
296
306
|
const n = o[1];
|
297
|
-
o = [
|
298
|
-
o.pop();
|
307
|
+
o = [ o[0] ];
|
299
308
|
unsignedLEB128_into(n, o);
|
300
309
|
}
|
301
310
|
|
302
311
|
// encode f64.const ops as ieee754 from raw number
|
303
312
|
if (o[0] === Opcodes.f64_const) {
|
304
313
|
const n = o[1];
|
305
|
-
o = [
|
306
|
-
o
|
307
|
-
|
314
|
+
// o = [ o[0] ];
|
315
|
+
// ieee754_binary64_into(n, o);
|
316
|
+
o = ieee754_binary64(n);
|
317
|
+
if (o.length === 8) o.unshift(Opcodes.f64_const);
|
308
318
|
}
|
309
319
|
|
310
|
-
|
320
|
+
// encode call ops as unsigned leb128 from raw number
|
321
|
+
if ((o[0] === Opcodes.call /* || o[0] === Opcodes.return_call */) && o[1] >= importedFuncs.length) {
|
311
322
|
const n = o[1] - importDelta;
|
312
|
-
o = [
|
313
|
-
o.pop();
|
323
|
+
o = [ o[0] ];
|
314
324
|
unsignedLEB128_into(n, o);
|
315
325
|
}
|
316
326
|
|
327
|
+
// encode call indirect ops as types from info
|
317
328
|
if (o[0] === Opcodes.call_indirect) {
|
318
329
|
o = [...o];
|
319
330
|
const params = [];
|
@@ -338,19 +349,28 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
338
349
|
|
339
350
|
if (makeAssembled) wasmNonFlat.push(o);
|
340
351
|
}
|
352
|
+
// time(' wasm transform');
|
341
353
|
|
342
354
|
if (makeAssembled) {
|
343
355
|
x.assembled = { localDecl, wasm, wasmNonFlat };
|
344
356
|
}
|
345
357
|
|
346
|
-
|
358
|
+
let out = unsignedLEB128(localDecl.length)
|
359
|
+
.concat(localDecl.flat(), wasm, Opcodes.end);
|
360
|
+
|
361
|
+
out.unshift(...unsignedLEB128(out.length));
|
362
|
+
|
363
|
+
// time(' finish');
|
364
|
+
return out;
|
347
365
|
}))
|
348
366
|
);
|
367
|
+
time('code section');
|
349
368
|
|
350
369
|
const typeSection = createSection(
|
351
370
|
Section.type,
|
352
371
|
encodeVector(types)
|
353
372
|
);
|
373
|
+
time('type section');
|
354
374
|
|
355
375
|
const dataSection = data.length === 0 ? [] : createSection(
|
356
376
|
Section.data,
|
@@ -372,11 +392,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
372
392
|
return bytes;
|
373
393
|
}))
|
374
394
|
);
|
395
|
+
time('data section');
|
375
396
|
|
376
397
|
const dataCountSection = data.length === 0 ? [] : createSection(
|
377
398
|
Section.data_count,
|
378
399
|
unsignedLEB128(data.length)
|
379
400
|
);
|
401
|
+
time('datacount section');
|
380
402
|
|
381
403
|
if (Prefs.sections) console.log({
|
382
404
|
typeSection: typeSection.map(x => x.toString(16)),
|
package/compiler/builtins.js
CHANGED
@@ -1016,7 +1016,7 @@ export const BuiltinFuncs = function() {
|
|
1016
1016
|
[ Opcodes.i32_mul ],
|
1017
1017
|
...number(4, Valtype.i32),
|
1018
1018
|
[ Opcodes.i32_add ],
|
1019
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
1019
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ]
|
1020
1020
|
],
|
1021
1021
|
table: true
|
1022
1022
|
};
|
@@ -1031,7 +1031,7 @@ export const BuiltinFuncs = function() {
|
|
1031
1031
|
[ Opcodes.i32_mul ],
|
1032
1032
|
...number(2, Valtype.i32),
|
1033
1033
|
[ Opcodes.i32_add ],
|
1034
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
1034
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ]
|
1035
1035
|
],
|
1036
1036
|
table: true
|
1037
1037
|
};
|
@@ -1046,7 +1046,7 @@ export const BuiltinFuncs = function() {
|
|
1046
1046
|
[ Opcodes.i32_mul ],
|
1047
1047
|
...number(5, Valtype.i32),
|
1048
1048
|
[ Opcodes.i32_add ],
|
1049
|
-
...number(allocPage(scope, 'func lut')
|
1049
|
+
...number(allocPage(scope, 'func lut'), Valtype.i32),
|
1050
1050
|
[ Opcodes.i32_add ]
|
1051
1051
|
],
|
1052
1052
|
table: true
|
@@ -1062,11 +1062,11 @@ export const BuiltinFuncs = function() {
|
|
1062
1062
|
...number(2, Valtype.i32),
|
1063
1063
|
[ Opcodes.i32_add ],
|
1064
1064
|
...number(0, Valtype.i32),
|
1065
|
-
[ Opcodes.i32_store16, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
1065
|
+
[ Opcodes.i32_store16, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ],
|
1066
1066
|
|
1067
1067
|
[ Opcodes.local_get, 0 ],
|
1068
1068
|
...number(1, Valtype.i32),
|
1069
|
-
[ Opcodes.i32_store8, 0, ...unsignedLEB128(allocPage(scope, 'func length deletion table')
|
1069
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(allocPage(scope, 'func length deletion table')) ]
|
1070
1070
|
],
|
1071
1071
|
table: true
|
1072
1072
|
};
|
@@ -1081,11 +1081,11 @@ export const BuiltinFuncs = function() {
|
|
1081
1081
|
...number(5, Valtype.i32),
|
1082
1082
|
[ Opcodes.i32_add ],
|
1083
1083
|
...number(0, Valtype.i32),
|
1084
|
-
[ Opcodes.i32_store, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
1084
|
+
[ Opcodes.i32_store, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ],
|
1085
1085
|
|
1086
1086
|
[ Opcodes.local_get, 0 ],
|
1087
1087
|
...number(1, Valtype.i32),
|
1088
|
-
[ Opcodes.i32_store8, 0, ...unsignedLEB128(allocPage(scope, 'func name deletion table')
|
1088
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(allocPage(scope, 'func name deletion table')) ],
|
1089
1089
|
],
|
1090
1090
|
table: true
|
1091
1091
|
};
|
@@ -1096,7 +1096,7 @@ export const BuiltinFuncs = function() {
|
|
1096
1096
|
returnType: TYPES.boolean,
|
1097
1097
|
wasm: (scope, { allocPage }) => [
|
1098
1098
|
[ Opcodes.local_get, 0 ],
|
1099
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func length deletion table')
|
1099
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func length deletion table')) ]
|
1100
1100
|
],
|
1101
1101
|
table: true
|
1102
1102
|
};
|
@@ -1107,7 +1107,7 @@ export const BuiltinFuncs = function() {
|
|
1107
1107
|
returnType: TYPES.boolean,
|
1108
1108
|
wasm: (scope, { allocPage }) => [
|
1109
1109
|
[ Opcodes.local_get, 0 ],
|
1110
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func name deletion table')
|
1110
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func name deletion table')) ]
|
1111
1111
|
],
|
1112
1112
|
table: true
|
1113
1113
|
};
|
@@ -29,8 +29,7 @@ export default function({ builtinFuncs }, Prefs) {
|
|
29
29
|
if (existingFunc) {
|
30
30
|
ptr = 1;
|
31
31
|
} else {
|
32
|
-
|
33
|
-
ptr = page === 0 ? 16 : page * PageSize;
|
32
|
+
ptr = allocPage(scope, `builtin object: ${name}`);
|
34
33
|
}
|
35
34
|
|
36
35
|
const out = [
|