porffor 0.28.6 → 0.28.8

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.
@@ -1976,6 +1976,52 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1976
1976
 
1977
1977
  let out = [];
1978
1978
  if (protoName) {
1979
+ if (protoName === 'call') {
1980
+ const valTmp = localTmp(scope, '#call_val');
1981
+ const typeTmp = localTmp(scope, '#call_type', Valtype.i32);
1982
+
1983
+ return generateCall(scope, {
1984
+ type: 'CallExpression',
1985
+ callee: target,
1986
+ arguments: decl.arguments.slice(1),
1987
+ _thisWasm: [
1988
+ ...generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
1989
+ [ Opcodes.local_tee, valTmp ],
1990
+ ...getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
1991
+ [ Opcodes.local_tee, typeTmp ],
1992
+
1993
+ // check not undefined or null
1994
+ // todo: technically this should be allowed sometimes but for now, never
1995
+ ...nullish(scope,
1996
+ [ [ Opcodes.local_get, valTmp ] ],
1997
+ [ [ Opcodes.local_get, typeTmp ] ],
1998
+ false, true),
1999
+ [ Opcodes.if, Blocktype.void ],
2000
+ ...internalThrow(scope, 'TypeError', `Cannot use undefined or null as 'this'`),
2001
+ [ Opcodes.end ],
2002
+ ],
2003
+ _thisWasmComponents: {
2004
+ _callValue: [
2005
+ ...generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2006
+ [ Opcodes.local_tee, valTmp ],
2007
+ ...getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2008
+ [ Opcodes.local_set, typeTmp ],
2009
+
2010
+ // check not undefined or null
2011
+ // todo: technically this should be allowed sometimes but for now, never
2012
+ ...nullish(scope,
2013
+ [ [ Opcodes.local_get, valTmp ] ],
2014
+ [ [ Opcodes.local_get, typeTmp ] ],
2015
+ false, true),
2016
+ [ Opcodes.if, Blocktype.void ],
2017
+ ...internalThrow(scope, 'TypeError', `Cannot use undefined or null as 'this'`),
2018
+ [ Opcodes.end ],
2019
+ ],
2020
+ _callType: [ [ Opcodes.local_get, typeTmp ] ]
2021
+ }
2022
+ });
2023
+ }
2024
+
1979
2025
  if (['search'].includes(protoName)) {
1980
2026
  const regex = decl.arguments[0]?.regex?.pattern;
1981
2027
  if (!regex) return [
@@ -2024,6 +2070,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2024
2070
  [ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
2025
2071
  );
2026
2072
 
2073
+ if (decl._thisWasm) {
2074
+ // after to still generate original target
2075
+ out.push(
2076
+ ...decl._thisWasm,
2077
+ [ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
2078
+ [ Opcodes.local_set, localTmp(scope, '#proto_target') ]
2079
+ );
2080
+ }
2081
+
2027
2082
  for (const x of builtinProtoCands) {
2028
2083
  const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
2029
2084
  if (type == null) continue;
@@ -2137,7 +2192,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2137
2192
  return [
2138
2193
  ...out,
2139
2194
 
2140
- ...typeSwitch(scope, builtinProtoCands.length > 0 ? [ [ Opcodes.local_get, localTmp(scope, '#proto_target#type', Valtype.i32) ] ] : getNodeType(scope, target), {
2195
+ ...typeSwitch(scope, getNodeType(scope, target), {
2141
2196
  ...protoBC,
2142
2197
 
2143
2198
  // TODO: error better
@@ -2232,7 +2287,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2232
2287
  let locals = [];
2233
2288
 
2234
2289
  if (indirectMode === 'vararg') {
2235
- const minArgc = Prefs.indirectCallMinArgc ?? 3;
2290
+ const minArgc = Prefs.indirectCallMinArgc ?? 5;
2236
2291
 
2237
2292
  if (args.length < minArgc) {
2238
2293
  args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
@@ -2242,14 +2297,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2242
2297
  for (let i = 0; i < args.length; i++) {
2243
2298
  const arg = args[i];
2244
2299
  out = out.concat(generate(scope, arg));
2245
-
2246
- if (valtypeBinary !== Valtype.i32 && (
2247
- (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
2248
- (importedFuncs[name] && name.startsWith('profile'))
2249
- )) {
2250
- out.push(Opcodes.i32_to);
2251
- }
2252
-
2253
2300
  out = out.concat(getNodeType(scope, arg));
2254
2301
 
2255
2302
  if (indirectMode === 'vararg') {
@@ -2410,7 +2457,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2410
2457
  [ Opcodes.local_get, funcLocal ],
2411
2458
  ...number(128, Valtype.i32),
2412
2459
  [ Opcodes.i32_mul ],
2413
- ...number(2, Valtype.i32),
2460
+ ...number(4, Valtype.i32),
2414
2461
  [ Opcodes.i32_add ],
2415
2462
  [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2416
2463
  [ Opcodes.local_set, flags ],
@@ -2479,7 +2526,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2479
2526
  const internalProtoFunc = func && func.internal && func.name.includes('_prototype_');
2480
2527
  if (!globalThis.precompile && internalProtoFunc && !decl._protoInternalCall) {
2481
2528
  // just function called, not as prototype, add this to start
2482
- args.unshift(decl._thisWasm ?? createThisArg(scope, decl));
2529
+ args.unshift(decl._thisWasmComponents ?? decl._thisWasm ?? createThisArg(scope, decl));
2483
2530
  }
2484
2531
 
2485
2532
  if (func && func.constr) {
@@ -2521,7 +2568,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2521
2568
  continue;
2522
2569
  }
2523
2570
 
2524
- out = out.concat(generate(scope, arg));
2571
+ out = out.concat(arg._callValue ?? generate(scope, arg));
2525
2572
 
2526
2573
  // todo: this should be used instead of the too many args thing above (by removing that)
2527
2574
  if (i >= paramCount) {
@@ -2542,7 +2589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2542
2589
  out.push(Opcodes.i32_from);
2543
2590
  }
2544
2591
 
2545
- if (typedParams) out = out.concat(getNodeType(scope, arg));
2592
+ if (typedParams) out = out.concat(arg._callType ?? getNodeType(scope, arg));
2546
2593
  }
2547
2594
 
2548
2595
  out.push([ Opcodes.call, idx ]);
@@ -2976,16 +3023,12 @@ const generateVar = (scope, decl) => {
2976
3023
  type: 'VariableDeclarator',
2977
3024
  id: e.left,
2978
3025
  init: {
2979
- type: 'LogicalExpression',
2980
- operator: '??',
2981
- left: {
2982
- type: 'MemberExpression',
2983
- object: { type: 'Identifier', name: tmpName },
2984
- property: { type: 'Literal', value: i },
2985
- computed: true
2986
- },
2987
- right: e.right
2988
- }
3026
+ type: 'MemberExpression',
3027
+ object: { type: 'Identifier', name: tmpName },
3028
+ property: { type: 'Literal', value: i },
3029
+ computed: true
3030
+ },
3031
+ _default: e.right
2989
3032
  });
2990
3033
 
2991
3034
  break;
@@ -3018,7 +3061,8 @@ const generateVar = (scope, decl) => {
3018
3061
  declarations: [{
3019
3062
  type: 'VariableDeclarator',
3020
3063
  id: { type: 'Identifier', name: tmpName },
3021
- init: x.init
3064
+ init: x.init,
3065
+ _default: x._default
3022
3066
  }],
3023
3067
  kind: decl.kind,
3024
3068
  _global: false
@@ -3063,16 +3107,12 @@ const generateVar = (scope, decl) => {
3063
3107
  type: 'VariableDeclarator',
3064
3108
  id: prop.value.left,
3065
3109
  init: {
3066
- type: 'LogicalExpression',
3067
- operator: '??',
3068
- left: {
3069
- type: 'MemberExpression',
3070
- object: { type: 'Identifier', name: tmpName },
3071
- property: prop.key,
3072
- computed: prop.computed
3073
- },
3074
- right: prop.value.right
3075
- }
3110
+ type: 'MemberExpression',
3111
+ object: { type: 'Identifier', name: tmpName },
3112
+ property: prop.key,
3113
+ computed: prop.computed
3114
+ },
3115
+ _default: prop.value.right
3076
3116
  });
3077
3117
  } else {
3078
3118
  decls.push({
@@ -3097,7 +3137,8 @@ const generateVar = (scope, decl) => {
3097
3137
  declarations: [{
3098
3138
  type: 'VariableDeclarator',
3099
3139
  id: { type: 'Identifier', name: tmpName },
3100
- init: x.init
3140
+ init: x.init,
3141
+ _default: x._default
3101
3142
  }],
3102
3143
  kind: decl.kind,
3103
3144
  _global: false
@@ -3179,6 +3220,17 @@ const generateVar = (scope, decl) => {
3179
3220
 
3180
3221
  out = out.concat(newOut);
3181
3222
 
3223
+ if (x._default) {
3224
+ out.push(
3225
+ ...typeIsOneOf(getType(scope, name), [ TYPES.undefined, TYPES.empty ]),
3226
+ [ Opcodes.if, Blocktype.void ],
3227
+ ...generate(scope, x._default, global, name),
3228
+ [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
3229
+ ...setType(scope, name, getNodeType(scope, x._default)),
3230
+ [ Opcodes.end ],
3231
+ );
3232
+ }
3233
+
3182
3234
  if (globalThis.precompile && global) {
3183
3235
  scope.globalInits ??= {};
3184
3236
  scope.globalInits[name] = newOut;
@@ -5043,13 +5095,23 @@ const countParams = (func, name = undefined) => {
5043
5095
  }
5044
5096
  if (func.argc) return func.argc;
5045
5097
 
5098
+ name ??= func.name;
5046
5099
  let params = func.params.length;
5047
5100
  if (func.constr) params -= 4;
5048
- if (!func.internal || builtinFuncs[func.name]?.typedParams) params = Math.floor(params / 2);
5101
+ if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
5049
5102
 
5050
5103
  return func.argc = params;
5051
5104
  };
5052
5105
 
5106
+ const countLength = (func, name = undefined) => {
5107
+ name ??= func.name;
5108
+
5109
+ let count = countParams(func, name);
5110
+ if (builtinFuncs[name] && name.includes('_prototype_')) count--;
5111
+
5112
+ return count;
5113
+ };
5114
+
5053
5115
  const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
5054
5116
  const name = decl.object.name;
5055
5117
 
@@ -5068,9 +5130,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5068
5130
  // todo: support optional
5069
5131
 
5070
5132
  const func = funcs.find(x => x.name === name);
5071
- if (func) return withType(scope, number(countParams(func)), TYPES.number);
5133
+ if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
5072
5134
 
5073
- if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countParams(builtinFuncs[name])), TYPES.number);
5135
+ if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
5074
5136
  if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
5075
5137
  if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
5076
5138
 
@@ -5402,7 +5464,7 @@ const objectHack = node => {
5402
5464
  if (node.computed || node.optional) return;
5403
5465
 
5404
5466
  // hack: block these properties as they can be accessed on functions
5405
- if (node.property.name == 'length' || node.property.name == 'name') return;
5467
+ if (node.property.name == 'length' || node.property.name == 'name' || node.property.name == 'call') return;
5406
5468
 
5407
5469
  let objectName = node.object.name;
5408
5470
 
@@ -5481,6 +5543,7 @@ const generateFunc = (scope, decl) => {
5481
5543
  }
5482
5544
  }
5483
5545
 
5546
+ const prelude = [];
5484
5547
  const defaultValues = {};
5485
5548
  for (let i = 0; i < params.length; i++) {
5486
5549
  let name;
@@ -5508,7 +5571,27 @@ const generateFunc = (scope, decl) => {
5508
5571
 
5509
5572
  allocVar(func, name, false);
5510
5573
  if (typedInput && params[i].typeAnnotation) {
5511
- addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
5574
+ const typeAnno = extractTypeAnnotation(params[i]);
5575
+ addVarMetadata(func, name, false, typeAnno);
5576
+
5577
+ // automatically add throws if unexpected this type to builtins
5578
+ if (globalThis.precompile && i === 0 && func.name.includes('_prototype_') && [
5579
+ TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
5580
+ TYPES.set, TYPES.map,
5581
+ TYPES.weakref, TYPES.weakset, TYPES.weakmap,
5582
+ TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
5583
+ ].includes(typeAnno.type)) {
5584
+ prelude.push(
5585
+ [ Opcodes.local_get, i * 2 + 1 ],
5586
+ ...number(typeAnno.type, Valtype.i32),
5587
+ [ Opcodes.i32_ne ],
5588
+ [ Opcodes.if, Blocktype.void ],
5589
+ ...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
5590
+ [ Opcodes.end ]
5591
+ );
5592
+ }
5593
+
5594
+ // todo: if string, try converting to it to one
5512
5595
  }
5513
5596
  }
5514
5597
 
@@ -5523,7 +5606,6 @@ const generateFunc = (scope, decl) => {
5523
5606
  };
5524
5607
  }
5525
5608
 
5526
- const prelude = [];
5527
5609
  for (const x in defaultValues) {
5528
5610
  prelude.push(
5529
5611
  ...getType(func, x),
@@ -1,5 +1,5 @@
1
1
  import { Opcodes, Valtype } from './wasmSpec.js';
2
- import { read_unsignedLEB128 } from './encoding.js';
2
+ import { read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
3
3
  import { TYPES } from './types.js';
4
4
 
5
5
  import process from 'node:process';
@@ -151,7 +151,7 @@ const compile = async (file, _funcs) => {
151
151
 
152
152
 
153
153
  if (y[0] === Opcodes.i32_const && n[0] === Opcodes.throw) {
154
- const id = y[1];
154
+ const id = read_signedLEB128(y.slice(1));
155
155
  y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
156
156
 
157
157
  // remove throw inst
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.28.6+56105b926",
4
+ "version": "0.28.8+a0f4bd584",
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.28.6+56105b926';
3
+ globalThis.version = '0.28.8+a0f4bd584';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {