porffor 0.0.0-44bc2d8 → 0.0.0-61de729

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.
@@ -35,7 +35,14 @@ const debug = str => {
35
35
  };
36
36
 
37
37
  const todo = msg => {
38
- throw new Error(`todo: ${msg}`);
38
+ class TodoError extends Error {
39
+ constructor(message) {
40
+ super(message);
41
+ this.name = 'TodoError';
42
+ }
43
+ }
44
+
45
+ throw new TodoError(`todo: ${msg}`);
39
46
 
40
47
  const code = [];
41
48
 
@@ -298,10 +305,10 @@ const localTmp = (scope, name, type = valtypeBinary) => {
298
305
  return idx;
299
306
  };
300
307
 
301
- const performLogicOp = (scope, op, left, right) => {
308
+ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
302
309
  const checks = {
303
- '||': Opcodes.eqz,
304
- '&&': [ Opcodes.i32_to ]
310
+ '||': falsy,
311
+ '&&': truthy,
305
312
  // todo: ??
306
313
  };
307
314
 
@@ -313,7 +320,8 @@ const performLogicOp = (scope, op, left, right) => {
313
320
  return [
314
321
  ...left,
315
322
  [ Opcodes.local_tee, localTmp(scope, 'logictmp') ],
316
- ...checks[op],
323
+ ...checks[op](scope, [], leftType),
324
+ Opcodes.i32_to,
317
325
  [ Opcodes.if, valtypeBinary ],
318
326
  ...right,
319
327
  [ Opcodes.else ],
@@ -563,75 +571,77 @@ const compareStrings = (scope, left, right) => {
563
571
  ];
564
572
  };
565
573
 
566
- const falsy = (scope, wasm, type) => {
574
+ const truthy = (scope, wasm, type) => {
567
575
  // arrays are always truthy
568
576
  if (type === TYPES._array) return [
569
577
  ...wasm,
570
- [ Opcodes.drop ],
571
- number(0)
578
+ ...(wasm.length === 0 ? [] : [ [ Opcodes.drop ] ]),
579
+ number(1)
572
580
  ];
573
581
 
574
582
  if (type === TYPES.string) {
575
- // if "" (length = 0)
583
+ // if not "" (length = 0)
576
584
  return [
577
585
  // pointer
578
586
  ...wasm,
587
+ Opcodes.i32_to_u,
579
588
 
580
589
  // get length
581
590
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
582
591
 
583
- // if length == 0
584
- [ Opcodes.i32_eqz ],
592
+ // if length != 0
593
+ /* [ Opcodes.i32_eqz ],
594
+ [ Opcodes.i32_eqz ], */
585
595
  Opcodes.i32_from_u
586
596
  ]
587
597
  }
588
598
 
589
- // if = 0
599
+ // if != 0
590
600
  return [
591
601
  ...wasm,
592
602
 
593
- ...Opcodes.eqz,
594
- Opcodes.i32_from_u
603
+ /* Opcodes.eqz,
604
+ [ Opcodes.i32_eqz ],
605
+ Opcodes.i32_from */
595
606
  ];
596
607
  };
597
608
 
598
- const truthy = (scope, wasm, type) => {
609
+ const falsy = (scope, wasm, type) => {
599
610
  // arrays are always truthy
600
611
  if (type === TYPES._array) return [
601
612
  ...wasm,
602
- [ Opcodes.drop ],
603
- number(1)
613
+ ...(wasm.length === 0 ? [] : [ [ Opcodes.drop ] ]),
614
+ number(0)
604
615
  ];
605
616
 
606
617
  if (type === TYPES.string) {
607
- // if not "" (length = 0)
618
+ // if "" (length = 0)
608
619
  return [
609
620
  // pointer
610
621
  ...wasm,
622
+ Opcodes.i32_to_u,
611
623
 
612
624
  // get length
613
625
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
614
626
 
615
- // if length != 0
616
- /* [ Opcodes.i32_eqz ],
617
- [ Opcodes.i32_eqz ], */
627
+ // if length == 0
628
+ [ Opcodes.i32_eqz ],
618
629
  Opcodes.i32_from_u
619
630
  ]
620
631
  }
621
632
 
622
- // if != 0
633
+ // if = 0
623
634
  return [
624
635
  ...wasm,
625
636
 
626
- /* Opcodes.eqz,
627
- [ Opcodes.i32_eqz ],
628
- Opcodes.i32_from */
637
+ ...Opcodes.eqz,
638
+ Opcodes.i32_from_u
629
639
  ];
630
640
  };
631
641
 
632
642
  const performOp = (scope, op, left, right, leftType, rightType, _global = false, _name = '$undeclared', assign = false) => {
633
643
  if (op === '||' || op === '&&' || op === '??') {
634
- return performLogicOp(scope, op, left, right);
644
+ return performLogicOp(scope, op, left, right, leftType, rightType);
635
645
  }
636
646
 
637
647
  if (codeLog && (!leftType || !rightType)) log('codegen', 'untracked type in op', op, _name, '\n' + new Error().stack.split('\n').slice(1).join('\n'));
@@ -772,7 +782,7 @@ const includeBuiltin = (scope, builtin) => {
772
782
  };
773
783
 
774
784
  const generateLogicExp = (scope, decl) => {
775
- return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right));
785
+ return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
776
786
  };
777
787
 
778
788
  const TYPES = {
@@ -1189,7 +1199,7 @@ const generateNew = (scope, decl, _global, _name) => {
1189
1199
  // hack: basically treat this as a normal call for builtins for now
1190
1200
  const name = mapName(decl.callee.name);
1191
1201
  if (internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
1192
- if (!builtinFuncs[name]) return todo(`new statement is not supported yet (new ${unhackName(name)})`);
1202
+ if (!builtinFuncs[name]) return todo(`new statement is not supported yet`); // return todo(`new statement is not supported yet (new ${unhackName(name)})`);
1193
1203
 
1194
1204
  return generateCall(scope, decl, _global, _name);
1195
1205
  };
@@ -1377,7 +1387,7 @@ const generateUnary = (scope, decl) => {
1377
1387
 
1378
1388
  case '!':
1379
1389
  // !=
1380
- return falsy(scope, generate(scope, decl.argument));
1390
+ return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument));
1381
1391
 
1382
1392
  case '~':
1383
1393
  return [
@@ -1665,7 +1675,16 @@ const allocPage = reason => {
1665
1675
  let ind = pages.size;
1666
1676
  pages.set(reason, ind);
1667
1677
 
1668
- if (codeLog) log('codegen', `allocated new page of memory (${ind}) | ${reason}`);
1678
+ if (allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason}`);
1679
+
1680
+ return ind;
1681
+ };
1682
+
1683
+ const freePage = reason => {
1684
+ let ind = pages.get(reason);
1685
+ pages.delete(reason);
1686
+
1687
+ if (allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
1669
1688
 
1670
1689
  return ind;
1671
1690
  };
package/compiler/index.js CHANGED
@@ -14,7 +14,8 @@ const bold = x => `\u001b[1m${x}\u001b[0m`;
14
14
  const areaColors = {
15
15
  codegen: [ 20, 80, 250 ],
16
16
  opt: [ 250, 20, 80 ],
17
- sections: [ 20, 250, 80 ]
17
+ sections: [ 20, 250, 80 ],
18
+ alloc: [ 250, 250, 20 ]
18
19
  };
19
20
 
20
21
  globalThis.log = (area, ...args) => console.log(`\u001b[90m[\u001b[0m${rgb(...areaColors[area], area)}\u001b[90m]\u001b[0m`, ...args);
@@ -38,6 +39,7 @@ const logFuncs = (funcs, globals, exceptions) => {
38
39
  export default (code, flags) => {
39
40
  globalThis.optLog = process.argv.includes('-opt-log');
40
41
  globalThis.codeLog = process.argv.includes('-code-log');
42
+ globalThis.allocLog = process.argv.includes('-alloc-log');
41
43
 
42
44
  for (const x in BuiltinPreludes) {
43
45
  if (code.indexOf(x + '(') !== -1) code = BuiltinPreludes[x] + code;
@@ -63,5 +65,12 @@ export default (code, flags) => {
63
65
  const sections = produceSections(funcs, globals, tags, pages, flags);
64
66
  if (flags.includes('info')) console.log(`4. produced sections in ${(performance.now() - t3).toFixed(2)}ms`);
65
67
 
68
+ if (allocLog) {
69
+ const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
70
+ const bytes = wasmPages * 65536;
71
+ log('alloc', `\x1B[1mallocated ${bytes / 1024}KiB\x1B[0m for ${pages.size} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}`);
72
+ // console.log([...pages.keys()].map(x => `\x1B[36m - ${x}\x1B[0m`).join('\n'));
73
+ }
74
+
66
75
  return { wasm: sections, funcs, globals, tags, exceptions, pages };
67
76
  };
@@ -25,7 +25,6 @@ export const PrototypeFuncs = function() {
25
25
 
26
26
  this[TYPES._array] = {
27
27
  // lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
28
- // todo: out of bounds (>) properly
29
28
  at: (pointer, length, wIndex, iTmp) => [
30
29
  ...wIndex,
31
30
  Opcodes.i32_to,
@@ -147,7 +146,6 @@ export const PrototypeFuncs = function() {
147
146
  this[TYPES._array].push.noArgRetLength = true;
148
147
 
149
148
  this[TYPES.string] = {
150
- // todo: out of bounds properly
151
149
  at: (pointer, length, wIndex, iTmp, arrayShell) => {
152
150
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
153
151
 
@@ -157,9 +155,9 @@ export const PrototypeFuncs = function() {
157
155
  [ Opcodes.drop ],
158
156
 
159
157
  ...number(0, Valtype.i32), // base 0 for store later
160
- Opcodes.i32_to_u,
161
158
 
162
159
  ...wIndex,
160
+ Opcodes.i32_to_u,
163
161
  [ Opcodes.local_tee, iTmp ],
164
162
 
165
163
  // if index < 0: access index + array length
@@ -265,7 +263,7 @@ export const PrototypeFuncs = function() {
265
263
  },
266
264
  };
267
265
 
268
- this[TYPES.string].at.local = valtypeBinary;
266
+ this[TYPES.string].at.local = Valtype.i32;
269
267
  this[TYPES.string].at.returnType = TYPES.string;
270
268
  this[TYPES.string].charAt.returnType = TYPES.string;
271
269
  this[TYPES.string].charCodeAt.local = Valtype.i32;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.0.0-44bc2d8",
4
+ "version": "0.0.0-61de729",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/runner/index.js CHANGED
@@ -5,6 +5,12 @@ import fs from 'node:fs';
5
5
 
6
6
  const file = process.argv.slice(2).find(x => x[0] !== '-');
7
7
  if (!file) {
8
+ if (process.argv.includes('-v')) {
9
+ // just print version
10
+ console.log((await import('./version.js')).default);
11
+ process.exit(0);
12
+ }
13
+
8
14
  // run repl if no file given
9
15
  await import('./repl.js');
10
16
 
package/runner/repl.js CHANGED
@@ -1,14 +1,7 @@
1
1
  import compile from '../compiler/wrap.js';
2
+ import rev from './version.js';
2
3
 
3
4
  import repl from 'node:repl';
4
- import fs from 'node:fs';
5
-
6
- let rev = 'unknown';
7
- try {
8
- rev = fs.readFileSync(new URL('../.git/refs/heads/main', import.meta.url), 'utf8').trim().slice(0, 7);
9
- } catch {
10
- rev = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version.split('-')[1];
11
- }
12
5
 
13
6
  // process.argv.push('-O0'); // disable opts
14
7
 
@@ -48,7 +41,7 @@ const memoryToString = mem => {
48
41
  return out;
49
42
  };
50
43
 
51
- const alwaysPrev = process.argv.includes('-always-prev');
44
+ const alwaysPrev = process.argv.includes('-prev');
52
45
 
53
46
  let prev = '';
54
47
  const run = async (source, _context, _filename, callback, run = true) => {
@@ -56,7 +49,7 @@ const run = async (source, _context, _filename, callback, run = true) => {
56
49
  if (alwaysPrev) prev = toRun + ';\n';
57
50
 
58
51
  const { exports, wasm, pages } = await compile(toRun, []);
59
- fs.writeFileSync('out.wasm', Buffer.from(wasm));
52
+ // fs.writeFileSync('out.wasm', Buffer.from(wasm));
60
53
 
61
54
  if (run && exports.$) {
62
55
  lastMemory = exports.$;
@@ -0,0 +1,10 @@
1
+ import fs from 'node:fs';
2
+
3
+ let rev = 'unknown';
4
+ try {
5
+ rev = fs.readFileSync(new URL('../.git/refs/heads/main', import.meta.url), 'utf8').trim().slice(0, 7);
6
+ } catch {
7
+ rev = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version.split('-')[1].slice(0, 7);
8
+ }
9
+
10
+ export default rev;