porffor 0.42.4 → 0.42.6

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.
@@ -121,20 +121,19 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
121
121
 
122
122
  const nameSection = Prefs.d ? customSection('name', encodeNames(funcs)) : [];
123
123
 
124
- const directFuncs = funcs.filter(x => !x.indirect);
124
+ const indirectFuncs = funcs.filter(x => x.indirect);
125
125
  const tableSection = !funcs.table ? [] : createSection(
126
126
  Section.table,
127
- encodeVector([ [ Reftype.funcref, 0x00, ...unsignedLEB128(directFuncs.length) ] ])
127
+ encodeVector([ [ Reftype.funcref, 0x00, ...unsignedLEB128(indirectFuncs.length) ] ])
128
128
  );
129
129
  time('table section');
130
130
 
131
- const emptyWrapperFunc = funcs.find(x => x.name === '#indirect#empty');
132
131
  const elementSection = !funcs.table ? [] : createSection(
133
132
  Section.element,
134
133
  encodeVector([ [
135
134
  0x00,
136
135
  Opcodes.i32_const, 0, Opcodes.end,
137
- ...encodeVector(directFuncs.map(x => unsignedLEB128((x.wrapperFunc ?? emptyWrapperFunc ?? x).asmIndex)))
136
+ ...encodeVector(indirectFuncs.map(x => unsignedLEB128(x.asmIndex)))
138
137
  ] ])
139
138
  );
140
139
  time('element section');
@@ -147,8 +146,8 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
147
146
 
148
147
  // generate func lut data
149
148
  const bytes = [];
150
- for (let i = 0; i < directFuncs.length; i++) {
151
- const func = directFuncs[i];
149
+ for (let i = 0; i < indirectFuncs.length; i++) {
150
+ const func = indirectFuncs[i].wrapperOf;
152
151
  let name = func.name;
153
152
 
154
153
  // userland exposed .length
@@ -18,14 +18,14 @@ export default function({ builtinFuncs }, Prefs) {
18
18
  locals: [],
19
19
  returns: [ Valtype.i32 ],
20
20
  returnType: TYPES.object,
21
- wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin, glbl }) => {
21
+ wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin, funcRef, glbl }) => {
22
22
  if (globalThis.precompile) return [ [ 'get object', name ] ];
23
23
 
24
24
  // todo/perf: precompute bytes here instead of calling real funcs if we really care about perf later
25
25
 
26
26
  let ptr;
27
27
  if (existingFunc) {
28
- ptr = builtin(name, true);
28
+ ptr = funcRef(name)[0][1];
29
29
  } else {
30
30
  ptr = allocPage(scope, `builtin object: ${name}`);
31
31
  }
@@ -86,20 +86,11 @@ export default function({ builtinFuncs }, Prefs) {
86
86
  }
87
87
  };
88
88
 
89
- if (existingFunc) {
90
- this[name] = (scope, { builtin, funcRef }) => [
91
- [ Opcodes.call, builtin('#get_' + name) ],
92
- [ Opcodes.drop ],
93
- ...funcRef(name)
94
- ];
95
- this[name].type = TYPES.function;
96
- } else {
97
- this[name] = (scope, { builtin }) => [
98
- [ Opcodes.call, builtin('#get_' + name) ],
99
- Opcodes.i32_from_u
100
- ];
101
- this[name].type = TYPES.object;
102
- }
89
+ this[name] = (scope, { builtin }) => [
90
+ [ Opcodes.call, builtin('#get_' + name) ],
91
+ Opcodes.i32_from_u
92
+ ];
93
+ this[name].type = existingFunc ? TYPES.function : TYPES.object;
103
94
 
104
95
  for (const x in props) {
105
96
  const d = props[x];
@@ -79,7 +79,12 @@ const funcRef = func => {
79
79
  ],
80
80
  constr: true,
81
81
  internal: true,
82
- indirect: true
82
+ indirect: true,
83
+ wrapperOf: {
84
+ name: '',
85
+ jsLength: 0
86
+ },
87
+ indirectIndex: indirectFuncs.length
83
88
  };
84
89
 
85
90
  // check not being constructed
@@ -91,6 +96,8 @@ const funcRef = func => {
91
96
  [ Opcodes.end ]
92
97
  );
93
98
 
99
+ // have empty func as indirect funcs 0 and 1
100
+ indirectFuncs.push(emptyFunc);
94
101
  indirectFuncs.push(emptyFunc);
95
102
  }
96
103
 
@@ -142,7 +149,9 @@ const funcRef = func => {
142
149
  wasm,
143
150
  constr: true,
144
151
  internal: true,
145
- indirect: true
152
+ indirect: true,
153
+ wrapperOf: func,
154
+ indirectIndex: indirectFuncs.length
146
155
  };
147
156
 
148
157
  indirectFuncs.push(wrapperFunc);
@@ -163,7 +172,7 @@ const funcRef = func => {
163
172
  }
164
173
 
165
174
  return [
166
- [ Opcodes.const, func.index - importedFuncs.length ]
175
+ [ Opcodes.const, func.wrapperFunc.indirectIndex ]
167
176
  ];
168
177
  };
169
178
 
@@ -3680,6 +3689,8 @@ const ifIdentifierErrors = (scope, decl) => {
3680
3689
  const generateUnary = (scope, decl) => {
3681
3690
  switch (decl.operator) {
3682
3691
  case '+':
3692
+ // todo/opt: skip ToNumber if already known number type
3693
+
3683
3694
  // 13.5.4 Unary + Operator, 13.5.4.1 Runtime Semantics: Evaluation
3684
3695
  // https://tc39.es/ecma262/#sec-unary-plus-operator-runtime-semantics-evaluation
3685
3696
  // 1. Let expr be ? Evaluation of UnaryExpression.
@@ -3812,33 +3823,62 @@ const generateUnary = (scope, decl) => {
3812
3823
 
3813
3824
  const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
3814
3825
  const { name } = decl.argument;
3815
-
3816
3826
  const [ local, isGlobal ] = lookupName(scope, name);
3827
+ if (local != null) {
3828
+ // fast path: just a local
3829
+ // todo: not as compliant as slow path (non numbers)
3830
+ const idx = local.idx;
3831
+ const out = [];
3832
+
3833
+ out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3834
+ if (!decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3835
+
3836
+ switch (decl.operator) {
3837
+ case '++':
3838
+ out.push(...number(1), [ Opcodes.add ]);
3839
+ break;
3817
3840
 
3818
- if (local === undefined) {
3819
- return todo(scope, `update expression with undefined variable`, true);
3820
- }
3821
-
3822
- const idx = local.idx;
3823
- const out = [];
3824
-
3825
- out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3826
- if (!decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3841
+ case '--':
3842
+ out.push(...number(1), [ Opcodes.sub ]);
3843
+ break;
3844
+ }
3827
3845
 
3828
- switch (decl.operator) {
3829
- case '++':
3830
- out.push(...number(1), [ Opcodes.add ]);
3831
- break;
3846
+ out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
3847
+ if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3832
3848
 
3833
- case '--':
3834
- out.push(...number(1), [ Opcodes.sub ]);
3835
- break;
3849
+ return out;
3836
3850
  }
3837
3851
 
3838
- out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
3839
- if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3852
+ // ++x: tmp = +x; x = tmp + 1
3853
+ // x++: tmp = +x; x = tmp + 1; tmp
3854
+ const tmp = localTmp(scope, '#updatetmp');
3855
+ addVarMetadata(scope, '#updatetmp', false, { type: TYPES.number });
3840
3856
 
3841
- return out;
3857
+ return [
3858
+ // tmp = +x
3859
+ // if postfix, tee to keep on stack as return value
3860
+ ...generate(scope, {
3861
+ type: 'UnaryExpression',
3862
+ operator: '+',
3863
+ prefix: true,
3864
+ argument: decl.argument
3865
+ }),
3866
+ [ decl.prefix ? Opcodes.local_set : Opcodes.local_tee, tmp ],
3867
+
3868
+ // x = tmp + 1
3869
+ ...generate(scope, {
3870
+ type: 'AssignmentExpression',
3871
+ operator: '=',
3872
+ left: decl.argument,
3873
+ right: {
3874
+ type: 'BinaryExpression',
3875
+ operator: decl.operator[0],
3876
+ left: { type: 'Identifier', name: '#updatetmp' },
3877
+ right: { type: 'Literal', value: 1 }
3878
+ }
3879
+ }),
3880
+ ...(decl.prefix ? [] : [ [ Opcodes.drop ] ])
3881
+ ];
3842
3882
  };
3843
3883
 
3844
3884
  const generateIf = (scope, decl) => {
package/compiler/wrap.js CHANGED
@@ -132,8 +132,7 @@ ${flags & 0b0001 ? ` get func idx: ${get}
132
132
  if (value < 0) {
133
133
  func = importedFuncs[value + importedFuncs.length];
134
134
  } else {
135
- value += importedFuncs.length;
136
- func = funcs.find(x => x.index === value);
135
+ func = funcs.find(x => x.wrapperFunc?.indirectIndex === value);
137
136
  }
138
137
 
139
138
  if (!func) return function () {};
@@ -321,7 +320,7 @@ ${flags & 0b0001 ? ` get func idx: ${get}
321
320
  const err = new (globalThis[TYPE_NAMES[type]] ?? Error)(obj.message);
322
321
 
323
322
  err.name = obj.name;
324
- err.stack = `${TYPE_NAMES[type]}: ${obj.message}`;
323
+ err.stack = `${obj.name}: ${obj.message}`;
325
324
  return err;
326
325
  }
327
326
 
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.42.4+82c4bc5cf",
4
+ "version": "0.42.6+d8f9d3f11",
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.42.4+82c4bc5cf';
3
+ globalThis.version = '0.42.6+d8f9d3f11';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {