porffor 0.16.0-fe07da0f4 → 0.17.0-05070e1f0
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 +146 -81
- package/compiler/allocators.js +128 -0
- package/compiler/assemble.js +12 -5
- package/compiler/builtins/array.ts +94 -5
- package/compiler/builtins/base64.ts +28 -24
- package/compiler/builtins/date.ts +3 -30
- package/compiler/builtins/math.ts +6 -2
- package/compiler/builtins/number.ts +10 -21
- package/compiler/builtins/porffor.d.ts +10 -0
- package/compiler/builtins/set.ts +9 -14
- package/compiler/builtins/string_f64.ts +10 -0
- package/compiler/builtins/typedarray.js +42 -0
- package/compiler/builtins/z_ecma262.ts +62 -0
- package/compiler/builtins.js +51 -6
- package/compiler/codegen.js +824 -409
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +3 -1
- package/compiler/generated_builtins.js +420 -162
- 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 +220 -0
- package/compiler/precompile.js +12 -7
- package/compiler/prefs.js +8 -4
- package/compiler/prototype.js +34 -43
- package/compiler/types.js +31 -5
- package/compiler/wasmSpec.js +4 -2
- package/compiler/wrap.js +120 -21
- package/package.json +3 -5
- package/rhemyn/README.md +7 -4
- package/rhemyn/compile.js +138 -66
- package/runner/debug.js +1 -1
- package/runner/index.js +31 -14
- package/runner/{profiler.js → profile.js} +1 -1
- package/runner/repl.js +16 -11
package/compiler/codegen.js
CHANGED
@@ -1,23 +1,24 @@
|
|
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';
|
6
6
|
import { number } from './embedding.js';
|
7
|
-
import { TYPES, TYPE_NAMES } from './types.js';
|
7
|
+
import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
|
8
8
|
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
|
|
@@ -76,6 +72,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
76
72
|
case 'ExpressionStatement':
|
77
73
|
return generateExp(scope, decl);
|
78
74
|
|
75
|
+
case 'SequenceExpression':
|
76
|
+
return generateSequence(scope, decl);
|
77
|
+
|
79
78
|
case 'CallExpression':
|
80
79
|
return generateCall(scope, decl, global, name, valueUnused);
|
81
80
|
|
@@ -181,12 +180,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
181
180
|
continue;
|
182
181
|
}
|
183
182
|
|
184
|
-
if (asm[0] === 'memory') {
|
185
|
-
allocPage(scope, 'asm instrinsic');
|
186
|
-
// todo: add to store/load offset insts
|
187
|
-
continue;
|
188
|
-
}
|
189
|
-
|
190
183
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
191
184
|
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
192
185
|
|
@@ -274,10 +267,12 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
|
|
274
267
|
argument: {
|
275
268
|
type: 'NewExpression',
|
276
269
|
callee: {
|
270
|
+
type: 'Identifier',
|
277
271
|
name: constructor
|
278
272
|
},
|
279
273
|
arguments: [
|
280
274
|
{
|
275
|
+
type: 'Literal',
|
281
276
|
value: message
|
282
277
|
}
|
283
278
|
]
|
@@ -299,12 +294,13 @@ const generateIdent = (scope, decl) => {
|
|
299
294
|
return wasm.slice();
|
300
295
|
}
|
301
296
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
297
|
+
// todo: enable this by default in future
|
298
|
+
// if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
299
|
+
// includeBuiltin(scope, name);
|
300
|
+
// return number(funcIndex[name] - importedFuncs.length);
|
301
|
+
// }
|
306
302
|
|
307
|
-
if (isExistingProtoFunc(name)) {
|
303
|
+
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
308
304
|
// todo: return an actual something
|
309
305
|
return number(1);
|
310
306
|
}
|
@@ -433,63 +429,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
433
429
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
434
430
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
435
431
|
|
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
432
|
const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
|
488
433
|
|
489
434
|
// alloc/assign array
|
490
|
-
const [ , pointer ] = makeArray(scope, {
|
435
|
+
const [ out, pointer ] = makeArray(scope, {
|
491
436
|
rawElements: new Array(0)
|
492
|
-
}, global, name, true, 'i16');
|
437
|
+
}, assign ? false : global, assign ? undefined : name, true, 'i16', true);
|
493
438
|
|
494
439
|
return [
|
495
440
|
// setup left
|
@@ -503,7 +448,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
503
448
|
[ Opcodes.local_set, rightPointer ],
|
504
449
|
|
505
450
|
// calculate length
|
506
|
-
...
|
451
|
+
...out,
|
507
452
|
|
508
453
|
[ Opcodes.local_get, leftPointer ],
|
509
454
|
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
@@ -516,11 +461,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
516
461
|
[ Opcodes.i32_add ],
|
517
462
|
|
518
463
|
// store length
|
519
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
464
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
520
465
|
|
521
466
|
// copy left
|
522
467
|
// dst = out pointer + length size
|
523
|
-
...
|
468
|
+
...pointer,
|
469
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
470
|
+
[ Opcodes.i32_add ],
|
524
471
|
|
525
472
|
// src = left pointer + length size
|
526
473
|
[ Opcodes.local_get, leftPointer ],
|
@@ -533,7 +480,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
533
480
|
|
534
481
|
// copy right
|
535
482
|
// dst = out pointer + length size + left length * sizeof valtype
|
536
|
-
...
|
483
|
+
...pointer,
|
484
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
485
|
+
[ Opcodes.i32_add ],
|
537
486
|
|
538
487
|
[ Opcodes.local_get, leftLength ],
|
539
488
|
...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
|
@@ -553,7 +502,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
553
502
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ],
|
554
503
|
|
555
504
|
// return new string (page)
|
556
|
-
...
|
505
|
+
...pointer,
|
506
|
+
Opcodes.i32_from_u
|
557
507
|
];
|
558
508
|
};
|
559
509
|
|
@@ -673,7 +623,10 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
673
623
|
...wasm,
|
674
624
|
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
675
625
|
];
|
676
|
-
|
626
|
+
if (isIntOp(wasm[wasm.length - 1])) return [
|
627
|
+
...wasm,
|
628
|
+
...(intOut ? [] : [ Opcodes.i32_from ]),
|
629
|
+
];
|
677
630
|
|
678
631
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
679
632
|
|
@@ -1014,12 +967,9 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1014
967
|
[ Opcodes.end ],
|
1015
968
|
]));
|
1016
969
|
|
1017
|
-
//
|
1018
|
-
|
1019
|
-
|
1020
|
-
// endOut.push(stringOnly([ Opcodes.end ]));
|
1021
|
-
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1022
|
-
// }
|
970
|
+
// add a surrounding block
|
971
|
+
startOut.push(stringOnly([ Opcodes.block, Valtype.i32 ]));
|
972
|
+
endOut.unshift(stringOnly([ Opcodes.end ]));
|
1023
973
|
}
|
1024
974
|
|
1025
975
|
return finalize([
|
@@ -1032,6 +982,33 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1032
982
|
};
|
1033
983
|
|
1034
984
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
985
|
+
if (decl.operator === 'instanceof') {
|
986
|
+
// very hacky basic instanceof
|
987
|
+
// todo: support dynamic right-hand side
|
988
|
+
|
989
|
+
const out = generate(scope, decl.left);
|
990
|
+
disposeLeftover(out);
|
991
|
+
|
992
|
+
const rightName = decl.right.name;
|
993
|
+
if (!rightName) return todo(scope, 'instanceof dynamic right-hand side is not supported yet', true);
|
994
|
+
|
995
|
+
const checkType = TYPES[rightName.toLowerCase()];
|
996
|
+
if (checkType == null || rightName !== TYPE_NAMES[checkType] || checkType === TYPES.undefined) return todo(scope, 'instanceof right-hand side type unsupported', true);
|
997
|
+
|
998
|
+
if ([TYPES.number, TYPES.boolean, TYPES.string, TYPES.symbol, TYPES.object].includes(checkType)) {
|
999
|
+
out.push(...number(0));
|
1000
|
+
} else {
|
1001
|
+
out.push(
|
1002
|
+
...getNodeType(scope, decl.left),
|
1003
|
+
...number(checkType, Valtype.i32),
|
1004
|
+
[ Opcodes.i32_eq ],
|
1005
|
+
Opcodes.i32_from_u
|
1006
|
+
);
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
return out;
|
1010
|
+
}
|
1011
|
+
|
1035
1012
|
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
1036
1013
|
|
1037
1014
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
@@ -1054,7 +1031,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1054
1031
|
});
|
1055
1032
|
};
|
1056
1033
|
|
1057
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1034
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1058
1035
|
const existing = funcs.find(x => x.name === name);
|
1059
1036
|
if (existing) return existing;
|
1060
1037
|
|
@@ -1068,7 +1045,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1068
1045
|
|
1069
1046
|
for (const x of _data) {
|
1070
1047
|
const copy = { ...x };
|
1071
|
-
copy.offset += pages.size * pageSize;
|
1048
|
+
if (copy.offset != null) copy.offset += pages.size * pageSize;
|
1072
1049
|
data.push(copy);
|
1073
1050
|
}
|
1074
1051
|
|
@@ -1078,7 +1055,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1078
1055
|
locals,
|
1079
1056
|
localInd: allLocals.length,
|
1080
1057
|
returns,
|
1081
|
-
returnType
|
1058
|
+
returnType,
|
1082
1059
|
internal: true,
|
1083
1060
|
index: currentFuncIndex++,
|
1084
1061
|
table
|
@@ -1091,9 +1068,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1091
1068
|
|
1092
1069
|
let baseGlobalIdx, i = 0;
|
1093
1070
|
for (const type of globalTypes) {
|
1094
|
-
if (baseGlobalIdx === undefined) baseGlobalIdx =
|
1071
|
+
if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
|
1095
1072
|
|
1096
|
-
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx:
|
1073
|
+
globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
|
1097
1074
|
i++;
|
1098
1075
|
}
|
1099
1076
|
|
@@ -1106,11 +1083,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1106
1083
|
}
|
1107
1084
|
}
|
1108
1085
|
|
1109
|
-
if (table)
|
1110
|
-
|
1111
|
-
inst.
|
1112
|
-
|
1086
|
+
if (table) {
|
1087
|
+
for (const inst of wasm) {
|
1088
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1089
|
+
inst.splice(2, 99);
|
1090
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1091
|
+
}
|
1113
1092
|
}
|
1093
|
+
|
1094
|
+
funcs.table = true;
|
1114
1095
|
}
|
1115
1096
|
|
1116
1097
|
func.wasm = wasm;
|
@@ -1254,7 +1235,7 @@ const getNodeType = (scope, node) => {
|
|
1254
1235
|
const func = funcs.find(x => x.name === name);
|
1255
1236
|
|
1256
1237
|
if (func) {
|
1257
|
-
if (func.returnType) return func.returnType;
|
1238
|
+
if (func.returnType != null) return func.returnType;
|
1258
1239
|
}
|
1259
1240
|
|
1260
1241
|
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
|
@@ -1270,15 +1251,7 @@ const getNodeType = (scope, node) => {
|
|
1270
1251
|
const func = spl[spl.length - 1];
|
1271
1252
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1272
1253
|
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;
|
1254
|
+
if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
|
1282
1255
|
}
|
1283
1256
|
}
|
1284
1257
|
|
@@ -1326,7 +1299,15 @@ const getNodeType = (scope, node) => {
|
|
1326
1299
|
}
|
1327
1300
|
|
1328
1301
|
if (node.type === 'AssignmentExpression') {
|
1329
|
-
|
1302
|
+
const op = node.operator.slice(0, -1) || '=';
|
1303
|
+
if (op === '=') return getNodeType(scope, node.right);
|
1304
|
+
|
1305
|
+
return getNodeType(scope, {
|
1306
|
+
type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
|
1307
|
+
left: node.left,
|
1308
|
+
right: node.right,
|
1309
|
+
operator: op
|
1310
|
+
});
|
1330
1311
|
}
|
1331
1312
|
|
1332
1313
|
if (node.type === 'ArrayExpression') {
|
@@ -1334,7 +1315,7 @@ const getNodeType = (scope, node) => {
|
|
1334
1315
|
}
|
1335
1316
|
|
1336
1317
|
if (node.type === 'BinaryExpression') {
|
1337
|
-
if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
|
1318
|
+
if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof'].includes(node.operator)) return TYPES.boolean;
|
1338
1319
|
if (node.operator !== '+') return TYPES.number;
|
1339
1320
|
|
1340
1321
|
const knownLeft = knownType(scope, getNodeType(scope, node.left));
|
@@ -1345,23 +1326,6 @@ const getNodeType = (scope, node) => {
|
|
1345
1326
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1346
1327
|
|
1347
1328
|
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
1329
|
}
|
1366
1330
|
|
1367
1331
|
if (node.type === 'UnaryExpression') {
|
@@ -1381,18 +1345,16 @@ const getNodeType = (scope, node) => {
|
|
1381
1345
|
if (Prefs.fastLength) return TYPES.number;
|
1382
1346
|
}
|
1383
1347
|
|
1384
|
-
|
1385
1348
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1386
1349
|
if (objectKnownType != null) {
|
1387
1350
|
if (name === 'length') {
|
1388
|
-
if (
|
1351
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1389
1352
|
else return TYPES.undefined;
|
1390
1353
|
}
|
1391
1354
|
|
1392
1355
|
if (node.computed) {
|
1393
1356
|
if (objectKnownType === TYPES.string) return TYPES.string;
|
1394
1357
|
if (objectKnownType === TYPES.bytestring) return TYPES.bytestring;
|
1395
|
-
if (objectKnownType === TYPES.array) return TYPES.number;
|
1396
1358
|
}
|
1397
1359
|
}
|
1398
1360
|
|
@@ -1458,10 +1420,10 @@ const countLeftover = wasm => {
|
|
1458
1420
|
|
1459
1421
|
if (depth === 0)
|
1460
1422
|
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] <
|
1423
|
+
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.f32_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
1424
|
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
|
-
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]
|
1425
|
+
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1426
|
+
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1465
1427
|
else if (inst[0] === Opcodes.return) count = 0;
|
1466
1428
|
else if (inst[0] === Opcodes.call) {
|
1467
1429
|
let func = funcs.find(x => x.index === inst[1]);
|
@@ -1498,6 +1460,18 @@ const generateExp = (scope, decl) => {
|
|
1498
1460
|
return out;
|
1499
1461
|
};
|
1500
1462
|
|
1463
|
+
const generateSequence = (scope, decl) => {
|
1464
|
+
let out = [];
|
1465
|
+
|
1466
|
+
const exprs = decl.expressions;
|
1467
|
+
for (let i = 0; i < exprs.length; i++) {
|
1468
|
+
if (i > 0) disposeLeftover(out);
|
1469
|
+
out.push(...generate(scope, exprs[i]));
|
1470
|
+
}
|
1471
|
+
|
1472
|
+
return out;
|
1473
|
+
};
|
1474
|
+
|
1501
1475
|
const CTArrayUtil = {
|
1502
1476
|
getLengthI32: pointer => [
|
1503
1477
|
...number(0, Valtype.i32),
|
@@ -1733,7 +1707,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1733
1707
|
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1734
1708
|
return makeArray(scope, {
|
1735
1709
|
rawElements: new Array(length)
|
1736
|
-
}, _global, _name, true, itemType);
|
1710
|
+
}, _global, _name, true, itemType, true);
|
1737
1711
|
}, () => {
|
1738
1712
|
optUnused = true;
|
1739
1713
|
return unusedValue;
|
@@ -1815,7 +1789,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1815
1789
|
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1816
1790
|
|
1817
1791
|
// value
|
1818
|
-
i32_const: { imms: 1, args: [], returns:
|
1792
|
+
i32_const: { imms: 1, args: [], returns: 0 },
|
1819
1793
|
};
|
1820
1794
|
|
1821
1795
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1900,7 +1874,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1900
1874
|
if (indirectMode === 'strict') {
|
1901
1875
|
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
1902
1876
|
[TYPES.function]: [
|
1903
|
-
...
|
1877
|
+
...out,
|
1904
1878
|
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1905
1879
|
Opcodes.i32_to_u,
|
1906
1880
|
[ Opcodes.call_indirect, args.length, 0 ],
|
@@ -1978,7 +1952,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
1952
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1979
1953
|
const userFunc = func && !func.internal;
|
1980
1954
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1981
|
-
const typedReturns = (
|
1955
|
+
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1982
1956
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1983
1957
|
|
1984
1958
|
let args = decl.arguments;
|
@@ -2006,13 +1980,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2006
1980
|
continue;
|
2007
1981
|
}
|
2008
1982
|
|
2009
|
-
if (valtypeBinary !== Valtype.i32 &&
|
2010
|
-
(
|
2011
|
-
|
2012
|
-
)) {
|
1983
|
+
if (valtypeBinary !== Valtype.i32 &&
|
1984
|
+
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1985
|
+
) {
|
2013
1986
|
out.push(Opcodes.i32_to);
|
2014
1987
|
}
|
2015
1988
|
|
1989
|
+
if (valtypeBinary === Valtype.i32 &&
|
1990
|
+
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1991
|
+
) {
|
1992
|
+
out.push([ Opcodes.f64_convert_i32_s ]);
|
1993
|
+
}
|
1994
|
+
|
2016
1995
|
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
2017
1996
|
}
|
2018
1997
|
|
@@ -2034,6 +2013,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2034
2013
|
out.push(Opcodes.i32_from);
|
2035
2014
|
}
|
2036
2015
|
|
2016
|
+
if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32) {
|
2017
|
+
out.push(Opcodes.i32_trunc_sat_f64_s);
|
2018
|
+
}
|
2019
|
+
|
2037
2020
|
return out;
|
2038
2021
|
};
|
2039
2022
|
|
@@ -2057,9 +2040,9 @@ const generateNew = (scope, decl, _global, _name) => {
|
|
2057
2040
|
if (
|
2058
2041
|
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2059
2042
|
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2060
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor
|
2043
|
+
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2061
2044
|
|
2062
|
-
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet
|
2045
|
+
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
2046
|
|
2064
2047
|
return generateCall(scope, decl, _global, _name);
|
2065
2048
|
};
|
@@ -2077,7 +2060,7 @@ const unhackName = name => {
|
|
2077
2060
|
|
2078
2061
|
const knownType = (scope, type) => {
|
2079
2062
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2080
|
-
return type[0]
|
2063
|
+
return read_signedLEB128(type[0].slice(1));
|
2081
2064
|
}
|
2082
2065
|
|
2083
2066
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2123,7 +2106,6 @@ const brTable = (input, bc, returns) => {
|
|
2123
2106
|
}
|
2124
2107
|
|
2125
2108
|
for (let i = 0; i < count; i++) {
|
2126
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2127
2109
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2128
2110
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2129
2111
|
}
|
@@ -2157,10 +2139,8 @@ const brTable = (input, bc, returns) => {
|
|
2157
2139
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2158
2140
|
);
|
2159
2141
|
|
2160
|
-
//
|
2161
|
-
// (
|
2162
|
-
// dm me and if you are correct and the first person
|
2163
|
-
// I will somehow shout you out or something
|
2142
|
+
// sort the wrong way and then reverse
|
2143
|
+
// so strings ('default') are at the start before any numbers
|
2164
2144
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2165
2145
|
|
2166
2146
|
br = count - 1;
|
@@ -2186,10 +2166,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2186
2166
|
return bc[known] ?? bc.default;
|
2187
2167
|
}
|
2188
2168
|
|
2189
|
-
if (Prefs.
|
2169
|
+
if (Prefs.typeswitchBrtable)
|
2190
2170
|
return brTable(type, bc, returns);
|
2191
2171
|
|
2192
|
-
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
2172
|
+
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
2193
2173
|
const out = [
|
2194
2174
|
...type,
|
2195
2175
|
[ Opcodes.local_set, tmp ],
|
@@ -2241,11 +2221,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2241
2221
|
return target[name].idx;
|
2242
2222
|
}
|
2243
2223
|
|
2244
|
-
let idx = global ?
|
2224
|
+
let idx = global ? globals['#ind']++ : scope.localInd++;
|
2245
2225
|
target[name] = { idx, type: valtypeBinary };
|
2246
2226
|
|
2247
2227
|
if (type) {
|
2248
|
-
let typeIdx = global ?
|
2228
|
+
let typeIdx = global ? globals['#ind']++ : scope.localInd++;
|
2249
2229
|
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2250
2230
|
}
|
2251
2231
|
|
@@ -2338,24 +2318,10 @@ const generateVar = (scope, decl) => {
|
|
2338
2318
|
}
|
2339
2319
|
|
2340
2320
|
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
|
-
// }
|
2321
|
+
const alreadyArray = scope.arrays?.get(name) != null;
|
2356
2322
|
|
2357
2323
|
const generated = generate(scope, x.init, global, name);
|
2358
|
-
if (scope.arrays?.get(name) != null) {
|
2324
|
+
if (!alreadyArray && scope.arrays?.get(name) != null) {
|
2359
2325
|
// hack to set local as pointer before
|
2360
2326
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2361
2327
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
@@ -2381,11 +2347,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2381
2347
|
const { type, name } = decl.left;
|
2382
2348
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2383
2349
|
|
2384
|
-
if (type === 'ObjectPattern') {
|
2385
|
-
// hack: ignore object parts of `var a = {} = 2`
|
2386
|
-
return generate(scope, decl.right);
|
2387
|
-
}
|
2388
|
-
|
2389
2350
|
if (isFuncType(decl.right.type)) {
|
2390
2351
|
// hack for a = function () { ... }
|
2391
2352
|
decl.right.id = { name };
|
@@ -2407,19 +2368,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2407
2368
|
|
2408
2369
|
// hack: .length setter
|
2409
2370
|
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
2371
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2416
2372
|
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2417
2373
|
|
2418
2374
|
return [
|
2419
|
-
...(
|
2420
|
-
|
2421
|
-
Opcodes.i32_to_u
|
2422
|
-
]),
|
2375
|
+
...generate(scope, decl.left.object),
|
2376
|
+
Opcodes.i32_to_u,
|
2423
2377
|
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2424
2378
|
|
2425
2379
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
@@ -2430,7 +2384,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2430
2384
|
[ Opcodes.local_tee, newValueTmp ],
|
2431
2385
|
|
2432
2386
|
Opcodes.i32_to_u,
|
2433
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
2387
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2434
2388
|
|
2435
2389
|
[ Opcodes.local_get, newValueTmp ]
|
2436
2390
|
];
|
@@ -2438,21 +2392,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2438
2392
|
|
2439
2393
|
// arr[i]
|
2440
2394
|
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
2395
|
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
2447
2396
|
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2448
2397
|
|
2449
2398
|
return [
|
2450
2399
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2451
2400
|
[TYPES.array]: [
|
2452
|
-
...(
|
2453
|
-
|
2454
|
-
Opcodes.i32_to_u
|
2455
|
-
]),
|
2401
|
+
...generate(scope, decl.left.object),
|
2402
|
+
Opcodes.i32_to_u,
|
2456
2403
|
|
2457
2404
|
// get index as valtype
|
2458
2405
|
...generate(scope, decl.left.property),
|
@@ -2461,39 +2408,172 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2461
2408
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2462
2409
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2463
2410
|
[ Opcodes.i32_mul ],
|
2464
|
-
|
2411
|
+
[ Opcodes.i32_add ],
|
2465
2412
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2466
2413
|
|
2467
2414
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2468
2415
|
[ Opcodes.local_get, pointerTmp ],
|
2469
|
-
[ Opcodes.load, 0,
|
2416
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ]
|
2470
2417
|
], generate(scope, decl.right), [
|
2471
2418
|
[ Opcodes.local_get, pointerTmp ],
|
2472
|
-
[ Opcodes.i32_load8_u, 0,
|
2419
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2473
2420
|
], getNodeType(scope, decl.right), false, name, true)),
|
2474
2421
|
[ Opcodes.local_tee, newValueTmp ],
|
2475
|
-
|
2476
|
-
[ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2422
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2477
2423
|
],
|
2478
2424
|
|
2479
|
-
|
2425
|
+
...wrapBC({
|
2426
|
+
[TYPES.uint8array]: [
|
2427
|
+
[ Opcodes.i32_add ],
|
2428
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2429
|
+
|
2430
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2431
|
+
[ Opcodes.local_get, pointerTmp ],
|
2432
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2433
|
+
Opcodes.i32_from_u
|
2434
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2435
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2436
|
+
|
2437
|
+
Opcodes.i32_to_u,
|
2438
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2439
|
+
],
|
2440
|
+
[TYPES.uint8clampedarray]: [
|
2441
|
+
[ Opcodes.i32_add ],
|
2442
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2443
|
+
|
2444
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2445
|
+
[ Opcodes.local_get, pointerTmp ],
|
2446
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2447
|
+
Opcodes.i32_from_u
|
2448
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2449
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2450
|
+
|
2451
|
+
...number(0),
|
2452
|
+
[ Opcodes.f64_max ],
|
2453
|
+
...number(255),
|
2454
|
+
[ Opcodes.f64_min ],
|
2455
|
+
Opcodes.i32_to_u,
|
2456
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2457
|
+
],
|
2458
|
+
[TYPES.int8array]: [
|
2459
|
+
[ Opcodes.i32_add ],
|
2460
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2461
|
+
|
2462
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2463
|
+
[ Opcodes.local_get, pointerTmp ],
|
2464
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2465
|
+
Opcodes.i32_from
|
2466
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2467
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2468
|
+
|
2469
|
+
Opcodes.i32_to,
|
2470
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2471
|
+
],
|
2472
|
+
[TYPES.uint16array]: [
|
2473
|
+
...number(2, Valtype.i32),
|
2474
|
+
[ Opcodes.i32_mul ],
|
2475
|
+
[ Opcodes.i32_add ],
|
2476
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2477
|
+
|
2478
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2479
|
+
[ Opcodes.local_get, pointerTmp ],
|
2480
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2481
|
+
Opcodes.i32_from_u
|
2482
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2483
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2484
|
+
|
2485
|
+
Opcodes.i32_to_u,
|
2486
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2487
|
+
],
|
2488
|
+
[TYPES.int16array]: [
|
2489
|
+
...number(2, Valtype.i32),
|
2490
|
+
[ Opcodes.i32_mul ],
|
2491
|
+
[ Opcodes.i32_add ],
|
2492
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2493
|
+
|
2494
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2495
|
+
[ Opcodes.local_get, pointerTmp ],
|
2496
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2497
|
+
Opcodes.i32_from
|
2498
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2499
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2500
|
+
|
2501
|
+
Opcodes.i32_to,
|
2502
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2503
|
+
],
|
2504
|
+
[TYPES.uint32array]: [
|
2505
|
+
...number(4, Valtype.i32),
|
2506
|
+
[ Opcodes.i32_mul ],
|
2507
|
+
[ Opcodes.i32_add ],
|
2508
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2509
|
+
|
2510
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2511
|
+
[ Opcodes.local_get, pointerTmp ],
|
2512
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2513
|
+
Opcodes.i32_from_u
|
2514
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2515
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2516
|
+
|
2517
|
+
Opcodes.i32_to_u,
|
2518
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2519
|
+
],
|
2520
|
+
[TYPES.int32array]: [
|
2521
|
+
...number(4, Valtype.i32),
|
2522
|
+
[ Opcodes.i32_mul ],
|
2523
|
+
[ Opcodes.i32_add ],
|
2524
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2525
|
+
|
2526
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2527
|
+
[ Opcodes.local_get, pointerTmp ],
|
2528
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2529
|
+
Opcodes.i32_from
|
2530
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2531
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2532
|
+
|
2533
|
+
Opcodes.i32_to,
|
2534
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2535
|
+
],
|
2536
|
+
[TYPES.float32array]: [
|
2537
|
+
...number(4, Valtype.i32),
|
2538
|
+
[ Opcodes.i32_mul ],
|
2539
|
+
[ Opcodes.i32_add ],
|
2540
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2541
|
+
|
2542
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2543
|
+
[ Opcodes.local_get, pointerTmp ],
|
2544
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2545
|
+
[ Opcodes.f64_promote_f32 ]
|
2546
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2547
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2548
|
+
|
2549
|
+
[ Opcodes.f32_demote_f64 ],
|
2550
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2551
|
+
],
|
2552
|
+
[TYPES.float64array]: [
|
2553
|
+
...number(8, Valtype.i32),
|
2554
|
+
[ Opcodes.i32_mul ],
|
2555
|
+
[ Opcodes.i32_add ],
|
2556
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2557
|
+
|
2558
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2559
|
+
[ Opcodes.local_get, pointerTmp ],
|
2560
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2561
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2562
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2563
|
+
|
2564
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2565
|
+
],
|
2566
|
+
}, {
|
2567
|
+
prelude: [
|
2568
|
+
...generate(scope, decl.left.object),
|
2569
|
+
Opcodes.i32_to_u,
|
2570
|
+
...generate(scope, decl.left.property),
|
2571
|
+
Opcodes.i32_to_u,
|
2572
|
+
],
|
2573
|
+
postlude: setLastType(scope, TYPES.number)
|
2574
|
+
}),
|
2480
2575
|
|
2481
|
-
|
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
|
-
// ]
|
2576
|
+
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2497
2577
|
}, Blocktype.void),
|
2498
2578
|
|
2499
2579
|
[ Opcodes.local_get, newValueTmp ]
|
@@ -2555,9 +2635,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2555
2635
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2556
2636
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2557
2637
|
|
2558
|
-
|
2559
|
-
|
2560
|
-
...setType(scope, name, TYPES.number)
|
2638
|
+
...setType(scope, name, getNodeType(scope, decl))
|
2561
2639
|
];
|
2562
2640
|
};
|
2563
2641
|
|
@@ -2571,7 +2649,7 @@ const generateUnary = (scope, decl) => {
|
|
2571
2649
|
// * -1
|
2572
2650
|
|
2573
2651
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
2574
|
-
// if
|
2652
|
+
// if -n, just return that as a const
|
2575
2653
|
return number(-1 * decl.argument.value);
|
2576
2654
|
}
|
2577
2655
|
|
@@ -2583,14 +2661,14 @@ const generateUnary = (scope, decl) => {
|
|
2583
2661
|
case '!':
|
2584
2662
|
const arg = decl.argument;
|
2585
2663
|
if (arg.type === 'UnaryExpression' && arg.operator === '!') {
|
2586
|
-
// !!x -> is x truthy
|
2664
|
+
// opt: !!x -> is x truthy
|
2587
2665
|
return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
|
2588
2666
|
}
|
2667
|
+
|
2589
2668
|
// !=
|
2590
|
-
return falsy(scope, generate(scope,
|
2669
|
+
return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
|
2591
2670
|
|
2592
2671
|
case '~':
|
2593
|
-
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
2594
2672
|
return [
|
2595
2673
|
...generate(scope, decl.argument),
|
2596
2674
|
Opcodes.i32_to,
|
@@ -2877,12 +2955,14 @@ const generateForOf = (scope, decl) => {
|
|
2877
2955
|
|
2878
2956
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2879
2957
|
// hack: this is naughty and will break things!
|
2880
|
-
let newOut = number(0, Valtype.
|
2881
|
-
|
2958
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2959
|
+
|
2960
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
2961
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2882
2962
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2883
2963
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2884
|
-
rawElements: new Array(
|
2885
|
-
}, isGlobal, leftName, true, 'i16');
|
2964
|
+
rawElements: new Array(0)
|
2965
|
+
}, isGlobal, leftName, true, 'i16', true);
|
2886
2966
|
}
|
2887
2967
|
|
2888
2968
|
// set type for local
|
@@ -2926,26 +3006,32 @@ const generateForOf = (scope, decl) => {
|
|
2926
3006
|
[ Opcodes.end ],
|
2927
3007
|
[ Opcodes.end ]
|
2928
3008
|
],
|
3009
|
+
|
2929
3010
|
[TYPES.string]: [
|
2930
3011
|
...setType(scope, leftName, TYPES.string),
|
2931
3012
|
|
2932
|
-
[ Opcodes.loop, Blocktype.void ],
|
2933
|
-
|
2934
3013
|
// setup new/out array
|
2935
3014
|
...newOut,
|
2936
|
-
[ Opcodes.drop ],
|
2937
3015
|
|
2938
|
-
|
3016
|
+
// set length to 1
|
3017
|
+
...number(1, Valtype.i32),
|
3018
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3019
|
+
|
3020
|
+
[ Opcodes.loop, Blocktype.void ],
|
3021
|
+
|
3022
|
+
// use as pointer for store later
|
3023
|
+
...newPointer,
|
2939
3024
|
|
2940
3025
|
// load current string ind {arg}
|
2941
3026
|
[ Opcodes.local_get, pointer ],
|
2942
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3027
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2943
3028
|
|
2944
3029
|
// store to new string ind 0
|
2945
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3030
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
2946
3031
|
|
2947
3032
|
// return new string (page)
|
2948
|
-
...
|
3033
|
+
...newPointer,
|
3034
|
+
Opcodes.i32_from_u,
|
2949
3035
|
|
2950
3036
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2951
3037
|
|
@@ -2977,25 +3063,30 @@ const generateForOf = (scope, decl) => {
|
|
2977
3063
|
[TYPES.bytestring]: [
|
2978
3064
|
...setType(scope, leftName, TYPES.bytestring),
|
2979
3065
|
|
2980
|
-
[ Opcodes.loop, Blocktype.void ],
|
2981
|
-
|
2982
3066
|
// setup new/out array
|
2983
3067
|
...newOut,
|
2984
|
-
[ Opcodes.drop ],
|
2985
3068
|
|
2986
|
-
|
3069
|
+
// set length to 1
|
3070
|
+
...number(1, Valtype.i32),
|
3071
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3072
|
+
|
3073
|
+
[ Opcodes.loop, Blocktype.void ],
|
3074
|
+
|
3075
|
+
// use as pointer for store later
|
3076
|
+
...newPointer,
|
2987
3077
|
|
2988
3078
|
// load current string ind {arg}
|
2989
3079
|
[ Opcodes.local_get, pointer ],
|
2990
3080
|
[ Opcodes.local_get, counter ],
|
2991
3081
|
[ Opcodes.i32_add ],
|
2992
|
-
[ Opcodes.i32_load8_u, 0,
|
3082
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
2993
3083
|
|
2994
3084
|
// store to new string ind 0
|
2995
|
-
[ Opcodes.i32_store8, 0,
|
3085
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
2996
3086
|
|
2997
3087
|
// return new string (page)
|
2998
|
-
...
|
3088
|
+
...newPointer,
|
3089
|
+
Opcodes.i32_from_u,
|
2999
3090
|
|
3000
3091
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3001
3092
|
|
@@ -3024,6 +3115,7 @@ const generateForOf = (scope, decl) => {
|
|
3024
3115
|
[ Opcodes.end ],
|
3025
3116
|
[ Opcodes.end ]
|
3026
3117
|
],
|
3118
|
+
|
3027
3119
|
[TYPES.set]: [
|
3028
3120
|
[ Opcodes.loop, Blocktype.void ],
|
3029
3121
|
|
@@ -3062,6 +3154,106 @@ const generateForOf = (scope, decl) => {
|
|
3062
3154
|
[ Opcodes.end ],
|
3063
3155
|
[ Opcodes.end ]
|
3064
3156
|
],
|
3157
|
+
|
3158
|
+
...wrapBC({
|
3159
|
+
[TYPES.uint8array]: [
|
3160
|
+
[ Opcodes.i32_add ],
|
3161
|
+
|
3162
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3163
|
+
Opcodes.i32_from_u
|
3164
|
+
],
|
3165
|
+
[TYPES.uint8clampedarray]: [
|
3166
|
+
[ Opcodes.i32_add ],
|
3167
|
+
|
3168
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3169
|
+
Opcodes.i32_from_u
|
3170
|
+
],
|
3171
|
+
[TYPES.int8array]: [
|
3172
|
+
[ Opcodes.i32_add ],
|
3173
|
+
|
3174
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3175
|
+
Opcodes.i32_from
|
3176
|
+
],
|
3177
|
+
[TYPES.uint16array]: [
|
3178
|
+
...number(2, Valtype.i32),
|
3179
|
+
[ Opcodes.i32_mul ],
|
3180
|
+
[ Opcodes.i32_add ],
|
3181
|
+
|
3182
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3183
|
+
Opcodes.i32_from_u
|
3184
|
+
],
|
3185
|
+
[TYPES.int16array]: [
|
3186
|
+
...number(2, Valtype.i32),
|
3187
|
+
[ Opcodes.i32_mul ],
|
3188
|
+
[ Opcodes.i32_add ],
|
3189
|
+
|
3190
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3191
|
+
Opcodes.i32_from
|
3192
|
+
],
|
3193
|
+
[TYPES.uint32array]: [
|
3194
|
+
...number(4, Valtype.i32),
|
3195
|
+
[ Opcodes.i32_mul ],
|
3196
|
+
[ Opcodes.i32_add ],
|
3197
|
+
|
3198
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3199
|
+
Opcodes.i32_from_u
|
3200
|
+
],
|
3201
|
+
[TYPES.int32array]: [
|
3202
|
+
...number(4, Valtype.i32),
|
3203
|
+
[ Opcodes.i32_mul ],
|
3204
|
+
[ Opcodes.i32_add ],
|
3205
|
+
|
3206
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3207
|
+
Opcodes.i32_from
|
3208
|
+
],
|
3209
|
+
[TYPES.float32array]: [
|
3210
|
+
...number(4, Valtype.i32),
|
3211
|
+
[ Opcodes.i32_mul ],
|
3212
|
+
[ Opcodes.i32_add ],
|
3213
|
+
|
3214
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3215
|
+
[ Opcodes.f64_promote_f32 ]
|
3216
|
+
],
|
3217
|
+
[TYPES.float64array]: [
|
3218
|
+
...number(8, Valtype.i32),
|
3219
|
+
[ Opcodes.i32_mul ],
|
3220
|
+
[ Opcodes.i32_add ],
|
3221
|
+
|
3222
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3223
|
+
],
|
3224
|
+
}, {
|
3225
|
+
prelude: [
|
3226
|
+
...setType(scope, leftName, TYPES.number),
|
3227
|
+
|
3228
|
+
[ Opcodes.loop, Blocktype.void ],
|
3229
|
+
|
3230
|
+
[ Opcodes.local_get, pointer ],
|
3231
|
+
[ Opcodes.local_get, counter ]
|
3232
|
+
],
|
3233
|
+
postlude: [
|
3234
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3235
|
+
|
3236
|
+
[ Opcodes.block, Blocktype.void ],
|
3237
|
+
[ Opcodes.block, Blocktype.void ],
|
3238
|
+
...generate(scope, decl.body),
|
3239
|
+
[ Opcodes.end ],
|
3240
|
+
|
3241
|
+
// increment counter by 1
|
3242
|
+
[ Opcodes.local_get, counter ],
|
3243
|
+
...number(1, Valtype.i32),
|
3244
|
+
[ Opcodes.i32_add ],
|
3245
|
+
[ Opcodes.local_tee, counter ],
|
3246
|
+
|
3247
|
+
// loop if counter != length
|
3248
|
+
[ Opcodes.local_get, length ],
|
3249
|
+
[ Opcodes.i32_ne ],
|
3250
|
+
[ Opcodes.br_if, 1 ],
|
3251
|
+
|
3252
|
+
[ Opcodes.end ],
|
3253
|
+
[ Opcodes.end ]
|
3254
|
+
]
|
3255
|
+
}),
|
3256
|
+
|
3065
3257
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
3066
3258
|
}, Blocktype.void));
|
3067
3259
|
|
@@ -3134,32 +3326,102 @@ const generateLabel = (scope, decl) => {
|
|
3134
3326
|
const generateThrow = (scope, decl) => {
|
3135
3327
|
scope.throws = true;
|
3136
3328
|
|
3137
|
-
|
3329
|
+
const exceptionMode = Prefs.exceptionMode ?? 'lut';
|
3330
|
+
if (exceptionMode === 'lut') {
|
3331
|
+
let message = decl.argument.value, constructor = null;
|
3332
|
+
|
3333
|
+
// support `throw (new)? Error(...)`
|
3334
|
+
if (!message && (decl.argument.type === 'NewExpression' || decl.argument.type === 'CallExpression')) {
|
3335
|
+
constructor = decl.argument.callee.name;
|
3336
|
+
message = decl.argument.arguments[0]?.value ?? '';
|
3337
|
+
}
|
3338
|
+
|
3339
|
+
if (tags.length === 0) tags.push({
|
3340
|
+
params: [ Valtype.i32 ],
|
3341
|
+
results: [],
|
3342
|
+
idx: tags.length
|
3343
|
+
});
|
3344
|
+
|
3345
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3346
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3347
|
+
|
3348
|
+
scope.exceptions ??= [];
|
3349
|
+
scope.exceptions.push(exceptId);
|
3138
3350
|
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
|
3351
|
+
return [
|
3352
|
+
...number(exceptId, Valtype.i32),
|
3353
|
+
[ Opcodes.throw, tags[0].idx ]
|
3354
|
+
];
|
3143
3355
|
}
|
3144
3356
|
|
3145
|
-
if (
|
3146
|
-
|
3147
|
-
|
3148
|
-
|
3149
|
-
|
3357
|
+
if (exceptionMode === 'stack') {
|
3358
|
+
if (tags.length === 0) tags.push({
|
3359
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
3360
|
+
results: [],
|
3361
|
+
idx: tags.length
|
3362
|
+
});
|
3150
3363
|
|
3151
|
-
|
3152
|
-
|
3364
|
+
return [
|
3365
|
+
...generate(scope, decl.argument),
|
3366
|
+
...getNodeType(scope, decl.argument),
|
3367
|
+
[ Opcodes.throw, tags[0].idx ]
|
3368
|
+
];
|
3369
|
+
}
|
3153
3370
|
|
3154
|
-
|
3155
|
-
|
3371
|
+
if (exceptionMode === 'stackest') {
|
3372
|
+
let message = decl.argument, constructor = null;
|
3156
3373
|
|
3157
|
-
|
3374
|
+
// support `throw (new)? Error(...)`
|
3375
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3376
|
+
constructor = decl.argument.callee;
|
3377
|
+
message = decl.argument.arguments[0];
|
3378
|
+
}
|
3158
3379
|
|
3159
|
-
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3380
|
+
message ??= DEFAULT_VALUE;
|
3381
|
+
|
3382
|
+
if (tags.length === 0) tags.push({
|
3383
|
+
params: [ valtypeBinary, valtypeBinary, Valtype.i32 ],
|
3384
|
+
results: [],
|
3385
|
+
idx: tags.length
|
3386
|
+
});
|
3387
|
+
|
3388
|
+
return [
|
3389
|
+
...(constructor == null ? number(-1) : generate(scope, constructor)),
|
3390
|
+
...generate(scope, message),
|
3391
|
+
...getNodeType(scope, message),
|
3392
|
+
[ Opcodes.throw, tags[0].idx ]
|
3393
|
+
];
|
3394
|
+
}
|
3395
|
+
|
3396
|
+
if (exceptionMode === 'partial') {
|
3397
|
+
let message = decl.argument, constructor = null;
|
3398
|
+
|
3399
|
+
// support `throw (new)? Error(...)`
|
3400
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3401
|
+
constructor = decl.argument.callee.name;
|
3402
|
+
message = decl.argument.arguments[0];
|
3403
|
+
}
|
3404
|
+
|
3405
|
+
message ??= DEFAULT_VALUE;
|
3406
|
+
|
3407
|
+
if (tags.length === 0) tags.push({
|
3408
|
+
params: [ Valtype.i32, valtypeBinary, Valtype.i32 ],
|
3409
|
+
results: [],
|
3410
|
+
idx: tags.length
|
3411
|
+
});
|
3412
|
+
|
3413
|
+
let exceptId = exceptions.push({ constructor }) - 1;
|
3414
|
+
|
3415
|
+
scope.exceptions ??= [];
|
3416
|
+
scope.exceptions.push(exceptId);
|
3417
|
+
|
3418
|
+
return [
|
3419
|
+
...number(exceptId, Valtype.i32),
|
3420
|
+
...generate(scope, message),
|
3421
|
+
...getNodeType(scope, message),
|
3422
|
+
[ Opcodes.throw, tags[0].idx ]
|
3423
|
+
];
|
3424
|
+
}
|
3163
3425
|
};
|
3164
3426
|
|
3165
3427
|
const generateTry = (scope, decl) => {
|
@@ -3210,18 +3472,6 @@ const allocPage = (scope, reason, type) => {
|
|
3210
3472
|
scope.pages ??= new Map();
|
3211
3473
|
scope.pages.set(reason, { ind, type });
|
3212
3474
|
|
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
3475
|
return ind;
|
3226
3476
|
};
|
3227
3477
|
|
@@ -3259,39 +3509,58 @@ const compileBytes = (val, itemType) => {
|
|
3259
3509
|
}
|
3260
3510
|
};
|
3261
3511
|
|
3262
|
-
const
|
3263
|
-
|
3264
|
-
case 'i8': return 'bytestring';
|
3265
|
-
case 'i16': return 'string';
|
3512
|
+
const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
|
3513
|
+
const length = elements.length;
|
3266
3514
|
|
3267
|
-
|
3515
|
+
// if length is 0 memory/data will just be 0000... anyway
|
3516
|
+
if (length === 0) return false;
|
3517
|
+
|
3518
|
+
let bytes = compileBytes(length, 'i32');
|
3519
|
+
|
3520
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3521
|
+
if (elements[i] == null) continue;
|
3522
|
+
|
3523
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
3268
3524
|
}
|
3269
|
-
};
|
3270
3525
|
|
3271
|
-
const
|
3272
|
-
|
3526
|
+
const obj = { bytes };
|
3527
|
+
if (offset != null) obj.offset = offset;
|
3528
|
+
|
3529
|
+
const idx = data.push(obj) - 1;
|
3530
|
+
|
3531
|
+
scope.data ??= [];
|
3532
|
+
scope.data.push(idx);
|
3273
3533
|
|
3274
|
-
|
3534
|
+
return { idx, size: bytes.length };
|
3535
|
+
};
|
3275
3536
|
|
3276
|
-
|
3277
|
-
|
3278
|
-
firstAssign = true;
|
3537
|
+
const printStaticStr = str => {
|
3538
|
+
const out = [];
|
3279
3539
|
|
3280
|
-
|
3281
|
-
|
3540
|
+
for (let i = 0; i < str.length; i++) {
|
3541
|
+
out.push(
|
3542
|
+
// ...number(str.charCodeAt(i)),
|
3543
|
+
...number(str.charCodeAt(i), Valtype.i32),
|
3544
|
+
Opcodes.i32_from_u,
|
3545
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3546
|
+
);
|
3547
|
+
}
|
3282
3548
|
|
3283
|
-
|
3284
|
-
|
3285
|
-
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3549
|
+
return out;
|
3550
|
+
};
|
3286
3551
|
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3552
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
|
3553
|
+
if (itemType !== 'i16' && itemType !== 'i8') {
|
3554
|
+
pages.hasArray = true;
|
3555
|
+
} else {
|
3556
|
+
pages.hasAnyString = true;
|
3557
|
+
if (itemType === 'i8') pages.hasByteString = true;
|
3558
|
+
else pages.hasString = true;
|
3290
3559
|
}
|
3291
3560
|
|
3292
|
-
const
|
3561
|
+
const out = [];
|
3293
3562
|
|
3294
|
-
const
|
3563
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3295
3564
|
|
3296
3565
|
const useRawElements = !!decl.rawElements;
|
3297
3566
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
@@ -3299,46 +3568,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3299
3568
|
const valtype = itemTypeToValtype[itemType];
|
3300
3569
|
const length = elements.length;
|
3301
3570
|
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3571
|
+
const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
|
3572
|
+
|
3573
|
+
let pointer = allocated;
|
3574
|
+
if (allocator.constructor.name !== 'StaticAllocator') {
|
3575
|
+
// const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
|
3576
|
+
const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
|
3577
|
+
out.push(
|
3578
|
+
...allocated,
|
3579
|
+
[ Opcodes.local_set, tmp ]
|
3580
|
+
);
|
3581
|
+
|
3582
|
+
if (Prefs.runtimeAllocLog) out.push(
|
3583
|
+
...printStaticStr(`${name}: `),
|
3584
|
+
|
3585
|
+
[ Opcodes.local_get, tmp ],
|
3586
|
+
Opcodes.i32_from_u,
|
3587
|
+
[ Opcodes.call, 0 ],
|
3588
|
+
|
3589
|
+
...number(10),
|
3590
|
+
[ Opcodes.call, 1 ]
|
3591
|
+
);
|
3306
3592
|
|
3307
|
-
|
3308
|
-
if (elements[i] == null) continue;
|
3593
|
+
pointer = [ [ Opcodes.local_get, tmp ] ];
|
3309
3594
|
|
3310
|
-
|
3595
|
+
if (Prefs.data && useRawElements) {
|
3596
|
+
const data = makeData(scope, elements, null, itemType, initEmpty);
|
3597
|
+
if (data) {
|
3598
|
+
// init data
|
3599
|
+
out.push(
|
3600
|
+
...pointer,
|
3601
|
+
...number(0, Valtype.i32),
|
3602
|
+
...number(data.size, Valtype.i32),
|
3603
|
+
[ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
|
3604
|
+
);
|
3311
3605
|
}
|
3312
3606
|
|
3313
|
-
|
3314
|
-
|
3315
|
-
|
3316
|
-
|
3607
|
+
// return pointer in out
|
3608
|
+
out.push(
|
3609
|
+
...pointer,
|
3610
|
+
...(!intOut ? [ Opcodes.i32_from_u ] : [])
|
3611
|
+
);
|
3317
3612
|
|
3318
|
-
|
3319
|
-
scope.data.push(ind);
|
3613
|
+
return [ out, pointer ];
|
3320
3614
|
}
|
3615
|
+
} else {
|
3616
|
+
const rawPtr = read_signedLEB128(pointer[0].slice(1));
|
3321
3617
|
|
3322
|
-
|
3323
|
-
|
3618
|
+
scope.arrays ??= new Map();
|
3619
|
+
const firstAssign = !scope.arrays.has(uniqueName);
|
3620
|
+
if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
|
3324
3621
|
|
3325
|
-
|
3326
|
-
|
3622
|
+
if (Prefs.data && firstAssign && useRawElements) {
|
3623
|
+
makeData(scope, elements, rawPtr, itemType, initEmpty);
|
3327
3624
|
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
)
|
3625
|
+
// local value as pointer
|
3626
|
+
return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
|
3627
|
+
}
|
3628
|
+
|
3629
|
+
const local = global ? globals[name] : scope.locals[name];
|
3630
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3631
|
+
if (pointerTmp != null) {
|
3632
|
+
out.push(
|
3633
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3634
|
+
Opcodes.i32_to_u,
|
3635
|
+
[ Opcodes.local_set, pointerTmp ]
|
3636
|
+
);
|
3637
|
+
|
3638
|
+
pointer = [ [ Opcodes.local_get, pointerTmp ] ];
|
3639
|
+
}
|
3335
3640
|
}
|
3336
3641
|
|
3337
|
-
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3338
3642
|
|
3339
3643
|
// store length
|
3340
3644
|
out.push(
|
3341
|
-
...
|
3645
|
+
...pointer,
|
3342
3646
|
...number(length, Valtype.i32),
|
3343
3647
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3344
3648
|
);
|
@@ -3350,11 +3654,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3350
3654
|
|
3351
3655
|
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3352
3656
|
out.push(
|
3353
|
-
...
|
3657
|
+
...pointer,
|
3354
3658
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3355
3659
|
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3356
3660
|
...(!typed ? [] : [ // typed presumes !useRawElements
|
3357
|
-
...
|
3661
|
+
...pointer,
|
3358
3662
|
...getNodeType(scope, elements[i]),
|
3359
3663
|
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3360
3664
|
])
|
@@ -3362,12 +3666,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3362
3666
|
}
|
3363
3667
|
|
3364
3668
|
// local value as pointer
|
3365
|
-
out.push(...
|
3669
|
+
out.push(...pointer);
|
3670
|
+
if (!intOut) out.push(Opcodes.i32_from_u);
|
3366
3671
|
|
3367
3672
|
return [ out, pointer ];
|
3368
3673
|
};
|
3369
3674
|
|
3370
|
-
const storeArray = (scope, array, index, element
|
3675
|
+
const storeArray = (scope, array, index, element) => {
|
3371
3676
|
if (!Array.isArray(element)) element = generate(scope, element);
|
3372
3677
|
if (typeof index === 'number') index = number(index);
|
3373
3678
|
|
@@ -3379,26 +3684,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
|
|
3379
3684
|
Opcodes.i32_to_u,
|
3380
3685
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3381
3686
|
[ Opcodes.i32_mul ],
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
]),
|
3687
|
+
|
3688
|
+
...array,
|
3689
|
+
Opcodes.i32_to_u,
|
3690
|
+
[ Opcodes.i32_add ],
|
3387
3691
|
[ Opcodes.local_set, offset ],
|
3388
3692
|
|
3389
3693
|
// store value
|
3390
3694
|
[ Opcodes.local_get, offset ],
|
3391
3695
|
...generate(scope, element),
|
3392
|
-
[ Opcodes.store, 0,
|
3696
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
3393
3697
|
|
3394
3698
|
// store type
|
3395
3699
|
[ Opcodes.local_get, offset ],
|
3396
3700
|
...getNodeType(scope, element),
|
3397
|
-
[ Opcodes.i32_store8, 0,
|
3701
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3398
3702
|
];
|
3399
3703
|
};
|
3400
3704
|
|
3401
|
-
const loadArray = (scope, array, index
|
3705
|
+
const loadArray = (scope, array, index) => {
|
3402
3706
|
if (typeof index === 'number') index = number(index);
|
3403
3707
|
|
3404
3708
|
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
@@ -3409,20 +3713,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
|
|
3409
3713
|
Opcodes.i32_to_u,
|
3410
3714
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3411
3715
|
[ Opcodes.i32_mul ],
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3415
|
-
|
3416
|
-
]),
|
3716
|
+
|
3717
|
+
...array,
|
3718
|
+
Opcodes.i32_to_u,
|
3719
|
+
[ Opcodes.i32_add ],
|
3417
3720
|
[ Opcodes.local_set, offset ],
|
3418
3721
|
|
3419
3722
|
// load value
|
3420
3723
|
[ Opcodes.local_get, offset ],
|
3421
|
-
[ Opcodes.load, 0,
|
3724
|
+
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
3422
3725
|
|
3423
3726
|
// load type
|
3424
3727
|
[ Opcodes.local_get, offset ],
|
3425
|
-
[ Opcodes.i32_load8_u, 0,
|
3728
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
3426
3729
|
];
|
3427
3730
|
};
|
3428
3731
|
|
@@ -3454,7 +3757,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3454
3757
|
};
|
3455
3758
|
|
3456
3759
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3457
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3760
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
|
3458
3761
|
};
|
3459
3762
|
|
3460
3763
|
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
@@ -3471,11 +3774,21 @@ const withType = (scope, wasm, type) => [
|
|
3471
3774
|
...setLastType(scope, type)
|
3472
3775
|
];
|
3473
3776
|
|
3777
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
3778
|
+
const out = {};
|
3779
|
+
for (const x in bc) {
|
3780
|
+
out[x] = [
|
3781
|
+
...prelude,
|
3782
|
+
...bc[x],
|
3783
|
+
...postlude
|
3784
|
+
];
|
3785
|
+
}
|
3786
|
+
|
3787
|
+
return out;
|
3788
|
+
};
|
3789
|
+
|
3474
3790
|
const generateMember = (scope, decl, _global, _name) => {
|
3475
3791
|
const name = decl.object.name;
|
3476
|
-
const pointer = scope.arrays?.get(name);
|
3477
|
-
|
3478
|
-
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3479
3792
|
|
3480
3793
|
// hack: .name
|
3481
3794
|
if (decl.property.name === 'name') {
|
@@ -3510,18 +3823,16 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3510
3823
|
}
|
3511
3824
|
|
3512
3825
|
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);
|
3826
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3514
3827
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3515
3828
|
|
3516
3829
|
if (Prefs.fastLength) {
|
3517
3830
|
// presume valid length object
|
3518
3831
|
return [
|
3519
|
-
...(
|
3520
|
-
|
3521
|
-
Opcodes.i32_to_u
|
3522
|
-
]),
|
3832
|
+
...generate(scope, decl.object),
|
3833
|
+
Opcodes.i32_to_u,
|
3523
3834
|
|
3524
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3835
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3525
3836
|
Opcodes.i32_from_u
|
3526
3837
|
];
|
3527
3838
|
}
|
@@ -3529,13 +3840,11 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3529
3840
|
const type = getNodeType(scope, decl.object);
|
3530
3841
|
const known = knownType(scope, type);
|
3531
3842
|
if (known != null) {
|
3532
|
-
if (
|
3533
|
-
...(
|
3534
|
-
|
3535
|
-
Opcodes.i32_to_u
|
3536
|
-
]),
|
3843
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3844
|
+
...generate(scope, decl.object),
|
3845
|
+
Opcodes.i32_to_u,
|
3537
3846
|
|
3538
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3847
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3539
3848
|
Opcodes.i32_from_u
|
3540
3849
|
];
|
3541
3850
|
|
@@ -3543,14 +3852,14 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3543
3852
|
}
|
3544
3853
|
|
3545
3854
|
return [
|
3546
|
-
...
|
3855
|
+
...getNodeType(scope, decl.object),
|
3856
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
3857
|
+
[ Opcodes.i32_and ],
|
3547
3858
|
[ Opcodes.if, valtypeBinary ],
|
3548
|
-
...(
|
3549
|
-
|
3550
|
-
Opcodes.i32_to_u
|
3551
|
-
]),
|
3859
|
+
...generate(scope, decl.object),
|
3860
|
+
Opcodes.i32_to_u,
|
3552
3861
|
|
3553
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1,
|
3862
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3554
3863
|
Opcodes.i32_from_u,
|
3555
3864
|
|
3556
3865
|
...setLastType(scope, TYPES.number),
|
@@ -3593,25 +3902,31 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3593
3902
|
|
3594
3903
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3595
3904
|
// hack: this is naughty and will break things!
|
3596
|
-
let newOut = number(0,
|
3597
|
-
|
3905
|
+
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3906
|
+
|
3907
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
3908
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3909
|
+
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3598
3910
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3599
|
-
rawElements: new Array(
|
3600
|
-
}, _global, _name, true, 'i16');
|
3911
|
+
rawElements: new Array(0)
|
3912
|
+
}, _global, _name, true, 'i16', true);
|
3601
3913
|
}
|
3602
3914
|
|
3603
3915
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3604
3916
|
[TYPES.array]: [
|
3605
|
-
...loadArray(scope, object, property
|
3917
|
+
...loadArray(scope, object, property),
|
3606
3918
|
...setLastType(scope)
|
3607
3919
|
],
|
3608
|
-
|
3609
3920
|
[TYPES.string]: [
|
3610
3921
|
// setup new/out array
|
3611
3922
|
...newOut,
|
3612
|
-
[ Opcodes.drop ],
|
3613
3923
|
|
3614
|
-
|
3924
|
+
// set length to 1
|
3925
|
+
...number(1, Valtype.i32),
|
3926
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3927
|
+
|
3928
|
+
// use as pointer for store later
|
3929
|
+
...newPointer,
|
3615
3930
|
|
3616
3931
|
...property,
|
3617
3932
|
Opcodes.i32_to_u,
|
@@ -3619,54 +3934,132 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3619
3934
|
...number(ValtypeSize.i16, Valtype.i32),
|
3620
3935
|
[ Opcodes.i32_mul ],
|
3621
3936
|
|
3622
|
-
...
|
3623
|
-
|
3624
|
-
|
3625
|
-
[ Opcodes.i32_add ]
|
3626
|
-
]),
|
3937
|
+
...object,
|
3938
|
+
Opcodes.i32_to_u,
|
3939
|
+
[ Opcodes.i32_add ],
|
3627
3940
|
|
3628
3941
|
// load current string ind {arg}
|
3629
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1,
|
3942
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3630
3943
|
|
3631
3944
|
// store to new string ind 0
|
3632
|
-
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1,
|
3945
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
3633
3946
|
|
3634
3947
|
// return new string (page)
|
3635
|
-
...
|
3948
|
+
...newPointer,
|
3949
|
+
Opcodes.i32_from_u,
|
3636
3950
|
...setLastType(scope, TYPES.string)
|
3637
3951
|
],
|
3638
3952
|
[TYPES.bytestring]: [
|
3639
3953
|
// setup new/out array
|
3640
3954
|
...newOut,
|
3641
|
-
[ Opcodes.drop ],
|
3642
3955
|
|
3643
|
-
|
3956
|
+
// set length to 1
|
3957
|
+
...number(1, Valtype.i32),
|
3958
|
+
[ Opcodes.i32_store, 0, 0 ],
|
3959
|
+
|
3960
|
+
// use as pointer for store later
|
3961
|
+
...newPointer,
|
3644
3962
|
|
3645
3963
|
...property,
|
3646
3964
|
Opcodes.i32_to_u,
|
3647
3965
|
|
3648
|
-
...
|
3649
|
-
|
3650
|
-
|
3651
|
-
[ Opcodes.i32_add ]
|
3652
|
-
]),
|
3966
|
+
...object,
|
3967
|
+
Opcodes.i32_to_u,
|
3968
|
+
[ Opcodes.i32_add ],
|
3653
3969
|
|
3654
3970
|
// load current string ind {arg}
|
3655
|
-
[ Opcodes.i32_load8_u, 0,
|
3971
|
+
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
|
3656
3972
|
|
3657
3973
|
// store to new string ind 0
|
3658
|
-
[ Opcodes.i32_store8, 0,
|
3974
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
|
3659
3975
|
|
3660
3976
|
// return new string (page)
|
3661
|
-
...
|
3977
|
+
...newPointer,
|
3978
|
+
Opcodes.i32_from_u,
|
3662
3979
|
...setLastType(scope, TYPES.bytestring)
|
3663
3980
|
],
|
3664
3981
|
|
3982
|
+
...wrapBC({
|
3983
|
+
[TYPES.uint8array]: [
|
3984
|
+
[ Opcodes.i32_add ],
|
3985
|
+
|
3986
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3987
|
+
Opcodes.i32_from_u
|
3988
|
+
],
|
3989
|
+
[TYPES.uint8clampedarray]: [
|
3990
|
+
[ Opcodes.i32_add ],
|
3991
|
+
|
3992
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3993
|
+
Opcodes.i32_from_u
|
3994
|
+
],
|
3995
|
+
[TYPES.int8array]: [
|
3996
|
+
[ Opcodes.i32_add ],
|
3997
|
+
|
3998
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3999
|
+
Opcodes.i32_from
|
4000
|
+
],
|
4001
|
+
[TYPES.uint16array]: [
|
4002
|
+
...number(2, Valtype.i32),
|
4003
|
+
[ Opcodes.i32_mul ],
|
4004
|
+
[ Opcodes.i32_add ],
|
4005
|
+
|
4006
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4007
|
+
Opcodes.i32_from_u
|
4008
|
+
],
|
4009
|
+
[TYPES.int16array]: [
|
4010
|
+
...number(2, Valtype.i32),
|
4011
|
+
[ Opcodes.i32_mul ],
|
4012
|
+
[ Opcodes.i32_add ],
|
4013
|
+
|
4014
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4015
|
+
Opcodes.i32_from
|
4016
|
+
],
|
4017
|
+
[TYPES.uint32array]: [
|
4018
|
+
...number(4, Valtype.i32),
|
4019
|
+
[ Opcodes.i32_mul ],
|
4020
|
+
[ Opcodes.i32_add ],
|
4021
|
+
|
4022
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4023
|
+
Opcodes.i32_from_u
|
4024
|
+
],
|
4025
|
+
[TYPES.int32array]: [
|
4026
|
+
...number(4, Valtype.i32),
|
4027
|
+
[ Opcodes.i32_mul ],
|
4028
|
+
[ Opcodes.i32_add ],
|
4029
|
+
|
4030
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4031
|
+
Opcodes.i32_from
|
4032
|
+
],
|
4033
|
+
[TYPES.float32array]: [
|
4034
|
+
...number(4, Valtype.i32),
|
4035
|
+
[ Opcodes.i32_mul ],
|
4036
|
+
[ Opcodes.i32_add ],
|
4037
|
+
|
4038
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4039
|
+
[ Opcodes.f64_promote_f32 ]
|
4040
|
+
],
|
4041
|
+
[TYPES.float64array]: [
|
4042
|
+
...number(8, Valtype.i32),
|
4043
|
+
[ Opcodes.i32_mul ],
|
4044
|
+
[ Opcodes.i32_add ],
|
4045
|
+
|
4046
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4047
|
+
],
|
4048
|
+
}, {
|
4049
|
+
prelude: [
|
4050
|
+
...object,
|
4051
|
+
Opcodes.i32_to_u,
|
4052
|
+
...property,
|
4053
|
+
Opcodes.i32_to_u
|
4054
|
+
],
|
4055
|
+
postlude: setLastType(scope, TYPES.number)
|
4056
|
+
}),
|
4057
|
+
|
3665
4058
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3666
4059
|
});
|
3667
4060
|
};
|
3668
4061
|
|
3669
|
-
const randId = () => Math.random().toString(16).slice(
|
4062
|
+
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
3670
4063
|
|
3671
4064
|
const objectHack = node => {
|
3672
4065
|
if (!node) return node;
|
@@ -3718,7 +4111,7 @@ const generateFunc = (scope, decl) => {
|
|
3718
4111
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3719
4112
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3720
4113
|
|
3721
|
-
const name = decl.id ? decl.id.name : `
|
4114
|
+
const name = decl.id ? decl.id.name : `anonymous${randId()}`;
|
3722
4115
|
const params = decl.params ?? [];
|
3723
4116
|
|
3724
4117
|
// TODO: share scope/locals between !!!
|
@@ -3732,6 +4125,9 @@ const generateFunc = (scope, decl) => {
|
|
3732
4125
|
index: currentFuncIndex++
|
3733
4126
|
};
|
3734
4127
|
|
4128
|
+
funcIndex[name] = func.index;
|
4129
|
+
funcs.push(func);
|
4130
|
+
|
3735
4131
|
if (typedInput && decl.returnType) {
|
3736
4132
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3737
4133
|
// if (type != null && !Prefs.indirectCalls) {
|
@@ -3741,12 +4137,26 @@ const generateFunc = (scope, decl) => {
|
|
3741
4137
|
}
|
3742
4138
|
}
|
3743
4139
|
|
4140
|
+
const defaultValues = {};
|
3744
4141
|
for (let i = 0; i < params.length; i++) {
|
3745
|
-
|
4142
|
+
let name;
|
4143
|
+
const x = params[i];
|
4144
|
+
switch (x.type) {
|
4145
|
+
case 'Identifier': {
|
4146
|
+
name = x.name;
|
4147
|
+
break;
|
4148
|
+
}
|
4149
|
+
|
4150
|
+
case 'AssignmentPattern': {
|
4151
|
+
name = x.left.name;
|
4152
|
+
defaultValues[name] = x.right;
|
4153
|
+
break;
|
4154
|
+
}
|
4155
|
+
}
|
4156
|
+
|
3746
4157
|
// if (name == null) return todo('non-identifier args are not supported');
|
3747
4158
|
|
3748
4159
|
allocVar(func, name, false);
|
3749
|
-
|
3750
4160
|
if (typedInput && params[i].typeAnnotation) {
|
3751
4161
|
addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
|
3752
4162
|
}
|
@@ -3763,11 +4173,22 @@ const generateFunc = (scope, decl) => {
|
|
3763
4173
|
};
|
3764
4174
|
}
|
3765
4175
|
|
3766
|
-
|
3767
|
-
|
4176
|
+
const prelude = [];
|
4177
|
+
for (const x in defaultValues) {
|
4178
|
+
prelude.push(
|
4179
|
+
...getType(func, x),
|
4180
|
+
...number(TYPES.undefined, Valtype.i32),
|
4181
|
+
[ Opcodes.i32_eq ],
|
4182
|
+
[ Opcodes.if, Blocktype.void ],
|
4183
|
+
...generate(func, defaultValues[x], false, x),
|
4184
|
+
[ Opcodes.local_set, func.locals[x].idx ],
|
3768
4185
|
|
3769
|
-
|
3770
|
-
|
4186
|
+
...setType(func, x, getNodeType(scope, defaultValues[x])),
|
4187
|
+
[ Opcodes.end ]
|
4188
|
+
);
|
4189
|
+
}
|
4190
|
+
|
4191
|
+
const wasm = func.wasm = prelude.concat(generate(func, body));
|
3771
4192
|
|
3772
4193
|
if (name === 'main') func.gotLastType = true;
|
3773
4194
|
|
@@ -3803,23 +4224,24 @@ const internalConstrs = {
|
|
3803
4224
|
|
3804
4225
|
// new Array(n)
|
3805
4226
|
|
3806
|
-
const [ , pointer ] = makeArray(scope, {
|
4227
|
+
const [ out, pointer ] = makeArray(scope, {
|
3807
4228
|
rawElements: new Array(0)
|
3808
|
-
}, global, name, true);
|
4229
|
+
}, global, name, true, undefined, true);
|
3809
4230
|
|
3810
4231
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3811
4232
|
|
3812
4233
|
// todo: check in wasm instead of here
|
3813
4234
|
const literalValue = arg.value ?? 0;
|
3814
|
-
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, '
|
4235
|
+
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeError', 'Invalid array length', true);
|
3815
4236
|
|
3816
4237
|
return [
|
3817
|
-
...
|
4238
|
+
...out,
|
3818
4239
|
...generate(scope, arg, global, name),
|
3819
4240
|
Opcodes.i32_to_u,
|
3820
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
4241
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3821
4242
|
|
3822
|
-
...
|
4243
|
+
...pointer,
|
4244
|
+
Opcodes.i32_from_u
|
3823
4245
|
];
|
3824
4246
|
},
|
3825
4247
|
type: TYPES.array,
|
@@ -3968,8 +4390,9 @@ const internalConstrs = {
|
|
3968
4390
|
};
|
3969
4391
|
|
3970
4392
|
export default program => {
|
3971
|
-
globals = {
|
3972
|
-
|
4393
|
+
globals = {
|
4394
|
+
['#ind']: 0
|
4395
|
+
};
|
3973
4396
|
tags = [];
|
3974
4397
|
exceptions = [];
|
3975
4398
|
funcs = [];
|
@@ -3979,19 +4402,8 @@ export default program => {
|
|
3979
4402
|
data = [];
|
3980
4403
|
currentFuncIndex = importedFuncs.length;
|
3981
4404
|
|
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
4405
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3990
4406
|
|
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
4407
|
// set generic opcodes for current valtype
|
3996
4408
|
Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
|
3997
4409
|
Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
|
@@ -4013,6 +4425,7 @@ export default program => {
|
|
4013
4425
|
builtinFuncs = new BuiltinFuncs();
|
4014
4426
|
builtinVars = new BuiltinVars();
|
4015
4427
|
prototypeFuncs = new PrototypeFuncs();
|
4428
|
+
allocator = makeAllocator(Prefs.allocator ?? 'static');
|
4016
4429
|
|
4017
4430
|
program.id = { name: 'main' };
|
4018
4431
|
|
@@ -4055,6 +4468,8 @@ export default program => {
|
|
4055
4468
|
else main.returns = [];
|
4056
4469
|
}
|
4057
4470
|
|
4471
|
+
delete globals['#ind'];
|
4472
|
+
|
4058
4473
|
// if blank main func and other exports, remove it
|
4059
4474
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4060
4475
|
|