porffor 0.47.6 → 0.47.8
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/2c.js +4 -4
- package/compiler/allocator.js +64 -0
- package/compiler/assemble.js +2 -2
- package/compiler/builtins/__internal_string.ts +117 -34
- package/compiler/builtins/boolean.ts +2 -5
- package/compiler/builtins/function.ts +12 -3
- package/compiler/builtins/object.ts +10 -12
- package/compiler/builtins/z_ecma262.ts +4 -6
- package/compiler/builtins.js +2 -2
- package/compiler/builtins_objects.js +2 -2
- package/compiler/builtins_precompiled.js +722 -787
- package/compiler/cache.js +44 -0
- package/compiler/codegen.js +193 -306
- package/compiler/index.js +7 -1
- package/compiler/opt.js +1 -1
- package/compiler/parse.js +1 -1
- package/compiler/pgo.js +1 -1
- package/compiler/precompile.js +15 -20
- package/compiler/prototype.js +135 -123
- package/compiler/types.js +1 -1
- package/compiler/wrap.js +5 -5
- package/package.json +1 -1
- package/rhemyn/compile.js +1 -1
- package/runner/index.js +1 -1
- package/runner/repl.js +3 -3
- package/compiler/allocators.js +0 -130
package/compiler/codegen.js
CHANGED
@@ -8,8 +8,8 @@ import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
|
|
8
8
|
import * as Rhemyn from '../rhemyn/compile.js';
|
9
9
|
import parse from './parse.js';
|
10
10
|
import { log } from './log.js';
|
11
|
-
import
|
12
|
-
import
|
11
|
+
import './prefs.js';
|
12
|
+
import { allocPage as _allocPage, allocBytes, allocStr, nameToReason } from './allocator.js';
|
13
13
|
|
14
14
|
let globals = {};
|
15
15
|
let tags = [];
|
@@ -18,7 +18,6 @@ let exceptions = [];
|
|
18
18
|
let funcIndex = {};
|
19
19
|
let currentFuncIndex = importedFuncs.length;
|
20
20
|
let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
|
21
|
-
let allocator;
|
22
21
|
|
23
22
|
class TodoError extends Error {
|
24
23
|
constructor(message) {
|
@@ -191,6 +190,7 @@ const forceDuoValtype = (scope, wasm, forceValtype) => [
|
|
191
190
|
];
|
192
191
|
|
193
192
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
193
|
+
if (valueUnused && !Prefs.optUnused) valueUnused = false;
|
194
194
|
if (astCache.has(decl)) return astCache.get(decl);
|
195
195
|
|
196
196
|
switch (decl.type) {
|
@@ -240,7 +240,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
240
240
|
return cacheAst(decl, generateVar(scope, decl));
|
241
241
|
|
242
242
|
case 'AssignmentExpression':
|
243
|
-
return cacheAst(decl, generateAssign(scope, decl));
|
243
|
+
return cacheAst(decl, generateAssign(scope, decl, global, name, valueUnused));
|
244
244
|
|
245
245
|
case 'UnaryExpression':
|
246
246
|
return cacheAst(decl, generateUnary(scope, decl));
|
@@ -297,7 +297,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
297
297
|
return cacheAst(decl, [[ Opcodes.call, importedFuncs.debugger ]]);
|
298
298
|
|
299
299
|
case 'ArrayExpression':
|
300
|
-
return cacheAst(decl, generateArray(scope, decl, global, name));
|
300
|
+
return cacheAst(decl, generateArray(scope, decl, global, name, globalThis.precompile));
|
301
301
|
|
302
302
|
case 'ObjectExpression':
|
303
303
|
return cacheAst(decl, generateObject(scope, decl, global, name));
|
@@ -348,10 +348,12 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
348
348
|
return cacheAst(decl, []);
|
349
349
|
}
|
350
350
|
|
351
|
-
return cacheAst(decl, todo(scope, `no generation for ${decl.type}
|
351
|
+
return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`, !decl.type.endsWith('Statement') && !decl.type.endsWith('Declaration')));
|
352
352
|
}
|
353
353
|
};
|
354
354
|
|
355
|
+
const optional = (op, clause = op.at(-1)) => clause || clause === 0 ? (Array.isArray(op[0]) ? op : [ op ]) : [];
|
356
|
+
|
355
357
|
const lookupName = (scope, name) => {
|
356
358
|
if (Object.hasOwn(scope.locals, name)) return [ scope.locals[name], false ];
|
357
359
|
if (Object.hasOwn(globals, name)) return [ globals[name], true ];
|
@@ -363,7 +365,7 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
|
|
363
365
|
...generate(scope, {
|
364
366
|
type: 'ThrowStatement',
|
365
367
|
argument: {
|
366
|
-
type: '
|
368
|
+
type: 'CallExpression',
|
367
369
|
callee: {
|
368
370
|
type: 'Identifier',
|
369
371
|
name: constructor
|
@@ -415,7 +417,7 @@ const generateIdent = (scope, decl) => {
|
|
415
417
|
|
416
418
|
return generateArray(scope, {
|
417
419
|
elements: names.map(x => ({ type: 'Identifier', name: x }))
|
418
|
-
}, false, '#arguments');
|
420
|
+
}, false, '#arguments', true);
|
419
421
|
}
|
420
422
|
|
421
423
|
// no local var with name
|
@@ -1124,7 +1126,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1124
1126
|
|
1125
1127
|
const asmFuncToAsm = (scope, func) => {
|
1126
1128
|
return func(scope, {
|
1127
|
-
Valtype, Opcodes, TYPES, TYPE_NAMES, typeSwitch,
|
1129
|
+
Valtype, Opcodes, TYPES, TYPE_NAMES, typeSwitch, makeString, allocPage, internalThrow,
|
1128
1130
|
getNodeType, generate, generateIdent,
|
1129
1131
|
builtin: (n, offset = false) => {
|
1130
1132
|
let idx = funcIndex[n] ?? importedFuncs[n];
|
@@ -1197,6 +1199,10 @@ const asmFuncToAsm = (scope, func) => {
|
|
1197
1199
|
return [];
|
1198
1200
|
}, 0 ] ];
|
1199
1201
|
}
|
1202
|
+
},
|
1203
|
+
i32ify: wasm => {
|
1204
|
+
wasm.push(Opcodes.i32_to_u);
|
1205
|
+
return wasm;
|
1200
1206
|
}
|
1201
1207
|
});
|
1202
1208
|
};
|
@@ -1219,6 +1225,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
|
|
1219
1225
|
}
|
1220
1226
|
|
1221
1227
|
for (const x in _data) {
|
1228
|
+
if (data.find(y => y.page === x)) return;
|
1222
1229
|
data.push({ page: x, bytes: _data[x] });
|
1223
1230
|
}
|
1224
1231
|
|
@@ -1628,7 +1635,7 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
1628
1635
|
return number(decl.value ? 1 : 0);
|
1629
1636
|
|
1630
1637
|
case 'string':
|
1631
|
-
return makeString(scope, decl.value
|
1638
|
+
return makeString(scope, decl.value);
|
1632
1639
|
|
1633
1640
|
default:
|
1634
1641
|
return todo(scope, `cannot generate literal of type ${typeof decl.value}`, true);
|
@@ -1653,14 +1660,17 @@ const countLeftover = wasm => {
|
|
1653
1660
|
if (inst[0] === Opcodes.end) depth--;
|
1654
1661
|
|
1655
1662
|
if (depth === 0)
|
1656
|
-
if ([Opcodes.
|
1663
|
+
if ([Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1657
1664
|
else if ([Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.f32_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1658
1665
|
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
|
1659
1666
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8, Opcodes.select].includes(inst[0])) count -= 2;
|
1660
1667
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1661
1668
|
else if (inst[0] === Opcodes.return) count = 0;
|
1662
1669
|
else if (inst[0] === Opcodes.catch) count += 2;
|
1663
|
-
else if (inst[0] === Opcodes.
|
1670
|
+
else if (inst[0] === Opcodes.throw) {
|
1671
|
+
count--;
|
1672
|
+
if ((Prefs.exceptionMode ?? 'stack') === 'stack' || (globalThis.precompile && inst[1] === 1)) count--;
|
1673
|
+
} else if (inst[0] === Opcodes.call) {
|
1664
1674
|
if (inst[1] < importedFuncs.length) {
|
1665
1675
|
const func = importedFuncs[inst[1]];
|
1666
1676
|
count = count - func.params + func.returns;
|
@@ -1674,7 +1684,7 @@ const countLeftover = wasm => {
|
|
1674
1684
|
count += 2; // fixed return (value, type)
|
1675
1685
|
} else count--;
|
1676
1686
|
|
1677
|
-
// console.log(count, depth, decompile([ inst ]).slice(0, -1));
|
1687
|
+
// console.log(count, depth, decompile([ inst ], undefined, undefined, undefined, undefined, undefined, funcs).slice(0, -1));
|
1678
1688
|
}
|
1679
1689
|
|
1680
1690
|
return count;
|
@@ -1694,7 +1704,7 @@ const generateExp = (scope, decl) => {
|
|
1694
1704
|
}
|
1695
1705
|
}
|
1696
1706
|
|
1697
|
-
const out = generate(scope, expression, undefined, undefined,
|
1707
|
+
const out = generate(scope, expression, undefined, undefined, !scope.inEval);
|
1698
1708
|
disposeLeftover(out);
|
1699
1709
|
|
1700
1710
|
return out;
|
@@ -1716,33 +1726,7 @@ const generateChain = (scope, decl) => {
|
|
1716
1726
|
return generate(scope, decl.expression);
|
1717
1727
|
};
|
1718
1728
|
|
1719
|
-
const
|
1720
|
-
getLengthI32: pointer => [
|
1721
|
-
...number(0, Valtype.i32),
|
1722
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1723
|
-
],
|
1724
|
-
|
1725
|
-
getLength: pointer => [
|
1726
|
-
...number(0, Valtype.i32),
|
1727
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
|
1728
|
-
Opcodes.i32_from_u
|
1729
|
-
],
|
1730
|
-
|
1731
|
-
setLengthI32: (pointer, value) => [
|
1732
|
-
...number(0, Valtype.i32),
|
1733
|
-
...value,
|
1734
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1735
|
-
],
|
1736
|
-
|
1737
|
-
setLength: (pointer, value) => [
|
1738
|
-
...number(0, Valtype.i32),
|
1739
|
-
...value,
|
1740
|
-
Opcodes.i32_to_u,
|
1741
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1742
|
-
]
|
1743
|
-
};
|
1744
|
-
|
1745
|
-
const RTArrayUtil = {
|
1729
|
+
const ArrayUtil = {
|
1746
1730
|
getLengthI32: pointer => [
|
1747
1731
|
...pointer,
|
1748
1732
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
@@ -1969,10 +1953,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1969
1953
|
throw e;
|
1970
1954
|
}
|
1971
1955
|
|
1956
|
+
scope.inEval = true;
|
1972
1957
|
const out = generate(scope, {
|
1973
1958
|
type: 'BlockStatement',
|
1974
1959
|
body: parsed.body
|
1975
1960
|
});
|
1961
|
+
scope.inEval = false;
|
1976
1962
|
|
1977
1963
|
const lastInst = out[out.length - 1];
|
1978
1964
|
if (lastInst && lastInst[0] === Opcodes.drop) {
|
@@ -1985,12 +1971,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1985
1971
|
out.push(...setLastType(scope, TYPES.undefined));
|
1986
1972
|
}
|
1987
1973
|
|
1988
|
-
// if (lastInst && lastInst[0] === Opcodes.drop) {
|
1989
|
-
// out.splice(out.length - 1, 1);
|
1990
|
-
// } else if (countLeftover(out) === 0) {
|
1991
|
-
// out.push(...number(UNDEFINED));
|
1992
|
-
// }
|
1993
|
-
|
1994
1974
|
return out;
|
1995
1975
|
}
|
1996
1976
|
|
@@ -2200,7 +2180,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2200
2180
|
const protoFunc = protoCands[x];
|
2201
2181
|
if (protoFunc.noArgRetLength && decl.arguments.length === 0) {
|
2202
2182
|
protoBC[x] = [
|
2203
|
-
...
|
2183
|
+
...ArrayUtil.getLength(getPointer),
|
2204
2184
|
...setLastType(scope, TYPES.number)
|
2205
2185
|
];
|
2206
2186
|
continue;
|
@@ -2214,19 +2194,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2214
2194
|
const protoOut = protoFunc(getPointer, {
|
2215
2195
|
getCachedI32: () => [ [ Opcodes.local_get, lengthLocal ] ],
|
2216
2196
|
setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
|
2217
|
-
get: () =>
|
2218
|
-
getI32: () =>
|
2219
|
-
set: value =>
|
2220
|
-
setI32: value =>
|
2197
|
+
get: () => ArrayUtil.getLength(getPointer),
|
2198
|
+
getI32: () => ArrayUtil.getLengthI32(getPointer),
|
2199
|
+
set: value => ArrayUtil.setLength(getPointer, value),
|
2200
|
+
setI32: value => ArrayUtil.setLengthI32(getPointer, value)
|
2221
2201
|
},
|
2222
2202
|
generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2223
2203
|
getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2224
2204
|
protoLocal, protoLocal2,
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2229
|
-
},
|
2205
|
+
bytes => [
|
2206
|
+
...number(bytes, Valtype.i32),
|
2207
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ]
|
2208
|
+
],
|
2230
2209
|
() => {
|
2231
2210
|
optUnused = true;
|
2232
2211
|
return unusedValue;
|
@@ -2252,7 +2231,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2252
2231
|
] : []),
|
2253
2232
|
|
2254
2233
|
...(useLengthCache ? [
|
2255
|
-
...
|
2234
|
+
...ArrayUtil.getLengthI32(getPointer),
|
2256
2235
|
[ Opcodes.local_set, lengthLocal ],
|
2257
2236
|
] : []),
|
2258
2237
|
|
@@ -3335,7 +3314,6 @@ const isIdentAssignable = (scope, name, op = '=') => {
|
|
3335
3314
|
return false;
|
3336
3315
|
};
|
3337
3316
|
|
3338
|
-
// todo: optimize this func for valueUnused
|
3339
3317
|
const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
3340
3318
|
const { type, name } = decl.left;
|
3341
3319
|
const [ local, isGlobal ] = lookupName(scope, name);
|
@@ -3361,8 +3339,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3361
3339
|
|
3362
3340
|
// hack: .length setter
|
3363
3341
|
if (type === 'MemberExpression' && decl.left.property.name === 'length' && !decl._internalAssign) {
|
3364
|
-
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
3365
|
-
|
3342
|
+
const newValueTmp = !valueUnused && localTmp(scope, '__length_setter_tmp');
|
3343
|
+
let pointerTmp = op !== '=' && localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
3366
3344
|
|
3367
3345
|
const out = [
|
3368
3346
|
...generate(scope, decl.left.object),
|
@@ -3375,23 +3353,32 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3375
3353
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3376
3354
|
Opcodes.i32_from_u
|
3377
3355
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
3378
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3356
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3379
3357
|
|
3380
3358
|
Opcodes.i32_to_u,
|
3381
3359
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3382
3360
|
|
3383
|
-
[ Opcodes.local_get, newValueTmp ]
|
3361
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3384
3362
|
];
|
3385
3363
|
|
3386
3364
|
const type = getNodeType(scope, decl.left.object);
|
3387
3365
|
const known = knownType(scope, type);
|
3388
3366
|
if (known != null && typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3389
3367
|
...out,
|
3390
|
-
...(
|
3368
|
+
...optional([ Opcodes.local_tee, pointerTmp ]),
|
3391
3369
|
|
3392
|
-
...lengthTypeWasm
|
3370
|
+
...lengthTypeWasm,
|
3371
|
+
...optional(number(UNDEFINED), valueUnused)
|
3393
3372
|
];
|
3394
3373
|
|
3374
|
+
pointerTmp ||= localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
3375
|
+
|
3376
|
+
const slow = generate(scope, {
|
3377
|
+
...decl,
|
3378
|
+
_internalAssign: true
|
3379
|
+
});
|
3380
|
+
if (valueUnused) disposeLeftover(slow);
|
3381
|
+
|
3395
3382
|
return [
|
3396
3383
|
...out,
|
3397
3384
|
[ Opcodes.local_set, pointerTmp ],
|
@@ -3399,33 +3386,31 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3399
3386
|
...type,
|
3400
3387
|
...number(TYPE_FLAGS.length, Valtype.i32),
|
3401
3388
|
[ Opcodes.i32_and ],
|
3402
|
-
[ Opcodes.if, valtypeBinary ],
|
3389
|
+
[ Opcodes.if, valueUnused ? Blocktype.void : valtypeBinary ],
|
3403
3390
|
[ Opcodes.local_get, pointerTmp ],
|
3404
3391
|
...lengthTypeWasm,
|
3405
3392
|
[ Opcodes.else ],
|
3406
|
-
...
|
3407
|
-
|
3408
|
-
|
3409
|
-
}),
|
3410
|
-
[ Opcodes.end ]
|
3393
|
+
...slow,
|
3394
|
+
[ Opcodes.end ],
|
3395
|
+
...optional(number(UNDEFINED), valueUnused)
|
3411
3396
|
];
|
3412
3397
|
}
|
3413
3398
|
|
3414
3399
|
// arr[i]
|
3415
3400
|
if (type === 'MemberExpression') {
|
3416
|
-
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
3401
|
+
const newValueTmp = !valueUnused && localTmp(scope, '#member_setter_val_tmp');
|
3417
3402
|
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
3418
3403
|
|
3419
3404
|
const object = decl.left.object;
|
3420
3405
|
const property = getProperty(decl.left);
|
3421
3406
|
|
3422
3407
|
// todo/perf: use i32 object (and prop?) locals
|
3423
|
-
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#
|
3408
|
+
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj_assign') ] ];
|
3424
3409
|
const propertyWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_prop_assign') ] ];
|
3425
3410
|
|
3426
3411
|
return [
|
3427
3412
|
...generate(scope, object),
|
3428
|
-
[ Opcodes.local_set,
|
3413
|
+
[ Opcodes.local_set, objectWasm[0][1] ],
|
3429
3414
|
|
3430
3415
|
...generate(scope, property, false, '#member_prop_assign'),
|
3431
3416
|
[ Opcodes.local_set, localTmp(scope, '#member_prop_assign') ],
|
@@ -3454,14 +3439,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3454
3439
|
[ Opcodes.local_get, pointerTmp ],
|
3455
3440
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3456
3441
|
], getNodeType(scope, decl.right), false, name, true)),
|
3457
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3442
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3458
3443
|
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3459
3444
|
|
3460
3445
|
[ Opcodes.local_get, pointerTmp ],
|
3461
3446
|
...getNodeType(scope, decl),
|
3462
3447
|
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
3463
3448
|
|
3464
|
-
[ Opcodes.local_get, newValueTmp ]
|
3449
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3465
3450
|
],
|
3466
3451
|
|
3467
3452
|
...wrapBC({
|
@@ -3474,7 +3459,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3474
3459
|
[ Opcodes.i32_load8_u, 0, 4 ],
|
3475
3460
|
Opcodes.i32_from_u
|
3476
3461
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3477
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3462
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3478
3463
|
|
3479
3464
|
Opcodes.i32_to_u,
|
3480
3465
|
[ Opcodes.i32_store8, 0, 4 ]
|
@@ -3488,7 +3473,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3488
3473
|
[ Opcodes.i32_load8_u, 0, 4 ],
|
3489
3474
|
Opcodes.i32_from_u
|
3490
3475
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3491
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3476
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3492
3477
|
|
3493
3478
|
...number(0),
|
3494
3479
|
[ Opcodes.f64_max ],
|
@@ -3506,7 +3491,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3506
3491
|
[ Opcodes.i32_load8_s, 0, 4 ],
|
3507
3492
|
Opcodes.i32_from
|
3508
3493
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3509
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3494
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3510
3495
|
|
3511
3496
|
Opcodes.i32_to,
|
3512
3497
|
[ Opcodes.i32_store8, 0, 4 ]
|
@@ -3522,7 +3507,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3522
3507
|
[ Opcodes.i32_load16_u, 0, 4 ],
|
3523
3508
|
Opcodes.i32_from_u
|
3524
3509
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3525
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3510
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3526
3511
|
|
3527
3512
|
Opcodes.i32_to_u,
|
3528
3513
|
[ Opcodes.i32_store16, 0, 4 ]
|
@@ -3538,7 +3523,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3538
3523
|
[ Opcodes.i32_load16_s, 0, 4 ],
|
3539
3524
|
Opcodes.i32_from
|
3540
3525
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3541
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3526
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3542
3527
|
|
3543
3528
|
Opcodes.i32_to,
|
3544
3529
|
[ Opcodes.i32_store16, 0, 4 ]
|
@@ -3554,7 +3539,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3554
3539
|
[ Opcodes.i32_load, 0, 4 ],
|
3555
3540
|
Opcodes.i32_from_u
|
3556
3541
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3557
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3542
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3558
3543
|
|
3559
3544
|
Opcodes.i32_to_u,
|
3560
3545
|
[ Opcodes.i32_store, 0, 4 ]
|
@@ -3570,7 +3555,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3570
3555
|
[ Opcodes.i32_load, 0, 4 ],
|
3571
3556
|
Opcodes.i32_from
|
3572
3557
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3573
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3558
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3574
3559
|
|
3575
3560
|
Opcodes.i32_to,
|
3576
3561
|
[ Opcodes.i32_store, 0, 4 ]
|
@@ -3586,7 +3571,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3586
3571
|
[ Opcodes.f32_load, 0, 4 ],
|
3587
3572
|
[ Opcodes.f64_promote_f32 ]
|
3588
3573
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3589
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3574
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3590
3575
|
|
3591
3576
|
[ Opcodes.f32_demote_f64 ],
|
3592
3577
|
[ Opcodes.f32_store, 0, 4 ]
|
@@ -3601,7 +3586,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3601
3586
|
[ Opcodes.local_get, pointerTmp ],
|
3602
3587
|
[ Opcodes.f64_load, 0, 4 ]
|
3603
3588
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3604
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3589
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3605
3590
|
|
3606
3591
|
[ Opcodes.f64_store, 0, 4 ]
|
3607
3592
|
],
|
@@ -3616,12 +3601,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3616
3601
|
],
|
3617
3602
|
postlude: [
|
3618
3603
|
// setLastType(scope, TYPES.number)
|
3619
|
-
[ Opcodes.local_get, newValueTmp ]
|
3604
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3620
3605
|
]
|
3621
3606
|
}),
|
3622
3607
|
} : {}),
|
3623
3608
|
|
3624
|
-
[TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined',
|
3609
|
+
[TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined', !valueUnused),
|
3625
3610
|
|
3626
3611
|
// default: internalThrow(scope, 'TypeError', `Cannot assign member with this type`)
|
3627
3612
|
default: () => [
|
@@ -3652,9 +3637,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3652
3637
|
|
3653
3638
|
[ Opcodes.call, includeBuiltin(scope, scope.strict ? '__Porffor_object_setStrict' : '__Porffor_object_set').index ],
|
3654
3639
|
[ Opcodes.drop ],
|
3640
|
+
...(valueUnused ? [ [ Opcodes.drop ] ] : [])
|
3655
3641
|
// ...setLastType(scope, getNodeType(scope, decl)),
|
3656
3642
|
]
|
3657
|
-
}, valtypeBinary)
|
3643
|
+
}, valueUnused ? Blocktype.void : valtypeBinary),
|
3644
|
+
...optional(number(UNDEFINED), valueUnused)
|
3658
3645
|
];
|
3659
3646
|
}
|
3660
3647
|
|
@@ -3682,7 +3669,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3682
3669
|
// set global and return (eg a = 2)
|
3683
3670
|
return [
|
3684
3671
|
...generateVarDstr(scope, 'var', name, decl.right, undefined, true),
|
3685
|
-
...generate(scope, decl.left)
|
3672
|
+
...optional(generate(scope, decl.left), !valueUnused),
|
3673
|
+
...optional(number(UNDEFINED), valueUnused)
|
3686
3674
|
];
|
3687
3675
|
}
|
3688
3676
|
|
@@ -3690,7 +3678,10 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3690
3678
|
if (local.metadata?.kind === 'const') return internalThrow(scope, 'TypeError', `Cannot assign to constant variable ${name}`, true);
|
3691
3679
|
|
3692
3680
|
if (op === '=') {
|
3693
|
-
|
3681
|
+
const out = setLocalWithType(scope, name, isGlobal, decl.right, !valueUnused);
|
3682
|
+
|
3683
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3684
|
+
return out;
|
3694
3685
|
}
|
3695
3686
|
|
3696
3687
|
if (op === '||' || op === '&&' || op === '??') {
|
@@ -3713,12 +3704,15 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3713
3704
|
];
|
3714
3705
|
}
|
3715
3706
|
|
3716
|
-
|
3707
|
+
const out = setLocalWithType(
|
3717
3708
|
scope, name, isGlobal,
|
3718
3709
|
performOp(scope, op, [ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ] ], generate(scope, decl.right), getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
3719
|
-
|
3710
|
+
!valueUnused,
|
3720
3711
|
getNodeType(scope, decl)
|
3721
3712
|
);
|
3713
|
+
|
3714
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3715
|
+
return out;
|
3722
3716
|
};
|
3723
3717
|
|
3724
3718
|
const ifIdentifierErrors = (scope, decl) => {
|
@@ -3859,15 +3853,15 @@ const generateUnary = (scope, decl) => {
|
|
3859
3853
|
disposeLeftover(out);
|
3860
3854
|
|
3861
3855
|
out.push(...typeSwitch(scope, overrideType ?? getNodeType(scope, decl.argument), [
|
3862
|
-
[ TYPES.number, () => makeString(scope, 'number'
|
3863
|
-
[ TYPES.boolean, () => makeString(scope, 'boolean'
|
3864
|
-
[ [ TYPES.string, TYPES.bytestring ], () => makeString(scope, 'string'
|
3865
|
-
[ [ TYPES.undefined, TYPES.empty ], () => makeString(scope, 'undefined'
|
3866
|
-
[ TYPES.function, () => makeString(scope, 'function'
|
3867
|
-
[ TYPES.symbol, () => makeString(scope, 'symbol'
|
3856
|
+
[ TYPES.number, () => makeString(scope, 'number') ],
|
3857
|
+
[ TYPES.boolean, () => makeString(scope, 'boolean') ],
|
3858
|
+
[ [ TYPES.string, TYPES.bytestring ], () => makeString(scope, 'string') ],
|
3859
|
+
[ [ TYPES.undefined, TYPES.empty ], () => makeString(scope, 'undefined') ],
|
3860
|
+
[ TYPES.function, () => makeString(scope, 'function') ],
|
3861
|
+
[ TYPES.symbol, () => makeString(scope, 'symbol') ],
|
3868
3862
|
|
3869
3863
|
// object and internal types
|
3870
|
-
[ 'default', () => makeString(scope, 'object'
|
3864
|
+
[ 'default', () => makeString(scope, 'object') ],
|
3871
3865
|
]));
|
3872
3866
|
|
3873
3867
|
return out;
|
@@ -3903,6 +3897,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3903
3897
|
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
3904
3898
|
if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3905
3899
|
|
3900
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3906
3901
|
return out;
|
3907
3902
|
}
|
3908
3903
|
|
@@ -3920,7 +3915,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3920
3915
|
prefix: true,
|
3921
3916
|
argument: decl.argument
|
3922
3917
|
}),
|
3923
|
-
[ decl.prefix ? Opcodes.local_set : Opcodes.local_tee, tmp ],
|
3918
|
+
[ decl.prefix || valueUnused ? Opcodes.local_set : Opcodes.local_tee, tmp ],
|
3924
3919
|
|
3925
3920
|
// x = tmp + 1
|
3926
3921
|
...generate(scope, {
|
@@ -3933,8 +3928,9 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3933
3928
|
left: { type: 'Identifier', name: '#updatetmp' },
|
3934
3929
|
right: { type: 'Literal', value: 1 }
|
3935
3930
|
}
|
3936
|
-
}),
|
3937
|
-
...(decl.prefix ? [] : [ [ Opcodes.drop ] ])
|
3931
|
+
}, _global, _name, valueUnused),
|
3932
|
+
...(decl.prefix || valueUnused ? [] : [ [ Opcodes.drop ] ]),
|
3933
|
+
...optional(number(UNDEFINED), valueUnused)
|
3938
3934
|
];
|
3939
3935
|
};
|
3940
3936
|
|
@@ -4195,7 +4191,8 @@ const generateForOf = (scope, decl) => {
|
|
4195
4191
|
...setType(scope, tmpName, TYPES.string),
|
4196
4192
|
|
4197
4193
|
// allocate out string
|
4198
|
-
|
4194
|
+
...number(8, Valtype.i32),
|
4195
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
|
4199
4196
|
[ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],
|
4200
4197
|
|
4201
4198
|
// set length to 1
|
@@ -4250,7 +4247,8 @@ const generateForOf = (scope, decl) => {
|
|
4250
4247
|
...setType(scope, tmpName, TYPES.bytestring),
|
4251
4248
|
|
4252
4249
|
// allocate out string
|
4253
|
-
|
4250
|
+
...number(8, Valtype.i32),
|
4251
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
|
4254
4252
|
[ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],
|
4255
4253
|
|
4256
4254
|
// set length to 1
|
@@ -4897,18 +4895,7 @@ const generateMeta = (scope, decl) => {
|
|
4897
4895
|
};
|
4898
4896
|
|
4899
4897
|
let pages = new Map();
|
4900
|
-
const allocPage = (scope,
|
4901
|
-
const ptr = i => i === 0 ? 16 : (i * pageSize);
|
4902
|
-
if (pages.has(reason)) return ptr(pages.get(reason).ind);
|
4903
|
-
|
4904
|
-
const ind = pages.size;
|
4905
|
-
pages.set(reason, { ind, type });
|
4906
|
-
|
4907
|
-
scope.pages ??= new Map();
|
4908
|
-
scope.pages.set(reason, { ind, type });
|
4909
|
-
|
4910
|
-
return ptr(ind);
|
4911
|
-
};
|
4898
|
+
const allocPage = (scope, name) => _allocPage({ scope, pages }, name);
|
4912
4899
|
|
4913
4900
|
const itemTypeToValtype = {
|
4914
4901
|
i32: 'i32',
|
@@ -4942,18 +4929,23 @@ const compileBytes = (val, itemType) => {
|
|
4942
4929
|
}
|
4943
4930
|
};
|
4944
4931
|
|
4945
|
-
const makeData = (scope, elements, page = null, itemType
|
4932
|
+
const makeData = (scope, elements, page = null, itemType = 'i8') => {
|
4933
|
+
// if data for page already exists, abort
|
4934
|
+
if (page && data.find(x => x.page === page)) return;
|
4935
|
+
|
4946
4936
|
const length = elements.length;
|
4947
4937
|
|
4948
4938
|
// if length is 0 memory/data will just be 0000... anyway
|
4949
4939
|
if (length === 0) return false;
|
4950
4940
|
|
4951
4941
|
let bytes = compileBytes(length, 'i32');
|
4952
|
-
|
4953
|
-
|
4954
|
-
|
4955
|
-
|
4956
|
-
|
4942
|
+
if (itemType === 'i8') {
|
4943
|
+
bytes = bytes.concat(elements);
|
4944
|
+
} else {
|
4945
|
+
for (let i = 0; i < length; i++) {
|
4946
|
+
if (elements[i] == null) continue;
|
4947
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
4948
|
+
}
|
4957
4949
|
}
|
4958
4950
|
|
4959
4951
|
const obj = { bytes, page };
|
@@ -4981,169 +4973,6 @@ const printStaticStr = str => {
|
|
4981
4973
|
return out;
|
4982
4974
|
};
|
4983
4975
|
|
4984
|
-
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
4985
|
-
const out = [];
|
4986
|
-
|
4987
|
-
const uniqueName = name === '$undeclared' ? name + uniqId() : name;
|
4988
|
-
|
4989
|
-
const useRawElements = !!decl.rawElements;
|
4990
|
-
const elements = useRawElements ? decl.rawElements : decl.elements;
|
4991
|
-
|
4992
|
-
const valtype = itemTypeToValtype[itemType];
|
4993
|
-
const length = elements.length;
|
4994
|
-
|
4995
|
-
const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
|
4996
|
-
|
4997
|
-
let pointer = allocated;
|
4998
|
-
if (allocator.constructor.name !== 'StaticAllocator') {
|
4999
|
-
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
5000
|
-
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
5001
|
-
out.push(
|
5002
|
-
...allocated,
|
5003
|
-
[ Opcodes.local_set, tmp ]
|
5004
|
-
);
|
5005
|
-
|
5006
|
-
if (Prefs.runtimeAllocLog) out.push(
|
5007
|
-
...printStaticStr(`${name}: `),
|
5008
|
-
|
5009
|
-
[ Opcodes.local_get, tmp ],
|
5010
|
-
Opcodes.i32_from_u,
|
5011
|
-
[ Opcodes.call, 0 ],
|
5012
|
-
|
5013
|
-
...number(10),
|
5014
|
-
[ Opcodes.call, 1 ]
|
5015
|
-
);
|
5016
|
-
|
5017
|
-
pointer = [ [ Opcodes.local_get, tmp ] ];
|
5018
|
-
|
5019
|
-
if (Prefs.data && useRawElements) {
|
5020
|
-
const data = makeData(scope, elements, null, itemType, initEmpty);
|
5021
|
-
if (data) {
|
5022
|
-
// init data
|
5023
|
-
out.push(
|
5024
|
-
...pointer,
|
5025
|
-
...number(0, Valtype.i32),
|
5026
|
-
...number(data.size, Valtype.i32),
|
5027
|
-
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
5028
|
-
);
|
5029
|
-
}
|
5030
|
-
|
5031
|
-
// return pointer in out
|
5032
|
-
out.push(
|
5033
|
-
...pointer,
|
5034
|
-
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
5035
|
-
);
|
5036
|
-
|
5037
|
-
return [ out, pointer ];
|
5038
|
-
}
|
5039
|
-
} else {
|
5040
|
-
const rawPtr = allocator.lastPtr;
|
5041
|
-
|
5042
|
-
scope.arrays ??= new Map();
|
5043
|
-
const firstAssign = !scope.arrays.has(uniqueName);
|
5044
|
-
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
5045
|
-
|
5046
|
-
const local = global ? globals[name] : scope.locals?.[name];
|
5047
|
-
if (
|
5048
|
-
Prefs.data && useRawElements &&
|
5049
|
-
name !== '#member_prop' && name !== '#member_prop_assign' &&
|
5050
|
-
(!globalThis.precompile || !global)
|
5051
|
-
) {
|
5052
|
-
if (Prefs.activeData && firstAssign) {
|
5053
|
-
makeData(scope, elements, allocator.lastName, itemType, initEmpty);
|
5054
|
-
|
5055
|
-
// local value as pointer
|
5056
|
-
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
5057
|
-
}
|
5058
|
-
|
5059
|
-
if (Prefs.passiveData) {
|
5060
|
-
const data = makeData(scope, elements, null, itemType, initEmpty);
|
5061
|
-
if (data) {
|
5062
|
-
// init data
|
5063
|
-
out.push(
|
5064
|
-
...pointer,
|
5065
|
-
...number(0, Valtype.i32),
|
5066
|
-
...number(data.size, Valtype.i32),
|
5067
|
-
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
5068
|
-
);
|
5069
|
-
}
|
5070
|
-
|
5071
|
-
// return pointer in out
|
5072
|
-
out.push(...number(rawPtr, intOut ? Valtype.i32 : valtypeBinary));
|
5073
|
-
|
5074
|
-
return [ out, pointer ];
|
5075
|
-
}
|
5076
|
-
}
|
5077
|
-
|
5078
|
-
if (local != null) {
|
5079
|
-
// hack: handle allocation for #member_prop's here instead of in several places /shrug
|
5080
|
-
let shouldGet = true;
|
5081
|
-
if (name === '#member_prop') {
|
5082
|
-
out.push(...number(rawPtr));
|
5083
|
-
shouldGet = false;
|
5084
|
-
}
|
5085
|
-
|
5086
|
-
if (name === '#member_prop_assign') {
|
5087
|
-
out.push(
|
5088
|
-
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
|
5089
|
-
Opcodes.i32_from_u
|
5090
|
-
);
|
5091
|
-
shouldGet = false;
|
5092
|
-
}
|
5093
|
-
|
5094
|
-
const pointerTmp = localTmp(scope, '#makearray_pointer_tmp', Valtype.i32);
|
5095
|
-
out.push(
|
5096
|
-
...(shouldGet ? [
|
5097
|
-
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
5098
|
-
Opcodes.i32_to_u
|
5099
|
-
] : [
|
5100
|
-
// hack: make precompile realise we are allocating
|
5101
|
-
...(globalThis.precompile ? [
|
5102
|
-
[ global ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
5103
|
-
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
5104
|
-
] : []),
|
5105
|
-
Opcodes.i32_to_u
|
5106
|
-
]),
|
5107
|
-
[ Opcodes.local_set, pointerTmp ]
|
5108
|
-
);
|
5109
|
-
|
5110
|
-
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
5111
|
-
}
|
5112
|
-
}
|
5113
|
-
|
5114
|
-
|
5115
|
-
// store length
|
5116
|
-
out.push(
|
5117
|
-
...pointer,
|
5118
|
-
...number(length, Valtype.i32),
|
5119
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
5120
|
-
);
|
5121
|
-
|
5122
|
-
const storeOp = StoreOps[itemType];
|
5123
|
-
const sizePerEl = ValtypeSize[itemType] + (typed ? 1 : 0);
|
5124
|
-
if (!initEmpty) for (let i = 0; i < length; i++) {
|
5125
|
-
if (elements[i] == null) continue;
|
5126
|
-
|
5127
|
-
const offset = ValtypeSize.i32 + i * sizePerEl;
|
5128
|
-
out.push(
|
5129
|
-
...pointer,
|
5130
|
-
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
5131
|
-
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
5132
|
-
...(!typed ? [] : [ // typed presumes !useRawElements
|
5133
|
-
...pointer,
|
5134
|
-
...getNodeType(scope, elements[i]),
|
5135
|
-
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
5136
|
-
])
|
5137
|
-
);
|
5138
|
-
}
|
5139
|
-
|
5140
|
-
// local value as pointer
|
5141
|
-
out.push(...pointer);
|
5142
|
-
if (!intOut) out.push(Opcodes.i32_from_u);
|
5143
|
-
|
5144
|
-
return [ out, pointer ];
|
5145
|
-
};
|
5146
|
-
|
5147
4976
|
const storeArray = (scope, array, index, element) => {
|
5148
4977
|
if (!Array.isArray(element)) element = generate(scope, element);
|
5149
4978
|
if (typeof index === 'number') index = number(index);
|
@@ -5209,25 +5038,83 @@ const byteStringable = str => {
|
|
5209
5038
|
return true;
|
5210
5039
|
};
|
5211
5040
|
|
5212
|
-
const makeString = (scope, str,
|
5213
|
-
|
5214
|
-
|
5041
|
+
const makeString = (scope, str, forceBytestring = undefined) => {
|
5042
|
+
if (str.length === 0) return number(0);
|
5043
|
+
|
5044
|
+
const elements = new Array(str.length);
|
5045
|
+
let bytestring = forceBytestring !== false;
|
5215
5046
|
for (let i = 0; i < str.length; i++) {
|
5216
5047
|
const c = str.charCodeAt(i);
|
5217
|
-
|
5048
|
+
elements[i] = c;
|
5218
5049
|
|
5219
|
-
if (
|
5050
|
+
if (bytestring && c > 0xFF) bytestring = false;
|
5220
5051
|
}
|
5221
5052
|
|
5222
|
-
if (
|
5053
|
+
if (globalThis.precompile) return [
|
5054
|
+
[ Opcodes.const, 'str', str, forceBytestring ]
|
5055
|
+
];
|
5223
5056
|
|
5224
|
-
|
5225
|
-
|
5226
|
-
|
5057
|
+
const ptr = allocStr({ scope, pages }, str, bytestring);
|
5058
|
+
makeData(scope, elements, str, bytestring ? 'i8' : 'i16');
|
5059
|
+
|
5060
|
+
return number(ptr);
|
5227
5061
|
};
|
5228
5062
|
|
5229
|
-
const generateArray = (scope, decl, global = false, name = '$undeclared',
|
5230
|
-
|
5063
|
+
const generateArray = (scope, decl, global = false, name = '$undeclared', staticAlloc = false) => {
|
5064
|
+
const elements = decl.elements;
|
5065
|
+
const length = elements.length;
|
5066
|
+
|
5067
|
+
const out = [];
|
5068
|
+
let pointer;
|
5069
|
+
|
5070
|
+
if (staticAlloc) {
|
5071
|
+
const uniqueName = name === '$undeclared' ? name + uniqId() : name;
|
5072
|
+
|
5073
|
+
const ptr = allocPage(scope, uniqueName);
|
5074
|
+
pointer = number(ptr, Valtype.i32)[0];
|
5075
|
+
|
5076
|
+
scope.arrays ??= new Map();
|
5077
|
+
scope.arrays.set(uniqueName, ptr);
|
5078
|
+
} else {
|
5079
|
+
const tmp = localTmp(scope, '#create_array' + uniqId(), Valtype.i32);
|
5080
|
+
out.push(
|
5081
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
|
5082
|
+
[ Opcodes.local_set, tmp ]
|
5083
|
+
);
|
5084
|
+
|
5085
|
+
pointer = [ Opcodes.local_get, tmp ];
|
5086
|
+
}
|
5087
|
+
|
5088
|
+
// store length
|
5089
|
+
if (length !== 0) out.push(
|
5090
|
+
pointer,
|
5091
|
+
...number(length, Valtype.i32),
|
5092
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
5093
|
+
);
|
5094
|
+
|
5095
|
+
// todo: rewrite below to support RestElement (holdover from makeArray)
|
5096
|
+
for (let i = 0; i < length; i++) {
|
5097
|
+
if (elements[i] == null) continue;
|
5098
|
+
|
5099
|
+
const offset = ValtypeSize.i32 + i * (ValtypeSize[valtype] + 1);
|
5100
|
+
out.push(
|
5101
|
+
pointer,
|
5102
|
+
...generate(scope, elements[i]),
|
5103
|
+
[ Opcodes.store, 0, ...unsignedLEB128(offset) ],
|
5104
|
+
|
5105
|
+
pointer,
|
5106
|
+
...getNodeType(scope, elements[i]),
|
5107
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[valtype]) ]
|
5108
|
+
);
|
5109
|
+
}
|
5110
|
+
|
5111
|
+
// return array pointer
|
5112
|
+
out.push(
|
5113
|
+
pointer,
|
5114
|
+
Opcodes.i32_from_u
|
5115
|
+
);
|
5116
|
+
|
5117
|
+
return out;
|
5231
5118
|
};
|
5232
5119
|
|
5233
5120
|
// opt: do not call ToPropertyKey for non-computed properties as unneeded
|
@@ -5380,7 +5267,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5380
5267
|
if (name.startsWith('__')) name = name.split('_').pop();
|
5381
5268
|
if (name.startsWith('#')) name = '';
|
5382
5269
|
|
5383
|
-
return withType(scope, makeString(scope, name,
|
5270
|
+
return withType(scope, makeString(scope, name, true), TYPES.bytestring);
|
5384
5271
|
}
|
5385
5272
|
|
5386
5273
|
const object = decl.object;
|
@@ -5560,7 +5447,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5560
5447
|
|
5561
5448
|
[TYPES.string]: () => [
|
5562
5449
|
// allocate out string
|
5563
|
-
|
5450
|
+
...number(8, Valtype.i32),
|
5451
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
|
5564
5452
|
[ Opcodes.local_tee, localTmp(scope, '#member_allocd', Valtype.i32) ],
|
5565
5453
|
|
5566
5454
|
// set length to 1
|
@@ -5594,7 +5482,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5594
5482
|
|
5595
5483
|
[TYPES.bytestring]: () => [
|
5596
5484
|
// allocate out string
|
5597
|
-
|
5485
|
+
...number(8, Valtype.i32),
|
5486
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
|
5598
5487
|
[ Opcodes.local_tee, localTmp(scope, '#member_allocd', Valtype.i32) ],
|
5599
5488
|
|
5600
5489
|
// set length to 1
|
@@ -5982,8 +5871,8 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined) =
|
|
5982
5871
|
return out;
|
5983
5872
|
},
|
5984
5873
|
|
5985
|
-
__Porffor_bs: str => makeString(scope, str,
|
5986
|
-
__Porffor_s: str => makeString(scope, str,
|
5874
|
+
__Porffor_bs: str => makeString(scope, str, true),
|
5875
|
+
__Porffor_s: str => makeString(scope, str, false)
|
5987
5876
|
};
|
5988
5877
|
|
5989
5878
|
const { quasis, expressions } = decl.quasi;
|
@@ -6171,7 +6060,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6171
6060
|
}
|
6172
6061
|
|
6173
6062
|
if ([
|
6174
|
-
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
|
6063
|
+
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol, TYPES.function,
|
6175
6064
|
TYPES.set, TYPES.map,
|
6176
6065
|
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
6177
6066
|
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
@@ -6288,13 +6177,12 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6288
6177
|
if (name === 'main') {
|
6289
6178
|
func.gotLastType = true;
|
6290
6179
|
func.export = true;
|
6291
|
-
func.returns = [ valtypeBinary, Valtype.i32 ];
|
6292
6180
|
|
6293
6181
|
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6294
6182
|
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6295
6183
|
|
6296
6184
|
const lastInst = wasm[wasm.length - 1] ?? [ Opcodes.end ];
|
6297
|
-
if (lastInst[0] === Opcodes.drop) {
|
6185
|
+
if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
|
6298
6186
|
if (finalStatement.type.endsWith('Declaration')) {
|
6299
6187
|
// final statement is decl, force undefined
|
6300
6188
|
disposeLeftover(wasm);
|
@@ -6332,7 +6220,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6332
6220
|
}
|
6333
6221
|
} else {
|
6334
6222
|
// add end return if not found
|
6335
|
-
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm)
|
6223
|
+
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) < func.returns.length) {
|
6336
6224
|
wasm.push(...generateReturn(func, {}));
|
6337
6225
|
}
|
6338
6226
|
}
|
@@ -6572,7 +6460,6 @@ export default program => {
|
|
6572
6460
|
builtinFuncs = new BuiltinFuncs();
|
6573
6461
|
builtinVars = new BuiltinVars({ builtinFuncs });
|
6574
6462
|
prototypeFuncs = new PrototypeFuncs();
|
6575
|
-
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
6576
6463
|
|
6577
6464
|
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
6578
6465
|
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|