porffor 0.60.8 → 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.
@@ -1,5 +1,5 @@
1
1
  import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
2
- import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector, read_signedLEB128 } from './encoding.js';
2
+ import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
5
5
  import { TYPES, TYPE_FLAGS, TYPE_NAMES } from './types.js';
@@ -41,24 +41,30 @@ const allocBytes = (scope, reason, bytes) => {
41
41
  return allocs.get(reason);
42
42
  }
43
43
 
44
- let bin = bins.find(x => (pageSize - x.used) >= bytes);
45
- if (!bin) {
46
- // new bin
47
- const page = pages.size;
48
- bin = {
49
- used: 0,
50
- page
51
- };
44
+ let startingPtr = 0;
45
+ while (bytes > 0) {
46
+ const alloc = Math.min(bytes, pageSize);
47
+ bytes -= alloc;
52
48
 
53
- const id = bins.push(bin);
54
- pages.set(`#bin: ${id}`, page);
55
- }
49
+ let bin = bins.find(x => (pageSize - x.used) >= alloc);
50
+ if (!bin) {
51
+ // new bin
52
+ const page = pages.size;
53
+ bin = {
54
+ used: 0,
55
+ page
56
+ };
56
57
 
57
- const ptr = pagePtr(bin.page) + bin.used;
58
- bin.used += bytes;
58
+ const id = bins.push(bin);
59
+ pages.set(`#bin: ${id}`, page);
60
+ }
61
+
62
+ if (!startingPtr) startingPtr = pagePtr(bin.page) + bin.used;
63
+ bin.used += alloc;
64
+ }
59
65
 
60
- allocs.set(reason, ptr);
61
- return ptr;
66
+ allocs.set(reason, startingPtr);
67
+ return startingPtr;
62
68
  };
63
69
 
64
70
  export const allocStr = (scope, str, bytestring) => {
@@ -83,7 +89,7 @@ const isFuncType = type =>
83
89
  type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression' ||
84
90
  type === 'ClassDeclaration' || type === 'ClassExpression';
85
91
  const hasFuncWithName = name =>
86
- 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;
87
93
 
88
94
  const astCache = new WeakMap();
89
95
  const cacheAst = (decl, wasm) => {
@@ -535,8 +541,8 @@ const generateEnum = (scope, decl) => {
535
541
  const optional = (op, clause = op.at(-1)) => clause || clause === 0 ? (Array.isArray(op[0]) ? op : [ op ]) : [];
536
542
 
537
543
  const lookupName = (scope, name) => {
538
- if (Object.hasOwn(scope.locals, name)) return [ scope.locals[name], false ];
539
- 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 ];
540
546
 
541
547
  return [ undefined, undefined ];
542
548
  };
@@ -602,7 +608,7 @@ const hoistLookupType = (scope, name) => {
602
608
  const lookup = (scope, name, failEarly = false) => {
603
609
  let local = scope.locals[name];
604
610
 
605
- if (Object.hasOwn(builtinVars, name)) {
611
+ if (name in builtinVars) {
606
612
  let wasm = builtinVars[name];
607
613
  if (wasm.usesImports) scope.usesImports = true;
608
614
 
@@ -610,9 +616,9 @@ const lookup = (scope, name, failEarly = false) => {
610
616
  return wasm.slice();
611
617
  }
612
618
 
613
- if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
619
+ if (!(name in funcIndex) && name in builtinFuncs) {
614
620
  includeBuiltin(scope, name);
615
- } else if (Object.hasOwn(internalConstrs, name)) {
621
+ } else if (name in internalConstrs) {
616
622
  // todo: return an actual something
617
623
  return [ number(1) ];
618
624
  }
@@ -656,16 +662,16 @@ const lookup = (scope, name, failEarly = false) => {
656
662
  }
657
663
 
658
664
  // no local var with name
659
- if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
660
- if (Object.hasOwn(funcIndex, name)) return funcRef(funcByName(name));
661
- 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) ];
662
668
 
663
669
  if (name.startsWith('__')) {
664
670
  // return undefined if unknown key in already known var
665
671
  let parent = name.slice(2).split('_').slice(0, -1).join('_');
666
672
  if (parent.includes('_')) parent = '__' + parent;
667
673
 
668
- if (Object.hasOwn(builtinFuncs, name + '$get')) {
674
+ if ((name + '$get') in builtinFuncs) {
669
675
  // hack: force error as accessors should only be used with objects anyway
670
676
  return internalThrow(scope, 'TypeError', 'Accessor called without object');
671
677
  }
@@ -1468,7 +1474,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1468
1474
  },
1469
1475
  glbl: (opcode, name, type) => {
1470
1476
  const globalName = '#porf#' + name; // avoid potential name clashing with user js
1471
- if (!Object.hasOwn(globals, globalName)) {
1477
+ if (!(globalName in globals)) {
1472
1478
  const idx = globals['#ind']++;
1473
1479
  globals[globalName] = { idx, type };
1474
1480
 
@@ -1503,7 +1509,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1503
1509
  return out;
1504
1510
  },
1505
1511
  loc: (name, type) => {
1506
- if (!Object.hasOwn(scope.locals, name)) {
1512
+ if (!(name in scope.locals)) {
1507
1513
  const idx = scope.localInd++;
1508
1514
  scope.locals[name] = { idx, type };
1509
1515
  }
@@ -1545,7 +1551,7 @@ const asmFunc = (name, func) => {
1545
1551
  if (existing) return existing;
1546
1552
 
1547
1553
  const allLocals = params.concat(localTypes);
1548
- const locals = {};
1554
+ const locals = Object.create(null);
1549
1555
  for (let i = 0; i < allLocals.length; i++) {
1550
1556
  locals[localNames[i] ?? `l${i}`] = { idx: i, type: allLocals[i] };
1551
1557
  }
@@ -1640,14 +1646,14 @@ const getType = (scope, name, failEarly = false) => {
1640
1646
  [ null, () => hoistLookupType(scope, name) ]
1641
1647
  ];
1642
1648
 
1643
- 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) ];
1644
1650
 
1645
1651
  let metadata, typeLocal, global = null;
1646
- if (Object.hasOwn(scope.locals, name)) {
1652
+ if (name in scope.locals) {
1647
1653
  metadata = scope.locals[name].metadata;
1648
1654
  typeLocal = scope.locals[name + '#type'];
1649
1655
  global = false;
1650
- } else if (Object.hasOwn(globals, name)) {
1656
+ } else if (name in globals) {
1651
1657
  metadata = globals[name].metadata;
1652
1658
  typeLocal = globals[name + '#type'];
1653
1659
  global = true;
@@ -1681,10 +1687,10 @@ const setType = (scope, name, type, noInfer = false) => {
1681
1687
  const out = typeof type === 'number' ? [ number(type, Valtype.i32) ] : type;
1682
1688
 
1683
1689
  let metadata, typeLocal, global = false;
1684
- if (Object.hasOwn(scope.locals, name)) {
1690
+ if (name in scope.locals) {
1685
1691
  metadata = scope.locals[name].metadata;
1686
1692
  typeLocal = scope.locals[name + '#type'];
1687
- } else if (Object.hasOwn(globals, name)) {
1693
+ } else if (name in globals) {
1688
1694
  metadata = globals[name].metadata;
1689
1695
  typeLocal = globals[name + '#type'];
1690
1696
  global = true;
@@ -1791,8 +1797,8 @@ const getNodeType = (scope, node) => {
1791
1797
  if (func.returnType != null) return func.returnType;
1792
1798
  }
1793
1799
 
1794
- if (Object.hasOwn(builtinFuncs, name) && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1795
- 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;
1796
1802
 
1797
1803
  if (name.startsWith('__Porffor_wasm_')) {
1798
1804
  // todo: return undefined for non-returning ops
@@ -2165,7 +2171,7 @@ const createThisArg = (scope, decl) => {
2165
2171
  const name = decl.callee?.name;
2166
2172
  if (decl._new) {
2167
2173
  // if precompiling or builtin func, just make it null as unused
2168
- if (!decl._forceCreateThis && (globalThis.precompile || Object.hasOwn(builtinFuncs, name))) return [
2174
+ if (!decl._forceCreateThis && (globalThis.precompile || name in builtinFuncs)) return [
2169
2175
  number(NULL),
2170
2176
  number(TYPES.object, Valtype.i32)
2171
2177
  ];
@@ -2332,7 +2338,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2332
2338
  target.name = spl.slice(0, -1).join('_');
2333
2339
 
2334
2340
  if (builtinFuncs['__' + target.name + '_' + protoName]) protoName = null;
2335
- 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)) {
2336
2342
  if (lookupName(scope, '__' + target.name)[0] != null || builtinFuncs['__' + target.name]) target.name = '__' + target.name;
2337
2343
  else protoName = null;
2338
2344
  }
@@ -2472,18 +2478,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2472
2478
  let idx;
2473
2479
  if (decl._funcIdx) {
2474
2480
  idx = decl._funcIdx;
2475
- } else if (Object.hasOwn(internalConstrs, name) && !decl._noInternalConstr) {
2481
+ } else if (name in internalConstrs && !decl._noInternalConstr) {
2476
2482
  if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2477
2483
  return internalConstrs[name].generate(scope, decl, _global, _name);
2478
- } else if (Object.hasOwn(funcIndex, name)) {
2484
+ } else if (name in funcIndex) {
2479
2485
  idx = funcIndex[name];
2480
2486
  } else if (scope.name === name) {
2481
2487
  // fallback for own func but with a different var/id name
2482
2488
  idx = scope.index;
2483
- } else if (Object.hasOwn(importedFuncs, name)) {
2489
+ } else if (name in importedFuncs) {
2484
2490
  idx = importedFuncs[name];
2485
2491
  scope.usesImports = true;
2486
- } else if (Object.hasOwn(builtinFuncs, name)) {
2492
+ } else if (name in builtinFuncs) {
2487
2493
  if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2488
2494
 
2489
2495
  includeBuiltin(scope, name);
@@ -2840,7 +2846,7 @@ const knownType = (scope, type) => {
2840
2846
  if (typeof type === 'number') return type;
2841
2847
 
2842
2848
  if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
2843
- return read_signedLEB128(type[0].slice(1));
2849
+ return type[0][1];
2844
2850
  }
2845
2851
 
2846
2852
  if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
@@ -3130,7 +3136,7 @@ const allocVar = (scope, name, global = false, type = true, redecl = false, i32
3130
3136
  const target = global ? globals : scope.locals;
3131
3137
 
3132
3138
  // already declared
3133
- if (Object.hasOwn(target, name)) {
3139
+ if (name in target) {
3134
3140
  if (redecl) {
3135
3141
  // force change old local name(s)
3136
3142
  target['#redecl_' + name + uniqId()] = target[name];
@@ -3326,7 +3332,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3326
3332
  const [ _func, out ] = generateFunc(scope, init, true);
3327
3333
 
3328
3334
  const funcName = init.id?.name;
3329
- if (name !== funcName && Object.hasOwn(funcIndex, funcName)) {
3335
+ if (name !== funcName && funcName in funcIndex) {
3330
3336
  funcIndex[name] = funcIndex[funcName];
3331
3337
  delete funcIndex[funcName];
3332
3338
  }
@@ -3341,7 +3347,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3341
3347
  }
3342
3348
 
3343
3349
  let out = [];
3344
- if (topLevel && Object.hasOwn(builtinVars, name)) {
3350
+ if (topLevel && name in builtinVars) {
3345
3351
  // cannot redeclare
3346
3352
  if (kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
3347
3353
 
@@ -3389,7 +3395,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
3389
3395
  }
3390
3396
 
3391
3397
  if (globalThis.precompile && global) {
3392
- scope.globalInits ??= {};
3398
+ scope.globalInits ??= Object.create(null);
3393
3399
  scope.globalInits[name] = newOut;
3394
3400
  }
3395
3401
  } else {
@@ -4208,7 +4214,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
4208
4214
  ];
4209
4215
  }
4210
4216
 
4211
- if (Object.hasOwn(builtinVars, name)) {
4217
+ if (name in builtinVars) {
4212
4218
  if (scope.strict) return internalThrow(scope, 'TypeError', `Cannot assign to non-writable global ${name}`, true);
4213
4219
 
4214
4220
  // just return rhs (eg `NaN = 2`)
@@ -4319,7 +4325,7 @@ const generateUnary = (scope, decl) => {
4319
4325
  return [
4320
4326
  ...toNumeric(),
4321
4327
  Opcodes.i32_to,
4322
- [ Opcodes.i32_const, ...signedLEB128(-1) ],
4328
+ [ Opcodes.i32_const, -1 ],
4323
4329
  [ Opcodes.i32_xor ],
4324
4330
  Opcodes.i32_from
4325
4331
  ];
@@ -5118,14 +5124,14 @@ const generateForIn = (scope, decl) => {
5118
5124
  [ Opcodes.local_set, tmp ],
5119
5125
 
5120
5126
  // symbol is MSB 2 is set
5121
- [ Opcodes.i32_const, ...unsignedLEB128(TYPES.string) ],
5122
- [ Opcodes.i32_const, ...unsignedLEB128(TYPES.symbol) ],
5127
+ [ Opcodes.i32_const, TYPES.string ],
5128
+ [ Opcodes.i32_const, TYPES.symbol ],
5123
5129
  [ Opcodes.local_get, tmp ],
5124
5130
  number(0x40000000, Valtype.i32),
5125
5131
  [ Opcodes.i32_and ],
5126
5132
  [ Opcodes.select ],
5127
5133
  [ Opcodes.else ], // bytestring
5128
- [ Opcodes.i32_const, ...unsignedLEB128(TYPES.bytestring) ],
5134
+ [ Opcodes.i32_const, TYPES.bytestring ],
5129
5135
  [ Opcodes.end ]
5130
5136
  ]),
5131
5137
 
@@ -5839,7 +5845,7 @@ const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
5839
5845
 
5840
5846
  const countParams = (func, name = undefined) => {
5841
5847
  if (!func) {
5842
- if (Object.hasOwn(importedFuncs, name)) {
5848
+ if (name in importedFuncs) {
5843
5849
  // reverse lookup then normal lookup
5844
5850
  func = importedFuncs[importedFuncs[name]];
5845
5851
  if (func) return func.params?.length ?? func.params;
@@ -6571,6 +6577,7 @@ const generateTemplate = (scope, decl) => {
6571
6577
 
6572
6578
  const generateTaggedTemplate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
6573
6579
  const intrinsics = {
6580
+ __proto__: null,
6574
6581
  __Porffor_wasm: str => {
6575
6582
  let out = [];
6576
6583
 
@@ -6597,12 +6604,12 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6597
6604
  const immediates = asm.slice(1).map(x => {
6598
6605
  const n = parseFloat(x);
6599
6606
  if (Number.isNaN(n) && x !== 'NaN') {
6600
- if (Object.hasOwn(builtinFuncs, x)) {
6607
+ if (x in builtinFuncs) {
6601
6608
  if (funcIndex[x] == null) includeBuiltin(scope, x);
6602
6609
  return funcIndex[x];
6603
6610
  }
6604
6611
 
6605
- if (Object.hasOwn(importedFuncs, x)) {
6612
+ if (x in importedFuncs) {
6606
6613
  scope.usesImports = true;
6607
6614
  return importedFuncs[x];
6608
6615
  }
@@ -6615,6 +6622,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6615
6622
 
6616
6623
  const encodeFunc = ({
6617
6624
  [Opcodes.f64_const]: x => x,
6625
+ [Opcodes.i32_const]: x => x,
6618
6626
  [Opcodes.if]: unsignedLEB128,
6619
6627
  [Opcodes.loop]: unsignedLEB128
6620
6628
  })[inst[0]] ?? signedLEB128;
@@ -6641,7 +6649,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6641
6649
  };
6642
6650
 
6643
6651
  const { quasis, expressions } = decl.quasi;
6644
- if (Object.hasOwn(intrinsics, decl.tag.name)) {
6652
+ if (decl.tag.name in intrinsics) {
6645
6653
  let str = quasis[0].value.raw;
6646
6654
 
6647
6655
  for (let i = 0; i < expressions.length; i++) {
@@ -6725,7 +6733,7 @@ const objectHack = node => {
6725
6733
  if (objectName !== 'Object_prototype' && (node.property.name === 'propertyIsEnumerable' || node.property.name === 'hasOwnProperty' || node.property.name === 'isPrototypeOf')) return abortOut;
6726
6734
 
6727
6735
  const name = '__' + objectName + '_' + node.property.name;
6728
- 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;
6729
6737
 
6730
6738
  if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
6731
6739
 
@@ -6788,7 +6796,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6788
6796
  const arrow = decl.type === 'ArrowFunctionExpression' || decl.type === 'Program';
6789
6797
  const func = {
6790
6798
  start: decl.start,
6791
- locals: {},
6799
+ locals: Object.create(null),
6792
6800
  localInd: 0,
6793
6801
  returns: [ valtypeBinary, Valtype.i32 ], // value, type
6794
6802
  name,
@@ -6998,7 +7006,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6998
7006
  wasm.push(...getNodeType(func, getLastNode(decl.body.body)));
6999
7007
 
7000
7008
  // inject promise job runner func at the end of main if promises are made
7001
- 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)) {
7002
7010
  wasm.push(
7003
7011
  [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ]
7004
7012
  );
@@ -7173,6 +7181,7 @@ const generateBlock = (scope, decl) => {
7173
7181
  };
7174
7182
 
7175
7183
  const internalConstrs = {
7184
+ __proto__: null,
7176
7185
  __Array_of: {
7177
7186
  // this is not a constructor but best fits internal structure here
7178
7187
  generate: (scope, decl, global, name) => {
@@ -7362,7 +7371,8 @@ const internalConstrs = {
7362
7371
 
7363
7372
  let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
7364
7373
  export default program => {
7365
- globals = { ['#ind']: 0 };
7374
+ globals = Object.create(null);
7375
+ globals['#ind'] = 0;
7366
7376
  tags = [];
7367
7377
  exceptions = [];
7368
7378
  funcs = []; indirectFuncs = [];
@@ -7370,7 +7380,7 @@ export default program => {
7370
7380
  return indirectFuncs._bytesPerFuncLut ??=
7371
7381
  Math.min(Math.floor((pageSize * 2) / indirectFuncs.length), indirectFuncs.reduce((acc, x) => x.name.length > acc ? x.name.length : acc, 0) + 8);
7372
7382
  };
7373
- funcIndex = {};
7383
+ funcIndex = Object.create(null);
7374
7384
  depth = [];
7375
7385
  pages = new Map();
7376
7386
  data = [];
@@ -7397,8 +7407,8 @@ export default program => {
7397
7407
  // keep builtins between compiles as much as possible
7398
7408
  if (lastValtype !== valtypeBinary) {
7399
7409
  lastValtype = valtypeBinary;
7400
- builtinFuncs = new BuiltinFuncs();
7401
- builtinVars = new BuiltinVars({ builtinFuncs });
7410
+ builtinFuncs = BuiltinFuncs();
7411
+ builtinVars = BuiltinVars({ builtinFuncs });
7402
7412
 
7403
7413
  const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7404
7414
  objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
@@ -1,5 +1,5 @@
1
1
  // cyclone: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
2
- import { number, read_signedLEB128 } from './encoding.js';
2
+ import { number } from './encoding.js';
3
3
  import { Opcodes, Valtype } from './wasmSpec.js';
4
4
  import './prefs.js';
5
5
 
@@ -123,7 +123,7 @@ export default ({ name, wasm, locals: _locals, params }) => {
123
123
  }
124
124
 
125
125
  case Opcodes.i32_const: {
126
- const n = read_signedLEB128(op.slice(1));
126
+ const n = op[1];
127
127
  push(n);
128
128
  break;
129
129
  }
@@ -1,5 +1,5 @@
1
1
  import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
2
- import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
2
+ import { read_unsignedLEB128 } from './encoding.js';
3
3
  import { importedFuncs } from './builtins.js';
4
4
 
5
5
  const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
@@ -74,7 +74,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
74
74
  if (inst[0] === Opcodes.f64_const) {
75
75
  out += ` ${inst[1]}`;
76
76
  } else if (inst[0] === Opcodes.i32_const || inst[0] === Opcodes.i64_const) {
77
- out += ` ${read_signedLEB128(inst.slice(1))}`;
77
+ out += ` ${inst[1]}`;
78
78
  } else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store || inst[0] === Opcodes.i32_store16 || inst[0] === Opcodes.i32_load16_u) {
79
79
  out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}`;
80
80
  } else for (const operand of inst.slice(1)) {
@@ -3,10 +3,10 @@ import { Opcodes, Valtype } from './wasmSpec.js';
3
3
  export const number = (n, valtype = valtypeBinary) => {
4
4
  if (valtype === Valtype.f64) return [ Opcodes.f64_const, n ];
5
5
 
6
- const out = [ valtype === Valtype.i32 ? Opcodes.i32_const : Opcodes.i64_const ];
7
- signedLEB128_into(n, out);
8
-
9
- return out;
6
+ return [
7
+ valtype === Valtype.i32 ? Opcodes.i32_const : Opcodes.i64_const,
8
+ n
9
+ ];
10
10
  };
11
11
 
12
12
  export const codifyString = str => {
@@ -23,6 +23,9 @@ export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat
23
23
 
24
24
  // todo: this only works with integers within 32 bit range
25
25
  export const signedLEB128 = n => {
26
+ if (n === Infinity) return signedLEB128(2147483647);
27
+ if (n === -Infinity) return signedLEB128(-2147483648);
28
+
26
29
  n |= 0;
27
30
 
28
31
  // just input for small numbers (for perf as common)
@@ -49,6 +52,9 @@ export const signedLEB128 = n => {
49
52
  };
50
53
 
51
54
  export const unsignedLEB128 = n => {
55
+ if (n === Infinity) return unsignedLEB128(4294967295);
56
+ if (n === -Infinity) return unsignedLEB128(0);
57
+
52
58
  n |= 0;
53
59
 
54
60
  // just input for small numbers (for perf as common)
@@ -69,6 +75,9 @@ export const unsignedLEB128 = n => {
69
75
  };
70
76
 
71
77
  export const unsignedLEB128_length = n => {
78
+ if (n === Infinity) return unsignedLEB128_length(4294967295);
79
+ if (n === -Infinity) return unsignedLEB128_length(0);
80
+
72
81
  if (n < 0) n = n >>> 0;
73
82
  if (n <= 127) return 1;
74
83
  if (n <= 16383) return 2;
@@ -85,6 +94,9 @@ export const unsignedLEB128_length = n => {
85
94
  };
86
95
 
87
96
  export const signedLEB128_length = n => {
97
+ if (n === Infinity) return signedLEB128_length(2147483647);
98
+ if (n === -Infinity) return signedLEB128_length(-2147483648);
99
+
88
100
  if (n >= -64 && n <= 63) return 1;
89
101
  if (n >= -8192 && n <= 8191) return 2;
90
102
  if (n >= -1048576 && n <= 1048575) return 3;
@@ -201,6 +213,9 @@ export const read_ieee754_binary64 = buffer => new Float64Array(new Uint8Array(b
201
213
 
202
214
  // into funcs append to a given existing buffer instead of creating our own for perf
203
215
  export const signedLEB128_into = (n, buffer) => {
216
+ if (n === Infinity) return signedLEB128_into(2147483647, buffer);
217
+ if (n === -Infinity) return signedLEB128_into(-2147483648, buffer);
218
+
204
219
  n |= 0;
205
220
 
206
221
  // just input for small numbers (for perf as common)
@@ -224,6 +239,9 @@ export const signedLEB128_into = (n, buffer) => {
224
239
  };
225
240
 
226
241
  export const unsignedLEB128_into = (n, buffer) => {
242
+ if (n === Infinity) return unsignedLEB128_into(4294967295, buffer);
243
+ if (n === -Infinity) return unsignedLEB128_into(0, buffer);
244
+
227
245
  n |= 0;
228
246
 
229
247
  // just input for small numbers (for perf as common)
@@ -46,31 +46,6 @@ export const operatorOpcode = {
46
46
  ]
47
47
  },
48
48
 
49
- i64: {
50
- '+': Opcodes.i64_add,
51
- '-': Opcodes.i64_sub,
52
- '*': Opcodes.i64_mul,
53
- '/': Opcodes.i64_div_s,
54
- '%': Opcodes.i64_rem_s,
55
-
56
- '&': Opcodes.i64_and,
57
- '|': Opcodes.i64_or,
58
- '^': Opcodes.i64_xor,
59
- '<<': Opcodes.i64_shl,
60
- '>>': Opcodes.i64_shr_s,
61
- '>>>': Opcodes.i64_shr_u,
62
-
63
- '==': Opcodes.i64_eq,
64
- '===': Opcodes.i64_eq,
65
- '!=': Opcodes.i64_ne,
66
- '!==': Opcodes.i64_ne,
67
-
68
- '>': Opcodes.i64_gt_s,
69
- '>=': Opcodes.i64_ge_s,
70
- '<': Opcodes.i64_lt_s,
71
- '<=': Opcodes.i64_le_s
72
- },
73
-
74
49
  f64: {
75
50
  '+': Opcodes.f64_add,
76
51
  '-': Opcodes.f64_sub,
package/compiler/opt.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Opcodes, Valtype } from './wasmSpec.js';
2
- import { number, read_signedLEB128 } from './encoding.js';
2
+ import { number } from './encoding.js';
3
3
  import { log } from './log.js';
4
4
  import './prefs.js';
5
5
 
@@ -177,7 +177,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
177
177
  // -->
178
178
  // i32.const 0
179
179
 
180
- wasm[i - 1] = number(valtype === 'f64' ? lastInst[1] : read_signedLEB128(lastInst.slice(1)), Valtype.i32); // f64.const -> i32.const
180
+ wasm[i - 1] = number(lastInst[1], Valtype.i32); // f64.const -> i32.const
181
181
 
182
182
  wasm.splice(i, 1); // remove this inst
183
183
  i--;
@@ -192,7 +192,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
192
192
  // -->
193
193
  // f64.const 0
194
194
 
195
- wasm[i - 1] = number(read_signedLEB128(lastInst.slice(1))); // i32.const -> f64.const
195
+ wasm[i - 1] = number(lastInst[1], Valtype.f64); // i32.const -> f64.const
196
196
 
197
197
  wasm.splice(i, 1); // remove this inst
198
198
  i--;
@@ -215,18 +215,18 @@ export default (funcs, globals, pages, tags, exceptions) => {
215
215
  continue;
216
216
  }
217
217
 
218
- if (false && i === wasm.length - 1 && inst[0] === Opcodes.return) {
219
- // replace final return, end -> end (wasm has implicit return)
220
- // return
221
- // end
222
- // -->
223
- // end
224
-
225
- wasm.splice(i, 1); // remove this inst (return)
226
- i--;
227
- // if (Prefs.optLog) log('opt', `removed redundant return at end`);
228
- continue;
229
- }
218
+ // if (i === wasm.length - 1 && inst[0] === Opcodes.return) {
219
+ // // replace final return, end -> end (wasm has implicit return)
220
+ // // return
221
+ // // end
222
+ // // -->
223
+ // // end
224
+
225
+ // wasm.splice(i, 1); // remove this inst (return)
226
+ // i--;
227
+ // // if (Prefs.optLog) log('opt', `removed redundant return at end`);
228
+ // continue;
229
+ // }
230
230
 
231
231
  // remove unneeded before get with update exprs (n++, etc) when value is unused
232
232
  if (i < wasm.length - 4 && lastInst[1] === inst[1] && lastInst[0] === Opcodes.local_get && inst[0] === Opcodes.local_get && wasm[i + 1][0] === Opcodes.const && [Opcodes.add, Opcodes.sub].includes(wasm[i + 2][0]) && wasm[i + 3][0] === Opcodes.local_set && wasm[i + 3][1] === inst[1] && (wasm[i + 4][0] === Opcodes.drop || wasm[i + 4][0] === Opcodes.br)) {
@@ -176,7 +176,7 @@ const compile = async (file, _funcs) => {
176
176
  x.usesTag = true;
177
177
  let id;
178
178
  if (y[0] === Opcodes.i32_const && n[1] === 0) {
179
- id = read_signedLEB128(y.slice(1));
179
+ id = y[1];
180
180
  wasm[i] = [ 'throw', exceptions[id].constructor, exceptions[id].message ];
181
181
 
182
182
  // remove throw inst
@@ -237,14 +237,14 @@ 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) => {
244
244
  if (Number.isNaN(v) || v === Infinity || v === -Infinity) return v.toString();
245
245
  return v;
246
246
  })
247
- .replace(/\["alloc","(.*?)",(.*?)\]/g, (_, reason, valtype) => `number(allocPage(_,'${reason}'),${valtype})`)
247
+ .replace(/\["alloc","(.*?)",(.*?)\]/g, (_, reason, valtype) => `[${valtype === Valtype.i32 ? Opcodes.i32_const : Opcodes.f64_const},allocPage(_,'${reason}')]`)
248
248
  .replace(/\["global",(.*?),"(.*?)",(.*?)\]/g, (_, opcode, name, valtype) => `...glbl(${opcode},'${name}',${valtype})`)
249
249
  .replace(/\"local","(.*?)",(.*?)\]/g, (_, name, valtype) => `loc('${name}',${valtype})]`)
250
250
  .replace(/\[16,"(.*?)"]/g, (_, name) => `[16,builtin('${name}')]`)
@@ -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/compiler/wrap.js CHANGED
@@ -586,7 +586,10 @@ export default (source, module = undefined, print = str => process.stdout.write(
586
586
  }
587
587
 
588
588
  times.push(performance.now() - t2);
589
- if (Prefs.profileCompiler && !globalThis.onProgress) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
589
+ if (Prefs.profileCompiler) {
590
+ if (globalThis.onProgress) globalThis.onProgress('instantiated', times[1]);
591
+ else console.log(`instantiated in ${times[1].toFixed(2)}ms`);
592
+ }
590
593
 
591
594
  const exports = {};
592
595
  const rawValues = Prefs.d;