porffor 0.28.5 → 0.28.7

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.
@@ -1848,12 +1848,33 @@ const createThisArg = (scope, decl, knownThis = undefined) => {
1848
1848
  ...number(TYPES.object, Valtype.i32)
1849
1849
  ];
1850
1850
  } else {
1851
+ const name = mapName(decl.callee?.name);
1852
+ if (name && name.startsWith('__') && name.includes('_prototype_')) {
1853
+ // todo: this should just be same as decl._new
1854
+ // but we do not support prototype, constructor, etc yet
1855
+ // so do `this` as `new Type()` instead
1856
+ const node = {
1857
+ type: 'NewExpression',
1858
+ callee: {
1859
+ type: 'Identifier',
1860
+ name: name.slice(2, name.indexOf('_', 2))
1861
+ },
1862
+ arguments: [],
1863
+ _new: true
1864
+ };
1865
+
1866
+ return [
1867
+ ...generateCall(scope, node),
1868
+ ...getNodeType(scope, node)
1869
+ ];
1870
+ }
1871
+
1851
1872
  return [
1852
1873
  ...generate(scope, { type: 'Identifier', name: 'globalThis' }),
1853
1874
  ...getType(scope, 'globalThis')
1854
1875
  ];
1855
1876
  }
1856
- }
1877
+ };
1857
1878
 
1858
1879
  const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1859
1880
  let name = mapName(decl.callee.name);
@@ -1955,6 +1976,52 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1955
1976
 
1956
1977
  let out = [];
1957
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
+
1958
2025
  if (['search'].includes(protoName)) {
1959
2026
  const regex = decl.arguments[0]?.regex?.pattern;
1960
2027
  if (!regex) return [
@@ -2003,6 +2070,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2003
2070
  [ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
2004
2071
  );
2005
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
+
2006
2082
  for (const x of builtinProtoCands) {
2007
2083
  const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
2008
2084
  if (type == null) continue;
@@ -2116,7 +2192,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2116
2192
  return [
2117
2193
  ...out,
2118
2194
 
2119
- ...typeSwitch(scope, builtinProtoCands.length > 0 ? [ [ Opcodes.local_get, localTmp(scope, '#proto_target#type', Valtype.i32) ] ] : getNodeType(scope, target), {
2195
+ ...typeSwitch(scope, getNodeType(scope, target), {
2120
2196
  ...protoBC,
2121
2197
 
2122
2198
  // TODO: error better
@@ -2211,7 +2287,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2211
2287
  let locals = [];
2212
2288
 
2213
2289
  if (indirectMode === 'vararg') {
2214
- const minArgc = Prefs.indirectCallMinArgc ?? 3;
2290
+ const minArgc = Prefs.indirectCallMinArgc ?? 5;
2215
2291
 
2216
2292
  if (args.length < minArgc) {
2217
2293
  args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
@@ -2221,14 +2297,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2221
2297
  for (let i = 0; i < args.length; i++) {
2222
2298
  const arg = args[i];
2223
2299
  out = out.concat(generate(scope, arg));
2224
-
2225
- if (valtypeBinary !== Valtype.i32 && (
2226
- (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
2227
- (importedFuncs[name] && name.startsWith('profile'))
2228
- )) {
2229
- out.push(Opcodes.i32_to);
2230
- }
2231
-
2232
2300
  out = out.concat(getNodeType(scope, arg));
2233
2301
 
2234
2302
  if (indirectMode === 'vararg') {
@@ -2389,7 +2457,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2389
2457
  [ Opcodes.local_get, funcLocal ],
2390
2458
  ...number(128, Valtype.i32),
2391
2459
  [ Opcodes.i32_mul ],
2392
- ...number(2, Valtype.i32),
2460
+ ...number(4, Valtype.i32),
2393
2461
  [ Opcodes.i32_add ],
2394
2462
  [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2395
2463
  [ Opcodes.local_set, flags ],
@@ -2454,13 +2522,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2454
2522
  return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2455
2523
  }
2456
2524
 
2525
+ let args = [...decl.arguments];
2526
+ const internalProtoFunc = func && func.internal && func.name.includes('_prototype_');
2527
+ if (!globalThis.precompile && internalProtoFunc && !decl._protoInternalCall) {
2528
+ // just function called, not as prototype, add this to start
2529
+ args.unshift(decl._thisWasmComponents ?? decl._thisWasm ?? createThisArg(scope, decl));
2530
+ }
2531
+
2457
2532
  if (func && func.constr) {
2458
2533
  out.push(...(decl._newTargetWasm ?? createNewTarget(scope, decl, idx - importedFuncs.length)));
2459
2534
  out.push(...(decl._thisWasm ?? createThisArg(scope, decl)));
2460
2535
  paramOffset += 4;
2461
2536
  }
2462
2537
 
2463
- let args = [...decl.arguments];
2464
2538
  if (func && !func.hasRestArgument && args.length < paramCount) {
2465
2539
  // too little args, push undefineds
2466
2540
  args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE()));
@@ -2488,7 +2562,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2488
2562
 
2489
2563
  for (let i = 0; i < args.length; i++) {
2490
2564
  const arg = args[i];
2491
- out = out.concat(generate(scope, arg));
2565
+ if (Array.isArray(arg)) {
2566
+ // if wasm, just append it
2567
+ out = out.concat(arg);
2568
+ continue;
2569
+ }
2570
+
2571
+ out = out.concat(arg._callValue ?? generate(scope, arg));
2492
2572
 
2493
2573
  // todo: this should be used instead of the too many args thing above (by removing that)
2494
2574
  if (i >= paramCount) {
@@ -2509,7 +2589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2509
2589
  out.push(Opcodes.i32_from);
2510
2590
  }
2511
2591
 
2512
- if (typedParams) out = out.concat(getNodeType(scope, arg));
2592
+ if (typedParams) out = out.concat(arg._callType ?? getNodeType(scope, arg));
2513
2593
  }
2514
2594
 
2515
2595
  out.push([ Opcodes.call, idx ]);
@@ -2929,7 +3009,8 @@ const generateVar = (scope, decl) => {
2929
3009
  object: { type: 'Identifier', name: tmpName, },
2930
3010
  property: { type: 'Identifier', name: 'length', }
2931
3011
  }
2932
- ]
3012
+ ],
3013
+ _protoInternalCall: true
2933
3014
  }
2934
3015
  });
2935
3016
  }
@@ -5009,13 +5090,23 @@ const countParams = (func, name = undefined) => {
5009
5090
  }
5010
5091
  if (func.argc) return func.argc;
5011
5092
 
5093
+ name ??= func.name;
5012
5094
  let params = func.params.length;
5013
5095
  if (func.constr) params -= 4;
5014
- if (!func.internal || builtinFuncs[func.name]?.typedParams) params = Math.floor(params / 2);
5096
+ if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
5015
5097
 
5016
5098
  return func.argc = params;
5017
5099
  };
5018
5100
 
5101
+ const countLength = (func, name = undefined) => {
5102
+ name ??= func.name;
5103
+
5104
+ let count = countParams(func, name);
5105
+ if (builtinFuncs[name] && name.includes('_prototype_')) count--;
5106
+
5107
+ return count;
5108
+ };
5109
+
5019
5110
  const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
5020
5111
  const name = decl.object.name;
5021
5112
 
@@ -5034,9 +5125,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5034
5125
  // todo: support optional
5035
5126
 
5036
5127
  const func = funcs.find(x => x.name === name);
5037
- if (func) return withType(scope, number(countParams(func)), TYPES.number);
5128
+ if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
5038
5129
 
5039
- if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countParams(builtinFuncs[name])), TYPES.number);
5130
+ if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
5040
5131
  if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
5041
5132
  if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
5042
5133
 
@@ -5368,7 +5459,7 @@ const objectHack = node => {
5368
5459
  if (node.computed || node.optional) return;
5369
5460
 
5370
5461
  // hack: block these properties as they can be accessed on functions
5371
- if (node.property.name == 'length' || node.property.name == 'name') return;
5462
+ if (node.property.name == 'length' || node.property.name == 'name' || node.property.name == 'call') return;
5372
5463
 
5373
5464
  let objectName = node.object.name;
5374
5465
 
@@ -5447,6 +5538,7 @@ const generateFunc = (scope, decl) => {
5447
5538
  }
5448
5539
  }
5449
5540
 
5541
+ const prelude = [];
5450
5542
  const defaultValues = {};
5451
5543
  for (let i = 0; i < params.length; i++) {
5452
5544
  let name;
@@ -5474,7 +5566,27 @@ const generateFunc = (scope, decl) => {
5474
5566
 
5475
5567
  allocVar(func, name, false);
5476
5568
  if (typedInput && params[i].typeAnnotation) {
5477
- addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
5569
+ const typeAnno = extractTypeAnnotation(params[i]);
5570
+ addVarMetadata(func, name, false, typeAnno);
5571
+
5572
+ // automatically add throws if unexpected this type to builtins
5573
+ if (globalThis.precompile && i === 0 && func.name.includes('_prototype_') && [
5574
+ TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
5575
+ TYPES.set, TYPES.map,
5576
+ TYPES.weakref, TYPES.weakset, TYPES.weakmap,
5577
+ TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
5578
+ ].includes(typeAnno.type)) {
5579
+ prelude.push(
5580
+ [ Opcodes.local_get, i * 2 + 1 ],
5581
+ ...number(typeAnno.type, Valtype.i32),
5582
+ [ Opcodes.i32_ne ],
5583
+ [ Opcodes.if, Blocktype.void ],
5584
+ ...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
5585
+ [ Opcodes.end ]
5586
+ );
5587
+ }
5588
+
5589
+ // todo: if string, try converting to it to one
5478
5590
  }
5479
5591
  }
5480
5592
 
@@ -5489,7 +5601,6 @@ const generateFunc = (scope, decl) => {
5489
5601
  };
5490
5602
  }
5491
5603
 
5492
- const prelude = [];
5493
5604
  for (const x in defaultValues) {
5494
5605
  prelude.push(
5495
5606
  ...getType(func, x),
@@ -5539,7 +5650,7 @@ const generateFunc = (scope, decl) => {
5539
5650
 
5540
5651
  if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
5541
5652
  if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
5542
- func.wasm.splice(main.wasm.length - 1, 1);
5653
+ func.wasm.splice(func.wasm.length - 1, 1);
5543
5654
  } else {
5544
5655
  func.returns = [];
5545
5656
  }
@@ -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.5+4f843e06e",
4
+ "version": "0.28.7+a711fccd4",
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.5+4f843e06e';
3
+ globalThis.version = '0.28.7+a711fccd4';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {