porffor 0.16.0-f9dde1759 → 0.16.0-fa3914030
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/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/string_f64.ts +10 -0
- package/compiler/builtins/z_ecma262.ts +62 -0
- package/compiler/codegen.js +277 -328
- package/compiler/cyclone.js +11 -11
- package/compiler/generated_builtins.js +131 -75
- package/compiler/index.js +15 -1
- package/compiler/opt.js +8 -6
- package/compiler/parse.js +0 -6
- package/compiler/pgo.js +5 -0
- package/compiler/precompile.js +9 -6
- package/compiler/prefs.js +2 -3
- package/compiler/prototype.js +34 -43
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +2 -1
- package/package.json +1 -1
- package/runner/index.js +5 -0
- 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 &&
|
2002
|
-
(
|
2003
|
-
|
2004
|
-
)) {
|
1935
|
+
if (valtypeBinary !== Valtype.i32 &&
|
1936
|
+
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1937
|
+
) {
|
2005
1938
|
out.push(Opcodes.i32_to);
|
2006
1939
|
}
|
2007
1940
|
|
1941
|
+
if (valtypeBinary === Valtype.i32 &&
|
1942
|
+
(func && func.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
|
|
@@ -2049,9 +1992,9 @@ const generateNew = (scope, decl, _global, _name) => {
|
|
2049
1992
|
if (
|
2050
1993
|
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2051
1994
|
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2052
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor
|
1995
|
+
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2053
1996
|
|
2054
|
-
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet
|
1997
|
+
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`, true); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
|
2055
1998
|
|
2056
1999
|
return generateCall(scope, decl, _global, _name);
|
2057
2000
|
};
|
@@ -2230,11 +2173,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2230
2173
|
return target[name].idx;
|
2231
2174
|
}
|
2232
2175
|
|
2233
|
-
let idx = global ?
|
2176
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2234
2177
|
target[name] = { idx, type: valtypeBinary };
|
2235
2178
|
|
2236
2179
|
if (type) {
|
2237
|
-
let typeIdx = global ?
|
2180
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2238
2181
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2239
2182
|
}
|
2240
2183
|
|
@@ -2327,24 +2270,10 @@ const generateVar = (scope, decl) => {
|
|
2327
2270
|
}
|
2328
2271
|
|
2329
2272
|
if (x.init) {
|
2330
|
-
|
2331
|
-
// // let a = function () { ... }
|
2332
|
-
// x.init.id = { name };
|
2333
|
-
|
2334
|
-
// const func = generateFunc(scope, x.init);
|
2335
|
-
|
2336
|
-
// out.push(
|
2337
|
-
// ...number(func.index - importedFuncs.length),
|
2338
|
-
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2339
|
-
|
2340
|
-
// ...setType(scope, name, TYPES.function)
|
2341
|
-
// );
|
2342
|
-
|
2343
|
-
// continue;
|
2344
|
-
// }
|
2273
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2345
2274
|
|
2346
2275
|
const generated = generate(scope, x.init, global, name);
|
2347
|
-
if (scope.arrays?.get(name) != null) {
|
2276
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2348
2277
|
// hack to set local as pointer before
|
2349
2278
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2350
2279
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2396,19 +2325,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2396
2325
|
|
2397
2326
|
// hack: .length setter
|
2398
2327
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2399
|
-
const name = decl.left.object.name;
|
2400
|
-
const pointer = scope.arrays?.get(name);
|
2401
|
-
|
2402
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2403
|
-
|
2404
2328
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2405
2329
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2406
2330
|
|
2407
2331
|
return [
|
2408
|
-
...(
|
2409
|
-
|
2410
|
-
Opcodes.i32_to_u
|
2411
|
-
]),
|
2332
|
+
...generate(scope, decl.left.object),
|
2333
|
+
Opcodes.i32_to_u,
|
2412
2334
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2413
2335
|
|
2414
2336
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2419,7 +2341,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2419
2341
|
[ Opcodes.local_tee, newValueTmp ],
|
2420
2342
|
|
2421
2343
|
Opcodes.i32_to_u,
|
2422
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2344
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2423
2345
|
|
2424
2346
|
[ Opcodes.local_get, newValueTmp ]
|
2425
2347
|
];
|
@@ -2427,21 +2349,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2427
2349
|
|
2428
2350
|
// arr[i]
|
2429
2351
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2430
|
-
const name = decl.left.object.name;
|
2431
|
-
const pointer = scope.arrays?.get(name);
|
2432
|
-
|
2433
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2434
|
-
|
2435
2352
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2436
2353
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2437
2354
|
|
2438
2355
|
return [
|
2439
2356
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2440
2357
|
[TYPES.array]: [
|
2441
|
-
...(
|
2442
|
-
|
2443
|
-
Opcodes.i32_to_u
|
2444
|
-
]),
|
2358
|
+
...generate(scope, decl.left.object),
|
2359
|
+
Opcodes.i32_to_u,
|
2445
2360
|
|
2446
2361
|
// get index as valtype
|
2447
2362
|
...generate(scope, decl.left.property),
|
@@ -2450,39 +2365,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2450
2365
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2451
2366
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2452
2367
|
[ Opcodes.i32_mul ],
|
2453
|
-
|
2368
|
+
[ Opcodes.i32_add ],
|
2454
2369
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2455
2370
|
|
2456
2371
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2457
2372
|
[ Opcodes.local_get, pointerTmp ],
|
2458
|
-
[ Opcodes.load, 0,
|
2373
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2459
2374
|
], generate(scope, decl.right), [
|
2460
2375
|
[ Opcodes.local_get, pointerTmp ],
|
2461
|
-
[ Opcodes.i32_load8_u, 0,
|
2376
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2462
2377
|
], getNodeType(scope, decl.right), false, name, true)),
|
2463
2378
|
[ Opcodes.local_tee, newValueTmp ],
|
2464
2379
|
|
2465
|
-
[ Opcodes.store, 0,
|
2380
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2466
2381
|
],
|
2467
2382
|
|
2468
2383
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2469
|
-
|
2470
|
-
// [TYPES.string]: [
|
2471
|
-
// // turn into byte offset by * sizeof i16
|
2472
|
-
// ...number(ValtypeSize.i16, Valtype.i32),
|
2473
|
-
// [ Opcodes.i32_mul ],
|
2474
|
-
// ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2475
|
-
// ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2476
|
-
|
2477
|
-
// ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2478
|
-
// [ Opcodes.local_get, pointerTmp ],
|
2479
|
-
// [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2480
|
-
// ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
|
2481
|
-
// [ Opcodes.local_tee, newValueTmp ],
|
2482
|
-
|
2483
|
-
// Opcodes.i32_to_u,
|
2484
|
-
// [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2485
|
-
// ]
|
2486
2384
|
}, Blocktype.void),
|
2487
2385
|
|
2488
2386
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2544,9 +2442,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2544
2442
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2545
2443
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2546
2444
|
|
2547
|
-
|
2548
|
-
|
2549
|
-
...setType(scope, name, TYPES.number)
|
2445
|
+
...setType(scope, name, getNodeType(scope, decl))
|
2550
2446
|
];
|
2551
2447
|
};
|
2552
2448
|
|
@@ -2866,12 +2762,12 @@ const generateForOf = (scope, decl) => {
|
|
2866
2762
|
|
2867
2763
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2868
2764
|
// hack: this is naughty and will break things!
|
2869
|
-
let newOut = number(0, Valtype.
|
2765
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2870
2766
|
if (pages.hasAnyString) {
|
2871
2767
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2872
2768
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2873
|
-
rawElements: new Array(
|
2874
|
-
}, isGlobal, leftName, true, 'i16');
|
2769
|
+
rawElements: new Array(0)
|
2770
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2875
2771
|
}
|
2876
2772
|
|
2877
2773
|
// set type for local
|
@@ -2918,23 +2814,28 @@ const generateForOf = (scope, decl) => {
|
|
2918
2814
|
[TYPES.string]: [
|
2919
2815
|
...setType(scope, leftName, TYPES.string),
|
2920
2816
|
|
2921
|
-
[ Opcodes.loop, Blocktype.void ],
|
2922
|
-
|
2923
2817
|
// setup new/out array
|
2924
2818
|
...newOut,
|
2925
|
-
[ Opcodes.drop ],
|
2926
2819
|
|
2927
|
-
|
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,
|
2928
2828
|
|
2929
2829
|
// load current string ind {arg}
|
2930
2830
|
[ Opcodes.local_get, pointer ],
|
2931
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
2831
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2932
2832
|
|
2933
2833
|
// store to new string ind 0
|
2934
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
2834
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2935
2835
|
|
2936
2836
|
// return new string (page)
|
2937
|
-
...
|
2837
|
+
...newPointer,
|
2838
|
+
Opcodes.i32_from_u,
|
2938
2839
|
|
2939
2840
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2940
2841
|
|
@@ -2966,25 +2867,30 @@ const generateForOf = (scope, decl) => {
|
|
2966
2867
|
[TYPES.bytestring]: [
|
2967
2868
|
...setType(scope, leftName, TYPES.bytestring),
|
2968
2869
|
|
2969
|
-
[ Opcodes.loop, Blocktype.void ],
|
2970
|
-
|
2971
2870
|
// setup new/out array
|
2972
2871
|
...newOut,
|
2973
|
-
[ Opcodes.drop ],
|
2974
2872
|
|
2975
|
-
|
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,
|
2976
2881
|
|
2977
2882
|
// load current string ind {arg}
|
2978
2883
|
[ Opcodes.local_get, pointer ],
|
2979
2884
|
[ Opcodes.local_get, counter ],
|
2980
2885
|
[ Opcodes.i32_add ],
|
2981
|
-
[ Opcodes.i32_load8_u, 0,
|
2886
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2982
2887
|
|
2983
2888
|
// store to new string ind 0
|
2984
|
-
[ Opcodes.i32_store8, 0,
|
2889
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2985
2890
|
|
2986
2891
|
// return new string (page)
|
2987
|
-
...
|
2892
|
+
...newPointer,
|
2893
|
+
Opcodes.i32_from_u,
|
2988
2894
|
|
2989
2895
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2990
2896
|
|
@@ -3199,18 +3105,6 @@ const allocPage = (scope, reason, type) => {
|
|
3199
3105
|
scope.pages ??= new Map();
|
3200
3106
|
scope.pages.set(reason, { ind, type });
|
3201
3107
|
|
3202
|
-
if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
3203
|
-
|
3204
|
-
return ind;
|
3205
|
-
};
|
3206
|
-
|
3207
|
-
// todo: add scope.pages
|
3208
|
-
const freePage = reason => {
|
3209
|
-
const { ind } = pages.get(reason);
|
3210
|
-
pages.delete(reason);
|
3211
|
-
|
3212
|
-
if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
3213
|
-
|
3214
3108
|
return ind;
|
3215
3109
|
};
|
3216
3110
|
|
@@ -3248,39 +3142,58 @@ const compileBytes = (val, itemType) => {
|
|
3248
3142
|
}
|
3249
3143
|
};
|
3250
3144
|
|
3251
|
-
const
|
3252
|
-
|
3253
|
-
|
3254
|
-
|
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;
|
3255
3150
|
|
3256
|
-
|
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));
|
3257
3157
|
}
|
3258
|
-
};
|
3259
3158
|
|
3260
|
-
const
|
3261
|
-
|
3159
|
+
const obj = { bytes };
|
3160
|
+
if (offset != null) obj.offset = offset;
|
3262
3161
|
|
3263
|
-
|
3162
|
+
const idx = data.push(obj) - 1;
|
3264
3163
|
|
3265
|
-
|
3266
|
-
|
3267
|
-
firstAssign = true;
|
3164
|
+
scope.data ??= [];
|
3165
|
+
scope.data.push(idx);
|
3268
3166
|
|
3269
|
-
|
3270
|
-
|
3167
|
+
return { idx, size: bytes.length };
|
3168
|
+
};
|
3271
3169
|
|
3272
|
-
|
3273
|
-
|
3274
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3170
|
+
const printStaticStr = str => {
|
3171
|
+
const out = [];
|
3275
3172
|
|
3276
|
-
|
3277
|
-
|
3278
|
-
|
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;
|
3279
3192
|
}
|
3280
3193
|
|
3281
|
-
const
|
3194
|
+
const out = [];
|
3282
3195
|
|
3283
|
-
const
|
3196
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3284
3197
|
|
3285
3198
|
const useRawElements = !!decl.rawElements;
|
3286
3199
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3288,46 +3201,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3288
3201
|
const valtype = itemTypeToValtype[itemType];
|
3289
3202
|
const length = elements.length;
|
3290
3203
|
|
3291
|
-
|
3292
|
-
|
3293
|
-
|
3294
|
-
|
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
|
+
);
|
3295
3225
|
|
3296
|
-
|
3297
|
-
if (elements[i] == null) continue;
|
3226
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3298
3227
|
|
3299
|
-
|
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
|
+
);
|
3300
3238
|
}
|
3301
3239
|
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3240
|
+
// return pointer in out
|
3241
|
+
out.push(
|
3242
|
+
...pointer,
|
3243
|
+
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
3244
|
+
);
|
3306
3245
|
|
3307
|
-
|
3308
|
-
scope.data.push(ind);
|
3246
|
+
return [ out, pointer ];
|
3309
3247
|
}
|
3248
|
+
} else {
|
3249
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3310
3250
|
|
3311
|
-
|
3312
|
-
|
3251
|
+
scope.arrays ??= new Map();
|
3252
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3253
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3313
3254
|
|
3314
|
-
|
3315
|
-
|
3255
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3256
|
+
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
3316
3257
|
|
3317
|
-
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3321
|
-
|
3322
|
-
|
3323
|
-
)
|
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
|
+
}
|
3324
3273
|
}
|
3325
3274
|
|
3326
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3327
3275
|
|
3328
3276
|
// store length
|
3329
3277
|
out.push(
|
3330
|
-
...
|
3278
|
+
...pointer,
|
3331
3279
|
...number(length, Valtype.i32),
|
3332
3280
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3333
3281
|
);
|
@@ -3339,11 +3287,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3339
3287
|
|
3340
3288
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3341
3289
|
out.push(
|
3342
|
-
...
|
3290
|
+
...pointer,
|
3343
3291
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3344
3292
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3345
3293
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3346
|
-
...
|
3294
|
+
...pointer,
|
3347
3295
|
...getNodeType(scope, elements[i]),
|
3348
3296
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3349
3297
|
])
|
@@ -3351,12 +3299,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3351
3299
|
}
|
3352
3300
|
|
3353
3301
|
// local value as pointer
|
3354
|
-
out.push(...
|
3302
|
+
out.push(...pointer);
|
3303
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3355
3304
|
|
3356
3305
|
return [ out, pointer ];
|
3357
3306
|
};
|
3358
3307
|
|
3359
|
-
const storeArray = (scope, array, index, element
|
3308
|
+
const storeArray = (scope, array, index, element) => {
|
3360
3309
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3361
3310
|
if (typeof index === 'number') index = number(index);
|
3362
3311
|
|
@@ -3368,26 +3317,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3368
3317
|
Opcodes.i32_to_u,
|
3369
3318
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3370
3319
|
[ Opcodes.i32_mul ],
|
3371
|
-
|
3372
|
-
|
3373
|
-
|
3374
|
-
|
3375
|
-
]),
|
3320
|
+
|
3321
|
+
...array,
|
3322
|
+
Opcodes.i32_to_u,
|
3323
|
+
[ Opcodes.i32_add ],
|
3376
3324
|
[ Opcodes.local_set, offset ],
|
3377
3325
|
|
3378
3326
|
// store value
|
3379
3327
|
[ Opcodes.local_get, offset ],
|
3380
3328
|
...generate(scope, element),
|
3381
|
-
[ Opcodes.store, 0,
|
3329
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3382
3330
|
|
3383
3331
|
// store type
|
3384
3332
|
[ Opcodes.local_get, offset ],
|
3385
3333
|
...getNodeType(scope, element),
|
3386
|
-
[ Opcodes.i32_store8, 0,
|
3334
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3387
3335
|
];
|
3388
3336
|
};
|
3389
3337
|
|
3390
|
-
const loadArray = (scope, array, index
|
3338
|
+
const loadArray = (scope, array, index) => {
|
3391
3339
|
if (typeof index === 'number') index = number(index);
|
3392
3340
|
|
3393
3341
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3398,20 +3346,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3398
3346
|
Opcodes.i32_to_u,
|
3399
3347
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3400
3348
|
[ Opcodes.i32_mul ],
|
3401
|
-
|
3402
|
-
|
3403
|
-
|
3404
|
-
|
3405
|
-
]),
|
3349
|
+
|
3350
|
+
...array,
|
3351
|
+
Opcodes.i32_to_u,
|
3352
|
+
[ Opcodes.i32_add ],
|
3406
3353
|
[ Opcodes.local_set, offset ],
|
3407
3354
|
|
3408
3355
|
// load value
|
3409
3356
|
[ Opcodes.local_get, offset ],
|
3410
|
-
[ Opcodes.load, 0,
|
3357
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3411
3358
|
|
3412
3359
|
// load type
|
3413
3360
|
[ Opcodes.local_get, offset ],
|
3414
|
-
[ Opcodes.i32_load8_u, 0,
|
3361
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3415
3362
|
];
|
3416
3363
|
};
|
3417
3364
|
|
@@ -3443,7 +3390,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3443
3390
|
};
|
3444
3391
|
|
3445
3392
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3446
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3393
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3447
3394
|
};
|
3448
3395
|
|
3449
3396
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3462,9 +3409,6 @@ const withType = (scope, wasm, type) => [
|
|
3462
3409
|
|
3463
3410
|
const generateMember = (scope, decl, _global, _name) => {
|
3464
3411
|
const name = decl.object.name;
|
3465
|
-
const pointer = scope.arrays?.get(name);
|
3466
|
-
|
3467
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3468
3412
|
|
3469
3413
|
// hack: .name
|
3470
3414
|
if (decl.property.name === 'name') {
|
@@ -3505,12 +3449,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3505
3449
|
if (Prefs.fastLength) {
|
3506
3450
|
// presume valid length object
|
3507
3451
|
return [
|
3508
|
-
...(
|
3509
|
-
|
3510
|
-
Opcodes.i32_to_u
|
3511
|
-
]),
|
3452
|
+
...generate(scope, decl.object),
|
3453
|
+
Opcodes.i32_to_u,
|
3512
3454
|
|
3513
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3455
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3514
3456
|
Opcodes.i32_from_u
|
3515
3457
|
];
|
3516
3458
|
}
|
@@ -3519,12 +3461,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3519
3461
|
const known = knownType(scope, type);
|
3520
3462
|
if (known != null) {
|
3521
3463
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3522
|
-
...(
|
3523
|
-
|
3524
|
-
Opcodes.i32_to_u
|
3525
|
-
]),
|
3464
|
+
...generate(scope, decl.object),
|
3465
|
+
Opcodes.i32_to_u,
|
3526
3466
|
|
3527
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3467
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3528
3468
|
Opcodes.i32_from_u
|
3529
3469
|
];
|
3530
3470
|
|
@@ -3534,12 +3474,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3534
3474
|
return [
|
3535
3475
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3536
3476
|
[ Opcodes.if, valtypeBinary ],
|
3537
|
-
...(
|
3538
|
-
|
3539
|
-
Opcodes.i32_to_u
|
3540
|
-
]),
|
3477
|
+
...generate(scope, decl.object),
|
3478
|
+
Opcodes.i32_to_u,
|
3541
3479
|
|
3542
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3480
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3543
3481
|
Opcodes.i32_from_u,
|
3544
3482
|
|
3545
3483
|
...setLastType(scope, TYPES.number),
|
@@ -3582,25 +3520,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3582
3520
|
|
3583
3521
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3584
3522
|
// hack: this is naughty and will break things!
|
3585
|
-
let newOut = number(0,
|
3586
|
-
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?
|
3587
3526
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3588
|
-
rawElements: new Array(
|
3589
|
-
}, _global, _name, true, 'i16');
|
3527
|
+
rawElements: new Array(0)
|
3528
|
+
}, _global, _name, true, 'i16', true);
|
3590
3529
|
}
|
3591
3530
|
|
3592
3531
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3593
3532
|
[TYPES.array]: [
|
3594
|
-
...loadArray(scope, object, property
|
3533
|
+
...loadArray(scope, object, property),
|
3595
3534
|
...setLastType(scope)
|
3596
3535
|
],
|
3597
|
-
|
3598
3536
|
[TYPES.string]: [
|
3599
3537
|
// setup new/out array
|
3600
3538
|
...newOut,
|
3601
|
-
[ Opcodes.drop ],
|
3602
3539
|
|
3603
|
-
|
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,
|
3604
3546
|
|
3605
3547
|
...property,
|
3606
3548
|
Opcodes.i32_to_u,
|
@@ -3608,46 +3550,48 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3608
3550
|
...number(ValtypeSize.i16, Valtype.i32),
|
3609
3551
|
[ Opcodes.i32_mul ],
|
3610
3552
|
|
3611
|
-
...
|
3612
|
-
|
3613
|
-
|
3614
|
-
[ Opcodes.i32_add ]
|
3615
|
-
]),
|
3553
|
+
...object,
|
3554
|
+
Opcodes.i32_to_u,
|
3555
|
+
[ Opcodes.i32_add ],
|
3616
3556
|
|
3617
3557
|
// load current string ind {arg}
|
3618
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3558
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3619
3559
|
|
3620
3560
|
// store to new string ind 0
|
3621
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3561
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3622
3562
|
|
3623
3563
|
// return new string (page)
|
3624
|
-
...
|
3564
|
+
...newPointer,
|
3565
|
+
Opcodes.i32_from_u,
|
3625
3566
|
...setLastType(scope, TYPES.string)
|
3626
3567
|
],
|
3627
3568
|
[TYPES.bytestring]: [
|
3628
3569
|
// setup new/out array
|
3629
3570
|
...newOut,
|
3630
|
-
[ Opcodes.drop ],
|
3631
3571
|
|
3632
|
-
|
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,
|
3633
3578
|
|
3634
3579
|
...property,
|
3635
3580
|
Opcodes.i32_to_u,
|
3636
3581
|
|
3637
|
-
...
|
3638
|
-
|
3639
|
-
|
3640
|
-
[ Opcodes.i32_add ]
|
3641
|
-
]),
|
3582
|
+
...object,
|
3583
|
+
Opcodes.i32_to_u,
|
3584
|
+
[ Opcodes.i32_add ],
|
3642
3585
|
|
3643
3586
|
// load current string ind {arg}
|
3644
|
-
[ Opcodes.i32_load8_u, 0,
|
3587
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3645
3588
|
|
3646
3589
|
// store to new string ind 0
|
3647
|
-
[ Opcodes.i32_store8, 0,
|
3590
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3648
3591
|
|
3649
3592
|
// return new string (page)
|
3650
|
-
...
|
3593
|
+
...newPointer,
|
3594
|
+
Opcodes.i32_from_u,
|
3651
3595
|
...setLastType(scope, TYPES.bytestring)
|
3652
3596
|
],
|
3653
3597
|
|
@@ -3792,9 +3736,9 @@ const internalConstrs = {
|
|
3792
3736
|
|
3793
3737
|
// new Array(n)
|
3794
3738
|
|
3795
|
-
const [ , pointer ] = makeArray(scope, {
|
3739
|
+
const [ out, pointer ] = makeArray(scope, {
|
3796
3740
|
rawElements: new Array(0)
|
3797
|
-
}, global, name, true);
|
3741
|
+
}, global, name, true, undefined, true);
|
3798
3742
|
|
3799
3743
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3800
3744
|
|
@@ -3803,12 +3747,13 @@ const internalConstrs = {
|
|
3803
3747
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3804
3748
|
|
3805
3749
|
return [
|
3806
|
-
...
|
3750
|
+
...out,
|
3807
3751
|
...generate(scope, arg, global, name),
|
3808
3752
|
Opcodes.i32_to_u,
|
3809
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3753
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3810
3754
|
|
3811
|
-
...
|
3755
|
+
...pointer,
|
3756
|
+
Opcodes.i32_from_u
|
3812
3757
|
];
|
3813
3758
|
},
|
3814
3759
|
type: TYPES.array,
|
@@ -3957,8 +3902,9 @@ const internalConstrs = {
|
|
3957
3902
|
};
|
3958
3903
|
|
3959
3904
|
export default program => {
|
3960
|
-
globals = {
|
3961
|
-
|
3905
|
+
globals = {
|
3906
|
+
['#ind']: 0
|
3907
|
+
};
|
3962
3908
|
tags = [];
|
3963
3909
|
exceptions = [];
|
3964
3910
|
funcs = [];
|
@@ -3991,6 +3937,7 @@ export default program => {
|
|
3991
3937
|
builtinFuncs = new BuiltinFuncs();
|
3992
3938
|
builtinVars = new BuiltinVars();
|
3993
3939
|
prototypeFuncs = new PrototypeFuncs();
|
3940
|
+
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
3994
3941
|
|
3995
3942
|
program.id = { name: 'main' };
|
3996
3943
|
|
@@ -4033,6 +3980,8 @@ export default program => {
|
|
4033
3980
|
else main.returns = [];
|
4034
3981
|
}
|
4035
3982
|
|
3983
|
+
delete globals['#ind'];
|
3984
|
+
|
4036
3985
|
// if blank main func and other exports, remove it
|
4037
3986
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4038
3987
|
|