porffor 0.22.4 → 0.22.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.
@@ -269,6 +269,51 @@ local.set ${err}`;
269
269
  0, 12);
270
270
  };
271
271
 
272
+ export const __Porffor_object_delete = (_this: object, key: any): boolean => {
273
+ const entryPtr: i32 = __Porffor_object_lookup(_this, key);
274
+ if (entryPtr == -1) {
275
+ // not found, stop
276
+ return true;
277
+ }
278
+
279
+ const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
280
+ if (!(tail & 0b0010)) {
281
+ // not configurable
282
+ // todo: throw in strict mode
283
+ return false;
284
+ }
285
+
286
+ const ind: i32 = (entryPtr - Porffor.wasm`local.get ${_this}`) / 14;
287
+
288
+ // decrement size
289
+ let size: i32 = Porffor.wasm.i32.load(_this, 0, 0);
290
+ Porffor.wasm.i32.store(_this, --size, 0, 0);
291
+
292
+ if (size > ind) {
293
+ // offset all elements after by -1 ind
294
+ Porffor.wasm`
295
+ ;; dst = entryPtr
296
+ local.get ${entryPtr}
297
+
298
+ ;; src = entryPtr + 14 (+ 1 entry)
299
+ local.get ${entryPtr}
300
+ i32.const 14
301
+ i32.add
302
+
303
+ ;; size = (size - ind) * 14
304
+ local.get ${size}
305
+ local.get ${ind}
306
+ i32.sub
307
+ i32.const 14
308
+ i32.mul
309
+
310
+ memory.copy 0 0`;
311
+ }
312
+
313
+ return true;
314
+ };
315
+
316
+
272
317
  export const __Porffor_object_isEnumerable = (entryPtr: i32): boolean => {
273
318
  const out: boolean = Porffor.wasm.i32.load8_u(entryPtr, 0, 12) & 0b0100;
274
319
  return out;
@@ -0,0 +1,34 @@
1
+ import type {} from './porffor.d.ts';
2
+
3
+ // todo: support receiver
4
+ export const __Reflect_get = (target: any, property: any) => {
5
+ if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
6
+
7
+ const p: any = ecma262.ToPropertyKey(property);
8
+
9
+ const t: i32 = Porffor.rawType(target);
10
+ if (t == Porffor.TYPES.object) {
11
+ return Porffor.object.get(target, p);
12
+ }
13
+
14
+ const keys: any[] = Object.keys(target);
15
+ const idx: i32 = __Array_prototype_indexOf(keys, p);
16
+ if (idx == -1) return undefined;
17
+
18
+ const vals: any[] = Object.values(target);
19
+ return vals[idx];
20
+ };
21
+
22
+ export const __Reflect_has = (target: any, property: any) => {
23
+ if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
24
+
25
+ const p: any = ecma262.ToPropertyKey(property);
26
+
27
+ const t: i32 = Porffor.rawType(target);
28
+ if (t == Porffor.TYPES.object) {
29
+ return Porffor.object.lookup(target, p) != -1;
30
+ }
31
+
32
+ const keys: any[] = Object.keys(target);
33
+ return __Array_prototype_includes(keys, p);
34
+ };
@@ -2843,6 +2843,15 @@ const generateVar = (scope, decl) => {
2843
2843
  return out;
2844
2844
  };
2845
2845
 
2846
+ const getMemberProperty = decl => {
2847
+ if (decl.computed) return decl.property;
2848
+
2849
+ return {
2850
+ type: 'Literal',
2851
+ value: decl.property.name
2852
+ };
2853
+ };
2854
+
2846
2855
  // todo: optimize this func for valueUnused
2847
2856
  const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2848
2857
  const { type, name } = decl.left;
@@ -2897,10 +2906,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2897
2906
  const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
2898
2907
 
2899
2908
  const object = decl.left.object;
2900
- const property = decl.left.computed ? decl.left.property : {
2901
- type: 'Literal',
2902
- value: decl.left.property.name
2903
- };
2909
+ const property = getMemberProperty(decl.left);
2904
2910
 
2905
2911
  // todo/perf: use i32 object (and prop?) locals
2906
2912
  const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj') ] ];
@@ -3249,6 +3255,25 @@ const generateUnary = (scope, decl) => {
3249
3255
  }
3250
3256
 
3251
3257
  case 'delete': {
3258
+ if (decl.argument.type === 'MemberExpression') {
3259
+ const object = decl.argument.object;
3260
+ const property = getMemberProperty(decl.argument);
3261
+
3262
+ return [
3263
+ ...generate(scope, object),
3264
+ Opcodes.i32_to_u,
3265
+ ...getNodeType(scope, object),
3266
+
3267
+ ...generate(scope, property),
3268
+ ...getNodeType(scope, property),
3269
+ ...toPropertyKey(scope, true),
3270
+
3271
+ [ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Porffor_object_delete').index) ],
3272
+ [ Opcodes.drop ],
3273
+ Opcodes.i32_from_u
3274
+ ];
3275
+ }
3276
+
3252
3277
  let toReturn = true, toGenerate = true;
3253
3278
 
3254
3279
  if (decl.argument.type === 'Identifier') {
@@ -3256,6 +3281,7 @@ const generateUnary = (scope, decl) => {
3256
3281
 
3257
3282
  // if ReferenceError (undeclared var), ignore and return true. otherwise false
3258
3283
  if (!out[1]) {
3284
+ // todo: throw in strict mode
3259
3285
  // exists
3260
3286
  toReturn = false;
3261
3287
  } else {
@@ -4654,20 +4680,29 @@ const generateMember = (scope, decl, _global, _name) => {
4654
4680
  return number(0);
4655
4681
  }
4656
4682
 
4683
+ const useTmp = !Prefs.lengthNoTmp;
4684
+ const tmp = useTmp && localTmp(scope, '#length_tmp', Valtype.i32);
4657
4685
  return [
4658
- ...out,
4659
- [ Opcodes.local_set, localTmp(scope, '#length_tmp', Valtype.i32) ],
4686
+ ...(useTmp ? [
4687
+ ...out,
4688
+ [ Opcodes.local_set, tmp ],
4689
+ ] : []),
4660
4690
 
4661
4691
  ...getNodeType(scope, decl.object),
4662
4692
  ...number(TYPE_FLAGS.length, Valtype.i32),
4663
4693
  [ Opcodes.i32_and ],
4664
4694
  [ Opcodes.if, valtypeBinary ],
4665
- [ Opcodes.local_get, localTmp(scope, '#length_tmp', Valtype.i32) ],
4695
+ ...(useTmp ? [ [ Opcodes.local_get, tmp ] ] : out),
4666
4696
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
4667
4697
  Opcodes.i32_from_u,
4668
4698
 
4669
4699
  ...setLastType(scope, TYPES.number),
4670
4700
  [ Opcodes.else ],
4701
+ ...(useTmp ? [] : [
4702
+ ...out,
4703
+ [ Opcodes.drop ]
4704
+ ]),
4705
+
4671
4706
  ...number(0),
4672
4707
  ...setLastType(scope, TYPES.undefined),
4673
4708
  [ Opcodes.end ]
@@ -4703,10 +4738,7 @@ const generateMember = (scope, decl, _global, _name) => {
4703
4738
  }
4704
4739
 
4705
4740
  const object = decl.object;
4706
- const property = decl.computed ? decl.property : {
4707
- type: 'Literal',
4708
- value: decl.property.name
4709
- };
4741
+ const property = getMemberProperty(decl);
4710
4742
 
4711
4743
  // todo/perf: use i32 object (and prop?) locals
4712
4744
  const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj') ] ];
@@ -56,6 +56,12 @@ export const BuiltinFuncs = function() {
56
56
  returns: [127,127], typedReturns: 1,
57
57
  locals: [127,127,127,127,127,127,127,127], localNames: ["_this","_this#type","key","key#type","value","value#type","flags","flags#type","entryPtr","#last_type","#logicinner_tmp","#typeswitch_tmp","size","tail","err","logictmp"],
58
58
  };
59
+ this.__Porffor_object_delete = {
60
+ wasm: (scope, {builtin}) => [[32,0],[65,7],[32,2],[32,3],[16, ...builtin('__Porffor_object_lookup')],[26],[34,4],[65,127],[70],[4,64],[65,1],[65,2],[15],[11],[32,4],[47,0,12],[34,6],[65,2],[113],[69],[4,64],[65,0],[65,2],[15],[11],[32,4],[32,0],[107],[65,14],[109],[33,7],[32,0],[40,0,0],[33,8],[32,0],[32,8],[65,1],[107],[34,8],[54,0,0],[32,8],[32,7],[74],[4,64],[32,4],[32,4],[65,14],[106],[32,8],[32,7],[107],[65,14],[108],[252,10,0,0],[11],[65,1],[65,2],[15]],
61
+ params: [127,127,127,127], typedParams: 1,
62
+ returns: [127,127], typedReturns: 1,
63
+ locals: [127,127,127,127,127], localNames: ["_this","_this#type","key","key#type","entryPtr","#last_type","tail","ind","size"],
64
+ };
59
65
  this.__Porffor_object_isEnumerable = {
60
66
  wasm: (scope, {}) => [[32,0],[45,0,12],[65,4],[113],[34,2],[65,2],[15]],
61
67
  params: [127,127], typedParams: 1,
@@ -1835,6 +1841,18 @@ export const BuiltinFuncs = function() {
1835
1841
  returns: [124,127], typedReturns: 1,
1836
1842
  locals: [], localNames: ["_this","_this#type"],
1837
1843
  };
1844
+ this.__Reflect_get = {
1845
+ wasm: (scope, {builtin,internalThrow}) => [[32,0],[252,2],[32,1],[16, ...builtin('__Porffor_object_isObject')],[33,4],[183],[33,5],[32,4],[33,6],[2,124],[32,6],[65,195,0],[70],[4,64,"TYPESWITCH|String"],[32,5],[252,3],[40,1,0],[69],[184],[12,1],[11],[32,6],[65,195,1],[70],[4,64,"TYPESWITCH|ByteString"],[32,5],[252,3],[40,1,0],[69],[184],[12,1],[11],[32,5],[68,0,0,0,0,0,0,0,0],[97],[184],[11,"TYPESWITCH_end"],[252,3],[4,64],...internalThrow(scope, 'TypeError', `Target is a non-object`),[11],[32,2],[32,3],[16, ...builtin('__ecma262_ToPropertyKey')],[33,8],[33,7],[32,0],[32,1],[16, ...builtin('__Porffor_rawType')],[34,9],[68,0,0,0,0,0,0,28,64],[97],[4,64],[32,0],[252,2],[32,1],[32,7],[252,2],[32,8],[16, ...builtin('__Porffor_object_get')],[34,4],[15],[11],[32,0],[32,1],[16, ...builtin('__Object_keys')],[26],[34,10],[65,208,0],[32,7],[32,8],[68,0,0,0,0,0,0,0,0],[65,128,1],[16, ...builtin('__Array_prototype_indexOf')],[26],[34,11],[68,0,0,0,0,0,0,240,191],[97],[4,64],[68,0,0,0,0,0,0,0,0],[65,128,1],[15],[11],[32,0],[32,1],[16, ...builtin('__Object_values')],[26],[34,12],[33,13],[32,11],[34,14],[252,3],[65,9],[108],[32,13],[252,3],[106],[34,15],[43,0,4],[32,15],[45,0,12],[34,4],[15]],
1846
+ params: [124,127,124,127], typedParams: 1,
1847
+ returns: [124,127], typedReturns: 1,
1848
+ locals: [127,124,127,124,127,124,124,124,124,124,124,127,127], localNames: ["target","target#type","property","property#type","#last_type","#logicinner_tmp","#typeswitch_tmp","p","p#type","t","keys","idx","vals","#member_obj","#member_prop","#loadArray_offset","#swap"],
1849
+ };
1850
+ this.__Reflect_has = {
1851
+ wasm: (scope, {builtin,internalThrow}) => [[32,0],[252,2],[32,1],[16, ...builtin('__Porffor_object_isObject')],[33,4],[183],[33,5],[32,4],[33,6],[2,124],[32,6],[65,195,0],[70],[4,64,"TYPESWITCH|String"],[32,5],[252,3],[40,1,0],[69],[184],[12,1],[11],[32,6],[65,195,1],[70],[4,64,"TYPESWITCH|ByteString"],[32,5],[252,3],[40,1,0],[69],[184],[12,1],[11],[32,5],[68,0,0,0,0,0,0,0,0],[97],[184],[11,"TYPESWITCH_end"],[252,3],[4,64],...internalThrow(scope, 'TypeError', `Target is a non-object`),[11],[32,2],[32,3],[16, ...builtin('__ecma262_ToPropertyKey')],[33,8],[33,7],[32,0],[32,1],[16, ...builtin('__Porffor_rawType')],[34,9],[68,0,0,0,0,0,0,28,64],[97],[4,64],[32,0],[252,2],[32,1],[32,7],[252,2],[32,8],[16, ...builtin('__Porffor_object_lookup')],[33,4],[183],[68,0,0,0,0,0,0,240,191],[98],[184],[65,2],[15],[11],[32,0],[32,1],[16, ...builtin('__Object_keys')],[26],[34,10],[65,208,0],[32,7],[32,8],[68,0,0,0,0,0,0,0,0],[65,128,1],[16, ...builtin('__Array_prototype_includes')],[34,4],[15]],
1852
+ params: [124,127,124,127], typedParams: 1,
1853
+ returns: [124,127], typedReturns: 1,
1854
+ locals: [127,124,127,124,127,124,124], localNames: ["target","target#type","property","property#type","#last_type","#logicinner_tmp","#typeswitch_tmp","p","p#type","t","keys"],
1855
+ };
1838
1856
  this.__Porffor_set_read = {
1839
1857
  wasm: (scope, {}) => [[32,2],[252,3],[65,9],[108],[32,0],[252,3],[106],[34,4],[43,0,4],[32,4],[45,0,12],[15]],
1840
1858
  params: [124,127,124,127], typedParams: 1,
package/compiler/havoc.js CHANGED
@@ -90,4 +90,29 @@ export const f64ToI32s = (func, targets) => {
90
90
  }
91
91
  }
92
92
  }
93
+ };
94
+
95
+ export const withLocalDomains = (func, targets, domains) => {
96
+ const { wasm } = func;
97
+
98
+ // update wasm
99
+ for (let i = 0; i < wasm.length; i++) {
100
+ const op = wasm[i];
101
+ const opcode = op[0];
102
+ const idx = op[1];
103
+
104
+ let target;
105
+ if ((opcode === Opcodes.local_get || opcode === Opcodes.local_tee) &&
106
+ (target = targets.indexOf(idx)) !== -1) {
107
+ const n1 = wasm[i + 1];
108
+ if (n1?.[0] !== Opcodes.i32_const && n1?.[0] !== Opcodes.f64_const) continue;
109
+
110
+ const n2 = wasm[i + 2];
111
+ if (!n2?.[0]) continue;
112
+
113
+ switch (n2[0]) {
114
+
115
+ }
116
+ }
117
+ }
93
118
  };
package/compiler/pgo.js CHANGED
@@ -10,8 +10,13 @@ export const setup = () => {
10
10
  importedFuncs[importedFuncs.profile2].params = [ Valtype.i32, valtypeBinary ];
11
11
 
12
12
  // enable these prefs by default for pgo
13
- Prefs.typeswitchUniqueTmp = Prefs.typeswitchUniqueTmp === false ? false : true;
14
- Prefs.cyclone = Prefs.cyclone === false ? false : true;
13
+ for (const x of [
14
+ 'typeswitchUniqueTmp', // use unique tmps for typeswitches
15
+ 'lengthNoTmp', // use duplicated inline code instead of tmp for .length
16
+ 'cyclone', // enable cyclone pre-evaler
17
+ ]) {
18
+ Prefs[x] = Prefs[x] === false ? false : true;
19
+ }
15
20
  };
16
21
 
17
22
  export const run = obj => {
@@ -158,8 +163,24 @@ export const run = obj => {
158
163
  return true;
159
164
  });
160
165
 
166
+ const domains = localData[i].map((x, j) => {
167
+ if (j < func.params.length) return false; // param
168
+ if (consistents[j] !== false) return false; // already consistent
169
+ if (x.length < 2) return false; // <2 samples
170
+
171
+ let min = Infinity, max = -Infinity;
172
+ for (const y of x) {
173
+ if (y < min) min = y;
174
+ if (y > max) max = y;
175
+ }
176
+
177
+ counts[2]++;
178
+ return [ min, max ];
179
+ });
180
+
161
181
  func.consistents = consistents;
162
182
  func.integerOnlyF64s = integerOnlyF64s;
183
+ func.domains = domains;
163
184
 
164
185
  log += ` ${func.name}: identified ${counts[0]}/${total} locals as consistent${Prefs.verbosePgo ? ':' : ''}\n`;
165
186
  if (Prefs.verbosePgo) {
@@ -174,12 +195,20 @@ export const run = obj => {
174
195
  if (localValues[j].type !== Valtype.f64) continue;
175
196
  log += ` ${integerOnlyF64s[j] ? '\u001b[92m' : '\u001b[91m'}${localKeys[j]}\u001b[0m\n`;
176
197
  }
198
+ }
199
+
200
+ log += ` ${func.name}: identified ${counts[2]}/${total} local non-consistent domains${Prefs.verbosePgo ? ':' : ''}\n`;
201
+ if (Prefs.verbosePgo) {
202
+ for (let j = func.params.length; j < localData[i].length; j++) {
203
+ if (domains[j] === false) continue;
204
+ log += ` ${domains[j] !== false ? '\u001b[92m' : '\u001b[91m'}${localKeys[j]}\u001b[0m: ${domains[j] !== false ? `${domains[j][0]} ≤ x ≤ ${domains[j][1]}` : ''}\n`;
205
+ }
177
206
 
178
207
  log += '\n';
179
208
  }
180
209
  }
181
210
 
182
- time(2, 'processed PGO data' + log);
211
+ time(2, 'processed PGO data\n' + log);
183
212
  time(3, 'optimizing using PGO data...');
184
213
 
185
214
  log = '';
@@ -216,5 +245,5 @@ export const run = obj => {
216
245
  if (targets.length > 0) Havoc.localsToConsts(wasmFunc, targets, consts, { localKeys: x.localKeys });
217
246
  }
218
247
 
219
- time(3, 'optimized using PGO data' + log);
248
+ time(3, 'optimized using PGO data\n' + log);
220
249
  };
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.22.4+619e50acb",
4
+ "version": "0.22.6+e32079e96",
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.22.4+619e50acb';
3
+ globalThis.version = '0.22.6+e32079e96';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {