porffor 0.2.0-fdf0fc5 → 0.14.0-4e46400a9
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 +9 -2
- package/byg/index.js +3 -24
- package/compiler/2c.js +2 -53
- package/compiler/assemble.js +26 -11
- package/compiler/builtins/annexb_string.js +10 -10
- package/compiler/builtins/annexb_string.ts +3 -3
- package/compiler/builtins/array.ts +2 -6
- package/compiler/builtins/base64.ts +1 -1
- package/compiler/builtins/boolean.ts +0 -2
- package/compiler/builtins/crypto.ts +1 -1
- package/compiler/builtins/date.ts +1 -4
- package/compiler/builtins/escape.ts +1 -1
- package/compiler/builtins/function.ts +0 -2
- package/compiler/builtins/int.ts +0 -2
- package/compiler/builtins/number.ts +3 -8
- package/compiler/builtins/object.ts +0 -2
- package/compiler/builtins/porffor.d.ts +9 -8
- package/compiler/builtins/set.ts +184 -2
- package/compiler/builtins/string.ts +1 -1
- package/compiler/builtins.js +4 -7
- package/compiler/codegen.js +78 -121
- package/compiler/decompile.js +2 -2
- package/compiler/embedding.js +2 -2
- package/compiler/encoding.js +0 -14
- package/compiler/expression.js +1 -1
- package/compiler/generated_builtins.js +303 -204
- package/compiler/index.js +0 -2
- package/compiler/opt.js +7 -7
- package/compiler/parse.js +1 -3
- package/compiler/precompile.js +17 -25
- package/compiler/prototype.js +5 -5
- package/compiler/wasmSpec.js +5 -0
- package/compiler/wrap.js +75 -57
- package/package.json +1 -1
- package/runner/compare.js +0 -1
- package/runner/debug.js +1 -6
- package/runner/profiler.js +15 -42
- package/runner/repl.js +3 -9
- package/runner/sizes.js +2 -2
- package/runner/version.js +10 -8
package/compiler/builtins/set.ts
CHANGED
@@ -1,5 +1,187 @@
|
|
1
|
-
//
|
1
|
+
// dark wasm magic for dealing with memory, sorry.
|
2
|
+
export const __Porffor_allocate = (): number => {
|
3
|
+
Porffor.wasm`i32.const 1
|
4
|
+
memory.grow 0
|
5
|
+
drop
|
6
|
+
memory.size 0
|
7
|
+
i32.const 1
|
8
|
+
i32.sub
|
9
|
+
i32.const 65536
|
10
|
+
i32.mul
|
11
|
+
i32.from_u
|
12
|
+
return`;
|
13
|
+
};
|
2
14
|
|
3
|
-
export const
|
15
|
+
export const __Porffor_set_read = (_this: Set, index: number): any => {
|
16
|
+
Porffor.wasm`
|
17
|
+
local offset i32
|
18
|
+
local.get ${index}
|
19
|
+
i32.to_u
|
20
|
+
i32.const 9
|
21
|
+
i32.mul
|
22
|
+
local.get ${_this}
|
23
|
+
i32.to_u
|
24
|
+
i32.add
|
25
|
+
local.set offset
|
4
26
|
|
27
|
+
local.get offset
|
28
|
+
f64.load 0 4
|
29
|
+
|
30
|
+
local.get offset
|
31
|
+
i32.load8_u 0 12
|
32
|
+
return`;
|
33
|
+
};
|
34
|
+
|
35
|
+
export const __Porffor_set_write = (_this: Set, index: number, value: any): boolean => {
|
36
|
+
Porffor.wasm`
|
37
|
+
local offset i32
|
38
|
+
local.get ${index}
|
39
|
+
i32.to_u
|
40
|
+
i32.const 9
|
41
|
+
i32.mul
|
42
|
+
local.get ${_this}
|
43
|
+
i32.to_u
|
44
|
+
i32.add
|
45
|
+
local.set offset
|
46
|
+
|
47
|
+
local.get offset
|
48
|
+
local.get ${value}
|
49
|
+
f64.store 0 4
|
50
|
+
|
51
|
+
local.get offset
|
52
|
+
local.get ${value+1}
|
53
|
+
i32.store8 0 12`;
|
54
|
+
|
55
|
+
return true;
|
56
|
+
};
|
57
|
+
|
58
|
+
|
59
|
+
// todo: this should be a getter somehow not a method
|
60
|
+
export const __Set_prototype_size = (_this: Set) => {
|
61
|
+
return Porffor.wasm.i32.load(_this, 0, 0);
|
62
|
+
};
|
63
|
+
|
64
|
+
export const __Set_prototype_values = (_this: Set) => {
|
65
|
+
// todo: this should return an iterator not array
|
66
|
+
const size: number = __Set_prototype_size(_this);
|
67
|
+
|
68
|
+
const out: any[] = __Porffor_allocate();
|
69
|
+
for (let i: number = 0; i < size; i++) {
|
70
|
+
const val: any = __Porffor_set_read(_this, i);
|
71
|
+
out.push(val);
|
72
|
+
}
|
73
|
+
|
74
|
+
return out;
|
75
|
+
};
|
76
|
+
|
77
|
+
export const __Set_prototype_keys = (_this: Set) => {
|
78
|
+
return __Set_prototype_values(_this);
|
79
|
+
};
|
80
|
+
|
81
|
+
export const __Set_prototype_has = (_this: Set, value: any) => {
|
82
|
+
const size: number = __Set_prototype_size(_this);
|
83
|
+
|
84
|
+
for (let i: number = 0; i < size; i++) {
|
85
|
+
if (__Porffor_set_read(_this, i) === value) return true;
|
86
|
+
}
|
87
|
+
|
88
|
+
return false;
|
89
|
+
};
|
90
|
+
|
91
|
+
export const __Set_prototype_add = (_this: Set, value: any) => {
|
92
|
+
const size: number = __Set_prototype_size(_this);
|
93
|
+
|
94
|
+
// check if already in set
|
95
|
+
for (let i: number = 0; i < size; i++) {
|
96
|
+
if (__Porffor_set_read(_this, i) === value) return _this;
|
97
|
+
}
|
98
|
+
|
99
|
+
// not, add it
|
100
|
+
// increment size by 1
|
101
|
+
Porffor.wasm.i32.store(_this, size + 1, 0, 0);
|
102
|
+
|
103
|
+
// write new value at end
|
104
|
+
__Porffor_set_write(_this, size, value);
|
105
|
+
|
106
|
+
return _this;
|
107
|
+
};
|
108
|
+
|
109
|
+
export const __Set_prototype_delete = (_this: Set, value: any) => {
|
110
|
+
const size: number = __Set_prototype_size(_this);
|
111
|
+
|
112
|
+
// check if already in set
|
113
|
+
for (let i: number = 0; i < size; i++) {
|
114
|
+
if (__Porffor_set_read(_this, i) === value) {
|
115
|
+
// found, delete
|
116
|
+
// decrement size by 1
|
117
|
+
Porffor.wasm.i32.store(_this, size - 1, 0, 0);
|
118
|
+
|
119
|
+
// offset all elements after by -1 ind
|
120
|
+
Porffor.wasm`
|
121
|
+
local offset i32
|
122
|
+
local.get ${i}
|
123
|
+
i32.to_u
|
124
|
+
i32.const 9
|
125
|
+
i32.mul
|
126
|
+
local.get ${_this}
|
127
|
+
i32.to_u
|
128
|
+
i32.add
|
129
|
+
i32.const 4
|
130
|
+
i32.add
|
131
|
+
local.set offset
|
132
|
+
|
133
|
+
;; dst = offset (this element)
|
134
|
+
local.get offset
|
135
|
+
|
136
|
+
;; src = offset + 9 (this element + 1 element)
|
137
|
+
local.get offset
|
138
|
+
i32.const 9
|
139
|
+
i32.add
|
140
|
+
|
141
|
+
;; size = (size - i - 1) * 9
|
142
|
+
local.get ${size}
|
143
|
+
local.get ${i}
|
144
|
+
f64.sub
|
145
|
+
i32.to_u
|
146
|
+
i32.const 1
|
147
|
+
i32.sub
|
148
|
+
i32.const 9
|
149
|
+
i32.mul
|
150
|
+
|
151
|
+
memory.copy 0 0`;
|
152
|
+
|
153
|
+
return true;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
// not, return false
|
158
|
+
return false;
|
159
|
+
};
|
160
|
+
|
161
|
+
export const __Set_prototype_clear = (_this: Set) => {
|
162
|
+
// just set size to 0
|
163
|
+
// do not need to delete any as will not be accessed anymore,
|
164
|
+
// and will be overwritten with new add
|
165
|
+
Porffor.wasm.i32.store(_this, 0, 0, 0);
|
166
|
+
};
|
167
|
+
|
168
|
+
export const Set = () => {
|
169
|
+
throw new TypeError("Constructor Set requires 'new'");
|
170
|
+
};
|
171
|
+
|
172
|
+
export const Set$constructor = (iterable: any): Set => {
|
173
|
+
const out: Set = __Porffor_allocate();
|
174
|
+
|
175
|
+
const type: number = Porffor.rawType(iterable);
|
176
|
+
if (Porffor.fastOr(
|
177
|
+
type == Porffor.TYPES.array,
|
178
|
+
type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
|
179
|
+
type == Porffor.TYPES.set
|
180
|
+
)) {
|
181
|
+
for (const x of iterable) {
|
182
|
+
__Set_prototype_add(out, x);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
return out;
|
5
187
|
};
|
package/compiler/builtins.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype, ValtypeSize } from "./wasmSpec.js";
|
2
|
-
import { number, i32x4 } from "./embedding.js";
|
3
|
-
import Prefs from './prefs.js';
|
4
1
|
import * as GeneratedBuiltins from './generated_builtins.js';
|
2
|
+
import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
3
|
+
import { number } from './embedding.js';
|
5
4
|
import { TYPES } from './types.js';
|
5
|
+
import Prefs from './prefs.js';
|
6
6
|
|
7
7
|
export const importedFuncs = [
|
8
8
|
{
|
@@ -48,8 +48,6 @@ for (let i = 0; i < importedFuncs.length; i++) {
|
|
48
48
|
importedFuncs[f.name] = i;
|
49
49
|
}
|
50
50
|
|
51
|
-
const char = c => number(c.charCodeAt(0));
|
52
|
-
|
53
51
|
const printStaticStr = str => {
|
54
52
|
const out = [];
|
55
53
|
|
@@ -140,7 +138,7 @@ export const BuiltinVars = function() {
|
|
140
138
|
this.Math = number(1);
|
141
139
|
|
142
140
|
// wintercg(tm)
|
143
|
-
this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.
|
141
|
+
this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.14.0`, false, '__navigator_userAgent');
|
144
142
|
this.__navigator_userAgent.type = Prefs.bytestring ? TYPES.bytestring : TYPES.string;
|
145
143
|
|
146
144
|
for (const x in TYPES) {
|
@@ -569,7 +567,6 @@ export const BuiltinFuncs = function() {
|
|
569
567
|
|
570
568
|
// this is an implementation of xorshift128+ (in wasm bytecode)
|
571
569
|
// fun fact: v8, SM, JSC also use this (you will need this fun fact to maintain your sanity reading this code)
|
572
|
-
// const prngSeed0 = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), prngSeed1 = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
573
570
|
const prngSeed0 = (Math.random() * (2 ** 30)) | 0, prngSeed1 = (Math.random() * (2 ** 30)) | 0;
|
574
571
|
|
575
572
|
const prng = ({
|
package/compiler/codegen.js
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from
|
2
|
-
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from
|
3
|
-
import { operatorOpcode } from
|
4
|
-
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from
|
5
|
-
import { PrototypeFuncs } from
|
6
|
-
import { number
|
7
|
-
import { log } from "./log.js";
|
8
|
-
import parse from "./parse.js";
|
9
|
-
import * as Rhemyn from "../rhemyn/compile.js";
|
10
|
-
import Prefs from './prefs.js';
|
1
|
+
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
|
3
|
+
import { operatorOpcode } from './expression.js';
|
4
|
+
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
|
+
import { PrototypeFuncs } from './prototype.js';
|
6
|
+
import { number } from './embedding.js';
|
11
7
|
import { TYPES, TYPE_NAMES } from './types.js';
|
8
|
+
import * as Rhemyn from '../rhemyn/compile.js';
|
9
|
+
import parse from './parse.js';
|
10
|
+
import { log } from './log.js';
|
11
|
+
import Prefs from './prefs.js';
|
12
12
|
|
13
13
|
let globals = {};
|
14
14
|
let globalInd = 0;
|
@@ -19,24 +19,6 @@ let funcIndex = {};
|
|
19
19
|
let currentFuncIndex = importedFuncs.length;
|
20
20
|
let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
|
21
21
|
|
22
|
-
const debug = str => {
|
23
|
-
const code = [];
|
24
|
-
|
25
|
-
const logChar = n => {
|
26
|
-
code.push(...number(n));
|
27
|
-
|
28
|
-
code.push([ Opcodes.call, 0 ]);
|
29
|
-
};
|
30
|
-
|
31
|
-
for (let i = 0; i < str.length; i++) {
|
32
|
-
logChar(str.charCodeAt(i));
|
33
|
-
}
|
34
|
-
|
35
|
-
logChar(10); // new line
|
36
|
-
|
37
|
-
return code;
|
38
|
-
};
|
39
|
-
|
40
22
|
class TodoError extends Error {
|
41
23
|
constructor(message) {
|
42
24
|
super(message);
|
@@ -76,10 +58,11 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
76
58
|
|
77
59
|
case 'ArrowFunctionExpression':
|
78
60
|
case 'FunctionDeclaration':
|
61
|
+
case 'FunctionExpression':
|
79
62
|
const func = generateFunc(scope, decl);
|
80
63
|
|
81
64
|
if (decl.type.endsWith('Expression')) {
|
82
|
-
return number(func.index);
|
65
|
+
return number(func.index - importedFuncs.length);
|
83
66
|
}
|
84
67
|
|
85
68
|
return [];
|
@@ -171,11 +154,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
171
154
|
newFunc.export = true;
|
172
155
|
}
|
173
156
|
|
174
|
-
// if (funcsBefore === funcs.length) throw new Error('no new func added in export');
|
175
|
-
|
176
|
-
// const newFunc = funcs[funcs.length - 1];
|
177
|
-
// newFunc.export = true;
|
178
|
-
|
179
157
|
return [];
|
180
158
|
|
181
159
|
case 'TaggedTemplateExpression': {
|
@@ -210,7 +188,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
210
188
|
if (!Array.isArray(inst)) inst = [ inst ];
|
211
189
|
const immediates = asm.slice(1).map(x => {
|
212
190
|
const int = parseInt(x);
|
213
|
-
if (Number.isNaN(int)) return scope.locals[x]?.idx;
|
191
|
+
if (Number.isNaN(int)) return scope.locals[x]?.idx ?? globals[x].idx;
|
214
192
|
return int;
|
215
193
|
});
|
216
194
|
|
@@ -336,10 +314,10 @@ const generateIdent = (scope, decl) => {
|
|
336
314
|
|
337
315
|
if (local?.idx === undefined) {
|
338
316
|
// no local var with name
|
339
|
-
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name]);
|
340
|
-
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name]);
|
341
|
-
|
342
317
|
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
318
|
+
|
319
|
+
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
|
320
|
+
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name] - importedFuncs.length);
|
343
321
|
}
|
344
322
|
|
345
323
|
if (local?.idx === undefined && rawName.startsWith('__')) {
|
@@ -858,31 +836,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
858
836
|
|
859
837
|
// if strict (in)equal check types match
|
860
838
|
if (strictOp) {
|
861
|
-
// startOut.push(
|
862
|
-
// ...leftType,
|
863
|
-
// ...rightType,
|
864
|
-
// [ Opcodes.i32_eq ]
|
865
|
-
// );
|
866
|
-
|
867
|
-
// endOut.push(
|
868
|
-
// [ Opcodes.i32_and ]
|
869
|
-
// );
|
870
|
-
|
871
|
-
// startOut.push(
|
872
|
-
// [ Opcodes.block, Valtype.i32 ],
|
873
|
-
// ...leftType,
|
874
|
-
// ...rightType,
|
875
|
-
// [ Opcodes.i32_ne ],
|
876
|
-
// [ Opcodes.if, Blocktype.void ],
|
877
|
-
// ...number(op === '===' ? 0 : 1, Valtype.i32),
|
878
|
-
// [ Opcodes.br, 1 ],
|
879
|
-
// [ Opcodes.end ]
|
880
|
-
// );
|
881
|
-
|
882
|
-
// endOut.push(
|
883
|
-
// [ Opcodes.end ]
|
884
|
-
// );
|
885
|
-
|
886
839
|
endOut.push(
|
887
840
|
...leftType,
|
888
841
|
...rightType,
|
@@ -1089,7 +1042,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1089
1042
|
|
1090
1043
|
const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
|
1091
1044
|
return func({ name, params, locals, returns, localInd }, {
|
1092
|
-
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
|
1045
|
+
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
|
1093
1046
|
builtin: name => {
|
1094
1047
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1095
1048
|
if (idx === undefined && builtinFuncs[name]) {
|
@@ -1248,7 +1201,7 @@ const setLastType = scope => {
|
|
1248
1201
|
};
|
1249
1202
|
|
1250
1203
|
const getNodeType = (scope, node) => {
|
1251
|
-
const
|
1204
|
+
const ret = (() => {
|
1252
1205
|
if (node.type === 'Literal') {
|
1253
1206
|
if (node.regex) return TYPES.regexp;
|
1254
1207
|
|
@@ -1291,7 +1244,6 @@ const getNodeType = (scope, node) => {
|
|
1291
1244
|
const func = funcs.find(x => x.name === name);
|
1292
1245
|
|
1293
1246
|
if (func) {
|
1294
|
-
// console.log(scope, func, func.returnType);
|
1295
1247
|
if (func.returnType) return func.returnType;
|
1296
1248
|
}
|
1297
1249
|
|
@@ -1435,10 +1387,8 @@ const getNodeType = (scope, node) => {
|
|
1435
1387
|
// presume
|
1436
1388
|
// todo: warn here?
|
1437
1389
|
return TYPES.number;
|
1438
|
-
};
|
1390
|
+
})();
|
1439
1391
|
|
1440
|
-
const ret = inner();
|
1441
|
-
// console.trace(node, ret);
|
1442
1392
|
if (typeof ret === 'number') return number(ret, Valtype.i32);
|
1443
1393
|
return ret;
|
1444
1394
|
};
|
@@ -1577,15 +1527,6 @@ const RTArrayUtil = {
|
|
1577
1527
|
};
|
1578
1528
|
|
1579
1529
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1580
|
-
/* const callee = decl.callee;
|
1581
|
-
const args = decl.arguments;
|
1582
|
-
|
1583
|
-
return [
|
1584
|
-
...generate(args),
|
1585
|
-
...generate(callee),
|
1586
|
-
Opcodes.call_indirect,
|
1587
|
-
]; */
|
1588
|
-
|
1589
1530
|
let name = mapName(decl.callee.name);
|
1590
1531
|
if (isFuncType(decl.callee.type)) { // iife
|
1591
1532
|
const func = generateFunc(scope, decl.callee);
|
@@ -1759,8 +1700,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1759
1700
|
continue;
|
1760
1701
|
}
|
1761
1702
|
|
1762
|
-
// const protoLocal = protoFunc.local ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp`, protoFunc.local) : -1;
|
1763
|
-
// const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp2`, protoFunc.local2) : -1;
|
1764
1703
|
const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
|
1765
1704
|
const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
|
1766
1705
|
|
@@ -1837,22 +1776,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1837
1776
|
|
1838
1777
|
includeBuiltin(scope, name);
|
1839
1778
|
idx = funcIndex[name];
|
1840
|
-
|
1841
|
-
// infer arguments types from builtins params
|
1842
|
-
// const func = funcs.find(x => x.name === name);
|
1843
|
-
// for (let i = 0; i < decl.arguments.length; i++) {
|
1844
|
-
// const arg = decl.arguments[i];
|
1845
|
-
// if (!arg.name) continue;
|
1846
|
-
|
1847
|
-
// const local = scope.locals[arg.name];
|
1848
|
-
// if (!local) continue;
|
1849
|
-
|
1850
|
-
// local.type = func.params[i];
|
1851
|
-
// if (local.type === Valtype.v128) {
|
1852
|
-
// // specify vec subtype inferred from last vec type in function name
|
1853
|
-
// local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1854
|
-
// }
|
1855
|
-
// }
|
1856
1779
|
}
|
1857
1780
|
|
1858
1781
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1909,7 +1832,23 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1909
1832
|
}
|
1910
1833
|
|
1911
1834
|
if (idx === undefined) {
|
1912
|
-
if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined)
|
1835
|
+
if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) {
|
1836
|
+
if (!Prefs.indirectCalls) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1837
|
+
|
1838
|
+
const [ local, global ] = lookupName(scope, name);
|
1839
|
+
funcs.table = true;
|
1840
|
+
|
1841
|
+
// todo: only works when:
|
1842
|
+
// 1. arg count matches arg count of function
|
1843
|
+
// 2. function uses typedParams and typedReturns
|
1844
|
+
return typeSwitch(scope, getNodeType(decl.callee), {
|
1845
|
+
[TYPES.function]: [
|
1846
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1847
|
+
[ Opcodes.call_indirect ]
|
1848
|
+
],
|
1849
|
+
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
1850
|
+
});
|
1851
|
+
}
|
1913
1852
|
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
1914
1853
|
}
|
1915
1854
|
|
@@ -1938,11 +1877,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1938
1877
|
const arg = args[i];
|
1939
1878
|
out = out.concat(generate(scope, arg));
|
1940
1879
|
|
1941
|
-
if (
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
if (importedFuncs[name] && name.startsWith('profile')) {
|
1880
|
+
if (valtypeBinary !== Valtype.i32 && (
|
1881
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
1882
|
+
(importedFuncs[name] && name.startsWith('profile'))
|
1883
|
+
)) {
|
1946
1884
|
out.push(Opcodes.i32_to);
|
1947
1885
|
}
|
1948
1886
|
|
@@ -2178,7 +2116,6 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
|
2178
2116
|
const typeAnnoToPorfType = x => {
|
2179
2117
|
if (!x) return null;
|
2180
2118
|
if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
|
2181
|
-
if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
|
2182
2119
|
|
2183
2120
|
switch (x) {
|
2184
2121
|
case 'i32':
|
@@ -2219,9 +2156,8 @@ const generateVar = (scope, decl) => {
|
|
2219
2156
|
|
2220
2157
|
const topLevel = scope.name === 'main';
|
2221
2158
|
|
2222
|
-
// global variable if in top scope (main)
|
2223
|
-
const global = topLevel || decl._bare;
|
2224
|
-
const target = global ? globals : scope.locals;
|
2159
|
+
// global variable if in top scope (main) or if internally wanted
|
2160
|
+
const global = topLevel || decl._bare;
|
2225
2161
|
|
2226
2162
|
for (const x of decl.declarations) {
|
2227
2163
|
const name = mapName(x.id.name);
|
@@ -2235,7 +2171,6 @@ const generateVar = (scope, decl) => {
|
|
2235
2171
|
continue;
|
2236
2172
|
}
|
2237
2173
|
|
2238
|
-
// console.log(name);
|
2239
2174
|
if (topLevel && builtinVars[name]) {
|
2240
2175
|
// cannot redeclare
|
2241
2176
|
if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
|
@@ -2255,6 +2190,22 @@ const generateVar = (scope, decl) => {
|
|
2255
2190
|
}
|
2256
2191
|
|
2257
2192
|
if (x.init) {
|
2193
|
+
// if (isFuncType(x.init.type)) {
|
2194
|
+
// // let a = function () { ... }
|
2195
|
+
// x.init.id = { name };
|
2196
|
+
|
2197
|
+
// const func = generateFunc(scope, x.init);
|
2198
|
+
|
2199
|
+
// out.push(
|
2200
|
+
// ...number(func.index - importedFuncs.length),
|
2201
|
+
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2202
|
+
|
2203
|
+
// ...setType(scope, name, TYPES.function)
|
2204
|
+
// );
|
2205
|
+
|
2206
|
+
// continue;
|
2207
|
+
// }
|
2208
|
+
|
2258
2209
|
const generated = generate(scope, x.init, global, name);
|
2259
2210
|
if (scope.arrays?.get(name) != null) {
|
2260
2211
|
// hack to set local as pointer before
|
@@ -2266,6 +2217,7 @@ const generateVar = (scope, decl) => {
|
|
2266
2217
|
out = out.concat(generated);
|
2267
2218
|
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2268
2219
|
}
|
2220
|
+
|
2269
2221
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2270
2222
|
}
|
2271
2223
|
|
@@ -2279,6 +2231,7 @@ const generateVar = (scope, decl) => {
|
|
2279
2231
|
// todo: optimize this func for valueUnused
|
2280
2232
|
const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
2281
2233
|
const { type, name } = decl.left;
|
2234
|
+
const [ local, isGlobal ] = lookupName(scope, name);
|
2282
2235
|
|
2283
2236
|
if (type === 'ObjectPattern') {
|
2284
2237
|
// hack: ignore object parts of `var a = {} = 2`
|
@@ -2288,8 +2241,18 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2288
2241
|
if (isFuncType(decl.right.type)) {
|
2289
2242
|
// hack for a = function () { ... }
|
2290
2243
|
decl.right.id = { name };
|
2291
|
-
|
2292
|
-
|
2244
|
+
|
2245
|
+
const func = generateFunc(scope, decl.right);
|
2246
|
+
|
2247
|
+
return [
|
2248
|
+
...number(func.index - importedFuncs.length),
|
2249
|
+
...(local != null ? [
|
2250
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2251
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2252
|
+
|
2253
|
+
...setType(scope, name, TYPES.function)
|
2254
|
+
] : [])
|
2255
|
+
];
|
2293
2256
|
}
|
2294
2257
|
|
2295
2258
|
const op = decl.operator.slice(0, -1) || '=';
|
@@ -2388,8 +2351,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2388
2351
|
|
2389
2352
|
if (!name) return todo(scope, 'destructuring is not supported yet', true);
|
2390
2353
|
|
2391
|
-
const [ local, isGlobal ] = lookupName(scope, name);
|
2392
|
-
|
2393
2354
|
if (local === undefined) {
|
2394
2355
|
// todo: this should be a sloppy mode only thing
|
2395
2356
|
|
@@ -3036,13 +2997,6 @@ const generateEmpty = (scope, decl) => {
|
|
3036
2997
|
return [];
|
3037
2998
|
};
|
3038
2999
|
|
3039
|
-
const generateAssignPat = (scope, decl) => {
|
3040
|
-
// TODO
|
3041
|
-
// if identifier declared, use that
|
3042
|
-
// else, use default (right)
|
3043
|
-
return todo(scope, 'assignment pattern (optional arg)');
|
3044
|
-
};
|
3045
|
-
|
3046
3000
|
let pages = new Map();
|
3047
3001
|
const allocPage = (scope, reason, type) => {
|
3048
3002
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3455,8 +3409,11 @@ const generateFunc = (scope, decl) => {
|
|
3455
3409
|
};
|
3456
3410
|
|
3457
3411
|
if (typedInput && decl.returnType) {
|
3458
|
-
|
3459
|
-
|
3412
|
+
const { type } = extractTypeAnnotation(decl.returnType);
|
3413
|
+
if (type != null && !Prefs.indirectCalls) {
|
3414
|
+
innerScope.returnType = type;
|
3415
|
+
innerScope.returns = [ valtypeBinary ];
|
3416
|
+
}
|
3460
3417
|
}
|
3461
3418
|
|
3462
3419
|
for (let i = 0; i < params.length; i++) {
|
@@ -3498,7 +3455,7 @@ const generateFunc = (scope, decl) => {
|
|
3498
3455
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3499
3456
|
wasm.push(
|
3500
3457
|
...number(0),
|
3501
|
-
...number(TYPES.undefined, Valtype.i32),
|
3458
|
+
...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3502
3459
|
[ Opcodes.return ]
|
3503
3460
|
);
|
3504
3461
|
}
|
package/compiler/decompile.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype } from
|
2
|
-
import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from
|
1
|
+
import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
2
|
+
import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
|
3
3
|
|
4
4
|
const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
|
5
5
|
const invOpcodes = inv(Opcodes);
|
package/compiler/embedding.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Opcodes, Valtype } from
|
2
|
-
import { signedLEB128, ieee754_binary64 } from
|
1
|
+
import { Opcodes, Valtype } from './wasmSpec.js';
|
2
|
+
import { signedLEB128, ieee754_binary64 } from './encoding.js';
|
3
3
|
|
4
4
|
export const number = (n, valtype = valtypeBinary) => {
|
5
5
|
switch (valtype) {
|
package/compiler/encoding.js
CHANGED
@@ -7,21 +7,7 @@ export const codifyString = str => {
|
|
7
7
|
return out;
|
8
8
|
};
|
9
9
|
|
10
|
-
// export const encodeString = str => [
|
11
|
-
// str.length,
|
12
|
-
// ...codifyString(str)
|
13
|
-
// ];
|
14
10
|
export const encodeString = str => unsignedLEB128(str.length).concat(codifyString(str));
|
15
|
-
|
16
|
-
// export const encodeVector = data => [
|
17
|
-
// ...unsignedLEB128(data.length),
|
18
|
-
// ...data.flat()
|
19
|
-
// ];
|
20
|
-
// export const encodeVector = data => {
|
21
|
-
// const out = data.flat();
|
22
|
-
// out.unshift.apply(out, unsignedLEB128(data.length));
|
23
|
-
// return out;
|
24
|
-
// };
|
25
11
|
export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat());
|
26
12
|
|
27
13
|
export const encodeLocal = (count, type) => [
|
package/compiler/expression.js
CHANGED