porffor 0.16.0-8107e135a → 0.16.0-97bb4f33b
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/assemble.js +1 -7
- package/compiler/builtins/date.ts +4 -2
- package/compiler/builtins/set.ts +4 -2
- package/compiler/codegen.js +293 -227
- package/compiler/cyclone.js +12 -12
- package/compiler/generated_builtins.js +46 -46
- package/compiler/havoc.js +1 -1
- package/compiler/index.js +4 -29
- package/compiler/opt.js +5 -7
- package/compiler/parse.js +1 -1
- package/compiler/pgo.js +10 -11
- package/compiler/precompile.js +7 -12
- package/compiler/prefs.js +1 -1
- package/compiler/prototype.js +43 -34
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +2 -3
- package/no_pgo.txt +923 -0
- package/package.json +5 -3
- package/pgo.txt +916 -0
- package/runner/index.js +3 -10
- package/bf +0 -0
- package/compiler/allocators/grow.js +0 -25
- package/compiler/allocators/index.js +0 -10
- package/compiler/allocators/static.js +0 -42
package/compiler/codegen.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
2
|
-
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector
|
1
|
+
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } 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,16 +9,15 @@ 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 Allocator from './allocators/index.js';
|
13
12
|
|
14
13
|
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;
|
22
21
|
|
23
22
|
class TodoError extends Error {
|
24
23
|
constructor(message) {
|
@@ -182,6 +181,12 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
182
181
|
continue;
|
183
182
|
}
|
184
183
|
|
184
|
+
if (asm[0] === 'memory') {
|
185
|
+
allocPage(scope, 'asm instrinsic');
|
186
|
+
// todo: add to store/load offset insts
|
187
|
+
continue;
|
188
|
+
}
|
189
|
+
|
185
190
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
186
191
|
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
187
192
|
|
@@ -428,12 +433,63 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
428
433
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
429
434
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
430
435
|
|
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
|
+
|
431
487
|
const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
|
432
488
|
|
433
489
|
// alloc/assign array
|
434
|
-
const [
|
490
|
+
const [ , pointer ] = makeArray(scope, {
|
435
491
|
rawElements: new Array(0)
|
436
|
-
}, global, name, true, 'i16'
|
492
|
+
}, global, name, true, 'i16');
|
437
493
|
|
438
494
|
return [
|
439
495
|
// setup left
|
@@ -447,7 +503,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
447
503
|
[ Opcodes.local_set, rightPointer ],
|
448
504
|
|
449
505
|
// calculate length
|
450
|
-
...
|
506
|
+
...number(0, Valtype.i32), // base 0 for store later
|
451
507
|
|
452
508
|
[ Opcodes.local_get, leftPointer ],
|
453
509
|
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
@@ -460,13 +516,11 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
516
|
[ Opcodes.i32_add ],
|
461
517
|
|
462
518
|
// store length
|
463
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
519
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
|
464
520
|
|
465
521
|
// copy left
|
466
522
|
// dst = out pointer + length size
|
467
|
-
...pointer,
|
468
|
-
...number(ValtypeSize.i32, Valtype.i32),
|
469
|
-
[ Opcodes.i32_add ],
|
523
|
+
...number(pointer + ValtypeSize.i32, Valtype.i32),
|
470
524
|
|
471
525
|
// src = left pointer + length size
|
472
526
|
[ Opcodes.local_get, leftPointer ],
|
@@ -479,9 +533,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
479
533
|
|
480
534
|
// copy right
|
481
535
|
// dst = out pointer + length size + left length * sizeof valtype
|
482
|
-
...pointer,
|
483
|
-
...number(ValtypeSize.i32, Valtype.i32),
|
484
|
-
[ Opcodes.i32_add ],
|
536
|
+
...number(pointer + ValtypeSize.i32, Valtype.i32),
|
485
537
|
|
486
538
|
[ Opcodes.local_get, leftLength ],
|
487
539
|
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
@@ -501,8 +553,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
501
553
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
502
554
|
|
503
555
|
// return new string (page)
|
504
|
-
...pointer
|
505
|
-
Opcodes.i32_from_u
|
556
|
+
...number(pointer)
|
506
557
|
];
|
507
558
|
};
|
508
559
|
|
@@ -618,10 +669,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
618
669
|
};
|
619
670
|
|
620
671
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
672
|
+
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
673
|
+
...wasm,
|
674
|
+
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
675
|
+
];
|
625
676
|
// if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
|
626
677
|
|
627
678
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
@@ -1017,7 +1068,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1017
1068
|
|
1018
1069
|
for (const x of _data) {
|
1019
1070
|
const copy = { ...x };
|
1020
|
-
|
1071
|
+
copy.offset += pages.size * pageSize;
|
1021
1072
|
data.push(copy);
|
1022
1073
|
}
|
1023
1074
|
|
@@ -1040,9 +1091,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1040
1091
|
|
1041
1092
|
let baseGlobalIdx, i = 0;
|
1042
1093
|
for (const type of globalTypes) {
|
1043
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1094
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globalInd;
|
1044
1095
|
|
1045
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1096
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globalInd++, type, init: globalInits[i] ?? 0 };
|
1046
1097
|
i++;
|
1047
1098
|
}
|
1048
1099
|
|
@@ -1055,15 +1106,11 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1055
1106
|
}
|
1056
1107
|
}
|
1057
1108
|
|
1058
|
-
if (table) {
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1063
|
-
}
|
1109
|
+
if (table) for (const inst of wasm) {
|
1110
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1111
|
+
inst.splice(2, 99);
|
1112
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1064
1113
|
}
|
1065
|
-
|
1066
|
-
funcs.table = true;
|
1067
1114
|
}
|
1068
1115
|
|
1069
1116
|
func.wasm = wasm;
|
@@ -1403,10 +1450,10 @@ const countLeftover = wasm => {
|
|
1403
1450
|
|
1404
1451
|
if (depth === 0)
|
1405
1452
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1406
|
-
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] <
|
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] < 0x0a)) {}
|
1407
1454
|
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++;
|
1408
1455
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1409
|
-
else if (
|
1456
|
+
else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
|
1410
1457
|
else if (inst[0] === Opcodes.return) count = 0;
|
1411
1458
|
else if (inst[0] === Opcodes.call) {
|
1412
1459
|
let func = funcs.find(x => x.index === inst[1]);
|
@@ -1678,7 +1725,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1678
1725
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1679
1726
|
return makeArray(scope, {
|
1680
1727
|
rawElements: new Array(length)
|
1681
|
-
}, _global, _name, true, itemType
|
1728
|
+
}, _global, _name, true, itemType);
|
1682
1729
|
}, () => {
|
1683
1730
|
optUnused = true;
|
1684
1731
|
return unusedValue;
|
@@ -2068,6 +2115,7 @@ const brTable = (input, bc, returns) => {
|
|
2068
2115
|
}
|
2069
2116
|
|
2070
2117
|
for (let i = 0; i < count; i++) {
|
2118
|
+
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2071
2119
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2072
2120
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2073
2121
|
}
|
@@ -2101,8 +2149,10 @@ const brTable = (input, bc, returns) => {
|
|
2101
2149
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2102
2150
|
);
|
2103
2151
|
|
2104
|
-
// sort the wrong way and then reverse
|
2105
|
-
//
|
2152
|
+
// if you can guess why we sort the wrong way and then reverse
|
2153
|
+
// (instead of just sorting the correct way)
|
2154
|
+
// dm me and if you are correct and the first person
|
2155
|
+
// I will somehow shout you out or something
|
2106
2156
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2107
2157
|
|
2108
2158
|
br = count - 1;
|
@@ -2128,7 +2178,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2128
2178
|
return bc[known] ?? bc.default;
|
2129
2179
|
}
|
2130
2180
|
|
2131
|
-
if (Prefs.
|
2181
|
+
if (Prefs.typeswitchUseBrtable)
|
2132
2182
|
return brTable(type, bc, returns);
|
2133
2183
|
|
2134
2184
|
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
@@ -2183,11 +2233,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2183
2233
|
return target[name].idx;
|
2184
2234
|
}
|
2185
2235
|
|
2186
|
-
let idx = global ?
|
2236
|
+
let idx = global ? globalInd++ : scope.localInd++;
|
2187
2237
|
target[name] = { idx, type: valtypeBinary };
|
2188
2238
|
|
2189
2239
|
if (type) {
|
2190
|
-
let typeIdx = global ?
|
2240
|
+
let typeIdx = global ? globalInd++ : scope.localInd++;
|
2191
2241
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2192
2242
|
}
|
2193
2243
|
|
@@ -2280,10 +2330,24 @@ const generateVar = (scope, decl) => {
|
|
2280
2330
|
}
|
2281
2331
|
|
2282
2332
|
if (x.init) {
|
2283
|
-
|
2333
|
+
// if (isFuncType(x.init.type)) {
|
2334
|
+
// // let a = function () { ... }
|
2335
|
+
// x.init.id = { name };
|
2336
|
+
|
2337
|
+
// const func = generateFunc(scope, x.init);
|
2338
|
+
|
2339
|
+
// out.push(
|
2340
|
+
// ...number(func.index - importedFuncs.length),
|
2341
|
+
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2342
|
+
|
2343
|
+
// ...setType(scope, name, TYPES.function)
|
2344
|
+
// );
|
2345
|
+
|
2346
|
+
// continue;
|
2347
|
+
// }
|
2284
2348
|
|
2285
2349
|
const generated = generate(scope, x.init, global, name);
|
2286
|
-
if (
|
2350
|
+
if (scope.arrays?.get(name) != null) {
|
2287
2351
|
// hack to set local as pointer before
|
2288
2352
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2289
2353
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2335,12 +2399,19 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2335
2399
|
|
2336
2400
|
// hack: .length setter
|
2337
2401
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2402
|
+
const name = decl.left.object.name;
|
2403
|
+
const pointer = scope.arrays?.get(name);
|
2404
|
+
|
2405
|
+
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2406
|
+
|
2338
2407
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2339
2408
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2340
2409
|
|
2341
2410
|
return [
|
2342
|
-
...
|
2343
|
-
|
2411
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
2412
|
+
...generate(scope, decl.left.object),
|
2413
|
+
Opcodes.i32_to_u
|
2414
|
+
]),
|
2344
2415
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2345
2416
|
|
2346
2417
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2351,7 +2422,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2351
2422
|
[ Opcodes.local_tee, newValueTmp ],
|
2352
2423
|
|
2353
2424
|
Opcodes.i32_to_u,
|
2354
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2425
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
2355
2426
|
|
2356
2427
|
[ Opcodes.local_get, newValueTmp ]
|
2357
2428
|
];
|
@@ -2359,14 +2430,21 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2359
2430
|
|
2360
2431
|
// arr[i]
|
2361
2432
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2433
|
+
const name = decl.left.object.name;
|
2434
|
+
const pointer = scope.arrays?.get(name);
|
2435
|
+
|
2436
|
+
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2437
|
+
|
2362
2438
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2363
2439
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2364
2440
|
|
2365
2441
|
return [
|
2366
2442
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2367
2443
|
[TYPES.array]: [
|
2368
|
-
...
|
2369
|
-
|
2444
|
+
...(aotPointer ? [] : [
|
2445
|
+
...generate(scope, decl.left.object),
|
2446
|
+
Opcodes.i32_to_u
|
2447
|
+
]),
|
2370
2448
|
|
2371
2449
|
// get index as valtype
|
2372
2450
|
...generate(scope, decl.left.property),
|
@@ -2375,22 +2453,39 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2375
2453
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2376
2454
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2377
2455
|
[ Opcodes.i32_mul ],
|
2378
|
-
[ Opcodes.i32_add ],
|
2456
|
+
...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2379
2457
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2380
2458
|
|
2381
2459
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2382
2460
|
[ Opcodes.local_get, pointerTmp ],
|
2383
|
-
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2461
|
+
[ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2384
2462
|
], generate(scope, decl.right), [
|
2385
2463
|
[ Opcodes.local_get, pointerTmp ],
|
2386
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2464
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
2387
2465
|
], getNodeType(scope, decl.right), false, name, true)),
|
2388
2466
|
[ Opcodes.local_tee, newValueTmp ],
|
2389
2467
|
|
2390
|
-
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2468
|
+
[ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2391
2469
|
],
|
2392
2470
|
|
2393
2471
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2472
|
+
|
2473
|
+
// [TYPES.string]: [
|
2474
|
+
// // turn into byte offset by * sizeof i16
|
2475
|
+
// ...number(ValtypeSize.i16, Valtype.i32),
|
2476
|
+
// [ Opcodes.i32_mul ],
|
2477
|
+
// ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2478
|
+
// ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2479
|
+
|
2480
|
+
// ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2481
|
+
// [ Opcodes.local_get, pointerTmp ],
|
2482
|
+
// [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2483
|
+
// ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
|
2484
|
+
// [ Opcodes.local_tee, newValueTmp ],
|
2485
|
+
|
2486
|
+
// Opcodes.i32_to_u,
|
2487
|
+
// [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2488
|
+
// ]
|
2394
2489
|
}, Blocktype.void),
|
2395
2490
|
|
2396
2491
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2774,12 +2869,12 @@ const generateForOf = (scope, decl) => {
|
|
2774
2869
|
|
2775
2870
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2776
2871
|
// hack: this is naughty and will break things!
|
2777
|
-
let newOut = number(0, Valtype.
|
2872
|
+
let newOut = number(0, Valtype.f64), newPointer = -1;
|
2778
2873
|
if (pages.hasAnyString) {
|
2779
2874
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2780
2875
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2781
|
-
rawElements: new Array(
|
2782
|
-
}, isGlobal, leftName, true, 'i16'
|
2876
|
+
rawElements: new Array(1)
|
2877
|
+
}, isGlobal, leftName, true, 'i16');
|
2783
2878
|
}
|
2784
2879
|
|
2785
2880
|
// set type for local
|
@@ -2826,28 +2921,23 @@ const generateForOf = (scope, decl) => {
|
|
2826
2921
|
[TYPES.string]: [
|
2827
2922
|
...setType(scope, leftName, TYPES.string),
|
2828
2923
|
|
2924
|
+
[ Opcodes.loop, Blocktype.void ],
|
2925
|
+
|
2829
2926
|
// setup new/out array
|
2830
2927
|
...newOut,
|
2928
|
+
[ Opcodes.drop ],
|
2831
2929
|
|
2832
|
-
//
|
2833
|
-
...number(1, Valtype.i32),
|
2834
|
-
[ Opcodes.i32_store, 0, 0 ],
|
2835
|
-
|
2836
|
-
[ Opcodes.loop, Blocktype.void ],
|
2837
|
-
|
2838
|
-
// use as pointer for store later
|
2839
|
-
...newPointer,
|
2930
|
+
...number(0, Valtype.i32), // base 0 for store after
|
2840
2931
|
|
2841
2932
|
// load current string ind {arg}
|
2842
2933
|
[ Opcodes.local_get, pointer ],
|
2843
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2934
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
2844
2935
|
|
2845
2936
|
// store to new string ind 0
|
2846
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2937
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
2847
2938
|
|
2848
2939
|
// return new string (page)
|
2849
|
-
...newPointer,
|
2850
|
-
Opcodes.i32_from_u,
|
2940
|
+
...number(newPointer),
|
2851
2941
|
|
2852
2942
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2853
2943
|
|
@@ -2879,30 +2969,25 @@ const generateForOf = (scope, decl) => {
|
|
2879
2969
|
[TYPES.bytestring]: [
|
2880
2970
|
...setType(scope, leftName, TYPES.bytestring),
|
2881
2971
|
|
2972
|
+
[ Opcodes.loop, Blocktype.void ],
|
2973
|
+
|
2882
2974
|
// setup new/out array
|
2883
2975
|
...newOut,
|
2976
|
+
[ Opcodes.drop ],
|
2884
2977
|
|
2885
|
-
//
|
2886
|
-
...number(1, Valtype.i32),
|
2887
|
-
[ Opcodes.i32_store, 0, 0 ],
|
2888
|
-
|
2889
|
-
[ Opcodes.loop, Blocktype.void ],
|
2890
|
-
|
2891
|
-
// use as pointer for store later
|
2892
|
-
...newPointer,
|
2978
|
+
...number(0, Valtype.i32), // base 0 for store after
|
2893
2979
|
|
2894
2980
|
// load current string ind {arg}
|
2895
2981
|
[ Opcodes.local_get, pointer ],
|
2896
2982
|
[ Opcodes.local_get, counter ],
|
2897
2983
|
[ Opcodes.i32_add ],
|
2898
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2984
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
2899
2985
|
|
2900
2986
|
// store to new string ind 0
|
2901
|
-
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2987
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
2902
2988
|
|
2903
2989
|
// return new string (page)
|
2904
|
-
...newPointer,
|
2905
|
-
Opcodes.i32_from_u,
|
2990
|
+
...number(newPointer),
|
2906
2991
|
|
2907
2992
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2908
2993
|
|
@@ -3122,6 +3207,16 @@ const allocPage = (scope, reason, type) => {
|
|
3122
3207
|
return ind;
|
3123
3208
|
};
|
3124
3209
|
|
3210
|
+
// todo: add scope.pages
|
3211
|
+
const freePage = reason => {
|
3212
|
+
const { ind } = pages.get(reason);
|
3213
|
+
pages.delete(reason);
|
3214
|
+
|
3215
|
+
if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
3216
|
+
|
3217
|
+
return ind;
|
3218
|
+
};
|
3219
|
+
|
3125
3220
|
const itemTypeToValtype = {
|
3126
3221
|
i32: 'i32',
|
3127
3222
|
i64: 'i64',
|
@@ -3156,43 +3251,39 @@ const compileBytes = (val, itemType) => {
|
|
3156
3251
|
}
|
3157
3252
|
};
|
3158
3253
|
|
3159
|
-
const
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3163
|
-
if (length === 0) return false;
|
3164
|
-
|
3165
|
-
let bytes = compileBytes(length, 'i32');
|
3166
|
-
|
3167
|
-
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3168
|
-
if (elements[i] == null) continue;
|
3254
|
+
const getAllocType = itemType => {
|
3255
|
+
switch (itemType) {
|
3256
|
+
case 'i8': return 'bytestring';
|
3257
|
+
case 'i16': return 'string';
|
3169
3258
|
|
3170
|
-
|
3259
|
+
default: return 'array';
|
3171
3260
|
}
|
3261
|
+
};
|
3172
3262
|
|
3173
|
-
|
3174
|
-
|
3263
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
|
3264
|
+
const out = [];
|
3175
3265
|
|
3176
|
-
|
3266
|
+
scope.arrays ??= new Map();
|
3177
3267
|
|
3178
|
-
|
3179
|
-
scope.
|
3268
|
+
let firstAssign = false;
|
3269
|
+
if (!scope.arrays.has(name) || name === '$undeclared') {
|
3270
|
+
firstAssign = true;
|
3180
3271
|
|
3181
|
-
|
3182
|
-
|
3272
|
+
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3273
|
+
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3274
|
+
|
3275
|
+
let page;
|
3276
|
+
if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
|
3277
|
+
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3183
3278
|
|
3184
|
-
|
3185
|
-
|
3186
|
-
|
3187
|
-
} else {
|
3188
|
-
pages.hasAnyString = true;
|
3189
|
-
if (itemType === 'i8') pages.hasByteString = true;
|
3190
|
-
else pages.hasString = true;
|
3279
|
+
// hack: use 1 for page 0 pointer for fast truthiness
|
3280
|
+
const ptr = page === 0 ? 1 : (page * pageSize);
|
3281
|
+
scope.arrays.set(name, ptr);
|
3191
3282
|
}
|
3192
3283
|
|
3193
|
-
const
|
3284
|
+
const pointer = scope.arrays.get(name);
|
3194
3285
|
|
3195
|
-
const
|
3286
|
+
const local = global ? globals[name] : scope.locals[name];
|
3196
3287
|
|
3197
3288
|
const useRawElements = !!decl.rawElements;
|
3198
3289
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3200,70 +3291,46 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3200
3291
|
const valtype = itemTypeToValtype[itemType];
|
3201
3292
|
const length = elements.length;
|
3202
3293
|
|
3203
|
-
|
3294
|
+
if (firstAssign && useRawElements && !Prefs.noData) {
|
3295
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3296
|
+
if (length !== 0) {
|
3297
|
+
let bytes = compileBytes(length, 'i32');
|
3204
3298
|
|
3205
|
-
|
3206
|
-
|
3207
|
-
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3208
|
-
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
3209
|
-
out.push(
|
3210
|
-
...allocated,
|
3211
|
-
[ Opcodes.local_set, tmp ]
|
3212
|
-
);
|
3213
|
-
|
3214
|
-
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3299
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3300
|
+
if (elements[i] == null) continue;
|
3215
3301
|
|
3216
|
-
|
3217
|
-
const data = makeData(scope, elements, null, itemType, initEmpty);
|
3218
|
-
if (data) {
|
3219
|
-
// init data
|
3220
|
-
out.push(
|
3221
|
-
...pointer,
|
3222
|
-
...number(0, Valtype.i32),
|
3223
|
-
...number(data.size, Valtype.i32),
|
3224
|
-
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
3225
|
-
);
|
3302
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3226
3303
|
}
|
3227
3304
|
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
);
|
3305
|
+
const ind = data.push({
|
3306
|
+
offset: pointer,
|
3307
|
+
bytes
|
3308
|
+
}) - 1;
|
3233
3309
|
|
3234
|
-
|
3310
|
+
scope.data ??= [];
|
3311
|
+
scope.data.push(ind);
|
3235
3312
|
}
|
3236
|
-
} else {
|
3237
|
-
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3238
|
-
|
3239
|
-
scope.arrays ??= new Map();
|
3240
|
-
const firstAssign = !scope.arrays.has(uniqueName);
|
3241
|
-
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3242
3313
|
|
3243
|
-
|
3244
|
-
|
3245
|
-
|
3246
|
-
// local value as pointer
|
3247
|
-
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3248
|
-
}
|
3314
|
+
// local value as pointer
|
3315
|
+
out.push(...number(pointer));
|
3249
3316
|
|
3250
|
-
|
3251
|
-
|
3252
|
-
if (pointerTmp != null) {
|
3253
|
-
out.push(
|
3254
|
-
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3255
|
-
Opcodes.i32_to_u,
|
3256
|
-
[ Opcodes.local_set, pointerTmp ]
|
3257
|
-
);
|
3317
|
+
return [ out, pointer ];
|
3318
|
+
}
|
3258
3319
|
|
3259
|
-
|
3260
|
-
|
3320
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3321
|
+
if (pointerTmp != null) {
|
3322
|
+
out.push(
|
3323
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3324
|
+
Opcodes.i32_to_u,
|
3325
|
+
[ Opcodes.local_set, pointerTmp ]
|
3326
|
+
);
|
3261
3327
|
}
|
3262
3328
|
|
3329
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3263
3330
|
|
3264
3331
|
// store length
|
3265
3332
|
out.push(
|
3266
|
-
...
|
3333
|
+
...pointerWasm,
|
3267
3334
|
...number(length, Valtype.i32),
|
3268
3335
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3269
3336
|
);
|
@@ -3275,11 +3342,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3275
3342
|
|
3276
3343
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3277
3344
|
out.push(
|
3278
|
-
...
|
3345
|
+
...pointerWasm,
|
3279
3346
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3280
3347
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3281
3348
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3282
|
-
...
|
3349
|
+
...pointerWasm,
|
3283
3350
|
...getNodeType(scope, elements[i]),
|
3284
3351
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3285
3352
|
])
|
@@ -3287,13 +3354,12 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3287
3354
|
}
|
3288
3355
|
|
3289
3356
|
// local value as pointer
|
3290
|
-
out.push(...
|
3291
|
-
if (!intOut) out.push(Opcodes.i32_from_u);
|
3357
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3292
3358
|
|
3293
3359
|
return [ out, pointer ];
|
3294
3360
|
};
|
3295
3361
|
|
3296
|
-
const storeArray = (scope, array, index, element) => {
|
3362
|
+
const storeArray = (scope, array, index, element, aotPointer = null) => {
|
3297
3363
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3298
3364
|
if (typeof index === 'number') index = number(index);
|
3299
3365
|
|
@@ -3305,25 +3371,26 @@ const storeArray = (scope, array, index, element) => {
|
|
3305
3371
|
Opcodes.i32_to_u,
|
3306
3372
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3307
3373
|
[ Opcodes.i32_mul ],
|
3308
|
-
|
3309
|
-
|
3310
|
-
|
3311
|
-
|
3374
|
+
...(aotPointer ? [] : [
|
3375
|
+
...array,
|
3376
|
+
Opcodes.i32_to_u,
|
3377
|
+
[ Opcodes.i32_add ],
|
3378
|
+
]),
|
3312
3379
|
[ Opcodes.local_set, offset ],
|
3313
3380
|
|
3314
3381
|
// store value
|
3315
3382
|
[ Opcodes.local_get, offset ],
|
3316
3383
|
...generate(scope, element),
|
3317
|
-
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3384
|
+
[ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3318
3385
|
|
3319
3386
|
// store type
|
3320
3387
|
[ Opcodes.local_get, offset ],
|
3321
3388
|
...getNodeType(scope, element),
|
3322
|
-
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3389
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
3323
3390
|
];
|
3324
3391
|
};
|
3325
3392
|
|
3326
|
-
const loadArray = (scope, array, index) => {
|
3393
|
+
const loadArray = (scope, array, index, aotPointer = null) => {
|
3327
3394
|
if (typeof index === 'number') index = number(index);
|
3328
3395
|
|
3329
3396
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3334,19 +3401,20 @@ const loadArray = (scope, array, index) => {
|
|
3334
3401
|
Opcodes.i32_to_u,
|
3335
3402
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3336
3403
|
[ Opcodes.i32_mul ],
|
3337
|
-
|
3338
|
-
|
3339
|
-
|
3340
|
-
|
3404
|
+
...(aotPointer ? [] : [
|
3405
|
+
...array,
|
3406
|
+
Opcodes.i32_to_u,
|
3407
|
+
[ Opcodes.i32_add ],
|
3408
|
+
]),
|
3341
3409
|
[ Opcodes.local_set, offset ],
|
3342
3410
|
|
3343
3411
|
// load value
|
3344
3412
|
[ Opcodes.local_get, offset ],
|
3345
|
-
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3413
|
+
[ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3346
3414
|
|
3347
3415
|
// load type
|
3348
3416
|
[ Opcodes.local_get, offset ],
|
3349
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3417
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
3350
3418
|
];
|
3351
3419
|
};
|
3352
3420
|
|
@@ -3378,7 +3446,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3378
3446
|
};
|
3379
3447
|
|
3380
3448
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3381
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype,
|
3449
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3382
3450
|
};
|
3383
3451
|
|
3384
3452
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3397,6 +3465,9 @@ const withType = (scope, wasm, type) => [
|
|
3397
3465
|
|
3398
3466
|
const generateMember = (scope, decl, _global, _name) => {
|
3399
3467
|
const name = decl.object.name;
|
3468
|
+
const pointer = scope.arrays?.get(name);
|
3469
|
+
|
3470
|
+
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3400
3471
|
|
3401
3472
|
// hack: .name
|
3402
3473
|
if (decl.property.name === 'name') {
|
@@ -3437,10 +3508,12 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3437
3508
|
if (Prefs.fastLength) {
|
3438
3509
|
// presume valid length object
|
3439
3510
|
return [
|
3440
|
-
...
|
3441
|
-
|
3511
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3512
|
+
...generate(scope, decl.object),
|
3513
|
+
Opcodes.i32_to_u
|
3514
|
+
]),
|
3442
3515
|
|
3443
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3516
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3444
3517
|
Opcodes.i32_from_u
|
3445
3518
|
];
|
3446
3519
|
}
|
@@ -3449,10 +3522,12 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3449
3522
|
const known = knownType(scope, type);
|
3450
3523
|
if (known != null) {
|
3451
3524
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3452
|
-
...
|
3453
|
-
|
3525
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3526
|
+
...generate(scope, decl.object),
|
3527
|
+
Opcodes.i32_to_u
|
3528
|
+
]),
|
3454
3529
|
|
3455
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3530
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3456
3531
|
Opcodes.i32_from_u
|
3457
3532
|
];
|
3458
3533
|
|
@@ -3462,10 +3537,12 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3462
3537
|
return [
|
3463
3538
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3464
3539
|
[ Opcodes.if, valtypeBinary ],
|
3465
|
-
...
|
3466
|
-
|
3540
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3541
|
+
...generate(scope, decl.object),
|
3542
|
+
Opcodes.i32_to_u
|
3543
|
+
]),
|
3467
3544
|
|
3468
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3545
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3469
3546
|
Opcodes.i32_from_u,
|
3470
3547
|
|
3471
3548
|
...setLastType(scope, TYPES.number),
|
@@ -3508,29 +3585,25 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3508
3585
|
|
3509
3586
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3510
3587
|
// hack: this is naughty and will break things!
|
3511
|
-
let newOut = number(0,
|
3588
|
+
let newOut = number(0, valtypeBinary), newPointer = -1;
|
3512
3589
|
if (pages.hasAnyString) {
|
3513
|
-
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3514
3590
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3515
|
-
rawElements: new Array(
|
3516
|
-
}, _global, _name, true, 'i16'
|
3591
|
+
rawElements: new Array(1)
|
3592
|
+
}, _global, _name, true, 'i16');
|
3517
3593
|
}
|
3518
3594
|
|
3519
3595
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3520
3596
|
[TYPES.array]: [
|
3521
|
-
...loadArray(scope, object, property),
|
3597
|
+
...loadArray(scope, object, property, aotPointer),
|
3522
3598
|
...setLastType(scope)
|
3523
3599
|
],
|
3600
|
+
|
3524
3601
|
[TYPES.string]: [
|
3525
3602
|
// setup new/out array
|
3526
3603
|
...newOut,
|
3604
|
+
[ Opcodes.drop ],
|
3527
3605
|
|
3528
|
-
//
|
3529
|
-
...number(1, Valtype.i32),
|
3530
|
-
[ Opcodes.i32_store, 0, 0 ],
|
3531
|
-
|
3532
|
-
// use as pointer for store later
|
3533
|
-
...newPointer,
|
3606
|
+
...number(0, Valtype.i32), // base 0 for store later
|
3534
3607
|
|
3535
3608
|
...property,
|
3536
3609
|
Opcodes.i32_to_u,
|
@@ -3538,48 +3611,46 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3538
3611
|
...number(ValtypeSize.i16, Valtype.i32),
|
3539
3612
|
[ Opcodes.i32_mul ],
|
3540
3613
|
|
3541
|
-
...
|
3542
|
-
|
3543
|
-
|
3614
|
+
...(aotPointer ? [] : [
|
3615
|
+
...object,
|
3616
|
+
Opcodes.i32_to_u,
|
3617
|
+
[ Opcodes.i32_add ]
|
3618
|
+
]),
|
3544
3619
|
|
3545
3620
|
// load current string ind {arg}
|
3546
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3621
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3547
3622
|
|
3548
3623
|
// store to new string ind 0
|
3549
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3624
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
3550
3625
|
|
3551
3626
|
// return new string (page)
|
3552
|
-
...newPointer,
|
3553
|
-
Opcodes.i32_from_u,
|
3627
|
+
...number(newPointer),
|
3554
3628
|
...setLastType(scope, TYPES.string)
|
3555
3629
|
],
|
3556
3630
|
[TYPES.bytestring]: [
|
3557
3631
|
// setup new/out array
|
3558
3632
|
...newOut,
|
3633
|
+
[ Opcodes.drop ],
|
3559
3634
|
|
3560
|
-
//
|
3561
|
-
...number(1, Valtype.i32),
|
3562
|
-
[ Opcodes.i32_store, 0, 0 ],
|
3563
|
-
|
3564
|
-
// use as pointer for store later
|
3565
|
-
...newPointer,
|
3635
|
+
...number(0, Valtype.i32), // base 0 for store later
|
3566
3636
|
|
3567
3637
|
...property,
|
3568
3638
|
Opcodes.i32_to_u,
|
3569
3639
|
|
3570
|
-
...
|
3571
|
-
|
3572
|
-
|
3640
|
+
...(aotPointer ? [] : [
|
3641
|
+
...object,
|
3642
|
+
Opcodes.i32_to_u,
|
3643
|
+
[ Opcodes.i32_add ]
|
3644
|
+
]),
|
3573
3645
|
|
3574
3646
|
// load current string ind {arg}
|
3575
|
-
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3647
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3576
3648
|
|
3577
3649
|
// store to new string ind 0
|
3578
|
-
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3650
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
3579
3651
|
|
3580
3652
|
// return new string (page)
|
3581
|
-
...newPointer,
|
3582
|
-
Opcodes.i32_from_u,
|
3653
|
+
...number(newPointer),
|
3583
3654
|
...setLastType(scope, TYPES.bytestring)
|
3584
3655
|
],
|
3585
3656
|
|
@@ -3587,7 +3658,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3587
3658
|
});
|
3588
3659
|
};
|
3589
3660
|
|
3590
|
-
const randId = () => Math.random().toString(16).slice(
|
3661
|
+
const randId = () => Math.random().toString(16).slice(0, -4);
|
3591
3662
|
|
3592
3663
|
const objectHack = node => {
|
3593
3664
|
if (!node) return node;
|
@@ -3639,7 +3710,7 @@ const generateFunc = (scope, decl) => {
|
|
3639
3710
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3640
3711
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3641
3712
|
|
3642
|
-
const name = decl.id ? decl.id.name : `
|
3713
|
+
const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
|
3643
3714
|
const params = decl.params ?? [];
|
3644
3715
|
|
3645
3716
|
// TODO: share scope/locals between !!!
|
@@ -3724,9 +3795,9 @@ const internalConstrs = {
|
|
3724
3795
|
|
3725
3796
|
// new Array(n)
|
3726
3797
|
|
3727
|
-
const [
|
3798
|
+
const [ , pointer ] = makeArray(scope, {
|
3728
3799
|
rawElements: new Array(0)
|
3729
|
-
}, global, name, true
|
3800
|
+
}, global, name, true);
|
3730
3801
|
|
3731
3802
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3732
3803
|
|
@@ -3735,13 +3806,12 @@ const internalConstrs = {
|
|
3735
3806
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3736
3807
|
|
3737
3808
|
return [
|
3738
|
-
...
|
3809
|
+
...number(0, Valtype.i32),
|
3739
3810
|
...generate(scope, arg, global, name),
|
3740
3811
|
Opcodes.i32_to_u,
|
3741
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3812
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
|
3742
3813
|
|
3743
|
-
...pointer
|
3744
|
-
Opcodes.i32_from_u
|
3814
|
+
...number(pointer)
|
3745
3815
|
];
|
3746
3816
|
},
|
3747
3817
|
type: TYPES.array,
|
@@ -3890,9 +3960,8 @@ const internalConstrs = {
|
|
3890
3960
|
};
|
3891
3961
|
|
3892
3962
|
export default program => {
|
3893
|
-
globals = {
|
3894
|
-
|
3895
|
-
};
|
3963
|
+
globals = {};
|
3964
|
+
globalInd = 0;
|
3896
3965
|
tags = [];
|
3897
3966
|
exceptions = [];
|
3898
3967
|
funcs = [];
|
@@ -3925,7 +3994,6 @@ export default program => {
|
|
3925
3994
|
builtinFuncs = new BuiltinFuncs();
|
3926
3995
|
builtinVars = new BuiltinVars();
|
3927
3996
|
prototypeFuncs = new PrototypeFuncs();
|
3928
|
-
allocator = Allocator(Prefs.allocator ?? 'static');
|
3929
3997
|
|
3930
3998
|
program.id = { name: 'main' };
|
3931
3999
|
|
@@ -3968,8 +4036,6 @@ export default program => {
|
|
3968
4036
|
else main.returns = [];
|
3969
4037
|
}
|
3970
4038
|
|
3971
|
-
delete globals['#ind'];
|
3972
|
-
|
3973
4039
|
// if blank main func and other exports, remove it
|
3974
4040
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
3975
4041
|
|