porffor 0.42.0 → 0.42.1

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.
@@ -66,6 +66,34 @@ const funcRef = func => {
66
66
  }
67
67
  let localInd = (wrapperArgc + 2) * 2;
68
68
 
69
+ if (indirectFuncs.length === 0) {
70
+ // add empty indirect func
71
+ const emptyFunc = {
72
+ name: '#indirect#empty',
73
+ params,
74
+ locals: { ...locals }, localInd,
75
+ returns: [ valtypeBinary, Valtype.i32 ],
76
+ wasm: [
77
+ ...number(0),
78
+ ...number(0, Valtype.i32)
79
+ ],
80
+ constr: true,
81
+ internal: true,
82
+ indirect: true
83
+ };
84
+
85
+ // check not being constructed
86
+ emptyFunc.wasm.unshift(
87
+ [ Opcodes.local_get, 0 ], // new.target value
88
+ Opcodes.i32_to_u,
89
+ [ Opcodes.if, Blocktype.void ], // if value is non-zero
90
+ ...internalThrow(emptyFunc, 'TypeError', `Function is not a constructor`), // throw type error
91
+ [ Opcodes.end ]
92
+ );
93
+
94
+ indirectFuncs.push(emptyFunc);
95
+ }
96
+
69
97
  const wasm = [];
70
98
  const offset = func.constr ? 0 : 4;
71
99
  for (let i = 0; i < func.params.length; i++) {
@@ -427,32 +455,75 @@ const generateReturn = (scope, decl) => {
427
455
  ];
428
456
  }
429
457
 
430
- const out = [];
431
458
  if (
432
459
  scope.constr && // only do this in constructors
433
460
  !globalThis.precompile // skip in precompiled built-ins, we should not require this and handle it ourselves
434
461
  ) {
435
- // ignore return value and return this if being constructed
436
- // todo: only do this when trying to return a primitive?
437
- out.push(
438
- // ...truthy(scope, [ [ Opcodes.local_get, scope.locals['#newtarget'].idx ] ], [ [ Opcodes.local_get, scope.locals['#newtarget#type'].idx ] ], false, true),
439
- [ Opcodes.local_get, scope.locals['#newtarget'].idx ],
440
- Opcodes.i32_to_u,
441
- [ Opcodes.if, Blocktype.void ],
442
- [ Opcodes.local_get, scope.locals['#this'].idx ],
443
- ...(scope.returnType != null ? [] : [ [ Opcodes.local_get, scope.locals['#this#type'].idx ] ]),
444
- [ Opcodes.return ],
445
- [ Opcodes.end ]
446
- );
462
+ // perform return value checks for constructors and (sub)classes
463
+ return [
464
+ ...generate(scope, arg),
465
+ [ Opcodes.local_set, localTmp(scope, '#return') ],
466
+ ...(scope.returnType != null ? [] : getNodeType(scope, arg)),
467
+ [ Opcodes.local_set, localTmp(scope, '#return#type', Valtype.i32) ],
468
+
469
+ ...(scope._onlyConstr ? [] : [
470
+ [ Opcodes.local_get, scope.locals['#newtarget'].idx ],
471
+ Opcodes.i32_to_u,
472
+ [ Opcodes.if, Blocktype.void ]
473
+ ]),
474
+ ...(scope.subclass ? [
475
+ // if subclass and returning undefined, return this
476
+ [ Opcodes.local_get, localTmp(scope, '#return#type') ],
477
+ ...number(TYPE_FLAGS.parity, Valtype.i32),
478
+ [ Opcodes.i32_or ],
479
+ ...number(TYPES.undefined, Valtype.i32),
480
+ [ Opcodes.i32_eq ],
481
+ [ Opcodes.if, Blocktype.void ],
482
+ [ Opcodes.local_get, scope.locals['#this'].idx ],
483
+ ...(scope.returnType != null ? [] : [ [ Opcodes.local_get, scope.locals['#this#type'].idx ] ]),
484
+ [ Opcodes.return ],
485
+ [ Opcodes.end ]
486
+ ] : []),
487
+
488
+ // if not object, then...
489
+ ...generate(scope, {
490
+ type: 'CallExpression',
491
+ callee: {
492
+ type: 'Identifier',
493
+ name: '__Porffor_object_isObject'
494
+ },
495
+ arguments: [
496
+ { type: 'Identifier', name: '#return' }
497
+ ]
498
+ }),
499
+ Opcodes.i32_to_u,
500
+ [ Opcodes.i32_eqz ],
501
+ [ Opcodes.if, Blocktype.void ],
502
+ ...(scope.subclass ? [
503
+ // throw if subclass
504
+ ...internalThrow(scope, 'TypeError', 'Subclass can only return an object or undefined'),
505
+ ] : [
506
+ // return this if not subclass
507
+ [ Opcodes.local_get, scope.locals['#this'].idx ],
508
+ ...(scope.returnType != null ? [] : [ [ Opcodes.local_get, scope.locals['#this#type'].idx ] ]),
509
+ [ Opcodes.return ],
510
+ ]),
511
+ [ Opcodes.end ],
512
+ ...(scope._onlyConstr ? [] : [
513
+ [ Opcodes.end ]
514
+ ]),
515
+
516
+ [ Opcodes.local_get, localTmp(scope, '#return') ],
517
+ [ Opcodes.local_get, localTmp(scope, '#return#type') ],
518
+ [ Opcodes.return ]
519
+ ];
447
520
  }
448
521
 
449
- out.push(
522
+ return [
450
523
  ...generate(scope, arg),
451
524
  ...(scope.returnType != null ? [] : getNodeType(scope, arg)),
452
525
  [ Opcodes.return ]
453
- );
454
-
455
- return out;
526
+ ];
456
527
  };
457
528
 
458
529
  const localTmp = (scope, name, type = valtypeBinary) => {
@@ -1061,7 +1132,7 @@ const asmFuncToAsm = (scope, func) => {
1061
1132
  });
1062
1133
  };
1063
1134
 
1064
- const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTypes = [], globals: globalTypes = [], globalInits = [], returns = [], returnType, localNames = [], globalNames = [], data: _data = [], table = false, constr = false, hasRestArgument = false, usedTypes = [] } = {}) => {
1135
+ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTypes = [], globals: globalTypes = [], globalInits = [], returns = [], returnType, localNames = [], globalNames = [], data: _data = [], table = false, constr = false, hasRestArgument = false, usesTag = false, usedTypes = [] } = {}) => {
1065
1136
  if (wasm == null) { // called with no builtin
1066
1137
  log.warning('codegen', `${name} has no built-in!`);
1067
1138
  wasm = [];
@@ -1134,6 +1205,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1134
1205
  }
1135
1206
 
1136
1207
  if (hasRestArgument) func.hasRestArgument = true;
1208
+ if (usesTag) ensureTag();
1137
1209
 
1138
1210
  for (const x of usedTypes) typeUsed(func, x);
1139
1211
 
@@ -4604,9 +4676,20 @@ const generateLabel = (scope, decl) => {
4604
4676
  return generate(scope, decl.body);
4605
4677
  };
4606
4678
 
4679
+ const ensureTag = (exceptionMode = Prefs.exceptionMode ?? 'stack') => {
4680
+ if (tags.length !== 0) return;
4681
+
4682
+ tags.push({
4683
+ params: exceptionMode === 'lut' ? [ Valtype.i32 ] : [ valtypeBinary, Valtype.i32 ],
4684
+ results: [],
4685
+ idx: tags.length
4686
+ });
4687
+ };
4688
+
4607
4689
  const generateThrow = (scope, decl) => {
4608
4690
  let exceptionMode = Prefs.exceptionMode ?? 'stack';
4609
4691
  if (globalThis.precompile) exceptionMode = decl.argument.callee != null ? 'lut' : 'stack';
4692
+ ensureTag(exceptionMode);
4610
4693
 
4611
4694
  if (exceptionMode === 'lut') {
4612
4695
  let message = decl.argument.value, constructor = null;
@@ -4617,12 +4700,6 @@ const generateThrow = (scope, decl) => {
4617
4700
  message = decl.argument.arguments[0]?.value ?? '';
4618
4701
  }
4619
4702
 
4620
- if (tags.length === 0) tags.push({
4621
- params: [ Valtype.i32 ],
4622
- results: [],
4623
- idx: tags.length
4624
- });
4625
-
4626
4703
  if (constructor && constructor.startsWith('__')) constructor = constructor.split('_').pop();
4627
4704
 
4628
4705
  let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
@@ -4637,19 +4714,11 @@ const generateThrow = (scope, decl) => {
4637
4714
  ];
4638
4715
  }
4639
4716
 
4640
- if (exceptionMode === 'stack') {
4641
- if (tags.length === 0) tags.push({
4642
- params: [ valtypeBinary, Valtype.i32 ],
4643
- results: [],
4644
- idx: tags.length
4645
- });
4646
-
4647
- return [
4648
- ...generate(scope, decl.argument),
4649
- ...getNodeType(scope, decl.argument),
4650
- [ Opcodes.throw, globalThis.precompile ? 1 : 0 ]
4651
- ];
4652
- }
4717
+ return [
4718
+ ...generate(scope, decl.argument),
4719
+ ...getNodeType(scope, decl.argument),
4720
+ [ Opcodes.throw, globalThis.precompile ? 1 : 0 ]
4721
+ ];
4653
4722
  };
4654
4723
 
4655
4724
  const generateTry = (scope, decl) => {
@@ -4692,6 +4761,9 @@ const generateTry = (scope, decl) => {
4692
4761
 
4693
4762
  ...generateVarDstr(scope, 'let', param, { type: 'Identifier', name: tmpName }, undefined, false)
4694
4763
  );
4764
+
4765
+ // ensure tag exists for specific catch
4766
+ ensureTag();
4695
4767
  } else {
4696
4768
  out.push([ Opcodes.catch_all ]);
4697
4769
  }
@@ -5633,9 +5705,10 @@ const generateClass = (scope, decl) => {
5633
5705
  }
5634
5706
  }),
5635
5707
  id: root,
5636
- _onlyConstr: true,
5637
5708
  strict: true,
5638
- type: expr ? 'FunctionExpression' : 'FunctionDeclaration'
5709
+ type: expr ? 'FunctionExpression' : 'FunctionDeclaration',
5710
+ _onlyConstr: true,
5711
+ _subclass: !!decl.superClass
5639
5712
  });
5640
5713
 
5641
5714
  // always generate class constructor funcs
@@ -5943,7 +6016,7 @@ const generateFunc = (scope, decl) => {
5943
6016
  index: currentFuncIndex++,
5944
6017
  arrow,
5945
6018
  constr: !arrow && !decl.generator && !decl.async,
5946
- _onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
6019
+ subclass: decl._subclass, _onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
5947
6020
  strict: scope.strict || decl.strict,
5948
6021
 
5949
6022
  generate() {
@@ -6031,6 +6104,9 @@ const generateFunc = (scope, decl) => {
6031
6104
  ...number(TYPES.promise, Valtype.i32),
6032
6105
  [ Opcodes.return ]
6033
6106
  );
6107
+
6108
+ // ensure tag exists for specific catch
6109
+ ensureTag();
6034
6110
  }
6035
6111
 
6036
6112
  if (name === 'main') {
@@ -153,6 +153,7 @@ const compile = async (file, _funcs) => {
153
153
  }
154
154
 
155
155
  if (n[0] === Opcodes.throw) {
156
+ x.usesTag = true;
156
157
  if (y[0] === Opcodes.i32_const && n[1] === 0) {
157
158
  const id = read_signedLEB128(y.slice(1));
158
159
  y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
@@ -163,6 +164,10 @@ const compile = async (file, _funcs) => {
163
164
  n[1]--;
164
165
  }
165
166
  }
167
+
168
+ if (n[0] === Opcodes.catch) {
169
+ x.usesTag = true;
170
+ }
166
171
  }
167
172
  };
168
173
 
@@ -251,7 +256,7 @@ params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.retu
251
256
  locals:${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))},localNames:${JSON.stringify(locals.map(x => x[0]))},
252
257
  ${usedTypes.length > 0 ? `usedTypes:${JSON.stringify(usedTypes)},` : ''}
253
258
  ${x.globalInits ? `globalInits:{${Object.keys(x.globalInits).map(y => `${y}:${rewriteWasm(x.globalInits[y])}`).join(',')}},` : ''}${x.data && Object.keys(x.data).length > 0 ? `data:${JSON.stringify(x.data)},` : ''}
254
- ${x.table ? `table:1,` : ''}${x.constr ? `constr:1,` : ''}${x.hasRestArgument ? `hasRestArgument:1,` : ''}
259
+ ${x.table ? `table:1,` : ''}${x.constr ? `constr:1,` : ''}${x.hasRestArgument ? `hasRestArgument:1,` : ''}${x.usesTag ? `usesTag:1,` : ''}
255
260
  }`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n').replaceAll('\n\n', '\n');
256
261
  }).join('\n')}
257
262
  }`;
package/compiler/wrap.js CHANGED
@@ -520,12 +520,10 @@ export default (source, module = undefined, customImports = {}, print = str => p
520
520
  throw new constructor(exception.message);
521
521
  }
522
522
 
523
- if (exceptionMode === 'stack') {
524
- const value = e.getArg(exceptTag, 0);
525
- const type = e.getArg(exceptTag, 1);
523
+ const value = e.getArg(exceptTag, 0);
524
+ const type = e.getArg(exceptTag, 1);
526
525
 
527
- throw porfToJSValue({ memory, funcs, pages }, value, type);
528
- }
526
+ throw porfToJSValue({ memory, funcs, pages }, value, type);
529
527
  }
530
528
 
531
529
  if (e instanceof WebAssembly.RuntimeError) {
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.42.0+93da2c806",
4
+ "version": "0.42.1+240c1785e",
5
5
  "author": "CanadaHonk",
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.42.0+93da2c806';
3
+ globalThis.version = '0.42.1+240c1785e';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {