porffor 0.14.0-b481bfc5f → 0.14.0-bb0b06c17
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/compiler/assemble.js +14 -0
- package/compiler/builtins/array.ts +76 -0
- package/compiler/builtins/math.ts +408 -0
- package/compiler/builtins.js +3 -4
- package/compiler/codegen.js +187 -104
- package/compiler/generated_builtins.js +314 -27
- package/compiler/precompile.js +4 -3
- package/package.json +1 -1
package/compiler/codegen.js
CHANGED
@@ -40,11 +40,11 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
40
40
|
}
|
41
41
|
};
|
42
42
|
|
43
|
-
const isFuncType = type =>
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
const isFuncType = type =>
|
44
|
+
type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
45
|
+
const hasFuncWithName = name =>
|
46
|
+
funcIndex[name] != null || builtinFuncs[name] != null || importedFuncs[name] != null || internalConstrs[name] != null;
|
47
|
+
|
48
48
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
49
49
|
switch (decl.type) {
|
50
50
|
case 'BinaryExpression':
|
@@ -147,14 +147,16 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
147
147
|
return generateMember(scope, decl, global, name);
|
148
148
|
|
149
149
|
case 'ExportNamedDeclaration':
|
150
|
-
|
151
|
-
const funcsBefore = funcs.length;
|
150
|
+
const funcsBefore = funcs.map(x => x.name);
|
152
151
|
generate(scope, decl.declaration);
|
153
152
|
|
154
|
-
|
155
|
-
|
156
|
-
const
|
157
|
-
|
153
|
+
// set new funcs as exported
|
154
|
+
if (funcsBefore.length !== funcs.length) {
|
155
|
+
const newFuncs = funcs.filter(x => !funcsBefore.includes(x.name)).filter(x => !x.internal);
|
156
|
+
|
157
|
+
for (const x of newFuncs) {
|
158
|
+
x.export = true;
|
159
|
+
}
|
158
160
|
}
|
159
161
|
|
160
162
|
return [];
|
@@ -1048,14 +1050,14 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1048
1050
|
return out;
|
1049
1051
|
};
|
1050
1052
|
|
1051
|
-
const asmFuncToAsm = (func,
|
1052
|
-
return func(
|
1053
|
+
const asmFuncToAsm = (func, scope) => {
|
1054
|
+
return func(scope, {
|
1053
1055
|
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
|
1054
|
-
builtin:
|
1055
|
-
let idx = funcIndex[
|
1056
|
-
if (idx
|
1057
|
-
includeBuiltin(null,
|
1058
|
-
idx = funcIndex[
|
1056
|
+
builtin: n => {
|
1057
|
+
let idx = funcIndex[n] ?? importedFuncs[n];
|
1058
|
+
if (idx == null && builtinFuncs[n]) {
|
1059
|
+
includeBuiltin(null, n);
|
1060
|
+
idx = funcIndex[n];
|
1059
1061
|
}
|
1060
1062
|
|
1061
1063
|
return idx;
|
@@ -1063,7 +1065,7 @@ const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals =
|
|
1063
1065
|
});
|
1064
1066
|
};
|
1065
1067
|
|
1066
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [],
|
1068
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1067
1069
|
const existing = funcs.find(x => x.name === name);
|
1068
1070
|
if (existing) return existing;
|
1069
1071
|
|
@@ -1081,7 +1083,22 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1081
1083
|
data.push(copy);
|
1082
1084
|
}
|
1083
1085
|
|
1084
|
-
|
1086
|
+
const func = {
|
1087
|
+
name,
|
1088
|
+
params,
|
1089
|
+
locals,
|
1090
|
+
localInd: allLocals.length,
|
1091
|
+
returns,
|
1092
|
+
returnType: returnType ?? TYPES.number,
|
1093
|
+
internal: true,
|
1094
|
+
index: currentFuncIndex++,
|
1095
|
+
table
|
1096
|
+
};
|
1097
|
+
|
1098
|
+
funcs.push(func);
|
1099
|
+
funcIndex[name] = func.index;
|
1100
|
+
|
1101
|
+
if (typeof wasm === 'function') wasm = asmFuncToAsm(wasm, func);
|
1085
1102
|
|
1086
1103
|
let baseGlobalIdx, i = 0;
|
1087
1104
|
for (const type of globalTypes) {
|
@@ -1100,25 +1117,14 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1100
1117
|
}
|
1101
1118
|
}
|
1102
1119
|
|
1103
|
-
const
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
returns,
|
1108
|
-
returnType: returnType ?? TYPES.number,
|
1109
|
-
wasm,
|
1110
|
-
internal: true,
|
1111
|
-
index: currentFuncIndex++
|
1112
|
-
};
|
1113
|
-
|
1114
|
-
if (callsSelf) for (const inst of wasm) {
|
1115
|
-
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
1116
|
-
inst[1] = func.index;
|
1120
|
+
if (table) for (const inst of wasm) {
|
1121
|
+
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1122
|
+
inst.splice(2, 99);
|
1123
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
|
1117
1124
|
}
|
1118
1125
|
}
|
1119
1126
|
|
1120
|
-
|
1121
|
-
funcIndex[name] = func.index;
|
1127
|
+
func.wasm = wasm;
|
1122
1128
|
|
1123
1129
|
return func;
|
1124
1130
|
};
|
@@ -1470,16 +1476,11 @@ const countLeftover = wasm => {
|
|
1470
1476
|
else if (inst[0] === Opcodes.return) count = 0;
|
1471
1477
|
else if (inst[0] === Opcodes.call) {
|
1472
1478
|
let func = funcs.find(x => x.index === inst[1]);
|
1473
|
-
if (inst[1]
|
1474
|
-
|
1475
|
-
|
1476
|
-
count -= importedFuncs[inst[1]].params;
|
1477
|
-
count += importedFuncs[inst[1]].returns;
|
1479
|
+
if (inst[1] < importedFuncs.length) {
|
1480
|
+
func = importedFuncs[inst[1]];
|
1481
|
+
count = count - func.params + func.returns;
|
1478
1482
|
} else {
|
1479
|
-
|
1480
|
-
count -= func.params.length;
|
1481
|
-
} else count--;
|
1482
|
-
if (func) count += func.returns.length;
|
1483
|
+
count = count - func.params.length + func.returns.length;
|
1483
1484
|
}
|
1484
1485
|
} else if (inst[0] === Opcodes.call_indirect) {
|
1485
1486
|
count--; // funcidx
|
@@ -1632,6 +1633,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1632
1633
|
|
1633
1634
|
if (!funcIndex[rhemynName]) {
|
1634
1635
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1636
|
+
func.internal = true;
|
1635
1637
|
|
1636
1638
|
funcIndex[func.name] = func.index;
|
1637
1639
|
funcs.push(func);
|
@@ -1803,11 +1805,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1803
1805
|
|
1804
1806
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1805
1807
|
|
1806
|
-
if (idx === undefined && name === scope.name) {
|
1807
|
-
// hack: calling self, func generator will fix later
|
1808
|
-
idx = -1;
|
1809
|
-
}
|
1810
|
-
|
1811
1808
|
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1812
1809
|
const wasmOps = {
|
1813
1810
|
// pointer, align, offset
|
@@ -1859,36 +1856,128 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1859
1856
|
const [ local, global ] = lookupName(scope, name);
|
1860
1857
|
if (!Prefs.indirectCalls || local == null) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1861
1858
|
|
1862
|
-
// todo: only works when
|
1863
|
-
|
1864
|
-
|
1859
|
+
// todo: only works when function uses typedParams and typedReturns
|
1860
|
+
|
1861
|
+
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1862
|
+
// options: vararg, strict
|
1863
|
+
// - strict: simpler, smaller size usage, no func argc lut needed.
|
1864
|
+
// ONLY works when arg count of call == arg count of function being called
|
1865
|
+
// - vararg: large size usage, cursed.
|
1866
|
+
// works when arg count of call != arg count of function being called*
|
1867
|
+
// * most of the time, some edgecases
|
1865
1868
|
|
1866
1869
|
funcs.table = true;
|
1870
|
+
scope.table = true;
|
1867
1871
|
|
1868
1872
|
let args = decl.arguments;
|
1869
|
-
let
|
1873
|
+
let out = [];
|
1874
|
+
|
1875
|
+
let locals = [];
|
1876
|
+
|
1877
|
+
if (indirectMode === 'vararg') {
|
1878
|
+
const minArgc = Prefs.indirectCallMinArgc ?? 3;
|
1879
|
+
|
1880
|
+
if (args.length < minArgc) {
|
1881
|
+
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE));
|
1882
|
+
}
|
1883
|
+
}
|
1870
1884
|
|
1871
1885
|
for (let i = 0; i < args.length; i++) {
|
1872
1886
|
const arg = args[i];
|
1873
|
-
|
1887
|
+
out = out.concat(generate(scope, arg));
|
1874
1888
|
|
1875
1889
|
if (valtypeBinary !== Valtype.i32 && (
|
1876
1890
|
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
1877
1891
|
(importedFuncs[name] && name.startsWith('profile'))
|
1878
1892
|
)) {
|
1879
|
-
|
1893
|
+
out.push(Opcodes.i32_to);
|
1894
|
+
}
|
1895
|
+
|
1896
|
+
out = out.concat(getNodeType(scope, arg));
|
1897
|
+
|
1898
|
+
if (indirectMode === 'vararg') {
|
1899
|
+
const typeLocal = localTmp(scope, `#indirect_arg${i}_type`, Valtype.i32);
|
1900
|
+
const valLocal = localTmp(scope, `#indirect_arg${i}_val`);
|
1901
|
+
|
1902
|
+
locals.push([valLocal, typeLocal]);
|
1903
|
+
|
1904
|
+
out.push(
|
1905
|
+
[ Opcodes.local_set, typeLocal ],
|
1906
|
+
[ Opcodes.local_set, valLocal ]
|
1907
|
+
);
|
1880
1908
|
}
|
1909
|
+
}
|
1910
|
+
|
1911
|
+
if (indirectMode === 'strict') {
|
1912
|
+
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
1913
|
+
[TYPES.function]: [
|
1914
|
+
...argWasm,
|
1915
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1916
|
+
Opcodes.i32_to_u,
|
1917
|
+
[ Opcodes.call_indirect, args.length, 0 ],
|
1918
|
+
...setLastType(scope)
|
1919
|
+
],
|
1920
|
+
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
1921
|
+
});
|
1922
|
+
}
|
1923
|
+
|
1924
|
+
// hi, I will now explain how vararg mode works:
|
1925
|
+
// wasm's indirect_call instruction requires you know the func type at compile-time
|
1926
|
+
// since we have varargs (variable argument count), we do not know it.
|
1927
|
+
// we could just store args in memory and not use wasm func args,
|
1928
|
+
// but that is slow (probably) and breaks js exports.
|
1929
|
+
// instead, we generate every* possibility of argc and use different indirect_call
|
1930
|
+
// ops for each one, with type depending on argc for that branch.
|
1931
|
+
// then we load the argc for the wanted function from a memory lut,
|
1932
|
+
// and call the branch with the matching argc we require.
|
1933
|
+
// sorry, yes it is very cursed (and size inefficient), but indirect calls
|
1934
|
+
// are kind of rare anyway (mostly callbacks) so I am not concerned atm.
|
1935
|
+
// *for argc 0-3, in future (todo:) the max number should be
|
1936
|
+
// dynamically changed to the max argc of any func in the js file.
|
1937
|
+
|
1938
|
+
const funcLocal = localTmp(scope, `#indirect_func`, Valtype.i32);
|
1939
|
+
|
1940
|
+
const gen = argc => {
|
1941
|
+
const out = [];
|
1942
|
+
for (let i = 0; i < argc; i++) {
|
1943
|
+
out.push(
|
1944
|
+
[ Opcodes.local_get, locals[i][0] ],
|
1945
|
+
[ Opcodes.local_get, locals[i][1] ]
|
1946
|
+
);
|
1947
|
+
}
|
1948
|
+
|
1949
|
+
out.push(
|
1950
|
+
[ Opcodes.local_get, funcLocal ],
|
1951
|
+
[ Opcodes.call_indirect, argc, 0 ],
|
1952
|
+
...setLastType(scope)
|
1953
|
+
)
|
1954
|
+
|
1955
|
+
return out;
|
1956
|
+
};
|
1881
1957
|
|
1882
|
-
|
1958
|
+
const tableBc = {};
|
1959
|
+
for (let i = 0; i <= args.length; i++) {
|
1960
|
+
tableBc[i] = gen(i);
|
1883
1961
|
}
|
1884
1962
|
|
1963
|
+
// todo/perf: check if we should use br_table here or just generate our own big if..elses
|
1964
|
+
|
1885
1965
|
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
1886
1966
|
[TYPES.function]: [
|
1887
|
-
...
|
1967
|
+
...out,
|
1968
|
+
|
1888
1969
|
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1889
1970
|
Opcodes.i32_to_u,
|
1890
|
-
[ Opcodes.
|
1891
|
-
|
1971
|
+
[ Opcodes.local_set, funcLocal ],
|
1972
|
+
|
1973
|
+
...brTable([
|
1974
|
+
// get argc of func we are calling
|
1975
|
+
[ Opcodes.local_get, funcLocal ],
|
1976
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
1977
|
+
[ Opcodes.i32_mul ],
|
1978
|
+
|
1979
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func argc lut') * pageSize), 'read_argc' ]
|
1980
|
+
], tableBc, valtypeBinary)
|
1892
1981
|
],
|
1893
1982
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
1894
1983
|
});
|
@@ -1897,11 +1986,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1897
1986
|
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
1898
1987
|
}
|
1899
1988
|
|
1900
|
-
const func = funcs.find(x => x.index === idx);
|
1901
|
-
|
1902
|
-
const userFunc = (funcIndex[name] && !importedFuncs[name] && !builtinFuncs[name] && !internalConstrs[name]) || idx === -1;
|
1989
|
+
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1990
|
+
const userFunc = func && !func.internal;
|
1903
1991
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1904
|
-
const typedReturns = (func
|
1992
|
+
const typedReturns = (func && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1905
1993
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1906
1994
|
|
1907
1995
|
let args = decl.arguments;
|
@@ -2046,16 +2134,17 @@ const brTable = (input, bc, returns) => {
|
|
2046
2134
|
}
|
2047
2135
|
|
2048
2136
|
for (let i = 0; i < count; i++) {
|
2049
|
-
if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2137
|
+
// if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
2138
|
+
if (i === 0) out.push([ Opcodes.block, returns ]);
|
2050
2139
|
else out.push([ Opcodes.block, Blocktype.void ]);
|
2051
2140
|
}
|
2052
2141
|
|
2053
|
-
const nums = keys.filter(x => +x);
|
2142
|
+
const nums = keys.filter(x => +x >= 0);
|
2054
2143
|
const offset = Math.min(...nums);
|
2055
2144
|
const max = Math.max(...nums);
|
2056
2145
|
|
2057
2146
|
const table = [];
|
2058
|
-
let br =
|
2147
|
+
let br = 0;
|
2059
2148
|
|
2060
2149
|
for (let i = offset; i <= max; i++) {
|
2061
2150
|
// if branch for this num, go to that block
|
@@ -2095,10 +2184,9 @@ const brTable = (input, bc, returns) => {
|
|
2095
2184
|
br--;
|
2096
2185
|
}
|
2097
2186
|
|
2098
|
-
|
2099
|
-
|
2100
|
-
|
2101
|
-
];
|
2187
|
+
out.push([ Opcodes.end ]);
|
2188
|
+
|
2189
|
+
return out;
|
2102
2190
|
};
|
2103
2191
|
|
2104
2192
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
@@ -3043,14 +3131,18 @@ const generateThrow = (scope, decl) => {
|
|
3043
3131
|
};
|
3044
3132
|
|
3045
3133
|
const generateTry = (scope, decl) => {
|
3046
|
-
|
3134
|
+
// todo: handle control-flow pre-exit for finally
|
3135
|
+
// "Immediately before a control-flow statement (return, throw, break, continue) is executed in the try block or catch block."
|
3047
3136
|
|
3048
3137
|
const out = [];
|
3049
3138
|
|
3139
|
+
const finalizer = decl.finalizer ? generate(scope, decl.finalizer) : [];
|
3140
|
+
|
3050
3141
|
out.push([ Opcodes.try, Blocktype.void ]);
|
3051
3142
|
depth.push('try');
|
3052
3143
|
|
3053
3144
|
out.push(...generate(scope, decl.block));
|
3145
|
+
out.push(...finalizer);
|
3054
3146
|
|
3055
3147
|
if (decl.handler) {
|
3056
3148
|
depth.pop();
|
@@ -3058,6 +3150,7 @@ const generateTry = (scope, decl) => {
|
|
3058
3150
|
|
3059
3151
|
out.push([ Opcodes.catch_all ]);
|
3060
3152
|
out.push(...generate(scope, decl.handler.body));
|
3153
|
+
out.push(...finalizer);
|
3061
3154
|
}
|
3062
3155
|
|
3063
3156
|
out.push([ Opcodes.end ]);
|
@@ -3365,8 +3458,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3365
3458
|
if (decl.property.name === 'length') {
|
3366
3459
|
const func = funcs.find(x => x.name === name);
|
3367
3460
|
if (func) {
|
3368
|
-
const
|
3369
|
-
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
3461
|
+
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3370
3462
|
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3371
3463
|
}
|
3372
3464
|
|
@@ -3592,33 +3684,39 @@ const generateFunc = (scope, decl) => {
|
|
3592
3684
|
const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
|
3593
3685
|
const params = decl.params ?? [];
|
3594
3686
|
|
3595
|
-
// const innerScope = { ...scope };
|
3596
3687
|
// TODO: share scope/locals between !!!
|
3597
|
-
const
|
3688
|
+
const func = {
|
3598
3689
|
locals: {},
|
3599
3690
|
localInd: 0,
|
3600
3691
|
// value, type
|
3601
3692
|
returns: [ valtypeBinary, Valtype.i32 ],
|
3602
3693
|
throws: false,
|
3603
|
-
name
|
3694
|
+
name,
|
3695
|
+
index: currentFuncIndex++
|
3604
3696
|
};
|
3605
3697
|
|
3606
3698
|
if (typedInput && decl.returnType) {
|
3607
3699
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3608
|
-
if (type != null && !Prefs.indirectCalls) {
|
3609
|
-
|
3610
|
-
|
3700
|
+
// if (type != null && !Prefs.indirectCalls) {
|
3701
|
+
if (type != null) {
|
3702
|
+
func.returnType = type;
|
3703
|
+
func.returns = [ valtypeBinary ];
|
3611
3704
|
}
|
3612
3705
|
}
|
3613
3706
|
|
3614
3707
|
for (let i = 0; i < params.length; i++) {
|
3615
|
-
|
3708
|
+
const name = params[i].name;
|
3709
|
+
// if (name == null) return todo('non-identifier args are not supported');
|
3710
|
+
|
3711
|
+
allocVar(func, name, false);
|
3616
3712
|
|
3617
3713
|
if (typedInput && params[i].typeAnnotation) {
|
3618
|
-
addVarMetadata(
|
3714
|
+
addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
|
3619
3715
|
}
|
3620
3716
|
}
|
3621
3717
|
|
3718
|
+
func.params = Object.values(func.locals).map(x => x.type);
|
3719
|
+
|
3622
3720
|
let body = objectHack(decl.body);
|
3623
3721
|
if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
|
3624
3722
|
// hack: () => 0 -> () => return 0
|
@@ -3628,37 +3726,23 @@ const generateFunc = (scope, decl) => {
|
|
3628
3726
|
};
|
3629
3727
|
}
|
3630
3728
|
|
3631
|
-
const wasm = generate(innerScope, body);
|
3632
|
-
const func = {
|
3633
|
-
name,
|
3634
|
-
params: Object.values(innerScope.locals).slice(0, params.length * 2).map(x => x.type),
|
3635
|
-
index: currentFuncIndex++,
|
3636
|
-
...innerScope
|
3637
|
-
};
|
3638
3729
|
funcIndex[name] = func.index;
|
3730
|
+
funcs.push(func);
|
3639
3731
|
|
3640
|
-
|
3732
|
+
const wasm = generate(func, body);
|
3733
|
+
func.wasm = wasm;
|
3641
3734
|
|
3642
|
-
|
3643
|
-
for (const inst of wasm) {
|
3644
|
-
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
3645
|
-
inst[1] = func.index;
|
3646
|
-
}
|
3647
|
-
}
|
3735
|
+
if (name === 'main') func.gotLastType = true;
|
3648
3736
|
|
3649
3737
|
// add end return if not found
|
3650
3738
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3651
3739
|
wasm.push(
|
3652
3740
|
...number(0),
|
3653
|
-
...(
|
3741
|
+
...(func.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3654
3742
|
[ Opcodes.return ]
|
3655
3743
|
);
|
3656
3744
|
}
|
3657
3745
|
|
3658
|
-
func.wasm = wasm;
|
3659
|
-
|
3660
|
-
funcs.push(func);
|
3661
|
-
|
3662
3746
|
return func;
|
3663
3747
|
};
|
3664
3748
|
|
@@ -3907,9 +3991,8 @@ export default program => {
|
|
3907
3991
|
|
3908
3992
|
if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
|
3909
3993
|
|
3910
|
-
generateFunc(scope, program);
|
3994
|
+
const main = generateFunc(scope, program);
|
3911
3995
|
|
3912
|
-
const main = funcs[funcs.length - 1];
|
3913
3996
|
main.export = true;
|
3914
3997
|
main.returns = [ valtypeBinary, Valtype.i32 ];
|
3915
3998
|
|
@@ -3936,7 +4019,7 @@ export default program => {
|
|
3936
4019
|
}
|
3937
4020
|
|
3938
4021
|
// if blank main func and other exports, remove it
|
3939
|
-
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(
|
4022
|
+
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
3940
4023
|
|
3941
4024
|
return { funcs, globals, tags, exceptions, pages, data };
|
3942
4025
|
};
|