porffor 0.2.0-3272f21 → 0.2.0-3aaa9b4
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/CONTRIBUTING.md +183 -0
- package/README.md +50 -35
- package/asur/index.js +1 -1
- package/compiler/assemble.js +1 -1
- package/compiler/builtins/annexb_string.js +1 -1
- package/compiler/builtins/annexb_string.ts +1 -1
- package/compiler/builtins/array.ts +1 -1
- package/compiler/builtins/base64.ts +1 -1
- package/compiler/builtins/crypto.ts +1 -1
- package/compiler/builtins/date.ts +549 -63
- package/compiler/builtins/escape.ts +1 -1
- package/compiler/builtins/int.ts +1 -1
- package/compiler/builtins/number.ts +1 -1
- package/compiler/builtins/porffor.d.ts +21 -4
- package/compiler/builtins/string.ts +1 -1
- package/compiler/builtins/tostring.ts +1 -1
- package/compiler/codegen.js +74 -38
- package/compiler/decompile.js +0 -1
- package/compiler/generated_builtins.js +266 -83
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +6 -1
- package/compiler/prefs.js +6 -5
- package/package.json +1 -1
- package/rhemyn/compile.js +42 -25
- package/rhemyn/parse.js +4 -5
- package/runner/index.js +41 -6
- package/runner/repl.js +2 -2
- package/runner/sizes.js +1 -1
@@ -7,23 +7,40 @@ type PorfforGlobal = {
|
|
7
7
|
wasm: {
|
8
8
|
(...args: any[]): any;
|
9
9
|
i32: {
|
10
|
-
or(a: i32, b: i32): i32;
|
11
|
-
|
12
10
|
load(pointer: i32, align: i32, offset: i32): i32;
|
13
11
|
store(pointer: i32, value: i32, align: i32, offset: i32): i32;
|
14
12
|
load8_u(pointer: i32, align: i32, offset: i32): i32;
|
15
13
|
store8(pointer: i32, value: i32, align: i32, offset: i32): i32;
|
16
14
|
load16_u(pointer: i32, align: i32, offset: i32): i32;
|
17
15
|
store16(pointer: i32, value: i32, align: i32, offset: i32): i32;
|
16
|
+
const(value: i32): i32;
|
17
|
+
}
|
18
|
+
|
19
|
+
f64: {
|
20
|
+
load(pointer: i32, align: i32, offset: i32): i32;
|
21
|
+
store(pointer: i32, value: f64, align: i32, offset: i32): f64;
|
18
22
|
}
|
19
23
|
}
|
20
24
|
|
21
|
-
// randomInt(): i32;
|
22
25
|
randomByte(): i32;
|
23
26
|
|
24
27
|
type(x: any): bytestring;
|
25
28
|
rawType(x: any): i32;
|
26
|
-
TYPES:
|
29
|
+
TYPES: {
|
30
|
+
number: i32;
|
31
|
+
boolean: i32;
|
32
|
+
string: i32;
|
33
|
+
undefined: i32;
|
34
|
+
object: i32;
|
35
|
+
function: i32;
|
36
|
+
symbol: i32;
|
37
|
+
bigint: i32;
|
38
|
+
|
39
|
+
_array: i32;
|
40
|
+
_regexp: i32;
|
41
|
+
_bytestring: i32;
|
42
|
+
_date: i32;
|
43
|
+
}
|
27
44
|
|
28
45
|
fastOr(...args: any): boolean;
|
29
46
|
fastAnd(...args: any): boolean;
|
package/compiler/codegen.js
CHANGED
@@ -201,7 +201,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
201
201
|
}
|
202
202
|
|
203
203
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
204
|
-
if (
|
204
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
205
205
|
|
206
206
|
if (!Array.isArray(inst)) inst = [ inst ];
|
207
207
|
const immediates = asm.slice(1).map(x => {
|
@@ -460,7 +460,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
460
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
461
461
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
462
462
|
|
463
|
-
if (assign) {
|
463
|
+
if (assign && Prefs.aotPointerOpt) {
|
464
464
|
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
465
465
|
|
466
466
|
return [
|
@@ -1646,18 +1646,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1646
1646
|
// megahack for /regex/.func()
|
1647
1647
|
const funcName = decl.callee.property.name;
|
1648
1648
|
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1649
|
-
const
|
1649
|
+
const regex = decl.callee.object.regex.pattern;
|
1650
|
+
const rhemynName = `regex_${funcName}_${regex}`;
|
1650
1651
|
|
1651
|
-
funcIndex[
|
1652
|
-
|
1652
|
+
if (!funcIndex[rhemynName]) {
|
1653
|
+
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1653
1654
|
|
1655
|
+
funcIndex[func.name] = func.index;
|
1656
|
+
funcs.push(func);
|
1657
|
+
}
|
1658
|
+
|
1659
|
+
const idx = funcIndex[rhemynName];
|
1654
1660
|
return [
|
1655
1661
|
// make string arg
|
1656
1662
|
...generate(scope, decl.arguments[0]),
|
1663
|
+
Opcodes.i32_to_u,
|
1664
|
+
...getNodeType(scope, decl.arguments[0]),
|
1657
1665
|
|
1658
1666
|
// call regex func
|
1659
|
-
Opcodes.
|
1660
|
-
[ Opcodes.call, func.index ],
|
1667
|
+
[ Opcodes.call, idx ],
|
1661
1668
|
Opcodes.i32_from_u,
|
1662
1669
|
|
1663
1670
|
...number(TYPES.boolean, Valtype.i32),
|
@@ -1820,20 +1827,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1820
1827
|
idx = funcIndex[name];
|
1821
1828
|
|
1822
1829
|
// infer arguments types from builtins params
|
1823
|
-
const func = funcs.find(x => x.name === name);
|
1824
|
-
for (let i = 0; i < decl.arguments.length; i++) {
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
}
|
1830
|
+
// const func = funcs.find(x => x.name === name);
|
1831
|
+
// for (let i = 0; i < decl.arguments.length; i++) {
|
1832
|
+
// const arg = decl.arguments[i];
|
1833
|
+
// if (!arg.name) continue;
|
1834
|
+
|
1835
|
+
// const local = scope.locals[arg.name];
|
1836
|
+
// if (!local) continue;
|
1837
|
+
|
1838
|
+
// local.type = func.params[i];
|
1839
|
+
// if (local.type === Valtype.v128) {
|
1840
|
+
// // specify vec subtype inferred from last vec type in function name
|
1841
|
+
// local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1842
|
+
// }
|
1843
|
+
// }
|
1837
1844
|
}
|
1838
1845
|
|
1839
1846
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1865,9 +1872,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1865
1872
|
|
1866
1873
|
// value
|
1867
1874
|
i32_const: { imms: 1, args: [], returns: 1 },
|
1868
|
-
|
1869
|
-
// a, b
|
1870
|
-
i32_or: { imms: 0, args: [ true, true ], returns: 1 },
|
1871
1875
|
};
|
1872
1876
|
|
1873
1877
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -2205,6 +2209,7 @@ const generateVar = (scope, decl) => {
|
|
2205
2209
|
|
2206
2210
|
// global variable if in top scope (main) and var ..., or if wanted
|
2207
2211
|
const global = topLevel || decl._bare; // decl.kind === 'var';
|
2212
|
+
const target = global ? globals : scope.locals;
|
2208
2213
|
|
2209
2214
|
for (const x of decl.declarations) {
|
2210
2215
|
const name = mapName(x.id.name);
|
@@ -2226,6 +2231,10 @@ const generateVar = (scope, decl) => {
|
|
2226
2231
|
continue; // always ignore
|
2227
2232
|
}
|
2228
2233
|
|
2234
|
+
// // generate init before allocating var
|
2235
|
+
// let generated;
|
2236
|
+
// if (x.init) generated = generate(scope, x.init, global, name);
|
2237
|
+
|
2229
2238
|
const typed = typedInput && x.id.typeAnnotation;
|
2230
2239
|
let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
|
2231
2240
|
|
@@ -2234,9 +2243,17 @@ const generateVar = (scope, decl) => {
|
|
2234
2243
|
}
|
2235
2244
|
|
2236
2245
|
if (x.init) {
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2246
|
+
const generated = generate(scope, x.init, global, name);
|
2247
|
+
if (scope.arrays?.get(name) != null) {
|
2248
|
+
// hack to set local as pointer before
|
2249
|
+
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2250
|
+
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2251
|
+
generated.pop();
|
2252
|
+
out = out.concat(generated);
|
2253
|
+
} else {
|
2254
|
+
out = out.concat(generated);
|
2255
|
+
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2256
|
+
}
|
2240
2257
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2241
2258
|
}
|
2242
2259
|
|
@@ -2263,6 +2280,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2263
2280
|
return [];
|
2264
2281
|
}
|
2265
2282
|
|
2283
|
+
const op = decl.operator.slice(0, -1) || '=';
|
2284
|
+
|
2266
2285
|
// hack: .length setter
|
2267
2286
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2268
2287
|
const name = decl.left.object.name;
|
@@ -2271,14 +2290,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2271
2290
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2272
2291
|
|
2273
2292
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2293
|
+
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2274
2294
|
|
2275
2295
|
return [
|
2276
2296
|
...(aotPointer ? number(0, Valtype.i32) : [
|
2277
2297
|
...generate(scope, decl.left.object),
|
2278
2298
|
Opcodes.i32_to_u
|
2279
2299
|
]),
|
2300
|
+
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2280
2301
|
|
2281
|
-
...generate(scope, decl.right),
|
2302
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2303
|
+
[ Opcodes.local_get, pointerTmp ],
|
2304
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2305
|
+
Opcodes.i32_from_u
|
2306
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
2282
2307
|
[ Opcodes.local_tee, newValueTmp ],
|
2283
2308
|
|
2284
2309
|
Opcodes.i32_to_u,
|
@@ -2288,8 +2313,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2288
2313
|
];
|
2289
2314
|
}
|
2290
2315
|
|
2291
|
-
const op = decl.operator.slice(0, -1) || '=';
|
2292
|
-
|
2293
2316
|
// arr[i]
|
2294
2317
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2295
2318
|
const name = decl.left.object.name;
|
@@ -3093,12 +3116,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3093
3116
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3094
3117
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3095
3118
|
|
3096
|
-
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${
|
3119
|
+
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
|
3097
3120
|
else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
3098
3121
|
}
|
3099
3122
|
|
3100
3123
|
const pointer = scope.arrays.get(name);
|
3101
3124
|
|
3125
|
+
const local = global ? globals[name] : scope.locals[name];
|
3126
|
+
|
3102
3127
|
const useRawElements = !!decl.rawElements;
|
3103
3128
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3104
3129
|
|
@@ -3131,11 +3156,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3131
3156
|
return [ out, pointer ];
|
3132
3157
|
}
|
3133
3158
|
|
3159
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3160
|
+
if (pointerTmp != null) {
|
3161
|
+
out.push(
|
3162
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3163
|
+
Opcodes.i32_to_u,
|
3164
|
+
[ Opcodes.local_set, pointerTmp ]
|
3165
|
+
);
|
3166
|
+
}
|
3167
|
+
|
3168
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3169
|
+
|
3134
3170
|
// store length as 0th array
|
3135
3171
|
out.push(
|
3136
|
-
...
|
3172
|
+
...pointerWasm,
|
3137
3173
|
...number(length, Valtype.i32),
|
3138
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3174
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3139
3175
|
);
|
3140
3176
|
|
3141
3177
|
const storeOp = StoreOps[itemType];
|
@@ -3144,14 +3180,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3144
3180
|
if (elements[i] == null) continue;
|
3145
3181
|
|
3146
3182
|
out.push(
|
3147
|
-
...
|
3183
|
+
...pointerWasm,
|
3148
3184
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3149
|
-
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(
|
3185
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
3150
3186
|
);
|
3151
3187
|
}
|
3152
3188
|
|
3153
3189
|
// local value as pointer
|
3154
|
-
out.push(...
|
3190
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3155
3191
|
|
3156
3192
|
return [ out, pointer ];
|
3157
3193
|
};
|
@@ -3649,7 +3685,7 @@ export default program => {
|
|
3649
3685
|
|
3650
3686
|
globalThis.valtype = 'f64';
|
3651
3687
|
|
3652
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('
|
3688
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3653
3689
|
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3654
3690
|
|
3655
3691
|
globalThis.valtypeBinary = Valtype[valtype];
|
@@ -3657,7 +3693,7 @@ export default program => {
|
|
3657
3693
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3658
3694
|
|
3659
3695
|
globalThis.pageSize = PageSize;
|
3660
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('
|
3696
|
+
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3661
3697
|
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3662
3698
|
|
3663
3699
|
// set generic opcodes for current valtype
|