porffor 0.28.6 → 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.
@@ -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 ]);
@@ -5043,13 +5090,23 @@ const countParams = (func, name = undefined) => {
5043
5090
  }
5044
5091
  if (func.argc) return func.argc;
5045
5092
 
5093
+ name ??= func.name;
5046
5094
  let params = func.params.length;
5047
5095
  if (func.constr) params -= 4;
5048
- if (!func.internal || builtinFuncs[func.name]?.typedParams) params = Math.floor(params / 2);
5096
+ if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
5049
5097
 
5050
5098
  return func.argc = params;
5051
5099
  };
5052
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
+
5053
5110
  const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
5054
5111
  const name = decl.object.name;
5055
5112
 
@@ -5068,9 +5125,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5068
5125
  // todo: support optional
5069
5126
 
5070
5127
  const func = funcs.find(x => x.name === name);
5071
- if (func) return withType(scope, number(countParams(func)), TYPES.number);
5128
+ if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
5072
5129
 
5073
- 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);
5074
5131
  if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
5075
5132
  if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
5076
5133
 
@@ -5402,7 +5459,7 @@ const objectHack = node => {
5402
5459
  if (node.computed || node.optional) return;
5403
5460
 
5404
5461
  // hack: block these properties as they can be accessed on functions
5405
- 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;
5406
5463
 
5407
5464
  let objectName = node.object.name;
5408
5465
 
@@ -5481,6 +5538,7 @@ const generateFunc = (scope, decl) => {
5481
5538
  }
5482
5539
  }
5483
5540
 
5541
+ const prelude = [];
5484
5542
  const defaultValues = {};
5485
5543
  for (let i = 0; i < params.length; i++) {
5486
5544
  let name;
@@ -5508,7 +5566,27 @@ const generateFunc = (scope, decl) => {
5508
5566
 
5509
5567
  allocVar(func, name, false);
5510
5568
  if (typedInput && params[i].typeAnnotation) {
5511
- 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
5512
5590
  }
5513
5591
  }
5514
5592
 
@@ -5523,7 +5601,6 @@ const generateFunc = (scope, decl) => {
5523
5601
  };
5524
5602
  }
5525
5603
 
5526
- const prelude = [];
5527
5604
  for (const x in defaultValues) {
5528
5605
  prelude.push(
5529
5606
  ...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.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.6+56105b926';
3
+ globalThis.version = '0.28.7+a711fccd4';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {