porffor 0.16.0-594397507 → 0.16.0-688a50c13
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/a.txt +457 -0
- package/b.txt +457 -0
- package/compiler/2c.js +53 -65
- package/compiler/allocators/grow.js +26 -0
- package/compiler/allocators/index.js +10 -0
- package/compiler/allocators/static.js +42 -0
- package/compiler/assemble.js +5 -4
- package/compiler/builtins/date.ts +2 -4
- package/compiler/builtins/porffor.d.ts +3 -0
- package/compiler/builtins/set.ts +2 -4
- package/compiler/builtins.js +25 -5
- package/compiler/codegen.js +210 -325
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +3 -1
- package/compiler/generated_builtins.js +18 -18
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +89 -6
- package/compiler/opt.js +10 -44
- package/compiler/parse.js +1 -1
- package/compiler/pgo.js +207 -0
- package/compiler/precompile.js +11 -6
- package/compiler/prefs.js +7 -2
- package/compiler/prototype.js +34 -43
- package/compiler/wrap.js +66 -25
- package/no_pgo.txt +923 -0
- package/package.json +3 -5
- package/pgo.txt +916 -0
- package/runner/index.js +21 -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 Allocator from './allocators/index.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) {
|
@@ -181,12 +182,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
181
182
|
continue;
|
182
183
|
}
|
183
184
|
|
184
|
-
if (asm[0] === 'memory') {
|
185
|
-
allocPage(scope, 'asm instrinsic');
|
186
|
-
// todo: add to store/load offset insts
|
187
|
-
continue;
|
188
|
-
}
|
189
|
-
|
190
185
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
191
186
|
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
192
187
|
|
@@ -433,63 +428,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
433
428
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
434
429
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
435
430
|
|
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
431
|
const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
|
488
432
|
|
489
433
|
// alloc/assign array
|
490
434
|
const [ , pointer ] = makeArray(scope, {
|
491
435
|
rawElements: new Array(0)
|
492
|
-
}, global, name, true, 'i16');
|
436
|
+
}, global, name, true, 'i16', true);
|
493
437
|
|
494
438
|
return [
|
495
439
|
// setup left
|
@@ -503,7 +447,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
503
447
|
[ Opcodes.local_set, rightPointer ],
|
504
448
|
|
505
449
|
// calculate length
|
506
|
-
...
|
450
|
+
...pointer, // base 0 for store later
|
507
451
|
|
508
452
|
[ Opcodes.local_get, leftPointer ],
|
509
453
|
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
@@ -516,11 +460,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
516
460
|
[ Opcodes.i32_add ],
|
517
461
|
|
518
462
|
// store length
|
519
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
463
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
520
464
|
|
521
465
|
// copy left
|
522
466
|
// dst = out pointer + length size
|
523
|
-
...
|
467
|
+
...pointer,
|
468
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
469
|
+
[ Opcodes.i32_add ],
|
524
470
|
|
525
471
|
// src = left pointer + length size
|
526
472
|
[ Opcodes.local_get, leftPointer ],
|
@@ -533,7 +479,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
533
479
|
|
534
480
|
// copy right
|
535
481
|
// dst = out pointer + length size + left length * sizeof valtype
|
536
|
-
...
|
482
|
+
...pointer,
|
483
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
484
|
+
[ Opcodes.i32_add ],
|
537
485
|
|
538
486
|
[ Opcodes.local_get, leftLength ],
|
539
487
|
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
@@ -553,7 +501,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
553
501
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
554
502
|
|
555
503
|
// return new string (page)
|
556
|
-
...
|
504
|
+
...pointer,
|
505
|
+
Opcodes.i32_from_u
|
557
506
|
];
|
558
507
|
};
|
559
508
|
|
@@ -669,10 +618,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
669
618
|
};
|
670
619
|
|
671
620
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
672
|
-
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
673
|
-
|
674
|
-
|
675
|
-
];
|
621
|
+
// if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
622
|
+
// ...wasm,
|
623
|
+
// ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
624
|
+
// ];
|
676
625
|
// if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
|
677
626
|
|
678
627
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
@@ -1078,7 +1027,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1078
1027
|
locals,
|
1079
1028
|
localInd: allLocals.length,
|
1080
1029
|
returns,
|
1081
|
-
returnType
|
1030
|
+
returnType,
|
1082
1031
|
internal: true,
|
1083
1032
|
index: currentFuncIndex++,
|
1084
1033
|
table
|
@@ -1091,9 +1040,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1091
1040
|
|
1092
1041
|
let baseGlobalIdx, i = 0;
|
1093
1042
|
for (const type of globalTypes) {
|
1094
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1043
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
|
1095
1044
|
|
1096
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1045
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
|
1097
1046
|
i++;
|
1098
1047
|
}
|
1099
1048
|
|
@@ -1106,11 +1055,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1106
1055
|
}
|
1107
1056
|
}
|
1108
1057
|
|
1109
|
-
if (table)
|
1110
|
-
|
1111
|
-
inst.
|
1112
|
-
|
1058
|
+
if (table) {
|
1059
|
+
for (const inst of wasm) {
|
1060
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1061
|
+
inst.splice(2, 99);
|
1062
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1063
|
+
}
|
1113
1064
|
}
|
1065
|
+
|
1066
|
+
funcs.table = true;
|
1114
1067
|
}
|
1115
1068
|
|
1116
1069
|
func.wasm = wasm;
|
@@ -1254,7 +1207,7 @@ const getNodeType = (scope, node) => {
|
|
1254
1207
|
const func = funcs.find(x => x.name === name);
|
1255
1208
|
|
1256
1209
|
if (func) {
|
1257
|
-
if (func.returnType) return func.returnType;
|
1210
|
+
if (func.returnType != null) return func.returnType;
|
1258
1211
|
}
|
1259
1212
|
|
1260
1213
|
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
|
@@ -1270,15 +1223,7 @@ const getNodeType = (scope, node) => {
|
|
1270
1223
|
const func = spl[spl.length - 1];
|
1271
1224
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1272
1225
|
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;
|
1226
|
+
if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
|
1282
1227
|
}
|
1283
1228
|
}
|
1284
1229
|
|
@@ -1733,7 +1678,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1733
1678
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1734
1679
|
return makeArray(scope, {
|
1735
1680
|
rawElements: new Array(length)
|
1736
|
-
}, _global, _name, true, itemType);
|
1681
|
+
}, _global, _name, true, itemType, true);
|
1737
1682
|
}, () => {
|
1738
1683
|
optUnused = true;
|
1739
1684
|
return unusedValue;
|
@@ -1815,7 +1760,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1815
1760
|
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1816
1761
|
|
1817
1762
|
// value
|
1818
|
-
i32_const: { imms: 1, args: [], returns:
|
1763
|
+
i32_const: { imms: 1, args: [], returns: 0 },
|
1819
1764
|
};
|
1820
1765
|
|
1821
1766
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1978,7 +1923,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
1923
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1979
1924
|
const userFunc = func && !func.internal;
|
1980
1925
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1981
|
-
const typedReturns = (
|
1926
|
+
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1982
1927
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1983
1928
|
|
1984
1929
|
let args = decl.arguments;
|
@@ -2007,8 +1952,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2007
1952
|
}
|
2008
1953
|
|
2009
1954
|
if (valtypeBinary !== Valtype.i32 && (
|
2010
|
-
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2011
|
-
(importedFuncs[name] && name.startsWith('profile'))
|
1955
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1956
|
+
// (importedFuncs[name] && name.startsWith('profile'))
|
2012
1957
|
)) {
|
2013
1958
|
out.push(Opcodes.i32_to);
|
2014
1959
|
}
|
@@ -2123,7 +2068,6 @@ const brTable = (input, bc, returns) => {
|
|
2123
2068
|
}
|
2124
2069
|
|
2125
2070
|
for (let i = 0; i < count; i++) {
|
2126
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2127
2071
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2128
2072
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2129
2073
|
}
|
@@ -2157,10 +2101,8 @@ const brTable = (input, bc, returns) => {
|
|
2157
2101
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2158
2102
|
);
|
2159
2103
|
|
2160
|
-
//
|
2161
|
-
// (
|
2162
|
-
// dm me and if you are correct and the first person
|
2163
|
-
// I will somehow shout you out or something
|
2104
|
+
// sort the wrong way and then reverse
|
2105
|
+
// so strings ('default') are at the start before any numbers
|
2164
2106
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2165
2107
|
|
2166
2108
|
br = count - 1;
|
@@ -2186,10 +2128,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2186
2128
|
return bc[known] ?? bc.default;
|
2187
2129
|
}
|
2188
2130
|
|
2189
|
-
if (Prefs.
|
2131
|
+
if (Prefs.typeswitchBrtable)
|
2190
2132
|
return brTable(type, bc, returns);
|
2191
2133
|
|
2192
|
-
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
2134
|
+
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
2193
2135
|
const out = [
|
2194
2136
|
...type,
|
2195
2137
|
[ Opcodes.local_set, tmp ],
|
@@ -2241,11 +2183,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2241
2183
|
return target[name].idx;
|
2242
2184
|
}
|
2243
2185
|
|
2244
|
-
let idx = global ?
|
2186
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2245
2187
|
target[name] = { idx, type: valtypeBinary };
|
2246
2188
|
|
2247
2189
|
if (type) {
|
2248
|
-
let typeIdx = global ?
|
2190
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2249
2191
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2250
2192
|
}
|
2251
2193
|
|
@@ -2338,24 +2280,10 @@ const generateVar = (scope, decl) => {
|
|
2338
2280
|
}
|
2339
2281
|
|
2340
2282
|
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
|
-
// }
|
2283
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2356
2284
|
|
2357
2285
|
const generated = generate(scope, x.init, global, name);
|
2358
|
-
if (scope.arrays?.get(name) != null) {
|
2286
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2359
2287
|
// hack to set local as pointer before
|
2360
2288
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2361
2289
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2407,19 +2335,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2407
2335
|
|
2408
2336
|
// hack: .length setter
|
2409
2337
|
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
2338
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2416
2339
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2417
2340
|
|
2418
2341
|
return [
|
2419
|
-
...(
|
2420
|
-
|
2421
|
-
Opcodes.i32_to_u
|
2422
|
-
]),
|
2342
|
+
...generate(scope, decl.left.object),
|
2343
|
+
Opcodes.i32_to_u,
|
2423
2344
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2424
2345
|
|
2425
2346
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2430,7 +2351,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2430
2351
|
[ Opcodes.local_tee, newValueTmp ],
|
2431
2352
|
|
2432
2353
|
Opcodes.i32_to_u,
|
2433
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2354
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2434
2355
|
|
2435
2356
|
[ Opcodes.local_get, newValueTmp ]
|
2436
2357
|
];
|
@@ -2438,21 +2359,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2438
2359
|
|
2439
2360
|
// arr[i]
|
2440
2361
|
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
2362
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2447
2363
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2448
2364
|
|
2449
2365
|
return [
|
2450
2366
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2451
2367
|
[TYPES.array]: [
|
2452
|
-
...(
|
2453
|
-
|
2454
|
-
Opcodes.i32_to_u
|
2455
|
-
]),
|
2368
|
+
...generate(scope, decl.left.object),
|
2369
|
+
Opcodes.i32_to_u,
|
2456
2370
|
|
2457
2371
|
// get index as valtype
|
2458
2372
|
...generate(scope, decl.left.property),
|
@@ -2461,39 +2375,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2461
2375
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2462
2376
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2463
2377
|
[ Opcodes.i32_mul ],
|
2464
|
-
|
2378
|
+
[ Opcodes.i32_add ],
|
2465
2379
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2466
2380
|
|
2467
2381
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2468
2382
|
[ Opcodes.local_get, pointerTmp ],
|
2469
|
-
[ Opcodes.load, 0,
|
2383
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2470
2384
|
], generate(scope, decl.right), [
|
2471
2385
|
[ Opcodes.local_get, pointerTmp ],
|
2472
|
-
[ Opcodes.i32_load8_u, 0,
|
2386
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2473
2387
|
], getNodeType(scope, decl.right), false, name, true)),
|
2474
2388
|
[ Opcodes.local_tee, newValueTmp ],
|
2475
2389
|
|
2476
|
-
[ Opcodes.store, 0,
|
2390
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2477
2391
|
],
|
2478
2392
|
|
2479
2393
|
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
2394
|
}, Blocktype.void),
|
2498
2395
|
|
2499
2396
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2571,7 +2468,7 @@ const generateUnary = (scope, decl) => {
|
|
2571
2468
|
// * -1
|
2572
2469
|
|
2573
2470
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
2574
|
-
// if
|
2471
|
+
// if -n, just return that as a const
|
2575
2472
|
return number(-1 * decl.argument.value);
|
2576
2473
|
}
|
2577
2474
|
|
@@ -2583,14 +2480,14 @@ const generateUnary = (scope, decl) => {
|
|
2583
2480
|
case '!':
|
2584
2481
|
const arg = decl.argument;
|
2585
2482
|
if (arg.type === 'UnaryExpression' && arg.operator === '!') {
|
2586
|
-
// !!x -> is x truthy
|
2483
|
+
// opt: !!x -> is x truthy
|
2587
2484
|
return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
|
2588
2485
|
}
|
2486
|
+
|
2589
2487
|
// !=
|
2590
|
-
return falsy(scope, generate(scope,
|
2488
|
+
return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
|
2591
2489
|
|
2592
2490
|
case '~':
|
2593
|
-
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
2594
2491
|
return [
|
2595
2492
|
...generate(scope, decl.argument),
|
2596
2493
|
Opcodes.i32_to,
|
@@ -2877,12 +2774,12 @@ const generateForOf = (scope, decl) => {
|
|
2877
2774
|
|
2878
2775
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2879
2776
|
// hack: this is naughty and will break things!
|
2880
|
-
let newOut = number(0, Valtype.
|
2777
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2881
2778
|
if (pages.hasAnyString) {
|
2882
2779
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2883
2780
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2884
|
-
rawElements: new Array(
|
2885
|
-
}, isGlobal, leftName, true, 'i16');
|
2781
|
+
rawElements: new Array(0)
|
2782
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2886
2783
|
}
|
2887
2784
|
|
2888
2785
|
// set type for local
|
@@ -2929,23 +2826,28 @@ const generateForOf = (scope, decl) => {
|
|
2929
2826
|
[TYPES.string]: [
|
2930
2827
|
...setType(scope, leftName, TYPES.string),
|
2931
2828
|
|
2932
|
-
[ Opcodes.loop, Blocktype.void ],
|
2933
|
-
|
2934
2829
|
// setup new/out array
|
2935
2830
|
...newOut,
|
2936
|
-
[ Opcodes.drop ],
|
2937
2831
|
|
2938
|
-
|
2832
|
+
// set length to 1
|
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,
|
2939
2840
|
|
2940
2841
|
// load current string ind {arg}
|
2941
2842
|
[ Opcodes.local_get, pointer ],
|
2942
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
2843
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2943
2844
|
|
2944
2845
|
// store to new string ind 0
|
2945
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
2846
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2946
2847
|
|
2947
2848
|
// return new string (page)
|
2948
|
-
...
|
2849
|
+
...newPointer,
|
2850
|
+
Opcodes.i32_from_u,
|
2949
2851
|
|
2950
2852
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2951
2853
|
|
@@ -2977,25 +2879,30 @@ const generateForOf = (scope, decl) => {
|
|
2977
2879
|
[TYPES.bytestring]: [
|
2978
2880
|
...setType(scope, leftName, TYPES.bytestring),
|
2979
2881
|
|
2980
|
-
[ Opcodes.loop, Blocktype.void ],
|
2981
|
-
|
2982
2882
|
// setup new/out array
|
2983
2883
|
...newOut,
|
2984
|
-
[ Opcodes.drop ],
|
2985
2884
|
|
2986
|
-
|
2885
|
+
// set length to 1
|
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,
|
2987
2893
|
|
2988
2894
|
// load current string ind {arg}
|
2989
2895
|
[ Opcodes.local_get, pointer ],
|
2990
2896
|
[ Opcodes.local_get, counter ],
|
2991
2897
|
[ Opcodes.i32_add ],
|
2992
|
-
[ Opcodes.i32_load8_u, 0,
|
2898
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2993
2899
|
|
2994
2900
|
// store to new string ind 0
|
2995
|
-
[ Opcodes.i32_store8, 0,
|
2901
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2996
2902
|
|
2997
2903
|
// return new string (page)
|
2998
|
-
...
|
2904
|
+
...newPointer,
|
2905
|
+
Opcodes.i32_from_u,
|
2999
2906
|
|
3000
2907
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3001
2908
|
|
@@ -3215,16 +3122,6 @@ const allocPage = (scope, reason, type) => {
|
|
3215
3122
|
return ind;
|
3216
3123
|
};
|
3217
3124
|
|
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
|
-
return ind;
|
3226
|
-
};
|
3227
|
-
|
3228
3125
|
const itemTypeToValtype = {
|
3229
3126
|
i32: 'i32',
|
3230
3127
|
i64: 'i64',
|
@@ -3259,86 +3156,84 @@ const compileBytes = (val, itemType) => {
|
|
3259
3156
|
}
|
3260
3157
|
};
|
3261
3158
|
|
3262
|
-
const
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3159
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
3160
|
+
if (itemType !== 'i16' && itemType !== 'i8') {
|
3161
|
+
pages.hasArray = true;
|
3162
|
+
} else {
|
3163
|
+
pages.hasAnyString = true;
|
3164
|
+
if (itemType === 'i8') pages.hasByteString = true;
|
3165
|
+
else pages.hasString = true;
|
3268
3166
|
}
|
3269
|
-
};
|
3270
3167
|
|
3271
|
-
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
|
3272
3168
|
const out = [];
|
3273
3169
|
|
3274
|
-
|
3170
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3275
3171
|
|
3276
|
-
|
3277
|
-
|
3278
|
-
firstAssign = true;
|
3172
|
+
const useRawElements = !!decl.rawElements;
|
3173
|
+
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3279
3174
|
|
3280
|
-
|
3281
|
-
|
3175
|
+
const valtype = itemTypeToValtype[itemType];
|
3176
|
+
const length = elements.length;
|
3282
3177
|
|
3283
|
-
|
3284
|
-
if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
|
3285
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3178
|
+
const allocated = allocator.alloc({ scope, pages, globals }, uniqueName, { itemType });
|
3286
3179
|
|
3287
|
-
|
3288
|
-
|
3289
|
-
scope
|
3290
|
-
|
3180
|
+
let pointer = allocated;
|
3181
|
+
if (allocator.constructor.name !== 'StaticAllocator') {
|
3182
|
+
const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3183
|
+
out.push(
|
3184
|
+
...allocated,
|
3185
|
+
[ Opcodes.local_set, tmp ]
|
3186
|
+
);
|
3291
3187
|
|
3292
|
-
|
3188
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3189
|
+
} else {
|
3190
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3293
3191
|
|
3294
|
-
|
3192
|
+
scope.arrays ??= new Map();
|
3193
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3194
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3295
3195
|
|
3296
|
-
|
3297
|
-
|
3196
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3197
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3198
|
+
if (length !== 0) {
|
3199
|
+
let bytes = compileBytes(length, 'i32');
|
3298
3200
|
|
3299
|
-
|
3300
|
-
|
3201
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3202
|
+
if (elements[i] == null) continue;
|
3301
3203
|
|
3302
|
-
|
3303
|
-
|
3304
|
-
if (length !== 0) {
|
3305
|
-
let bytes = compileBytes(length, 'i32');
|
3204
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3205
|
+
}
|
3306
3206
|
|
3307
|
-
|
3308
|
-
|
3207
|
+
const ind = data.push({
|
3208
|
+
offset: rawPtr,
|
3209
|
+
bytes
|
3210
|
+
}) - 1;
|
3309
3211
|
|
3310
|
-
|
3212
|
+
scope.data ??= [];
|
3213
|
+
scope.data.push(ind);
|
3311
3214
|
}
|
3312
3215
|
|
3313
|
-
|
3314
|
-
|
3315
|
-
bytes
|
3316
|
-
}) - 1;
|
3317
|
-
|
3318
|
-
scope.data ??= [];
|
3319
|
-
scope.data.push(ind);
|
3216
|
+
// local value as pointer
|
3217
|
+
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3320
3218
|
}
|
3321
3219
|
|
3322
|
-
|
3323
|
-
|
3324
|
-
|
3325
|
-
|
3326
|
-
|
3220
|
+
const local = global ? globals[name] : scope.locals[name];
|
3221
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3222
|
+
if (pointerTmp != null) {
|
3223
|
+
out.push(
|
3224
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3225
|
+
Opcodes.i32_to_u,
|
3226
|
+
[ Opcodes.local_set, pointerTmp ]
|
3227
|
+
);
|
3327
3228
|
|
3328
|
-
|
3329
|
-
|
3330
|
-
out.push(
|
3331
|
-
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3332
|
-
Opcodes.i32_to_u,
|
3333
|
-
[ Opcodes.local_set, pointerTmp ]
|
3334
|
-
);
|
3229
|
+
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
3230
|
+
}
|
3335
3231
|
}
|
3336
3232
|
|
3337
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3338
3233
|
|
3339
3234
|
// store length
|
3340
3235
|
out.push(
|
3341
|
-
...
|
3236
|
+
...pointer,
|
3342
3237
|
...number(length, Valtype.i32),
|
3343
3238
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3344
3239
|
);
|
@@ -3350,11 +3245,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3350
3245
|
|
3351
3246
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3352
3247
|
out.push(
|
3353
|
-
...
|
3248
|
+
...pointer,
|
3354
3249
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3355
3250
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3356
3251
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3357
|
-
...
|
3252
|
+
...pointer,
|
3358
3253
|
...getNodeType(scope, elements[i]),
|
3359
3254
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3360
3255
|
])
|
@@ -3362,12 +3257,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3362
3257
|
}
|
3363
3258
|
|
3364
3259
|
// local value as pointer
|
3365
|
-
out.push(...
|
3260
|
+
out.push(...pointer);
|
3261
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3366
3262
|
|
3367
3263
|
return [ out, pointer ];
|
3368
3264
|
};
|
3369
3265
|
|
3370
|
-
const storeArray = (scope, array, index, element
|
3266
|
+
const storeArray = (scope, array, index, element) => {
|
3371
3267
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3372
3268
|
if (typeof index === 'number') index = number(index);
|
3373
3269
|
|
@@ -3379,26 +3275,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3379
3275
|
Opcodes.i32_to_u,
|
3380
3276
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3381
3277
|
[ Opcodes.i32_mul ],
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
]),
|
3278
|
+
|
3279
|
+
...array,
|
3280
|
+
Opcodes.i32_to_u,
|
3281
|
+
[ Opcodes.i32_add ],
|
3387
3282
|
[ Opcodes.local_set, offset ],
|
3388
3283
|
|
3389
3284
|
// store value
|
3390
3285
|
[ Opcodes.local_get, offset ],
|
3391
3286
|
...generate(scope, element),
|
3392
|
-
[ Opcodes.store, 0,
|
3287
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3393
3288
|
|
3394
3289
|
// store type
|
3395
3290
|
[ Opcodes.local_get, offset ],
|
3396
3291
|
...getNodeType(scope, element),
|
3397
|
-
[ Opcodes.i32_store8, 0,
|
3292
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3398
3293
|
];
|
3399
3294
|
};
|
3400
3295
|
|
3401
|
-
const loadArray = (scope, array, index
|
3296
|
+
const loadArray = (scope, array, index) => {
|
3402
3297
|
if (typeof index === 'number') index = number(index);
|
3403
3298
|
|
3404
3299
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3409,20 +3304,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3409
3304
|
Opcodes.i32_to_u,
|
3410
3305
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3411
3306
|
[ Opcodes.i32_mul ],
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3415
|
-
|
3416
|
-
]),
|
3307
|
+
|
3308
|
+
...array,
|
3309
|
+
Opcodes.i32_to_u,
|
3310
|
+
[ Opcodes.i32_add ],
|
3417
3311
|
[ Opcodes.local_set, offset ],
|
3418
3312
|
|
3419
3313
|
// load value
|
3420
3314
|
[ Opcodes.local_get, offset ],
|
3421
|
-
[ Opcodes.load, 0,
|
3315
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3422
3316
|
|
3423
3317
|
// load type
|
3424
3318
|
[ Opcodes.local_get, offset ],
|
3425
|
-
[ Opcodes.i32_load8_u, 0,
|
3319
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3426
3320
|
];
|
3427
3321
|
};
|
3428
3322
|
|
@@ -3454,7 +3348,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3454
3348
|
};
|
3455
3349
|
|
3456
3350
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3457
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3351
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3458
3352
|
};
|
3459
3353
|
|
3460
3354
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3473,9 +3367,6 @@ const withType = (scope, wasm, type) => [
|
|
3473
3367
|
|
3474
3368
|
const generateMember = (scope, decl, _global, _name) => {
|
3475
3369
|
const name = decl.object.name;
|
3476
|
-
const pointer = scope.arrays?.get(name);
|
3477
|
-
|
3478
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3479
3370
|
|
3480
3371
|
// hack: .name
|
3481
3372
|
if (decl.property.name === 'name') {
|
@@ -3510,18 +3401,16 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3510
3401
|
}
|
3511
3402
|
|
3512
3403
|
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);
|
3404
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3514
3405
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3515
3406
|
|
3516
3407
|
if (Prefs.fastLength) {
|
3517
3408
|
// presume valid length object
|
3518
3409
|
return [
|
3519
|
-
...(
|
3520
|
-
|
3521
|
-
Opcodes.i32_to_u
|
3522
|
-
]),
|
3410
|
+
...generate(scope, decl.object),
|
3411
|
+
Opcodes.i32_to_u,
|
3523
3412
|
|
3524
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3413
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3525
3414
|
Opcodes.i32_from_u
|
3526
3415
|
];
|
3527
3416
|
}
|
@@ -3530,12 +3419,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3530
3419
|
const known = knownType(scope, type);
|
3531
3420
|
if (known != null) {
|
3532
3421
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3533
|
-
...(
|
3534
|
-
|
3535
|
-
Opcodes.i32_to_u
|
3536
|
-
]),
|
3422
|
+
...generate(scope, decl.object),
|
3423
|
+
Opcodes.i32_to_u,
|
3537
3424
|
|
3538
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3425
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3539
3426
|
Opcodes.i32_from_u
|
3540
3427
|
];
|
3541
3428
|
|
@@ -3545,12 +3432,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3545
3432
|
return [
|
3546
3433
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3547
3434
|
[ Opcodes.if, valtypeBinary ],
|
3548
|
-
...(
|
3549
|
-
|
3550
|
-
Opcodes.i32_to_u
|
3551
|
-
]),
|
3435
|
+
...generate(scope, decl.object),
|
3436
|
+
Opcodes.i32_to_u,
|
3552
3437
|
|
3553
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3438
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3554
3439
|
Opcodes.i32_from_u,
|
3555
3440
|
|
3556
3441
|
...setLastType(scope, TYPES.number),
|
@@ -3593,25 +3478,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3593
3478
|
|
3594
3479
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3595
3480
|
// hack: this is naughty and will break things!
|
3596
|
-
let newOut = number(0,
|
3481
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3597
3482
|
if (pages.hasAnyString) {
|
3483
|
+
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3598
3484
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3599
|
-
rawElements: new Array(
|
3600
|
-
}, _global, _name, true, 'i16');
|
3485
|
+
rawElements: new Array(0)
|
3486
|
+
}, _global, _name, true, 'i16', true);
|
3601
3487
|
}
|
3602
3488
|
|
3603
3489
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3604
3490
|
[TYPES.array]: [
|
3605
|
-
...loadArray(scope, object, property
|
3491
|
+
...loadArray(scope, object, property),
|
3606
3492
|
...setLastType(scope)
|
3607
3493
|
],
|
3608
|
-
|
3609
3494
|
[TYPES.string]: [
|
3610
3495
|
// setup new/out array
|
3611
3496
|
...newOut,
|
3612
|
-
[ Opcodes.drop ],
|
3613
3497
|
|
3614
|
-
|
3498
|
+
// set length to 1
|
3499
|
+
...number(1, Valtype.i32),
|
3500
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3501
|
+
|
3502
|
+
// use as pointer for store later
|
3503
|
+
...newPointer,
|
3615
3504
|
|
3616
3505
|
...property,
|
3617
3506
|
Opcodes.i32_to_u,
|
@@ -3619,46 +3508,48 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3619
3508
|
...number(ValtypeSize.i16, Valtype.i32),
|
3620
3509
|
[ Opcodes.i32_mul ],
|
3621
3510
|
|
3622
|
-
...
|
3623
|
-
|
3624
|
-
|
3625
|
-
[ Opcodes.i32_add ]
|
3626
|
-
]),
|
3511
|
+
...object,
|
3512
|
+
Opcodes.i32_to_u,
|
3513
|
+
[ Opcodes.i32_add ],
|
3627
3514
|
|
3628
3515
|
// load current string ind {arg}
|
3629
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3516
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3630
3517
|
|
3631
3518
|
// store to new string ind 0
|
3632
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3519
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3633
3520
|
|
3634
3521
|
// return new string (page)
|
3635
|
-
...
|
3522
|
+
...newPointer,
|
3523
|
+
Opcodes.i32_from_u,
|
3636
3524
|
...setLastType(scope, TYPES.string)
|
3637
3525
|
],
|
3638
3526
|
[TYPES.bytestring]: [
|
3639
3527
|
// setup new/out array
|
3640
3528
|
...newOut,
|
3641
|
-
[ Opcodes.drop ],
|
3642
3529
|
|
3643
|
-
|
3530
|
+
// set length to 1
|
3531
|
+
...number(1, Valtype.i32),
|
3532
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3533
|
+
|
3534
|
+
// use as pointer for store later
|
3535
|
+
...newPointer,
|
3644
3536
|
|
3645
3537
|
...property,
|
3646
3538
|
Opcodes.i32_to_u,
|
3647
3539
|
|
3648
|
-
...
|
3649
|
-
|
3650
|
-
|
3651
|
-
[ Opcodes.i32_add ]
|
3652
|
-
]),
|
3540
|
+
...object,
|
3541
|
+
Opcodes.i32_to_u,
|
3542
|
+
[ Opcodes.i32_add ],
|
3653
3543
|
|
3654
3544
|
// load current string ind {arg}
|
3655
|
-
[ Opcodes.i32_load8_u, 0,
|
3545
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3656
3546
|
|
3657
3547
|
// store to new string ind 0
|
3658
|
-
[ Opcodes.i32_store8, 0,
|
3548
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3659
3549
|
|
3660
3550
|
// return new string (page)
|
3661
|
-
...
|
3551
|
+
...newPointer,
|
3552
|
+
Opcodes.i32_from_u,
|
3662
3553
|
...setLastType(scope, TYPES.bytestring)
|
3663
3554
|
],
|
3664
3555
|
|
@@ -3666,7 +3557,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3666
3557
|
});
|
3667
3558
|
};
|
3668
3559
|
|
3669
|
-
const randId = () => Math.random().toString(16).slice(
|
3560
|
+
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
3670
3561
|
|
3671
3562
|
const objectHack = node => {
|
3672
3563
|
if (!node) return node;
|
@@ -3718,7 +3609,7 @@ const generateFunc = (scope, decl) => {
|
|
3718
3609
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3719
3610
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3720
3611
|
|
3721
|
-
const name = decl.id ? decl.id.name : `
|
3612
|
+
const name = decl.id ? decl.id.name : `anonymous${randId()}`;
|
3722
3613
|
const params = decl.params ?? [];
|
3723
3614
|
|
3724
3615
|
// TODO: share scope/locals between !!!
|
@@ -3814,12 +3705,13 @@ const internalConstrs = {
|
|
3814
3705
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3815
3706
|
|
3816
3707
|
return [
|
3817
|
-
...
|
3708
|
+
...pointer,
|
3818
3709
|
...generate(scope, arg, global, name),
|
3819
3710
|
Opcodes.i32_to_u,
|
3820
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3711
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3821
3712
|
|
3822
|
-
...
|
3713
|
+
...pointer,
|
3714
|
+
Opcodes.i32_from_u
|
3823
3715
|
];
|
3824
3716
|
},
|
3825
3717
|
type: TYPES.array,
|
@@ -3968,8 +3860,9 @@ const internalConstrs = {
|
|
3968
3860
|
};
|
3969
3861
|
|
3970
3862
|
export default program => {
|
3971
|
-
globals = {
|
3972
|
-
|
3863
|
+
globals = {
|
3864
|
+
['#ind']: 0
|
3865
|
+
};
|
3973
3866
|
tags = [];
|
3974
3867
|
exceptions = [];
|
3975
3868
|
funcs = [];
|
@@ -3979,19 +3872,8 @@ export default program => {
|
|
3979
3872
|
data = [];
|
3980
3873
|
currentFuncIndex = importedFuncs.length;
|
3981
3874
|
|
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
3875
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3990
3876
|
|
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
3877
|
// set generic opcodes for current valtype
|
3996
3878
|
Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
|
3997
3879
|
Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
|
@@ -4013,6 +3895,7 @@ export default program => {
|
|
4013
3895
|
builtinFuncs = new BuiltinFuncs();
|
4014
3896
|
builtinVars = new BuiltinVars();
|
4015
3897
|
prototypeFuncs = new PrototypeFuncs();
|
3898
|
+
allocator = Allocator(Prefs.allocator ?? 'static');
|
4016
3899
|
|
4017
3900
|
program.id = { name: 'main' };
|
4018
3901
|
|
@@ -4055,6 +3938,8 @@ export default program => {
|
|
4055
3938
|
else main.returns = [];
|
4056
3939
|
}
|
4057
3940
|
|
3941
|
+
delete globals['#ind'];
|
3942
|
+
|
4058
3943
|
// if blank main func and other exports, remove it
|
4059
3944
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4060
3945
|
|