porffor 0.0.0-758fed5 → 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 +29 -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 +465 -112
- package/compiler/decompile.js +1 -1
- package/compiler/embedding.js +9 -5
- package/compiler/index.js +47 -5
- package/compiler/opt.js +15 -19
- package/compiler/parse.js +1 -0
- package/compiler/prototype.js +170 -30
- package/compiler/sections.js +20 -4
- package/compiler/wrap.js +12 -3
- 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 -52
- package/runner/info.js +37 -2
- package/runner/transform.js +2 -1
- package/tmp.c +58 -0
package/compiler/decompile.js
CHANGED
@@ -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/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
|
|
@@ -15,7 +17,8 @@ const areaColors = {
|
|
15
17
|
codegen: [ 20, 80, 250 ],
|
16
18
|
opt: [ 250, 20, 80 ],
|
17
19
|
sections: [ 20, 250, 80 ],
|
18
|
-
alloc: [ 250, 250, 20 ]
|
20
|
+
alloc: [ 250, 250, 20 ],
|
21
|
+
'2c': [ 20, 250, 250 ]
|
19
22
|
};
|
20
23
|
|
21
24
|
globalThis.log = (area, ...args) => console.log(`\u001b[90m[\u001b[0m${rgb(...areaColors[area], area)}\u001b[90m]\u001b[0m`, ...args);
|
@@ -36,10 +39,16 @@ const logFuncs = (funcs, globals, exceptions) => {
|
|
36
39
|
console.log();
|
37
40
|
};
|
38
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
|
+
|
39
47
|
export default (code, flags) => {
|
40
48
|
globalThis.optLog = process.argv.includes('-opt-log');
|
41
49
|
globalThis.codeLog = process.argv.includes('-code-log');
|
42
50
|
globalThis.allocLog = process.argv.includes('-alloc-log');
|
51
|
+
globalThis.regexLog = process.argv.includes('-regex-log');
|
43
52
|
|
44
53
|
for (const x in BuiltinPreludes) {
|
45
54
|
if (code.indexOf(x + '(') !== -1) code = BuiltinPreludes[x] + code;
|
@@ -50,7 +59,7 @@ export default (code, flags) => {
|
|
50
59
|
if (flags.includes('info')) console.log(`1. parsed in ${(performance.now() - t0).toFixed(2)}ms`);
|
51
60
|
|
52
61
|
const t1 = performance.now();
|
53
|
-
const { funcs, globals, tags, exceptions, pages } = codeGen(program);
|
62
|
+
const { funcs, globals, tags, exceptions, pages, data } = codeGen(program);
|
54
63
|
if (flags.includes('info')) console.log(`2. generated code in ${(performance.now() - t1).toFixed(2)}ms`);
|
55
64
|
|
56
65
|
if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
|
@@ -62,15 +71,48 @@ export default (code, flags) => {
|
|
62
71
|
if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
|
63
72
|
|
64
73
|
const t3 = performance.now();
|
65
|
-
const sections = produceSections(funcs, globals, tags, pages, flags);
|
74
|
+
const sections = produceSections(funcs, globals, tags, pages, data, flags);
|
66
75
|
if (flags.includes('info')) console.log(`4. produced sections in ${(performance.now() - t3).toFixed(2)}ms`);
|
67
76
|
|
68
77
|
if (allocLog) {
|
69
78
|
const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
|
70
79
|
const bytes = wasmPages * 65536;
|
71
80
|
log('alloc', `\x1B[1mallocated ${bytes / 1024}KiB\x1B[0m for ${pages.size} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}`);
|
72
|
-
|
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();
|
73
115
|
}
|
74
116
|
|
75
|
-
return
|
117
|
+
return out;
|
76
118
|
};
|
package/compiler/opt.js
CHANGED
@@ -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
|
}
|
@@ -317,28 +317,24 @@ export default (funcs, globals) => {
|
|
317
317
|
continue;
|
318
318
|
}
|
319
319
|
|
320
|
-
|
321
|
-
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
|
322
326
|
|
323
|
-
|
324
|
-
|
325
|
-
if (lastLastInst[0] === Opcodes.end && lastInst[1] === inst[1] && lastInst[0] === Opcodes.local_get && inst[0] === Opcodes.local_get) {
|
326
|
-
// local.get 1
|
327
|
-
// local.get 1
|
328
|
-
// -->
|
329
|
-
// local.get 1
|
330
|
-
|
331
|
-
// remove drop at the end as well
|
332
|
-
if (wasm[i + 4][0] === Opcodes.drop) {
|
333
|
-
wasm.splice(i + 4, 1);
|
334
|
-
}
|
327
|
+
// remove drop at the end as well
|
328
|
+
if (wasm[i + 4][0] === Opcodes.drop) wasm.splice(i + 4, 1);
|
335
329
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
}
|
330
|
+
wasm.splice(i, 1); // remove this inst (second get)
|
331
|
+
i--;
|
332
|
+
continue;
|
340
333
|
}
|
341
334
|
|
335
|
+
if (i < 2) continue;
|
336
|
+
const lastLastInst = wasm[i - 2];
|
337
|
+
|
342
338
|
if (lastLastInst[1] === inst[1] && inst[0] === Opcodes.local_get && lastInst[0] === Opcodes.local_tee && lastLastInst[0] === Opcodes.local_set) {
|
343
339
|
// local.set x
|
344
340
|
// local.tee y
|
package/compiler/parse.js
CHANGED
package/compiler/prototype.js
CHANGED
@@ -15,13 +15,17 @@ 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
|
@@ -35,7 +39,7 @@ export const PrototypeFuncs = function() {
|
|
35
39
|
[ Opcodes.i32_lt_s ],
|
36
40
|
[ Opcodes.if, Blocktype.void ],
|
37
41
|
[ Opcodes.local_get, iTmp ],
|
38
|
-
...length.
|
42
|
+
...length.getCachedI32(),
|
39
43
|
[ Opcodes.i32_add ],
|
40
44
|
[ Opcodes.local_set, iTmp ],
|
41
45
|
[ Opcodes.end ],
|
@@ -46,7 +50,7 @@ export const PrototypeFuncs = function() {
|
|
46
50
|
[ Opcodes.i32_lt_s ],
|
47
51
|
|
48
52
|
[ Opcodes.local_get, iTmp ],
|
49
|
-
...length.
|
53
|
+
...length.getCachedI32(),
|
50
54
|
[ Opcodes.i32_ge_s ],
|
51
55
|
[ Opcodes.i32_or ],
|
52
56
|
|
@@ -66,7 +70,7 @@ export const PrototypeFuncs = function() {
|
|
66
70
|
// todo: only for 1 argument
|
67
71
|
push: (pointer, length, wNewMember) => [
|
68
72
|
// get memory offset of array at last index (length)
|
69
|
-
...length.
|
73
|
+
...length.getCachedI32(),
|
70
74
|
...number(ValtypeSize[valtype], Valtype.i32),
|
71
75
|
[ Opcodes.i32_mul ],
|
72
76
|
|
@@ -78,17 +82,17 @@ export const PrototypeFuncs = function() {
|
|
78
82
|
|
79
83
|
// bump array length by 1 and return it
|
80
84
|
...length.setI32([
|
81
|
-
...length.
|
85
|
+
...length.getCachedI32(),
|
82
86
|
...number(1, Valtype.i32),
|
83
87
|
[ Opcodes.i32_add ]
|
84
88
|
]),
|
85
89
|
|
86
|
-
...length.get
|
90
|
+
...length.get()
|
87
91
|
],
|
88
92
|
|
89
93
|
pop: (pointer, length) => [
|
90
94
|
// if length == 0, noop
|
91
|
-
...length.
|
95
|
+
...length.getCachedI32(),
|
92
96
|
[ Opcodes.i32_eqz ],
|
93
97
|
[ Opcodes.if, Blocktype.void ],
|
94
98
|
...number(UNDEFINED),
|
@@ -99,13 +103,13 @@ export const PrototypeFuncs = function() {
|
|
99
103
|
|
100
104
|
// decrement length by 1
|
101
105
|
...length.setI32([
|
102
|
-
...length.
|
106
|
+
...length.getCachedI32(),
|
103
107
|
...number(1, Valtype.i32),
|
104
108
|
[ Opcodes.i32_sub ]
|
105
109
|
]),
|
106
110
|
|
107
111
|
// load last element
|
108
|
-
...length.
|
112
|
+
...length.getCachedI32(),
|
109
113
|
...number(ValtypeSize[valtype], Valtype.i32),
|
110
114
|
[ Opcodes.i32_mul ],
|
111
115
|
|
@@ -114,7 +118,7 @@ export const PrototypeFuncs = function() {
|
|
114
118
|
|
115
119
|
shift: (pointer, length) => [
|
116
120
|
// if length == 0, noop
|
117
|
-
...length.
|
121
|
+
...length.getCachedI32(),
|
118
122
|
Opcodes.i32_eqz,
|
119
123
|
[ Opcodes.if, Blocktype.void ],
|
120
124
|
...number(UNDEFINED),
|
@@ -125,7 +129,7 @@ export const PrototypeFuncs = function() {
|
|
125
129
|
|
126
130
|
// decrement length by 1
|
127
131
|
...length.setI32([
|
128
|
-
...length.
|
132
|
+
...length.getCachedI32(),
|
129
133
|
...number(1, Valtype.i32),
|
130
134
|
[ Opcodes.i32_sub ]
|
131
135
|
]),
|
@@ -139,14 +143,69 @@ export const PrototypeFuncs = function() {
|
|
139
143
|
...number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
|
140
144
|
...number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
|
141
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)
|
142
199
|
]
|
143
200
|
};
|
144
201
|
|
145
202
|
this[TYPES._array].at.local = Valtype.i32;
|
146
203
|
this[TYPES._array].push.noArgRetLength = true;
|
204
|
+
this[TYPES._array].fill.local = valtypeBinary;
|
205
|
+
this[TYPES._array].fill.returnType = TYPES._array;
|
147
206
|
|
148
207
|
this[TYPES.string] = {
|
149
|
-
at: (pointer, length, wIndex, iTmp, arrayShell) => {
|
208
|
+
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
150
209
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
151
210
|
|
152
211
|
return [
|
@@ -165,7 +224,7 @@ export const PrototypeFuncs = function() {
|
|
165
224
|
[ Opcodes.i32_lt_s ],
|
166
225
|
[ Opcodes.if, Blocktype.void ],
|
167
226
|
[ Opcodes.local_get, iTmp ],
|
168
|
-
...length.
|
227
|
+
...length.getCachedI32(),
|
169
228
|
[ Opcodes.i32_add ],
|
170
229
|
[ Opcodes.local_set, iTmp ],
|
171
230
|
[ Opcodes.end ],
|
@@ -176,7 +235,7 @@ export const PrototypeFuncs = function() {
|
|
176
235
|
[ Opcodes.i32_lt_s ],
|
177
236
|
|
178
237
|
[ Opcodes.local_get, iTmp ],
|
179
|
-
...length.
|
238
|
+
...length.getCachedI32(),
|
180
239
|
[ Opcodes.i32_ge_s ],
|
181
240
|
[ Opcodes.i32_or ],
|
182
241
|
|
@@ -201,7 +260,7 @@ export const PrototypeFuncs = function() {
|
|
201
260
|
},
|
202
261
|
|
203
262
|
// todo: out of bounds properly
|
204
|
-
charAt: (pointer, length, wIndex,
|
263
|
+
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
205
264
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
206
265
|
|
207
266
|
return [
|
@@ -232,39 +291,120 @@ export const PrototypeFuncs = function() {
|
|
232
291
|
return [
|
233
292
|
...wIndex,
|
234
293
|
Opcodes.i32_to,
|
235
|
-
[ Opcodes.local_set, iTmp ],
|
236
294
|
|
237
|
-
|
238
|
-
|
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
|
+
|
239
316
|
[ Opcodes.local_get, iTmp ],
|
240
|
-
...number(0, Valtype.i32),
|
241
|
-
[ Opcodes.i32_lt_s ],
|
242
317
|
]),
|
243
318
|
|
244
|
-
|
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
|
+
|
245
341
|
[ Opcodes.local_get, iTmp ],
|
246
|
-
...
|
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),
|
247
356
|
[ Opcodes.i32_ge_s ],
|
357
|
+
[ Opcodes.if, Blocktype.void ],
|
358
|
+
...number(0),
|
359
|
+
[ Opcodes.br, 3 ],
|
360
|
+
[ Opcodes.end ],
|
248
361
|
|
249
|
-
|
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 ],
|
250
369
|
[ Opcodes.if, Blocktype.void ],
|
251
|
-
...number(
|
252
|
-
[ Opcodes.br,
|
370
|
+
...number(0),
|
371
|
+
[ Opcodes.br, 3 ],
|
253
372
|
[ Opcodes.end ],
|
254
373
|
|
374
|
+
// bump index again since gone through two valid chars
|
255
375
|
[ Opcodes.local_get, iTmp ],
|
256
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),
|
257
390
|
[ Opcodes.i32_mul ],
|
391
|
+
[ Opcodes.i32_ne ],
|
392
|
+
[ Opcodes.br_if, 0 ],
|
258
393
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
394
|
+
[ Opcodes.end ],
|
395
|
+
|
396
|
+
// return true
|
397
|
+
...number(1)
|
398
|
+
]
|
399
|
+
}
|
264
400
|
};
|
265
401
|
|
266
402
|
this[TYPES.string].at.local = Valtype.i32;
|
267
403
|
this[TYPES.string].at.returnType = TYPES.string;
|
268
404
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
269
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;
|
270
410
|
};
|
package/compiler/sections.js
CHANGED
@@ -1,5 +1,5 @@
|
|
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
5
|
|
@@ -20,7 +20,7 @@ const chHint = (topTier, baselineTier, strategy) => {
|
|
20
20
|
return (strategy | (baselineTier << 2) | (topTier << 4));
|
21
21
|
};
|
22
22
|
|
23
|
-
export default (funcs, globals, tags, pages, flags) => {
|
23
|
+
export default (funcs, globals, tags, pages, data, flags) => {
|
24
24
|
const types = [], typeCache = {};
|
25
25
|
|
26
26
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
@@ -76,6 +76,7 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
76
76
|
}
|
77
77
|
}
|
78
78
|
}
|
79
|
+
globalThis.importFuncs = importFuncs;
|
79
80
|
|
80
81
|
if (optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
81
82
|
|
@@ -104,6 +105,8 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
104
105
|
|
105
106
|
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
|
106
107
|
|
108
|
+
if (process.argv.includes('-always-memory') && pages.size === 0) pages.set('-always-memory', 0);
|
109
|
+
|
107
110
|
const usesMemory = pages.size > 0;
|
108
111
|
const memorySection = !usesMemory ? [] : createSection(
|
109
112
|
Section.memory,
|
@@ -154,13 +157,24 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
154
157
|
encodeVector(types)
|
155
158
|
);
|
156
159
|
|
160
|
+
const dataSection = data.length === 0 ? [] : createSection(
|
161
|
+
Section.data,
|
162
|
+
encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
|
163
|
+
);
|
164
|
+
|
165
|
+
const dataCountSection = data.length === 0 ? [] : createSection(
|
166
|
+
Section.data_count,
|
167
|
+
unsignedLEB128(data.length)
|
168
|
+
);
|
169
|
+
|
157
170
|
if (process.argv.includes('-sections')) console.log({
|
158
171
|
typeSection: typeSection.map(x => x.toString(16)),
|
159
172
|
importSection: importSection.map(x => x.toString(16)),
|
160
173
|
funcSection: funcSection.map(x => x.toString(16)),
|
161
174
|
globalSection: globalSection.map(x => x.toString(16)),
|
162
175
|
exportSection: exportSection.map(x => x.toString(16)),
|
163
|
-
codeSection: codeSection.map(x => x.toString(16))
|
176
|
+
codeSection: codeSection.map(x => x.toString(16)),
|
177
|
+
dataSection: dataSection.map(x => x.toString(16)),
|
164
178
|
});
|
165
179
|
|
166
180
|
return Uint8Array.from([
|
@@ -174,6 +188,8 @@ export default (funcs, globals, tags, pages, flags) => {
|
|
174
188
|
...tagSection,
|
175
189
|
...globalSection,
|
176
190
|
...exportSection,
|
177
|
-
...
|
191
|
+
...dataCountSection,
|
192
|
+
...codeSection,
|
193
|
+
...dataSection
|
178
194
|
]);
|
179
195
|
};
|
package/compiler/wrap.js
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
import compile from './index.js';
|
2
2
|
import decompile from './decompile.js';
|
3
|
-
import fs from 'node:fs';
|
3
|
+
// import fs from 'node:fs';
|
4
4
|
|
5
5
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
6
6
|
|
7
7
|
const typeBase = 0xffffffffffff0;
|
8
|
+
const internalTypeBase = 0xfffffffffff0f;
|
8
9
|
const TYPES = {
|
9
10
|
[typeBase]: 'number',
|
10
11
|
[typeBase + 1]: 'boolean',
|
@@ -16,7 +17,8 @@ const TYPES = {
|
|
16
17
|
[typeBase + 7]: 'bigint',
|
17
18
|
|
18
19
|
// internal
|
19
|
-
[
|
20
|
+
[internalTypeBase]: '_array',
|
21
|
+
[internalTypeBase + 1]: '_regexp'
|
20
22
|
};
|
21
23
|
|
22
24
|
export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
@@ -27,16 +29,23 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
27
29
|
|
28
30
|
if (source.includes('export function')) flags.push('module');
|
29
31
|
|
30
|
-
fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
32
|
+
// fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
31
33
|
|
32
34
|
times.push(performance.now() - t1);
|
33
35
|
if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
34
36
|
|
37
|
+
const getString = pointer => {
|
38
|
+
const length = new Int32Array(memory.buffer, pointer, 1);
|
39
|
+
|
40
|
+
return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
41
|
+
};
|
42
|
+
|
35
43
|
const t2 = performance.now();
|
36
44
|
const { instance } = await WebAssembly.instantiate(wasm, {
|
37
45
|
'': {
|
38
46
|
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
39
47
|
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
48
|
+
s: valtype === 'i64' ? i => print(getString(Number(i))) : i => print(getString(i)),
|
40
49
|
a: c => { if (!Number(c)) throw new Error(`assert failed`); },
|
41
50
|
t: _ => performance.now(),
|
42
51
|
...customImports
|
package/cool.exe
ADDED
Binary file
|
package/g
ADDED
Binary file
|
package/g.exe
ADDED
Binary file
|
package/hi.c
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
|
3
|
+
double inline f64_f(double x, double y) {
|
4
|
+
return x - (int)(x / y) * y;
|
5
|
+
}
|
6
|
+
|
7
|
+
double isPrime(double number) {
|
8
|
+
double i;
|
9
|
+
|
10
|
+
if (number < 2e+0) {
|
11
|
+
return 0e+0;
|
12
|
+
}
|
13
|
+
i = 2e+0;
|
14
|
+
while (i < number) {
|
15
|
+
if (f64_f(number, i) == 0e+0) {
|
16
|
+
return 0e+0;
|
17
|
+
}
|
18
|
+
i = i + 1e+0;
|
19
|
+
}
|
20
|
+
return 1e+0;
|
21
|
+
}
|
22
|
+
|
23
|
+
int main() {
|
24
|
+
double sum;
|
25
|
+
double counter;
|
26
|
+
|
27
|
+
sum = 0e+0;
|
28
|
+
counter = 0e+0;
|
29
|
+
while (counter <= 1e+5) {
|
30
|
+
if (isPrime(counter) == 1e+0) {
|
31
|
+
sum = sum + counter;
|
32
|
+
}
|
33
|
+
counter = counter + 1e+0;
|
34
|
+
}
|
35
|
+
printf("%f\n", sum);
|
36
|
+
}
|
37
|
+
|
package/out
ADDED
Binary file
|
package/out.exe
ADDED
Binary file
|