porffor 0.2.0-fde989a → 0.14.0-0d97d1e6a

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.
Files changed (61) hide show
  1. package/CONTRIBUTING.md +256 -0
  2. package/LICENSE +20 -20
  3. package/README.md +131 -86
  4. package/asur/README.md +2 -0
  5. package/asur/index.js +1262 -0
  6. package/byg/index.js +216 -0
  7. package/compiler/2c.js +2 -53
  8. package/compiler/{sections.js → assemble.js} +95 -21
  9. package/compiler/builtins/annexb_string.js +72 -0
  10. package/compiler/builtins/annexb_string.ts +18 -0
  11. package/compiler/builtins/array.ts +145 -0
  12. package/compiler/builtins/base64.ts +76 -0
  13. package/compiler/builtins/boolean.ts +18 -0
  14. package/compiler/builtins/crypto.ts +120 -0
  15. package/compiler/builtins/date.ts +2067 -0
  16. package/compiler/builtins/escape.ts +141 -0
  17. package/compiler/builtins/function.ts +5 -0
  18. package/compiler/builtins/int.ts +145 -0
  19. package/compiler/builtins/number.ts +529 -0
  20. package/compiler/builtins/object.ts +4 -0
  21. package/compiler/builtins/porffor.d.ts +60 -0
  22. package/compiler/builtins/set.ts +187 -0
  23. package/compiler/builtins/string.ts +1080 -0
  24. package/compiler/builtins/symbol.ts +61 -0
  25. package/compiler/builtins.js +440 -285
  26. package/compiler/{codeGen.js → codegen.js} +1116 -489
  27. package/compiler/decompile.js +3 -4
  28. package/compiler/embedding.js +22 -22
  29. package/compiler/encoding.js +94 -10
  30. package/compiler/expression.js +1 -1
  31. package/compiler/generated_builtins.js +1670 -0
  32. package/compiler/index.js +27 -43
  33. package/compiler/log.js +6 -3
  34. package/compiler/opt.js +55 -41
  35. package/compiler/parse.js +38 -30
  36. package/compiler/precompile.js +120 -0
  37. package/compiler/prefs.js +31 -0
  38. package/compiler/prototype.js +31 -46
  39. package/compiler/types.js +38 -0
  40. package/compiler/wasmSpec.js +33 -8
  41. package/compiler/wrap.js +107 -71
  42. package/package.json +9 -5
  43. package/porf +2 -0
  44. package/rhemyn/compile.js +46 -27
  45. package/rhemyn/parse.js +322 -320
  46. package/rhemyn/test/parse.js +58 -58
  47. package/runner/compare.js +33 -34
  48. package/runner/debug.js +117 -0
  49. package/runner/index.js +78 -11
  50. package/runner/profiler.js +75 -0
  51. package/runner/repl.js +40 -13
  52. package/runner/sizes.js +37 -37
  53. package/runner/version.js +10 -8
  54. package/compiler/builtins/base64.js +0 -92
  55. package/filesize.cmd +0 -2
  56. package/runner/info.js +0 -89
  57. package/runner/profile.js +0 -46
  58. package/runner/results.json +0 -1
  59. package/runner/transform.js +0 -15
  60. package/tmp.c +0 -661
  61. package/util/enum.js +0 -20
package/byg/index.js ADDED
@@ -0,0 +1,216 @@
1
+ import fs from 'node:fs';
2
+
3
+ const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
4
+ const printLine = (line, number, breakpoint = false, current = false, selected = false) => {
5
+ console.log(`\x1b[${breakpoint ? (selected ? '43' : '103') : (selected ? '47' : '100')}m\x1b[${selected || breakpoint ? '30' : '97'}m${number.toFixed(0).padStart(4, ' ')}\x1b[${breakpoint ? (selected ? '33' : '93') : (selected ? '37' : '90')}m\x1b[${current ? '47' : '40'}m▌ \x1b[${current ? '47' : '40'}m\x1b[${current ? '30' : '37'}m${current ? noAnsi(line) : line}\x1b[0K`);
6
+ };
7
+
8
+ const box = (x, y, width, height, title = '', content = [], color = ['90', '100', '37', '35', '45'], padding = true) => {
9
+ if (padding) {
10
+ width += 1;
11
+ height += 1;
12
+
13
+ // top
14
+ process.stdout.write(`\x1b[48m\x1b[${y + 1};${x + 1}H\x1b[${color[0]}m` + '▄'.repeat(width));
15
+ // bottom
16
+ process.stdout.write(`\x1b[${y + height + 1};${x + 1}H▝` + '▀'.repeat(width - 1) + '▘');
17
+ // left
18
+ process.stdout.write(`\x1b[${y + 1};${x + 1}H▗` + '\x1b[1B\x1b[1D▐'.repeat(height - 1));
19
+ // right
20
+ process.stdout.write(`\x1b[${y + 1};${x + width + 1}H▖` + '\x1b[1B\x1b[1D▌'.repeat(height - 1));
21
+
22
+ x += 1;
23
+ y += 1;
24
+ width -= 1;
25
+ height -= 1;
26
+ }
27
+
28
+ // bg
29
+ process.stdout.write(`\x1b[${y + 1};${x + 1}H\x1b[${color[1]}m` + ' '.repeat(width) + (`\x1b[1B\x1b[${width}D` + ' '.repeat(width)).repeat(Math.max(0, height - 1)));
30
+
31
+ // title
32
+ if (title) process.stdout.write(`\x1b[${y};${x}H\x1b[0m\x1b[${color[3]}m▐\x1b[${color[4]}m\x1b[${color[2]}m\x1b[1m${' '.repeat((width - title.length) / 2 | 0)}${title}${' '.repeat(width - (((width - title.length) / 2 | 0)) - title.length)}\x1b[0m\x1b[${color[3]}m▌`);
33
+
34
+ // content
35
+ process.stdout.write(`\x1b[${y + (title ? 1 : 1)};${x + 1}H\x1b[${color[1]}m\x1b[${color[2]}m${content.join(`\x1b[1B\x1b[${x + 1}G`)}`);
36
+ };
37
+
38
+ const controls = {
39
+ 'ret': 'resume ',
40
+ 'b': 'breakpoint ',
41
+ 's': 'step over',
42
+ 'i': 'step in',
43
+ 'o': 'step out ',
44
+ };
45
+
46
+ const controlInfo = Object.keys(controls).reduce((acc, x, i) => acc + `\x1B[45m\x1B[97m${x}\x1b[105m\x1b[37m ${controls[x]} `, '');
47
+ const plainControlInfo = noAnsi(controlInfo);
48
+
49
+ globalThis.termWidth = process.stdout.columns || 80;
50
+ globalThis.termHeight = process.stdout.rows || 24;
51
+
52
+ export default ({ lines, pause, breakpoint }) => {
53
+ process.stdin.setRawMode(true);
54
+ process.stdin.resume();
55
+ process.stdin.setEncoding('utf8');
56
+
57
+ process.stdin.on('data', s => {
58
+ // ctrl c
59
+ if (s === '\u0003') {
60
+ process.exit();
61
+ }
62
+
63
+ if (!paused) pause();
64
+ });
65
+
66
+ const stdin = fs.openSync('/dev/stdin', 'r+');
67
+ const readCharSync = () => {
68
+ const buffer = Buffer.alloc(1);
69
+ fs.readSync(stdin, buffer, 0, 1);
70
+ return buffer.toString('utf8');
71
+ };
72
+
73
+ const tooManyLines = lines.length > (termHeight - 1);
74
+ const breakpoints = {};
75
+
76
+ process.on('exit', () => {
77
+ process.stdout.write('\x1b[0m');
78
+ });
79
+
80
+ console.clear();
81
+
82
+ let paused = true;
83
+ return (_paused, currentLine, text, boxes = []) => {
84
+ paused = _paused;
85
+
86
+ let scrollOffset = 0;
87
+ let currentLinePos = currentLine;
88
+
89
+ const draw = () => {
90
+ console.clear();
91
+ process.stdout.write(`\x1b[1;1H`);
92
+
93
+ if (tooManyLines) {
94
+ const edgePadding = (termHeight / 2) - 1;
95
+ let beforePadding = currentLine - edgePadding;
96
+ let afterPadding = currentLine + edgePadding + 1;
97
+
98
+ if (beforePadding < 0) {
99
+ afterPadding += Math.abs(beforePadding);
100
+ beforePadding = 0;
101
+ }
102
+
103
+ beforePadding += scrollOffset;
104
+ afterPadding += scrollOffset;
105
+
106
+ if (afterPadding > lines.length) {
107
+ beforePadding -= afterPadding - lines.length;
108
+ afterPadding = lines.length;
109
+ }
110
+
111
+ for (let i = Math.max(0, beforePadding); i < Math.max(0, beforePadding) + (termHeight - 1); i++) {
112
+ printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
113
+ }
114
+
115
+ currentLinePos = currentLine - beforePadding;
116
+ } else {
117
+ for (let i = 0; i < lines.length; i++) {
118
+ printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
119
+ }
120
+ }
121
+
122
+ for (const x of boxes) {
123
+ const y = x.y({ currentLinePos });
124
+ if (y < 0 || y >= termHeight) continue;
125
+
126
+ box(x.x, y, x.width, x.height, x.title, x.content);
127
+ }
128
+
129
+ // text += ` | rss: ${(process.memoryUsage.rss() / 1024 / 1024).toFixed(2)}mb`;
130
+
131
+ process.stdout.write(`\x1b[${termHeight};1H\x1b[105m\x1b[37m${text}${' '.repeat(termWidth - plainControlInfo.length - noAnsi(text).length - 1)}${controlInfo} \x1b[0m`);
132
+ };
133
+
134
+ draw();
135
+
136
+ let lastSpecial = false;
137
+ while (true) {
138
+ const char = readCharSync();
139
+
140
+ if (char === '[') {
141
+ lastSpecial = true;
142
+ continue;
143
+ }
144
+
145
+ switch (char.toLowerCase()) {
146
+ case '\r': {
147
+ paused = false;
148
+ return 'resume';
149
+ }
150
+
151
+ case 's': {
152
+ return 'stepOver';
153
+ }
154
+
155
+ case 'i': {
156
+ return 'stepIn';
157
+ }
158
+
159
+ case 'o': {
160
+ return 'stepOut';
161
+ }
162
+
163
+ case 'b': {
164
+ if (!lastSpecial) {
165
+ // b pressed normally
166
+ breakpoints[currentLine + scrollOffset] = !breakpoints[currentLine + scrollOffset];
167
+ draw();
168
+
169
+ breakpoint(currentLine + scrollOffset, breakpoints[currentLine + scrollOffset]);
170
+ break;
171
+ }
172
+
173
+ // arrow down
174
+ if (scrollOffset < lines.length - currentLine - 1) scrollOffset++;
175
+ draw();
176
+ break;
177
+ }
178
+
179
+ case 'a': {
180
+ if (!lastSpecial) break;
181
+
182
+ // arrow up
183
+ if (scrollOffset > -currentLine) scrollOffset--;
184
+ draw();
185
+
186
+ break;
187
+ }
188
+
189
+ case '5': {
190
+ if (!lastSpecial) break;
191
+
192
+ // page up
193
+ scrollOffset -= Math.min(scrollOffset + currentLine, termHeight - 1);
194
+ draw();
195
+ break;
196
+ }
197
+
198
+ case '6': {
199
+ if (!lastSpecial) break;
200
+
201
+ // page down
202
+ scrollOffset += Math.min(lines.length - (scrollOffset + currentLine) - 1, termHeight - 1);
203
+ draw();
204
+ break;
205
+ }
206
+
207
+ case 'q':
208
+ case '\u0003': {
209
+ process.exit();
210
+ }
211
+ }
212
+
213
+ lastSpecial = false;
214
+ }
215
+ };
216
+ };
package/compiler/2c.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
2
2
  import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
3
3
  import { operatorOpcode } from './expression.js';
4
- import { log } from "./log.js";
4
+ import { log } from './log.js';
5
5
 
6
6
  const CValtype = {
7
7
  i8: 'i8',
@@ -106,17 +106,6 @@ for (const x in CValtype) {
106
106
  if (Valtype[x]) CValtype[Valtype[x]] = CValtype[x];
107
107
  }
108
108
 
109
- const todo = msg => {
110
- class TodoError extends Error {
111
- constructor(message) {
112
- super(message);
113
- this.name = 'TodoError';
114
- }
115
- }
116
-
117
- throw new TodoError(`todo: ${msg}`);
118
- };
119
-
120
109
  const removeBrackets = str => {
121
110
  // return str;
122
111
  // if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
@@ -167,11 +156,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
167
156
  prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
168
157
  }
169
158
 
170
- // for (const [ x, p ] of pages) {
171
- // out += `${CValtype[p.type]} ${x.replace(': ', '_').replace(/[^0-9a-zA-Z_]/g, '')}[100]`;
172
- // out += ';\n';
173
- // }
174
-
175
159
  if (out) out += '\n';
176
160
 
177
161
  let depth = 1;
@@ -213,9 +197,9 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
213
197
 
214
198
  for (const f of funcs) {
215
199
  depth = 1;
200
+ brDepth = 0;
216
201
 
217
202
  const invLocals = inv(f.locals, x => x.idx);
218
- // if (f.returns.length > 1) todo('funcs returning >1 value unsupported');
219
203
 
220
204
  for (const x in invLocals) {
221
205
  invLocals[x] = sanitize(invLocals[x]);
@@ -247,12 +231,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
247
231
  const brs = [];
248
232
  let lastCond = false;
249
233
 
250
- // let brDepth = 0;
251
-
252
234
  const blockStart = (i, loop) => {
253
- // reset "stack"
254
- // vals = [];
255
-
256
235
  rets.push(i[1]);
257
236
 
258
237
  const br = brId++;
@@ -269,25 +248,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
269
248
  brDepth++;
270
249
  };
271
250
 
272
- const highlight = i => {
273
- const surrounding = 6;
274
-
275
- const decomp = decompile(f.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, f.locals, f.params, f.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
276
-
277
- const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
278
- let longest = 0;
279
- for (let j = 0; j < decomp.length; j++) {
280
- longest = Math.max(longest, noAnsi(decomp[j]).length);
281
- }
282
-
283
- const middle = Math.floor(decomp.length / 2);
284
- decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
285
-
286
- console.log('\x1B[90m...\x1B[0m');
287
- console.log(decomp.join('\n'));
288
- console.log('\x1B[90m...\x1B[0m\n');
289
- };
290
-
291
251
  for (let _ = 0; _ < f.wasm.length; _++) {
292
252
  const i = f.wasm[_];
293
253
  if (!i || !i[0]) continue;
@@ -415,8 +375,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
415
375
  const br = brs.at(-1);
416
376
  const ret = rets.at(-1);
417
377
  if (ret && ret !== Blocktype.void) {
418
- // console.log(vals, ret);
419
- // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
420
378
  if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
421
379
  // vals.push(`_r${br}`);
422
380
  }
@@ -425,8 +383,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
425
383
  line(`} else {`, false);
426
384
  depth++;
427
385
 
428
- // reset "stack"
429
- // vals = [];
430
386
  break;
431
387
  }
432
388
 
@@ -441,8 +397,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
441
397
  const br = brs.pop();
442
398
  const ret = rets.pop();
443
399
  if (ret && ret !== Blocktype.void) {
444
- // console.log(vals, ret);
445
- // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
446
400
  if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
447
401
  vals.push(`_r${br}`);
448
402
  }
@@ -541,18 +495,14 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
541
495
 
542
496
  case Opcodes.br: {
543
497
  const ret = rets[brDepth - i[1] - 1];
544
- // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
545
498
  if (ret !== Blocktype.void) line(`_r${brs[brDepth - i[1] - 1]} = ${removeBrackets(vals.pop())}`);
546
499
  line(`goto j${brs[brDepth - i[1] - 1]}`);
547
500
 
548
- // // reset "stack"
549
- // vals = [];
550
501
  break;
551
502
  }
552
503
 
553
504
  case Opcodes.br_if: {
554
505
  const ret = rets[brDepth - i[1] - 1];
555
- // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
556
506
 
557
507
  let cond = removeBrackets(vals.pop());
558
508
  if (!lastCond) {
@@ -602,7 +552,6 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
602
552
  }
603
553
 
604
554
  log.warning('2c', `unimplemented op: ${invOpcodes[i[0]]}`);
605
- // todo(`unimplemented op: ${invOpcodes[i[0]]}`);
606
555
  }
607
556
 
608
557
  lastCond = false;
@@ -1,8 +1,8 @@
1
- import { Valtype, FuncType, Empty, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize } from './wasmSpec.js';
2
- import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 } from './encoding.js';
3
- import { number } from './embedding.js';
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';
4
3
  import { importedFuncs } from './builtins.js';
5
- import { log } from "./log.js";
4
+ import { log } from './log.js';
5
+ import Prefs from './prefs.js';
6
6
 
7
7
  const createSection = (type, data) => [
8
8
  type,
@@ -26,12 +26,12 @@ export default (funcs, globals, tags, pages, data, flags) => {
26
26
 
27
27
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
28
28
 
29
- const compileHints = process.argv.includes('-compile-hints');
30
- if (compileHints) log.warning('sections', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
29
+ const compileHints = Prefs.compileHints;
30
+ if (compileHints) log.warning('assemble', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
31
31
 
32
32
  const getType = (params, returns) => {
33
33
  const hash = `${params.join(',')}_${returns.join(',')}`;
34
- if (optLog) log('sections', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
34
+ if (Prefs.optLog) log('assemble', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
35
35
  if (optLevel >= 1 && typeCache[hash] !== undefined) return typeCache[hash];
36
36
 
37
37
  const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
@@ -44,7 +44,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
44
44
 
45
45
  let importFuncs = [];
46
46
 
47
- if (optLevel < 1) {
47
+ if (optLevel < 1 || !Prefs.treeshakeWasmImports) {
48
48
  importFuncs = importedFuncs;
49
49
  } else {
50
50
  let imports = new Map();
@@ -65,6 +65,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
65
65
  importFuncs = [...imports.values()];
66
66
 
67
67
  // fix call indexes for non-imports
68
+ // also fix call_indirect types
68
69
  const delta = importedFuncs.length - importFuncs.length;
69
70
  for (const f of funcs) {
70
71
  f.originalIndex = f.index;
@@ -74,16 +75,26 @@ export default (funcs, globals, tags, pages, data, flags) => {
74
75
  if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] >= importedFuncs.length) {
75
76
  inst[1] -= delta;
76
77
  }
78
+
79
+ if (inst[0] === Opcodes.call_indirect) {
80
+ const params = [];
81
+ for (let i = 0; i < inst[1]; i++) {
82
+ params.push(valtypeBinary, Valtype.i32);
83
+ }
84
+
85
+ const returns = [ valtypeBinary, Valtype.i32 ];
86
+ inst[1] = getType(params, returns);
87
+ }
77
88
  }
78
89
  }
79
90
  }
80
91
  globalThis.importFuncs = importFuncs;
81
92
 
82
- if (optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
93
+ if (Prefs.optLog) log('assemble', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
83
94
 
84
95
  const importSection = importFuncs.length === 0 ? [] : createSection(
85
96
  Section.import,
86
- encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
97
+ encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(x.name.startsWith('profile') ? Valtype.i32 : valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
87
98
  );
88
99
 
89
100
  const funcSection = createSection(
@@ -91,22 +102,75 @@ export default (funcs, globals, tags, pages, data, flags) => {
91
102
  encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
92
103
  );
93
104
 
94
- // compilation hints section - unspecd, v8 only
95
- // https://github.com/WebAssembly/design/issues/1473#issuecomment-1431274746
96
- const chSection = !compileHints ? [] : customSection(
97
- 'compilationHints',
98
- // for now just do everything as optimise eager
99
- encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
105
+ const tableSection = !funcs.table ? [] : createSection(
106
+ Section.table,
107
+ encodeVector([ [ Reftype.funcref, 0x00, funcs.length ] ])
100
108
  );
101
109
 
102
- const globalSection = Object.keys(globals).length === 0 ? [] : createSection(
103
- Section.global,
104
- encodeVector(Object.keys(globals).map(x => [ globals[x].type, 0x01, ...number(globals[x].init ?? 0, globals[x].type).flat(), Opcodes.end ]))
110
+ const elementSection = !funcs.table ? [] : createSection(
111
+ Section.element,
112
+ encodeVector([ [
113
+ 0x00,
114
+ Opcodes.i32_const, 0, Opcodes.end,
115
+ ...encodeVector(funcs.map(x => x.index))
116
+ ] ])
105
117
  );
106
118
 
119
+ // const t0 = performance.now();
120
+
121
+ // specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
122
+ const globalsValues = Object.values(globals);
123
+
124
+ let globalSection = [];
125
+ if (globalsValues.length > 0) {
126
+ let data = unsignedLEB128(globalsValues.length);
127
+ for (let i = 0; i < globalsValues.length; i++) {
128
+ const global = globalsValues[i];
129
+
130
+ switch (global.type) {
131
+ case Valtype.i32:
132
+ if (i > 0) data.push(Opcodes.end, Valtype.i32, 0x01, Opcodes.i32_const);
133
+ else data.push(Valtype.i32, 0x01, Opcodes.i32_const);
134
+
135
+ signedLEB128_into(global.init ?? 0, data);
136
+ break;
137
+
138
+ case Valtype.i64:
139
+ if (i > 0) data.push(Opcodes.end, Valtype.i64, 0x01, Opcodes.i64_const);
140
+ else data.push(Valtype.i64, 0x01, Opcodes.i64_const);
141
+
142
+ signedLEB128_into(global.init ?? 0, data);
143
+ break;
144
+
145
+ case Valtype.f64:
146
+ if (i > 0) data.push(Opcodes.end, Valtype.f64, 0x01, Opcodes.f64_const);
147
+ else data.push(Valtype.f64, 0x01, Opcodes.f64_const);
148
+
149
+ ieee754_binary64_into(global.init ?? 0, data);
150
+ break;
151
+ }
152
+ }
153
+
154
+ data.push(Opcodes.end);
155
+
156
+ globalSection.push(Section.global);
157
+
158
+ unsignedLEB128_into(data.length, globalSection);
159
+ globalSection = globalSection.concat(data);
160
+ }
161
+
162
+ // if (Prefs.profileCompiler) {
163
+ // const log = console.log;
164
+ // console.log = function () {
165
+ // log.apply(this, arguments);
166
+ // console.log = log;
167
+ // console.log(` a. assembled global section in ${(performance.now() - t0).toFixed(2)}ms\n`);
168
+ // };
169
+ // }
170
+
107
171
  const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
108
172
 
109
- if (process.argv.includes('-always-memory') && pages.size === 0) pages.set('-always-memory', 0);
173
+ if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
110
174
  if (optLevel === 0) pages.set('O0 precaution', 0);
111
175
 
112
176
  const usesMemory = pages.size > 0;
@@ -169,7 +233,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
169
233
  unsignedLEB128(data.length)
170
234
  );
171
235
 
172
- if (process.argv.includes('-sections')) console.log({
236
+ if (Prefs.sections) console.log({
173
237
  typeSection: typeSection.map(x => x.toString(16)),
174
238
  importSection: importSection.map(x => x.toString(16)),
175
239
  funcSection: funcSection.map(x => x.toString(16)),
@@ -179,6 +243,14 @@ export default (funcs, globals, tags, pages, data, flags) => {
179
243
  dataSection: dataSection.map(x => x.toString(16)),
180
244
  });
181
245
 
246
+ // compilation hints section - unspecd, v8 only
247
+ // https://github.com/WebAssembly/design/issues/1473#issuecomment-1431274746
248
+ const chSection = !compileHints ? [] : customSection(
249
+ 'compilationHints',
250
+ // for now just do everything as optimize eager
251
+ encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
252
+ );
253
+
182
254
  return Uint8Array.from([
183
255
  ...Magic,
184
256
  ...ModuleVersion,
@@ -186,10 +258,12 @@ export default (funcs, globals, tags, pages, data, flags) => {
186
258
  ...importSection,
187
259
  ...funcSection,
188
260
  ...chSection,
261
+ ...tableSection,
189
262
  ...memorySection,
190
263
  ...tagSection,
191
264
  ...globalSection,
192
265
  ...exportSection,
266
+ ...elementSection,
193
267
  ...dataCountSection,
194
268
  ...codeSection,
195
269
  ...dataSection
@@ -0,0 +1,72 @@
1
+ export default () => {
2
+ let out = `// @porf --funsafe-no-unlikely-proto-checks --valtype=i32
3
+ `;
4
+
5
+ const noArgs = (a0, a1) => out += `
6
+ export const __String_prototype_${a0} = (_this: string) => {
7
+ let out: string = Porffor.s\`<${a1}>\`;
8
+
9
+ let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${(2 + a1.length) * 2};
10
+
11
+ let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
12
+ let thisLen: i32 = _this.length;
13
+ let endPtr: i32 = thisPtr + thisLen * 2;
14
+
15
+ while (thisPtr < endPtr) {
16
+ let chr: i32 = Porffor.wasm.i32.load16_u(thisPtr, 0, 4);
17
+ Porffor.wasm.i32.store16(outPtr, chr, 0, 4);
18
+
19
+ thisPtr += 2;
20
+ outPtr += 2;
21
+ }
22
+
23
+ Porffor.wasm.i32.store16(outPtr, 60, 0, 4); // <
24
+ Porffor.wasm.i32.store16(outPtr, 47, 0, 6); // /
25
+
26
+ ${[...a1].map((x, i) => ` Porffor.wasm.i32.store16(outPtr, ${x.charCodeAt(0)}, 0, ${8 + i * 2}); // ${x}`).join('\n')}
27
+
28
+ Porffor.wasm.i32.store16(outPtr, 62, 0, ${8 + a1.length * 2}); // >
29
+
30
+ out.length = thisLen + ${a1.length * 2 + 2 + 3};
31
+
32
+ return out;
33
+ };
34
+ export const __ByteString_prototype_${a0} = (_this: bytestring) => {
35
+ let out: bytestring = Porffor.bs\`<${a1}>\`;
36
+
37
+ let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${2 + a1.length};
38
+
39
+ let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
40
+ let thisLen: i32 = _this.length;
41
+ let endPtr: i32 = thisPtr + thisLen;
42
+
43
+ while (thisPtr < endPtr) {
44
+ let chr: i32 = Porffor.wasm.i32.load8_u(thisPtr++, 0, 4);
45
+ Porffor.wasm.i32.store8(outPtr++, chr, 0, 4);
46
+ }
47
+
48
+ Porffor.wasm.i32.store8(outPtr, 60, 0, 4); // <
49
+ Porffor.wasm.i32.store8(outPtr, 47, 0, 5); // /
50
+
51
+ ${[...a1].map((x, i) => ` Porffor.wasm.i32.store8(outPtr, ${x.charCodeAt(0)}, 0, ${6 + i}); // ${x}`).join('\n')}
52
+
53
+ Porffor.wasm.i32.store8(outPtr, 62, 0, ${6 + a1.length}); // >
54
+
55
+ out.length = thisLen + ${a1.length * 2 + 2 + 3};
56
+
57
+ return out;
58
+ };
59
+ `;
60
+
61
+ noArgs('big', 'big');
62
+ noArgs('blink', 'blink');
63
+ noArgs('bold', 'b');
64
+ noArgs('fixed', 'tt');
65
+ noArgs('italics', 'i');
66
+ noArgs('small', 'small');
67
+ noArgs('strike', 'strike');
68
+ noArgs('sub', 'sub');
69
+ noArgs('sup', 'sup');
70
+
71
+ return out;
72
+ };
@@ -0,0 +1,18 @@
1
+ // @porf --valtype=i32
2
+
3
+ export const __String_prototype_trimLeft = (_this: string) => {
4
+ return __String_prototype_trimStart(_this);
5
+ };
6
+
7
+ export const __ByteString_prototype_trimLeft = (_this: string) => {
8
+ return __ByteString_prototype_trimStart(_this);
9
+ };
10
+
11
+
12
+ export const __String_prototype_trimRight = (_this: string) => {
13
+ return __String_prototype_trimEnd(_this);
14
+ };
15
+
16
+ export const __ByteString_prototype_trimRight = (_this: string) => {
17
+ return __ByteString_prototype_trimEnd(_this);
18
+ };