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.
@@ -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.offset !== offset);
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
- const locals = Object.values(x.locals).sort((a, b) => a.idx - b.idx).slice(x.params.length).sort((a, b) => a.idx - b.idx);
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 = [...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 = [...o];
306
- o.pop();
307
- ieee754_binary64_into(n, o);
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
- if ((o[0] === Opcodes.call || o[0] === Opcodes.return_call) && o[1] >= importedFuncs.length) {
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 = [...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
- return encodeVector([ ...encodeVector(localDecl), ...wasm, Opcodes.end ]);
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)),
@@ -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') * pageSize) ]
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') * pageSize) ]
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') * pageSize, Valtype.i32),
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') * pageSize) ],
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') * pageSize) ]
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') * pageSize) ],
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') * pageSize) ],
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') * pageSize) ]
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') * pageSize) ]
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
- const page = allocPage(scope, `builtin object: ${name}`);
33
- ptr = page === 0 ? 16 : page * PageSize;
32
+ ptr = allocPage(scope, `builtin object: ${name}`);
34
33
  }
35
34
 
36
35
  const out = [