porffor 0.55.20 → 0.55.21

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.
@@ -5,11 +5,11 @@ export const __Porffor_bigint_fromDigits = (negative: boolean, digits: i32[]): b
5
5
  const len: i32 = digits.length;
6
6
  if (len > 16383) throw new RangeError('Maximum BigInt size exceeded'); // (65536 - 4) / 4
7
7
 
8
- // const ptr: i32 = Porffor.allocate();
8
+ // use digits pointer as bigint pointer, as only used here
9
9
  let ptr: i32 = Porffor.wasm`local.get ${digits}`;
10
10
 
11
- Porffor.wasm.i32.store8(ptr, negative ? 1 : 0, 0, 0);
12
- Porffor.wasm.i32.store16(ptr, len, 0, 2);
11
+ Porffor.wasm.i32.store8(ptr, negative ? 1 : 0, 0, 0); // sign
12
+ Porffor.wasm.i32.store16(ptr, len, 0, 2); // digit count
13
13
 
14
14
  let allZero: boolean = true;
15
15
  for (let i: i32 = 0; i < len; i++) {
@@ -84,14 +84,10 @@ export const __Porffor_bigint_fromString = (n: string|bytestring): bigint => {
84
84
  offset = 1;
85
85
  }
86
86
 
87
- // n -> digits (base 2^32) (most to least significant)
88
- // 4294967294 -> [ 4294967294 ]
87
+ // n -> base 2^32 digits (most to least significant)
89
88
  // 4294967295 -> [ 4294967295 ]
90
89
  // 4294967296 -> [ 1, 0 ]
91
90
  // 4294967297 -> [ 1, 1 ]
92
- // 9007199254740992 -> [ 2097152, 0 ]
93
- // 9007199254740993 -> [ 2097152, 1 ]
94
- // 9007199254740994 -> [ 2097152, 2 ]
95
91
 
96
92
  const BASE: i32 = 0x100000000; // 2^32
97
93
  const digits: i32[] = Porffor.allocate(); // todo: free later
@@ -462,7 +462,7 @@ const lookup = (scope, name, failEarly = false) => {
462
462
  }
463
463
 
464
464
  if (local?.idx === undefined) {
465
- if (name === 'arguments' && scope.name !== '#main' && !scope.arrow) {
465
+ if (name === 'arguments' && !scope.arrow) {
466
466
  // todo: not compliant
467
467
  let len = countLength(scope);
468
468
  const names = new Array(len);
@@ -1386,29 +1386,6 @@ const generateLogicExp = (scope, decl) => {
1386
1386
  return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
1387
1387
  };
1388
1388
 
1389
- // potential future ideas for nan boxing (unused):
1390
- // T = JS type, V = value/pointer
1391
- // 0bTTT
1392
- // qNAN: 0 11111111111 1000000000000000000000000000000000000000000000000001
1393
- // 50 bits usable: 0 11111111111 11??????????????????????????????????????????????????
1394
- // js type: 4 bits
1395
- // internal type: ? bits
1396
- // pointer: 32 bits
1397
- // https://piotrduperas.com/posts/nan-boxing
1398
- // 0x7ffc000000000000
1399
- // budget: 50 bits
1400
- // js type: 4 bits
1401
- // internal type: ? bits
1402
- // pointer: 32 bits
1403
- // generic
1404
- // 1 23 4 5
1405
- // 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
1406
- // 1: regular iEEE 754 double NaN
1407
- // 2: extra 1 bit to identify NaN box
1408
- // 3: js type
1409
- // 4: internal type
1410
- // 5: pointer
1411
-
1412
1389
  const isExistingProtoFunc = name => {
1413
1390
  if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
1414
1391
  if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
@@ -1470,7 +1447,7 @@ const getType = (scope, name, failEarly = false) => {
1470
1447
  global = true;
1471
1448
  }
1472
1449
 
1473
- if (global !== false && name === 'arguments' && scope.name !== '#main' && !scope.arrow) {
1450
+ if (global !== false && name === 'arguments' && !scope.arrow) {
1474
1451
  return [ number(TYPES.array, Valtype.i32) ];
1475
1452
  }
1476
1453
 
@@ -2750,18 +2727,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2750
2727
  }
2751
2728
 
2752
2729
  out.push([ Opcodes.call, idx ]);
2753
-
2754
- if (!typedReturns) {
2755
- // let type;
2756
- // if (builtinFuncs[name]) type = TYPES[builtinFuncs[name].returnType ?? 'number'];
2757
- // if (internalConstrs[name]) type = internalConstrs[name].type;
2758
- // if (importedFuncs[name] && importedFuncs[]) type =
2759
-
2760
- // if (type) out.push(
2761
- // number(type, Valtype.i32),
2762
- // [ Opcodes.local_set, localTmp(scope, '#last_type', Valtype.i32) ]
2763
- // );
2764
- } else out.push(...setLastType(scope));
2730
+ if (typedReturns) out.push(...setLastType(scope));
2765
2731
 
2766
2732
  if (
2767
2733
  func?.returns?.length === 0 ||
@@ -3571,9 +3537,8 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3571
3537
  const generateVar = (scope, decl) => {
3572
3538
  let out = [];
3573
3539
 
3574
- const topLevel = scope.name === '#main';
3575
-
3576
3540
  // global variable if in top scope (main) or if internally wanted
3541
+ const topLevel = scope.name === '#main';
3577
3542
  const global = decl._global ?? (topLevel || decl._bare);
3578
3543
 
3579
3544
  for (const x of decl.declarations) {
@@ -3637,6 +3602,15 @@ const memberTmpNames = scope => {
3637
3602
  // COCTC: cross-object compile-time cache
3638
3603
  let coctc = new Map();
3639
3604
  const coctcOffset = prop => {
3605
+ if (typeof prop === 'object') {
3606
+ if (
3607
+ prop.computed || prop.optional ||
3608
+ ['prototype', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength', 'length', '__proto__'].includes(prop.property.name)
3609
+ ) return 0;
3610
+
3611
+ prop = prop.property.name;
3612
+ }
3613
+
3640
3614
  let offset = coctc.get(prop);
3641
3615
  if (offset == null) {
3642
3616
  offset = (coctc.lastOffset ?? 60000) - 9;
@@ -3768,7 +3742,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3768
3742
  // todo/perf: use i32 object (and prop?) locals
3769
3743
  const { objectTmp, propertyTmp, objectGet, propertyGet } = memberTmpNames(scope);
3770
3744
 
3771
- const useCoctc = Prefs.coctc && !decl.left.computed && !decl.left.optional && !['prototype', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength', 'length', '__proto__'].includes(decl.left.property.name) && coctcOffset(decl.left.property.name) > 0;
3745
+ const useCoctc = Prefs.coctc && coctcOffset(decl.left) > 0;
3772
3746
  if (useCoctc) valueUnused = false;
3773
3747
 
3774
3748
  // opt: do not mark prototype funcs as referenced to optimize this in them
@@ -4214,7 +4188,7 @@ const generateUnary = (scope, decl) => {
4214
4188
  const property = getProperty(decl.argument);
4215
4189
  if (property.value === 'length' || property.value === 'name') scope.noFastFuncMembers = true;
4216
4190
 
4217
- const useCoctc = Prefs.coctc && !decl.argument.computed && !decl.argument.optional && !['prototype', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength', 'length', '__proto__'].includes(decl.argument.property.name) && coctcOffset(decl.argument.property.name) > 0;
4191
+ const useCoctc = Prefs.coctc && coctcOffset(decl.argument) > 0;
4218
4192
  const objectTmp = useCoctc && localTmp(scope, '#coctc_object', Valtype.i32);
4219
4193
 
4220
4194
  const out = [
@@ -5410,7 +5384,7 @@ const makeData = (scope, elements, page = null, itemType = 'i8') => {
5410
5384
 
5411
5385
  const length = elements.length;
5412
5386
 
5413
- // if length is 0 memory/data will just be 0000... anyway
5387
+ // if length is 0, memory/data will just be 0000... anyway
5414
5388
  if (length === 0) return false;
5415
5389
 
5416
5390
  let bytes = compileBytes(length, 'i32');
@@ -5424,7 +5398,6 @@ const makeData = (scope, elements, page = null, itemType = 'i8') => {
5424
5398
  }
5425
5399
 
5426
5400
  const obj = { bytes, page };
5427
-
5428
5401
  const idx = data.push(obj) - 1;
5429
5402
 
5430
5403
  scope.data ??= [];
@@ -5448,63 +5421,6 @@ const printStaticStr = str => {
5448
5421
  return out;
5449
5422
  };
5450
5423
 
5451
- const storeArray = (scope, array, index, element) => {
5452
- if (!Array.isArray(element)) element = generate(scope, element);
5453
- if (typeof index === 'number') index = [ number(index) ];
5454
-
5455
- const offset = localTmp(scope, '#storeArray_offset', Valtype.i32);
5456
-
5457
- return [
5458
- // calculate offset
5459
- ...index,
5460
- Opcodes.i32_to_u,
5461
- number(ValtypeSize[valtype] + 1, Valtype.i32),
5462
- [ Opcodes.i32_mul ],
5463
-
5464
- ...array,
5465
- Opcodes.i32_to_u,
5466
- [ Opcodes.i32_add ],
5467
- [ Opcodes.local_set, offset ],
5468
-
5469
- // store value
5470
- [ Opcodes.local_get, offset ],
5471
- ...generate(scope, element),
5472
- [ Opcodes.store, 0, ValtypeSize.i32 ],
5473
-
5474
- // store type
5475
- [ Opcodes.local_get, offset ],
5476
- ...getNodeType(scope, element),
5477
- [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
5478
- ];
5479
- };
5480
-
5481
- const loadArray = (scope, array, index) => {
5482
- if (typeof index === 'number') index = [ number(index) ];
5483
-
5484
- const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
5485
-
5486
- return [
5487
- // calculate offset
5488
- ...index,
5489
- Opcodes.i32_to_u,
5490
- number(ValtypeSize[valtype] + 1, Valtype.i32),
5491
- [ Opcodes.i32_mul ],
5492
-
5493
- ...array,
5494
- Opcodes.i32_to_u,
5495
- [ Opcodes.i32_add ],
5496
- [ Opcodes.local_set, offset ],
5497
-
5498
- // load value
5499
- [ Opcodes.local_get, offset ],
5500
- [ Opcodes.load, 0, ValtypeSize.i32 ],
5501
-
5502
- // load type
5503
- [ Opcodes.local_get, offset ],
5504
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
5505
- ];
5506
- };
5507
-
5508
5424
  const byteStringable = str => {
5509
5425
  for (let i = 0; i < str.length; i++) {
5510
5426
  if (str.charCodeAt(i) > 0xFF) return false;
@@ -5943,14 +5859,27 @@ const generateMember = (scope, decl, _global, _name) => {
5943
5859
  }
5944
5860
  }
5945
5861
 
5946
- const useCoctc = Prefs.coctc && !decl.computed && !decl.optional && !['prototype', 'size', 'description', 'byteLength', 'byteOffset', 'buffer', 'detached', 'resizable', 'growable', 'maxByteLength', 'length', '__proto__'].includes(decl.property.name) && coctcOffset(decl.property.name) > 0;
5862
+ const useCoctc = Prefs.coctc && coctcOffset(decl) > 0;
5947
5863
  const coctcObjTmp = useCoctc && localTmp(scope, '#coctc_obj' + uniqId(), Valtype.i32);
5948
5864
 
5949
5865
  const out = typeSwitch(scope, getNodeType(scope, object), {
5950
5866
  ...(decl.computed ? {
5951
5867
  [TYPES.array]: () => [
5952
- ...loadArray(scope, [ objectGet ], [ propertyGet ]),
5953
- ...setLastType(scope)
5868
+ propertyGet,
5869
+ Opcodes.i32_to_u,
5870
+ number(ValtypeSize[valtype] + 1, Valtype.i32),
5871
+ [ Opcodes.i32_mul ],
5872
+
5873
+ objectGet,
5874
+ Opcodes.i32_to_u,
5875
+ [ Opcodes.i32_add ],
5876
+ [ Opcodes.local_tee, localTmp(scope, '#loadArray_offset', Valtype.i32) ],
5877
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
5878
+
5879
+ ...setLastType(scope, [
5880
+ [ Opcodes.local_get, localTmp(scope, '#loadArray_offset', Valtype.i32) ],
5881
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
5882
+ ])
5954
5883
  ],
5955
5884
 
5956
5885
  [TYPES.string]: () => [
@@ -7072,28 +7001,24 @@ export default program => {
7072
7001
  const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7073
7002
  objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
7074
7003
 
7075
- program.id = { name: '#main' };
7076
-
7077
- program.body = {
7078
- type: 'BlockStatement',
7079
- body: program.body
7080
- };
7081
-
7082
- if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
7083
-
7084
- const [ main ] = generateFunc({}, program);
7004
+ const [ main ] = generateFunc({}, {
7005
+ type: 'Program',
7006
+ id: { name: '#main' },
7007
+ body: {
7008
+ type: 'BlockStatement',
7009
+ body: program.body
7010
+ }
7011
+ });
7085
7012
 
7086
7013
  // if wanted and blank main func and other exports, remove it
7087
7014
  if (Prefs.rmBlankMain && main.wasm.length === 0 && funcs.some(x => x.export)) funcs.splice(main.index - importedFuncs.length, 1);
7088
7015
 
7089
- // make ~empty funcs for never generated funcs
7090
- // todo: these should just be deleted once able
7091
7016
  for (let i = 0; i < funcs.length; i++) {
7092
7017
  const f = funcs[i];
7093
7018
 
7094
- if (f.wasm) {
7095
- // run callbacks
7096
- const wasm = f.wasm;
7019
+ const wasm = f.wasm;
7020
+ if (wasm) {
7021
+ // func was generated, run callback ops
7097
7022
  for (let j = 0; j < wasm.length; j++) {
7098
7023
  const o = wasm[j];
7099
7024
  if (o[0] === null && typeof o[1] === 'function') {
@@ -7104,14 +7029,8 @@ export default program => {
7104
7029
  continue;
7105
7030
  }
7106
7031
 
7107
- // make wasm just return 0s for expected returns
7032
+ // func was never generated, make wasm just return 0s for expected returns
7108
7033
  f.wasm = f.returns.map(x => number(0, x));
7109
-
7110
- // alternative: make func empty, may break some indirect calls
7111
- // f.wasm = [];
7112
- // f.returns = [];
7113
- // f.params = [];
7114
- // f.locals = {};
7115
7034
  }
7116
7035
 
7117
7036
  // // remove never generated functions
@@ -7151,10 +7070,9 @@ export default program => {
7151
7070
  for (let i = 0; i < indirectFuncs.length; i++) {
7152
7071
  const f = indirectFuncs[i];
7153
7072
  f.index = currentFuncIndex++;
7073
+ funcs.push(f);
7154
7074
  }
7155
7075
 
7156
- funcs.push(...indirectFuncs);
7157
-
7158
7076
  delete globals['#ind'];
7159
7077
 
7160
7078
  return { funcs, globals, tags, exceptions, pages, data };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.55.20",
4
+ "version": "0.55.21",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.55.20';
3
+ globalThis.version = '0.55.21';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {