porffor 0.16.0-e5b6b94c8 → 0.16.0-f9dde1759
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 +4 -3
- package/compiler/2c.js +53 -65
- package/compiler/assemble.js +5 -4
- package/compiler/builtins/console.ts +1 -1
- package/compiler/builtins/porffor.d.ts +11 -0
- package/compiler/builtins/set.ts +3 -2
- package/compiler/builtins/symbol.ts +6 -6
- package/compiler/builtins.js +25 -5
- package/compiler/codegen.js +20 -42
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +3 -1
- package/compiler/generated_builtins.js +1 -1
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +89 -6
- package/compiler/opt.js +3 -39
- package/compiler/parse.js +2 -2
- package/compiler/pgo.js +207 -0
- package/compiler/precompile.js +3 -1
- package/compiler/prefs.js +6 -1
- package/compiler/wrap.js +53 -12
- package/no_pgo.txt +923 -0
- package/package.json +3 -5
- package/pgo.txt +916 -0
- package/runner/index.js +21 -11
- /package/runner/{profiler.js → profile.js} +0 -0
package/compiler/codegen.js
CHANGED
@@ -1078,7 +1078,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1078
1078
|
locals,
|
1079
1079
|
localInd: allLocals.length,
|
1080
1080
|
returns,
|
1081
|
-
returnType
|
1081
|
+
returnType,
|
1082
1082
|
internal: true,
|
1083
1083
|
index: currentFuncIndex++,
|
1084
1084
|
table
|
@@ -1254,7 +1254,7 @@ const getNodeType = (scope, node) => {
|
|
1254
1254
|
const func = funcs.find(x => x.name === name);
|
1255
1255
|
|
1256
1256
|
if (func) {
|
1257
|
-
if (func.returnType) return func.returnType;
|
1257
|
+
if (func.returnType != null) return func.returnType;
|
1258
1258
|
}
|
1259
1259
|
|
1260
1260
|
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
|
@@ -1270,15 +1270,7 @@ const getNodeType = (scope, node) => {
|
|
1270
1270
|
const func = spl[spl.length - 1];
|
1271
1271
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1272
1272
|
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;
|
1273
|
+
if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
|
1282
1274
|
}
|
1283
1275
|
}
|
1284
1276
|
|
@@ -1815,7 +1807,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1815
1807
|
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1816
1808
|
|
1817
1809
|
// value
|
1818
|
-
i32_const: { imms: 1, args: [], returns:
|
1810
|
+
i32_const: { imms: 1, args: [], returns: 0 },
|
1819
1811
|
};
|
1820
1812
|
|
1821
1813
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1978,7 +1970,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
1970
|
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1979
1971
|
const userFunc = func && !func.internal;
|
1980
1972
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1981
|
-
const typedReturns = (
|
1973
|
+
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1982
1974
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1983
1975
|
|
1984
1976
|
let args = decl.arguments;
|
@@ -2007,8 +1999,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2007
1999
|
}
|
2008
2000
|
|
2009
2001
|
if (valtypeBinary !== Valtype.i32 && (
|
2010
|
-
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2011
|
-
(importedFuncs[name] && name.startsWith('profile'))
|
2002
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2003
|
+
// (importedFuncs[name] && name.startsWith('profile'))
|
2012
2004
|
)) {
|
2013
2005
|
out.push(Opcodes.i32_to);
|
2014
2006
|
}
|
@@ -2123,7 +2115,6 @@ const brTable = (input, bc, returns) => {
|
|
2123
2115
|
}
|
2124
2116
|
|
2125
2117
|
for (let i = 0; i < count; i++) {
|
2126
|
-
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2127
2118
|
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2128
2119
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2129
2120
|
}
|
@@ -2157,10 +2148,8 @@ const brTable = (input, bc, returns) => {
|
|
2157
2148
|
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
2158
2149
|
);
|
2159
2150
|
|
2160
|
-
//
|
2161
|
-
// (
|
2162
|
-
// dm me and if you are correct and the first person
|
2163
|
-
// I will somehow shout you out or something
|
2151
|
+
// sort the wrong way and then reverse
|
2152
|
+
// so strings ('default') are at the start before any numbers
|
2164
2153
|
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
2165
2154
|
|
2166
2155
|
br = count - 1;
|
@@ -2186,10 +2175,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2186
2175
|
return bc[known] ?? bc.default;
|
2187
2176
|
}
|
2188
2177
|
|
2189
|
-
if (Prefs.
|
2178
|
+
if (Prefs.typeswitchBrtable)
|
2190
2179
|
return brTable(type, bc, returns);
|
2191
2180
|
|
2192
|
-
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
2181
|
+
const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
|
2193
2182
|
const out = [
|
2194
2183
|
...type,
|
2195
2184
|
[ Opcodes.local_set, tmp ],
|
@@ -2571,7 +2560,7 @@ const generateUnary = (scope, decl) => {
|
|
2571
2560
|
// * -1
|
2572
2561
|
|
2573
2562
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
2574
|
-
// if
|
2563
|
+
// if -n, just return that as a const
|
2575
2564
|
return number(-1 * decl.argument.value);
|
2576
2565
|
}
|
2577
2566
|
|
@@ -2582,15 +2571,15 @@ const generateUnary = (scope, decl) => {
|
|
2582
2571
|
|
2583
2572
|
case '!':
|
2584
2573
|
const arg = decl.argument;
|
2585
|
-
if (arg.type ===
|
2586
|
-
// !!x -> is x truthy
|
2574
|
+
if (arg.type === 'UnaryExpression' && arg.operator === '!') {
|
2575
|
+
// opt: !!x -> is x truthy
|
2587
2576
|
return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
|
2588
2577
|
}
|
2578
|
+
|
2589
2579
|
// !=
|
2590
|
-
return falsy(scope, generate(scope,
|
2580
|
+
return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
|
2591
2581
|
|
2592
2582
|
case '~':
|
2593
|
-
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
2594
2583
|
return [
|
2595
2584
|
...generate(scope, decl.argument),
|
2596
2585
|
Opcodes.i32_to,
|
@@ -3278,7 +3267,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3278
3267
|
firstAssign = true;
|
3279
3268
|
|
3280
3269
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3281
|
-
const uniqueName = name === '$undeclared' ? name +
|
3270
|
+
const uniqueName = name === '$undeclared' ? name + randId() : name;
|
3282
3271
|
|
3283
3272
|
let page;
|
3284
3273
|
if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
|
@@ -3510,7 +3499,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3510
3499
|
}
|
3511
3500
|
|
3512
3501
|
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);
|
3502
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3514
3503
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3515
3504
|
|
3516
3505
|
if (Prefs.fastLength) {
|
@@ -3666,7 +3655,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3666
3655
|
});
|
3667
3656
|
};
|
3668
3657
|
|
3669
|
-
const randId = () => Math.random().toString(16).slice(
|
3658
|
+
const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
|
3670
3659
|
|
3671
3660
|
const objectHack = node => {
|
3672
3661
|
if (!node) return node;
|
@@ -3718,7 +3707,7 @@ const generateFunc = (scope, decl) => {
|
|
3718
3707
|
if (decl.async) return todo(scope, 'async functions are not supported');
|
3719
3708
|
if (decl.generator) return todo(scope, 'generator functions are not supported');
|
3720
3709
|
|
3721
|
-
const name = decl.id ? decl.id.name : `
|
3710
|
+
const name = decl.id ? decl.id.name : `anonymous${randId()}`;
|
3722
3711
|
const params = decl.params ?? [];
|
3723
3712
|
|
3724
3713
|
// TODO: share scope/locals between !!!
|
@@ -3979,19 +3968,8 @@ export default program => {
|
|
3979
3968
|
data = [];
|
3980
3969
|
currentFuncIndex = importedFuncs.length;
|
3981
3970
|
|
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
3971
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3990
3972
|
|
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
3973
|
// set generic opcodes for current valtype
|
3996
3974
|
Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
|
3997
3975
|
Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
|
@@ -0,0 +1,535 @@
|
|
1
|
+
// cyclone: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
|
2
|
+
import { signedLEB128, ieee754_binary64, read_ieee754_binary64, read_signedLEB128 } from './encoding.js';
|
3
|
+
import { Opcodes, Valtype } from './wasmSpec.js';
|
4
|
+
|
5
|
+
const number = (n, valtype = valtypeBinary) => {
|
6
|
+
switch (valtype) {
|
7
|
+
case Valtype.i32: return [ Opcodes.i32_const, ...signedLEB128(n) ];
|
8
|
+
case Valtype.i64: return [ Opcodes.i64_const, ...signedLEB128(n) ];
|
9
|
+
case Valtype.f64: return [ Opcodes.f64_const, ...ieee754_binary64(n) ];
|
10
|
+
}
|
11
|
+
};
|
12
|
+
|
13
|
+
const f64ToI32Op = {
|
14
|
+
[Opcodes.f64_eq]: Opcodes.i32_eq,
|
15
|
+
[Opcodes.f64_ne]: Opcodes.i32_ne,
|
16
|
+
[Opcodes.f64_lt]: Opcodes.i32_lt_s,
|
17
|
+
[Opcodes.f64_le]: Opcodes.i32_le_s,
|
18
|
+
[Opcodes.f64_gt]: Opcodes.i32_gt_s,
|
19
|
+
[Opcodes.f64_ge]: Opcodes.i32_ge_s,
|
20
|
+
[Opcodes.f64_add]: Opcodes.i32_add,
|
21
|
+
[Opcodes.f64_sub]: Opcodes.i32_sub,
|
22
|
+
[Opcodes.f64_mul]: Opcodes.i32_mul,
|
23
|
+
[Opcodes.f64_div]: Opcodes.i32_div_s,
|
24
|
+
};
|
25
|
+
|
26
|
+
export default wasm => {
|
27
|
+
let stack = []; // """""stack"""""
|
28
|
+
for (let i = 0; i < wasm.length; i++) {
|
29
|
+
let op = wasm[i];
|
30
|
+
if (!op) continue;
|
31
|
+
|
32
|
+
// op = [ ...op.filter(x => x != null && x <= 0xff) ];
|
33
|
+
op = [ ...op ];
|
34
|
+
wasm[i] = op;
|
35
|
+
|
36
|
+
let opcode = op[0];
|
37
|
+
if (opcode === 0xfc) { // multibyte op
|
38
|
+
opcode = (opcode << 8) + op[1];
|
39
|
+
}
|
40
|
+
|
41
|
+
const push = val => {
|
42
|
+
stack.push({ val, op });
|
43
|
+
};
|
44
|
+
|
45
|
+
const pop = () => {
|
46
|
+
const popped = stack.pop();
|
47
|
+
|
48
|
+
// remove the op
|
49
|
+
wasm.splice(wasm.indexOf(popped.op), 1);
|
50
|
+
i--;
|
51
|
+
|
52
|
+
return popped.val;
|
53
|
+
};
|
54
|
+
|
55
|
+
const pop2 = () => [ pop(), pop() ];
|
56
|
+
|
57
|
+
const bool = v => v ? 1 : 0;
|
58
|
+
|
59
|
+
const replaceOp = newOp => {
|
60
|
+
op.splice(0, op.length, ...newOp);
|
61
|
+
};
|
62
|
+
const replaceVal = (val, valtype) => replaceOp(number(val, valtype));
|
63
|
+
|
64
|
+
const empty = () => {
|
65
|
+
stack = [];
|
66
|
+
};
|
67
|
+
|
68
|
+
switch (opcode) {
|
69
|
+
case Opcodes.i32_const: {
|
70
|
+
const n = read_signedLEB128(op.slice(1));
|
71
|
+
push(n);
|
72
|
+
break;
|
73
|
+
}
|
74
|
+
case Opcodes.f64_const: {
|
75
|
+
const n = read_ieee754_binary64(op.slice(1));
|
76
|
+
push(n);
|
77
|
+
break;
|
78
|
+
}
|
79
|
+
|
80
|
+
case Opcodes.i32_eqz: {
|
81
|
+
if (stack.length < 1) { empty(); break; };
|
82
|
+
const v = bool(pop() === 0);
|
83
|
+
|
84
|
+
replaceVal(v, Valtype.i32);
|
85
|
+
push(v);
|
86
|
+
break;
|
87
|
+
}
|
88
|
+
case Opcodes.i32_eq: {
|
89
|
+
if (stack.length < 2) { empty(); break; };
|
90
|
+
const [ b, a ] = pop2();
|
91
|
+
const v = bool(a === b);
|
92
|
+
|
93
|
+
replaceVal(v, Valtype.i32);
|
94
|
+
push(v);
|
95
|
+
break;
|
96
|
+
}
|
97
|
+
case Opcodes.i32_ne: {
|
98
|
+
if (stack.length < 2) { empty(); break; };
|
99
|
+
const [ b, a ] = pop2();
|
100
|
+
const v = bool(a !== b);
|
101
|
+
|
102
|
+
replaceVal(v, Valtype.i32);
|
103
|
+
push(v);
|
104
|
+
break;
|
105
|
+
}
|
106
|
+
case Opcodes.i32_lt_s: {
|
107
|
+
if (stack.length < 2) { empty(); break; };
|
108
|
+
const [ b, a ] = pop2();
|
109
|
+
const v = bool(a < b);
|
110
|
+
|
111
|
+
replaceVal(v, Valtype.i32);
|
112
|
+
push(v);
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
case Opcodes.i32_le_s: {
|
116
|
+
if (stack.length < 2) { empty(); break; };
|
117
|
+
const [ b, a ] = pop2();
|
118
|
+
const v = bool(a <= b);
|
119
|
+
|
120
|
+
replaceVal(v, Valtype.i32);
|
121
|
+
push(v);
|
122
|
+
break;
|
123
|
+
}
|
124
|
+
case Opcodes.i32_gt_s: {
|
125
|
+
if (stack.length < 2) { empty(); break; };
|
126
|
+
const [ b, a ] = pop2();
|
127
|
+
const v = bool(a > b);
|
128
|
+
|
129
|
+
replaceVal(v, Valtype.i32);
|
130
|
+
push(v);
|
131
|
+
break;
|
132
|
+
}
|
133
|
+
case Opcodes.i32_ge_s: {
|
134
|
+
if (stack.length < 2) { empty(); break; };
|
135
|
+
const [ b, a ] = pop2();
|
136
|
+
const v = bool(a >= b);
|
137
|
+
|
138
|
+
replaceVal(v, Valtype.i32);
|
139
|
+
push(v);
|
140
|
+
break;
|
141
|
+
}
|
142
|
+
|
143
|
+
case Opcodes.i32_add: {
|
144
|
+
if (stack.length < 2) { empty(); break; };
|
145
|
+
const [ b, a ] = pop2();
|
146
|
+
const v = a + b;
|
147
|
+
|
148
|
+
replaceVal(v, Valtype.i32);
|
149
|
+
push(v);
|
150
|
+
break;
|
151
|
+
}
|
152
|
+
case Opcodes.i32_sub: {
|
153
|
+
if (stack.length < 2) { empty(); break; };
|
154
|
+
const [ b, a ] = pop2();
|
155
|
+
const v = a - b;
|
156
|
+
|
157
|
+
replaceVal(v, Valtype.i32);
|
158
|
+
push(v);
|
159
|
+
break;
|
160
|
+
}
|
161
|
+
case Opcodes.i32_mul: {
|
162
|
+
if (stack.length < 2) { empty(); break; };
|
163
|
+
const [ b, a ] = pop2();
|
164
|
+
const v = a * b;
|
165
|
+
|
166
|
+
replaceVal(v, Valtype.i32);
|
167
|
+
push(v);
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
case Opcodes.i32_div_s: {
|
171
|
+
if (stack.length < 2) { empty(); break; };
|
172
|
+
const [ b, a ] = pop2();
|
173
|
+
const v = a / b;
|
174
|
+
|
175
|
+
replaceVal(v, Valtype.i32);
|
176
|
+
push(v);
|
177
|
+
break;
|
178
|
+
}
|
179
|
+
case Opcodes.i32_rem_s: {
|
180
|
+
if (stack.length < 2) { empty(); break; };
|
181
|
+
const [ b, a ] = pop2();
|
182
|
+
const v = a % b; // not rem but good enough
|
183
|
+
|
184
|
+
replaceVal(v, Valtype.i32);
|
185
|
+
push(v);
|
186
|
+
break;
|
187
|
+
}
|
188
|
+
|
189
|
+
case Opcodes.i32_and: {
|
190
|
+
if (stack.length < 2) { empty(); break; };
|
191
|
+
const [ b, a ] = pop2();
|
192
|
+
const v = a & b;
|
193
|
+
|
194
|
+
replaceVal(v, Valtype.i32);
|
195
|
+
push(v);
|
196
|
+
break;
|
197
|
+
}
|
198
|
+
case Opcodes.i32_or: {
|
199
|
+
if (stack.length < 2) { empty(); break; };
|
200
|
+
const [ b, a ] = pop2();
|
201
|
+
const v = a | b;
|
202
|
+
|
203
|
+
replaceVal(v, Valtype.i32);
|
204
|
+
push(v);
|
205
|
+
break;
|
206
|
+
}
|
207
|
+
case Opcodes.i32_xor: {
|
208
|
+
if (stack.length < 2) { empty(); break; };
|
209
|
+
const [ b, a ] = pop2();
|
210
|
+
const v = a ^ b;
|
211
|
+
|
212
|
+
replaceVal(v, Valtype.i32);
|
213
|
+
push(v);
|
214
|
+
break;
|
215
|
+
}
|
216
|
+
case Opcodes.i32_shl: {
|
217
|
+
if (stack.length < 2) { empty(); break; };
|
218
|
+
const [ b, a ] = pop2();
|
219
|
+
const v = a << b;
|
220
|
+
|
221
|
+
replaceVal(v, Valtype.i32);
|
222
|
+
push(v);
|
223
|
+
break;
|
224
|
+
}
|
225
|
+
case Opcodes.i32_shr_s: {
|
226
|
+
if (stack.length < 2) { empty(); break; };
|
227
|
+
const [ b, a ] = pop2();
|
228
|
+
const v = a >> b;
|
229
|
+
|
230
|
+
replaceVal(v, Valtype.i32);
|
231
|
+
push(v);
|
232
|
+
break;
|
233
|
+
}
|
234
|
+
case Opcodes.i32_shr_u: {
|
235
|
+
if (stack.length < 2) { empty(); break; };
|
236
|
+
const [ b, a ] = pop2();
|
237
|
+
const v = a >>> b;
|
238
|
+
|
239
|
+
replaceVal(v, Valtype.i32);
|
240
|
+
push(v);
|
241
|
+
break;
|
242
|
+
}
|
243
|
+
|
244
|
+
case Opcodes.f64_eq: {
|
245
|
+
if (stack.length < 2) { empty(); break; };
|
246
|
+
const [ b, a ] = pop2();
|
247
|
+
const v = bool(a === b);
|
248
|
+
|
249
|
+
replaceVal(v, Valtype.f64);
|
250
|
+
push(v);
|
251
|
+
break;
|
252
|
+
}
|
253
|
+
case Opcodes.f64_ne: {
|
254
|
+
if (stack.length < 2) { empty(); break; };
|
255
|
+
const [ b, a ] = pop2();
|
256
|
+
const v = bool(a !== b);
|
257
|
+
|
258
|
+
replaceVal(v, Valtype.f64);
|
259
|
+
push(v);
|
260
|
+
break;
|
261
|
+
}
|
262
|
+
case Opcodes.f64_lt: {
|
263
|
+
if (stack.length < 2) { empty(); break; };
|
264
|
+
const [ b, a ] = pop2();
|
265
|
+
const v = bool(a < b);
|
266
|
+
|
267
|
+
replaceVal(v, Valtype.f64);
|
268
|
+
push(v);
|
269
|
+
break;
|
270
|
+
}
|
271
|
+
case Opcodes.f64_le: {
|
272
|
+
if (stack.length < 2) { empty(); break; };
|
273
|
+
const [ b, a ] = pop2();
|
274
|
+
const v = bool(a <= b);
|
275
|
+
|
276
|
+
replaceVal(v, Valtype.f64);
|
277
|
+
push(v);
|
278
|
+
break;
|
279
|
+
}
|
280
|
+
case Opcodes.f64_gt: {
|
281
|
+
if (stack.length < 2) { empty(); break; };
|
282
|
+
const [ b, a ] = pop2();
|
283
|
+
const v = bool(a > b);
|
284
|
+
|
285
|
+
replaceVal(v, Valtype.f64);
|
286
|
+
push(v);
|
287
|
+
break;
|
288
|
+
}
|
289
|
+
case Opcodes.f64_ge: {
|
290
|
+
if (stack.length < 2) { empty(); break; };
|
291
|
+
const [ b, a ] = pop2();
|
292
|
+
const v = bool(a >= b);
|
293
|
+
|
294
|
+
replaceVal(v, Valtype.f64);
|
295
|
+
push(v);
|
296
|
+
break;
|
297
|
+
}
|
298
|
+
|
299
|
+
case Opcodes.f64_abs: {
|
300
|
+
if (stack.length < 1) { empty(); break; };
|
301
|
+
const v = Math.abs(pop());
|
302
|
+
|
303
|
+
replaceVal(v, Valtype.f64);
|
304
|
+
push(v);
|
305
|
+
break;
|
306
|
+
}
|
307
|
+
case Opcodes.f64_neg: {
|
308
|
+
if (stack.length < 1) { empty(); break; };
|
309
|
+
const v = -pop();
|
310
|
+
|
311
|
+
replaceVal(v, Valtype.f64);
|
312
|
+
push(v);
|
313
|
+
break;
|
314
|
+
}
|
315
|
+
|
316
|
+
case Opcodes.f64_ceil: {
|
317
|
+
if (stack.length < 1) { empty(); break; };
|
318
|
+
const v = Math.ceil(pop());
|
319
|
+
|
320
|
+
replaceVal(v, Valtype.f64);
|
321
|
+
push(v);
|
322
|
+
break;
|
323
|
+
}
|
324
|
+
case Opcodes.f64_floor: {
|
325
|
+
if (stack.length < 1) { empty(); break; };
|
326
|
+
const v = Math.floor(pop());
|
327
|
+
|
328
|
+
replaceVal(v, Valtype.f64);
|
329
|
+
push(v);
|
330
|
+
break;
|
331
|
+
}
|
332
|
+
case Opcodes.f64_trunc: {
|
333
|
+
if (stack.length < 1) { empty(); break; };
|
334
|
+
const v = Math.trunc(pop());
|
335
|
+
|
336
|
+
replaceVal(v, Valtype.f64);
|
337
|
+
push(v);
|
338
|
+
break;
|
339
|
+
}
|
340
|
+
case Opcodes.f64_nearest: {
|
341
|
+
if (stack.length < 1) { empty(); break; };
|
342
|
+
const v = Math.round(pop());
|
343
|
+
|
344
|
+
replaceVal(v, Valtype.f64);
|
345
|
+
push(v);
|
346
|
+
break;
|
347
|
+
}
|
348
|
+
|
349
|
+
case Opcodes.f64_sqrt: {
|
350
|
+
if (stack.length < 1) { empty(); break; };
|
351
|
+
const v = Math.sqrt(pop());
|
352
|
+
|
353
|
+
replaceVal(v, Valtype.f64);
|
354
|
+
push(v);
|
355
|
+
break;
|
356
|
+
}
|
357
|
+
|
358
|
+
case Opcodes.f64_add: {
|
359
|
+
if (stack.length < 2) { empty(); break; };
|
360
|
+
const [ b, a ] = pop2();
|
361
|
+
const v = a + b;
|
362
|
+
|
363
|
+
replaceVal(v, Valtype.f64);
|
364
|
+
push(v);
|
365
|
+
break;
|
366
|
+
}
|
367
|
+
case Opcodes.f64_sub: {
|
368
|
+
if (stack.length < 2) { empty(); break; };
|
369
|
+
const [ b, a ] = pop2();
|
370
|
+
const v = a - b;
|
371
|
+
|
372
|
+
replaceVal(v, Valtype.f64);
|
373
|
+
push(v);
|
374
|
+
break;
|
375
|
+
}
|
376
|
+
case Opcodes.f64_mul: {
|
377
|
+
if (stack.length < 2) { empty(); break; };
|
378
|
+
const [ b, a ] = pop2();
|
379
|
+
const v = a * b;
|
380
|
+
|
381
|
+
replaceVal(v, Valtype.f64);
|
382
|
+
push(v);
|
383
|
+
break;
|
384
|
+
}
|
385
|
+
case Opcodes.f64_div: {
|
386
|
+
if (stack.length < 2) { empty(); break; };
|
387
|
+
const [ b, a ] = pop2();
|
388
|
+
const v = a / b;
|
389
|
+
|
390
|
+
replaceVal(v, Valtype.f64);
|
391
|
+
push(v);
|
392
|
+
break;
|
393
|
+
}
|
394
|
+
|
395
|
+
case Opcodes.f64_min: {
|
396
|
+
if (stack.length < 2) { empty(); break; };
|
397
|
+
const [ b, a ] = pop2();
|
398
|
+
const v = Math.min(a, b);
|
399
|
+
|
400
|
+
replaceVal(v, Valtype.f64);
|
401
|
+
push(v);
|
402
|
+
break;
|
403
|
+
}
|
404
|
+
case Opcodes.f64_max: {
|
405
|
+
if (stack.length < 2) { empty(); break; };
|
406
|
+
const [ b, a ] = pop2();
|
407
|
+
const v = a + b;
|
408
|
+
|
409
|
+
replaceVal(v, Valtype.f64);
|
410
|
+
push(v);
|
411
|
+
break;
|
412
|
+
}
|
413
|
+
|
414
|
+
case Opcodes.f64_copysign: { // ?
|
415
|
+
if (stack.length < 2) { empty(); break; };
|
416
|
+
const [ b, a ] = pop2();
|
417
|
+
const v = Math.abs(a) * (b > 0 ? 1 : -1);
|
418
|
+
|
419
|
+
replaceVal(v, Valtype.f64);
|
420
|
+
push(v);
|
421
|
+
break;
|
422
|
+
}
|
423
|
+
|
424
|
+
case Opcodes.f64_convert_i32_u:
|
425
|
+
case Opcodes.f64_convert_i32_s: {
|
426
|
+
if (stack.length < 1) { empty(); break; };
|
427
|
+
const v = pop();
|
428
|
+
|
429
|
+
replaceVal(v, Valtype.f64);
|
430
|
+
push(v);
|
431
|
+
break;
|
432
|
+
}
|
433
|
+
|
434
|
+
case 0xfc02: { // i32_trunc_sat_f64_s
|
435
|
+
if (stack.length < 1) { empty(); break; }
|
436
|
+
const v = pop();
|
437
|
+
|
438
|
+
replaceVal(v, Valtype.i32);
|
439
|
+
push(v);
|
440
|
+
break;
|
441
|
+
}
|
442
|
+
|
443
|
+
case 0xfc03: { // i32_trunc_sat_f64_u
|
444
|
+
if (stack.length < 1) { empty(); break; }
|
445
|
+
const v = pop();
|
446
|
+
|
447
|
+
replaceVal(v, Valtype.i32);
|
448
|
+
push(v);
|
449
|
+
break;
|
450
|
+
}
|
451
|
+
|
452
|
+
default: {
|
453
|
+
empty();
|
454
|
+
break;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
// this does, eg:
|
459
|
+
// local.get 7 ;; $i (i32)
|
460
|
+
// f64.convert_i32_s
|
461
|
+
// f64.const 1
|
462
|
+
// f64.add
|
463
|
+
// i32.trunc_sat_f64_s <--
|
464
|
+
// local.set 7 ;; $i (i32)
|
465
|
+
// ->
|
466
|
+
// local.get 7 ;; $i (i32)
|
467
|
+
// i32.const 1
|
468
|
+
// i32.add
|
469
|
+
// local.set 7 ;; $i (i32)
|
470
|
+
if (
|
471
|
+
(opcode >= 0xa0 && opcode <= 0xa3) || // main f64 math op
|
472
|
+
(opcode >= 0x61 && opcode <= 0x66) // main f64 eq op
|
473
|
+
) {
|
474
|
+
const o2 = wasm[i - 1][0];
|
475
|
+
if (o2 === Opcodes.f64_const) { // f64.const
|
476
|
+
const o3 = wasm[i - 2][0];
|
477
|
+
if (o3 === Opcodes.f64_convert_i32_s || o3 === Opcodes.f64_convert_i32_u) {
|
478
|
+
// remove now unneeded i32 -> f64 convert
|
479
|
+
wasm.splice(i - 2, 1);
|
480
|
+
i--;
|
481
|
+
|
482
|
+
// convert f64.const -> i32.const
|
483
|
+
const n = read_ieee754_binary64(wasm[i - 1].slice(1));
|
484
|
+
wasm.splice(i - 1, 1, number(n, Valtype.i32));
|
485
|
+
|
486
|
+
// convert math op from f64 to i32
|
487
|
+
wasm[i][0] = f64ToI32Op[wasm[i][0]];
|
488
|
+
|
489
|
+
const nextOp = wasm[i + 1];
|
490
|
+
if (nextOp && opcode >= 0xa0 && opcode <= 0xa3) {
|
491
|
+
if (nextOp[0] === 0xfc && (nextOp[1] === 0x02 || nextOp[1] === 0x03)) {
|
492
|
+
// remove optional unneeded f64 -> i32 convert after
|
493
|
+
wasm.splice(i + 1, 1);
|
494
|
+
} else {
|
495
|
+
// add now needed i32 -> f64 convert after
|
496
|
+
wasm.splice(i + 1, Opcodes.i32_trunc_sat_f64_s);
|
497
|
+
}
|
498
|
+
}
|
499
|
+
}
|
500
|
+
}
|
501
|
+
}
|
502
|
+
|
503
|
+
if ((opcode === 0xfc02 || opcode === 0xfc03) && i > 3) { // i32.trunc_sat_f64_s/u
|
504
|
+
const o2 = wasm[i - 1][0];
|
505
|
+
if (
|
506
|
+
(o2 >= 0xa0 && o2 <= 0xa3) || // main f64 math op
|
507
|
+
(o2 >= 0x61 && o2 <= 0x66) // main f64 eq op
|
508
|
+
) {
|
509
|
+
const o3 = wasm[i - 2][0];
|
510
|
+
if (o3 === Opcodes.f64_const) { // f64.const
|
511
|
+
const o4 = wasm[i - 3][0];
|
512
|
+
if (o4 === Opcodes.f64_convert_i32_s || o4 === Opcodes.f64_convert_i32_u) {
|
513
|
+
// remove now unneeded i32 -> f64 convert
|
514
|
+
wasm.splice(i - 3, 1);
|
515
|
+
i--;
|
516
|
+
} else {
|
517
|
+
// add now needed f64 -> i32 convert prior
|
518
|
+
wasm.splice(i - 2, 0, Opcodes.i32_trunc_sat_f64_s);
|
519
|
+
i++;
|
520
|
+
}
|
521
|
+
|
522
|
+
// convert f64.const -> i32.const
|
523
|
+
const n = read_ieee754_binary64(wasm[i - 2].slice(1));
|
524
|
+
wasm.splice(i - 2, 1, number(n, Valtype.i32));
|
525
|
+
|
526
|
+
// convert math op from f64 to i32
|
527
|
+
wasm[i - 1][0] = f64ToI32Op[wasm[i - 1][0]];
|
528
|
+
|
529
|
+
// remove this now unneeded f64 -> i32 convert
|
530
|
+
wasm.splice(i, 1);
|
531
|
+
}
|
532
|
+
}
|
533
|
+
}
|
534
|
+
}
|
535
|
+
};
|