porffor 0.60.9 → 0.60.10

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.
@@ -89,7 +89,7 @@ const isFuncType = type =>
89
89
  type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression' ||
90
90
  type === 'ClassDeclaration' || type === 'ClassExpression';
91
91
  const hasFuncWithName = name =>
92
- Object.hasOwn(funcIndex, name) || Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) || Object.hasOwn(internalConstrs, name);
92
+ name in funcIndex || name in builtinFuncs || name in importedFuncs || name in internalConstrs;
93
93
 
94
94
  const astCache = new WeakMap();
95
95
  const cacheAst = (decl, wasm) => {
@@ -541,8 +541,8 @@ const generateEnum = (scope, decl) => {
541
541
  const optional = (op, clause = op.at(-1)) => clause || clause === 0 ? (Array.isArray(op[0]) ? op : [ op ]) : [];
542
542
 
543
543
  const lookupName = (scope, name) => {
544
- if (Object.hasOwn(scope.locals, name)) return [ scope.locals[name], false ];
545
- if (Object.hasOwn(globals, name)) return [ globals[name], true ];
544
+ if (name in scope.locals) return [ scope.locals[name], false ];
545
+ if (name in globals) return [ globals[name], true ];
546
546
 
547
547
  return [ undefined, undefined ];
548
548
  };
@@ -608,7 +608,7 @@ const hoistLookupType = (scope, name) => {
608
608
  const lookup = (scope, name, failEarly = false) => {
609
609
  let local = scope.locals[name];
610
610
 
611
- if (Object.hasOwn(builtinVars, name)) {
611
+ if (name in builtinVars) {
612
612
  let wasm = builtinVars[name];
613
613
  if (wasm.usesImports) scope.usesImports = true;
614
614
 
@@ -616,9 +616,9 @@ const lookup = (scope, name, failEarly = false) => {
616
616
  return wasm.slice();
617
617
  }
618
618
 
619
- if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
619
+ if (!(name in funcIndex) && name in builtinFuncs) {
620
620
  includeBuiltin(scope, name);
621
- } else if (Object.hasOwn(internalConstrs, name)) {
621
+ } else if (name in internalConstrs) {
622
622
  // todo: return an actual something
623
623
  return [ number(1) ];
624
624
  }
@@ -662,16 +662,16 @@ const lookup = (scope, name, failEarly = false) => {
662
662
  }
663
663
 
664
664
  // no local var with name
665
- if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
666
- if (Object.hasOwn(funcIndex, name)) return funcRef(funcByName(name));
667
- if (Object.hasOwn(importedFuncs, name)) return [ number(importedFuncs[name] - importedFuncs.length) ];
665
+ if (name in globals) return [ [ Opcodes.global_get, globals[name].idx ] ];
666
+ if (name in funcIndex) return funcRef(funcByName(name));
667
+ if (name in importedFuncs) return [ number(importedFuncs[name] - importedFuncs.length) ];
668
668
 
669
669
  if (name.startsWith('__')) {
670
670
  // return undefined if unknown key in already known var
671
671
  let parent = name.slice(2).split('_').slice(0, -1).join('_');
672
672
  if (parent.includes('_')) parent = '__' + parent;
673
673
 
674
- if (Object.hasOwn(builtinFuncs, name + '$get')) {
674
+ if ((name + '$get') in builtinFuncs) {
675
675
  // hack: force error as accessors should only be used with objects anyway
676
676
  return internalThrow(scope, 'TypeError', 'Accessor called without object');
677
677
  }
@@ -1474,7 +1474,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1474
1474
  },
1475
1475
  glbl: (opcode, name, type) => {
1476
1476
  const globalName = '#porf#' + name; // avoid potential name clashing with user js
1477
- if (!Object.hasOwn(globals, globalName)) {
1477
+ if (!(globalName in globals)) {
1478
1478
  const idx = globals['#ind']++;
1479
1479
  globals[globalName] = { idx, type };
1480
1480
 
@@ -1509,7 +1509,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1509
1509
  return out;
1510
1510
  },
1511
1511
  loc: (name, type) => {
1512
- if (!Object.hasOwn(scope.locals, name)) {
1512
+ if (!(name in scope.locals)) {
1513
1513
  const idx = scope.localInd++;
1514
1514
  scope.locals[name] = { idx, type };
1515
1515
  }
@@ -1551,7 +1551,7 @@ const asmFunc = (name, func) => {
1551
1551
  if (existing) return existing;
1552
1552
 
1553
1553
  const allLocals = params.concat(localTypes);
1554
- const locals = {};
1554
+ const locals = Object.create(null);
1555
1555
  for (let i = 0; i < allLocals.length; i++) {
1556
1556
  locals[localNames[i] ?? `l${i}`] = { idx: i, type: allLocals[i] };
1557
1557
  }
@@ -1646,14 +1646,14 @@ const getType = (scope, name, failEarly = false) => {
1646
1646
  [ null, () => hoistLookupType(scope, name) ]
1647
1647
  ];
1648
1648
 
1649
- if (Object.hasOwn(builtinVars, name)) return [ number(builtinVars[name].type ?? TYPES.number, Valtype.i32) ];
1649
+ if (name in builtinVars) return [ number(builtinVars[name].type ?? TYPES.number, Valtype.i32) ];
1650
1650
 
1651
1651
  let metadata, typeLocal, global = null;
1652
- if (Object.hasOwn(scope.locals, name)) {
1652
+ if (name in scope.locals) {
1653
1653
  metadata = scope.locals[name].metadata;
1654
1654
  typeLocal = scope.locals[name + '#type'];
1655
1655
  global = false;
1656
- } else if (Object.hasOwn(globals, name)) {
1656
+ } else if (name in globals) {
1657
1657
  metadata = globals[name].metadata;
1658
1658
  typeLocal = globals[name + '#type'];
1659
1659
  global = true;
@@ -1687,10 +1687,10 @@ const setType = (scope, name, type, noInfer = false) => {
1687
1687
  const out = typeof type === 'number' ? [ number(type, Valtype.i32) ] : type;
1688
1688
 
1689
1689
  let metadata, typeLocal, global = false;
1690
- if (Object.hasOwn(scope.locals, name)) {
1690
+ if (name in scope.locals) {
1691
1691
  metadata = scope.locals[name].metadata;
1692
1692
  typeLocal = scope.locals[name + '#type'];
1693
- } else if (Object.hasOwn(globals, name)) {
1693
+ } else if (name in globals) {
1694
1694
  metadata = globals[name].metadata;
1695
1695
  typeLocal = globals[name + '#type'];
1696
1696
  global = true;
@@ -1797,8 +1797,8 @@ const getNodeType = (scope, node) => {
1797
1797
  if (func.returnType != null) return func.returnType;
1798
1798
  }
1799
1799
 
1800
- if (Object.hasOwn(builtinFuncs, name) && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1801
- if (Object.hasOwn(internalConstrs, name) && internalConstrs[name].type != null) return internalConstrs[name].type;
1800
+ if (name in builtinFuncs && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1801
+ if (name in internalConstrs && internalConstrs[name].type != null) return internalConstrs[name].type;
1802
1802
 
1803
1803
  if (name.startsWith('__Porffor_wasm_')) {
1804
1804
  // todo: return undefined for non-returning ops
@@ -2171,7 +2171,7 @@ const createThisArg = (scope, decl) => {
2171
2171
  const name = decl.callee?.name;
2172
2172
  if (decl._new) {
2173
2173
  // if precompiling or builtin func, just make it null as unused
2174
- if (!decl._forceCreateThis && (globalThis.precompile || Object.hasOwn(builtinFuncs, name))) return [
2174
+ if (!decl._forceCreateThis && (globalThis.precompile || name in builtinFuncs)) return [
2175
2175
  number(NULL),
2176
2176
  number(TYPES.object, Valtype.i32)
2177
2177
  ];
@@ -2338,7 +2338,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2338
2338
  target.name = spl.slice(0, -1).join('_');
2339
2339
 
2340
2340
  if (builtinFuncs['__' + target.name + '_' + protoName]) protoName = null;
2341
- else if (lookupName(scope, target.name)[0] == null && !Object.hasOwn(builtinFuncs, target.name)) {
2341
+ else if (lookupName(scope, target.name)[0] == null && !(target.name in builtinFuncs)) {
2342
2342
  if (lookupName(scope, '__' + target.name)[0] != null || builtinFuncs['__' + target.name]) target.name = '__' + target.name;
2343
2343
  else protoName = null;
2344
2344
  }
@@ -2478,18 +2478,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2478
2478
  let idx;
2479
2479
  if (decl._funcIdx) {
2480
2480
  idx = decl._funcIdx;
2481
- } else if (Object.hasOwn(internalConstrs, name) && !decl._noInternalConstr) {
2481
+ } else if (name in internalConstrs && !decl._noInternalConstr) {
2482
2482
  if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2483
2483
  return internalConstrs[name].generate(scope, decl, _global, _name);
2484
- } else if (Object.hasOwn(funcIndex, name)) {
2484
+ } else if (name in funcIndex) {
2485
2485
  idx = funcIndex[name];
2486
2486
  } else if (scope.name === name) {
2487
2487
  // fallback for own func but with a different var/id name
2488
2488
  idx = scope.index;
2489
- } else if (Object.hasOwn(importedFuncs, name)) {
2489
+ } else if (name in importedFuncs) {
2490
2490
  idx = importedFuncs[name];
2491
2491
  scope.usesImports = true;
2492
- } else if (Object.hasOwn(builtinFuncs, name)) {
2492
+ } else if (name in builtinFuncs) {
2493
2493
  if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2494
2494
 
2495
2495
  includeBuiltin(scope, name);
@@ -3136,7 +3136,7 @@ const allocVar = (scope, name, global = false, type = true, redecl = false, i32
3136
3136
  const target = global ? globals : scope.locals;
3137
3137
 
3138
3138
  // already declared
3139
- if (Object.hasOwn(target, name)) {
3139
+ if (name in target) {
3140
3140
  if (redecl) {
3141
3141
  // force change old local name(s)
3142
3142
  target['#redecl_' + name + uniqId()] = target[name];
@@ -3332,7 +3332,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3332
3332
  const [ _func, out ] = generateFunc(scope, init, true);
3333
3333
 
3334
3334
  const funcName = init.id?.name;
3335
- if (name !== funcName && Object.hasOwn(funcIndex, funcName)) {
3335
+ if (name !== funcName && funcName in funcIndex) {
3336
3336
  funcIndex[name] = funcIndex[funcName];
3337
3337
  delete funcIndex[funcName];
3338
3338
  }
@@ -3347,7 +3347,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3347
3347
  }
3348
3348
 
3349
3349
  let out = [];
3350
- if (topLevel && Object.hasOwn(builtinVars, name)) {
3350
+ if (topLevel && name in builtinVars) {
3351
3351
  // cannot redeclare
3352
3352
  if (kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
3353
3353
 
@@ -3395,7 +3395,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3395
3395
  }
3396
3396
 
3397
3397
  if (globalThis.precompile && global) {
3398
- scope.globalInits ??= {};
3398
+ scope.globalInits ??= Object.create(null);
3399
3399
  scope.globalInits[name] = newOut;
3400
3400
  }
3401
3401
  } else {
@@ -4214,7 +4214,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
4214
4214
  ];
4215
4215
  }
4216
4216
 
4217
- if (Object.hasOwn(builtinVars, name)) {
4217
+ if (name in builtinVars) {
4218
4218
  if (scope.strict) return internalThrow(scope, 'TypeError', `Cannot assign to non-writable global ${name}`, true);
4219
4219
 
4220
4220
  // just return rhs (eg `NaN = 2`)
@@ -5845,7 +5845,7 @@ const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
5845
5845
 
5846
5846
  const countParams = (func, name = undefined) => {
5847
5847
  if (!func) {
5848
- if (Object.hasOwn(importedFuncs, name)) {
5848
+ if (name in importedFuncs) {
5849
5849
  // reverse lookup then normal lookup
5850
5850
  func = importedFuncs[importedFuncs[name]];
5851
5851
  if (func) return func.params?.length ?? func.params;
@@ -6577,6 +6577,7 @@ const generateTemplate = (scope, decl) => {
6577
6577
 
6578
6578
  const generateTaggedTemplate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
6579
6579
  const intrinsics = {
6580
+ __proto__: null,
6580
6581
  __Porffor_wasm: str => {
6581
6582
  let out = [];
6582
6583
 
@@ -6603,12 +6604,12 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6603
6604
  const immediates = asm.slice(1).map(x => {
6604
6605
  const n = parseFloat(x);
6605
6606
  if (Number.isNaN(n) && x !== 'NaN') {
6606
- if (Object.hasOwn(builtinFuncs, x)) {
6607
+ if (x in builtinFuncs) {
6607
6608
  if (funcIndex[x] == null) includeBuiltin(scope, x);
6608
6609
  return funcIndex[x];
6609
6610
  }
6610
6611
 
6611
- if (Object.hasOwn(importedFuncs, x)) {
6612
+ if (x in importedFuncs) {
6612
6613
  scope.usesImports = true;
6613
6614
  return importedFuncs[x];
6614
6615
  }
@@ -6648,7 +6649,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6648
6649
  };
6649
6650
 
6650
6651
  const { quasis, expressions } = decl.quasi;
6651
- if (Object.hasOwn(intrinsics, decl.tag.name)) {
6652
+ if (decl.tag.name in intrinsics) {
6652
6653
  let str = quasis[0].value.raw;
6653
6654
 
6654
6655
  for (let i = 0; i < expressions.length; i++) {
@@ -6732,7 +6733,7 @@ const objectHack = node => {
6732
6733
  if (objectName !== 'Object_prototype' && (node.property.name === 'propertyIsEnumerable' || node.property.name === 'hasOwnProperty' || node.property.name === 'isPrototypeOf')) return abortOut;
6733
6734
 
6734
6735
  const name = '__' + objectName + '_' + node.property.name;
6735
- if ((!hasFuncWithName(name) && !Object.hasOwn(builtinVars, name) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || Object.hasOwn(builtinVars, objectName) || hasFuncWithName('__' + objectName) || Object.hasOwn(builtinVars, '__' + objectName))) return abortOut;
6736
+ if ((!hasFuncWithName(name) && !(name in builtinVars) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || objectName in builtinVars || hasFuncWithName('__' + objectName) || ('__' + objectName) in builtinVars)) return abortOut;
6736
6737
 
6737
6738
  if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
6738
6739
 
@@ -6795,7 +6796,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6795
6796
  const arrow = decl.type === 'ArrowFunctionExpression' || decl.type === 'Program';
6796
6797
  const func = {
6797
6798
  start: decl.start,
6798
- locals: {},
6799
+ locals: Object.create(null),
6799
6800
  localInd: 0,
6800
6801
  returns: [ valtypeBinary, Valtype.i32 ], // value, type
6801
6802
  name,
@@ -7005,7 +7006,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
7005
7006
  wasm.push(...getNodeType(func, getLastNode(decl.body.body)));
7006
7007
 
7007
7008
  // inject promise job runner func at the end of main if promises are made
7008
- if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
7009
+ if (('Promise' in funcIndex) || ('__Promise_resolve' in funcIndex) || ('__Promise_reject' in funcIndex)) {
7009
7010
  wasm.push(
7010
7011
  [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ]
7011
7012
  );
@@ -7180,6 +7181,7 @@ const generateBlock = (scope, decl) => {
7180
7181
  };
7181
7182
 
7182
7183
  const internalConstrs = {
7184
+ __proto__: null,
7183
7185
  __Array_of: {
7184
7186
  // this is not a constructor but best fits internal structure here
7185
7187
  generate: (scope, decl, global, name) => {
@@ -7369,7 +7371,8 @@ const internalConstrs = {
7369
7371
 
7370
7372
  let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
7371
7373
  export default program => {
7372
- globals = { ['#ind']: 0 };
7374
+ globals = Object.create(null);
7375
+ globals['#ind'] = 0;
7373
7376
  tags = [];
7374
7377
  exceptions = [];
7375
7378
  funcs = []; indirectFuncs = [];
@@ -7377,7 +7380,7 @@ export default program => {
7377
7380
  return indirectFuncs._bytesPerFuncLut ??=
7378
7381
  Math.min(Math.floor((pageSize * 2) / indirectFuncs.length), indirectFuncs.reduce((acc, x) => x.name.length > acc ? x.name.length : acc, 0) + 8);
7379
7382
  };
7380
- funcIndex = {};
7383
+ funcIndex = Object.create(null);
7381
7384
  depth = [];
7382
7385
  pages = new Map();
7383
7386
  data = [];
@@ -7404,8 +7407,8 @@ export default program => {
7404
7407
  // keep builtins between compiles as much as possible
7405
7408
  if (lastValtype !== valtypeBinary) {
7406
7409
  lastValtype = valtypeBinary;
7407
- builtinFuncs = new BuiltinFuncs();
7408
- builtinVars = new BuiltinVars({ builtinFuncs });
7410
+ builtinFuncs = BuiltinFuncs();
7411
+ builtinVars = BuiltinVars({ builtinFuncs });
7409
7412
 
7410
7413
  const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7411
7414
  objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
@@ -237,7 +237,7 @@ const precompile = async () => {
237
237
  return `// autogenerated by compiler/precompile.js
238
238
  import { number } from './encoding.js';
239
239
 
240
- export const BuiltinFuncs = function() {
240
+ export const BuiltinFuncs = x => {
241
241
  ${funcs.map(x => {
242
242
  const rewriteWasm = wasm => {
243
243
  const str = JSON.stringify(wasm.filter(x => x.length && (x[0] != null || typeof x[1] === 'string')), (k, v) => {
@@ -278,7 +278,7 @@ ${funcs.map(x => {
278
278
  const name = x.name.includes('#') ? `['${x.name}']` : `.${x.name}`;
279
279
 
280
280
  const returnTypes = [...(x.returnTypes ?? [])].filter(x => ![ TYPES.undefined, TYPES.number, TYPES.boolean, TYPES.function ].includes(x));
281
- return `this${name} = {
281
+ return `x${name} = {
282
282
  wasm:${rewriteWasm(x.wasm)},
283
283
  params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)},` : ''}${returnTypes.length > 0 ? `returnTypes:${JSON.stringify(returnTypes)},` : ''}jsLength:${x.jsLength},
284
284
  locals:${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))},localNames:${JSON.stringify(locals.map(x => x[0]))},
package/foo.js ADDED
@@ -0,0 +1,34 @@
1
+ // benchmark.js
2
+ const ITER = 50_000_000; // 50 million iterations
3
+ const key = "a";
4
+
5
+ // Create a null-prototype object
6
+ const o = Object.create(null);
7
+ o[key] = 123;
8
+
9
+ // --- Benchmark "in" ---
10
+ const t1 = Date.now();
11
+ for (let i = 0; i < ITER; i++) {
12
+ if (key in o) {
13
+ // noop
14
+ }
15
+ }
16
+ console.log(`in: ${Date.now() - t1}ms`);
17
+
18
+ // --- Benchmark Object.hasOwn ---
19
+ const t2 = Date.now();
20
+ for (let i = 0; i < ITER; i++) {
21
+ if (Object.hasOwn(o, key)) {
22
+ // noop
23
+ }
24
+ }
25
+ console.log(`Object.hasOwn: ${Date.now() - t2}ms`);
26
+
27
+ // --- Benchmark o[k] ---
28
+ const t3 = Date.now();
29
+ for (let i = 0; i < ITER; i++) {
30
+ if (o[key] !== undefined) {
31
+ // noop
32
+ }
33
+ }
34
+ console.log(`o[k]: ${Date.now() - t3}ms`);
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.60.9",
4
+ "version": "0.60.10",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.60.9';
3
+ globalThis.version = '0.60.10';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {