porffor 0.16.0-594397507 → 0.16.0-5c5338783
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/compiler/2c.js +53 -65
- package/compiler/allocators.js +129 -0
- package/compiler/assemble.js +12 -5
- package/compiler/builtins/array.ts +3 -4
- package/compiler/builtins/date.ts +2 -5
- package/compiler/builtins/porffor.d.ts +3 -0
- package/compiler/builtins/set.ts +2 -5
- package/compiler/builtins.js +25 -5
- package/compiler/codegen.js +266 -332
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +3 -1
- package/compiler/generated_builtins.js +46 -46
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +104 -7
- package/compiler/opt.js +10 -44
- package/compiler/parse.js +1 -7
- package/compiler/pgo.js +212 -0
- package/compiler/precompile.js +12 -7
- package/compiler/prefs.js +8 -4
- package/compiler/prototype.js +34 -43
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +55 -13
- package/package.json +3 -5
- package/runner/index.js +26 -11
- /package/runner/{profiler.js → profile.js} +0 -0
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
|
+
}, global, 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
|
@@ -1054,7 +998,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1054
998
|
});
|
1055
999
|
};
|
1056
1000
|
|
1057
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1001
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1058
1002
|
const existing = funcs.find(x => x.name === name);
|
1059
1003
|
if (existing) return existing;
|
1060
1004
|
|
@@ -1068,7 +1012,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1068
1012
|
|
1069
1013
|
for (const x of _data) {
|
1070
1014
|
const copy = { ...x };
|
1071
|
-
copy.offset += pages.size * pageSize;
|
1015
|
+
if (copy.offset != null) copy.offset += pages.size * pageSize;
|
1072
1016
|
data.push(copy);
|
1073
1017
|
}
|
1074
1018
|
|
@@ -1078,7 +1022,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1078
1022
|
locals,
|
1079
1023
|
localInd: allLocals.length,
|
1080
1024
|
returns,
|
1081
|
-
returnType
|
1025
|
+
returnType,
|
1082
1026
|
internal: true,
|
1083
1027
|
index: currentFuncIndex++,
|
1084
1028
|
table
|
@@ -1091,9 +1035,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1091
1035
|
|
1092
1036
|
let baseGlobalIdx, i = 0;
|
1093
1037
|
for (const type of globalTypes) {
|
1094
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1038
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
|
1095
1039
|
|
1096
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1040
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
|
1097
1041
|
i++;
|
1098
1042
|
}
|
1099
1043
|
|
@@ -1106,11 +1050,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1106
1050
|
}
|
1107
1051
|
}
|
1108
1052
|
|
1109
|
-
if (table)
|
1110
|
-
|
1111
|
-
inst.
|
1112
|
-
|
1053
|
+
if (table) {
|
1054
|
+
for (const inst of wasm) {
|
1055
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1056
|
+
inst.splice(2, 99);
|
1057
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1058
|
+
}
|
1113
1059
|
}
|
1060
|
+
|
1061
|
+
funcs.table = true;
|
1114
1062
|
}
|
1115
1063
|
|
1116
1064
|
func.wasm = wasm;
|
@@ -1254,7 +1202,7 @@ const getNodeType = (scope, node) => {
|
|
1254
1202
|
const func = funcs.find(x => x.name === name);
|
1255
1203
|
|
1256
1204
|
if (func) {
|
1257
|
-
if (func.returnType) return func.returnType;
|
1205
|
+
if (func.returnType != null) return func.returnType;
|
1258
1206
|
}
|
1259
1207
|
|
1260
1208
|
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
|
@@ -1270,15 +1218,7 @@ const getNodeType = (scope, node) => {
|
|
1270
1218
|
const func = spl[spl.length - 1];
|
1271
1219
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1272
1220
|
if (protoFuncs.length === 1) {
|
1273
|
-
if (protoFuncs[0].returnType) return protoFuncs[0].returnType;
|
1274
|
-
}
|
1275
|
-
|
1276
|
-
if (protoFuncs.length > 0) {
|
1277
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1278
|
-
|
1279
|
-
// presume
|
1280
|
-
// todo: warn here?
|
1281
|
-
return TYPES.number;
|
1221
|
+
if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
|
1282
1222
|
}
|
1283
1223
|
}
|
1284
1224
|
|
@@ -1458,10 +1398,10 @@ const countLeftover = wasm => {
|
|
1458
1398
|
|
1459
1399
|
if (depth === 0)
|
1460
1400
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1461
|
-
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] <
|
1401
|
+
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)) {}
|
1462
1402
|
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++;
|
1463
1403
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1464
|
-
else if (Opcodes.memory_copy[0]
|
1404
|
+
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1465
1405
|
else if (inst[0] === Opcodes.return) count = 0;
|
1466
1406
|
else if (inst[0] === Opcodes.call) {
|
1467
1407
|
let func = funcs.find(x => x.index === inst[1]);
|
@@ -1733,7 +1673,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1733
1673
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1734
1674
|
return makeArray(scope, {
|
1735
1675
|
rawElements: new Array(length)
|
1736
|
-
}, _global, _name, true, itemType);
|
1676
|
+
}, _global, _name, true, itemType, true);
|
1737
1677
|
}, () => {
|
1738
1678
|
optUnused = true;
|
1739
1679
|
return unusedValue;
|
@@ -1815,7 +1755,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1815
1755
|
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1816
1756
|
|
1817
1757
|
// value
|
1818
|
-
i32_const: { imms: 1, args: [], returns:
|
1758
|
+
i32_const: { imms: 1, args: [], returns: 0 },
|
1819
1759
|
};
|
1820
1760
|
|
1821
1761
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1978,7 +1918,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
1918
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1979
1919
|
const userFunc = func && !func.internal;
|
1980
1920
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1981
|
-
const typedReturns = (
|
1921
|
+
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1982
1922
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1983
1923
|
|
1984
1924
|
let args = decl.arguments;
|
@@ -2007,8 +1947,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2007
1947
|
}
|
2008
1948
|
|
2009
1949
|
if (valtypeBinary !== Valtype.i32 && (
|
2010
|
-
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2011
|
-
(importedFuncs[name] && name.startsWith('profile'))
|
1950
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1951
|
+
// (importedFuncs[name] && name.startsWith('profile'))
|
2012
1952
|
)) {
|
2013
1953
|
out.push(Opcodes.i32_to);
|
2014
1954
|
}
|
@@ -2123,7 +2063,6 @@ const brTable = (input, bc, returns) => {
|
|
2123
2063
|
}
|
2124
2064
|
|
2125
2065
|
for (let i = 0; i < count; i++) {
|
2126
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2127
2066
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2128
2067
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2129
2068
|
}
|
@@ -2157,10 +2096,8 @@ const brTable = (input, bc, returns) => {
|
|
2157
2096
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2158
2097
|
);
|
2159
2098
|
|
2160
|
-
//
|
2161
|
-
// (
|
2162
|
-
// dm me and if you are correct and the first person
|
2163
|
-
// I will somehow shout you out or something
|
2099
|
+
// sort the wrong way and then reverse
|
2100
|
+
// so strings ('default') are at the start before any numbers
|
2164
2101
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2165
2102
|
|
2166
2103
|
br = count - 1;
|
@@ -2186,10 +2123,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2186
2123
|
return bc[known] ?? bc.default;
|
2187
2124
|
}
|
2188
2125
|
|
2189
|
-
if (Prefs.
|
2126
|
+
if (Prefs.typeswitchBrtable)
|
2190
2127
|
return brTable(type, bc, returns);
|
2191
2128
|
|
2192
|
-
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
2129
|
+
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
2193
2130
|
const out = [
|
2194
2131
|
...type,
|
2195
2132
|
[ Opcodes.local_set, tmp ],
|
@@ -2241,11 +2178,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2241
2178
|
return target[name].idx;
|
2242
2179
|
}
|
2243
2180
|
|
2244
|
-
let idx = global ?
|
2181
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2245
2182
|
target[name] = { idx, type: valtypeBinary };
|
2246
2183
|
|
2247
2184
|
if (type) {
|
2248
|
-
let typeIdx = global ?
|
2185
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2249
2186
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2250
2187
|
}
|
2251
2188
|
|
@@ -2338,24 +2275,10 @@ const generateVar = (scope, decl) => {
|
|
2338
2275
|
}
|
2339
2276
|
|
2340
2277
|
if (x.init) {
|
2341
|
-
|
2342
|
-
// // let a = function () { ... }
|
2343
|
-
// x.init.id = { name };
|
2344
|
-
|
2345
|
-
// const func = generateFunc(scope, x.init);
|
2346
|
-
|
2347
|
-
// out.push(
|
2348
|
-
// ...number(func.index - importedFuncs.length),
|
2349
|
-
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2350
|
-
|
2351
|
-
// ...setType(scope, name, TYPES.function)
|
2352
|
-
// );
|
2353
|
-
|
2354
|
-
// continue;
|
2355
|
-
// }
|
2278
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2356
2279
|
|
2357
2280
|
const generated = generate(scope, x.init, global, name);
|
2358
|
-
if (scope.arrays?.get(name) != null) {
|
2281
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2359
2282
|
// hack to set local as pointer before
|
2360
2283
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2361
2284
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2407,19 +2330,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2407
2330
|
|
2408
2331
|
// hack: .length setter
|
2409
2332
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2410
|
-
const name = decl.left.object.name;
|
2411
|
-
const pointer = scope.arrays?.get(name);
|
2412
|
-
|
2413
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2414
|
-
|
2415
2333
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2416
2334
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2417
2335
|
|
2418
2336
|
return [
|
2419
|
-
...(
|
2420
|
-
|
2421
|
-
Opcodes.i32_to_u
|
2422
|
-
]),
|
2337
|
+
...generate(scope, decl.left.object),
|
2338
|
+
Opcodes.i32_to_u,
|
2423
2339
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2424
2340
|
|
2425
2341
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2430,7 +2346,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2430
2346
|
[ Opcodes.local_tee, newValueTmp ],
|
2431
2347
|
|
2432
2348
|
Opcodes.i32_to_u,
|
2433
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2349
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2434
2350
|
|
2435
2351
|
[ Opcodes.local_get, newValueTmp ]
|
2436
2352
|
];
|
@@ -2438,21 +2354,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2438
2354
|
|
2439
2355
|
// arr[i]
|
2440
2356
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2441
|
-
const name = decl.left.object.name;
|
2442
|
-
const pointer = scope.arrays?.get(name);
|
2443
|
-
|
2444
|
-
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2445
|
-
|
2446
2357
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2447
2358
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2448
2359
|
|
2449
2360
|
return [
|
2450
2361
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2451
2362
|
[TYPES.array]: [
|
2452
|
-
...(
|
2453
|
-
|
2454
|
-
Opcodes.i32_to_u
|
2455
|
-
]),
|
2363
|
+
...generate(scope, decl.left.object),
|
2364
|
+
Opcodes.i32_to_u,
|
2456
2365
|
|
2457
2366
|
// get index as valtype
|
2458
2367
|
...generate(scope, decl.left.property),
|
@@ -2461,39 +2370,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2461
2370
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2462
2371
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2463
2372
|
[ Opcodes.i32_mul ],
|
2464
|
-
|
2373
|
+
[ Opcodes.i32_add ],
|
2465
2374
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2466
2375
|
|
2467
2376
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2468
2377
|
[ Opcodes.local_get, pointerTmp ],
|
2469
|
-
[ Opcodes.load, 0,
|
2378
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2470
2379
|
], generate(scope, decl.right), [
|
2471
2380
|
[ Opcodes.local_get, pointerTmp ],
|
2472
|
-
[ Opcodes.i32_load8_u, 0,
|
2381
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2473
2382
|
], getNodeType(scope, decl.right), false, name, true)),
|
2474
2383
|
[ Opcodes.local_tee, newValueTmp ],
|
2475
2384
|
|
2476
|
-
[ Opcodes.store, 0,
|
2385
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2477
2386
|
],
|
2478
2387
|
|
2479
2388
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2480
|
-
|
2481
|
-
// [TYPES.string]: [
|
2482
|
-
// // turn into byte offset by * sizeof i16
|
2483
|
-
// ...number(ValtypeSize.i16, Valtype.i32),
|
2484
|
-
// [ Opcodes.i32_mul ],
|
2485
|
-
// ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2486
|
-
// ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2487
|
-
|
2488
|
-
// ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2489
|
-
// [ Opcodes.local_get, pointerTmp ],
|
2490
|
-
// [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2491
|
-
// ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
|
2492
|
-
// [ Opcodes.local_tee, newValueTmp ],
|
2493
|
-
|
2494
|
-
// Opcodes.i32_to_u,
|
2495
|
-
// [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2496
|
-
// ]
|
2497
2389
|
}, Blocktype.void),
|
2498
2390
|
|
2499
2391
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2571,7 +2463,7 @@ const generateUnary = (scope, decl) => {
|
|
2571
2463
|
// * -1
|
2572
2464
|
|
2573
2465
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
2574
|
-
// if
|
2466
|
+
// if -n, just return that as a const
|
2575
2467
|
return number(-1 * decl.argument.value);
|
2576
2468
|
}
|
2577
2469
|
|
@@ -2583,14 +2475,14 @@ const generateUnary = (scope, decl) => {
|
|
2583
2475
|
case '!':
|
2584
2476
|
const arg = decl.argument;
|
2585
2477
|
if (arg.type === 'UnaryExpression' && arg.operator === '!') {
|
2586
|
-
// !!x -> is x truthy
|
2478
|
+
// opt: !!x -> is x truthy
|
2587
2479
|
return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
|
2588
2480
|
}
|
2481
|
+
|
2589
2482
|
// !=
|
2590
|
-
return falsy(scope, generate(scope,
|
2483
|
+
return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
|
2591
2484
|
|
2592
2485
|
case '~':
|
2593
|
-
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
2594
2486
|
return [
|
2595
2487
|
...generate(scope, decl.argument),
|
2596
2488
|
Opcodes.i32_to,
|
@@ -2877,12 +2769,12 @@ const generateForOf = (scope, decl) => {
|
|
2877
2769
|
|
2878
2770
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2879
2771
|
// hack: this is naughty and will break things!
|
2880
|
-
let newOut = number(0, Valtype.
|
2772
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2881
2773
|
if (pages.hasAnyString) {
|
2882
2774
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2883
2775
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2884
|
-
rawElements: new Array(
|
2885
|
-
}, isGlobal, leftName, true, 'i16');
|
2776
|
+
rawElements: new Array(0)
|
2777
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2886
2778
|
}
|
2887
2779
|
|
2888
2780
|
// set type for local
|
@@ -2929,23 +2821,28 @@ const generateForOf = (scope, decl) => {
|
|
2929
2821
|
[TYPES.string]: [
|
2930
2822
|
...setType(scope, leftName, TYPES.string),
|
2931
2823
|
|
2932
|
-
[ Opcodes.loop, Blocktype.void ],
|
2933
|
-
|
2934
2824
|
// setup new/out array
|
2935
2825
|
...newOut,
|
2936
|
-
[ Opcodes.drop ],
|
2937
2826
|
|
2938
|
-
|
2827
|
+
// set length to 1
|
2828
|
+
...number(1, Valtype.i32),
|
2829
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2830
|
+
|
2831
|
+
[ Opcodes.loop, Blocktype.void ],
|
2832
|
+
|
2833
|
+
// use as pointer for store later
|
2834
|
+
...newPointer,
|
2939
2835
|
|
2940
2836
|
// load current string ind {arg}
|
2941
2837
|
[ Opcodes.local_get, pointer ],
|
2942
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
2838
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2943
2839
|
|
2944
2840
|
// store to new string ind 0
|
2945
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
2841
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2946
2842
|
|
2947
2843
|
// return new string (page)
|
2948
|
-
...
|
2844
|
+
...newPointer,
|
2845
|
+
Opcodes.i32_from_u,
|
2949
2846
|
|
2950
2847
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2951
2848
|
|
@@ -2977,25 +2874,30 @@ const generateForOf = (scope, decl) => {
|
|
2977
2874
|
[TYPES.bytestring]: [
|
2978
2875
|
...setType(scope, leftName, TYPES.bytestring),
|
2979
2876
|
|
2980
|
-
[ Opcodes.loop, Blocktype.void ],
|
2981
|
-
|
2982
2877
|
// setup new/out array
|
2983
2878
|
...newOut,
|
2984
|
-
[ Opcodes.drop ],
|
2985
2879
|
|
2986
|
-
|
2880
|
+
// set length to 1
|
2881
|
+
...number(1, Valtype.i32),
|
2882
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2883
|
+
|
2884
|
+
[ Opcodes.loop, Blocktype.void ],
|
2885
|
+
|
2886
|
+
// use as pointer for store later
|
2887
|
+
...newPointer,
|
2987
2888
|
|
2988
2889
|
// load current string ind {arg}
|
2989
2890
|
[ Opcodes.local_get, pointer ],
|
2990
2891
|
[ Opcodes.local_get, counter ],
|
2991
2892
|
[ Opcodes.i32_add ],
|
2992
|
-
[ Opcodes.i32_load8_u, 0,
|
2893
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2993
2894
|
|
2994
2895
|
// store to new string ind 0
|
2995
|
-
[ Opcodes.i32_store8, 0,
|
2896
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2996
2897
|
|
2997
2898
|
// return new string (page)
|
2998
|
-
...
|
2899
|
+
...newPointer,
|
2900
|
+
Opcodes.i32_from_u,
|
2999
2901
|
|
3000
2902
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3001
2903
|
|
@@ -3210,18 +3112,6 @@ const allocPage = (scope, reason, type) => {
|
|
3210
3112
|
scope.pages ??= new Map();
|
3211
3113
|
scope.pages.set(reason, { ind, type });
|
3212
3114
|
|
3213
|
-
if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
3214
|
-
|
3215
|
-
return ind;
|
3216
|
-
};
|
3217
|
-
|
3218
|
-
// todo: add scope.pages
|
3219
|
-
const freePage = reason => {
|
3220
|
-
const { ind } = pages.get(reason);
|
3221
|
-
pages.delete(reason);
|
3222
|
-
|
3223
|
-
if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
3224
|
-
|
3225
3115
|
return ind;
|
3226
3116
|
};
|
3227
3117
|
|
@@ -3259,39 +3149,58 @@ const compileBytes = (val, itemType) => {
|
|
3259
3149
|
}
|
3260
3150
|
};
|
3261
3151
|
|
3262
|
-
const
|
3263
|
-
|
3264
|
-
case 'i8': return 'bytestring';
|
3265
|
-
case 'i16': return 'string';
|
3152
|
+
const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
|
3153
|
+
const length = elements.length;
|
3266
3154
|
|
3267
|
-
|
3155
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3156
|
+
if (length === 0) return false;
|
3157
|
+
|
3158
|
+
let bytes = compileBytes(length, 'i32');
|
3159
|
+
|
3160
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3161
|
+
if (elements[i] == null) continue;
|
3162
|
+
|
3163
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3268
3164
|
}
|
3269
|
-
};
|
3270
3165
|
|
3271
|
-
const
|
3272
|
-
|
3166
|
+
const obj = { bytes };
|
3167
|
+
if (offset != null) obj.offset = offset;
|
3168
|
+
|
3169
|
+
const idx = data.push(obj) - 1;
|
3273
3170
|
|
3274
|
-
scope.
|
3171
|
+
scope.data ??= [];
|
3172
|
+
scope.data.push(idx);
|
3275
3173
|
|
3276
|
-
|
3277
|
-
|
3278
|
-
|
3174
|
+
return { idx, size: bytes.length };
|
3175
|
+
};
|
3176
|
+
|
3177
|
+
const printStaticStr = str => {
|
3178
|
+
const out = [];
|
3279
3179
|
|
3280
|
-
|
3281
|
-
|
3180
|
+
for (let i = 0; i < str.length; i++) {
|
3181
|
+
out.push(
|
3182
|
+
// ...number(str.charCodeAt(i)),
|
3183
|
+
...number(str.charCodeAt(i), Valtype.i32),
|
3184
|
+
Opcodes.i32_from_u,
|
3185
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3186
|
+
);
|
3187
|
+
}
|
3282
3188
|
|
3283
|
-
|
3284
|
-
|
3285
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3189
|
+
return out;
|
3190
|
+
};
|
3286
3191
|
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3192
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
3193
|
+
if (itemType !== 'i16' && itemType !== 'i8') {
|
3194
|
+
pages.hasArray = true;
|
3195
|
+
} else {
|
3196
|
+
pages.hasAnyString = true;
|
3197
|
+
if (itemType === 'i8') pages.hasByteString = true;
|
3198
|
+
else pages.hasString = true;
|
3290
3199
|
}
|
3291
3200
|
|
3292
|
-
const
|
3201
|
+
const out = [];
|
3293
3202
|
|
3294
|
-
const
|
3203
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3295
3204
|
|
3296
3205
|
const useRawElements = !!decl.rawElements;
|
3297
3206
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3299,46 +3208,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3299
3208
|
const valtype = itemTypeToValtype[itemType];
|
3300
3209
|
const length = elements.length;
|
3301
3210
|
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3211
|
+
const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
|
3212
|
+
|
3213
|
+
let pointer = allocated;
|
3214
|
+
if (allocator.constructor.name !== 'StaticAllocator') {
|
3215
|
+
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3216
|
+
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
3217
|
+
out.push(
|
3218
|
+
...allocated,
|
3219
|
+
[ Opcodes.local_set, tmp ]
|
3220
|
+
);
|
3221
|
+
|
3222
|
+
if (Prefs.runtimeAllocLog) out.push(
|
3223
|
+
...printStaticStr(`${name}: `),
|
3306
3224
|
|
3307
|
-
|
3308
|
-
|
3225
|
+
[ Opcodes.local_get, tmp ],
|
3226
|
+
Opcodes.i32_from_u,
|
3227
|
+
[ Opcodes.call, 0 ],
|
3309
3228
|
|
3310
|
-
|
3229
|
+
...number(10),
|
3230
|
+
[ Opcodes.call, 1 ]
|
3231
|
+
);
|
3232
|
+
|
3233
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3234
|
+
|
3235
|
+
if (Prefs.data && useRawElements) {
|
3236
|
+
const data = makeData(scope, elements, null, itemType, initEmpty);
|
3237
|
+
if (data) {
|
3238
|
+
// init data
|
3239
|
+
out.push(
|
3240
|
+
...pointer,
|
3241
|
+
...number(0, Valtype.i32),
|
3242
|
+
...number(data.size, Valtype.i32),
|
3243
|
+
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
3244
|
+
);
|
3311
3245
|
}
|
3312
3246
|
|
3313
|
-
|
3314
|
-
|
3315
|
-
|
3316
|
-
|
3247
|
+
// return pointer in out
|
3248
|
+
out.push(
|
3249
|
+
...pointer,
|
3250
|
+
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
3251
|
+
);
|
3317
3252
|
|
3318
|
-
|
3319
|
-
scope.data.push(ind);
|
3253
|
+
return [ out, pointer ];
|
3320
3254
|
}
|
3255
|
+
} else {
|
3256
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3321
3257
|
|
3322
|
-
|
3323
|
-
|
3258
|
+
scope.arrays ??= new Map();
|
3259
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3260
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3324
3261
|
|
3325
|
-
|
3326
|
-
|
3262
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3263
|
+
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
3327
3264
|
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
)
|
3265
|
+
// local value as pointer
|
3266
|
+
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3267
|
+
}
|
3268
|
+
|
3269
|
+
const local = global ? globals[name] : scope.locals[name];
|
3270
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3271
|
+
if (pointerTmp != null) {
|
3272
|
+
out.push(
|
3273
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3274
|
+
Opcodes.i32_to_u,
|
3275
|
+
[ Opcodes.local_set, pointerTmp ]
|
3276
|
+
);
|
3277
|
+
|
3278
|
+
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
3279
|
+
}
|
3335
3280
|
}
|
3336
3281
|
|
3337
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3338
3282
|
|
3339
3283
|
// store length
|
3340
3284
|
out.push(
|
3341
|
-
...
|
3285
|
+
...pointer,
|
3342
3286
|
...number(length, Valtype.i32),
|
3343
3287
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3344
3288
|
);
|
@@ -3350,11 +3294,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3350
3294
|
|
3351
3295
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3352
3296
|
out.push(
|
3353
|
-
...
|
3297
|
+
...pointer,
|
3354
3298
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3355
3299
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3356
3300
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3357
|
-
...
|
3301
|
+
...pointer,
|
3358
3302
|
...getNodeType(scope, elements[i]),
|
3359
3303
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3360
3304
|
])
|
@@ -3362,12 +3306,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3362
3306
|
}
|
3363
3307
|
|
3364
3308
|
// local value as pointer
|
3365
|
-
out.push(...
|
3309
|
+
out.push(...pointer);
|
3310
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3366
3311
|
|
3367
3312
|
return [ out, pointer ];
|
3368
3313
|
};
|
3369
3314
|
|
3370
|
-
const storeArray = (scope, array, index, element
|
3315
|
+
const storeArray = (scope, array, index, element) => {
|
3371
3316
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3372
3317
|
if (typeof index === 'number') index = number(index);
|
3373
3318
|
|
@@ -3379,26 +3324,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3379
3324
|
Opcodes.i32_to_u,
|
3380
3325
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3381
3326
|
[ Opcodes.i32_mul ],
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
]),
|
3327
|
+
|
3328
|
+
...array,
|
3329
|
+
Opcodes.i32_to_u,
|
3330
|
+
[ Opcodes.i32_add ],
|
3387
3331
|
[ Opcodes.local_set, offset ],
|
3388
3332
|
|
3389
3333
|
// store value
|
3390
3334
|
[ Opcodes.local_get, offset ],
|
3391
3335
|
...generate(scope, element),
|
3392
|
-
[ Opcodes.store, 0,
|
3336
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3393
3337
|
|
3394
3338
|
// store type
|
3395
3339
|
[ Opcodes.local_get, offset ],
|
3396
3340
|
...getNodeType(scope, element),
|
3397
|
-
[ Opcodes.i32_store8, 0,
|
3341
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3398
3342
|
];
|
3399
3343
|
};
|
3400
3344
|
|
3401
|
-
const loadArray = (scope, array, index
|
3345
|
+
const loadArray = (scope, array, index) => {
|
3402
3346
|
if (typeof index === 'number') index = number(index);
|
3403
3347
|
|
3404
3348
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3409,20 +3353,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3409
3353
|
Opcodes.i32_to_u,
|
3410
3354
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3411
3355
|
[ Opcodes.i32_mul ],
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3415
|
-
|
3416
|
-
]),
|
3356
|
+
|
3357
|
+
...array,
|
3358
|
+
Opcodes.i32_to_u,
|
3359
|
+
[ Opcodes.i32_add ],
|
3417
3360
|
[ Opcodes.local_set, offset ],
|
3418
3361
|
|
3419
3362
|
// load value
|
3420
3363
|
[ Opcodes.local_get, offset ],
|
3421
|
-
[ Opcodes.load, 0,
|
3364
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3422
3365
|
|
3423
3366
|
// load type
|
3424
3367
|
[ Opcodes.local_get, offset ],
|
3425
|
-
[ Opcodes.i32_load8_u, 0,
|
3368
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3426
3369
|
];
|
3427
3370
|
};
|
3428
3371
|
|
@@ -3454,7 +3397,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3454
3397
|
};
|
3455
3398
|
|
3456
3399
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3457
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3400
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3458
3401
|
};
|
3459
3402
|
|
3460
3403
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3473,9 +3416,6 @@ const withType = (scope, wasm, type) => [
|
|
3473
3416
|
|
3474
3417
|
const generateMember = (scope, decl, _global, _name) => {
|
3475
3418
|
const name = decl.object.name;
|
3476
|
-
const pointer = scope.arrays?.get(name);
|
3477
|
-
|
3478
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3479
3419
|
|
3480
3420
|
// hack: .name
|
3481
3421
|
if (decl.property.name === 'name') {
|
@@ -3510,18 +3450,16 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3510
3450
|
}
|
3511
3451
|
|
3512
3452
|
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
3513
|
-
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params), TYPES.number);
|
3453
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3514
3454
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3515
3455
|
|
3516
3456
|
if (Prefs.fastLength) {
|
3517
3457
|
// presume valid length object
|
3518
3458
|
return [
|
3519
|
-
...(
|
3520
|
-
|
3521
|
-
Opcodes.i32_to_u
|
3522
|
-
]),
|
3459
|
+
...generate(scope, decl.object),
|
3460
|
+
Opcodes.i32_to_u,
|
3523
3461
|
|
3524
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3462
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3525
3463
|
Opcodes.i32_from_u
|
3526
3464
|
];
|
3527
3465
|
}
|
@@ -3530,12 +3468,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3530
3468
|
const known = knownType(scope, type);
|
3531
3469
|
if (known != null) {
|
3532
3470
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3533
|
-
...(
|
3534
|
-
|
3535
|
-
Opcodes.i32_to_u
|
3536
|
-
]),
|
3471
|
+
...generate(scope, decl.object),
|
3472
|
+
Opcodes.i32_to_u,
|
3537
3473
|
|
3538
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3474
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3539
3475
|
Opcodes.i32_from_u
|
3540
3476
|
];
|
3541
3477
|
|
@@ -3545,12 +3481,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3545
3481
|
return [
|
3546
3482
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3547
3483
|
[ Opcodes.if, valtypeBinary ],
|
3548
|
-
...(
|
3549
|
-
|
3550
|
-
Opcodes.i32_to_u
|
3551
|
-
]),
|
3484
|
+
...generate(scope, decl.object),
|
3485
|
+
Opcodes.i32_to_u,
|
3552
3486
|
|
3553
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3487
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3554
3488
|
Opcodes.i32_from_u,
|
3555
3489
|
|
3556
3490
|
...setLastType(scope, TYPES.number),
|
@@ -3593,25 +3527,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3593
3527
|
|
3594
3528
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3595
3529
|
// hack: this is naughty and will break things!
|
3596
|
-
let newOut = number(0,
|
3530
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3597
3531
|
if (pages.hasAnyString) {
|
3532
|
+
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3598
3533
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3599
|
-
rawElements: new Array(
|
3600
|
-
}, _global, _name, true, 'i16');
|
3534
|
+
rawElements: new Array(0)
|
3535
|
+
}, _global, _name, true, 'i16', true);
|
3601
3536
|
}
|
3602
3537
|
|
3603
3538
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3604
3539
|
[TYPES.array]: [
|
3605
|
-
...loadArray(scope, object, property
|
3540
|
+
...loadArray(scope, object, property),
|
3606
3541
|
...setLastType(scope)
|
3607
3542
|
],
|
3608
|
-
|
3609
3543
|
[TYPES.string]: [
|
3610
3544
|
// setup new/out array
|
3611
3545
|
...newOut,
|
3612
|
-
[ Opcodes.drop ],
|
3613
3546
|
|
3614
|
-
|
3547
|
+
// set length to 1
|
3548
|
+
...number(1, Valtype.i32),
|
3549
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3550
|
+
|
3551
|
+
// use as pointer for store later
|
3552
|
+
...newPointer,
|
3615
3553
|
|
3616
3554
|
...property,
|
3617
3555
|
Opcodes.i32_to_u,
|
@@ -3619,46 +3557,48 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3619
3557
|
...number(ValtypeSize.i16, Valtype.i32),
|
3620
3558
|
[ Opcodes.i32_mul ],
|
3621
3559
|
|
3622
|
-
...
|
3623
|
-
|
3624
|
-
|
3625
|
-
[ Opcodes.i32_add ]
|
3626
|
-
]),
|
3560
|
+
...object,
|
3561
|
+
Opcodes.i32_to_u,
|
3562
|
+
[ Opcodes.i32_add ],
|
3627
3563
|
|
3628
3564
|
// load current string ind {arg}
|
3629
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3565
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3630
3566
|
|
3631
3567
|
// store to new string ind 0
|
3632
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3568
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3633
3569
|
|
3634
3570
|
// return new string (page)
|
3635
|
-
...
|
3571
|
+
...newPointer,
|
3572
|
+
Opcodes.i32_from_u,
|
3636
3573
|
...setLastType(scope, TYPES.string)
|
3637
3574
|
],
|
3638
3575
|
[TYPES.bytestring]: [
|
3639
3576
|
// setup new/out array
|
3640
3577
|
...newOut,
|
3641
|
-
[ Opcodes.drop ],
|
3642
3578
|
|
3643
|
-
|
3579
|
+
// set length to 1
|
3580
|
+
...number(1, Valtype.i32),
|
3581
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3582
|
+
|
3583
|
+
// use as pointer for store later
|
3584
|
+
...newPointer,
|
3644
3585
|
|
3645
3586
|
...property,
|
3646
3587
|
Opcodes.i32_to_u,
|
3647
3588
|
|
3648
|
-
...
|
3649
|
-
|
3650
|
-
|
3651
|
-
[ Opcodes.i32_add ]
|
3652
|
-
]),
|
3589
|
+
...object,
|
3590
|
+
Opcodes.i32_to_u,
|
3591
|
+
[ Opcodes.i32_add ],
|
3653
3592
|
|
3654
3593
|
// load current string ind {arg}
|
3655
|
-
[ Opcodes.i32_load8_u, 0,
|
3594
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3656
3595
|
|
3657
3596
|
// store to new string ind 0
|
3658
|
-
[ Opcodes.i32_store8, 0,
|
3597
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3659
3598
|
|
3660
3599
|
// return new string (page)
|
3661
|
-
...
|
3600
|
+
...newPointer,
|
3601
|
+
Opcodes.i32_from_u,
|
3662
3602
|
...setLastType(scope, TYPES.bytestring)
|
3663
3603
|
],
|
3664
3604
|
|
@@ -3666,7 +3606,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3666
3606
|
});
|
3667
3607
|
};
|
3668
3608
|
|
3669
|
-
const randId = () => Math.random().toString(16).slice(
|
3609
|
+
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
3670
3610
|
|
3671
3611
|
const objectHack = node => {
|
3672
3612
|
if (!node) return node;
|
@@ -3718,7 +3658,7 @@ const generateFunc = (scope, decl) => {
|
|
3718
3658
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3719
3659
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3720
3660
|
|
3721
|
-
const name = decl.id ? decl.id.name : `
|
3661
|
+
const name = decl.id ? decl.id.name : `anonymous${randId()}`;
|
3722
3662
|
const params = decl.params ?? [];
|
3723
3663
|
|
3724
3664
|
// TODO: share scope/locals between !!!
|
@@ -3803,9 +3743,9 @@ const internalConstrs = {
|
|
3803
3743
|
|
3804
3744
|
// new Array(n)
|
3805
3745
|
|
3806
|
-
const [ , pointer ] = makeArray(scope, {
|
3746
|
+
const [ out, pointer ] = makeArray(scope, {
|
3807
3747
|
rawElements: new Array(0)
|
3808
|
-
}, global, name, true);
|
3748
|
+
}, global, name, true, undefined, true);
|
3809
3749
|
|
3810
3750
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3811
3751
|
|
@@ -3814,12 +3754,13 @@ const internalConstrs = {
|
|
3814
3754
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3815
3755
|
|
3816
3756
|
return [
|
3817
|
-
...
|
3757
|
+
...out,
|
3818
3758
|
...generate(scope, arg, global, name),
|
3819
3759
|
Opcodes.i32_to_u,
|
3820
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3760
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3821
3761
|
|
3822
|
-
...
|
3762
|
+
...pointer,
|
3763
|
+
Opcodes.i32_from_u
|
3823
3764
|
];
|
3824
3765
|
},
|
3825
3766
|
type: TYPES.array,
|
@@ -3968,8 +3909,9 @@ const internalConstrs = {
|
|
3968
3909
|
};
|
3969
3910
|
|
3970
3911
|
export default program => {
|
3971
|
-
globals = {
|
3972
|
-
|
3912
|
+
globals = {
|
3913
|
+
['#ind']: 0
|
3914
|
+
};
|
3973
3915
|
tags = [];
|
3974
3916
|
exceptions = [];
|
3975
3917
|
funcs = [];
|
@@ -3979,19 +3921,8 @@ export default program => {
|
|
3979
3921
|
data = [];
|
3980
3922
|
currentFuncIndex = importedFuncs.length;
|
3981
3923
|
|
3982
|
-
globalThis.valtype = 'f64';
|
3983
|
-
|
3984
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3985
|
-
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3986
|
-
|
3987
|
-
globalThis.valtypeBinary = Valtype[valtype];
|
3988
|
-
|
3989
3924
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3990
3925
|
|
3991
|
-
globalThis.pageSize = PageSize;
|
3992
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3993
|
-
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3994
|
-
|
3995
3926
|
// set generic opcodes for current valtype
|
3996
3927
|
Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
|
3997
3928
|
Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
|
@@ -4013,6 +3944,7 @@ export default program => {
|
|
4013
3944
|
builtinFuncs = new BuiltinFuncs();
|
4014
3945
|
builtinVars = new BuiltinVars();
|
4015
3946
|
prototypeFuncs = new PrototypeFuncs();
|
3947
|
+
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
4016
3948
|
|
4017
3949
|
program.id = { name: 'main' };
|
4018
3950
|
|
@@ -4055,6 +3987,8 @@ export default program => {
|
|
4055
3987
|
else main.returns = [];
|
4056
3988
|
}
|
4057
3989
|
|
3990
|
+
delete globals['#ind'];
|
3991
|
+
|
4058
3992
|
// if blank main func and other exports, remove it
|
4059
3993
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4060
3994
|
|