porffor 0.16.0-30af62694 → 0.16.0-4d434e797
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 +1 -1
- package/README.md +5 -17
- package/compiler/2c.js +75 -15
- package/compiler/allocators.js +128 -0
- package/compiler/assemble.js +7 -1
- package/compiler/builtins/array.ts +72 -5
- package/compiler/builtins/date.ts +3 -30
- package/compiler/builtins/number.ts +10 -21
- package/compiler/builtins/porffor.d.ts +7 -0
- package/compiler/builtins/set.ts +2 -5
- package/compiler/builtins/z_ecma262.ts +62 -0
- package/compiler/codegen.js +277 -331
- package/compiler/cyclone.js +11 -11
- package/compiler/generated_builtins.js +113 -75
- package/compiler/index.js +15 -1
- package/compiler/opt.js +8 -6
- package/compiler/parse.js +1 -7
- package/compiler/pgo.js +5 -0
- package/compiler/precompile.js +12 -7
- package/compiler/prefs.js +2 -3
- package/compiler/prototype.js +34 -43
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +3 -2
- package/package.json +2 -4
- package/runner/index.js +13 -3
- package/no_pgo.txt +0 -923
- package/pgo.txt +0 -916
package/compiler/codegen.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype,
|
2
|
-
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
|
1
|
+
import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector, read_signedLEB128 } from './encoding.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
5
|
import { PrototypeFuncs } from './prototype.js';
|
@@ -9,15 +9,16 @@ import * as Rhemyn from '../rhemyn/compile.js';
|
|
9
9
|
import parse from './parse.js';
|
10
10
|
import { log } from './log.js';
|
11
11
|
import Prefs from './prefs.js';
|
12
|
+
import makeAllocator from './allocators.js';
|
12
13
|
|
13
14
|
let globals = {};
|
14
|
-
let globalInd = 0;
|
15
15
|
let tags = [];
|
16
16
|
let funcs = [];
|
17
17
|
let exceptions = [];
|
18
18
|
let funcIndex = {};
|
19
19
|
let currentFuncIndex = importedFuncs.length;
|
20
20
|
let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
|
21
|
+
let allocator;
|
21
22
|
|
22
23
|
class TodoError extends Error {
|
23
24
|
constructor(message) {
|
@@ -32,11 +33,6 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
32
33
|
|
33
34
|
case 'runtime':
|
34
35
|
return internalThrow(scope, 'TodoError', msg, expectsValue);
|
35
|
-
|
36
|
-
// return [
|
37
|
-
// ...debug(`todo! ${msg}`),
|
38
|
-
// [ Opcodes.unreachable ]
|
39
|
-
// ];
|
40
36
|
}
|
41
37
|
};
|
42
38
|
|
@@ -181,12 +177,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
181
177
|
continue;
|
182
178
|
}
|
183
179
|
|
184
|
-
if (asm[0] === 'memory') {
|
185
|
-
allocPage(scope, 'asm instrinsic');
|
186
|
-
// todo: add to store/load offset insts
|
187
|
-
continue;
|
188
|
-
}
|
189
|
-
|
190
180
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
191
181
|
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
192
182
|
|
@@ -433,63 +423,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
433
423
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
434
424
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
435
425
|
|
436
|
-
if (assign && Prefs.aotPointerOpt) {
|
437
|
-
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
438
|
-
|
439
|
-
return [
|
440
|
-
// setup right
|
441
|
-
...right,
|
442
|
-
Opcodes.i32_to_u,
|
443
|
-
[ Opcodes.local_set, rightPointer ],
|
444
|
-
|
445
|
-
// calculate length
|
446
|
-
...number(0, Valtype.i32), // base 0 for store later
|
447
|
-
|
448
|
-
...number(pointer, Valtype.i32),
|
449
|
-
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
450
|
-
[ Opcodes.local_tee, leftLength ],
|
451
|
-
|
452
|
-
[ Opcodes.local_get, rightPointer ],
|
453
|
-
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
454
|
-
[ Opcodes.local_tee, rightLength ],
|
455
|
-
|
456
|
-
[ Opcodes.i32_add ],
|
457
|
-
|
458
|
-
// store length
|
459
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
|
460
|
-
|
461
|
-
// copy right
|
462
|
-
// dst = out pointer + length size + current length * sizeof valtype
|
463
|
-
...number(pointer + ValtypeSize.i32, Valtype.i32),
|
464
|
-
|
465
|
-
[ Opcodes.local_get, leftLength ],
|
466
|
-
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
467
|
-
[ Opcodes.i32_mul ],
|
468
|
-
[ Opcodes.i32_add ],
|
469
|
-
|
470
|
-
// src = right pointer + length size
|
471
|
-
[ Opcodes.local_get, rightPointer ],
|
472
|
-
...number(ValtypeSize.i32, Valtype.i32),
|
473
|
-
[ Opcodes.i32_add ],
|
474
|
-
|
475
|
-
// size = right length * sizeof valtype
|
476
|
-
[ Opcodes.local_get, rightLength ],
|
477
|
-
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
478
|
-
[ Opcodes.i32_mul ],
|
479
|
-
|
480
|
-
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
481
|
-
|
482
|
-
// return new string (page)
|
483
|
-
...number(pointer)
|
484
|
-
];
|
485
|
-
}
|
486
|
-
|
487
426
|
const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
|
488
427
|
|
489
428
|
// alloc/assign array
|
490
|
-
const [ , pointer ] = makeArray(scope, {
|
429
|
+
const [ out, pointer ] = makeArray(scope, {
|
491
430
|
rawElements: new Array(0)
|
492
|
-
}, global, name, true, 'i16');
|
431
|
+
}, assign ? false : global, assign ? undefined : name, true, 'i16', true);
|
493
432
|
|
494
433
|
return [
|
495
434
|
// setup left
|
@@ -503,7 +442,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
503
442
|
[ Opcodes.local_set, rightPointer ],
|
504
443
|
|
505
444
|
// calculate length
|
506
|
-
...
|
445
|
+
...out,
|
507
446
|
|
508
447
|
[ Opcodes.local_get, leftPointer ],
|
509
448
|
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
@@ -516,11 +455,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
516
455
|
[ Opcodes.i32_add ],
|
517
456
|
|
518
457
|
// store length
|
519
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
458
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
520
459
|
|
521
460
|
// copy left
|
522
461
|
// dst = out pointer + length size
|
523
|
-
...
|
462
|
+
...pointer,
|
463
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
464
|
+
[ Opcodes.i32_add ],
|
524
465
|
|
525
466
|
// src = left pointer + length size
|
526
467
|
[ Opcodes.local_get, leftPointer ],
|
@@ -533,7 +474,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
533
474
|
|
534
475
|
// copy right
|
535
476
|
// dst = out pointer + length size + left length * sizeof valtype
|
536
|
-
...
|
477
|
+
...pointer,
|
478
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
479
|
+
[ Opcodes.i32_add ],
|
537
480
|
|
538
481
|
[ Opcodes.local_get, leftLength ],
|
539
482
|
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
@@ -553,7 +496,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
553
496
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
554
497
|
|
555
498
|
// return new string (page)
|
556
|
-
...
|
499
|
+
...pointer,
|
500
|
+
Opcodes.i32_from_u
|
557
501
|
];
|
558
502
|
};
|
559
503
|
|
@@ -669,10 +613,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
669
613
|
};
|
670
614
|
|
671
615
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
672
|
-
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
673
|
-
|
674
|
-
|
675
|
-
];
|
616
|
+
// if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
617
|
+
// ...wasm,
|
618
|
+
// ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
619
|
+
// ];
|
676
620
|
// if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
|
677
621
|
|
678
622
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
@@ -1014,12 +958,9 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1014
958
|
[ Opcodes.end ],
|
1015
959
|
]));
|
1016
960
|
|
1017
|
-
//
|
1018
|
-
|
1019
|
-
|
1020
|
-
// endOut.push(stringOnly([ Opcodes.end ]));
|
1021
|
-
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1022
|
-
// }
|
961
|
+
// add a surrounding block
|
962
|
+
startOut.push(stringOnly([ Opcodes.block, Valtype.i32 ]));
|
963
|
+
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1023
964
|
}
|
1024
965
|
|
1025
966
|
return finalize([
|
@@ -1054,7 +995,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1054
995
|
});
|
1055
996
|
};
|
1056
997
|
|
1057
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
998
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1058
999
|
const existing = funcs.find(x => x.name === name);
|
1059
1000
|
if (existing) return existing;
|
1060
1001
|
|
@@ -1068,7 +1009,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1068
1009
|
|
1069
1010
|
for (const x of _data) {
|
1070
1011
|
const copy = { ...x };
|
1071
|
-
copy.offset += pages.size * pageSize;
|
1012
|
+
if (copy.offset != null) copy.offset += pages.size * pageSize;
|
1072
1013
|
data.push(copy);
|
1073
1014
|
}
|
1074
1015
|
|
@@ -1091,9 +1032,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1091
1032
|
|
1092
1033
|
let baseGlobalIdx, i = 0;
|
1093
1034
|
for (const type of globalTypes) {
|
1094
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1035
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
|
1095
1036
|
|
1096
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1037
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
|
1097
1038
|
i++;
|
1098
1039
|
}
|
1099
1040
|
|
@@ -1106,11 +1047,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1106
1047
|
}
|
1107
1048
|
}
|
1108
1049
|
|
1109
|
-
if (table)
|
1110
|
-
|
1111
|
-
inst.
|
1112
|
-
|
1050
|
+
if (table) {
|
1051
|
+
for (const inst of wasm) {
|
1052
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1053
|
+
inst.splice(2, 99);
|
1054
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1055
|
+
}
|
1113
1056
|
}
|
1057
|
+
|
1058
|
+
funcs.table = true;
|
1114
1059
|
}
|
1115
1060
|
|
1116
1061
|
func.wasm = wasm;
|
@@ -1318,7 +1263,15 @@ const getNodeType = (scope, node) => {
|
|
1318
1263
|
}
|
1319
1264
|
|
1320
1265
|
if (node.type === 'AssignmentExpression') {
|
1321
|
-
|
1266
|
+
const op = node.operator.slice(0, -1) || '=';
|
1267
|
+
if (op === '=') return getNodeType(scope, node.right);
|
1268
|
+
|
1269
|
+
return getNodeType(scope, {
|
1270
|
+
type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
|
1271
|
+
left: node.left,
|
1272
|
+
right: node.right,
|
1273
|
+
operator: op
|
1274
|
+
});
|
1322
1275
|
}
|
1323
1276
|
|
1324
1277
|
if (node.type === 'ArrayExpression') {
|
@@ -1337,23 +1290,6 @@ const getNodeType = (scope, node) => {
|
|
1337
1290
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1338
1291
|
|
1339
1292
|
return TYPES.number;
|
1340
|
-
|
1341
|
-
// todo: string concat types
|
1342
|
-
// if (node.operator !== '+') return TYPES.number;
|
1343
|
-
// else return [
|
1344
|
-
// // if left is string
|
1345
|
-
// ...getNodeType(scope, node.left),
|
1346
|
-
// ...number(TYPES.string, Valtype.i32),
|
1347
|
-
// [ Opcodes.i32_eq ],
|
1348
|
-
|
1349
|
-
// // if right is string
|
1350
|
-
// ...getNodeType(scope, node.right),
|
1351
|
-
// ...number(TYPES.string, Valtype.i32),
|
1352
|
-
// [ Opcodes.i32_eq ],
|
1353
|
-
|
1354
|
-
// // if either are true
|
1355
|
-
// [ Opcodes.i32_or ],
|
1356
|
-
// ];
|
1357
1293
|
}
|
1358
1294
|
|
1359
1295
|
if (node.type === 'UnaryExpression') {
|
@@ -1373,7 +1309,6 @@ const getNodeType = (scope, node) => {
|
|
1373
1309
|
if (Prefs.fastLength) return TYPES.number;
|
1374
1310
|
}
|
1375
1311
|
|
1376
|
-
|
1377
1312
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1378
1313
|
if (objectKnownType != null) {
|
1379
1314
|
if (name === 'length') {
|
@@ -1384,7 +1319,6 @@ const getNodeType = (scope, node) => {
|
|
1384
1319
|
if (node.computed) {
|
1385
1320
|
if (objectKnownType === TYPES.string) return TYPES.string;
|
1386
1321
|
if (objectKnownType === TYPES.bytestring) return TYPES.bytestring;
|
1387
|
-
if (objectKnownType === TYPES.array) return TYPES.number;
|
1388
1322
|
}
|
1389
1323
|
}
|
1390
1324
|
|
@@ -1450,10 +1384,10 @@ const countLeftover = wasm => {
|
|
1450
1384
|
|
1451
1385
|
if (depth === 0)
|
1452
1386
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1453
|
-
else if ([null, 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.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] <
|
1387
|
+
else if ([null, 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.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)) {}
|
1454
1388
|
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++;
|
1455
1389
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1456
|
-
else if (Opcodes.memory_copy[0]
|
1390
|
+
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1457
1391
|
else if (inst[0] === Opcodes.return) count = 0;
|
1458
1392
|
else if (inst[0] === Opcodes.call) {
|
1459
1393
|
let func = funcs.find(x => x.index === inst[1]);
|
@@ -1725,7 +1659,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1725
1659
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1726
1660
|
return makeArray(scope, {
|
1727
1661
|
rawElements: new Array(length)
|
1728
|
-
}, _global, _name, true, itemType);
|
1662
|
+
}, _global, _name, true, itemType, true);
|
1729
1663
|
}, () => {
|
1730
1664
|
optUnused = true;
|
1731
1665
|
return unusedValue;
|
@@ -1998,13 +1932,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1998
1932
|
continue;
|
1999
1933
|
}
|
2000
1934
|
|
2001
|
-
if (valtypeBinary !== Valtype.i32 &&
|
1935
|
+
if (valtypeBinary !== Valtype.i32 &&
|
2002
1936
|
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2003
|
-
|
2004
|
-
)) {
|
1937
|
+
) {
|
2005
1938
|
out.push(Opcodes.i32_to);
|
2006
1939
|
}
|
2007
1940
|
|
1941
|
+
if (valtypeBinary === Valtype.i32 &&
|
1942
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1943
|
+
) {
|
1944
|
+
out.push(Opcodes.f64_convert_i32_s);
|
1945
|
+
}
|
1946
|
+
|
2008
1947
|
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
2009
1948
|
}
|
2010
1949
|
|
@@ -2026,6 +1965,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2026
1965
|
out.push(Opcodes.i32_from);
|
2027
1966
|
}
|
2028
1967
|
|
1968
|
+
if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32) {
|
1969
|
+
out.push(Opcodes.i32_trunc_sat_f64_s);
|
1970
|
+
}
|
1971
|
+
|
2029
1972
|
return out;
|
2030
1973
|
};
|
2031
1974
|
|
@@ -2115,7 +2058,6 @@ const brTable = (input, bc, returns) => {
|
|
2115
2058
|
}
|
2116
2059
|
|
2117
2060
|
for (let i = 0; i < count; i++) {
|
2118
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2119
2061
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2120
2062
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2121
2063
|
}
|
@@ -2149,10 +2091,8 @@ const brTable = (input, bc, returns) => {
|
|
2149
2091
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2150
2092
|
);
|
2151
2093
|
|
2152
|
-
//
|
2153
|
-
// (
|
2154
|
-
// dm me and if you are correct and the first person
|
2155
|
-
// I will somehow shout you out or something
|
2094
|
+
// sort the wrong way and then reverse
|
2095
|
+
// so strings ('default') are at the start before any numbers
|
2156
2096
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2157
2097
|
|
2158
2098
|
br = count - 1;
|
@@ -2178,7 +2118,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2178
2118
|
return bc[known] ?? bc.default;
|
2179
2119
|
}
|
2180
2120
|
|
2181
|
-
if (Prefs.
|
2121
|
+
if (Prefs.typeswitchBrtable)
|
2182
2122
|
return brTable(type, bc, returns);
|
2183
2123
|
|
2184
2124
|
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
@@ -2233,11 +2173,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2233
2173
|
return target[name].idx;
|
2234
2174
|
}
|
2235
2175
|
|
2236
|
-
let idx = global ?
|
2176
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2237
2177
|
target[name] = { idx, type: valtypeBinary };
|
2238
2178
|
|
2239
2179
|
if (type) {
|
2240
|
-
let typeIdx = global ?
|
2180
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2241
2181
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2242
2182
|
}
|
2243
2183
|
|
@@ -2330,24 +2270,10 @@ const generateVar = (scope, decl) => {
|
|
2330
2270
|
}
|
2331
2271
|
|
2332
2272
|
if (x.init) {
|
2333
|
-
|
2334
|
-
// // let a = function () { ... }
|
2335
|
-
// x.init.id = { name };
|
2336
|
-
|
2337
|
-
// const func = generateFunc(scope, x.init);
|
2338
|
-
|
2339
|
-
// out.push(
|
2340
|
-
// ...number(func.index - importedFuncs.length),
|
2341
|
-
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2342
|
-
|
2343
|
-
// ...setType(scope, name, TYPES.function)
|
2344
|
-
// );
|
2345
|
-
|
2346
|
-
// continue;
|
2347
|
-
// }
|
2273
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2348
2274
|
|
2349
2275
|
const generated = generate(scope, x.init, global, name);
|
2350
|
-
if (scope.arrays?.get(name) != null) {
|
2276
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2351
2277
|
// hack to set local as pointer before
|
2352
2278
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2353
2279
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2399,19 +2325,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2399
2325
|
|
2400
2326
|
// hack: .length setter
|
2401
2327
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2402
|
-
const name = decl.left.object.name;
|
2403
|
-
const pointer = scope.arrays?.get(name);
|
2404
|
-
|
2405
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2406
|
-
|
2407
2328
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2408
2329
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2409
2330
|
|
2410
2331
|
return [
|
2411
|
-
...(
|
2412
|
-
|
2413
|
-
Opcodes.i32_to_u
|
2414
|
-
]),
|
2332
|
+
...generate(scope, decl.left.object),
|
2333
|
+
Opcodes.i32_to_u,
|
2415
2334
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2416
2335
|
|
2417
2336
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2422,7 +2341,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2422
2341
|
[ Opcodes.local_tee, newValueTmp ],
|
2423
2342
|
|
2424
2343
|
Opcodes.i32_to_u,
|
2425
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2344
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2426
2345
|
|
2427
2346
|
[ Opcodes.local_get, newValueTmp ]
|
2428
2347
|
];
|
@@ -2430,21 +2349,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2430
2349
|
|
2431
2350
|
// arr[i]
|
2432
2351
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2433
|
-
const name = decl.left.object.name;
|
2434
|
-
const pointer = scope.arrays?.get(name);
|
2435
|
-
|
2436
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2437
|
-
|
2438
2352
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2439
2353
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2440
2354
|
|
2441
2355
|
return [
|
2442
2356
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2443
2357
|
[TYPES.array]: [
|
2444
|
-
...(
|
2445
|
-
|
2446
|
-
Opcodes.i32_to_u
|
2447
|
-
]),
|
2358
|
+
...generate(scope, decl.left.object),
|
2359
|
+
Opcodes.i32_to_u,
|
2448
2360
|
|
2449
2361
|
// get index as valtype
|
2450
2362
|
...generate(scope, decl.left.property),
|
@@ -2453,39 +2365,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2453
2365
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2454
2366
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2455
2367
|
[ Opcodes.i32_mul ],
|
2456
|
-
|
2368
|
+
[ Opcodes.i32_add ],
|
2457
2369
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2458
2370
|
|
2459
2371
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2460
2372
|
[ Opcodes.local_get, pointerTmp ],
|
2461
|
-
[ Opcodes.load, 0,
|
2373
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2462
2374
|
], generate(scope, decl.right), [
|
2463
2375
|
[ Opcodes.local_get, pointerTmp ],
|
2464
|
-
[ Opcodes.i32_load8_u, 0,
|
2376
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2465
2377
|
], getNodeType(scope, decl.right), false, name, true)),
|
2466
2378
|
[ Opcodes.local_tee, newValueTmp ],
|
2467
2379
|
|
2468
|
-
[ Opcodes.store, 0,
|
2380
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2469
2381
|
],
|
2470
2382
|
|
2471
2383
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2472
|
-
|
2473
|
-
// [TYPES.string]: [
|
2474
|
-
// // turn into byte offset by * sizeof i16
|
2475
|
-
// ...number(ValtypeSize.i16, Valtype.i32),
|
2476
|
-
// [ Opcodes.i32_mul ],
|
2477
|
-
// ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2478
|
-
// ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2479
|
-
|
2480
|
-
// ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2481
|
-
// [ Opcodes.local_get, pointerTmp ],
|
2482
|
-
// [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2483
|
-
// ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
|
2484
|
-
// [ Opcodes.local_tee, newValueTmp ],
|
2485
|
-
|
2486
|
-
// Opcodes.i32_to_u,
|
2487
|
-
// [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2488
|
-
// ]
|
2489
2384
|
}, Blocktype.void),
|
2490
2385
|
|
2491
2386
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2547,9 +2442,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2547
2442
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2548
2443
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2549
2444
|
|
2550
|
-
|
2551
|
-
|
2552
|
-
...setType(scope, name, TYPES.number)
|
2445
|
+
...setType(scope, name, getNodeType(scope, decl))
|
2553
2446
|
];
|
2554
2447
|
};
|
2555
2448
|
|
@@ -2869,12 +2762,12 @@ const generateForOf = (scope, decl) => {
|
|
2869
2762
|
|
2870
2763
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2871
2764
|
// hack: this is naughty and will break things!
|
2872
|
-
let newOut = number(0, Valtype.
|
2765
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2873
2766
|
if (pages.hasAnyString) {
|
2874
2767
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2875
2768
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2876
|
-
rawElements: new Array(
|
2877
|
-
}, isGlobal, leftName, true, 'i16');
|
2769
|
+
rawElements: new Array(0)
|
2770
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2878
2771
|
}
|
2879
2772
|
|
2880
2773
|
// set type for local
|
@@ -2921,23 +2814,28 @@ const generateForOf = (scope, decl) => {
|
|
2921
2814
|
[TYPES.string]: [
|
2922
2815
|
...setType(scope, leftName, TYPES.string),
|
2923
2816
|
|
2924
|
-
[ Opcodes.loop, Blocktype.void ],
|
2925
|
-
|
2926
2817
|
// setup new/out array
|
2927
2818
|
...newOut,
|
2928
|
-
[ Opcodes.drop ],
|
2929
2819
|
|
2930
|
-
|
2820
|
+
// set length to 1
|
2821
|
+
...number(1, Valtype.i32),
|
2822
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2823
|
+
|
2824
|
+
[ Opcodes.loop, Blocktype.void ],
|
2825
|
+
|
2826
|
+
// use as pointer for store later
|
2827
|
+
...newPointer,
|
2931
2828
|
|
2932
2829
|
// load current string ind {arg}
|
2933
2830
|
[ Opcodes.local_get, pointer ],
|
2934
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
2831
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2935
2832
|
|
2936
2833
|
// store to new string ind 0
|
2937
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
2834
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2938
2835
|
|
2939
2836
|
// return new string (page)
|
2940
|
-
...
|
2837
|
+
...newPointer,
|
2838
|
+
Opcodes.i32_from_u,
|
2941
2839
|
|
2942
2840
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2943
2841
|
|
@@ -2969,25 +2867,30 @@ const generateForOf = (scope, decl) => {
|
|
2969
2867
|
[TYPES.bytestring]: [
|
2970
2868
|
...setType(scope, leftName, TYPES.bytestring),
|
2971
2869
|
|
2972
|
-
[ Opcodes.loop, Blocktype.void ],
|
2973
|
-
|
2974
2870
|
// setup new/out array
|
2975
2871
|
...newOut,
|
2976
|
-
[ Opcodes.drop ],
|
2977
2872
|
|
2978
|
-
|
2873
|
+
// set length to 1
|
2874
|
+
...number(1, Valtype.i32),
|
2875
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2876
|
+
|
2877
|
+
[ Opcodes.loop, Blocktype.void ],
|
2878
|
+
|
2879
|
+
// use as pointer for store later
|
2880
|
+
...newPointer,
|
2979
2881
|
|
2980
2882
|
// load current string ind {arg}
|
2981
2883
|
[ Opcodes.local_get, pointer ],
|
2982
2884
|
[ Opcodes.local_get, counter ],
|
2983
2885
|
[ Opcodes.i32_add ],
|
2984
|
-
[ Opcodes.i32_load8_u, 0,
|
2886
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2985
2887
|
|
2986
2888
|
// store to new string ind 0
|
2987
|
-
[ Opcodes.i32_store8, 0,
|
2889
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2988
2890
|
|
2989
2891
|
// return new string (page)
|
2990
|
-
...
|
2892
|
+
...newPointer,
|
2893
|
+
Opcodes.i32_from_u,
|
2991
2894
|
|
2992
2895
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2993
2896
|
|
@@ -3202,18 +3105,6 @@ const allocPage = (scope, reason, type) => {
|
|
3202
3105
|
scope.pages ??= new Map();
|
3203
3106
|
scope.pages.set(reason, { ind, type });
|
3204
3107
|
|
3205
|
-
if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
3206
|
-
|
3207
|
-
return ind;
|
3208
|
-
};
|
3209
|
-
|
3210
|
-
// todo: add scope.pages
|
3211
|
-
const freePage = reason => {
|
3212
|
-
const { ind } = pages.get(reason);
|
3213
|
-
pages.delete(reason);
|
3214
|
-
|
3215
|
-
if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
3216
|
-
|
3217
3108
|
return ind;
|
3218
3109
|
};
|
3219
3110
|
|
@@ -3251,39 +3142,58 @@ const compileBytes = (val, itemType) => {
|
|
3251
3142
|
}
|
3252
3143
|
};
|
3253
3144
|
|
3254
|
-
const
|
3255
|
-
|
3256
|
-
|
3257
|
-
|
3145
|
+
const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
|
3146
|
+
const length = elements.length;
|
3147
|
+
|
3148
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3149
|
+
if (length === 0) return false;
|
3258
3150
|
|
3259
|
-
|
3151
|
+
let bytes = compileBytes(length, 'i32');
|
3152
|
+
|
3153
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3154
|
+
if (elements[i] == null) continue;
|
3155
|
+
|
3156
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3260
3157
|
}
|
3261
|
-
};
|
3262
3158
|
|
3263
|
-
const
|
3264
|
-
|
3159
|
+
const obj = { bytes };
|
3160
|
+
if (offset != null) obj.offset = offset;
|
3265
3161
|
|
3266
|
-
|
3162
|
+
const idx = data.push(obj) - 1;
|
3267
3163
|
|
3268
|
-
|
3269
|
-
|
3270
|
-
firstAssign = true;
|
3164
|
+
scope.data ??= [];
|
3165
|
+
scope.data.push(idx);
|
3271
3166
|
|
3272
|
-
|
3273
|
-
|
3167
|
+
return { idx, size: bytes.length };
|
3168
|
+
};
|
3274
3169
|
|
3275
|
-
|
3276
|
-
|
3277
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3170
|
+
const printStaticStr = str => {
|
3171
|
+
const out = [];
|
3278
3172
|
|
3279
|
-
|
3280
|
-
|
3281
|
-
|
3173
|
+
for (let i = 0; i < str.length; i++) {
|
3174
|
+
out.push(
|
3175
|
+
// ...number(str.charCodeAt(i)),
|
3176
|
+
...number(str.charCodeAt(i), Valtype.i32),
|
3177
|
+
Opcodes.i32_from_u,
|
3178
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3179
|
+
);
|
3180
|
+
}
|
3181
|
+
|
3182
|
+
return out;
|
3183
|
+
};
|
3184
|
+
|
3185
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
3186
|
+
if (itemType !== 'i16' && itemType !== 'i8') {
|
3187
|
+
pages.hasArray = true;
|
3188
|
+
} else {
|
3189
|
+
pages.hasAnyString = true;
|
3190
|
+
if (itemType === 'i8') pages.hasByteString = true;
|
3191
|
+
else pages.hasString = true;
|
3282
3192
|
}
|
3283
3193
|
|
3284
|
-
const
|
3194
|
+
const out = [];
|
3285
3195
|
|
3286
|
-
const
|
3196
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3287
3197
|
|
3288
3198
|
const useRawElements = !!decl.rawElements;
|
3289
3199
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3291,46 +3201,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3291
3201
|
const valtype = itemTypeToValtype[itemType];
|
3292
3202
|
const length = elements.length;
|
3293
3203
|
|
3294
|
-
|
3295
|
-
|
3296
|
-
|
3297
|
-
|
3204
|
+
const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
|
3205
|
+
|
3206
|
+
let pointer = allocated;
|
3207
|
+
if (allocator.constructor.name !== 'StaticAllocator') {
|
3208
|
+
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3209
|
+
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
3210
|
+
out.push(
|
3211
|
+
...allocated,
|
3212
|
+
[ Opcodes.local_set, tmp ]
|
3213
|
+
);
|
3214
|
+
|
3215
|
+
if (Prefs.runtimeAllocLog) out.push(
|
3216
|
+
...printStaticStr(`${name}: `),
|
3217
|
+
|
3218
|
+
[ Opcodes.local_get, tmp ],
|
3219
|
+
Opcodes.i32_from_u,
|
3220
|
+
[ Opcodes.call, 0 ],
|
3221
|
+
|
3222
|
+
...number(10),
|
3223
|
+
[ Opcodes.call, 1 ]
|
3224
|
+
);
|
3298
3225
|
|
3299
|
-
|
3300
|
-
if (elements[i] == null) continue;
|
3226
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3301
3227
|
|
3302
|
-
|
3228
|
+
if (Prefs.data && useRawElements) {
|
3229
|
+
const data = makeData(scope, elements, null, itemType, initEmpty);
|
3230
|
+
if (data) {
|
3231
|
+
// init data
|
3232
|
+
out.push(
|
3233
|
+
...pointer,
|
3234
|
+
...number(0, Valtype.i32),
|
3235
|
+
...number(data.size, Valtype.i32),
|
3236
|
+
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
3237
|
+
);
|
3303
3238
|
}
|
3304
3239
|
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3240
|
+
// return pointer in out
|
3241
|
+
out.push(
|
3242
|
+
...pointer,
|
3243
|
+
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
3244
|
+
);
|
3309
3245
|
|
3310
|
-
|
3311
|
-
scope.data.push(ind);
|
3246
|
+
return [ out, pointer ];
|
3312
3247
|
}
|
3248
|
+
} else {
|
3249
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3313
3250
|
|
3314
|
-
|
3315
|
-
|
3251
|
+
scope.arrays ??= new Map();
|
3252
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3253
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3316
3254
|
|
3317
|
-
|
3318
|
-
|
3255
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3256
|
+
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
3319
3257
|
|
3320
|
-
|
3321
|
-
|
3322
|
-
|
3323
|
-
|
3324
|
-
|
3325
|
-
|
3326
|
-
)
|
3258
|
+
// local value as pointer
|
3259
|
+
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3260
|
+
}
|
3261
|
+
|
3262
|
+
const local = global ? globals[name] : scope.locals[name];
|
3263
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3264
|
+
if (pointerTmp != null) {
|
3265
|
+
out.push(
|
3266
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3267
|
+
Opcodes.i32_to_u,
|
3268
|
+
[ Opcodes.local_set, pointerTmp ]
|
3269
|
+
);
|
3270
|
+
|
3271
|
+
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
3272
|
+
}
|
3327
3273
|
}
|
3328
3274
|
|
3329
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3330
3275
|
|
3331
3276
|
// store length
|
3332
3277
|
out.push(
|
3333
|
-
...
|
3278
|
+
...pointer,
|
3334
3279
|
...number(length, Valtype.i32),
|
3335
3280
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3336
3281
|
);
|
@@ -3342,11 +3287,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3342
3287
|
|
3343
3288
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3344
3289
|
out.push(
|
3345
|
-
...
|
3290
|
+
...pointer,
|
3346
3291
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3347
3292
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3348
3293
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3349
|
-
...
|
3294
|
+
...pointer,
|
3350
3295
|
...getNodeType(scope, elements[i]),
|
3351
3296
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3352
3297
|
])
|
@@ -3354,12 +3299,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3354
3299
|
}
|
3355
3300
|
|
3356
3301
|
// local value as pointer
|
3357
|
-
out.push(...
|
3302
|
+
out.push(...pointer);
|
3303
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3358
3304
|
|
3359
3305
|
return [ out, pointer ];
|
3360
3306
|
};
|
3361
3307
|
|
3362
|
-
const storeArray = (scope, array, index, element
|
3308
|
+
const storeArray = (scope, array, index, element) => {
|
3363
3309
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3364
3310
|
if (typeof index === 'number') index = number(index);
|
3365
3311
|
|
@@ -3371,26 +3317,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3371
3317
|
Opcodes.i32_to_u,
|
3372
3318
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3373
3319
|
[ Opcodes.i32_mul ],
|
3374
|
-
|
3375
|
-
|
3376
|
-
|
3377
|
-
|
3378
|
-
]),
|
3320
|
+
|
3321
|
+
...array,
|
3322
|
+
Opcodes.i32_to_u,
|
3323
|
+
[ Opcodes.i32_add ],
|
3379
3324
|
[ Opcodes.local_set, offset ],
|
3380
3325
|
|
3381
3326
|
// store value
|
3382
3327
|
[ Opcodes.local_get, offset ],
|
3383
3328
|
...generate(scope, element),
|
3384
|
-
[ Opcodes.store, 0,
|
3329
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3385
3330
|
|
3386
3331
|
// store type
|
3387
3332
|
[ Opcodes.local_get, offset ],
|
3388
3333
|
...getNodeType(scope, element),
|
3389
|
-
[ Opcodes.i32_store8, 0,
|
3334
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3390
3335
|
];
|
3391
3336
|
};
|
3392
3337
|
|
3393
|
-
const loadArray = (scope, array, index
|
3338
|
+
const loadArray = (scope, array, index) => {
|
3394
3339
|
if (typeof index === 'number') index = number(index);
|
3395
3340
|
|
3396
3341
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3401,20 +3346,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3401
3346
|
Opcodes.i32_to_u,
|
3402
3347
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3403
3348
|
[ Opcodes.i32_mul ],
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3407
|
-
|
3408
|
-
]),
|
3349
|
+
|
3350
|
+
...array,
|
3351
|
+
Opcodes.i32_to_u,
|
3352
|
+
[ Opcodes.i32_add ],
|
3409
3353
|
[ Opcodes.local_set, offset ],
|
3410
3354
|
|
3411
3355
|
// load value
|
3412
3356
|
[ Opcodes.local_get, offset ],
|
3413
|
-
[ Opcodes.load, 0,
|
3357
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3414
3358
|
|
3415
3359
|
// load type
|
3416
3360
|
[ Opcodes.local_get, offset ],
|
3417
|
-
[ Opcodes.i32_load8_u, 0,
|
3361
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3418
3362
|
];
|
3419
3363
|
};
|
3420
3364
|
|
@@ -3446,7 +3390,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3446
3390
|
};
|
3447
3391
|
|
3448
3392
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3449
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3393
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3450
3394
|
};
|
3451
3395
|
|
3452
3396
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3465,9 +3409,6 @@ const withType = (scope, wasm, type) => [
|
|
3465
3409
|
|
3466
3410
|
const generateMember = (scope, decl, _global, _name) => {
|
3467
3411
|
const name = decl.object.name;
|
3468
|
-
const pointer = scope.arrays?.get(name);
|
3469
|
-
|
3470
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3471
3412
|
|
3472
3413
|
// hack: .name
|
3473
3414
|
if (decl.property.name === 'name') {
|
@@ -3508,12 +3449,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3508
3449
|
if (Prefs.fastLength) {
|
3509
3450
|
// presume valid length object
|
3510
3451
|
return [
|
3511
|
-
...(
|
3512
|
-
|
3513
|
-
Opcodes.i32_to_u
|
3514
|
-
]),
|
3452
|
+
...generate(scope, decl.object),
|
3453
|
+
Opcodes.i32_to_u,
|
3515
3454
|
|
3516
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3455
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3517
3456
|
Opcodes.i32_from_u
|
3518
3457
|
];
|
3519
3458
|
}
|
@@ -3522,12 +3461,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3522
3461
|
const known = knownType(scope, type);
|
3523
3462
|
if (known != null) {
|
3524
3463
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3525
|
-
...(
|
3526
|
-
|
3527
|
-
Opcodes.i32_to_u
|
3528
|
-
]),
|
3464
|
+
...generate(scope, decl.object),
|
3465
|
+
Opcodes.i32_to_u,
|
3529
3466
|
|
3530
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3467
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3531
3468
|
Opcodes.i32_from_u
|
3532
3469
|
];
|
3533
3470
|
|
@@ -3537,12 +3474,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3537
3474
|
return [
|
3538
3475
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3539
3476
|
[ Opcodes.if, valtypeBinary ],
|
3540
|
-
...(
|
3541
|
-
|
3542
|
-
Opcodes.i32_to_u
|
3543
|
-
]),
|
3477
|
+
...generate(scope, decl.object),
|
3478
|
+
Opcodes.i32_to_u,
|
3544
3479
|
|
3545
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3480
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3546
3481
|
Opcodes.i32_from_u,
|
3547
3482
|
|
3548
3483
|
...setLastType(scope, TYPES.number),
|
@@ -3585,25 +3520,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3585
3520
|
|
3586
3521
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3587
3522
|
// hack: this is naughty and will break things!
|
3588
|
-
let newOut = number(0,
|
3589
|
-
if (pages.hasAnyString) {
|
3523
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3524
|
+
if (pages.hasAnyString && knownType(scope, getNodeType(scope, decl.object)) !== TYPES.array) {
|
3525
|
+
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3590
3526
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3591
|
-
rawElements: new Array(
|
3592
|
-
}, _global, _name, true, 'i16');
|
3527
|
+
rawElements: new Array(0)
|
3528
|
+
}, _global, _name, true, 'i16', true);
|
3593
3529
|
}
|
3594
3530
|
|
3595
3531
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3596
3532
|
[TYPES.array]: [
|
3597
|
-
...loadArray(scope, object, property
|
3533
|
+
...loadArray(scope, object, property),
|
3598
3534
|
...setLastType(scope)
|
3599
3535
|
],
|
3600
|
-
|
3601
3536
|
[TYPES.string]: [
|
3602
3537
|
// setup new/out array
|
3603
3538
|
...newOut,
|
3604
|
-
[ Opcodes.drop ],
|
3605
3539
|
|
3606
|
-
|
3540
|
+
// set length to 1
|
3541
|
+
...number(1, Valtype.i32),
|
3542
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3543
|
+
|
3544
|
+
// use as pointer for store later
|
3545
|
+
...newPointer,
|
3607
3546
|
|
3608
3547
|
...property,
|
3609
3548
|
Opcodes.i32_to_u,
|
@@ -3611,46 +3550,48 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3611
3550
|
...number(ValtypeSize.i16, Valtype.i32),
|
3612
3551
|
[ Opcodes.i32_mul ],
|
3613
3552
|
|
3614
|
-
...
|
3615
|
-
|
3616
|
-
|
3617
|
-
[ Opcodes.i32_add ]
|
3618
|
-
]),
|
3553
|
+
...object,
|
3554
|
+
Opcodes.i32_to_u,
|
3555
|
+
[ Opcodes.i32_add ],
|
3619
3556
|
|
3620
3557
|
// load current string ind {arg}
|
3621
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3558
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3622
3559
|
|
3623
3560
|
// store to new string ind 0
|
3624
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3561
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3625
3562
|
|
3626
3563
|
// return new string (page)
|
3627
|
-
...
|
3564
|
+
...newPointer,
|
3565
|
+
Opcodes.i32_from_u,
|
3628
3566
|
...setLastType(scope, TYPES.string)
|
3629
3567
|
],
|
3630
3568
|
[TYPES.bytestring]: [
|
3631
3569
|
// setup new/out array
|
3632
3570
|
...newOut,
|
3633
|
-
[ Opcodes.drop ],
|
3634
3571
|
|
3635
|
-
|
3572
|
+
// set length to 1
|
3573
|
+
...number(1, Valtype.i32),
|
3574
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3575
|
+
|
3576
|
+
// use as pointer for store later
|
3577
|
+
...newPointer,
|
3636
3578
|
|
3637
3579
|
...property,
|
3638
3580
|
Opcodes.i32_to_u,
|
3639
3581
|
|
3640
|
-
...
|
3641
|
-
|
3642
|
-
|
3643
|
-
[ Opcodes.i32_add ]
|
3644
|
-
]),
|
3582
|
+
...object,
|
3583
|
+
Opcodes.i32_to_u,
|
3584
|
+
[ Opcodes.i32_add ],
|
3645
3585
|
|
3646
3586
|
// load current string ind {arg}
|
3647
|
-
[ Opcodes.i32_load8_u, 0,
|
3587
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3648
3588
|
|
3649
3589
|
// store to new string ind 0
|
3650
|
-
[ Opcodes.i32_store8, 0,
|
3590
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3651
3591
|
|
3652
3592
|
// return new string (page)
|
3653
|
-
...
|
3593
|
+
...newPointer,
|
3594
|
+
Opcodes.i32_from_u,
|
3654
3595
|
...setLastType(scope, TYPES.bytestring)
|
3655
3596
|
],
|
3656
3597
|
|
@@ -3795,9 +3736,9 @@ const internalConstrs = {
|
|
3795
3736
|
|
3796
3737
|
// new Array(n)
|
3797
3738
|
|
3798
|
-
const [ , pointer ] = makeArray(scope, {
|
3739
|
+
const [ out, pointer ] = makeArray(scope, {
|
3799
3740
|
rawElements: new Array(0)
|
3800
|
-
}, global, name, true);
|
3741
|
+
}, global, name, true, undefined, true);
|
3801
3742
|
|
3802
3743
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3803
3744
|
|
@@ -3806,12 +3747,13 @@ const internalConstrs = {
|
|
3806
3747
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3807
3748
|
|
3808
3749
|
return [
|
3809
|
-
...
|
3750
|
+
...out,
|
3810
3751
|
...generate(scope, arg, global, name),
|
3811
3752
|
Opcodes.i32_to_u,
|
3812
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3753
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3813
3754
|
|
3814
|
-
...
|
3755
|
+
...pointer,
|
3756
|
+
Opcodes.i32_from_u
|
3815
3757
|
];
|
3816
3758
|
},
|
3817
3759
|
type: TYPES.array,
|
@@ -3960,8 +3902,9 @@ const internalConstrs = {
|
|
3960
3902
|
};
|
3961
3903
|
|
3962
3904
|
export default program => {
|
3963
|
-
globals = {
|
3964
|
-
|
3905
|
+
globals = {
|
3906
|
+
['#ind']: 0
|
3907
|
+
};
|
3965
3908
|
tags = [];
|
3966
3909
|
exceptions = [];
|
3967
3910
|
funcs = [];
|
@@ -3994,6 +3937,7 @@ export default program => {
|
|
3994
3937
|
builtinFuncs = new BuiltinFuncs();
|
3995
3938
|
builtinVars = new BuiltinVars();
|
3996
3939
|
prototypeFuncs = new PrototypeFuncs();
|
3940
|
+
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
3997
3941
|
|
3998
3942
|
program.id = { name: 'main' };
|
3999
3943
|
|
@@ -4036,6 +3980,8 @@ export default program => {
|
|
4036
3980
|
else main.returns = [];
|
4037
3981
|
}
|
4038
3982
|
|
3983
|
+
delete globals['#ind'];
|
3984
|
+
|
4039
3985
|
// if blank main func and other exports, remove it
|
4040
3986
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4041
3987
|
|