porffor 0.0.0-bddcdc3 → 0.0.0-beff13f
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/README.md +46 -13
- package/c +0 -0
- package/c.exe +0 -0
- package/compiler/2c.js +350 -0
- package/compiler/builtins.js +6 -1
- package/compiler/codeGen.js +463 -144
- package/compiler/decompile.js +3 -3
- package/compiler/embedding.js +9 -5
- package/compiler/encoding.js +4 -2
- package/compiler/index.js +55 -4
- package/compiler/opt.js +49 -23
- package/compiler/parse.js +1 -0
- package/compiler/prototype.js +94 -33
- package/compiler/sections.js +45 -6
- package/compiler/wrap.js +21 -3
- package/cool.exe +0 -0
- package/g +0 -0
- package/g.exe +0 -0
- package/hi.c +37 -0
- package/out +0 -0
- package/out.exe +0 -0
- package/package.json +1 -1
- package/r.js +39 -0
- package/rhemyn/README.md +37 -0
- package/rhemyn/compile.js +214 -0
- package/rhemyn/parse.js +321 -0
- package/rhemyn/test/parse.js +59 -0
- package/runner/index.js +54 -34
- package/runner/info.js +37 -2
- package/runner/repl.js +3 -10
- package/runner/transform.js +2 -1
- package/runner/version.js +10 -0
- package/tmp.c +58 -0
package/compiler/codeGen.js
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
|
2
|
-
import { signedLEB128, unsignedLEB128 } from "./encoding.js";
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128 } 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
|
-
import { number, i32x4 } from "./embedding.js";
|
6
|
+
import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enforceEightBytes } from "./embedding.js";
|
7
7
|
import parse from "./parse.js";
|
8
|
+
import * as Rhemyn from "../rhemyn/compile.js";
|
8
9
|
|
9
10
|
let globals = {};
|
10
11
|
let globalInd = 0;
|
@@ -35,7 +36,14 @@ const debug = str => {
|
|
35
36
|
};
|
36
37
|
|
37
38
|
const todo = msg => {
|
38
|
-
|
39
|
+
class TodoError extends Error {
|
40
|
+
constructor(message) {
|
41
|
+
super(message);
|
42
|
+
this.name = 'TodoError';
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
throw new TodoError(`todo: ${msg}`);
|
39
47
|
|
40
48
|
const code = [];
|
41
49
|
|
@@ -101,8 +109,8 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
101
109
|
case 'WhileStatement':
|
102
110
|
return generateWhile(scope, decl);
|
103
111
|
|
104
|
-
|
105
|
-
return generateForOf(scope, decl);
|
112
|
+
case 'ForOfStatement':
|
113
|
+
return generateForOf(scope, decl);
|
106
114
|
|
107
115
|
case 'BreakStatement':
|
108
116
|
return generateBreak(scope, decl);
|
@@ -144,45 +152,65 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
144
152
|
|
145
153
|
return [];
|
146
154
|
|
147
|
-
case 'TaggedTemplateExpression':
|
148
|
-
|
149
|
-
|
155
|
+
case 'TaggedTemplateExpression': {
|
156
|
+
const funcs = {
|
157
|
+
asm: str => {
|
158
|
+
let out = [];
|
150
159
|
|
151
|
-
|
152
|
-
|
160
|
+
for (const line of str.split('\n')) {
|
161
|
+
const asm = line.trim().split(';;')[0].split(' ');
|
162
|
+
if (asm[0] === '') continue; // blank
|
153
163
|
|
154
|
-
|
155
|
-
|
156
|
-
|
164
|
+
if (asm[0] === 'local') {
|
165
|
+
const [ name, idx, type ] = asm.slice(1);
|
166
|
+
scope.locals[name] = { idx: parseInt(idx), type: Valtype[type] };
|
167
|
+
continue;
|
168
|
+
}
|
157
169
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
}
|
170
|
+
if (asm[0] === 'returns') {
|
171
|
+
scope.returns = asm.slice(1).map(x => Valtype[x]);
|
172
|
+
continue;
|
173
|
+
}
|
163
174
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
175
|
+
if (asm[0] === 'memory') {
|
176
|
+
allocPage('asm instrinsic');
|
177
|
+
// todo: add to store/load offset insts
|
178
|
+
continue;
|
179
|
+
}
|
168
180
|
|
169
|
-
|
170
|
-
|
171
|
-
allocPage('asm instrinsic');
|
172
|
-
// todo: add to store/load offset insts
|
173
|
-
continue;
|
174
|
-
}
|
181
|
+
let inst = Opcodes[asm[0].replace('.', '_')];
|
182
|
+
if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
175
183
|
|
176
|
-
|
177
|
-
|
184
|
+
if (!Array.isArray(inst)) inst = [ inst ];
|
185
|
+
const immediates = asm.slice(1).map(x => parseInt(x));
|
178
186
|
|
179
|
-
|
180
|
-
|
187
|
+
out.push([ ...inst, ...immediates ]);
|
188
|
+
}
|
189
|
+
|
190
|
+
return out;
|
191
|
+
},
|
192
|
+
|
193
|
+
__internal_print_type: str => {
|
194
|
+
const type = getType(scope, str) - TYPES.number;
|
195
|
+
|
196
|
+
return [
|
197
|
+
...number(type),
|
198
|
+
[ Opcodes.call, importedFuncs.print ],
|
181
199
|
|
182
|
-
|
200
|
+
// newline
|
201
|
+
...number(10),
|
202
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
203
|
+
];
|
204
|
+
}
|
183
205
|
}
|
184
206
|
|
185
|
-
|
207
|
+
const name = decl.tag.name;
|
208
|
+
// hack for inline asm
|
209
|
+
if (!funcs[name]) return todo('tagged template expressions not implemented');
|
210
|
+
|
211
|
+
const str = decl.quasi.quasis[0].value.raw;
|
212
|
+
return funcs[name](str);
|
213
|
+
}
|
186
214
|
|
187
215
|
default:
|
188
216
|
return todo(`no generation for ${decl.type}!`);
|
@@ -281,7 +309,7 @@ const generateReturn = (scope, decl) => {
|
|
281
309
|
];
|
282
310
|
}
|
283
311
|
|
284
|
-
|
312
|
+
scope.returnType = getNodeType(scope, decl.argument);
|
285
313
|
|
286
314
|
return [
|
287
315
|
...generate(scope, decl.argument),
|
@@ -298,11 +326,11 @@ const localTmp = (scope, name, type = valtypeBinary) => {
|
|
298
326
|
return idx;
|
299
327
|
};
|
300
328
|
|
301
|
-
const performLogicOp = (scope, op, left, right) => {
|
329
|
+
const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
302
330
|
const checks = {
|
303
|
-
'||':
|
304
|
-
'&&':
|
305
|
-
|
331
|
+
'||': falsy,
|
332
|
+
'&&': truthy,
|
333
|
+
'??': nullish
|
306
334
|
};
|
307
335
|
|
308
336
|
if (!checks[op]) return todo(`logic operator ${op} not implemented yet`);
|
@@ -313,7 +341,8 @@ const performLogicOp = (scope, op, left, right) => {
|
|
313
341
|
return [
|
314
342
|
...left,
|
315
343
|
[ Opcodes.local_tee, localTmp(scope, 'logictmp') ],
|
316
|
-
...checks[op],
|
344
|
+
...checks[op](scope, [], leftType),
|
345
|
+
Opcodes.i32_to,
|
317
346
|
[ Opcodes.if, valtypeBinary ],
|
318
347
|
...right,
|
319
348
|
[ Opcodes.else ],
|
@@ -328,8 +357,6 @@ const concatStrings = (scope, left, right, global, name, assign) => {
|
|
328
357
|
// todo: optimize by looking up names in arrays and using that if exists?
|
329
358
|
// todo: optimize this if using literals/known lengths?
|
330
359
|
|
331
|
-
scope.memory = true;
|
332
|
-
|
333
360
|
const rightPointer = localTmp(scope, 'concat_right_pointer', Valtype.i32);
|
334
361
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
335
362
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
@@ -464,8 +491,6 @@ const compareStrings = (scope, left, right) => {
|
|
464
491
|
// todo: optimize by looking up names in arrays and using that if exists?
|
465
492
|
// todo: optimize this if using literals/known lengths?
|
466
493
|
|
467
|
-
scope.memory = true;
|
468
|
-
|
469
494
|
const leftPointer = localTmp(scope, 'compare_left_pointer', Valtype.i32);
|
470
495
|
const leftLength = localTmp(scope, 'compare_left_length', Valtype.i32);
|
471
496
|
const rightPointer = localTmp(scope, 'compare_right_pointer', Valtype.i32);
|
@@ -563,102 +588,142 @@ const compareStrings = (scope, left, right) => {
|
|
563
588
|
];
|
564
589
|
};
|
565
590
|
|
566
|
-
const
|
591
|
+
const truthy = (scope, wasm, type) => {
|
567
592
|
// arrays are always truthy
|
568
593
|
if (type === TYPES._array) return [
|
569
594
|
...wasm,
|
570
595
|
[ Opcodes.drop ],
|
571
|
-
number(
|
596
|
+
...number(1)
|
572
597
|
];
|
573
598
|
|
574
599
|
if (type === TYPES.string) {
|
575
|
-
// if "" (length = 0)
|
600
|
+
// if not "" (length = 0)
|
576
601
|
return [
|
577
602
|
// pointer
|
578
603
|
...wasm,
|
604
|
+
Opcodes.i32_to_u,
|
579
605
|
|
580
606
|
// get length
|
581
607
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
582
608
|
|
583
|
-
// if length
|
584
|
-
[ Opcodes.i32_eqz ],
|
609
|
+
// if length != 0
|
610
|
+
/* [ Opcodes.i32_eqz ],
|
611
|
+
[ Opcodes.i32_eqz ], */
|
585
612
|
Opcodes.i32_from_u
|
586
613
|
]
|
587
614
|
}
|
588
615
|
|
589
|
-
// if
|
616
|
+
// if != 0
|
590
617
|
return [
|
591
618
|
...wasm,
|
592
619
|
|
593
|
-
|
594
|
-
Opcodes.
|
620
|
+
/* Opcodes.eqz,
|
621
|
+
[ Opcodes.i32_eqz ],
|
622
|
+
Opcodes.i32_from */
|
595
623
|
];
|
596
624
|
};
|
597
625
|
|
598
|
-
const
|
626
|
+
const falsy = (scope, wasm, type) => {
|
599
627
|
// arrays are always truthy
|
600
628
|
if (type === TYPES._array) return [
|
601
629
|
...wasm,
|
602
630
|
[ Opcodes.drop ],
|
603
|
-
number(
|
631
|
+
...number(0)
|
604
632
|
];
|
605
633
|
|
606
634
|
if (type === TYPES.string) {
|
607
|
-
// if
|
635
|
+
// if "" (length = 0)
|
608
636
|
return [
|
609
637
|
// pointer
|
610
638
|
...wasm,
|
639
|
+
Opcodes.i32_to_u,
|
611
640
|
|
612
641
|
// get length
|
613
642
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
614
643
|
|
615
|
-
// if length
|
616
|
-
|
617
|
-
[ Opcodes.i32_eqz ], */
|
644
|
+
// if length == 0
|
645
|
+
[ Opcodes.i32_eqz ],
|
618
646
|
Opcodes.i32_from_u
|
619
647
|
]
|
620
648
|
}
|
621
649
|
|
622
|
-
// if
|
650
|
+
// if = 0
|
623
651
|
return [
|
624
652
|
...wasm,
|
625
653
|
|
626
|
-
|
627
|
-
|
628
|
-
|
654
|
+
...Opcodes.eqz,
|
655
|
+
Opcodes.i32_from_u
|
656
|
+
];
|
657
|
+
};
|
658
|
+
|
659
|
+
const nullish = (scope, wasm, type) => {
|
660
|
+
// undefined
|
661
|
+
if (type === TYPES.undefined) return [
|
662
|
+
...wasm,
|
663
|
+
[ Opcodes.drop ],
|
664
|
+
...number(1)
|
665
|
+
];
|
666
|
+
|
667
|
+
// null (if object and = "0")
|
668
|
+
if (type === TYPES.object) return [
|
669
|
+
...wasm,
|
670
|
+
...Opcodes.eqz,
|
671
|
+
Opcodes.i32_from_u
|
672
|
+
];
|
673
|
+
|
674
|
+
// not
|
675
|
+
return [
|
676
|
+
...wasm,
|
677
|
+
[ Opcodes.drop ],
|
678
|
+
...number(0)
|
629
679
|
];
|
630
680
|
};
|
631
681
|
|
632
682
|
const performOp = (scope, op, left, right, leftType, rightType, _global = false, _name = '$undeclared', assign = false) => {
|
633
683
|
if (op === '||' || op === '&&' || op === '??') {
|
634
|
-
return performLogicOp(scope, op, left, right);
|
684
|
+
return performLogicOp(scope, op, left, right, leftType, rightType);
|
635
685
|
}
|
636
686
|
|
637
687
|
if (codeLog && (!leftType || !rightType)) log('codegen', 'untracked type in op', op, _name, '\n' + new Error().stack.split('\n').slice(1).join('\n'));
|
638
688
|
|
639
|
-
|
640
|
-
|
689
|
+
const eqOp = ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op);
|
690
|
+
|
691
|
+
if (leftType && rightType && (
|
692
|
+
// if strict (in)equal and known types mismatch, return false (===)/true (!==)
|
693
|
+
((op === '===' || op === '!==') && leftType !== rightType) ||
|
694
|
+
|
695
|
+
// if equality op and an operand is undefined, return false
|
696
|
+
(eqOp && leftType === TYPES.undefined ^ rightType === TYPES.undefined)
|
697
|
+
)) {
|
698
|
+
// undefined == null
|
699
|
+
if (((leftType === TYPES.undefined && rightType === TYPES.object) || (leftType === TYPES.object && rightType === TYPES.undefined)) && (op === '==' || op === '!=')) return [
|
700
|
+
...(leftType === TYPES.object ? left : right),
|
701
|
+
...Opcodes.eqz,
|
702
|
+
...(op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
|
703
|
+
];
|
704
|
+
|
641
705
|
return [
|
642
706
|
...left,
|
643
|
-
...right,
|
644
|
-
|
645
|
-
// drop values
|
646
707
|
[ Opcodes.drop ],
|
708
|
+
|
709
|
+
...right,
|
647
710
|
[ Opcodes.drop ],
|
648
711
|
|
649
|
-
// return
|
650
|
-
...number(op === '===' ?
|
712
|
+
// return true (!=/!==) or false (else)
|
713
|
+
...number(op === '!=' || op === '!==' ? 1 : 0, Valtype.i32)
|
651
714
|
];
|
652
715
|
}
|
653
716
|
|
717
|
+
// todo: niche null hell with 0
|
718
|
+
|
654
719
|
if (leftType === TYPES.string || rightType === TYPES.string) {
|
655
720
|
if (op === '+') {
|
656
721
|
// string concat (a + b)
|
657
722
|
return concatStrings(scope, left, right, _global, _name, assign);
|
658
723
|
}
|
659
724
|
|
660
|
-
//
|
661
|
-
if (!
|
725
|
+
// not an equality op, NaN
|
726
|
+
if (!eqOp) return number(NaN);
|
662
727
|
|
663
728
|
// else leave bool ops
|
664
729
|
// todo: convert string to number if string and number/bool
|
@@ -703,21 +768,15 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
703
768
|
];
|
704
769
|
};
|
705
770
|
|
706
|
-
let binaryExpDepth = 0;
|
707
771
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
708
|
-
|
709
|
-
|
710
|
-
const out = [
|
711
|
-
...performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name)
|
712
|
-
];
|
772
|
+
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
713
773
|
|
714
774
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
715
775
|
|
716
|
-
binaryExpDepth--;
|
717
776
|
return out;
|
718
777
|
};
|
719
778
|
|
720
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType,
|
779
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [] }) => {
|
721
780
|
const existing = funcs.find(x => x.name === name);
|
722
781
|
if (existing) return existing;
|
723
782
|
|
@@ -753,7 +812,6 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
753
812
|
returns,
|
754
813
|
returnType: TYPES[returnType ?? 'number'],
|
755
814
|
wasm,
|
756
|
-
memory,
|
757
815
|
internal: true,
|
758
816
|
index: currentFuncIndex++
|
759
817
|
};
|
@@ -772,7 +830,7 @@ const includeBuiltin = (scope, builtin) => {
|
|
772
830
|
};
|
773
831
|
|
774
832
|
const generateLogicExp = (scope, decl) => {
|
775
|
-
return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right));
|
833
|
+
return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
|
776
834
|
};
|
777
835
|
|
778
836
|
const TYPES = {
|
@@ -786,7 +844,8 @@ const TYPES = {
|
|
786
844
|
bigint: 0xffffffffffff7,
|
787
845
|
|
788
846
|
// these are not "typeof" types but tracked internally
|
789
|
-
_array:
|
847
|
+
_array: 0xfffffffffff0f,
|
848
|
+
_regexp: 0xfffffffffff1f
|
790
849
|
};
|
791
850
|
|
792
851
|
const TYPE_NAMES = {
|
@@ -821,6 +880,8 @@ const getType = (scope, _name) => {
|
|
821
880
|
const getNodeType = (scope, node) => {
|
822
881
|
if (node.type === 'Literal') {
|
823
882
|
if (['number', 'boolean', 'string', 'undefined', 'object', 'function', 'symbol', 'bigint'].includes(node.value)) return TYPES.number;
|
883
|
+
if (node.regex) return TYPES._regexp;
|
884
|
+
|
824
885
|
return TYPES[typeof node.value];
|
825
886
|
}
|
826
887
|
|
@@ -854,6 +915,11 @@ const getNodeType = (scope, node) => {
|
|
854
915
|
|
855
916
|
// literal.func()
|
856
917
|
if (!name && node.callee.type === 'MemberExpression') {
|
918
|
+
if (node.callee.object.regex) {
|
919
|
+
const funcName = node.callee.property.name;
|
920
|
+
return Rhemyn[funcName] ? TYPES.boolean : TYPES.undefined;
|
921
|
+
}
|
922
|
+
|
857
923
|
const baseType = getNodeType(scope, node.callee.object);
|
858
924
|
|
859
925
|
const func = node.callee.property.name;
|
@@ -897,6 +963,11 @@ const getNodeType = (scope, node) => {
|
|
897
963
|
const generateLiteral = (scope, decl, global, name) => {
|
898
964
|
if (decl.value === null) return number(NULL);
|
899
965
|
|
966
|
+
if (decl.regex) {
|
967
|
+
scope.regex[name] = decl.regex;
|
968
|
+
return number(1);
|
969
|
+
}
|
970
|
+
|
900
971
|
switch (typeof decl.value) {
|
901
972
|
case 'number':
|
902
973
|
return number(decl.value);
|
@@ -936,7 +1007,8 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
936
1007
|
const countLeftover = wasm => {
|
937
1008
|
let count = 0, depth = 0;
|
938
1009
|
|
939
|
-
for (
|
1010
|
+
for (let i = 0; i < wasm.length; i++) {
|
1011
|
+
const inst = wasm[i];
|
940
1012
|
if (depth === 0 && (inst[0] === Opcodes.if || inst[0] === Opcodes.block || inst[0] === Opcodes.loop)) {
|
941
1013
|
if (inst[0] === Opcodes.if) count--;
|
942
1014
|
if (inst[1] !== Blocktype.void) count++;
|
@@ -957,6 +1029,8 @@ const countLeftover = wasm => {
|
|
957
1029
|
} else count--;
|
958
1030
|
if (func) count += func.returns.length;
|
959
1031
|
} else count--;
|
1032
|
+
|
1033
|
+
// console.log(count, decompile([ inst ]).slice(0, -1));
|
960
1034
|
}
|
961
1035
|
|
962
1036
|
return count;
|
@@ -1040,7 +1114,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1040
1114
|
}
|
1041
1115
|
|
1042
1116
|
let out = [];
|
1043
|
-
let protoFunc, protoName, baseType, baseName
|
1117
|
+
let protoFunc, protoName, baseType, baseName;
|
1044
1118
|
// ident.func()
|
1045
1119
|
if (name && name.startsWith('__')) {
|
1046
1120
|
const spl = name.slice(2).split('_');
|
@@ -1055,6 +1129,25 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1055
1129
|
|
1056
1130
|
// literal.func()
|
1057
1131
|
if (!name && decl.callee.type === 'MemberExpression') {
|
1132
|
+
// megahack for /regex/.func()
|
1133
|
+
if (decl.callee.object.regex) {
|
1134
|
+
const funcName = decl.callee.property.name;
|
1135
|
+
const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
|
1136
|
+
|
1137
|
+
funcIndex[func.name] = func.index;
|
1138
|
+
funcs.push(func);
|
1139
|
+
|
1140
|
+
return [
|
1141
|
+
// make string arg
|
1142
|
+
...generate(scope, decl.arguments[0]),
|
1143
|
+
|
1144
|
+
// call regex func
|
1145
|
+
Opcodes.i32_to_u,
|
1146
|
+
[ Opcodes.call, func.index ],
|
1147
|
+
Opcodes.i32_from
|
1148
|
+
];
|
1149
|
+
}
|
1150
|
+
|
1058
1151
|
baseType = getNodeType(scope, decl.callee.object);
|
1059
1152
|
|
1060
1153
|
const func = decl.callee.property.name;
|
@@ -1063,11 +1156,36 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1063
1156
|
|
1064
1157
|
out = generate(scope, decl.callee.object);
|
1065
1158
|
out.push([ Opcodes.drop ]);
|
1159
|
+
|
1160
|
+
baseName = [...arrays.keys()].pop();
|
1066
1161
|
}
|
1067
1162
|
|
1068
|
-
if (
|
1069
|
-
|
1163
|
+
if (protoName && baseType === TYPES.string && Rhemyn[protoName]) {
|
1164
|
+
const func = Rhemyn[protoName](decl.arguments[0].regex.pattern, currentFuncIndex++);
|
1165
|
+
|
1166
|
+
funcIndex[func.name] = func.index;
|
1167
|
+
funcs.push(func);
|
1070
1168
|
|
1169
|
+
const pointer = arrays.get(baseName);
|
1170
|
+
const [ local, isGlobal ] = lookupName(scope, baseName);
|
1171
|
+
|
1172
|
+
return [
|
1173
|
+
...out,
|
1174
|
+
|
1175
|
+
...(pointer == null ? [
|
1176
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1177
|
+
Opcodes.i32_to_u,
|
1178
|
+
] : [
|
1179
|
+
...number(pointer, Valtype.i32)
|
1180
|
+
]),
|
1181
|
+
|
1182
|
+
// call regex func
|
1183
|
+
[ Opcodes.call, func.index ],
|
1184
|
+
Opcodes.i32_from
|
1185
|
+
];
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
if (protoFunc) {
|
1071
1189
|
let pointer = arrays.get(baseName);
|
1072
1190
|
|
1073
1191
|
if (pointer == null) {
|
@@ -1075,7 +1193,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1075
1193
|
if (codeLog) log('codegen', 'cloning unknown dynamic pointer');
|
1076
1194
|
|
1077
1195
|
// register array
|
1078
|
-
|
1196
|
+
0, [ , pointer ] = makeArray(scope, {
|
1079
1197
|
rawElements: new Array(0)
|
1080
1198
|
}, _global, baseName, true, baseType === TYPES.string ? 'i16' : valtype);
|
1081
1199
|
|
@@ -1099,24 +1217,34 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1099
1217
|
// use local for cached i32 length as commonly used
|
1100
1218
|
let lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
1101
1219
|
|
1220
|
+
let lengthI32CacheUsed = false;
|
1221
|
+
|
1222
|
+
const protoOut = protoFunc(pointer, {
|
1223
|
+
getCachedI32: () => {
|
1224
|
+
lengthI32CacheUsed = true;
|
1225
|
+
return [ [ Opcodes.local_get, lengthLocal ] ]
|
1226
|
+
},
|
1227
|
+
setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
|
1228
|
+
get: () => arrayUtil.getLength(pointer),
|
1229
|
+
getI32: () => arrayUtil.getLengthI32(pointer),
|
1230
|
+
set: value => arrayUtil.setLength(pointer, value),
|
1231
|
+
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1232
|
+
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
|
1233
|
+
return makeArray(scope, {
|
1234
|
+
rawElements: new Array(length)
|
1235
|
+
}, _global, _name, true, itemType);
|
1236
|
+
});
|
1237
|
+
|
1102
1238
|
return [
|
1103
1239
|
...out,
|
1104
1240
|
|
1105
|
-
...
|
1106
|
-
|
1241
|
+
...(!lengthI32CacheUsed ? [] : [
|
1242
|
+
...arrayUtil.getLengthI32(pointer),
|
1243
|
+
[ Opcodes.local_set, lengthLocal ],
|
1244
|
+
]),
|
1107
1245
|
|
1108
1246
|
[ Opcodes.block, valtypeBinary ],
|
1109
|
-
...
|
1110
|
-
cachedI32: [ [ Opcodes.local_get, lengthLocal ] ],
|
1111
|
-
get: arrayUtil.getLength(pointer),
|
1112
|
-
getI32: arrayUtil.getLengthI32(pointer),
|
1113
|
-
set: value => arrayUtil.setLength(pointer, value),
|
1114
|
-
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1115
|
-
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
|
1116
|
-
return makeArray(scope, {
|
1117
|
-
rawElements: new Array(length)
|
1118
|
-
}, _global, _name, true, itemType);
|
1119
|
-
}),
|
1247
|
+
...protoOut,
|
1120
1248
|
[ Opcodes.end ]
|
1121
1249
|
];
|
1122
1250
|
}
|
@@ -1173,11 +1301,10 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1173
1301
|
args = args.slice(0, func.params.length);
|
1174
1302
|
}
|
1175
1303
|
|
1176
|
-
if (func && func.memory) scope.memory = true;
|
1177
1304
|
if (func && func.throws) scope.throws = true;
|
1178
1305
|
|
1179
1306
|
for (const arg of args) {
|
1180
|
-
out.
|
1307
|
+
out = out.concat(generate(scope, arg));
|
1181
1308
|
}
|
1182
1309
|
|
1183
1310
|
out.push([ Opcodes.call, idx ]);
|
@@ -1189,7 +1316,7 @@ const generateNew = (scope, decl, _global, _name) => {
|
|
1189
1316
|
// hack: basically treat this as a normal call for builtins for now
|
1190
1317
|
const name = mapName(decl.callee.name);
|
1191
1318
|
if (internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1192
|
-
if (!builtinFuncs[name]) return todo(`new statement is not supported yet (new ${unhackName(name)})`);
|
1319
|
+
if (!builtinFuncs[name]) return todo(`new statement is not supported yet`); // return todo(`new statement is not supported yet (new ${unhackName(name)})`);
|
1193
1320
|
|
1194
1321
|
return generateCall(scope, decl, _global, _name);
|
1195
1322
|
};
|
@@ -1297,8 +1424,6 @@ const generateAssign = (scope, decl) => {
|
|
1297
1424
|
const name = decl.left.object.name;
|
1298
1425
|
const pointer = arrays.get(name);
|
1299
1426
|
|
1300
|
-
scope.memory = true;
|
1301
|
-
|
1302
1427
|
const aotPointer = pointer != null;
|
1303
1428
|
|
1304
1429
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
@@ -1319,13 +1444,60 @@ const generateAssign = (scope, decl) => {
|
|
1319
1444
|
];
|
1320
1445
|
}
|
1321
1446
|
|
1447
|
+
const op = decl.operator.slice(0, -1) || '=';
|
1448
|
+
|
1449
|
+
// arr[i] | str[i]
|
1450
|
+
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
1451
|
+
const name = decl.left.object.name;
|
1452
|
+
const pointer = arrays.get(name);
|
1453
|
+
|
1454
|
+
const aotPointer = pointer != null;
|
1455
|
+
|
1456
|
+
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
1457
|
+
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
1458
|
+
|
1459
|
+
const parentType = getNodeType(scope, decl.left.object);
|
1460
|
+
|
1461
|
+
return [
|
1462
|
+
...(aotPointer ? [] : [
|
1463
|
+
...generate(scope, decl.left.object),
|
1464
|
+
Opcodes.i32_to_u
|
1465
|
+
]),
|
1466
|
+
|
1467
|
+
// get index as valtype
|
1468
|
+
...generate(scope, decl.left.property),
|
1469
|
+
|
1470
|
+
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
1471
|
+
Opcodes.i32_to_u,
|
1472
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
1473
|
+
[ Opcodes.i32_mul ],
|
1474
|
+
...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
1475
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
1476
|
+
|
1477
|
+
...(op === '=' ? generate(scope, decl.right, false, name) : performOp(scope, op, [
|
1478
|
+
[ Opcodes.local_get, pointerTmp ],
|
1479
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1480
|
+
], generate(scope, decl.right), parentType === TYPES._array ? TYPES.number : TYPES.string, getNodeType(scope, decl.right), false, name, true)),
|
1481
|
+
[ Opcodes.local_tee, newValueTmp ],
|
1482
|
+
|
1483
|
+
...(parentType === TYPES._array ? [
|
1484
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1485
|
+
] : [
|
1486
|
+
Opcodes.i32_to_u,
|
1487
|
+
[ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1488
|
+
]),
|
1489
|
+
|
1490
|
+
[ Opcodes.local_get, newValueTmp ]
|
1491
|
+
];
|
1492
|
+
}
|
1493
|
+
|
1322
1494
|
const [ local, isGlobal ] = lookupName(scope, name);
|
1323
1495
|
|
1324
1496
|
if (local === undefined) {
|
1325
1497
|
// todo: this should be a devtools/repl/??? only thing
|
1326
1498
|
|
1327
1499
|
// only allow = for this
|
1328
|
-
if (
|
1500
|
+
if (op !== '=') return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`);
|
1329
1501
|
|
1330
1502
|
if (builtinVars[name]) {
|
1331
1503
|
// just return rhs (eg `NaN = 2`)
|
@@ -1339,8 +1511,10 @@ const generateAssign = (scope, decl) => {
|
|
1339
1511
|
];
|
1340
1512
|
}
|
1341
1513
|
|
1342
|
-
|
1343
|
-
|
1514
|
+
typeStates[name] = getNodeType(scope, decl.right);
|
1515
|
+
|
1516
|
+
if (op === '=') {
|
1517
|
+
// typeStates[name] = getNodeType(scope, decl.right);
|
1344
1518
|
|
1345
1519
|
return [
|
1346
1520
|
...generate(scope, decl.right, isGlobal, name),
|
@@ -1349,8 +1523,26 @@ const generateAssign = (scope, decl) => {
|
|
1349
1523
|
];
|
1350
1524
|
}
|
1351
1525
|
|
1526
|
+
if (op === '||' || op === '&&' || op === '??') {
|
1527
|
+
// todo: is this needed?
|
1528
|
+
// for logical assignment ops, it is not left @= right ~= left = left @ right
|
1529
|
+
// instead, left @ (left = right)
|
1530
|
+
// eg, x &&= y ~= x && (x = y)
|
1531
|
+
|
1532
|
+
return [
|
1533
|
+
...performOp(scope, op, [
|
1534
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1535
|
+
], [
|
1536
|
+
...generate(scope, decl.right),
|
1537
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
1538
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1539
|
+
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
1540
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1541
|
+
];
|
1542
|
+
}
|
1543
|
+
|
1352
1544
|
return [
|
1353
|
-
...performOp(scope,
|
1545
|
+
...performOp(scope, op, [ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ] ], generate(scope, decl.right), getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
1354
1546
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
1355
1547
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1356
1548
|
];
|
@@ -1377,13 +1569,14 @@ const generateUnary = (scope, decl) => {
|
|
1377
1569
|
|
1378
1570
|
case '!':
|
1379
1571
|
// !=
|
1380
|
-
return falsy(scope, generate(scope, decl.argument));
|
1572
|
+
return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument));
|
1381
1573
|
|
1382
1574
|
case '~':
|
1575
|
+
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
1383
1576
|
return [
|
1384
1577
|
...generate(scope, decl.argument),
|
1385
1578
|
Opcodes.i32_to,
|
1386
|
-
[ Opcodes.i32_const, signedLEB128(-1) ],
|
1579
|
+
[ Opcodes.i32_const, ...signedLEB128(-1) ],
|
1387
1580
|
[ Opcodes.i32_xor ],
|
1388
1581
|
Opcodes.i32_from
|
1389
1582
|
];
|
@@ -1464,7 +1657,7 @@ const generateUpdate = (scope, decl) => {
|
|
1464
1657
|
};
|
1465
1658
|
|
1466
1659
|
const generateIf = (scope, decl) => {
|
1467
|
-
const out = truthy(scope, generate(scope, decl.test), decl.test);
|
1660
|
+
const out = truthy(scope, generate(scope, decl.test), getNodeType(scope, decl.test));
|
1468
1661
|
|
1469
1662
|
out.push(Opcodes.i32_to, [ Opcodes.if, Blocktype.void ]);
|
1470
1663
|
depth.push('if');
|
@@ -1557,18 +1750,106 @@ const generateWhile = (scope, decl) => {
|
|
1557
1750
|
const generateForOf = (scope, decl) => {
|
1558
1751
|
const out = [];
|
1559
1752
|
|
1753
|
+
const rightType = getNodeType(scope, decl.right);
|
1754
|
+
const valtypeSize = rightType === TYPES._array ? ValtypeSize[valtype] : ValtypeSize.i16; // presume array (:()
|
1755
|
+
|
1756
|
+
// todo: for of inside for of might fuck up?
|
1757
|
+
const pointer = localTmp(scope, 'forof_base_pointer', Valtype.i32);
|
1758
|
+
const length = localTmp(scope, 'forof_length', Valtype.i32);
|
1759
|
+
const counter = localTmp(scope, 'forof_counter', Valtype.i32);
|
1760
|
+
|
1761
|
+
out.push(
|
1762
|
+
// set pointer as right
|
1763
|
+
...generate(scope, decl.right),
|
1764
|
+
Opcodes.i32_to_u,
|
1765
|
+
[ Opcodes.local_set, pointer ],
|
1766
|
+
|
1767
|
+
// get length
|
1768
|
+
[ Opcodes.local_get, pointer ],
|
1769
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
1770
|
+
[ Opcodes.local_set, length ]
|
1771
|
+
);
|
1772
|
+
|
1560
1773
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
1561
|
-
depth.push('
|
1774
|
+
depth.push('forof');
|
1562
1775
|
|
1563
|
-
|
1564
|
-
|
1565
|
-
depth.push('if');
|
1776
|
+
// setup local for left
|
1777
|
+
generate(scope, decl.left);
|
1566
1778
|
|
1567
|
-
|
1779
|
+
const leftName = decl.left.declarations[0].id.name;
|
1568
1780
|
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1781
|
+
// set type for local
|
1782
|
+
typeStates[leftName] = rightType === TYPES._array ? TYPES.number : TYPES.string;
|
1783
|
+
|
1784
|
+
const [ local, isGlobal ] = lookupName(scope, leftName);
|
1785
|
+
|
1786
|
+
if (rightType === TYPES._array) { // array
|
1787
|
+
out.push(
|
1788
|
+
[ Opcodes.local_get, pointer ],
|
1789
|
+
[ Opcodes.load, Math.log2(valtypeSize) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
1790
|
+
);
|
1791
|
+
} else { // string
|
1792
|
+
const [ newOut, newPointer ] = makeArray(scope, {
|
1793
|
+
rawElements: new Array(1)
|
1794
|
+
}, isGlobal, leftName, true, 'i16');
|
1795
|
+
|
1796
|
+
out.push(
|
1797
|
+
// setup new/out array
|
1798
|
+
...newOut,
|
1799
|
+
[ Opcodes.drop ],
|
1800
|
+
|
1801
|
+
...number(0, Valtype.i32), // base 0 for store after
|
1802
|
+
|
1803
|
+
// load current string ind {arg}
|
1804
|
+
[ Opcodes.local_get, pointer ],
|
1805
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
1806
|
+
|
1807
|
+
// store to new string ind 0
|
1808
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
1809
|
+
|
1810
|
+
// return new string (page)
|
1811
|
+
...number(newPointer)
|
1812
|
+
);
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
// set left value
|
1816
|
+
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ]);
|
1817
|
+
|
1818
|
+
out.push(
|
1819
|
+
[ Opcodes.block, Blocktype.void ],
|
1820
|
+
[ Opcodes.block, Blocktype.void ]
|
1821
|
+
);
|
1822
|
+
depth.push('block');
|
1823
|
+
depth.push('block');
|
1824
|
+
|
1825
|
+
out.push(
|
1826
|
+
...generate(scope, decl.body),
|
1827
|
+
[ Opcodes.end ]
|
1828
|
+
);
|
1829
|
+
depth.pop();
|
1830
|
+
|
1831
|
+
out.push(
|
1832
|
+
// increment iter pointer by valtype size
|
1833
|
+
[ Opcodes.local_get, pointer ],
|
1834
|
+
...number(valtypeSize, Valtype.i32),
|
1835
|
+
[ Opcodes.i32_add ],
|
1836
|
+
[ Opcodes.local_set, pointer ],
|
1837
|
+
|
1838
|
+
// increment counter by 1
|
1839
|
+
[ Opcodes.local_get, counter ],
|
1840
|
+
...number(1, Valtype.i32),
|
1841
|
+
[ Opcodes.i32_add ],
|
1842
|
+
[ Opcodes.local_tee, counter ],
|
1843
|
+
|
1844
|
+
// loop if counter != length
|
1845
|
+
[ Opcodes.local_get, length ],
|
1846
|
+
[ Opcodes.i32_ne ],
|
1847
|
+
[ Opcodes.br_if, 1 ],
|
1848
|
+
|
1849
|
+
[ Opcodes.end ], [ Opcodes.end ]
|
1850
|
+
);
|
1851
|
+
depth.pop();
|
1852
|
+
depth.pop();
|
1572
1853
|
|
1573
1854
|
return out;
|
1574
1855
|
};
|
@@ -1659,13 +1940,22 @@ const generateAssignPat = (scope, decl) => {
|
|
1659
1940
|
};
|
1660
1941
|
|
1661
1942
|
let pages = new Map();
|
1662
|
-
const allocPage = reason => {
|
1663
|
-
if (pages.has(reason)) return pages.get(reason);
|
1943
|
+
const allocPage = (reason, type) => {
|
1944
|
+
if (pages.has(reason)) return pages.get(reason).ind;
|
1945
|
+
|
1946
|
+
const ind = pages.size;
|
1947
|
+
pages.set(reason, { ind, type });
|
1948
|
+
|
1949
|
+
if (allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
1950
|
+
|
1951
|
+
return ind;
|
1952
|
+
};
|
1664
1953
|
|
1665
|
-
|
1666
|
-
pages.
|
1954
|
+
const freePage = reason => {
|
1955
|
+
const { ind } = pages.get(reason);
|
1956
|
+
pages.delete(reason);
|
1667
1957
|
|
1668
|
-
if (
|
1958
|
+
if (allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
1669
1959
|
|
1670
1960
|
return ind;
|
1671
1961
|
};
|
@@ -1679,7 +1969,7 @@ const itemTypeToValtype = {
|
|
1679
1969
|
i16: 'i32'
|
1680
1970
|
};
|
1681
1971
|
|
1682
|
-
const
|
1972
|
+
const StoreOps = {
|
1683
1973
|
i32: Opcodes.i32_store,
|
1684
1974
|
i64: Opcodes.i64_store,
|
1685
1975
|
f64: Opcodes.f64_store,
|
@@ -1688,13 +1978,28 @@ const storeOps = {
|
|
1688
1978
|
i16: Opcodes.i32_store16
|
1689
1979
|
};
|
1690
1980
|
|
1981
|
+
let data = [];
|
1982
|
+
|
1983
|
+
const compileBytes = (val, itemType, signed = true) => {
|
1984
|
+
switch (itemType) {
|
1985
|
+
case 'i8': return enforceOneByte(unsignedLEB128(val));
|
1986
|
+
case 'i16': return enforceTwoBytes(unsignedLEB128(val));
|
1987
|
+
case 'i32': return enforceFourBytes(signedLEB128(val));
|
1988
|
+
case 'i64': return enforceEightBytes(signedLEB128(val));
|
1989
|
+
case 'f64': return enforceEightBytes(ieee754_binary64(val));
|
1990
|
+
}
|
1991
|
+
};
|
1992
|
+
|
1691
1993
|
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
|
1692
1994
|
const out = [];
|
1693
1995
|
|
1996
|
+
let firstAssign = false;
|
1694
1997
|
if (!arrays.has(name) || name === '$undeclared') {
|
1998
|
+
firstAssign = true;
|
1999
|
+
|
1695
2000
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
1696
2001
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
1697
|
-
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}
|
2002
|
+
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}`, itemType) * pageSize);
|
1698
2003
|
}
|
1699
2004
|
|
1700
2005
|
const pointer = arrays.get(name);
|
@@ -1702,8 +2007,29 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1702
2007
|
const useRawElements = !!decl.rawElements;
|
1703
2008
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
1704
2009
|
|
2010
|
+
const valtype = itemTypeToValtype[itemType];
|
1705
2011
|
const length = elements.length;
|
1706
2012
|
|
2013
|
+
if (firstAssign && useRawElements) {
|
2014
|
+
let bytes = compileBytes(length, 'i32');
|
2015
|
+
|
2016
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
2017
|
+
if (elements[i] == null) continue;
|
2018
|
+
|
2019
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
2020
|
+
}
|
2021
|
+
|
2022
|
+
data.push({
|
2023
|
+
offset: pointer,
|
2024
|
+
bytes
|
2025
|
+
});
|
2026
|
+
|
2027
|
+
// local value as pointer
|
2028
|
+
out.push(...number(pointer));
|
2029
|
+
|
2030
|
+
return [ out, pointer ];
|
2031
|
+
}
|
2032
|
+
|
1707
2033
|
// store length as 0th array
|
1708
2034
|
out.push(
|
1709
2035
|
...number(0, Valtype.i32),
|
@@ -1711,8 +2037,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1711
2037
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1712
2038
|
);
|
1713
2039
|
|
1714
|
-
const storeOp =
|
1715
|
-
const valtype = itemTypeToValtype[itemType];
|
2040
|
+
const storeOp = StoreOps[itemType];
|
1716
2041
|
|
1717
2042
|
if (!initEmpty) for (let i = 0; i < length; i++) {
|
1718
2043
|
if (elements[i] == null) continue;
|
@@ -1727,8 +2052,6 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1727
2052
|
// local value as pointer
|
1728
2053
|
out.push(...number(pointer));
|
1729
2054
|
|
1730
|
-
scope.memory = true;
|
1731
|
-
|
1732
2055
|
return [ out, pointer ];
|
1733
2056
|
};
|
1734
2057
|
|
@@ -1747,8 +2070,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
1747
2070
|
const name = decl.object.name;
|
1748
2071
|
const pointer = arrays.get(name);
|
1749
2072
|
|
1750
|
-
scope.memory = true;
|
1751
|
-
|
1752
2073
|
const aotPointer = pointer != null;
|
1753
2074
|
|
1754
2075
|
return [
|
@@ -1768,8 +2089,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
1768
2089
|
const name = decl.object.name;
|
1769
2090
|
const pointer = arrays.get(name);
|
1770
2091
|
|
1771
|
-
scope.memory = true;
|
1772
|
-
|
1773
2092
|
const aotPointer = pointer != null;
|
1774
2093
|
|
1775
2094
|
if (type === TYPES._array) {
|
@@ -1879,7 +2198,7 @@ const generateFunc = (scope, decl) => {
|
|
1879
2198
|
locals: {},
|
1880
2199
|
localInd: 0,
|
1881
2200
|
returns: [ valtypeBinary ],
|
1882
|
-
|
2201
|
+
returnType: null,
|
1883
2202
|
throws: false,
|
1884
2203
|
name
|
1885
2204
|
};
|
@@ -1905,7 +2224,6 @@ const generateFunc = (scope, decl) => {
|
|
1905
2224
|
returns: innerScope.returns,
|
1906
2225
|
returnType: innerScope.returnType,
|
1907
2226
|
locals: innerScope.locals,
|
1908
|
-
memory: innerScope.memory,
|
1909
2227
|
throws: innerScope.throws,
|
1910
2228
|
index: currentFuncIndex++
|
1911
2229
|
};
|
@@ -1920,6 +2238,8 @@ const generateFunc = (scope, decl) => {
|
|
1920
2238
|
|
1921
2239
|
if (name !== 'main' && func.returns.length !== 0 && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
1922
2240
|
wasm.push(...number(0), [ Opcodes.return ]);
|
2241
|
+
|
2242
|
+
if (func.returnType === null) func.returnType = TYPES.undefined;
|
1923
2243
|
}
|
1924
2244
|
|
1925
2245
|
// change v128 params into many <type> (i32x4 -> i32/etc) instead as unsupported param valtype
|
@@ -1930,9 +2250,7 @@ const generateFunc = (scope, decl) => {
|
|
1930
2250
|
if (local.type === Valtype.v128) {
|
1931
2251
|
vecParams++;
|
1932
2252
|
|
1933
|
-
/*
|
1934
|
-
|
1935
|
-
wasm.unshift( // add v128 load for param
|
2253
|
+
/* wasm.unshift( // add v128 load for param
|
1936
2254
|
[ Opcodes.i32_const, 0 ],
|
1937
2255
|
[ ...Opcodes.v128_load, 0, i * 16 ],
|
1938
2256
|
[ Opcodes.local_set, local.idx ]
|
@@ -2043,10 +2361,10 @@ const generateFunc = (scope, decl) => {
|
|
2043
2361
|
};
|
2044
2362
|
|
2045
2363
|
const generateCode = (scope, decl) => {
|
2046
|
-
|
2364
|
+
let out = [];
|
2047
2365
|
|
2048
2366
|
for (const x of decl.body) {
|
2049
|
-
out.
|
2367
|
+
out = out.concat(generate(scope, x));
|
2050
2368
|
}
|
2051
2369
|
|
2052
2370
|
return out;
|
@@ -2096,6 +2414,7 @@ export default program => {
|
|
2096
2414
|
typeStates = {};
|
2097
2415
|
arrays = new Map();
|
2098
2416
|
pages = new Map();
|
2417
|
+
data = [];
|
2099
2418
|
currentFuncIndex = importedFuncs.length;
|
2100
2419
|
|
2101
2420
|
globalThis.valtype = 'f64';
|
@@ -2172,5 +2491,5 @@ export default program => {
|
|
2172
2491
|
// if blank main func and other exports, remove it
|
2173
2492
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(funcs.length - 1, 1);
|
2174
2493
|
|
2175
|
-
return { funcs, globals, tags, exceptions, pages };
|
2494
|
+
return { funcs, globals, tags, exceptions, pages, data };
|
2176
2495
|
};
|