porffor 0.47.6 → 0.47.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/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/function.ts +12 -3
- package/compiler/builtins.js +2 -2
- package/compiler/builtins_objects.js +2 -2
- package/compiler/builtins_precompiled.js +705 -770
- package/compiler/cache.js +44 -0
- package/compiler/codegen.js +182 -302
- 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,15 @@ 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
|
-
return makeArray(scope, {
|
2227
|
-
rawElements: new Array(length)
|
2228
|
-
}, _global, _name, true, itemType, true);
|
2229
|
-
},
|
2205
|
+
() => [ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ] ],
|
2230
2206
|
() => {
|
2231
2207
|
optUnused = true;
|
2232
2208
|
return unusedValue;
|
@@ -2252,7 +2228,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2252
2228
|
] : []),
|
2253
2229
|
|
2254
2230
|
...(useLengthCache ? [
|
2255
|
-
...
|
2231
|
+
...ArrayUtil.getLengthI32(getPointer),
|
2256
2232
|
[ Opcodes.local_set, lengthLocal ],
|
2257
2233
|
] : []),
|
2258
2234
|
|
@@ -3335,7 +3311,6 @@ const isIdentAssignable = (scope, name, op = '=') => {
|
|
3335
3311
|
return false;
|
3336
3312
|
};
|
3337
3313
|
|
3338
|
-
// todo: optimize this func for valueUnused
|
3339
3314
|
const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
3340
3315
|
const { type, name } = decl.left;
|
3341
3316
|
const [ local, isGlobal ] = lookupName(scope, name);
|
@@ -3361,8 +3336,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3361
3336
|
|
3362
3337
|
// hack: .length setter
|
3363
3338
|
if (type === 'MemberExpression' && decl.left.property.name === 'length' && !decl._internalAssign) {
|
3364
|
-
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
3365
|
-
|
3339
|
+
const newValueTmp = !valueUnused && localTmp(scope, '__length_setter_tmp');
|
3340
|
+
let pointerTmp = op !== '=' && localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
3366
3341
|
|
3367
3342
|
const out = [
|
3368
3343
|
...generate(scope, decl.left.object),
|
@@ -3375,23 +3350,32 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3375
3350
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3376
3351
|
Opcodes.i32_from_u
|
3377
3352
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
3378
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3353
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3379
3354
|
|
3380
3355
|
Opcodes.i32_to_u,
|
3381
3356
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3382
3357
|
|
3383
|
-
[ Opcodes.local_get, newValueTmp ]
|
3358
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3384
3359
|
];
|
3385
3360
|
|
3386
3361
|
const type = getNodeType(scope, decl.left.object);
|
3387
3362
|
const known = knownType(scope, type);
|
3388
3363
|
if (known != null && typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3389
3364
|
...out,
|
3390
|
-
...(
|
3365
|
+
...optional([ Opcodes.local_tee, pointerTmp ]),
|
3391
3366
|
|
3392
|
-
...lengthTypeWasm
|
3367
|
+
...lengthTypeWasm,
|
3368
|
+
...optional(number(UNDEFINED), valueUnused)
|
3393
3369
|
];
|
3394
3370
|
|
3371
|
+
pointerTmp ||= localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
3372
|
+
|
3373
|
+
const slow = generate(scope, {
|
3374
|
+
...decl,
|
3375
|
+
_internalAssign: true
|
3376
|
+
});
|
3377
|
+
if (valueUnused) disposeLeftover(slow);
|
3378
|
+
|
3395
3379
|
return [
|
3396
3380
|
...out,
|
3397
3381
|
[ Opcodes.local_set, pointerTmp ],
|
@@ -3399,33 +3383,31 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3399
3383
|
...type,
|
3400
3384
|
...number(TYPE_FLAGS.length, Valtype.i32),
|
3401
3385
|
[ Opcodes.i32_and ],
|
3402
|
-
[ Opcodes.if, valtypeBinary ],
|
3386
|
+
[ Opcodes.if, valueUnused ? Blocktype.void : valtypeBinary ],
|
3403
3387
|
[ Opcodes.local_get, pointerTmp ],
|
3404
3388
|
...lengthTypeWasm,
|
3405
3389
|
[ Opcodes.else ],
|
3406
|
-
...
|
3407
|
-
|
3408
|
-
|
3409
|
-
}),
|
3410
|
-
[ Opcodes.end ]
|
3390
|
+
...slow,
|
3391
|
+
[ Opcodes.end ],
|
3392
|
+
...optional(number(UNDEFINED), valueUnused)
|
3411
3393
|
];
|
3412
3394
|
}
|
3413
3395
|
|
3414
3396
|
// arr[i]
|
3415
3397
|
if (type === 'MemberExpression') {
|
3416
|
-
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
3398
|
+
const newValueTmp = !valueUnused && localTmp(scope, '#member_setter_val_tmp');
|
3417
3399
|
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
3418
3400
|
|
3419
3401
|
const object = decl.left.object;
|
3420
3402
|
const property = getProperty(decl.left);
|
3421
3403
|
|
3422
3404
|
// todo/perf: use i32 object (and prop?) locals
|
3423
|
-
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#
|
3405
|
+
const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj_assign') ] ];
|
3424
3406
|
const propertyWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_prop_assign') ] ];
|
3425
3407
|
|
3426
3408
|
return [
|
3427
3409
|
...generate(scope, object),
|
3428
|
-
[ Opcodes.local_set,
|
3410
|
+
[ Opcodes.local_set, objectWasm[0][1] ],
|
3429
3411
|
|
3430
3412
|
...generate(scope, property, false, '#member_prop_assign'),
|
3431
3413
|
[ Opcodes.local_set, localTmp(scope, '#member_prop_assign') ],
|
@@ -3454,14 +3436,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3454
3436
|
[ Opcodes.local_get, pointerTmp ],
|
3455
3437
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3456
3438
|
], getNodeType(scope, decl.right), false, name, true)),
|
3457
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3439
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3458
3440
|
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3459
3441
|
|
3460
3442
|
[ Opcodes.local_get, pointerTmp ],
|
3461
3443
|
...getNodeType(scope, decl),
|
3462
3444
|
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
3463
3445
|
|
3464
|
-
[ Opcodes.local_get, newValueTmp ]
|
3446
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3465
3447
|
],
|
3466
3448
|
|
3467
3449
|
...wrapBC({
|
@@ -3474,7 +3456,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3474
3456
|
[ Opcodes.i32_load8_u, 0, 4 ],
|
3475
3457
|
Opcodes.i32_from_u
|
3476
3458
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3477
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3459
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3478
3460
|
|
3479
3461
|
Opcodes.i32_to_u,
|
3480
3462
|
[ Opcodes.i32_store8, 0, 4 ]
|
@@ -3488,7 +3470,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3488
3470
|
[ Opcodes.i32_load8_u, 0, 4 ],
|
3489
3471
|
Opcodes.i32_from_u
|
3490
3472
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3491
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3473
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3492
3474
|
|
3493
3475
|
...number(0),
|
3494
3476
|
[ Opcodes.f64_max ],
|
@@ -3506,7 +3488,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3506
3488
|
[ Opcodes.i32_load8_s, 0, 4 ],
|
3507
3489
|
Opcodes.i32_from
|
3508
3490
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3509
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3491
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3510
3492
|
|
3511
3493
|
Opcodes.i32_to,
|
3512
3494
|
[ Opcodes.i32_store8, 0, 4 ]
|
@@ -3522,7 +3504,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3522
3504
|
[ Opcodes.i32_load16_u, 0, 4 ],
|
3523
3505
|
Opcodes.i32_from_u
|
3524
3506
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3525
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3507
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3526
3508
|
|
3527
3509
|
Opcodes.i32_to_u,
|
3528
3510
|
[ Opcodes.i32_store16, 0, 4 ]
|
@@ -3538,7 +3520,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3538
3520
|
[ Opcodes.i32_load16_s, 0, 4 ],
|
3539
3521
|
Opcodes.i32_from
|
3540
3522
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3541
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3523
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3542
3524
|
|
3543
3525
|
Opcodes.i32_to,
|
3544
3526
|
[ Opcodes.i32_store16, 0, 4 ]
|
@@ -3554,7 +3536,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3554
3536
|
[ Opcodes.i32_load, 0, 4 ],
|
3555
3537
|
Opcodes.i32_from_u
|
3556
3538
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3557
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3539
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3558
3540
|
|
3559
3541
|
Opcodes.i32_to_u,
|
3560
3542
|
[ Opcodes.i32_store, 0, 4 ]
|
@@ -3570,7 +3552,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3570
3552
|
[ Opcodes.i32_load, 0, 4 ],
|
3571
3553
|
Opcodes.i32_from
|
3572
3554
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3573
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3555
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3574
3556
|
|
3575
3557
|
Opcodes.i32_to,
|
3576
3558
|
[ Opcodes.i32_store, 0, 4 ]
|
@@ -3586,7 +3568,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3586
3568
|
[ Opcodes.f32_load, 0, 4 ],
|
3587
3569
|
[ Opcodes.f64_promote_f32 ]
|
3588
3570
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3589
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3571
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3590
3572
|
|
3591
3573
|
[ Opcodes.f32_demote_f64 ],
|
3592
3574
|
[ Opcodes.f32_store, 0, 4 ]
|
@@ -3601,7 +3583,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3601
3583
|
[ Opcodes.local_get, pointerTmp ],
|
3602
3584
|
[ Opcodes.f64_load, 0, 4 ]
|
3603
3585
|
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
3604
|
-
[ Opcodes.local_tee, newValueTmp ],
|
3586
|
+
...optional([ Opcodes.local_tee, newValueTmp ]),
|
3605
3587
|
|
3606
3588
|
[ Opcodes.f64_store, 0, 4 ]
|
3607
3589
|
],
|
@@ -3616,12 +3598,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3616
3598
|
],
|
3617
3599
|
postlude: [
|
3618
3600
|
// setLastType(scope, TYPES.number)
|
3619
|
-
[ Opcodes.local_get, newValueTmp ]
|
3601
|
+
...optional([ Opcodes.local_get, newValueTmp ])
|
3620
3602
|
]
|
3621
3603
|
}),
|
3622
3604
|
} : {}),
|
3623
3605
|
|
3624
|
-
[TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined',
|
3606
|
+
[TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined', !valueUnused),
|
3625
3607
|
|
3626
3608
|
// default: internalThrow(scope, 'TypeError', `Cannot assign member with this type`)
|
3627
3609
|
default: () => [
|
@@ -3652,9 +3634,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3652
3634
|
|
3653
3635
|
[ Opcodes.call, includeBuiltin(scope, scope.strict ? '__Porffor_object_setStrict' : '__Porffor_object_set').index ],
|
3654
3636
|
[ Opcodes.drop ],
|
3637
|
+
...(valueUnused ? [ [ Opcodes.drop ] ] : [])
|
3655
3638
|
// ...setLastType(scope, getNodeType(scope, decl)),
|
3656
3639
|
]
|
3657
|
-
}, valtypeBinary)
|
3640
|
+
}, valueUnused ? Blocktype.void : valtypeBinary),
|
3641
|
+
...optional(number(UNDEFINED), valueUnused)
|
3658
3642
|
];
|
3659
3643
|
}
|
3660
3644
|
|
@@ -3682,7 +3666,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3682
3666
|
// set global and return (eg a = 2)
|
3683
3667
|
return [
|
3684
3668
|
...generateVarDstr(scope, 'var', name, decl.right, undefined, true),
|
3685
|
-
...generate(scope, decl.left)
|
3669
|
+
...optional(generate(scope, decl.left), !valueUnused),
|
3670
|
+
...optional(number(UNDEFINED), valueUnused)
|
3686
3671
|
];
|
3687
3672
|
}
|
3688
3673
|
|
@@ -3690,7 +3675,10 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3690
3675
|
if (local.metadata?.kind === 'const') return internalThrow(scope, 'TypeError', `Cannot assign to constant variable ${name}`, true);
|
3691
3676
|
|
3692
3677
|
if (op === '=') {
|
3693
|
-
|
3678
|
+
const out = setLocalWithType(scope, name, isGlobal, decl.right, !valueUnused);
|
3679
|
+
|
3680
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3681
|
+
return out;
|
3694
3682
|
}
|
3695
3683
|
|
3696
3684
|
if (op === '||' || op === '&&' || op === '??') {
|
@@ -3713,12 +3701,15 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3713
3701
|
];
|
3714
3702
|
}
|
3715
3703
|
|
3716
|
-
|
3704
|
+
const out = setLocalWithType(
|
3717
3705
|
scope, name, isGlobal,
|
3718
3706
|
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
|
-
|
3707
|
+
!valueUnused,
|
3720
3708
|
getNodeType(scope, decl)
|
3721
3709
|
);
|
3710
|
+
|
3711
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3712
|
+
return out;
|
3722
3713
|
};
|
3723
3714
|
|
3724
3715
|
const ifIdentifierErrors = (scope, decl) => {
|
@@ -3859,15 +3850,15 @@ const generateUnary = (scope, decl) => {
|
|
3859
3850
|
disposeLeftover(out);
|
3860
3851
|
|
3861
3852
|
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'
|
3853
|
+
[ TYPES.number, () => makeString(scope, 'number') ],
|
3854
|
+
[ TYPES.boolean, () => makeString(scope, 'boolean') ],
|
3855
|
+
[ [ TYPES.string, TYPES.bytestring ], () => makeString(scope, 'string') ],
|
3856
|
+
[ [ TYPES.undefined, TYPES.empty ], () => makeString(scope, 'undefined') ],
|
3857
|
+
[ TYPES.function, () => makeString(scope, 'function') ],
|
3858
|
+
[ TYPES.symbol, () => makeString(scope, 'symbol') ],
|
3868
3859
|
|
3869
3860
|
// object and internal types
|
3870
|
-
[ 'default', () => makeString(scope, 'object'
|
3861
|
+
[ 'default', () => makeString(scope, 'object') ],
|
3871
3862
|
]));
|
3872
3863
|
|
3873
3864
|
return out;
|
@@ -3903,6 +3894,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3903
3894
|
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
3904
3895
|
if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3905
3896
|
|
3897
|
+
if (valueUnused) out.push(...number(UNDEFINED));
|
3906
3898
|
return out;
|
3907
3899
|
}
|
3908
3900
|
|
@@ -3920,7 +3912,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3920
3912
|
prefix: true,
|
3921
3913
|
argument: decl.argument
|
3922
3914
|
}),
|
3923
|
-
[ decl.prefix ? Opcodes.local_set : Opcodes.local_tee, tmp ],
|
3915
|
+
[ decl.prefix || valueUnused ? Opcodes.local_set : Opcodes.local_tee, tmp ],
|
3924
3916
|
|
3925
3917
|
// x = tmp + 1
|
3926
3918
|
...generate(scope, {
|
@@ -3933,8 +3925,9 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3933
3925
|
left: { type: 'Identifier', name: '#updatetmp' },
|
3934
3926
|
right: { type: 'Literal', value: 1 }
|
3935
3927
|
}
|
3936
|
-
}),
|
3937
|
-
...(decl.prefix ? [] : [ [ Opcodes.drop ] ])
|
3928
|
+
}, _global, _name, valueUnused),
|
3929
|
+
...(decl.prefix || valueUnused ? [] : [ [ Opcodes.drop ] ]),
|
3930
|
+
...optional(number(UNDEFINED), valueUnused)
|
3938
3931
|
];
|
3939
3932
|
};
|
3940
3933
|
|
@@ -4897,18 +4890,7 @@ const generateMeta = (scope, decl) => {
|
|
4897
4890
|
};
|
4898
4891
|
|
4899
4892
|
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
|
-
};
|
4893
|
+
const allocPage = (scope, name) => _allocPage({ scope, pages }, name);
|
4912
4894
|
|
4913
4895
|
const itemTypeToValtype = {
|
4914
4896
|
i32: 'i32',
|
@@ -4942,18 +4924,23 @@ const compileBytes = (val, itemType) => {
|
|
4942
4924
|
}
|
4943
4925
|
};
|
4944
4926
|
|
4945
|
-
const makeData = (scope, elements, page = null, itemType
|
4927
|
+
const makeData = (scope, elements, page = null, itemType = 'i8') => {
|
4928
|
+
// if data for page already exists, abort
|
4929
|
+
if (page && data.find(x => x.page === page)) return;
|
4930
|
+
|
4946
4931
|
const length = elements.length;
|
4947
4932
|
|
4948
4933
|
// if length is 0 memory/data will just be 0000... anyway
|
4949
4934
|
if (length === 0) return false;
|
4950
4935
|
|
4951
4936
|
let bytes = compileBytes(length, 'i32');
|
4952
|
-
|
4953
|
-
|
4954
|
-
|
4955
|
-
|
4956
|
-
|
4937
|
+
if (itemType === 'i8') {
|
4938
|
+
bytes = bytes.concat(elements);
|
4939
|
+
} else {
|
4940
|
+
for (let i = 0; i < length; i++) {
|
4941
|
+
if (elements[i] == null) continue;
|
4942
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
4943
|
+
}
|
4957
4944
|
}
|
4958
4945
|
|
4959
4946
|
const obj = { bytes, page };
|
@@ -4981,169 +4968,6 @@ const printStaticStr = str => {
|
|
4981
4968
|
return out;
|
4982
4969
|
};
|
4983
4970
|
|
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
4971
|
const storeArray = (scope, array, index, element) => {
|
5148
4972
|
if (!Array.isArray(element)) element = generate(scope, element);
|
5149
4973
|
if (typeof index === 'number') index = number(index);
|
@@ -5209,25 +5033,83 @@ const byteStringable = str => {
|
|
5209
5033
|
return true;
|
5210
5034
|
};
|
5211
5035
|
|
5212
|
-
const makeString = (scope, str,
|
5213
|
-
|
5214
|
-
|
5036
|
+
const makeString = (scope, str, forceBytestring = undefined) => {
|
5037
|
+
if (str.length === 0) return number(0);
|
5038
|
+
|
5039
|
+
const elements = new Array(str.length);
|
5040
|
+
let bytestring = forceBytestring !== false;
|
5215
5041
|
for (let i = 0; i < str.length; i++) {
|
5216
5042
|
const c = str.charCodeAt(i);
|
5217
|
-
|
5043
|
+
elements[i] = c;
|
5218
5044
|
|
5219
|
-
if (
|
5045
|
+
if (bytestring && c > 0xFF) bytestring = false;
|
5220
5046
|
}
|
5221
5047
|
|
5222
|
-
if (
|
5048
|
+
if (globalThis.precompile) return [
|
5049
|
+
[ Opcodes.const, 'str', str, forceBytestring ]
|
5050
|
+
];
|
5051
|
+
|
5052
|
+
const ptr = allocStr({ scope, pages }, str, bytestring);
|
5053
|
+
makeData(scope, elements, str, bytestring ? 'i8' : 'i16');
|
5223
5054
|
|
5224
|
-
return
|
5225
|
-
rawElements
|
5226
|
-
}, global, name, false, byteStringable ? 'i8' : 'i16')[0];
|
5055
|
+
return number(ptr);
|
5227
5056
|
};
|
5228
5057
|
|
5229
|
-
const generateArray = (scope, decl, global = false, name = '$undeclared',
|
5230
|
-
|
5058
|
+
const generateArray = (scope, decl, global = false, name = '$undeclared', staticAlloc = false) => {
|
5059
|
+
const elements = decl.elements;
|
5060
|
+
const length = elements.length;
|
5061
|
+
|
5062
|
+
const out = [];
|
5063
|
+
let pointer;
|
5064
|
+
|
5065
|
+
if (staticAlloc) {
|
5066
|
+
const uniqueName = name === '$undeclared' ? name + uniqId() : name;
|
5067
|
+
|
5068
|
+
const ptr = allocPage(scope, uniqueName);
|
5069
|
+
pointer = number(ptr, Valtype.i32)[0];
|
5070
|
+
|
5071
|
+
scope.arrays ??= new Map();
|
5072
|
+
scope.arrays.set(uniqueName, ptr);
|
5073
|
+
} else {
|
5074
|
+
const tmp = localTmp(scope, '#create_array' + uniqId(), Valtype.i32);
|
5075
|
+
out.push(
|
5076
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
|
5077
|
+
[ Opcodes.local_set, tmp ]
|
5078
|
+
);
|
5079
|
+
|
5080
|
+
pointer = [ Opcodes.local_get, tmp ];
|
5081
|
+
}
|
5082
|
+
|
5083
|
+
// store length
|
5084
|
+
if (length !== 0) out.push(
|
5085
|
+
pointer,
|
5086
|
+
...number(length, Valtype.i32),
|
5087
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
5088
|
+
);
|
5089
|
+
|
5090
|
+
// todo: rewrite below to support RestElement (holdover from makeArray)
|
5091
|
+
for (let i = 0; i < length; i++) {
|
5092
|
+
if (elements[i] == null) continue;
|
5093
|
+
|
5094
|
+
const offset = ValtypeSize.i32 + i * (ValtypeSize[valtype] + 1);
|
5095
|
+
out.push(
|
5096
|
+
pointer,
|
5097
|
+
...generate(scope, elements[i]),
|
5098
|
+
[ Opcodes.store, 0, ...unsignedLEB128(offset) ],
|
5099
|
+
|
5100
|
+
pointer,
|
5101
|
+
...getNodeType(scope, elements[i]),
|
5102
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[valtype]) ]
|
5103
|
+
);
|
5104
|
+
}
|
5105
|
+
|
5106
|
+
// return array pointer
|
5107
|
+
out.push(
|
5108
|
+
pointer,
|
5109
|
+
Opcodes.i32_from_u
|
5110
|
+
);
|
5111
|
+
|
5112
|
+
return out;
|
5231
5113
|
};
|
5232
5114
|
|
5233
5115
|
// opt: do not call ToPropertyKey for non-computed properties as unneeded
|
@@ -5380,7 +5262,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5380
5262
|
if (name.startsWith('__')) name = name.split('_').pop();
|
5381
5263
|
if (name.startsWith('#')) name = '';
|
5382
5264
|
|
5383
|
-
return withType(scope, makeString(scope, name,
|
5265
|
+
return withType(scope, makeString(scope, name, true), TYPES.bytestring);
|
5384
5266
|
}
|
5385
5267
|
|
5386
5268
|
const object = decl.object;
|
@@ -5982,8 +5864,8 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined) =
|
|
5982
5864
|
return out;
|
5983
5865
|
},
|
5984
5866
|
|
5985
|
-
__Porffor_bs: str => makeString(scope, str,
|
5986
|
-
__Porffor_s: str => makeString(scope, str,
|
5867
|
+
__Porffor_bs: str => makeString(scope, str, true),
|
5868
|
+
__Porffor_s: str => makeString(scope, str, false)
|
5987
5869
|
};
|
5988
5870
|
|
5989
5871
|
const { quasis, expressions } = decl.quasi;
|
@@ -6171,7 +6053,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6171
6053
|
}
|
6172
6054
|
|
6173
6055
|
if ([
|
6174
|
-
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
|
6056
|
+
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol, TYPES.function,
|
6175
6057
|
TYPES.set, TYPES.map,
|
6176
6058
|
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
6177
6059
|
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
@@ -6288,13 +6170,12 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6288
6170
|
if (name === 'main') {
|
6289
6171
|
func.gotLastType = true;
|
6290
6172
|
func.export = true;
|
6291
|
-
func.returns = [ valtypeBinary, Valtype.i32 ];
|
6292
6173
|
|
6293
6174
|
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6294
6175
|
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6295
6176
|
|
6296
6177
|
const lastInst = wasm[wasm.length - 1] ?? [ Opcodes.end ];
|
6297
|
-
if (lastInst[0] === Opcodes.drop) {
|
6178
|
+
if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
|
6298
6179
|
if (finalStatement.type.endsWith('Declaration')) {
|
6299
6180
|
// final statement is decl, force undefined
|
6300
6181
|
disposeLeftover(wasm);
|
@@ -6332,7 +6213,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6332
6213
|
}
|
6333
6214
|
} else {
|
6334
6215
|
// add end return if not found
|
6335
|
-
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm)
|
6216
|
+
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) < func.returns.length) {
|
6336
6217
|
wasm.push(...generateReturn(func, {}));
|
6337
6218
|
}
|
6338
6219
|
}
|
@@ -6572,7 +6453,6 @@ export default program => {
|
|
6572
6453
|
builtinFuncs = new BuiltinFuncs();
|
6573
6454
|
builtinVars = new BuiltinVars({ builtinFuncs });
|
6574
6455
|
prototypeFuncs = new PrototypeFuncs();
|
6575
|
-
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
6576
6456
|
|
6577
6457
|
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
6578
6458
|
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|