porffor 0.16.0-594397507 → 0.16.0-688a50c13

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/parse.js CHANGED
@@ -43,7 +43,7 @@ export default (input, flags) => {
43
43
  webcompat: true,
44
44
 
45
45
  // babel
46
- plugins: types ? ['estree', 'typescript'] : ['estree'],
46
+ plugins: types || flags.includes('typed') ? ['estree', 'typescript'] : ['estree'],
47
47
 
48
48
  // multiple
49
49
  sourceType: flags.includes('module') ? 'module' : 'script',
@@ -0,0 +1,207 @@
1
+ import { Opcodes, Valtype } from './wasmSpec.js';
2
+ import { number } from './embedding.js';
3
+ import { importedFuncs } from './builtins.js';
4
+ import Prefs from './prefs.js';
5
+ import assemble from './assemble.js';
6
+ import wrap, { writeByteStr } from './wrap.js';
7
+ import * as Havoc from './havoc.js';
8
+
9
+ export const setup = () => {
10
+ importedFuncs[importedFuncs.profile2].params = [ Valtype.i32, valtypeBinary ];
11
+
12
+ // enable these prefs by default for pgo
13
+ Prefs.typeswitchUniqueTmp = Prefs.typeswitchUniqueTmp === false ? false : true;
14
+ Prefs.cyclone = Prefs.cyclone === false ? false : true;
15
+ };
16
+
17
+ export const run = obj => {
18
+ const wasmFuncs = obj.funcs;
19
+
20
+ let starts = {};
21
+ const time = (id, msg) => {
22
+ if (!Prefs.pgoLog) return;
23
+
24
+ if (!starts[id]) {
25
+ process.stdout.write(msg);
26
+ starts[id] = performance.now();
27
+ } else {
28
+ process.stdout.write(`\r${' '.repeat(50)}\r[${(performance.now() - starts[id]).toFixed(2)}ms] ${msg}\n`);
29
+ }
30
+ };
31
+
32
+ time(0, `injecting PGO logging...`);
33
+
34
+ let funcs = [];
35
+ for (let i = 0; i < wasmFuncs.length; i++) {
36
+ const { name, internal, params, locals, wasm } = wasmFuncs[i];
37
+ if (internal) continue; // ignore internal funcs
38
+ wasmFuncs[i].originalWasm = structuredClone(wasm);
39
+
40
+ const invLocals = Object.keys(locals).reduce((acc, x) => { acc[locals[x].idx] = locals[x]; return acc; }, {});
41
+
42
+ const id = funcs.length;
43
+ funcs.push({ name, id, locals, params, invLocals });
44
+
45
+ wasm.unshift(
46
+ // mark active func
47
+ ...number(i, Valtype.i32),
48
+ [ Opcodes.call, importedFuncs.profile1 ],
49
+
50
+ // log args
51
+ ...params.flatMap((_, i) => [
52
+ ...number(i, Valtype.i32),
53
+ [ Opcodes.local_get, i ],
54
+ ...(invLocals[i].type !== Valtype.f64 ? [ Opcodes.i32_from ] : []),
55
+ [ Opcodes.call, importedFuncs.profile2 ]
56
+ ])
57
+ );
58
+
59
+ for (let j = 0; j < wasm.length; j++) {
60
+ const inst = wasm[j];
61
+ if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
62
+ wasm.splice(j + 1, 0,
63
+ ...number(inst[1], Valtype.i32),
64
+ [ Opcodes.local_get, inst[1] ],
65
+ ...(invLocals[inst[1]].type !== Valtype.f64 ? [ Opcodes.i32_from ] : []),
66
+ [ Opcodes.call, importedFuncs.profile2 ]
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ let localData = funcs.map(x => new Array(Object.keys(x.locals).length).fill(0).map(() => []));
73
+
74
+ time(0, `injected PGO logging`);
75
+ time(1, `running with PGO logging...`);
76
+
77
+ let activeFunc = null, abort = false;
78
+ try {
79
+ obj.wasm = assemble(obj.funcs, obj.globals, obj.tags, obj.pages, obj.data, obj.flags, true);
80
+
81
+ const { exports } = wrap(obj, [], {
82
+ y: n => {
83
+ activeFunc = n;
84
+ },
85
+ z: (i, n) => {
86
+ if (activeFunc == null) throw 'fail';
87
+ localData[activeFunc][i].push(n);
88
+ },
89
+ w: (ind, outPtr) => { // readArgv
90
+ const pgoInd = process.argv.indexOf('--pgo');
91
+ const args = process.argv.slice(pgoInd).filter(x => !x.startsWith('-'));
92
+ const str = args[ind - 1];
93
+ if (pgoInd === -1 || !str) {
94
+ if (Prefs.pgoLog) console.log('\nPGO warning: script was expecting arguments, please specify args to use for PGO after --pgo arg');
95
+ return -1;
96
+ }
97
+
98
+ writeByteStr(exports.$, outPtr, str);
99
+ return str.length;
100
+ }
101
+ }, () => {});
102
+
103
+ exports.main();
104
+ } catch (e) {
105
+ throw e;
106
+ }
107
+
108
+ for (const x of funcs) {
109
+ const wasmFunc = wasmFuncs.find(y => y.name === x.name);
110
+ wasmFunc.wasm = wasmFunc.originalWasm;
111
+ delete wasmFunc.originalWasm;
112
+ }
113
+
114
+ if (abort) {
115
+ console.log('aborting PGO!');
116
+ return false;
117
+ }
118
+
119
+ time(1, `ran with PGO logging`);
120
+ time(2, 'processing PGO data...');
121
+
122
+ // process data
123
+ let log = '';
124
+ for (let i = 0; i < localData.length; i++) {
125
+ const func = funcs[i];
126
+ const total = localData[i].length;
127
+
128
+ const localKeys = Object.keys(func.locals).sort((a, b) => a.idx - b.idx);
129
+ const localValues = Object.values(func.locals).sort((a, b) => a.idx - b.idx);
130
+ func.localKeys = localKeys;
131
+ func.localValues = localValues;
132
+
133
+ let counts = new Array(10).fill(0);
134
+ const consistents = localData[i].map((x, j) => {
135
+ if (j < func.params.length) return false; // param
136
+ if (x.length === 0 || !x.every((y, i) => i < 1 ? true : y === x[i - 1])) return false; // not consistent
137
+
138
+ counts[0]++;
139
+ return x[0];
140
+ });
141
+
142
+ const integerOnlyF64s = localData[i].map((x, j) => {
143
+ if (j < func.params.length) return false; // param
144
+ if (localValues[j].type === Valtype.i32) return false; // already i32
145
+ if (x.length === 0 || !x.every(y => Number.isInteger(y))) return false; // not all integer values
146
+
147
+ counts[1]++;
148
+ return true;
149
+ });
150
+
151
+ func.consistents = consistents;
152
+ func.integerOnlyF64s = integerOnlyF64s;
153
+
154
+ log += ` ${func.name}: identified ${counts[0]}/${total} locals as consistent${Prefs.verbosePgo ? ':' : ''}\n`;
155
+ if (Prefs.verbosePgo) {
156
+ for (let j = func.params.length; j < localData[i].length; j++) {
157
+ log += ` ${consistents[j] !== false ? '\u001b[92m' : '\u001b[91m'}${localKeys[j]}\u001b[0m: ${new Set(localData[i][j]).size} unique values set\n`;
158
+ }
159
+ }
160
+
161
+ log += ` ${func.name}: identified ${counts[1]}/${localValues.reduce((acc, x) => acc + (x.type === Valtype.f64 ? 1 : 0), 0)} f64 locals as integer usage only${Prefs.verbosePgo ? ':' : ''}\n`;
162
+ if (Prefs.verbosePgo) {
163
+ for (let j = func.params.length; j < localData[i].length; j++) {
164
+ if (localValues[j].type !== Valtype.f64) continue;
165
+ log += ` ${integerOnlyF64s[j] ? '\u001b[92m' : '\u001b[91m'}${localKeys[j]}\u001b[0m\n`;
166
+ }
167
+
168
+ log += '\n';
169
+ }
170
+ }
171
+
172
+ time(2, 'processed PGO data' + log);
173
+ time(3, 'optimizing using PGO data...');
174
+
175
+ log = '';
176
+ for (const x of funcs) {
177
+ const wasmFunc = wasmFuncs.find(y => y.name === x.name);
178
+
179
+ let targets = [];
180
+ for (let i = 0; i < x.integerOnlyF64s.length; i++) {
181
+ const c = x.integerOnlyF64s[i];
182
+ if (c === false) continue;
183
+
184
+ targets.push(i);
185
+ }
186
+
187
+ log += ` ${x.name}: replaced ${targets.length} f64 locals with i32s\n`;
188
+ if (targets.length > 0) Havoc.f64ToI32s(wasmFunc, targets);
189
+
190
+ targets = [];
191
+ let consts = [];
192
+ for (let i = 0; i < x.consistents.length; i++) {
193
+ const c = x.consistents[i];
194
+ if (c === false) continue;
195
+
196
+ targets.push(i);
197
+
198
+ const valtype = x.localValues[i].type;
199
+ consts.push(number(c, valtype)[0]);
200
+ }
201
+
202
+ log += ` ${x.name}: replaced ${targets.length} locals with consts\n`;
203
+ if (targets.length > 0) Havoc.localsToConsts(wasmFunc, targets, consts, { localKeys: x.localKeys });
204
+ }
205
+
206
+ time(3, 'optimized using PGO data' + log);
207
+ };
@@ -26,7 +26,7 @@ const compile = async (file, [ _funcs, _globals ]) => {
26
26
 
27
27
  const porfCompile = (await import(`./index.js?_=${Date.now()}`)).default;
28
28
 
29
- let { funcs, globals, data, exceptions } = porfCompile(source, ['module']);
29
+ let { funcs, globals, data, exceptions } = porfCompile(source, ['module', 'typed']);
30
30
 
31
31
  const allocated = new Set();
32
32
 
@@ -38,11 +38,14 @@ const compile = async (file, [ _funcs, _globals ]) => {
38
38
  x.data[y].offset -= x.data[0].offset;
39
39
  }
40
40
  }
41
- if (x.exceptions) x.exceptions = x.exceptions.map(x => {
42
- const obj = exceptions[x];
43
- if (obj) obj.exceptId = x;
44
- return obj;
45
- }).filter(x => x);
41
+
42
+ if (x.exceptions) {
43
+ x.exceptions = x.exceptions.map(x => {
44
+ const obj = exceptions[x];
45
+ if (obj) obj.exceptId = x;
46
+ return obj;
47
+ }).filter(x => x);
48
+ }
46
49
 
47
50
  const locals = Object.keys(x.locals).reduce((acc, y) => {
48
51
  acc[x.locals[y].idx] = { ...x.locals[y], name: y };
@@ -87,6 +90,8 @@ const compile = async (file, [ _funcs, _globals ]) => {
87
90
  };
88
91
 
89
92
  const precompile = async () => {
93
+ if (globalThis._porf_loadParser) await globalThis._porf_loadParser('@babel/parser');
94
+
90
95
  const dir = join(__dirname, 'builtins');
91
96
 
92
97
  let funcs = [], globals = [];
package/compiler/prefs.js CHANGED
@@ -1,4 +1,4 @@
1
- const onByDefault = [ 'bytestring', 'treeshakeWasmImports', 'alwaysMemory', 'indirectCalls', 'optUnused' ];
1
+ const onByDefault = [ 'bytestring', 'treeshakeWasmImports', 'alwaysMemory', 'indirectCalls', 'optUnused', 'data', 'rmUnusedTypes' ];
2
2
 
3
3
  let cache = {};
4
4
  const obj = new Proxy({}, {
@@ -23,9 +23,14 @@ const obj = new Proxy({}, {
23
23
  // do not cache in web demo as args are changed live
24
24
  if (!globalThis.document) cache[p] = ret;
25
25
  return ret;
26
+ },
27
+
28
+ set(_, p, v) {
29
+ cache[p] = v;
30
+ return true;
26
31
  }
27
32
  });
28
33
 
29
- obj.uncache = () => cache = {};
34
+ export const uncache = () => cache = {};
30
35
 
31
36
  export default obj;
@@ -1,6 +1,5 @@
1
1
  import { Opcodes, Blocktype, Valtype, ValtypeSize } from './wasmSpec.js';
2
2
  import { number } from './embedding.js';
3
- import { unsignedLEB128 } from './encoding.js';
4
3
  import { UNDEFINED } from './builtins.js';
5
4
  import { TYPES } from './types.js';
6
5
  import Prefs from './prefs.js';
@@ -55,10 +54,10 @@ export const PrototypeFuncs = function() {
55
54
 
56
55
  // read from memory
57
56
  [ Opcodes.local_get, iTmp ],
58
- [ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
57
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
59
58
 
60
59
  [ Opcodes.local_get, iTmp ],
61
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
60
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
62
61
  ],
63
62
 
64
63
  // todo: only for 1 argument
@@ -74,12 +73,12 @@ export const PrototypeFuncs = function() {
74
73
  // store value
75
74
  [ Opcodes.local_get, iTmp ],
76
75
  ...wNewMember,
77
- [ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
76
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
78
77
 
79
78
  // store type
80
79
  [ Opcodes.local_get, iTmp ],
81
80
  ...wType,
82
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
81
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
83
82
 
84
83
  // bump array length by 1 and return it
85
84
  ...length.setI32([
@@ -137,10 +136,10 @@ export const PrototypeFuncs = function() {
137
136
  [ Opcodes.local_set, iTmp ],
138
137
 
139
138
  [ Opcodes.local_get, iTmp ],
140
- [ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
139
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
141
140
 
142
141
  [ Opcodes.local_get, iTmp ],
143
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
142
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
144
143
  ])
145
144
  ],
146
145
 
@@ -168,10 +167,10 @@ export const PrototypeFuncs = function() {
168
167
  // load first element
169
168
  // todo/perf: unusedValue opt
170
169
  ...pointer,
171
- [ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
170
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
172
171
 
173
172
  ...pointer,
174
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
173
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
175
174
 
176
175
  // offset page by -1 ind
177
176
  // ...number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
@@ -250,12 +249,12 @@ export const PrototypeFuncs = function() {
250
249
  // store value
251
250
  [ Opcodes.local_get, iTmp2 ],
252
251
  [ Opcodes.local_get, iTmp ],
253
- [ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
252
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
254
253
 
255
254
  // store type
256
255
  [ Opcodes.local_get, iTmp2 ],
257
256
  ...wType,
258
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
257
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
259
258
 
260
259
  // pointer - sizeof value
261
260
  ...length.getCachedI32(),
@@ -292,11 +291,8 @@ export const PrototypeFuncs = function() {
292
291
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
293
292
 
294
293
  return [
295
- // setup new/out array
294
+ // setup new/out array and use pointer for store
296
295
  ...newOut,
297
- [ Opcodes.drop ],
298
-
299
- ...number(0, Valtype.i32), // base 0 for store later
300
296
 
301
297
  ...wIndex,
302
298
  Opcodes.i32_to_u,
@@ -335,13 +331,14 @@ export const PrototypeFuncs = function() {
335
331
  [ Opcodes.i32_add ],
336
332
 
337
333
  // load current string ind {arg}
338
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
334
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
339
335
 
340
336
  // store to new string ind 0
341
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
337
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
342
338
 
343
339
  // return new string (pointer)
344
- ...number(newPointer)
340
+ ...newPointer,
341
+ Opcodes.i32_from_u
345
342
  ];
346
343
  },
347
344
 
@@ -350,11 +347,8 @@ export const PrototypeFuncs = function() {
350
347
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
351
348
 
352
349
  return [
353
- // setup new/out array
350
+ // setup new/out array and use as pointer for store
354
351
  ...newOut,
355
- [ Opcodes.drop ],
356
-
357
- ...number(0, Valtype.i32), // base 0 for store later
358
352
 
359
353
  ...wIndex,
360
354
  Opcodes.i32_to,
@@ -366,13 +360,14 @@ export const PrototypeFuncs = function() {
366
360
  [ Opcodes.i32_add ],
367
361
 
368
362
  // load current string ind {arg}
369
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
363
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
370
364
 
371
365
  // store to new string ind 0
372
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
366
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
373
367
 
374
368
  // return new string (page)
375
- ...number(newPointer)
369
+ ...newPointer,
370
+ Opcodes.i32_from_u
376
371
  ];
377
372
  },
378
373
 
@@ -411,7 +406,7 @@ export const PrototypeFuncs = function() {
411
406
  [ Opcodes.i32_add ],
412
407
 
413
408
  // load current string ind {arg}
414
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
409
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
415
410
  Opcodes.i32_from_u
416
411
  ],
417
412
 
@@ -433,7 +428,7 @@ export const PrototypeFuncs = function() {
433
428
  [ Opcodes.block, Blocktype.void ],
434
429
 
435
430
  [ Opcodes.local_get, iTmp ],
436
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
431
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
437
432
  [ Opcodes.local_set, iTmp2 ],
438
433
 
439
434
  // if not surrogate, continue
@@ -455,7 +450,7 @@ export const PrototypeFuncs = function() {
455
450
 
456
451
  // if not followed by trailing surrogate, return false
457
452
  [ Opcodes.local_get, iTmp ],
458
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize.i16) ],
453
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 + ValtypeSize.i16 ],
459
454
  ...number(0xFC00, Valtype.i32),
460
455
  [ Opcodes.i32_and ],
461
456
  ...number(0xDC00, Valtype.i32),
@@ -507,11 +502,8 @@ export const PrototypeFuncs = function() {
507
502
  const [ newOut, newPointer ] = arrayShell(1, 'i8');
508
503
 
509
504
  return [
510
- // setup new/out array
505
+ // setup new/out array and use pointer for store later
511
506
  ...newOut,
512
- [ Opcodes.drop ],
513
-
514
- ...number(0, Valtype.i32), // base 0 for store later
515
507
 
516
508
  ...wIndex,
517
509
  Opcodes.i32_to_u,
@@ -548,13 +540,14 @@ export const PrototypeFuncs = function() {
548
540
  [ Opcodes.i32_add ],
549
541
 
550
542
  // load current string ind {arg}
551
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
543
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
552
544
 
553
545
  // store to new string ind 0
554
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
546
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
555
547
 
556
548
  // return new string (pointer)
557
- ...number(newPointer)
549
+ ...newPointer,
550
+ Opcodes.i32_from_u
558
551
  ];
559
552
  },
560
553
 
@@ -563,11 +556,8 @@ export const PrototypeFuncs = function() {
563
556
  const [ newOut, newPointer ] = arrayShell(1, 'i8');
564
557
 
565
558
  return [
566
- // setup new/out array
559
+ // setup new/out array and use pointer for later
567
560
  ...newOut,
568
- [ Opcodes.drop ],
569
-
570
- ...number(0, Valtype.i32), // base 0 for store later
571
561
 
572
562
  ...wIndex,
573
563
  Opcodes.i32_to,
@@ -576,13 +566,14 @@ export const PrototypeFuncs = function() {
576
566
  [ Opcodes.i32_add ],
577
567
 
578
568
  // load current string ind {arg}
579
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
569
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
580
570
 
581
571
  // store to new string ind 0
582
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
572
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
583
573
 
584
574
  // return new string (page)
585
- ...number(newPointer)
575
+ ...newPointer,
576
+ Opcodes.i32_from_u
586
577
  ];
587
578
  },
588
579
 
@@ -618,7 +609,7 @@ export const PrototypeFuncs = function() {
618
609
  [ Opcodes.i32_add ],
619
610
 
620
611
  // load current string ind {arg}
621
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
612
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
622
613
  Opcodes.i32_from_u
623
614
  ],
624
615
 
package/compiler/wrap.js CHANGED
@@ -6,8 +6,25 @@ import { TYPES } from './types.js';
6
6
  import { log } from './log.js';
7
7
  import Prefs from './prefs.js';
8
8
 
9
+ const fs = (typeof process?.version !== 'undefined' ? (await import('node:fs')) : undefined);
10
+
9
11
  const bold = x => `\u001b[1m${x}\u001b[0m`;
10
12
 
13
+ export const readByteStr = (memory, ptr) => {
14
+ const length = (new Int32Array(memory.buffer.slice(ptr, ptr + 4), 0, 1))[0];
15
+ return Array.from(new Uint8Array(memory.buffer, ptr + 4, length)).map(x => String.fromCharCode(x)).join('');
16
+ };
17
+
18
+ export const writeByteStr = (memory, ptr, str) => {
19
+ const length = str.length;
20
+ (new Int32Array(memory.buffer.slice(ptr, ptr + 4), 0, 1))[0] = length;
21
+
22
+ const arr = new Uint8Array(memory.buffer, ptr + 4, length);
23
+ for (let i = 0; i < length; i++) {
24
+ arr[i] = str.charCodeAt(i);
25
+ }
26
+ };
27
+
11
28
  const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
12
29
  switch (type) {
13
30
  case TYPES.boolean: return Boolean(value);
@@ -29,17 +46,17 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
29
46
  }
30
47
 
31
48
  case TYPES.string: {
32
- const length = (new Int32Array(memory.buffer, value, 1))[0];
49
+ const length = (new Int32Array(memory.buffer.slice(value, value + 4), 0, 1))[0];
33
50
  return Array.from(new Uint16Array(memory.buffer, value + 4, length)).map(x => String.fromCharCode(x)).join('');
34
51
  }
35
52
 
36
53
  case TYPES.bytestring: {
37
- const length = (new Int32Array(memory.buffer, value, 1))[0];
54
+ const length = (new Int32Array(memory.buffer.slice(value, value + 4), 0, 1))[0];
38
55
  return Array.from(new Uint8Array(memory.buffer, value + 4, length)).map(x => String.fromCharCode(x)).join('');
39
56
  }
40
57
 
41
58
  case TYPES.array: {
42
- const length = (new Int32Array(memory.buffer, value, 1))[0];
59
+ const length = (new Int32Array(memory.buffer.slice(value, value + 4), 0, 1))[0];
43
60
 
44
61
  const out = [];
45
62
  for (let i = 0; i < length; i++) {
@@ -60,12 +77,12 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
60
77
  }
61
78
 
62
79
  case TYPES.date: {
63
- const t = (new Float64Array(memory.buffer, value, 1))[0];
80
+ const t = (new Float64Array(memory.buffer.slice(value, value + 8), 0, 1))[0];
64
81
  return new Date(t);
65
82
  }
66
83
 
67
84
  case TYPES.set: {
68
- const size = (new Int32Array(memory.buffer, value, 1))[0];
85
+ const size = (new Int32Array(memory.buffer.slice(value, value + 4), 0, 1))[0];
69
86
 
70
87
  const out = new Set();
71
88
  for (let i = 0; i < size; i++) {
@@ -85,44 +102,47 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
85
102
  return out;
86
103
  }
87
104
 
88
- case TYPES.symbol: {
89
- const descStore = pages.get('bytestring: __Porffor_symbol_descStore/ptr').ind * pageSize;
90
- const offset = descStore + 4 + ((value - 1) * 9);
105
+ // case TYPES.symbol: {
106
+ // const descStore = pages.get('bytestring: __Porffor_symbol_descStore/ptr').ind * pageSize;
107
+ // const offset = descStore + 4 + ((value - 1) * 9);
91
108
 
92
- const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
93
- const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
109
+ // const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
110
+ // const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
94
111
 
95
- const desc = porfToJSValue({ memory, funcs, pages }, v, t);
112
+ // const desc = porfToJSValue({ memory, funcs, pages }, v, t);
96
113
 
97
- return Symbol(desc);
98
- }
114
+ // return Symbol(desc);
115
+ // }
99
116
 
100
117
  default: return value;
101
118
  }
102
119
  };
103
120
 
104
- export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
121
+ export default (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
105
122
  const times = [];
106
123
 
107
124
  const t1 = performance.now();
108
- const { wasm, funcs, globals, tags, exceptions, pages, c } = compile(source, flags);
125
+ const { wasm, funcs, globals, tags, exceptions, pages, c } = typeof source === 'object' ? source : compile(source, flags);
109
126
 
110
127
  globalThis.porfDebugInfo = { funcs, globals };
111
128
 
112
- if (source.includes('export function')) flags.push('module');
129
+ if (source.includes?.('export ')) flags.push('module');
113
130
 
114
- // (await import('node:fs')).writeFileSync('out.wasm', Buffer.from(wasm));
131
+ // fs.writeFileSync('out.wasm', Buffer.from(wasm));
115
132
 
116
133
  times.push(performance.now() - t1);
117
134
  if (Prefs.profileCompiler) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
118
135
 
119
136
  const backtrace = (funcInd, blobOffset) => {
120
- if (funcInd == null || blobOffset == null) return false;
137
+ if (funcInd == null || blobOffset == null ||
138
+ Number.isNaN(funcInd) || Number.isNaN(blobOffset)) return false;
121
139
 
122
140
  // convert blob offset -> function wasm offset.
123
141
  // this is not good code and is somewhat duplicated
124
142
  // I just want it to work for debugging, I don't care about perf/yes
125
143
  const func = funcs.find(x => x.index === funcInd);
144
+ if (!func) return false;
145
+
126
146
  const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
127
147
 
128
148
  let localDecl = [], typeCount = 0, lastType;
@@ -197,13 +217,15 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
197
217
 
198
218
  let instance;
199
219
  try {
200
- let wasmEngine = WebAssembly;
201
- if (Prefs.asur) {
202
- log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
203
- wasmEngine = await import('../asur/index.js');
204
- }
205
-
206
- 0, { instance } = await wasmEngine.instantiate(wasm, {
220
+ // let wasmEngine = WebAssembly;
221
+ // if (Prefs.asur) {
222
+ // log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
223
+ // wasmEngine = await import('../asur/index.js');
224
+ // }
225
+
226
+ // 0, { instance } = await wasmEngine.instantiate(wasm, {
227
+ const module = new WebAssembly.Module(wasm);
228
+ instance = new WebAssembly.Instance(module, {
207
229
  '': {
208
230
  p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
209
231
  c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
@@ -211,12 +233,31 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
211
233
  u: () => performance.timeOrigin,
212
234
  y: () => {},
213
235
  z: () => {},
236
+ w: (ind, outPtr) => { // readArgv
237
+ const args = process.argv.slice(2).filter(x => !x.startsWith('-'));
238
+ const str = args[ind];
239
+ if (!str) return -1;
240
+
241
+ writeByteStr(memory, outPtr, str);
242
+ return str.length;
243
+ },
244
+ q: (pathPtr, outPtr) => { // readFile
245
+ try {
246
+ const path = readByteStr(memory, pathPtr);
247
+ const contents = fs.readFileSync(path, 'utf8');
248
+ writeByteStr(memory, outPtr, contents);
249
+ return contents.length;
250
+ } catch {
251
+ return -1;
252
+ }
253
+ },
214
254
  ...customImports
215
255
  }
216
256
  });
217
257
  } catch (e) {
218
258
  // only backtrace for runner, not test262/etc
219
259
  if (!process.argv[1].includes('/runner')) throw e;
260
+ if (!(e instanceof WebAssembly.CompileError)) throw e;
220
261
 
221
262
  const funcInd = parseInt(e.message.match(/function #([0-9]+) /)?.[1]);
222
263
  const blobOffset = parseInt(e.message.split('@')?.[1]);