porffor 0.22.5 → 0.22.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.
- package/compiler/assemble.js +21 -2
- package/compiler/builtins/_internal_object.ts +45 -2
- package/compiler/builtins/reflect.ts +132 -0
- package/compiler/codegen.js +46 -15
- package/compiler/generated_builtins.js +70 -11
- package/compiler/havoc.js +25 -0
- package/compiler/pgo.js +33 -4
- package/package.json +1 -1
- package/runner/index.js +1 -1
- package/tmp.txt +423 -0
package/compiler/assemble.js
CHANGED
@@ -230,7 +230,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
230
230
|
// };
|
231
231
|
// }
|
232
232
|
|
233
|
-
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
|
233
|
+
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, ...unsignedLEB128(x.index) ]);
|
234
234
|
|
235
235
|
if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
|
236
236
|
if (optLevel === 0) pages.set('O0 precaution', 0);
|
@@ -276,7 +276,26 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
|
|
276
276
|
|
277
277
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
278
278
|
|
279
|
-
|
279
|
+
// todo: move const, call transforms here too?
|
280
|
+
|
281
|
+
const wasm = [];
|
282
|
+
for (let i = 0; i < x.wasm.length; i++) {
|
283
|
+
let o = x.wasm[i];
|
284
|
+
|
285
|
+
if (
|
286
|
+
(o[0] === Opcodes.local_get || o[0] === Opcodes.local_set || o[0] === Opcodes.local_tee || o[0] === Opcodes.global_get || o[0] === Opcodes.global_set) &&
|
287
|
+
o[1] > 127
|
288
|
+
) {
|
289
|
+
const n = o[1];
|
290
|
+
o = [...o];
|
291
|
+
o.pop();
|
292
|
+
unsignedLEB128_into(n, o);
|
293
|
+
}
|
294
|
+
|
295
|
+
wasm.push(...o);
|
296
|
+
}
|
297
|
+
|
298
|
+
return encodeVector([ ...encodeVector(localDecl), ...wasm.flat().filter(x => x != null && x <= 0xff), Opcodes.end ]);
|
280
299
|
}))
|
281
300
|
);
|
282
301
|
|
@@ -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;
|
@@ -280,7 +325,6 @@ export const __Porffor_object_isObject = (arg: any): boolean => {
|
|
280
325
|
return Porffor.fastAnd(
|
281
326
|
arg != 0, // null
|
282
327
|
t > 0x05,
|
283
|
-
t != Porffor.TYPES.undefined,
|
284
328
|
t != Porffor.TYPES.string,
|
285
329
|
t != Porffor.TYPES.bytestring,
|
286
330
|
);
|
@@ -291,7 +335,6 @@ export const __Porffor_object_isObjectOrSymbol = (arg: any): boolean => {
|
|
291
335
|
return Porffor.fastAnd(
|
292
336
|
arg != 0, // null
|
293
337
|
t > 0x04,
|
294
|
-
t != Porffor.TYPES.undefined,
|
295
338
|
t != Porffor.TYPES.string,
|
296
339
|
t != Porffor.TYPES.bytestring,
|
297
340
|
);
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
// todo: support receiver
|
4
|
+
export const __Reflect_get = (target: any, prop: any) => {
|
5
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
6
|
+
|
7
|
+
return target[prop];
|
8
|
+
};
|
9
|
+
|
10
|
+
// todo: support receiver
|
11
|
+
export const __Reflect_set = (target: any, prop: any, value: any) => {
|
12
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
13
|
+
|
14
|
+
try {
|
15
|
+
target[prop] = value;
|
16
|
+
return true;
|
17
|
+
} catch {
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
export const __Reflect_has = (target: any, prop: any) => {
|
23
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
24
|
+
|
25
|
+
return prop in target;
|
26
|
+
};
|
27
|
+
|
28
|
+
export const __Reflect_defineProperty = (target: any, prop: any, descriptor: any) => {
|
29
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
30
|
+
if (!Porffor.object.isObject(descriptor)) throw new TypeError('Descriptor is a non-object');
|
31
|
+
|
32
|
+
try {
|
33
|
+
Object.defineProperty(target, prop, descriptor);
|
34
|
+
return true;
|
35
|
+
} catch {
|
36
|
+
return false;
|
37
|
+
}
|
38
|
+
};
|
39
|
+
|
40
|
+
export const __Reflect_deleteProperty = (target: any, prop: any) => {
|
41
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
42
|
+
|
43
|
+
return delete target[prop];
|
44
|
+
};
|
45
|
+
|
46
|
+
export const __Reflect_getOwnPropertyDescriptor = (target: any, prop: any) => {
|
47
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
48
|
+
|
49
|
+
return Object.getOwnPropertyDescriptor(target, prop);
|
50
|
+
};
|
51
|
+
|
52
|
+
export const __Reflect_isExtensible = (target: any) => {
|
53
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
54
|
+
|
55
|
+
return Object.isExtensible(target);
|
56
|
+
};
|
57
|
+
|
58
|
+
export const __Reflect_preventExtensions = (target: any) => {
|
59
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
60
|
+
|
61
|
+
try {
|
62
|
+
Object.preventExtensions(target);
|
63
|
+
return true;
|
64
|
+
} catch {
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
export const __Reflect_ownKeys = (target: any) => {
|
70
|
+
if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
|
71
|
+
|
72
|
+
const out: any[] = Porffor.allocate();
|
73
|
+
|
74
|
+
const t: i32 = Porffor.rawType(target);
|
75
|
+
if (t == Porffor.TYPES.object) {
|
76
|
+
let ptr: i32 = Porffor.wasm`local.get ${target}` + 5;
|
77
|
+
const endPtr: i32 = ptr + Porffor.wasm.i32.load(target, 0, 0) * 14;
|
78
|
+
|
79
|
+
let i: i32 = 0;
|
80
|
+
for (; ptr < endPtr; ptr += 14) {
|
81
|
+
let key: any;
|
82
|
+
Porffor.wasm`local raw i32
|
83
|
+
local msb i32
|
84
|
+
local.get ${ptr}
|
85
|
+
i32.to_u
|
86
|
+
i32.load 0 0
|
87
|
+
local.set raw
|
88
|
+
|
89
|
+
local.get raw
|
90
|
+
i32.const 30
|
91
|
+
i32.shr_u
|
92
|
+
local.tee msb
|
93
|
+
if 127
|
94
|
+
i32.const 5 ;; symbol
|
95
|
+
i32.const 67 ;; string
|
96
|
+
local.get msb
|
97
|
+
i32.const 3
|
98
|
+
i32.eq
|
99
|
+
select
|
100
|
+
local.set ${key+1}
|
101
|
+
|
102
|
+
local.get raw
|
103
|
+
i32.const 1073741823
|
104
|
+
i32.and ;; unset 2 MSBs
|
105
|
+
else
|
106
|
+
i32.const 195
|
107
|
+
local.set ${key+1}
|
108
|
+
|
109
|
+
local.get raw
|
110
|
+
end
|
111
|
+
i32.from_u
|
112
|
+
local.set ${key}`;
|
113
|
+
|
114
|
+
out[i++] = key;
|
115
|
+
}
|
116
|
+
|
117
|
+
out.length = i;
|
118
|
+
} else if (Porffor.fastOr(
|
119
|
+
t == Porffor.TYPES.array,
|
120
|
+
t == Porffor.TYPES.bytestring,
|
121
|
+
t == Porffor.TYPES.string
|
122
|
+
)) {
|
123
|
+
const len: i32 = target.length;
|
124
|
+
out.length = len;
|
125
|
+
|
126
|
+
for (let i: i32 = 0; i < len; i++) {
|
127
|
+
out[i] = __Number_prototype_toString(i);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
return out;
|
132
|
+
};
|
package/compiler/codegen.js
CHANGED
@@ -39,7 +39,7 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
39
39
|
const isFuncType = type =>
|
40
40
|
type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
41
41
|
const hasFuncWithName = name =>
|
42
|
-
Object.hasOwn(funcIndex, name)
|
42
|
+
Object.hasOwn(funcIndex, name) || Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) || Object.hasOwn(internalConstrs, name);
|
43
43
|
|
44
44
|
const astCache = new WeakMap();
|
45
45
|
const cacheAst = (decl, wasm) => {
|
@@ -164,6 +164,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
164
164
|
return cacheAst(decl, generateMember(scope, decl, global, name));
|
165
165
|
|
166
166
|
case 'ExportNamedDeclaration':
|
167
|
+
if (!decl.declaration) return todo(scope, 'unsupported export declaration');
|
168
|
+
|
167
169
|
const funcsBefore = funcs.map(x => x.name);
|
168
170
|
generate(scope, decl.declaration);
|
169
171
|
|
@@ -2835,14 +2837,20 @@ const generateVar = (scope, decl) => {
|
|
2835
2837
|
scope.globalInits[name] = newOut;
|
2836
2838
|
}
|
2837
2839
|
}
|
2838
|
-
|
2839
|
-
// hack: this follows spec properly but is mostly unneeded 😅
|
2840
|
-
// out.push(...setType(scope, name, x.init ? getNodeType(scope, x.init) : TYPES.undefined));
|
2841
2840
|
}
|
2842
2841
|
|
2843
2842
|
return out;
|
2844
2843
|
};
|
2845
2844
|
|
2845
|
+
const getMemberProperty = decl => {
|
2846
|
+
if (decl.computed) return decl.property;
|
2847
|
+
|
2848
|
+
return {
|
2849
|
+
type: 'Literal',
|
2850
|
+
value: decl.property.name
|
2851
|
+
};
|
2852
|
+
};
|
2853
|
+
|
2846
2854
|
// todo: optimize this func for valueUnused
|
2847
2855
|
const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
2848
2856
|
const { type, name } = decl.left;
|
@@ -2897,10 +2905,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2897
2905
|
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2898
2906
|
|
2899
2907
|
const object = decl.left.object;
|
2900
|
-
const property = decl.left
|
2901
|
-
type: 'Literal',
|
2902
|
-
value: decl.left.property.name
|
2903
|
-
};
|
2908
|
+
const property = getMemberProperty(decl.left);
|
2904
2909
|
|
2905
2910
|
// todo/perf: use i32 object (and prop?) locals
|
2906
2911
|
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj') ] ];
|
@@ -3249,6 +3254,25 @@ const generateUnary = (scope, decl) => {
|
|
3249
3254
|
}
|
3250
3255
|
|
3251
3256
|
case 'delete': {
|
3257
|
+
if (decl.argument.type === 'MemberExpression') {
|
3258
|
+
const object = decl.argument.object;
|
3259
|
+
const property = getMemberProperty(decl.argument);
|
3260
|
+
|
3261
|
+
return [
|
3262
|
+
...generate(scope, object),
|
3263
|
+
Opcodes.i32_to_u,
|
3264
|
+
...getNodeType(scope, object),
|
3265
|
+
|
3266
|
+
...generate(scope, property),
|
3267
|
+
...getNodeType(scope, property),
|
3268
|
+
...toPropertyKey(scope, true),
|
3269
|
+
|
3270
|
+
[ Opcodes.call, ...unsignedLEB128(includeBuiltin(scope, '__Porffor_object_delete').index) ],
|
3271
|
+
[ Opcodes.drop ],
|
3272
|
+
Opcodes.i32_from_u
|
3273
|
+
];
|
3274
|
+
}
|
3275
|
+
|
3252
3276
|
let toReturn = true, toGenerate = true;
|
3253
3277
|
|
3254
3278
|
if (decl.argument.type === 'Identifier') {
|
@@ -3256,6 +3280,7 @@ const generateUnary = (scope, decl) => {
|
|
3256
3280
|
|
3257
3281
|
// if ReferenceError (undeclared var), ignore and return true. otherwise false
|
3258
3282
|
if (!out[1]) {
|
3283
|
+
// todo: throw in strict mode
|
3259
3284
|
// exists
|
3260
3285
|
toReturn = false;
|
3261
3286
|
} else {
|
@@ -4654,20 +4679,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4654
4679
|
return number(0);
|
4655
4680
|
}
|
4656
4681
|
|
4682
|
+
const useTmp = !Prefs.lengthNoTmp;
|
4683
|
+
const tmp = useTmp && localTmp(scope, '#length_tmp', Valtype.i32);
|
4657
4684
|
return [
|
4658
|
-
...
|
4659
|
-
|
4685
|
+
...(useTmp ? [
|
4686
|
+
...out,
|
4687
|
+
[ Opcodes.local_set, tmp ],
|
4688
|
+
] : []),
|
4660
4689
|
|
4661
4690
|
...getNodeType(scope, decl.object),
|
4662
4691
|
...number(TYPE_FLAGS.length, Valtype.i32),
|
4663
4692
|
[ Opcodes.i32_and ],
|
4664
4693
|
[ Opcodes.if, valtypeBinary ],
|
4665
|
-
[ Opcodes.local_get,
|
4694
|
+
...(useTmp ? [ [ Opcodes.local_get, tmp ] ] : out),
|
4666
4695
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
4667
4696
|
Opcodes.i32_from_u,
|
4668
4697
|
|
4669
4698
|
...setLastType(scope, TYPES.number),
|
4670
4699
|
[ Opcodes.else ],
|
4700
|
+
...(useTmp ? [] : [
|
4701
|
+
...out,
|
4702
|
+
[ Opcodes.drop ]
|
4703
|
+
]),
|
4704
|
+
|
4671
4705
|
...number(0),
|
4672
4706
|
...setLastType(scope, TYPES.undefined),
|
4673
4707
|
[ Opcodes.end ]
|
@@ -4703,10 +4737,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4703
4737
|
}
|
4704
4738
|
|
4705
4739
|
const object = decl.object;
|
4706
|
-
const property = decl
|
4707
|
-
type: 'Literal',
|
4708
|
-
value: decl.property.name
|
4709
|
-
};
|
4740
|
+
const property = getMemberProperty(decl);
|
4710
4741
|
|
4711
4742
|
// todo/perf: use i32 object (and prop?) locals
|
4712
4743
|
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj') ] ];
|