porffor 0.1.1 → 0.2.0-c6c8c81
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 +184 -204
- package/compiler/2c.js +377 -0
- package/compiler/builtins/base64.js +91 -91
- package/compiler/builtins.js +19 -13
- package/compiler/codeGen.js +1313 -418
- package/compiler/decompile.js +35 -9
- package/compiler/embedding.js +9 -5
- package/compiler/encoding.js +8 -2
- package/compiler/index.js +55 -17
- package/compiler/log.js +15 -0
- package/compiler/opt.js +357 -258
- package/compiler/parse.js +24 -1
- package/compiler/prototype.js +263 -56
- package/compiler/sections.js +51 -8
- package/compiler/wasmSpec.js +3 -0
- package/compiler/wrap.js +20 -6
- package/package.json +6 -1
- package/porf.cmd +1 -1
- 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 -31
- package/runner/info.js +37 -2
- package/runner/profile.js +1 -2
- package/runner/repl.js +13 -11
- package/runner/results.json +1 -0
- package/runner/transform.js +15 -36
- package/runner/version.js +10 -0
- package/CNAME +0 -1
- package/index.html +0 -1264
- package/logo.png +0 -0
- package/sw.js +0 -26
package/compiler/parse.js
CHANGED
@@ -1,4 +1,27 @@
|
|
1
|
-
|
1
|
+
import { log } from "./log.js";
|
2
|
+
|
3
|
+
// deno compat
|
4
|
+
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
5
|
+
const textEncoder = new TextEncoder();
|
6
|
+
globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
|
7
|
+
}
|
8
|
+
|
9
|
+
// import { parse } from 'acorn';
|
10
|
+
|
11
|
+
// todo: review which to use by default
|
12
|
+
const parser = process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? 'acorn';
|
13
|
+
const { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
|
14
|
+
|
15
|
+
// supported parsers:
|
16
|
+
// - acorn
|
17
|
+
// - meriyah
|
18
|
+
// - hermes-parser
|
19
|
+
// - @babel/parser
|
20
|
+
|
21
|
+
// should we try to support types (while parsing)
|
22
|
+
const types = process.argv.includes('-types');
|
23
|
+
|
24
|
+
if (types && !['@babel/parser', 'hermes-parser'].includes(parser)) log.warning('parser', `passed -types with a parser (${parser}) which does not support`);
|
2
25
|
|
3
26
|
export default (input, flags) => {
|
4
27
|
return parse(input, {
|
package/compiler/prototype.js
CHANGED
@@ -5,27 +5,30 @@ import { UNDEFINED } from "./builtins.js";
|
|
5
5
|
|
6
6
|
// todo: do not duplicate this
|
7
7
|
const TYPES = {
|
8
|
-
number:
|
9
|
-
boolean:
|
10
|
-
string:
|
11
|
-
undefined:
|
12
|
-
object:
|
13
|
-
function:
|
14
|
-
symbol:
|
15
|
-
bigint:
|
8
|
+
number: 0x00,
|
9
|
+
boolean: 0x01,
|
10
|
+
string: 0x02,
|
11
|
+
undefined: 0x03,
|
12
|
+
object: 0x04,
|
13
|
+
function: 0x05,
|
14
|
+
symbol: 0x06,
|
15
|
+
bigint: 0x07,
|
16
16
|
|
17
17
|
// these are not "typeof" types but tracked internally
|
18
|
-
_array:
|
18
|
+
_array: 0x10,
|
19
|
+
_regexp: 0x11
|
19
20
|
};
|
20
21
|
|
21
22
|
// todo: turn these into built-ins once arrays and these become less hacky
|
22
23
|
|
23
24
|
export const PrototypeFuncs = function() {
|
24
25
|
const noUnlikelyChecks = process.argv.includes('-funsafe-no-unlikely-proto-checks');
|
26
|
+
let zeroChecks = process.argv.find(x => x.startsWith('-funsafe-zero-proto-checks='));
|
27
|
+
if (zeroChecks) zeroChecks = zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
|
28
|
+
else zeroChecks = {};
|
25
29
|
|
26
30
|
this[TYPES._array] = {
|
27
31
|
// lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
|
28
|
-
// todo: out of bounds (>) properly
|
29
32
|
at: (pointer, length, wIndex, iTmp) => [
|
30
33
|
...wIndex,
|
31
34
|
Opcodes.i32_to,
|
@@ -36,7 +39,7 @@ export const PrototypeFuncs = function() {
|
|
36
39
|
[ Opcodes.i32_lt_s ],
|
37
40
|
[ Opcodes.if, Blocktype.void ],
|
38
41
|
[ Opcodes.local_get, iTmp ],
|
39
|
-
...length.
|
42
|
+
...length.getCachedI32(),
|
40
43
|
[ Opcodes.i32_add ],
|
41
44
|
[ Opcodes.local_set, iTmp ],
|
42
45
|
[ Opcodes.end ],
|
@@ -47,7 +50,7 @@ export const PrototypeFuncs = function() {
|
|
47
50
|
[ Opcodes.i32_lt_s ],
|
48
51
|
|
49
52
|
[ Opcodes.local_get, iTmp ],
|
50
|
-
...length.
|
53
|
+
...length.getCachedI32(),
|
51
54
|
[ Opcodes.i32_ge_s ],
|
52
55
|
[ Opcodes.i32_or ],
|
53
56
|
|
@@ -60,36 +63,48 @@ export const PrototypeFuncs = function() {
|
|
60
63
|
...number(ValtypeSize[valtype], Valtype.i32),
|
61
64
|
[ Opcodes.i32_mul ],
|
62
65
|
|
66
|
+
...pointer,
|
67
|
+
[ Opcodes.i32_add ],
|
68
|
+
|
63
69
|
// read from memory
|
64
|
-
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(
|
70
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
65
71
|
],
|
66
72
|
|
67
73
|
// todo: only for 1 argument
|
68
74
|
push: (pointer, length, wNewMember) => [
|
69
75
|
// get memory offset of array at last index (length)
|
70
|
-
...length.
|
76
|
+
...length.getCachedI32(),
|
71
77
|
...number(ValtypeSize[valtype], Valtype.i32),
|
72
78
|
[ Opcodes.i32_mul ],
|
73
79
|
|
80
|
+
...pointer,
|
81
|
+
[ Opcodes.i32_add ],
|
82
|
+
|
74
83
|
// generated wasm for new member
|
75
84
|
...wNewMember,
|
76
85
|
|
77
86
|
// store in memory
|
78
|
-
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(
|
87
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
79
88
|
|
80
89
|
// bump array length by 1 and return it
|
81
90
|
...length.setI32([
|
82
|
-
...length.
|
91
|
+
...length.getCachedI32(),
|
83
92
|
...number(1, Valtype.i32),
|
84
|
-
[ Opcodes.i32_add ]
|
93
|
+
[ Opcodes.i32_add ],
|
94
|
+
|
95
|
+
...length.setCachedI32(),
|
96
|
+
...length.getCachedI32(),
|
85
97
|
]),
|
86
98
|
|
87
|
-
...length.
|
99
|
+
...length.getCachedI32(),
|
100
|
+
Opcodes.i32_from_u
|
101
|
+
|
102
|
+
// ...length.get()
|
88
103
|
],
|
89
104
|
|
90
105
|
pop: (pointer, length) => [
|
91
106
|
// if length == 0, noop
|
92
|
-
...length.
|
107
|
+
...length.getCachedI32(),
|
93
108
|
[ Opcodes.i32_eqz ],
|
94
109
|
[ Opcodes.if, Blocktype.void ],
|
95
110
|
...number(UNDEFINED),
|
@@ -100,22 +115,28 @@ export const PrototypeFuncs = function() {
|
|
100
115
|
|
101
116
|
// decrement length by 1
|
102
117
|
...length.setI32([
|
103
|
-
...length.
|
118
|
+
...length.getCachedI32(),
|
104
119
|
...number(1, Valtype.i32),
|
105
|
-
[ Opcodes.i32_sub ]
|
120
|
+
[ Opcodes.i32_sub ],
|
121
|
+
|
122
|
+
...length.setCachedI32(),
|
123
|
+
...length.getCachedI32(),
|
106
124
|
]),
|
107
125
|
|
108
126
|
// load last element
|
109
|
-
...length.
|
127
|
+
...length.getCachedI32(),
|
110
128
|
...number(ValtypeSize[valtype], Valtype.i32),
|
111
129
|
[ Opcodes.i32_mul ],
|
112
130
|
|
113
|
-
|
131
|
+
...pointer,
|
132
|
+
[ Opcodes.i32_add ],
|
133
|
+
|
134
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
114
135
|
],
|
115
136
|
|
116
137
|
shift: (pointer, length) => [
|
117
138
|
// if length == 0, noop
|
118
|
-
...length.
|
139
|
+
...length.getCachedI32(),
|
119
140
|
Opcodes.i32_eqz,
|
120
141
|
[ Opcodes.if, Blocktype.void ],
|
121
142
|
...number(UNDEFINED),
|
@@ -126,29 +147,122 @@ export const PrototypeFuncs = function() {
|
|
126
147
|
|
127
148
|
// decrement length by 1
|
128
149
|
...length.setI32([
|
129
|
-
...length.
|
150
|
+
...length.getCachedI32(),
|
130
151
|
...number(1, Valtype.i32),
|
131
|
-
[ Opcodes.i32_sub ]
|
152
|
+
[ Opcodes.i32_sub ],
|
153
|
+
|
154
|
+
...length.setCachedI32(),
|
155
|
+
...length.getCachedI32(),
|
132
156
|
]),
|
133
157
|
|
134
158
|
// load first element
|
135
|
-
...
|
136
|
-
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(
|
159
|
+
...pointer,
|
160
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
161
|
+
|
162
|
+
// offset page by -1 ind
|
163
|
+
// ...number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
|
164
|
+
// ...number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
|
165
|
+
// ...number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
|
166
|
+
// [ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
137
167
|
|
138
168
|
// offset all elements by -1 ind
|
139
|
-
|
140
|
-
|
141
|
-
...number(
|
169
|
+
|
170
|
+
// dst = base array index + length size
|
171
|
+
...number(ValtypeSize.i32, Valtype.i32),
|
172
|
+
...pointer,
|
173
|
+
[ Opcodes.i32_add ],
|
174
|
+
|
175
|
+
// src = base array index + length size + an index
|
176
|
+
...number(ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32),
|
177
|
+
...pointer,
|
178
|
+
[ Opcodes.i32_add ],
|
179
|
+
|
180
|
+
// size = new length * sizeof element
|
181
|
+
...length.getCachedI32(),
|
182
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
183
|
+
[ Opcodes.i32_mul ],
|
142
184
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
185
|
+
|
186
|
+
// move pointer + sizeof element
|
187
|
+
// ...pointer.get(),
|
188
|
+
// ...number(ValtypeSize[valtype], Valtype.i32),
|
189
|
+
// [ Opcodes.i32_add ],
|
190
|
+
// ...pointer.set(),
|
191
|
+
|
192
|
+
// // write length - 1 in new address
|
193
|
+
// ...length.setI32([
|
194
|
+
// ...length.getCachedI32(),
|
195
|
+
// ...number(1, Valtype.i32),
|
196
|
+
// [ Opcodes.i32_sub ]
|
197
|
+
// ]),
|
198
|
+
],
|
199
|
+
|
200
|
+
fill: (pointer, length, wElement, iTmp) => [
|
201
|
+
...wElement,
|
202
|
+
[ Opcodes.local_set, iTmp ],
|
203
|
+
|
204
|
+
// use cached length i32 as pointer
|
205
|
+
...length.getCachedI32(),
|
206
|
+
|
207
|
+
// length - 1 for indexes
|
208
|
+
...number(1, Valtype.i32),
|
209
|
+
[ Opcodes.i32_sub ],
|
210
|
+
|
211
|
+
// * sizeof value
|
212
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
213
|
+
[ Opcodes.i32_mul ],
|
214
|
+
|
215
|
+
...length.setCachedI32(),
|
216
|
+
|
217
|
+
...(noUnlikelyChecks ? [] : [
|
218
|
+
...length.getCachedI32(),
|
219
|
+
...number(0, Valtype.i32),
|
220
|
+
[ Opcodes.i32_lt_s ],
|
221
|
+
[ Opcodes.if, Blocktype.void ],
|
222
|
+
...pointer,
|
223
|
+
Opcodes.i32_from_u,
|
224
|
+
[ Opcodes.br, 1 ],
|
225
|
+
[ Opcodes.end ]
|
226
|
+
]),
|
227
|
+
|
228
|
+
[ Opcodes.loop, Blocktype.void ],
|
229
|
+
|
230
|
+
// set element using pointer
|
231
|
+
...length.getCachedI32(),
|
232
|
+
...pointer,
|
233
|
+
[ Opcodes.i32_add ],
|
234
|
+
|
235
|
+
[ Opcodes.local_get, iTmp ],
|
236
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128( ValtypeSize.i32) ],
|
237
|
+
|
238
|
+
// pointer - sizeof value
|
239
|
+
...length.getCachedI32(),
|
240
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
241
|
+
[ Opcodes.i32_sub ],
|
242
|
+
|
243
|
+
...length.setCachedI32(),
|
244
|
+
|
245
|
+
// if pointer >= 0, loop
|
246
|
+
...length.getCachedI32(),
|
247
|
+
...number(0, Valtype.i32),
|
248
|
+
[ Opcodes.i32_ge_s ],
|
249
|
+
[ Opcodes.br_if, 0 ],
|
250
|
+
|
251
|
+
[ Opcodes.end ],
|
252
|
+
|
253
|
+
// return this array
|
254
|
+
...pointer,
|
255
|
+
Opcodes.i32_from_u,
|
143
256
|
]
|
144
257
|
};
|
145
258
|
|
146
259
|
this[TYPES._array].at.local = Valtype.i32;
|
147
260
|
this[TYPES._array].push.noArgRetLength = true;
|
261
|
+
this[TYPES._array].fill.local = valtypeBinary;
|
262
|
+
this[TYPES._array].fill.returnType = TYPES._array;
|
148
263
|
|
149
264
|
this[TYPES.string] = {
|
150
|
-
|
151
|
-
at: (pointer, length, wIndex, iTmp, arrayShell) => {
|
265
|
+
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
152
266
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
153
267
|
|
154
268
|
return [
|
@@ -157,9 +271,9 @@ export const PrototypeFuncs = function() {
|
|
157
271
|
[ Opcodes.drop ],
|
158
272
|
|
159
273
|
...number(0, Valtype.i32), // base 0 for store later
|
160
|
-
Opcodes.i32_to_u,
|
161
274
|
|
162
275
|
...wIndex,
|
276
|
+
Opcodes.i32_to_u,
|
163
277
|
[ Opcodes.local_tee, iTmp ],
|
164
278
|
|
165
279
|
// if index < 0: access index + array length
|
@@ -167,7 +281,7 @@ export const PrototypeFuncs = function() {
|
|
167
281
|
[ Opcodes.i32_lt_s ],
|
168
282
|
[ Opcodes.if, Blocktype.void ],
|
169
283
|
[ Opcodes.local_get, iTmp ],
|
170
|
-
...length.
|
284
|
+
...length.getCachedI32(),
|
171
285
|
[ Opcodes.i32_add ],
|
172
286
|
[ Opcodes.local_set, iTmp ],
|
173
287
|
[ Opcodes.end ],
|
@@ -178,7 +292,7 @@ export const PrototypeFuncs = function() {
|
|
178
292
|
[ Opcodes.i32_lt_s ],
|
179
293
|
|
180
294
|
[ Opcodes.local_get, iTmp ],
|
181
|
-
...length.
|
295
|
+
...length.getCachedI32(),
|
182
296
|
[ Opcodes.i32_ge_s ],
|
183
297
|
[ Opcodes.i32_or ],
|
184
298
|
|
@@ -191,8 +305,11 @@ export const PrototypeFuncs = function() {
|
|
191
305
|
...number(ValtypeSize.i16, Valtype.i32),
|
192
306
|
[ Opcodes.i32_mul ],
|
193
307
|
|
308
|
+
...pointer,
|
309
|
+
[ Opcodes.i32_add ],
|
310
|
+
|
194
311
|
// load current string ind {arg}
|
195
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(
|
312
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
196
313
|
|
197
314
|
// store to new string ind 0
|
198
315
|
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
@@ -203,7 +320,7 @@ export const PrototypeFuncs = function() {
|
|
203
320
|
},
|
204
321
|
|
205
322
|
// todo: out of bounds properly
|
206
|
-
charAt: (pointer, length, wIndex,
|
323
|
+
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
207
324
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
208
325
|
|
209
326
|
return [
|
@@ -219,8 +336,11 @@ export const PrototypeFuncs = function() {
|
|
219
336
|
...number(ValtypeSize.i16, Valtype.i32),
|
220
337
|
[ Opcodes.i32_mul ],
|
221
338
|
|
339
|
+
...pointer,
|
340
|
+
[ Opcodes.i32_add ],
|
341
|
+
|
222
342
|
// load current string ind {arg}
|
223
|
-
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(
|
343
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
224
344
|
|
225
345
|
// store to new string ind 0
|
226
346
|
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
@@ -234,39 +354,126 @@ export const PrototypeFuncs = function() {
|
|
234
354
|
return [
|
235
355
|
...wIndex,
|
236
356
|
Opcodes.i32_to,
|
237
|
-
[ Opcodes.local_set, iTmp ],
|
238
357
|
|
239
|
-
|
240
|
-
|
358
|
+
...(zeroChecks.charcodeat ? [] : [
|
359
|
+
[ Opcodes.local_set, iTmp ],
|
360
|
+
|
361
|
+
// index < 0
|
362
|
+
...(noUnlikelyChecks ? [] : [
|
363
|
+
[ Opcodes.local_get, iTmp ],
|
364
|
+
...number(0, Valtype.i32),
|
365
|
+
[ Opcodes.i32_lt_s ],
|
366
|
+
]),
|
367
|
+
|
368
|
+
// index >= length
|
369
|
+
[ Opcodes.local_get, iTmp ],
|
370
|
+
...length.getCachedI32(),
|
371
|
+
[ Opcodes.i32_ge_s ],
|
372
|
+
|
373
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
374
|
+
[ Opcodes.if, Blocktype.void ],
|
375
|
+
...number(NaN),
|
376
|
+
[ Opcodes.br, 1 ],
|
377
|
+
[ Opcodes.end ],
|
378
|
+
|
241
379
|
[ Opcodes.local_get, iTmp ],
|
242
|
-
...number(0, Valtype.i32),
|
243
|
-
[ Opcodes.i32_lt_s ],
|
244
380
|
]),
|
245
381
|
|
246
|
-
|
382
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
383
|
+
[ Opcodes.i32_mul ],
|
384
|
+
|
385
|
+
...pointer,
|
386
|
+
[ Opcodes.i32_add ],
|
387
|
+
|
388
|
+
// load current string ind {arg}
|
389
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
390
|
+
Opcodes.i32_from_u
|
391
|
+
];
|
392
|
+
},
|
393
|
+
|
394
|
+
isWellFormed: (pointer, length, wIndex, iTmp, iTmp2) => {
|
395
|
+
return [
|
396
|
+
// note: we cannot presume it begins as 0 in case it was used previously
|
397
|
+
...pointer,
|
398
|
+
[ Opcodes.local_set, iTmp ],
|
399
|
+
|
400
|
+
// use cached length as end pointer
|
401
|
+
...length.getCachedI32(),
|
402
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
403
|
+
[ Opcodes.i32_mul ],
|
404
|
+
...pointer,
|
405
|
+
[ Opcodes.i32_add ],
|
406
|
+
...length.setCachedI32(),
|
407
|
+
|
408
|
+
[ Opcodes.loop, Blocktype.void ],
|
409
|
+
|
410
|
+
[ Opcodes.block, Blocktype.void ],
|
411
|
+
|
247
412
|
[ Opcodes.local_get, iTmp ],
|
248
|
-
...
|
413
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
414
|
+
[ Opcodes.local_set, iTmp2 ],
|
415
|
+
|
416
|
+
// if not surrogate, continue
|
417
|
+
[ Opcodes.local_get, iTmp2 ],
|
418
|
+
...number(0xF800, Valtype.i32),
|
419
|
+
[ Opcodes.i32_and ],
|
420
|
+
...number(0xD800, Valtype.i32),
|
421
|
+
[ Opcodes.i32_ne ],
|
422
|
+
[ Opcodes.br_if, 0 ],
|
423
|
+
|
424
|
+
// if not leading surrogate, return false
|
425
|
+
[ Opcodes.local_get, iTmp2 ],
|
426
|
+
...number(0xDC00, Valtype.i32),
|
249
427
|
[ Opcodes.i32_ge_s ],
|
428
|
+
[ Opcodes.if, Blocktype.void ],
|
429
|
+
...number(0),
|
430
|
+
[ Opcodes.br, 3 ],
|
431
|
+
[ Opcodes.end ],
|
250
432
|
|
251
|
-
|
433
|
+
// if not followed by trailing surrogate, return false
|
434
|
+
[ Opcodes.local_get, iTmp ],
|
435
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize.i16) ],
|
436
|
+
...number(0xFC00, Valtype.i32),
|
437
|
+
[ Opcodes.i32_and ],
|
438
|
+
...number(0xDC00, Valtype.i32),
|
439
|
+
[ Opcodes.i32_ne ],
|
252
440
|
[ Opcodes.if, Blocktype.void ],
|
253
|
-
...number(
|
254
|
-
[ Opcodes.br,
|
441
|
+
...number(0),
|
442
|
+
[ Opcodes.br, 3 ],
|
255
443
|
[ Opcodes.end ],
|
256
444
|
|
445
|
+
// bump index again since gone through two valid chars
|
257
446
|
[ Opcodes.local_get, iTmp ],
|
258
447
|
...number(ValtypeSize.i16, Valtype.i32),
|
259
|
-
[ Opcodes.
|
448
|
+
[ Opcodes.i32_add ],
|
449
|
+
[ Opcodes.local_set, iTmp ],
|
260
450
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
451
|
+
[ Opcodes.end ],
|
452
|
+
|
453
|
+
// bump pointer and loop if not at the end
|
454
|
+
[ Opcodes.local_get, iTmp ],
|
455
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
456
|
+
[ Opcodes.i32_add ],
|
457
|
+
[ Opcodes.local_tee, iTmp ],
|
458
|
+
|
459
|
+
...length.getCachedI32(), // end pointer
|
460
|
+
[ Opcodes.i32_ne ],
|
461
|
+
[ Opcodes.br_if, 0 ],
|
462
|
+
|
463
|
+
[ Opcodes.end ],
|
464
|
+
|
465
|
+
// return true
|
466
|
+
...number(1)
|
467
|
+
]
|
468
|
+
}
|
266
469
|
};
|
267
470
|
|
268
|
-
this[TYPES.string].at.local =
|
471
|
+
this[TYPES.string].at.local = Valtype.i32;
|
269
472
|
this[TYPES.string].at.returnType = TYPES.string;
|
270
473
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
271
474
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
475
|
+
|
476
|
+
this[TYPES.string].isWellFormed.local = Valtype.i32;
|
477
|
+
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
478
|
+
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
272
479
|
};
|
package/compiler/sections.js
CHANGED
@@ -1,18 +1,34 @@
|
|
1
1
|
import { Valtype, FuncType, Empty, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize } from './wasmSpec.js';
|
2
|
-
import { encodeVector, encodeString, encodeLocal } from './encoding.js';
|
2
|
+
import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 } from './encoding.js';
|
3
3
|
import { number } from './embedding.js';
|
4
4
|
import { importedFuncs } from './builtins.js';
|
5
|
+
import { log } from "./log.js";
|
5
6
|
|
6
7
|
const createSection = (type, data) => [
|
7
8
|
type,
|
8
9
|
...encodeVector(data)
|
9
10
|
];
|
10
11
|
|
11
|
-
|
12
|
+
const customSection = (name, data) => [
|
13
|
+
Section.custom,
|
14
|
+
...encodeVector([...encodeString(name), ...data])
|
15
|
+
];
|
16
|
+
|
17
|
+
const chHint = (topTier, baselineTier, strategy) => {
|
18
|
+
// 1 byte of 4 2 bit components: spare, top tier, baseline tier, compilation strategy
|
19
|
+
// tiers: 0x00 = default, 0x01 = baseline (liftoff), 0x02 = optimized (turbofan)
|
20
|
+
// strategy: 0x00 = default, 0x01 = lazy, 0x02 = eager, 0x03 = lazy baseline, eager top tier
|
21
|
+
return (strategy | (baselineTier << 2) | (topTier << 4));
|
22
|
+
};
|
23
|
+
|
24
|
+
export default (funcs, globals, tags, pages, data, flags) => {
|
12
25
|
const types = [], typeCache = {};
|
13
26
|
|
14
27
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
15
28
|
|
29
|
+
const compileHints = process.argv.includes('-compile-hints');
|
30
|
+
if (compileHints) log.warning('sections', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
|
31
|
+
|
16
32
|
const getType = (params, returns) => {
|
17
33
|
const hash = `${params.join(',')}_${returns.join(',')}`;
|
18
34
|
if (optLog) log('sections', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
|
@@ -36,7 +52,7 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
36
52
|
// tree shake imports
|
37
53
|
for (const f of funcs) {
|
38
54
|
for (const inst of f.wasm) {
|
39
|
-
if (inst[0] === Opcodes.call && inst[1] < importedFuncs.length) {
|
55
|
+
if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] < importedFuncs.length) {
|
40
56
|
const idx = inst[1];
|
41
57
|
const func = importedFuncs[idx];
|
42
58
|
|
@@ -51,15 +67,17 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
51
67
|
// fix call indexes for non-imports
|
52
68
|
const delta = importedFuncs.length - importFuncs.length;
|
53
69
|
for (const f of funcs) {
|
70
|
+
f.originalIndex = f.index;
|
54
71
|
f.index -= delta;
|
55
72
|
|
56
73
|
for (const inst of f.wasm) {
|
57
|
-
if (inst[0] === Opcodes.call && inst[1] >= importedFuncs.length) {
|
74
|
+
if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] >= importedFuncs.length) {
|
58
75
|
inst[1] -= delta;
|
59
76
|
}
|
60
77
|
}
|
61
78
|
}
|
62
79
|
}
|
80
|
+
globalThis.importFuncs = importFuncs;
|
63
81
|
|
64
82
|
if (optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
65
83
|
|
@@ -73,6 +91,14 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
73
91
|
encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
|
74
92
|
);
|
75
93
|
|
94
|
+
// compilation hints section - unspecd, v8 only
|
95
|
+
// https://github.com/WebAssembly/design/issues/1473#issuecomment-1431274746
|
96
|
+
const chSection = !compileHints ? [] : customSection(
|
97
|
+
'compilationHints',
|
98
|
+
// for now just do everything as optimise eager
|
99
|
+
encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
|
100
|
+
);
|
101
|
+
|
76
102
|
const globalSection = Object.keys(globals).length === 0 ? [] : createSection(
|
77
103
|
Section.global,
|
78
104
|
encodeVector(Object.keys(globals).map(x => [ globals[x].type, 0x01, ...number(globals[x].init ?? 0, globals[x].type).flat(), Opcodes.end ]))
|
@@ -80,10 +106,13 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
80
106
|
|
81
107
|
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
|
82
108
|
|
109
|
+
if (process.argv.includes('-always-memory') && pages.size === 0) pages.set('-always-memory', 0);
|
110
|
+
if (optLevel === 0) pages.set('O0 precaution', 0);
|
111
|
+
|
83
112
|
const usesMemory = pages.size > 0;
|
84
113
|
const memorySection = !usesMemory ? [] : createSection(
|
85
114
|
Section.memory,
|
86
|
-
encodeVector([ [ 0x00, Math.ceil((pages.size * pageSize) / PageSize) ] ])
|
115
|
+
encodeVector([ [ 0x00, ...unsignedLEB128(Math.ceil((pages.size * pageSize) / PageSize)) ] ])
|
87
116
|
);
|
88
117
|
|
89
118
|
// export memory if used
|
@@ -121,7 +150,7 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
121
150
|
|
122
151
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
123
152
|
|
124
|
-
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x
|
153
|
+
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x <= 0xff), Opcodes.end ]);
|
125
154
|
}))
|
126
155
|
);
|
127
156
|
|
@@ -130,13 +159,24 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
130
159
|
encodeVector(types)
|
131
160
|
);
|
132
161
|
|
162
|
+
const dataSection = data.length === 0 ? [] : createSection(
|
163
|
+
Section.data,
|
164
|
+
encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
|
165
|
+
);
|
166
|
+
|
167
|
+
const dataCountSection = data.length === 0 ? [] : createSection(
|
168
|
+
Section.data_count,
|
169
|
+
unsignedLEB128(data.length)
|
170
|
+
);
|
171
|
+
|
133
172
|
if (process.argv.includes('-sections')) console.log({
|
134
173
|
typeSection: typeSection.map(x => x.toString(16)),
|
135
174
|
importSection: importSection.map(x => x.toString(16)),
|
136
175
|
funcSection: funcSection.map(x => x.toString(16)),
|
137
176
|
globalSection: globalSection.map(x => x.toString(16)),
|
138
177
|
exportSection: exportSection.map(x => x.toString(16)),
|
139
|
-
codeSection: codeSection.map(x => x.toString(16))
|
178
|
+
codeSection: codeSection.map(x => x.toString(16)),
|
179
|
+
dataSection: dataSection.map(x => x.toString(16)),
|
140
180
|
});
|
141
181
|
|
142
182
|
return Uint8Array.from([
|
@@ -145,10 +185,13 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
145
185
|
...typeSection,
|
146
186
|
...importSection,
|
147
187
|
...funcSection,
|
188
|
+
...chSection,
|
148
189
|
...memorySection,
|
149
190
|
...tagSection,
|
150
191
|
...globalSection,
|
151
192
|
...exportSection,
|
152
|
-
...
|
193
|
+
...dataCountSection,
|
194
|
+
...codeSection,
|
195
|
+
...dataSection
|
153
196
|
]);
|
154
197
|
};
|
package/compiler/wasmSpec.js
CHANGED
@@ -118,6 +118,7 @@ export const Opcodes = {
|
|
118
118
|
i64_shl: 0x86,
|
119
119
|
i64_shr_s: 0x87,
|
120
120
|
i64_shr_u: 0x88,
|
121
|
+
i64_rotl: 0x89,
|
121
122
|
|
122
123
|
f64_eq: 0x61,
|
123
124
|
f64_ne: 0x62,
|
@@ -156,6 +157,8 @@ export const Opcodes = {
|
|
156
157
|
f64_convert_i64_s: 0xb9,
|
157
158
|
f64_convert_i64_u: 0xba,
|
158
159
|
|
160
|
+
f64_reinterpret_i64: 0xbf,
|
161
|
+
|
159
162
|
i32_trunc_sat_f64_s: [ 0xfc, 0x02 ],
|
160
163
|
i32_trunc_sat_f64_u: [ 0xfc, 0x03 ],
|
161
164
|
|