porffor 0.16.0-fe07da0f4 → 0.17.0-048c6f2ee
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 +2 -2
- package/README.md +5 -17
- package/compiler/2c.js +123 -75
- package/compiler/allocators.js +128 -0
- package/compiler/assemble.js +12 -5
- package/compiler/builtins/array.ts +72 -5
- package/compiler/builtins/base64.ts +28 -24
- package/compiler/builtins/date.ts +3 -30
- package/compiler/builtins/number.ts +10 -21
- package/compiler/builtins/porffor.d.ts +10 -0
- package/compiler/builtins/set.ts +7 -5
- package/compiler/builtins/string_f64.ts +10 -0
- package/compiler/builtins/z_ecma262.ts +62 -0
- package/compiler/builtins.js +26 -6
- package/compiler/codegen.js +364 -393
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +3 -1
- package/compiler/generated_builtins.js +153 -77
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +104 -7
- package/compiler/opt.js +10 -44
- package/compiler/parse.js +2 -8
- 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 +72 -20
- 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
|
|
@@ -274,10 +264,12 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
|
|
274
264
|
argument: {
|
275
265
|
type: 'NewExpression',
|
276
266
|
callee: {
|
267
|
+
type: 'Identifier',
|
277
268
|
name: constructor
|
278
269
|
},
|
279
270
|
arguments: [
|
280
271
|
{
|
272
|
+
type: 'Literal',
|
281
273
|
value: message
|
282
274
|
}
|
283
275
|
]
|
@@ -433,63 +425,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
433
425
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
434
426
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
435
427
|
|
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
428
|
const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
|
488
429
|
|
489
430
|
// alloc/assign array
|
490
|
-
const [ , pointer ] = makeArray(scope, {
|
431
|
+
const [ out, pointer ] = makeArray(scope, {
|
491
432
|
rawElements: new Array(0)
|
492
|
-
}, global, name, true, 'i16');
|
433
|
+
}, assign ? false : global, assign ? undefined : name, true, 'i16', true);
|
493
434
|
|
494
435
|
return [
|
495
436
|
// setup left
|
@@ -503,7 +444,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
503
444
|
[ Opcodes.local_set, rightPointer ],
|
504
445
|
|
505
446
|
// calculate length
|
506
|
-
...
|
447
|
+
...out,
|
507
448
|
|
508
449
|
[ Opcodes.local_get, leftPointer ],
|
509
450
|
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
@@ -516,11 +457,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
516
457
|
[ Opcodes.i32_add ],
|
517
458
|
|
518
459
|
// store length
|
519
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
460
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
520
461
|
|
521
462
|
// copy left
|
522
463
|
// dst = out pointer + length size
|
523
|
-
...
|
464
|
+
...pointer,
|
465
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
466
|
+
[ Opcodes.i32_add ],
|
524
467
|
|
525
468
|
// src = left pointer + length size
|
526
469
|
[ Opcodes.local_get, leftPointer ],
|
@@ -533,7 +476,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
533
476
|
|
534
477
|
// copy right
|
535
478
|
// dst = out pointer + length size + left length * sizeof valtype
|
536
|
-
...
|
479
|
+
...pointer,
|
480
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
481
|
+
[ Opcodes.i32_add ],
|
537
482
|
|
538
483
|
[ Opcodes.local_get, leftLength ],
|
539
484
|
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
@@ -553,7 +498,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
553
498
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
554
499
|
|
555
500
|
// return new string (page)
|
556
|
-
...
|
501
|
+
...pointer,
|
502
|
+
Opcodes.i32_from_u
|
557
503
|
];
|
558
504
|
};
|
559
505
|
|
@@ -669,10 +615,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
669
615
|
};
|
670
616
|
|
671
617
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
672
|
-
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
673
|
-
|
674
|
-
|
675
|
-
];
|
618
|
+
// if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
619
|
+
// ...wasm,
|
620
|
+
// ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
621
|
+
// ];
|
676
622
|
// if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
|
677
623
|
|
678
624
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
@@ -1014,12 +960,9 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1014
960
|
[ Opcodes.end ],
|
1015
961
|
]));
|
1016
962
|
|
1017
|
-
//
|
1018
|
-
|
1019
|
-
|
1020
|
-
// endOut.push(stringOnly([ Opcodes.end ]));
|
1021
|
-
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1022
|
-
// }
|
963
|
+
// add a surrounding block
|
964
|
+
startOut.push(stringOnly([ Opcodes.block, Valtype.i32 ]));
|
965
|
+
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1023
966
|
}
|
1024
967
|
|
1025
968
|
return finalize([
|
@@ -1054,7 +997,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1054
997
|
});
|
1055
998
|
};
|
1056
999
|
|
1057
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1000
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1058
1001
|
const existing = funcs.find(x => x.name === name);
|
1059
1002
|
if (existing) return existing;
|
1060
1003
|
|
@@ -1068,7 +1011,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1068
1011
|
|
1069
1012
|
for (const x of _data) {
|
1070
1013
|
const copy = { ...x };
|
1071
|
-
copy.offset += pages.size * pageSize;
|
1014
|
+
if (copy.offset != null) copy.offset += pages.size * pageSize;
|
1072
1015
|
data.push(copy);
|
1073
1016
|
}
|
1074
1017
|
|
@@ -1078,7 +1021,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1078
1021
|
locals,
|
1079
1022
|
localInd: allLocals.length,
|
1080
1023
|
returns,
|
1081
|
-
returnType
|
1024
|
+
returnType,
|
1082
1025
|
internal: true,
|
1083
1026
|
index: currentFuncIndex++,
|
1084
1027
|
table
|
@@ -1091,9 +1034,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1091
1034
|
|
1092
1035
|
let baseGlobalIdx, i = 0;
|
1093
1036
|
for (const type of globalTypes) {
|
1094
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1037
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
|
1095
1038
|
|
1096
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1039
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
|
1097
1040
|
i++;
|
1098
1041
|
}
|
1099
1042
|
|
@@ -1106,11 +1049,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1106
1049
|
}
|
1107
1050
|
}
|
1108
1051
|
|
1109
|
-
if (table)
|
1110
|
-
|
1111
|
-
inst.
|
1112
|
-
|
1052
|
+
if (table) {
|
1053
|
+
for (const inst of wasm) {
|
1054
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1055
|
+
inst.splice(2, 99);
|
1056
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1057
|
+
}
|
1113
1058
|
}
|
1059
|
+
|
1060
|
+
funcs.table = true;
|
1114
1061
|
}
|
1115
1062
|
|
1116
1063
|
func.wasm = wasm;
|
@@ -1254,7 +1201,7 @@ const getNodeType = (scope, node) => {
|
|
1254
1201
|
const func = funcs.find(x => x.name === name);
|
1255
1202
|
|
1256
1203
|
if (func) {
|
1257
|
-
if (func.returnType) return func.returnType;
|
1204
|
+
if (func.returnType != null) return func.returnType;
|
1258
1205
|
}
|
1259
1206
|
|
1260
1207
|
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
|
@@ -1270,15 +1217,7 @@ const getNodeType = (scope, node) => {
|
|
1270
1217
|
const func = spl[spl.length - 1];
|
1271
1218
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1272
1219
|
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;
|
1220
|
+
if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
|
1282
1221
|
}
|
1283
1222
|
}
|
1284
1223
|
|
@@ -1326,7 +1265,15 @@ const getNodeType = (scope, node) => {
|
|
1326
1265
|
}
|
1327
1266
|
|
1328
1267
|
if (node.type === 'AssignmentExpression') {
|
1329
|
-
|
1268
|
+
const op = node.operator.slice(0, -1) || '=';
|
1269
|
+
if (op === '=') return getNodeType(scope, node.right);
|
1270
|
+
|
1271
|
+
return getNodeType(scope, {
|
1272
|
+
type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
|
1273
|
+
left: node.left,
|
1274
|
+
right: node.right,
|
1275
|
+
operator: op
|
1276
|
+
});
|
1330
1277
|
}
|
1331
1278
|
|
1332
1279
|
if (node.type === 'ArrayExpression') {
|
@@ -1345,23 +1292,6 @@ const getNodeType = (scope, node) => {
|
|
1345
1292
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1346
1293
|
|
1347
1294
|
return TYPES.number;
|
1348
|
-
|
1349
|
-
// todo: string concat types
|
1350
|
-
// if (node.operator !== '+') return TYPES.number;
|
1351
|
-
// else return [
|
1352
|
-
// // if left is string
|
1353
|
-
// ...getNodeType(scope, node.left),
|
1354
|
-
// ...number(TYPES.string, Valtype.i32),
|
1355
|
-
// [ Opcodes.i32_eq ],
|
1356
|
-
|
1357
|
-
// // if right is string
|
1358
|
-
// ...getNodeType(scope, node.right),
|
1359
|
-
// ...number(TYPES.string, Valtype.i32),
|
1360
|
-
// [ Opcodes.i32_eq ],
|
1361
|
-
|
1362
|
-
// // if either are true
|
1363
|
-
// [ Opcodes.i32_or ],
|
1364
|
-
// ];
|
1365
1295
|
}
|
1366
1296
|
|
1367
1297
|
if (node.type === 'UnaryExpression') {
|
@@ -1381,7 +1311,6 @@ const getNodeType = (scope, node) => {
|
|
1381
1311
|
if (Prefs.fastLength) return TYPES.number;
|
1382
1312
|
}
|
1383
1313
|
|
1384
|
-
|
1385
1314
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1386
1315
|
if (objectKnownType != null) {
|
1387
1316
|
if (name === 'length') {
|
@@ -1392,7 +1321,6 @@ const getNodeType = (scope, node) => {
|
|
1392
1321
|
if (node.computed) {
|
1393
1322
|
if (objectKnownType === TYPES.string) return TYPES.string;
|
1394
1323
|
if (objectKnownType === TYPES.bytestring) return TYPES.bytestring;
|
1395
|
-
if (objectKnownType === TYPES.array) return TYPES.number;
|
1396
1324
|
}
|
1397
1325
|
}
|
1398
1326
|
|
@@ -1458,10 +1386,10 @@ const countLeftover = wasm => {
|
|
1458
1386
|
|
1459
1387
|
if (depth === 0)
|
1460
1388
|
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] <
|
1389
|
+
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
1390
|
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
1391
|
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]
|
1392
|
+
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1465
1393
|
else if (inst[0] === Opcodes.return) count = 0;
|
1466
1394
|
else if (inst[0] === Opcodes.call) {
|
1467
1395
|
let func = funcs.find(x => x.index === inst[1]);
|
@@ -1733,7 +1661,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1733
1661
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1734
1662
|
return makeArray(scope, {
|
1735
1663
|
rawElements: new Array(length)
|
1736
|
-
}, _global, _name, true, itemType);
|
1664
|
+
}, _global, _name, true, itemType, true);
|
1737
1665
|
}, () => {
|
1738
1666
|
optUnused = true;
|
1739
1667
|
return unusedValue;
|
@@ -1815,7 +1743,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1815
1743
|
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1816
1744
|
|
1817
1745
|
// value
|
1818
|
-
i32_const: { imms: 1, args: [], returns:
|
1746
|
+
i32_const: { imms: 1, args: [], returns: 0 },
|
1819
1747
|
};
|
1820
1748
|
|
1821
1749
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1900,7 +1828,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1900
1828
|
if (indirectMode === 'strict') {
|
1901
1829
|
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
1902
1830
|
[TYPES.function]: [
|
1903
|
-
...
|
1831
|
+
...out,
|
1904
1832
|
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1905
1833
|
Opcodes.i32_to_u,
|
1906
1834
|
[ Opcodes.call_indirect, args.length, 0 ],
|
@@ -1978,7 +1906,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
1906
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1979
1907
|
const userFunc = func && !func.internal;
|
1980
1908
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1981
|
-
const typedReturns = (
|
1909
|
+
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1982
1910
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1983
1911
|
|
1984
1912
|
let args = decl.arguments;
|
@@ -2006,13 +1934,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2006
1934
|
continue;
|
2007
1935
|
}
|
2008
1936
|
|
2009
|
-
if (valtypeBinary !== Valtype.i32 &&
|
2010
|
-
(
|
2011
|
-
|
2012
|
-
)) {
|
1937
|
+
if (valtypeBinary !== Valtype.i32 &&
|
1938
|
+
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1939
|
+
) {
|
2013
1940
|
out.push(Opcodes.i32_to);
|
2014
1941
|
}
|
2015
1942
|
|
1943
|
+
if (valtypeBinary === Valtype.i32 &&
|
1944
|
+
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1945
|
+
) {
|
1946
|
+
out.push([ Opcodes.f64_convert_i32_s ]);
|
1947
|
+
}
|
1948
|
+
|
2016
1949
|
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
2017
1950
|
}
|
2018
1951
|
|
@@ -2034,6 +1967,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2034
1967
|
out.push(Opcodes.i32_from);
|
2035
1968
|
}
|
2036
1969
|
|
1970
|
+
if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32) {
|
1971
|
+
out.push(Opcodes.i32_trunc_sat_f64_s);
|
1972
|
+
}
|
1973
|
+
|
2037
1974
|
return out;
|
2038
1975
|
};
|
2039
1976
|
|
@@ -2057,9 +1994,9 @@ const generateNew = (scope, decl, _global, _name) => {
|
|
2057
1994
|
if (
|
2058
1995
|
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2059
1996
|
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2060
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor
|
1997
|
+
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2061
1998
|
|
2062
|
-
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet
|
1999
|
+
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`, true); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
|
2063
2000
|
|
2064
2001
|
return generateCall(scope, decl, _global, _name);
|
2065
2002
|
};
|
@@ -2123,7 +2060,6 @@ const brTable = (input, bc, returns) => {
|
|
2123
2060
|
}
|
2124
2061
|
|
2125
2062
|
for (let i = 0; i < count; i++) {
|
2126
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2127
2063
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2128
2064
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2129
2065
|
}
|
@@ -2157,10 +2093,8 @@ const brTable = (input, bc, returns) => {
|
|
2157
2093
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2158
2094
|
);
|
2159
2095
|
|
2160
|
-
//
|
2161
|
-
// (
|
2162
|
-
// dm me and if you are correct and the first person
|
2163
|
-
// I will somehow shout you out or something
|
2096
|
+
// sort the wrong way and then reverse
|
2097
|
+
// so strings ('default') are at the start before any numbers
|
2164
2098
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2165
2099
|
|
2166
2100
|
br = count - 1;
|
@@ -2186,10 +2120,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2186
2120
|
return bc[known] ?? bc.default;
|
2187
2121
|
}
|
2188
2122
|
|
2189
|
-
if (Prefs.
|
2123
|
+
if (Prefs.typeswitchBrtable)
|
2190
2124
|
return brTable(type, bc, returns);
|
2191
2125
|
|
2192
|
-
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
2126
|
+
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
2193
2127
|
const out = [
|
2194
2128
|
...type,
|
2195
2129
|
[ Opcodes.local_set, tmp ],
|
@@ -2241,11 +2175,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2241
2175
|
return target[name].idx;
|
2242
2176
|
}
|
2243
2177
|
|
2244
|
-
let idx = global ?
|
2178
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2245
2179
|
target[name] = { idx, type: valtypeBinary };
|
2246
2180
|
|
2247
2181
|
if (type) {
|
2248
|
-
let typeIdx = global ?
|
2182
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2249
2183
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2250
2184
|
}
|
2251
2185
|
|
@@ -2338,24 +2272,10 @@ const generateVar = (scope, decl) => {
|
|
2338
2272
|
}
|
2339
2273
|
|
2340
2274
|
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
|
-
// }
|
2275
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2356
2276
|
|
2357
2277
|
const generated = generate(scope, x.init, global, name);
|
2358
|
-
if (scope.arrays?.get(name) != null) {
|
2278
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2359
2279
|
// hack to set local as pointer before
|
2360
2280
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2361
2281
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2407,19 +2327,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2407
2327
|
|
2408
2328
|
// hack: .length setter
|
2409
2329
|
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
2330
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2416
2331
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2417
2332
|
|
2418
2333
|
return [
|
2419
|
-
...(
|
2420
|
-
|
2421
|
-
Opcodes.i32_to_u
|
2422
|
-
]),
|
2334
|
+
...generate(scope, decl.left.object),
|
2335
|
+
Opcodes.i32_to_u,
|
2423
2336
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2424
2337
|
|
2425
2338
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2430,7 +2343,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2430
2343
|
[ Opcodes.local_tee, newValueTmp ],
|
2431
2344
|
|
2432
2345
|
Opcodes.i32_to_u,
|
2433
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2346
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2434
2347
|
|
2435
2348
|
[ Opcodes.local_get, newValueTmp ]
|
2436
2349
|
];
|
@@ -2438,21 +2351,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2438
2351
|
|
2439
2352
|
// arr[i]
|
2440
2353
|
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
2354
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2447
2355
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2448
2356
|
|
2449
2357
|
return [
|
2450
2358
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2451
2359
|
[TYPES.array]: [
|
2452
|
-
...(
|
2453
|
-
|
2454
|
-
Opcodes.i32_to_u
|
2455
|
-
]),
|
2360
|
+
...generate(scope, decl.left.object),
|
2361
|
+
Opcodes.i32_to_u,
|
2456
2362
|
|
2457
2363
|
// get index as valtype
|
2458
2364
|
...generate(scope, decl.left.property),
|
@@ -2461,39 +2367,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2461
2367
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2462
2368
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2463
2369
|
[ Opcodes.i32_mul ],
|
2464
|
-
|
2370
|
+
[ Opcodes.i32_add ],
|
2465
2371
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2466
2372
|
|
2467
2373
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2468
2374
|
[ Opcodes.local_get, pointerTmp ],
|
2469
|
-
[ Opcodes.load, 0,
|
2375
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2470
2376
|
], generate(scope, decl.right), [
|
2471
2377
|
[ Opcodes.local_get, pointerTmp ],
|
2472
|
-
[ Opcodes.i32_load8_u, 0,
|
2378
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2473
2379
|
], getNodeType(scope, decl.right), false, name, true)),
|
2474
2380
|
[ Opcodes.local_tee, newValueTmp ],
|
2475
2381
|
|
2476
|
-
[ Opcodes.store, 0,
|
2382
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2477
2383
|
],
|
2478
2384
|
|
2479
2385
|
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
2386
|
}, Blocktype.void),
|
2498
2387
|
|
2499
2388
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2555,9 +2444,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2555
2444
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2556
2445
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2557
2446
|
|
2558
|
-
|
2559
|
-
|
2560
|
-
...setType(scope, name, TYPES.number)
|
2447
|
+
...setType(scope, name, getNodeType(scope, decl))
|
2561
2448
|
];
|
2562
2449
|
};
|
2563
2450
|
|
@@ -2571,7 +2458,7 @@ const generateUnary = (scope, decl) => {
|
|
2571
2458
|
// * -1
|
2572
2459
|
|
2573
2460
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
2574
|
-
// if
|
2461
|
+
// if -n, just return that as a const
|
2575
2462
|
return number(-1 * decl.argument.value);
|
2576
2463
|
}
|
2577
2464
|
|
@@ -2583,14 +2470,14 @@ const generateUnary = (scope, decl) => {
|
|
2583
2470
|
case '!':
|
2584
2471
|
const arg = decl.argument;
|
2585
2472
|
if (arg.type === 'UnaryExpression' && arg.operator === '!') {
|
2586
|
-
// !!x -> is x truthy
|
2473
|
+
// opt: !!x -> is x truthy
|
2587
2474
|
return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
|
2588
2475
|
}
|
2476
|
+
|
2589
2477
|
// !=
|
2590
|
-
return falsy(scope, generate(scope,
|
2478
|
+
return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
|
2591
2479
|
|
2592
2480
|
case '~':
|
2593
|
-
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
2594
2481
|
return [
|
2595
2482
|
...generate(scope, decl.argument),
|
2596
2483
|
Opcodes.i32_to,
|
@@ -2877,12 +2764,12 @@ const generateForOf = (scope, decl) => {
|
|
2877
2764
|
|
2878
2765
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2879
2766
|
// hack: this is naughty and will break things!
|
2880
|
-
let newOut = number(0, Valtype.
|
2767
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2881
2768
|
if (pages.hasAnyString) {
|
2882
2769
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2883
2770
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2884
|
-
rawElements: new Array(
|
2885
|
-
}, isGlobal, leftName, true, 'i16');
|
2771
|
+
rawElements: new Array(0)
|
2772
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2886
2773
|
}
|
2887
2774
|
|
2888
2775
|
// set type for local
|
@@ -2929,23 +2816,28 @@ const generateForOf = (scope, decl) => {
|
|
2929
2816
|
[TYPES.string]: [
|
2930
2817
|
...setType(scope, leftName, TYPES.string),
|
2931
2818
|
|
2932
|
-
[ Opcodes.loop, Blocktype.void ],
|
2933
|
-
|
2934
2819
|
// setup new/out array
|
2935
2820
|
...newOut,
|
2936
|
-
[ Opcodes.drop ],
|
2937
2821
|
|
2938
|
-
|
2822
|
+
// set length to 1
|
2823
|
+
...number(1, Valtype.i32),
|
2824
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2825
|
+
|
2826
|
+
[ Opcodes.loop, Blocktype.void ],
|
2827
|
+
|
2828
|
+
// use as pointer for store later
|
2829
|
+
...newPointer,
|
2939
2830
|
|
2940
2831
|
// load current string ind {arg}
|
2941
2832
|
[ Opcodes.local_get, pointer ],
|
2942
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
2833
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2943
2834
|
|
2944
2835
|
// store to new string ind 0
|
2945
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
2836
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2946
2837
|
|
2947
2838
|
// return new string (page)
|
2948
|
-
...
|
2839
|
+
...newPointer,
|
2840
|
+
Opcodes.i32_from_u,
|
2949
2841
|
|
2950
2842
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2951
2843
|
|
@@ -2977,25 +2869,30 @@ const generateForOf = (scope, decl) => {
|
|
2977
2869
|
[TYPES.bytestring]: [
|
2978
2870
|
...setType(scope, leftName, TYPES.bytestring),
|
2979
2871
|
|
2980
|
-
[ Opcodes.loop, Blocktype.void ],
|
2981
|
-
|
2982
2872
|
// setup new/out array
|
2983
2873
|
...newOut,
|
2984
|
-
[ Opcodes.drop ],
|
2985
2874
|
|
2986
|
-
|
2875
|
+
// set length to 1
|
2876
|
+
...number(1, Valtype.i32),
|
2877
|
+
[ Opcodes.i32_store, 0, 0 ],
|
2878
|
+
|
2879
|
+
[ Opcodes.loop, Blocktype.void ],
|
2880
|
+
|
2881
|
+
// use as pointer for store later
|
2882
|
+
...newPointer,
|
2987
2883
|
|
2988
2884
|
// load current string ind {arg}
|
2989
2885
|
[ Opcodes.local_get, pointer ],
|
2990
2886
|
[ Opcodes.local_get, counter ],
|
2991
2887
|
[ Opcodes.i32_add ],
|
2992
|
-
[ Opcodes.i32_load8_u, 0,
|
2888
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2993
2889
|
|
2994
2890
|
// store to new string ind 0
|
2995
|
-
[ Opcodes.i32_store8, 0,
|
2891
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2996
2892
|
|
2997
2893
|
// return new string (page)
|
2998
|
-
...
|
2894
|
+
...newPointer,
|
2895
|
+
Opcodes.i32_from_u,
|
2999
2896
|
|
3000
2897
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3001
2898
|
|
@@ -3134,32 +3031,46 @@ const generateLabel = (scope, decl) => {
|
|
3134
3031
|
const generateThrow = (scope, decl) => {
|
3135
3032
|
scope.throws = true;
|
3136
3033
|
|
3137
|
-
|
3034
|
+
const exceptionMode = Prefs.exceptionMode ?? 'lut';
|
3035
|
+
if (exceptionMode === 'lut') {
|
3036
|
+
let message = decl.argument.value, constructor = null;
|
3138
3037
|
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
|
3143
|
-
|
3038
|
+
// support `throw (new)? Error(...)`
|
3039
|
+
if (!message && (decl.argument.type === 'NewExpression' || decl.argument.type === 'CallExpression')) {
|
3040
|
+
constructor = decl.argument.callee.name;
|
3041
|
+
message = decl.argument.arguments[0]?.value ?? '';
|
3042
|
+
}
|
3144
3043
|
|
3145
|
-
|
3146
|
-
|
3147
|
-
|
3148
|
-
|
3149
|
-
|
3044
|
+
if (tags.length === 0) tags.push({
|
3045
|
+
params: [ Valtype.i32 ],
|
3046
|
+
results: [],
|
3047
|
+
idx: tags.length
|
3048
|
+
});
|
3150
3049
|
|
3151
|
-
|
3152
|
-
let tagIdx = tags[0].idx;
|
3050
|
+
let exceptId = exceptions.push({ constructor, message }) - 1;
|
3153
3051
|
|
3154
|
-
|
3155
|
-
|
3052
|
+
scope.exceptions ??= [];
|
3053
|
+
scope.exceptions.push(exceptId);
|
3156
3054
|
|
3157
|
-
|
3055
|
+
return [
|
3056
|
+
[ Opcodes.i32_const, signedLEB128(exceptId) ],
|
3057
|
+
[ Opcodes.throw, tags[0].idx ]
|
3058
|
+
];
|
3059
|
+
}
|
3158
3060
|
|
3159
|
-
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3061
|
+
if (exceptionMode === 'stack') {
|
3062
|
+
if (tags.length === 0) tags.push({
|
3063
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
3064
|
+
results: [],
|
3065
|
+
idx: tags.length
|
3066
|
+
});
|
3067
|
+
|
3068
|
+
return [
|
3069
|
+
...generate(scope, decl.argument),
|
3070
|
+
...getNodeType(scope, decl.argument),
|
3071
|
+
[ Opcodes.throw, tags[0].idx ]
|
3072
|
+
];
|
3073
|
+
}
|
3163
3074
|
};
|
3164
3075
|
|
3165
3076
|
const generateTry = (scope, decl) => {
|
@@ -3210,18 +3121,6 @@ const allocPage = (scope, reason, type) => {
|
|
3210
3121
|
scope.pages ??= new Map();
|
3211
3122
|
scope.pages.set(reason, { ind, type });
|
3212
3123
|
|
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
3124
|
return ind;
|
3226
3125
|
};
|
3227
3126
|
|
@@ -3259,39 +3158,58 @@ const compileBytes = (val, itemType) => {
|
|
3259
3158
|
}
|
3260
3159
|
};
|
3261
3160
|
|
3262
|
-
const
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3161
|
+
const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
|
3162
|
+
const length = elements.length;
|
3163
|
+
|
3164
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3165
|
+
if (length === 0) return false;
|
3166
|
+
|
3167
|
+
let bytes = compileBytes(length, 'i32');
|
3168
|
+
|
3169
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3170
|
+
if (elements[i] == null) continue;
|
3266
3171
|
|
3267
|
-
|
3172
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3268
3173
|
}
|
3269
|
-
};
|
3270
3174
|
|
3271
|
-
const
|
3272
|
-
|
3175
|
+
const obj = { bytes };
|
3176
|
+
if (offset != null) obj.offset = offset;
|
3273
3177
|
|
3274
|
-
|
3178
|
+
const idx = data.push(obj) - 1;
|
3275
3179
|
|
3276
|
-
|
3277
|
-
|
3278
|
-
firstAssign = true;
|
3180
|
+
scope.data ??= [];
|
3181
|
+
scope.data.push(idx);
|
3279
3182
|
|
3280
|
-
|
3281
|
-
|
3183
|
+
return { idx, size: bytes.length };
|
3184
|
+
};
|
3282
3185
|
|
3283
|
-
|
3284
|
-
|
3285
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3186
|
+
const printStaticStr = str => {
|
3187
|
+
const out = [];
|
3286
3188
|
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3189
|
+
for (let i = 0; i < str.length; i++) {
|
3190
|
+
out.push(
|
3191
|
+
// ...number(str.charCodeAt(i)),
|
3192
|
+
...number(str.charCodeAt(i), Valtype.i32),
|
3193
|
+
Opcodes.i32_from_u,
|
3194
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3195
|
+
);
|
3290
3196
|
}
|
3291
3197
|
|
3292
|
-
|
3198
|
+
return out;
|
3199
|
+
};
|
3200
|
+
|
3201
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
3202
|
+
if (itemType !== 'i16' && itemType !== 'i8') {
|
3203
|
+
pages.hasArray = true;
|
3204
|
+
} else {
|
3205
|
+
pages.hasAnyString = true;
|
3206
|
+
if (itemType === 'i8') pages.hasByteString = true;
|
3207
|
+
else pages.hasString = true;
|
3208
|
+
}
|
3209
|
+
|
3210
|
+
const out = [];
|
3293
3211
|
|
3294
|
-
const
|
3212
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3295
3213
|
|
3296
3214
|
const useRawElements = !!decl.rawElements;
|
3297
3215
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3299,46 +3217,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3299
3217
|
const valtype = itemTypeToValtype[itemType];
|
3300
3218
|
const length = elements.length;
|
3301
3219
|
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3220
|
+
const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
|
3221
|
+
|
3222
|
+
let pointer = allocated;
|
3223
|
+
if (allocator.constructor.name !== 'StaticAllocator') {
|
3224
|
+
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3225
|
+
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
3226
|
+
out.push(
|
3227
|
+
...allocated,
|
3228
|
+
[ Opcodes.local_set, tmp ]
|
3229
|
+
);
|
3230
|
+
|
3231
|
+
if (Prefs.runtimeAllocLog) out.push(
|
3232
|
+
...printStaticStr(`${name}: `),
|
3233
|
+
|
3234
|
+
[ Opcodes.local_get, tmp ],
|
3235
|
+
Opcodes.i32_from_u,
|
3236
|
+
[ Opcodes.call, 0 ],
|
3237
|
+
|
3238
|
+
...number(10),
|
3239
|
+
[ Opcodes.call, 1 ]
|
3240
|
+
);
|
3306
3241
|
|
3307
|
-
|
3308
|
-
if (elements[i] == null) continue;
|
3242
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3309
3243
|
|
3310
|
-
|
3244
|
+
if (Prefs.data && useRawElements) {
|
3245
|
+
const data = makeData(scope, elements, null, itemType, initEmpty);
|
3246
|
+
if (data) {
|
3247
|
+
// init data
|
3248
|
+
out.push(
|
3249
|
+
...pointer,
|
3250
|
+
...number(0, Valtype.i32),
|
3251
|
+
...number(data.size, Valtype.i32),
|
3252
|
+
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
3253
|
+
);
|
3311
3254
|
}
|
3312
3255
|
|
3313
|
-
|
3314
|
-
|
3315
|
-
|
3316
|
-
|
3256
|
+
// return pointer in out
|
3257
|
+
out.push(
|
3258
|
+
...pointer,
|
3259
|
+
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
3260
|
+
);
|
3317
3261
|
|
3318
|
-
|
3319
|
-
scope.data.push(ind);
|
3262
|
+
return [ out, pointer ];
|
3320
3263
|
}
|
3264
|
+
} else {
|
3265
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3321
3266
|
|
3322
|
-
|
3323
|
-
|
3267
|
+
scope.arrays ??= new Map();
|
3268
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3269
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3324
3270
|
|
3325
|
-
|
3326
|
-
|
3271
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3272
|
+
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
3327
3273
|
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
)
|
3274
|
+
// local value as pointer
|
3275
|
+
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3276
|
+
}
|
3277
|
+
|
3278
|
+
const local = global ? globals[name] : scope.locals[name];
|
3279
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3280
|
+
if (pointerTmp != null) {
|
3281
|
+
out.push(
|
3282
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3283
|
+
Opcodes.i32_to_u,
|
3284
|
+
[ Opcodes.local_set, pointerTmp ]
|
3285
|
+
);
|
3286
|
+
|
3287
|
+
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
3288
|
+
}
|
3335
3289
|
}
|
3336
3290
|
|
3337
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3338
3291
|
|
3339
3292
|
// store length
|
3340
3293
|
out.push(
|
3341
|
-
...
|
3294
|
+
...pointer,
|
3342
3295
|
...number(length, Valtype.i32),
|
3343
3296
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3344
3297
|
);
|
@@ -3350,11 +3303,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3350
3303
|
|
3351
3304
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3352
3305
|
out.push(
|
3353
|
-
...
|
3306
|
+
...pointer,
|
3354
3307
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3355
3308
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3356
3309
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3357
|
-
...
|
3310
|
+
...pointer,
|
3358
3311
|
...getNodeType(scope, elements[i]),
|
3359
3312
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3360
3313
|
])
|
@@ -3362,12 +3315,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3362
3315
|
}
|
3363
3316
|
|
3364
3317
|
// local value as pointer
|
3365
|
-
out.push(...
|
3318
|
+
out.push(...pointer);
|
3319
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3366
3320
|
|
3367
3321
|
return [ out, pointer ];
|
3368
3322
|
};
|
3369
3323
|
|
3370
|
-
const storeArray = (scope, array, index, element
|
3324
|
+
const storeArray = (scope, array, index, element) => {
|
3371
3325
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3372
3326
|
if (typeof index === 'number') index = number(index);
|
3373
3327
|
|
@@ -3379,26 +3333,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3379
3333
|
Opcodes.i32_to_u,
|
3380
3334
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3381
3335
|
[ Opcodes.i32_mul ],
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
]),
|
3336
|
+
|
3337
|
+
...array,
|
3338
|
+
Opcodes.i32_to_u,
|
3339
|
+
[ Opcodes.i32_add ],
|
3387
3340
|
[ Opcodes.local_set, offset ],
|
3388
3341
|
|
3389
3342
|
// store value
|
3390
3343
|
[ Opcodes.local_get, offset ],
|
3391
3344
|
...generate(scope, element),
|
3392
|
-
[ Opcodes.store, 0,
|
3345
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3393
3346
|
|
3394
3347
|
// store type
|
3395
3348
|
[ Opcodes.local_get, offset ],
|
3396
3349
|
...getNodeType(scope, element),
|
3397
|
-
[ Opcodes.i32_store8, 0,
|
3350
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3398
3351
|
];
|
3399
3352
|
};
|
3400
3353
|
|
3401
|
-
const loadArray = (scope, array, index
|
3354
|
+
const loadArray = (scope, array, index) => {
|
3402
3355
|
if (typeof index === 'number') index = number(index);
|
3403
3356
|
|
3404
3357
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3409,20 +3362,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3409
3362
|
Opcodes.i32_to_u,
|
3410
3363
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3411
3364
|
[ Opcodes.i32_mul ],
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3415
|
-
|
3416
|
-
]),
|
3365
|
+
|
3366
|
+
...array,
|
3367
|
+
Opcodes.i32_to_u,
|
3368
|
+
[ Opcodes.i32_add ],
|
3417
3369
|
[ Opcodes.local_set, offset ],
|
3418
3370
|
|
3419
3371
|
// load value
|
3420
3372
|
[ Opcodes.local_get, offset ],
|
3421
|
-
[ Opcodes.load, 0,
|
3373
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3422
3374
|
|
3423
3375
|
// load type
|
3424
3376
|
[ Opcodes.local_get, offset ],
|
3425
|
-
[ Opcodes.i32_load8_u, 0,
|
3377
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3426
3378
|
];
|
3427
3379
|
};
|
3428
3380
|
|
@@ -3454,7 +3406,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3454
3406
|
};
|
3455
3407
|
|
3456
3408
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3457
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3409
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3458
3410
|
};
|
3459
3411
|
|
3460
3412
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3473,9 +3425,6 @@ const withType = (scope, wasm, type) => [
|
|
3473
3425
|
|
3474
3426
|
const generateMember = (scope, decl, _global, _name) => {
|
3475
3427
|
const name = decl.object.name;
|
3476
|
-
const pointer = scope.arrays?.get(name);
|
3477
|
-
|
3478
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3479
3428
|
|
3480
3429
|
// hack: .name
|
3481
3430
|
if (decl.property.name === 'name') {
|
@@ -3510,18 +3459,16 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3510
3459
|
}
|
3511
3460
|
|
3512
3461
|
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);
|
3462
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3514
3463
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3515
3464
|
|
3516
3465
|
if (Prefs.fastLength) {
|
3517
3466
|
// presume valid length object
|
3518
3467
|
return [
|
3519
|
-
...(
|
3520
|
-
|
3521
|
-
Opcodes.i32_to_u
|
3522
|
-
]),
|
3468
|
+
...generate(scope, decl.object),
|
3469
|
+
Opcodes.i32_to_u,
|
3523
3470
|
|
3524
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3471
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3525
3472
|
Opcodes.i32_from_u
|
3526
3473
|
];
|
3527
3474
|
}
|
@@ -3530,12 +3477,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3530
3477
|
const known = knownType(scope, type);
|
3531
3478
|
if (known != null) {
|
3532
3479
|
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3533
|
-
...(
|
3534
|
-
|
3535
|
-
Opcodes.i32_to_u
|
3536
|
-
]),
|
3480
|
+
...generate(scope, decl.object),
|
3481
|
+
Opcodes.i32_to_u,
|
3537
3482
|
|
3538
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3483
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3539
3484
|
Opcodes.i32_from_u
|
3540
3485
|
];
|
3541
3486
|
|
@@ -3545,12 +3490,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3545
3490
|
return [
|
3546
3491
|
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3547
3492
|
[ Opcodes.if, valtypeBinary ],
|
3548
|
-
...(
|
3549
|
-
|
3550
|
-
Opcodes.i32_to_u
|
3551
|
-
]),
|
3493
|
+
...generate(scope, decl.object),
|
3494
|
+
Opcodes.i32_to_u,
|
3552
3495
|
|
3553
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3496
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3554
3497
|
Opcodes.i32_from_u,
|
3555
3498
|
|
3556
3499
|
...setLastType(scope, TYPES.number),
|
@@ -3593,25 +3536,29 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3593
3536
|
|
3594
3537
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3595
3538
|
// hack: this is naughty and will break things!
|
3596
|
-
let newOut = number(0,
|
3597
|
-
if (pages.hasAnyString) {
|
3539
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3540
|
+
if (pages.hasAnyString && knownType(scope, getNodeType(scope, decl.object)) !== TYPES.array) {
|
3541
|
+
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3598
3542
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3599
|
-
rawElements: new Array(
|
3600
|
-
}, _global, _name, true, 'i16');
|
3543
|
+
rawElements: new Array(0)
|
3544
|
+
}, _global, _name, true, 'i16', true);
|
3601
3545
|
}
|
3602
3546
|
|
3603
3547
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3604
3548
|
[TYPES.array]: [
|
3605
|
-
...loadArray(scope, object, property
|
3549
|
+
...loadArray(scope, object, property),
|
3606
3550
|
...setLastType(scope)
|
3607
3551
|
],
|
3608
|
-
|
3609
3552
|
[TYPES.string]: [
|
3610
3553
|
// setup new/out array
|
3611
3554
|
...newOut,
|
3612
|
-
[ Opcodes.drop ],
|
3613
3555
|
|
3614
|
-
|
3556
|
+
// set length to 1
|
3557
|
+
...number(1, Valtype.i32),
|
3558
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3559
|
+
|
3560
|
+
// use as pointer for store later
|
3561
|
+
...newPointer,
|
3615
3562
|
|
3616
3563
|
...property,
|
3617
3564
|
Opcodes.i32_to_u,
|
@@ -3619,46 +3566,48 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3619
3566
|
...number(ValtypeSize.i16, Valtype.i32),
|
3620
3567
|
[ Opcodes.i32_mul ],
|
3621
3568
|
|
3622
|
-
...
|
3623
|
-
|
3624
|
-
|
3625
|
-
[ Opcodes.i32_add ]
|
3626
|
-
]),
|
3569
|
+
...object,
|
3570
|
+
Opcodes.i32_to_u,
|
3571
|
+
[ Opcodes.i32_add ],
|
3627
3572
|
|
3628
3573
|
// load current string ind {arg}
|
3629
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3574
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3630
3575
|
|
3631
3576
|
// store to new string ind 0
|
3632
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3577
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3633
3578
|
|
3634
3579
|
// return new string (page)
|
3635
|
-
...
|
3580
|
+
...newPointer,
|
3581
|
+
Opcodes.i32_from_u,
|
3636
3582
|
...setLastType(scope, TYPES.string)
|
3637
3583
|
],
|
3638
3584
|
[TYPES.bytestring]: [
|
3639
3585
|
// setup new/out array
|
3640
3586
|
...newOut,
|
3641
|
-
[ Opcodes.drop ],
|
3642
3587
|
|
3643
|
-
|
3588
|
+
// set length to 1
|
3589
|
+
...number(1, Valtype.i32),
|
3590
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3591
|
+
|
3592
|
+
// use as pointer for store later
|
3593
|
+
...newPointer,
|
3644
3594
|
|
3645
3595
|
...property,
|
3646
3596
|
Opcodes.i32_to_u,
|
3647
3597
|
|
3648
|
-
...
|
3649
|
-
|
3650
|
-
|
3651
|
-
[ Opcodes.i32_add ]
|
3652
|
-
]),
|
3598
|
+
...object,
|
3599
|
+
Opcodes.i32_to_u,
|
3600
|
+
[ Opcodes.i32_add ],
|
3653
3601
|
|
3654
3602
|
// load current string ind {arg}
|
3655
|
-
[ Opcodes.i32_load8_u, 0,
|
3603
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3656
3604
|
|
3657
3605
|
// store to new string ind 0
|
3658
|
-
[ Opcodes.i32_store8, 0,
|
3606
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3659
3607
|
|
3660
3608
|
// return new string (page)
|
3661
|
-
...
|
3609
|
+
...newPointer,
|
3610
|
+
Opcodes.i32_from_u,
|
3662
3611
|
...setLastType(scope, TYPES.bytestring)
|
3663
3612
|
],
|
3664
3613
|
|
@@ -3666,7 +3615,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3666
3615
|
});
|
3667
3616
|
};
|
3668
3617
|
|
3669
|
-
const randId = () => Math.random().toString(16).slice(
|
3618
|
+
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
3670
3619
|
|
3671
3620
|
const objectHack = node => {
|
3672
3621
|
if (!node) return node;
|
@@ -3718,7 +3667,7 @@ const generateFunc = (scope, decl) => {
|
|
3718
3667
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3719
3668
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3720
3669
|
|
3721
|
-
const name = decl.id ? decl.id.name : `
|
3670
|
+
const name = decl.id ? decl.id.name : `anonymous${randId()}`;
|
3722
3671
|
const params = decl.params ?? [];
|
3723
3672
|
|
3724
3673
|
// TODO: share scope/locals between !!!
|
@@ -3732,6 +3681,9 @@ const generateFunc = (scope, decl) => {
|
|
3732
3681
|
index: currentFuncIndex++
|
3733
3682
|
};
|
3734
3683
|
|
3684
|
+
funcIndex[name] = func.index;
|
3685
|
+
funcs.push(func);
|
3686
|
+
|
3735
3687
|
if (typedInput && decl.returnType) {
|
3736
3688
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3737
3689
|
// if (type != null && !Prefs.indirectCalls) {
|
@@ -3741,12 +3693,26 @@ const generateFunc = (scope, decl) => {
|
|
3741
3693
|
}
|
3742
3694
|
}
|
3743
3695
|
|
3696
|
+
const defaultValues = {};
|
3744
3697
|
for (let i = 0; i < params.length; i++) {
|
3745
|
-
|
3698
|
+
let name;
|
3699
|
+
const x = params[i];
|
3700
|
+
switch (x.type) {
|
3701
|
+
case 'Identifier': {
|
3702
|
+
name = x.name;
|
3703
|
+
break;
|
3704
|
+
}
|
3705
|
+
|
3706
|
+
case 'AssignmentPattern': {
|
3707
|
+
name = x.left.name;
|
3708
|
+
defaultValues[name] = x.right;
|
3709
|
+
break;
|
3710
|
+
}
|
3711
|
+
}
|
3712
|
+
|
3746
3713
|
// if (name == null) return todo('non-identifier args are not supported');
|
3747
3714
|
|
3748
3715
|
allocVar(func, name, false);
|
3749
|
-
|
3750
3716
|
if (typedInput && params[i].typeAnnotation) {
|
3751
3717
|
addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
|
3752
3718
|
}
|
@@ -3763,11 +3729,22 @@ const generateFunc = (scope, decl) => {
|
|
3763
3729
|
};
|
3764
3730
|
}
|
3765
3731
|
|
3766
|
-
|
3767
|
-
|
3732
|
+
const prelude = [];
|
3733
|
+
for (const x in defaultValues) {
|
3734
|
+
prelude.push(
|
3735
|
+
...getType(func, x),
|
3736
|
+
...number(TYPES.undefined, Valtype.i32),
|
3737
|
+
[ Opcodes.i32_eq ],
|
3738
|
+
[ Opcodes.if, Blocktype.void ],
|
3739
|
+
...generate(func, defaultValues[x], false, x),
|
3740
|
+
[ Opcodes.local_set, func.locals[x].idx ],
|
3768
3741
|
|
3769
|
-
|
3770
|
-
|
3742
|
+
...setType(func, x, getNodeType(scope, defaultValues[x])),
|
3743
|
+
[ Opcodes.end ]
|
3744
|
+
);
|
3745
|
+
}
|
3746
|
+
|
3747
|
+
const wasm = func.wasm = prelude.concat(generate(func, body));
|
3771
3748
|
|
3772
3749
|
if (name === 'main') func.gotLastType = true;
|
3773
3750
|
|
@@ -3803,9 +3780,9 @@ const internalConstrs = {
|
|
3803
3780
|
|
3804
3781
|
// new Array(n)
|
3805
3782
|
|
3806
|
-
const [ , pointer ] = makeArray(scope, {
|
3783
|
+
const [ out, pointer ] = makeArray(scope, {
|
3807
3784
|
rawElements: new Array(0)
|
3808
|
-
}, global, name, true);
|
3785
|
+
}, global, name, true, undefined, true);
|
3809
3786
|
|
3810
3787
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3811
3788
|
|
@@ -3814,12 +3791,13 @@ const internalConstrs = {
|
|
3814
3791
|
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
|
3815
3792
|
|
3816
3793
|
return [
|
3817
|
-
...
|
3794
|
+
...out,
|
3818
3795
|
...generate(scope, arg, global, name),
|
3819
3796
|
Opcodes.i32_to_u,
|
3820
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3797
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3821
3798
|
|
3822
|
-
...
|
3799
|
+
...pointer,
|
3800
|
+
Opcodes.i32_from_u
|
3823
3801
|
];
|
3824
3802
|
},
|
3825
3803
|
type: TYPES.array,
|
@@ -3968,8 +3946,9 @@ const internalConstrs = {
|
|
3968
3946
|
};
|
3969
3947
|
|
3970
3948
|
export default program => {
|
3971
|
-
globals = {
|
3972
|
-
|
3949
|
+
globals = {
|
3950
|
+
['#ind']: 0
|
3951
|
+
};
|
3973
3952
|
tags = [];
|
3974
3953
|
exceptions = [];
|
3975
3954
|
funcs = [];
|
@@ -3979,19 +3958,8 @@ export default program => {
|
|
3979
3958
|
data = [];
|
3980
3959
|
currentFuncIndex = importedFuncs.length;
|
3981
3960
|
|
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
3961
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3990
3962
|
|
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
3963
|
// set generic opcodes for current valtype
|
3996
3964
|
Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
|
3997
3965
|
Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
|
@@ -4013,6 +3981,7 @@ export default program => {
|
|
4013
3981
|
builtinFuncs = new BuiltinFuncs();
|
4014
3982
|
builtinVars = new BuiltinVars();
|
4015
3983
|
prototypeFuncs = new PrototypeFuncs();
|
3984
|
+
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
4016
3985
|
|
4017
3986
|
program.id = { name: 'main' };
|
4018
3987
|
|
@@ -4055,6 +4024,8 @@ export default program => {
|
|
4055
4024
|
else main.returns = [];
|
4056
4025
|
}
|
4057
4026
|
|
4027
|
+
delete globals['#ind'];
|
4028
|
+
|
4058
4029
|
// if blank main func and other exports, remove it
|
4059
4030
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4060
4031
|
|