porffor 0.0.0-745e995 → 0.0.0-7d5ae9c
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 +49 -15
- package/c +0 -0
- package/c.exe +0 -0
- package/compiler/2c.js +350 -0
- package/compiler/builtins.js +6 -1
- package/compiler/codeGen.js +639 -186
- package/compiler/decompile.js +3 -3
- package/compiler/embedding.js +9 -5
- package/compiler/encoding.js +4 -2
- package/compiler/index.js +55 -4
- package/compiler/opt.js +49 -23
- package/compiler/parse.js +1 -0
- package/compiler/prototype.js +172 -34
- package/compiler/sections.js +47 -6
- package/compiler/wrap.js +19 -1
- package/cool.exe +0 -0
- package/g +0 -0
- package/g.exe +0 -0
- package/hi.c +37 -0
- package/out +0 -0
- package/out.exe +0 -0
- package/package.json +1 -1
- package/r.js +39 -0
- package/rhemyn/README.md +37 -0
- package/rhemyn/compile.js +214 -0
- package/rhemyn/parse.js +321 -0
- package/rhemyn/test/parse.js +59 -0
- package/runner/index.js +54 -33
- package/runner/info.js +37 -2
- package/runner/repl.js +6 -11
- package/runner/transform.js +5 -26
- package/runner/version.js +10 -0
- package/t.js +31 -0
- package/tmp.c +58 -0
package/compiler/decompile.js
CHANGED
@@ -42,8 +42,8 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
42
42
|
out += ` ${read_ieee754_binary64(inst.slice(1))}`;
|
43
43
|
} else if (inst[0] === Opcodes.i32_const || inst[0] === Opcodes.i64_const) {
|
44
44
|
out += ` ${read_signedLEB128(inst.slice(1))}`;
|
45
|
-
} else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store) {
|
46
|
-
out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}
|
45
|
+
} else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store || inst[0] === Opcodes.i32_store16 || inst[0] === Opcodes.i32_load16_u) {
|
46
|
+
out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}`;
|
47
47
|
} else for (const operand of inst.slice(1)) {
|
48
48
|
if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block) {
|
49
49
|
if (operand === Blocktype.void) continue;
|
@@ -57,7 +57,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
57
57
|
out += ` ;; label @${depth}`;
|
58
58
|
}
|
59
59
|
|
60
|
-
if (inst[0] === Opcodes.br) {
|
60
|
+
if (inst[0] === Opcodes.br || inst[0] === Opcodes.br_if) {
|
61
61
|
out += ` ;; goto @${depth - inst[1]}`;
|
62
62
|
}
|
63
63
|
|
package/compiler/embedding.js
CHANGED
@@ -9,11 +9,15 @@ export const number = (n, valtype = valtypeBinary) => {
|
|
9
9
|
}
|
10
10
|
};
|
11
11
|
|
12
|
-
const
|
12
|
+
export const enforceOneByte = arr => [ arr[0] ?? 0 ];
|
13
|
+
export const enforceTwoBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0 ];
|
14
|
+
export const enforceFourBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0 ];
|
15
|
+
export const enforceEightBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0, arr[4] ?? 0, arr[5] ?? 0, arr[6] ?? 0, arr[7] ?? 0 ];
|
16
|
+
|
13
17
|
export const i32x4 = (a, b, c, d) => [ [
|
14
18
|
...Opcodes.v128_const,
|
15
|
-
...
|
16
|
-
...
|
17
|
-
...
|
18
|
-
...
|
19
|
+
...enforceFourBytes(signedLEB128(a)),
|
20
|
+
...enforceFourBytes(signedLEB128(b)),
|
21
|
+
...enforceFourBytes(signedLEB128(c)),
|
22
|
+
...enforceFourBytes(signedLEB128(d))
|
19
23
|
] ];
|
package/compiler/encoding.js
CHANGED
@@ -22,15 +22,15 @@ export const encodeLocal = (count, type) => [
|
|
22
22
|
type
|
23
23
|
];
|
24
24
|
|
25
|
+
// todo: this only works with integers within 32 bit range
|
25
26
|
export const signedLEB128 = n => {
|
26
|
-
|
27
|
+
n |= 0;
|
27
28
|
|
28
29
|
// just input for small numbers (for perf as common)
|
29
30
|
if (n >= 0 && n <= 63) return [ n ];
|
30
31
|
if (n >= -64 && n <= 0) return [ 128 + n ];
|
31
32
|
|
32
33
|
const buffer = [];
|
33
|
-
n |= 0;
|
34
34
|
|
35
35
|
while (true) {
|
36
36
|
let byte = n & 0x7f;
|
@@ -50,6 +50,8 @@ export const signedLEB128 = n => {
|
|
50
50
|
};
|
51
51
|
|
52
52
|
export const unsignedLEB128 = n => {
|
53
|
+
n |= 0;
|
54
|
+
|
53
55
|
// just input for small numbers (for perf as common)
|
54
56
|
if (n >= 0 && n <= 127) return [ n ];
|
55
57
|
|
package/compiler/index.js
CHANGED
@@ -4,6 +4,8 @@ import opt from './opt.js';
|
|
4
4
|
import produceSections from './sections.js';
|
5
5
|
import decompile from './decompile.js';
|
6
6
|
import { BuiltinPreludes } from './builtins.js';
|
7
|
+
import toc from './2c.js';
|
8
|
+
|
7
9
|
|
8
10
|
globalThis.decompile = decompile;
|
9
11
|
|
@@ -14,7 +16,9 @@ const bold = x => `\u001b[1m${x}\u001b[0m`;
|
|
14
16
|
const areaColors = {
|
15
17
|
codegen: [ 20, 80, 250 ],
|
16
18
|
opt: [ 250, 20, 80 ],
|
17
|
-
sections: [ 20, 250, 80 ]
|
19
|
+
sections: [ 20, 250, 80 ],
|
20
|
+
alloc: [ 250, 250, 20 ],
|
21
|
+
'2c': [ 20, 250, 250 ]
|
18
22
|
};
|
19
23
|
|
20
24
|
globalThis.log = (area, ...args) => console.log(`\u001b[90m[\u001b[0m${rgb(...areaColors[area], area)}\u001b[90m]\u001b[0m`, ...args);
|
@@ -35,9 +39,16 @@ const logFuncs = (funcs, globals, exceptions) => {
|
|
35
39
|
console.log();
|
36
40
|
};
|
37
41
|
|
42
|
+
const getArg = name => process.argv.find(x => x.startsWith(`-${name}=`))?.slice(name.length + 2);
|
43
|
+
|
44
|
+
const writeFileSync = (typeof process !== 'undefined' ? (await import('node:fs')).writeFileSync : undefined);
|
45
|
+
const execSync = (typeof process !== 'undefined' ? (await import('node:child_process')).execSync : undefined);
|
46
|
+
|
38
47
|
export default (code, flags) => {
|
39
48
|
globalThis.optLog = process.argv.includes('-opt-log');
|
40
49
|
globalThis.codeLog = process.argv.includes('-code-log');
|
50
|
+
globalThis.allocLog = process.argv.includes('-alloc-log');
|
51
|
+
globalThis.regexLog = process.argv.includes('-regex-log');
|
41
52
|
|
42
53
|
for (const x in BuiltinPreludes) {
|
43
54
|
if (code.indexOf(x + '(') !== -1) code = BuiltinPreludes[x] + code;
|
@@ -48,7 +59,7 @@ export default (code, flags) => {
|
|
48
59
|
if (flags.includes('info')) console.log(`1. parsed in ${(performance.now() - t0).toFixed(2)}ms`);
|
49
60
|
|
50
61
|
const t1 = performance.now();
|
51
|
-
const { funcs, globals, tags, exceptions, pages } = codeGen(program);
|
62
|
+
const { funcs, globals, tags, exceptions, pages, data } = codeGen(program);
|
52
63
|
if (flags.includes('info')) console.log(`2. generated code in ${(performance.now() - t1).toFixed(2)}ms`);
|
53
64
|
|
54
65
|
if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
|
@@ -60,8 +71,48 @@ export default (code, flags) => {
|
|
60
71
|
if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
|
61
72
|
|
62
73
|
const t3 = performance.now();
|
63
|
-
const sections = produceSections(funcs, globals, tags, pages, flags);
|
74
|
+
const sections = produceSections(funcs, globals, tags, pages, data, flags);
|
64
75
|
if (flags.includes('info')) console.log(`4. produced sections in ${(performance.now() - t3).toFixed(2)}ms`);
|
65
76
|
|
66
|
-
|
77
|
+
if (allocLog) {
|
78
|
+
const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
|
79
|
+
const bytes = wasmPages * 65536;
|
80
|
+
log('alloc', `\x1B[1mallocated ${bytes / 1024}KiB\x1B[0m for ${pages.size} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}`);
|
81
|
+
console.log([...pages.keys()].map(x => `\x1B[36m - ${x}\x1B[0m`).join('\n') + '\n');
|
82
|
+
}
|
83
|
+
|
84
|
+
const out = { wasm: sections, funcs, globals, tags, exceptions, pages };
|
85
|
+
|
86
|
+
const target = getArg('target') ?? getArg('t') ?? 'wasm';
|
87
|
+
const outFile = getArg('o');
|
88
|
+
|
89
|
+
if (target === 'c') {
|
90
|
+
const c = toc(out);
|
91
|
+
|
92
|
+
if (outFile) {
|
93
|
+
writeFileSync(outFile, c);
|
94
|
+
} else {
|
95
|
+
console.log(c);
|
96
|
+
}
|
97
|
+
|
98
|
+
process.exit();
|
99
|
+
}
|
100
|
+
|
101
|
+
if (target === 'native') {
|
102
|
+
const compiler = getArg('compiler') ?? 'clang';
|
103
|
+
const cO = getArg('cO') ?? 'Ofast';
|
104
|
+
|
105
|
+
const tmpfile = 'tmp.c';
|
106
|
+
const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native' ];
|
107
|
+
|
108
|
+
const c = toc(out);
|
109
|
+
writeFileSync(tmpfile, c);
|
110
|
+
|
111
|
+
// obvious command escape is obvious
|
112
|
+
execSync(args.join(' '), { stdio: 'inherit' });
|
113
|
+
|
114
|
+
process.exit();
|
115
|
+
}
|
116
|
+
|
117
|
+
return out;
|
67
118
|
};
|
package/compiler/opt.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Opcodes, Valtype } from "./wasmSpec.js";
|
2
2
|
import { number } from "./embedding.js";
|
3
|
+
import { read_signedLEB128, read_ieee754_binary64 } from "./encoding.js";
|
3
4
|
|
4
5
|
// deno compat
|
5
6
|
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
@@ -20,7 +21,7 @@ export default (funcs, globals) => {
|
|
20
21
|
if (optLevel === 0) return;
|
21
22
|
|
22
23
|
const tailCall = process.argv.includes('-tail-call');
|
23
|
-
if (tailCall) log('opt', 'tail call proposal is not widely implemented! (you used -tail-call)');
|
24
|
+
if (tailCall) log('opt', 'warning: tail call proposal is not widely implemented! (you used -tail-call)');
|
24
25
|
|
25
26
|
if (optLevel >= 2 && !process.argv.includes('-opt-no-inline')) {
|
26
27
|
// inline pass (very WIP)
|
@@ -95,7 +96,6 @@ export default (funcs, globals) => {
|
|
95
96
|
}
|
96
97
|
|
97
98
|
if (t.index > c.index) t.index--; // adjust index if after removed func
|
98
|
-
if (c.memory) t.memory = true;
|
99
99
|
}
|
100
100
|
|
101
101
|
funcs.splice(funcs.indexOf(c), 1); // remove func from funcs
|
@@ -142,7 +142,7 @@ export default (funcs, globals) => {
|
|
142
142
|
depth--;
|
143
143
|
if (depth <= 0) break;
|
144
144
|
}
|
145
|
-
if (op === Opcodes.br) {
|
145
|
+
if (op === Opcodes.br || op === Opcodes.br_if) {
|
146
146
|
hasBranch = true;
|
147
147
|
break;
|
148
148
|
}
|
@@ -213,9 +213,9 @@ export default (funcs, globals) => {
|
|
213
213
|
// i32.const 0
|
214
214
|
// drop
|
215
215
|
// -->
|
216
|
-
// <nothing
|
216
|
+
// <nothing>
|
217
217
|
|
218
|
-
wasm.splice(i - 1, 2); // remove
|
218
|
+
wasm.splice(i - 1, 2); // remove these inst
|
219
219
|
i -= 2;
|
220
220
|
continue;
|
221
221
|
}
|
@@ -259,6 +259,36 @@ export default (funcs, globals) => {
|
|
259
259
|
continue;
|
260
260
|
}
|
261
261
|
|
262
|
+
if (lastInst[0] === Opcodes.const && (inst === Opcodes.i32_to || inst === Opcodes.i32_to_u)) {
|
263
|
+
// change const and immediate i32 convert to i32 const
|
264
|
+
// f64.const 0
|
265
|
+
// i32.trunc_sat_f64_s || i32.trunc_sat_f64_u
|
266
|
+
// -->
|
267
|
+
// i32.const 0
|
268
|
+
|
269
|
+
wasm[i - 1] = number((valtype === 'f64' ? read_ieee754_binary64 : read_signedLEB128)(lastInst.slice(1)), Valtype.i32)[0]; // f64.const -> i32.const
|
270
|
+
|
271
|
+
wasm.splice(i, 1); // remove this inst
|
272
|
+
i--;
|
273
|
+
if (optLog) log('opt', `converted const -> i32 convert into i32 const`);
|
274
|
+
continue;
|
275
|
+
}
|
276
|
+
|
277
|
+
if (lastInst[0] === Opcodes.i32_const && (inst === Opcodes.i32_from || inst === Opcodes.i32_from_u)) {
|
278
|
+
// change i32 const and immediate convert to const (opposite way of previous)
|
279
|
+
// i32.const 0
|
280
|
+
// f64.convert_i32_s || f64.convert_i32_u
|
281
|
+
// -->
|
282
|
+
// f64.const 0
|
283
|
+
|
284
|
+
wasm[i - 1] = number(read_signedLEB128(lastInst.slice(1)))[0]; // i32.const -> f64.const
|
285
|
+
|
286
|
+
wasm.splice(i, 1); // remove this inst
|
287
|
+
i--;
|
288
|
+
if (optLog) log('opt', `converted i32 const -> convert into const`);
|
289
|
+
continue;
|
290
|
+
}
|
291
|
+
|
262
292
|
if (tailCall && lastInst[0] === Opcodes.call && inst[0] === Opcodes.return) {
|
263
293
|
// replace call, return with tail calls (return_call)
|
264
294
|
// call X
|
@@ -287,28 +317,24 @@ export default (funcs, globals) => {
|
|
287
317
|
continue;
|
288
318
|
}
|
289
319
|
|
290
|
-
|
291
|
-
const
|
320
|
+
// remove unneeded before get with update exprs (n++, etc) when value is unused
|
321
|
+
if (i < wasm.length - 4 && lastInst[1] === inst[1] && lastInst[0] === Opcodes.local_get && inst[0] === Opcodes.local_get && wasm[i + 1][0] === Opcodes.const && [Opcodes.add, Opcodes.sub].includes(wasm[i + 2][0]) && wasm[i + 3][0] === Opcodes.local_set && wasm[i + 3][1] === inst[1] && (wasm[i + 4][0] === Opcodes.drop || wasm[i + 4][0] === Opcodes.br)) {
|
322
|
+
// local.get 1
|
323
|
+
// local.get 1
|
324
|
+
// -->
|
325
|
+
// local.get 1
|
292
326
|
|
293
|
-
|
294
|
-
|
295
|
-
if (lastLastInst[0] === Opcodes.end && lastInst[1] === inst[1] && lastInst[0] === Opcodes.local_get && inst[0] === Opcodes.local_get) {
|
296
|
-
// local.get 1
|
297
|
-
// local.get 1
|
298
|
-
// -->
|
299
|
-
// local.get 1
|
300
|
-
|
301
|
-
// remove drop at the end as well
|
302
|
-
if (wasm[i + 4][0] === Opcodes.drop) {
|
303
|
-
wasm.splice(i + 4, 1);
|
304
|
-
}
|
327
|
+
// remove drop at the end as well
|
328
|
+
if (wasm[i + 4][0] === Opcodes.drop) wasm.splice(i + 4, 1);
|
305
329
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
}
|
330
|
+
wasm.splice(i, 1); // remove this inst (second get)
|
331
|
+
i--;
|
332
|
+
continue;
|
310
333
|
}
|
311
334
|
|
335
|
+
if (i < 2) continue;
|
336
|
+
const lastLastInst = wasm[i - 2];
|
337
|
+
|
312
338
|
if (lastLastInst[1] === inst[1] && inst[0] === Opcodes.local_get && lastInst[0] === Opcodes.local_tee && lastLastInst[0] === Opcodes.local_set) {
|
313
339
|
// local.set x
|
314
340
|
// local.tee y
|
package/compiler/parse.js
CHANGED
package/compiler/prototype.js
CHANGED
@@ -15,17 +15,20 @@ const TYPES = {
|
|
15
15
|
bigint: 0xffffffffffff7,
|
16
16
|
|
17
17
|
// these are not "typeof" types but tracked internally
|
18
|
-
_array:
|
18
|
+
_array: 0xfffffffffff0f,
|
19
|
+
_regexp: 0xfffffffffff1f
|
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
|
|
@@ -67,7 +70,7 @@ export const PrototypeFuncs = function() {
|
|
67
70
|
// todo: only for 1 argument
|
68
71
|
push: (pointer, length, wNewMember) => [
|
69
72
|
// get memory offset of array at last index (length)
|
70
|
-
...length.
|
73
|
+
...length.getCachedI32(),
|
71
74
|
...number(ValtypeSize[valtype], Valtype.i32),
|
72
75
|
[ Opcodes.i32_mul ],
|
73
76
|
|
@@ -79,17 +82,17 @@ export const PrototypeFuncs = function() {
|
|
79
82
|
|
80
83
|
// bump array length by 1 and return it
|
81
84
|
...length.setI32([
|
82
|
-
...length.
|
85
|
+
...length.getCachedI32(),
|
83
86
|
...number(1, Valtype.i32),
|
84
87
|
[ Opcodes.i32_add ]
|
85
88
|
]),
|
86
89
|
|
87
|
-
...length.get
|
90
|
+
...length.get()
|
88
91
|
],
|
89
92
|
|
90
93
|
pop: (pointer, length) => [
|
91
94
|
// if length == 0, noop
|
92
|
-
...length.
|
95
|
+
...length.getCachedI32(),
|
93
96
|
[ Opcodes.i32_eqz ],
|
94
97
|
[ Opcodes.if, Blocktype.void ],
|
95
98
|
...number(UNDEFINED),
|
@@ -100,13 +103,13 @@ export const PrototypeFuncs = function() {
|
|
100
103
|
|
101
104
|
// decrement length by 1
|
102
105
|
...length.setI32([
|
103
|
-
...length.
|
106
|
+
...length.getCachedI32(),
|
104
107
|
...number(1, Valtype.i32),
|
105
108
|
[ Opcodes.i32_sub ]
|
106
109
|
]),
|
107
110
|
|
108
111
|
// load last element
|
109
|
-
...length.
|
112
|
+
...length.getCachedI32(),
|
110
113
|
...number(ValtypeSize[valtype], Valtype.i32),
|
111
114
|
[ Opcodes.i32_mul ],
|
112
115
|
|
@@ -115,7 +118,7 @@ export const PrototypeFuncs = function() {
|
|
115
118
|
|
116
119
|
shift: (pointer, length) => [
|
117
120
|
// if length == 0, noop
|
118
|
-
...length.
|
121
|
+
...length.getCachedI32(),
|
119
122
|
Opcodes.i32_eqz,
|
120
123
|
[ Opcodes.if, Blocktype.void ],
|
121
124
|
...number(UNDEFINED),
|
@@ -126,7 +129,7 @@ export const PrototypeFuncs = function() {
|
|
126
129
|
|
127
130
|
// decrement length by 1
|
128
131
|
...length.setI32([
|
129
|
-
...length.
|
132
|
+
...length.getCachedI32(),
|
130
133
|
...number(1, Valtype.i32),
|
131
134
|
[ Opcodes.i32_sub ]
|
132
135
|
]),
|
@@ -140,15 +143,69 @@ export const PrototypeFuncs = function() {
|
|
140
143
|
...number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
|
141
144
|
...number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
|
142
145
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
146
|
+
],
|
147
|
+
|
148
|
+
fill: (pointer, length, wElement, iTmp) => [
|
149
|
+
...wElement,
|
150
|
+
[ Opcodes.local_set, iTmp ],
|
151
|
+
|
152
|
+
// use cached length i32 as pointer
|
153
|
+
...length.getCachedI32(),
|
154
|
+
|
155
|
+
// length - 1 for indexes
|
156
|
+
...number(1, Valtype.i32),
|
157
|
+
[ Opcodes.i32_sub ],
|
158
|
+
|
159
|
+
// * sizeof value
|
160
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
161
|
+
[ Opcodes.i32_mul ],
|
162
|
+
|
163
|
+
...length.setCachedI32(),
|
164
|
+
|
165
|
+
...(noUnlikelyChecks ? [] : [
|
166
|
+
...length.getCachedI32(),
|
167
|
+
...number(0, Valtype.i32),
|
168
|
+
[ Opcodes.i32_lt_s ],
|
169
|
+
[ Opcodes.if, Blocktype.void ],
|
170
|
+
...number(pointer),
|
171
|
+
[ Opcodes.br, 1 ],
|
172
|
+
[ Opcodes.end ]
|
173
|
+
]),
|
174
|
+
|
175
|
+
[ Opcodes.loop, Blocktype.void ],
|
176
|
+
|
177
|
+
// set element using pointer
|
178
|
+
...length.getCachedI32(),
|
179
|
+
[ Opcodes.local_get, iTmp ],
|
180
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
|
181
|
+
|
182
|
+
// pointer - sizeof value
|
183
|
+
...length.getCachedI32(),
|
184
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
185
|
+
[ Opcodes.i32_sub ],
|
186
|
+
|
187
|
+
...length.setCachedI32(),
|
188
|
+
|
189
|
+
// if pointer >= 0, loop
|
190
|
+
...length.getCachedI32(),
|
191
|
+
...number(0, Valtype.i32),
|
192
|
+
[ Opcodes.i32_ge_s ],
|
193
|
+
[ Opcodes.br_if, 0 ],
|
194
|
+
|
195
|
+
[ Opcodes.end ],
|
196
|
+
|
197
|
+
// return this array
|
198
|
+
...number(pointer)
|
143
199
|
]
|
144
200
|
};
|
145
201
|
|
146
202
|
this[TYPES._array].at.local = Valtype.i32;
|
147
203
|
this[TYPES._array].push.noArgRetLength = true;
|
204
|
+
this[TYPES._array].fill.local = valtypeBinary;
|
205
|
+
this[TYPES._array].fill.returnType = TYPES._array;
|
148
206
|
|
149
207
|
this[TYPES.string] = {
|
150
|
-
|
151
|
-
at: (pointer, length, wIndex, iTmp, arrayShell) => {
|
208
|
+
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
152
209
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
153
210
|
|
154
211
|
return [
|
@@ -157,9 +214,9 @@ export const PrototypeFuncs = function() {
|
|
157
214
|
[ Opcodes.drop ],
|
158
215
|
|
159
216
|
...number(0, Valtype.i32), // base 0 for store later
|
160
|
-
Opcodes.i32_to_u,
|
161
217
|
|
162
218
|
...wIndex,
|
219
|
+
Opcodes.i32_to_u,
|
163
220
|
[ Opcodes.local_tee, iTmp ],
|
164
221
|
|
165
222
|
// if index < 0: access index + array length
|
@@ -167,7 +224,7 @@ export const PrototypeFuncs = function() {
|
|
167
224
|
[ Opcodes.i32_lt_s ],
|
168
225
|
[ Opcodes.if, Blocktype.void ],
|
169
226
|
[ Opcodes.local_get, iTmp ],
|
170
|
-
...length.
|
227
|
+
...length.getCachedI32(),
|
171
228
|
[ Opcodes.i32_add ],
|
172
229
|
[ Opcodes.local_set, iTmp ],
|
173
230
|
[ Opcodes.end ],
|
@@ -178,7 +235,7 @@ export const PrototypeFuncs = function() {
|
|
178
235
|
[ Opcodes.i32_lt_s ],
|
179
236
|
|
180
237
|
[ Opcodes.local_get, iTmp ],
|
181
|
-
...length.
|
238
|
+
...length.getCachedI32(),
|
182
239
|
[ Opcodes.i32_ge_s ],
|
183
240
|
[ Opcodes.i32_or ],
|
184
241
|
|
@@ -203,7 +260,7 @@ export const PrototypeFuncs = function() {
|
|
203
260
|
},
|
204
261
|
|
205
262
|
// todo: out of bounds properly
|
206
|
-
charAt: (pointer, length, wIndex,
|
263
|
+
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
207
264
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
208
265
|
|
209
266
|
return [
|
@@ -234,39 +291,120 @@ export const PrototypeFuncs = function() {
|
|
234
291
|
return [
|
235
292
|
...wIndex,
|
236
293
|
Opcodes.i32_to,
|
237
|
-
[ Opcodes.local_set, iTmp ],
|
238
294
|
|
239
|
-
|
240
|
-
|
295
|
+
...(zeroChecks.charcodeat ? [] : [
|
296
|
+
[ Opcodes.local_set, iTmp ],
|
297
|
+
|
298
|
+
// index < 0
|
299
|
+
...(noUnlikelyChecks ? [] : [
|
300
|
+
[ Opcodes.local_get, iTmp ],
|
301
|
+
...number(0, Valtype.i32),
|
302
|
+
[ Opcodes.i32_lt_s ],
|
303
|
+
]),
|
304
|
+
|
305
|
+
// index >= length
|
306
|
+
[ Opcodes.local_get, iTmp ],
|
307
|
+
...length.getCachedI32(),
|
308
|
+
[ Opcodes.i32_ge_s ],
|
309
|
+
|
310
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
311
|
+
[ Opcodes.if, Blocktype.void ],
|
312
|
+
...number(NaN),
|
313
|
+
[ Opcodes.br, 1 ],
|
314
|
+
[ Opcodes.end ],
|
315
|
+
|
241
316
|
[ Opcodes.local_get, iTmp ],
|
242
|
-
...number(0, Valtype.i32),
|
243
|
-
[ Opcodes.i32_lt_s ],
|
244
317
|
]),
|
245
318
|
|
246
|
-
|
319
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
320
|
+
[ Opcodes.i32_mul ],
|
321
|
+
|
322
|
+
// load current string ind {arg}
|
323
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
|
324
|
+
Opcodes.i32_from_u
|
325
|
+
];
|
326
|
+
},
|
327
|
+
|
328
|
+
isWellFormed: (pointer, length, wIndex, iTmp, iTmp2, arrayShell, { wellFormed } = {}) => {
|
329
|
+
// aot approx metadata
|
330
|
+
if (wellFormed != null) return number(wellFormed ? 1 : 0);
|
331
|
+
|
332
|
+
return [
|
333
|
+
// note: we cannot presume it begins as 0 in case it was used previously
|
334
|
+
...number(0, Valtype.i32),
|
335
|
+
[ Opcodes.local_set, iTmp ],
|
336
|
+
|
337
|
+
[ Opcodes.loop, Blocktype.void ],
|
338
|
+
|
339
|
+
[ Opcodes.block, Blocktype.void ],
|
340
|
+
|
247
341
|
[ Opcodes.local_get, iTmp ],
|
248
|
-
...
|
342
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32) ],
|
343
|
+
[ Opcodes.local_set, iTmp2 ],
|
344
|
+
|
345
|
+
// if not surrogate, continue
|
346
|
+
[ Opcodes.local_get, iTmp2 ],
|
347
|
+
...number(0xF800, Valtype.i32),
|
348
|
+
[ Opcodes.i32_and ],
|
349
|
+
...number(0xD800, Valtype.i32),
|
350
|
+
[ Opcodes.i32_ne ],
|
351
|
+
[ Opcodes.br_if, 0 ],
|
352
|
+
|
353
|
+
// if not leading surrogate, return false
|
354
|
+
[ Opcodes.local_get, iTmp2 ],
|
355
|
+
...number(0xDC00, Valtype.i32),
|
249
356
|
[ Opcodes.i32_ge_s ],
|
357
|
+
[ Opcodes.if, Blocktype.void ],
|
358
|
+
...number(0),
|
359
|
+
[ Opcodes.br, 3 ],
|
360
|
+
[ Opcodes.end ],
|
250
361
|
|
251
|
-
|
362
|
+
// if not followed by trailing surrogate, return false
|
363
|
+
[ Opcodes.local_get, iTmp ],
|
364
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + ValtypeSize.i16) ],
|
365
|
+
...number(0xFC00, Valtype.i32),
|
366
|
+
[ Opcodes.i32_and ],
|
367
|
+
...number(0xDC00, Valtype.i32),
|
368
|
+
[ Opcodes.i32_ne ],
|
252
369
|
[ Opcodes.if, Blocktype.void ],
|
253
|
-
...number(
|
254
|
-
[ Opcodes.br,
|
370
|
+
...number(0),
|
371
|
+
[ Opcodes.br, 3 ],
|
255
372
|
[ Opcodes.end ],
|
256
373
|
|
374
|
+
// bump index again since gone through two valid chars
|
257
375
|
[ Opcodes.local_get, iTmp ],
|
258
376
|
...number(ValtypeSize.i16, Valtype.i32),
|
377
|
+
[ Opcodes.i32_add ],
|
378
|
+
[ Opcodes.local_set, iTmp ],
|
379
|
+
|
380
|
+
[ Opcodes.end ],
|
381
|
+
|
382
|
+
// bump pointer and loop if not at the end
|
383
|
+
[ Opcodes.local_get, iTmp ],
|
384
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
385
|
+
[ Opcodes.i32_add ],
|
386
|
+
[ Opcodes.local_tee, iTmp ],
|
387
|
+
|
388
|
+
...length.getCachedI32(),
|
389
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
259
390
|
[ Opcodes.i32_mul ],
|
391
|
+
[ Opcodes.i32_ne ],
|
392
|
+
[ Opcodes.br_if, 0 ],
|
260
393
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
394
|
+
[ Opcodes.end ],
|
395
|
+
|
396
|
+
// return true
|
397
|
+
...number(1)
|
398
|
+
]
|
399
|
+
}
|
266
400
|
};
|
267
401
|
|
268
|
-
this[TYPES.string].at.local =
|
402
|
+
this[TYPES.string].at.local = Valtype.i32;
|
269
403
|
this[TYPES.string].at.returnType = TYPES.string;
|
270
404
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
271
405
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
406
|
+
|
407
|
+
this[TYPES.string].isWellFormed.local = Valtype.i32;
|
408
|
+
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
409
|
+
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
272
410
|
};
|