porffor 0.14.0-f67c123a1 → 0.16.0-a2e115b05
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/CONTRIBUTING.md +15 -9
- package/README.md +9 -13
- package/asur/index.js +1 -1
- package/compiler/2c.js +104 -51
- package/compiler/assemble.js +26 -1
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +84 -4
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +3 -1
- package/compiler/builtins/console.ts +6 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/porffor.d.ts +11 -0
- package/compiler/builtins/set.ts +20 -7
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +62 -0
- package/compiler/builtins.js +48 -10
- package/compiler/codegen.js +569 -258
- package/compiler/decompile.js +5 -1
- package/compiler/generated_builtins.js +555 -60
- package/compiler/index.js +5 -9
- package/compiler/opt.js +2 -2
- package/compiler/parse.js +2 -2
- package/compiler/precompile.js +5 -4
- package/compiler/prefs.js +6 -2
- package/compiler/prototype.js +180 -157
- package/compiler/wrap.js +82 -40
- package/package.json +1 -1
- package/runner/index.js +5 -4
- package/runner/repl.js +18 -2
package/compiler/index.js
CHANGED
@@ -12,14 +12,7 @@ globalThis.decompile = decompile;
|
|
12
12
|
const logFuncs = (funcs, globals, exceptions) => {
|
13
13
|
console.log('\n' + underline(bold('funcs')));
|
14
14
|
|
15
|
-
const startIndex = funcs.sort((a, b) => a.index - b.index)[0].index;
|
16
15
|
for (const f of funcs) {
|
17
|
-
console.log(`${underline(f.name)} (${f.index - startIndex})`);
|
18
|
-
|
19
|
-
console.log(`params: ${f.params.map((_, i) => Object.keys(f.locals)[Object.values(f.locals).indexOf(Object.values(f.locals).find(x => x.idx === i))]).join(', ')}`);
|
20
|
-
console.log(`returns: ${f.returns.length > 0 ? true : false}`);
|
21
|
-
console.log(`locals: ${Object.keys(f.locals).sort((a, b) => f.locals[a].idx - f.locals[b].idx).map(x => `${x} (${f.locals[x].idx})`).join(', ')}`);
|
22
|
-
console.log();
|
23
16
|
console.log(decompile(f.wasm, f.name, f.index, f.locals, f.params, f.returns, funcs, globals, exceptions));
|
24
17
|
}
|
25
18
|
|
@@ -44,12 +37,14 @@ export default (code, flags) => {
|
|
44
37
|
opt(funcs, globals, pages, tags, exceptions);
|
45
38
|
if (Prefs.profileCompiler) console.log(`3. optimized in ${(performance.now() - t2).toFixed(2)}ms`);
|
46
39
|
|
47
|
-
if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
40
|
+
// if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
48
41
|
|
49
42
|
const t3 = performance.now();
|
50
43
|
const wasm = assemble(funcs, globals, tags, pages, data, flags);
|
51
44
|
if (Prefs.profileCompiler) console.log(`4. assembled in ${(performance.now() - t3).toFixed(2)}ms`);
|
52
45
|
|
46
|
+
if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
47
|
+
|
53
48
|
if (Prefs.allocLog) {
|
54
49
|
const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
|
55
50
|
const bytes = wasmPages * 65536;
|
@@ -89,7 +84,8 @@ export default (code, flags) => {
|
|
89
84
|
else compiler = [ compiler ];
|
90
85
|
|
91
86
|
const tmpfile = 'porffor_tmp.c';
|
92
|
-
const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO
|
87
|
+
const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO ];
|
88
|
+
if (!Prefs.compiler) args.push('-flto=thin', '-march=native', '-s', '-ffast-math', '-fno-exceptions', '-fno-ident', '-fno-asynchronous-unwind-tables', '-ffunction-sections', '-fdata-sections', '-Wl,--gc-sections');
|
93
89
|
|
94
90
|
const c = toc(out);
|
95
91
|
fs.writeFileSync(tmpfile, c);
|
package/compiler/opt.js
CHANGED
@@ -108,7 +108,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
108
108
|
for (const f of funcs) {
|
109
109
|
const wasm = f.wasm;
|
110
110
|
|
111
|
-
const lastType = f.locals['#last_type'];
|
111
|
+
const lastType = f.locals['#last_type']?.idx;
|
112
112
|
|
113
113
|
let runs = (+Prefs.optWasmRuns) || 2; // todo: how many by default?
|
114
114
|
while (runs > 0) {
|
@@ -248,7 +248,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
248
248
|
}
|
249
249
|
|
250
250
|
// remove setting last type if it is never gotten
|
251
|
-
if (!f.gotLastType && inst[0] === Opcodes.local_set && inst[1] === lastType
|
251
|
+
if (!f.gotLastType && inst[0] === Opcodes.local_set && inst[1] === lastType) {
|
252
252
|
// replace this inst with drop
|
253
253
|
wasm.splice(i, 1, [ Opcodes.drop ]); // remove this and last inst
|
254
254
|
if (i > 0) i--;
|
package/compiler/parse.js
CHANGED
@@ -7,10 +7,10 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
|
7
7
|
globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
|
8
8
|
}
|
9
9
|
|
10
|
-
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
10
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-' && !['run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(x));
|
11
11
|
|
12
12
|
// should we try to support types (while parsing)
|
13
|
-
const types = Prefs.parseTypes || file?.endsWith('.ts');
|
13
|
+
const types = Prefs.parseTypes || Prefs.t || file?.endsWith('.ts');
|
14
14
|
globalThis.typedInput = types && Prefs.optTypes;
|
15
15
|
|
16
16
|
// todo: review which to use by default
|
package/compiler/precompile.js
CHANGED
@@ -18,9 +18,9 @@ const compile = async (file, [ _funcs, _globals ]) => {
|
|
18
18
|
first = source.slice(0, source.indexOf('\n'));
|
19
19
|
}
|
20
20
|
|
21
|
-
let args = ['--bytestring', '--todo-time=compile', '--
|
21
|
+
let args = ['--bytestring', '--todo-time=compile', '--truthy=no_nan_negative', '--no-treeshake-wasm-imports', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--fast-length', '--parse-types', '--opt-types'];
|
22
22
|
if (first.startsWith('// @porf')) {
|
23
|
-
args =
|
23
|
+
args = first.slice('// @porf '.length).split(' ').concat(args);
|
24
24
|
}
|
25
25
|
process.argv = argv.concat(args);
|
26
26
|
|
@@ -111,8 +111,9 @@ ${funcs.map(x => {
|
|
111
111
|
${x.returnType != null ? `returnType: ${JSON.stringify(x.returnType)}` : 'typedReturns: true'},
|
112
112
|
locals: ${JSON.stringify(Object.values(x.locals).slice(x.params.length).map(x => x.type))},
|
113
113
|
localNames: ${JSON.stringify(Object.keys(x.locals))},
|
114
|
-
${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)}
|
115
|
-
|
114
|
+
${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)},` : ''}
|
115
|
+
${x.table ? ` table: true` : ''}
|
116
|
+
};`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n').replaceAll('\n\n', '\n');
|
116
117
|
}).join('\n')}
|
117
118
|
};`;
|
118
119
|
};
|
package/compiler/prefs.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
const onByDefault = [ 'bytestring', '
|
1
|
+
const onByDefault = [ 'bytestring', 'treeshakeWasmImports', 'alwaysMemory', 'indirectCalls', 'optUnused' ];
|
2
2
|
|
3
3
|
let cache = {};
|
4
4
|
const obj = new Proxy({}, {
|
@@ -6,7 +6,7 @@ const obj = new Proxy({}, {
|
|
6
6
|
// intentionally misses with undefined values cached
|
7
7
|
if (cache[p]) return cache[p];
|
8
8
|
|
9
|
-
|
9
|
+
const ret = (() => {
|
10
10
|
// fooBar -> foo-bar
|
11
11
|
const name = p[0] === '_' ? p : p.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
|
12
12
|
const prefix = name.length === 1 ? '-' : '--';
|
@@ -19,6 +19,10 @@ const obj = new Proxy({}, {
|
|
19
19
|
if (onByDefault.includes(p)) return true;
|
20
20
|
return undefined;
|
21
21
|
})();
|
22
|
+
|
23
|
+
// do not cache in web demo as args are changed live
|
24
|
+
if (!globalThis.document) cache[p] = ret;
|
25
|
+
return ret;
|
22
26
|
}
|
23
27
|
});
|
24
28
|
|
package/compiler/prototype.js
CHANGED
@@ -16,7 +16,7 @@ export const PrototypeFuncs = function() {
|
|
16
16
|
|
17
17
|
this[TYPES.array] = {
|
18
18
|
// lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
|
19
|
-
at: (pointer, length, wIndex, iTmp) => [
|
19
|
+
at: (pointer, length, wIndex, wType, iTmp) => [
|
20
20
|
...wIndex,
|
21
21
|
Opcodes.i32_to,
|
22
22
|
[ Opcodes.local_tee, iTmp ],
|
@@ -47,31 +47,39 @@ export const PrototypeFuncs = function() {
|
|
47
47
|
[ Opcodes.end ],
|
48
48
|
|
49
49
|
[ Opcodes.local_get, iTmp ],
|
50
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
50
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
51
51
|
[ Opcodes.i32_mul ],
|
52
|
-
|
53
52
|
...pointer,
|
54
53
|
[ Opcodes.i32_add ],
|
54
|
+
[ Opcodes.local_set, iTmp ],
|
55
55
|
|
56
56
|
// read from memory
|
57
|
-
[ Opcodes.
|
57
|
+
[ Opcodes.local_get, iTmp ],
|
58
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
59
|
+
|
60
|
+
[ Opcodes.local_get, iTmp ],
|
61
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
58
62
|
],
|
59
63
|
|
60
64
|
// todo: only for 1 argument
|
61
|
-
push: (pointer, length, wNewMember,
|
65
|
+
push: (pointer, length, wNewMember, wType, iTmp, _2, _3, unusedValue) => [
|
62
66
|
// get memory offset of array at last index (length)
|
63
67
|
...length.getCachedI32(),
|
64
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
68
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
65
69
|
[ Opcodes.i32_mul ],
|
66
|
-
|
67
70
|
...pointer,
|
68
71
|
[ Opcodes.i32_add ],
|
72
|
+
[ Opcodes.local_set, iTmp ],
|
69
73
|
|
70
|
-
//
|
74
|
+
// store value
|
75
|
+
[ Opcodes.local_get, iTmp ],
|
71
76
|
...wNewMember,
|
77
|
+
[ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
72
78
|
|
73
|
-
// store
|
74
|
-
[ Opcodes.
|
79
|
+
// store type
|
80
|
+
[ Opcodes.local_get, iTmp ],
|
81
|
+
...wType,
|
82
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
75
83
|
|
76
84
|
// bump array length by 1 and return it
|
77
85
|
...length.setI32([
|
@@ -93,7 +101,7 @@ export const PrototypeFuncs = function() {
|
|
93
101
|
// ...length.get()
|
94
102
|
],
|
95
103
|
|
96
|
-
pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
|
104
|
+
pop: (pointer, length, _1, _2, iTmp, _3, _4, unusedValue) => [
|
97
105
|
// if length == 0, noop
|
98
106
|
...length.getCachedI32(),
|
99
107
|
[ Opcodes.i32_eqz ],
|
@@ -121,13 +129,18 @@ export const PrototypeFuncs = function() {
|
|
121
129
|
// load last element
|
122
130
|
...(unusedValue() ? [] : [
|
123
131
|
...length.getCachedI32(),
|
124
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
132
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
125
133
|
[ Opcodes.i32_mul ],
|
126
134
|
|
127
135
|
...pointer,
|
128
136
|
[ Opcodes.i32_add ],
|
137
|
+
[ Opcodes.local_set, iTmp ],
|
129
138
|
|
130
|
-
[ Opcodes.
|
139
|
+
[ Opcodes.local_get, iTmp ],
|
140
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
141
|
+
|
142
|
+
[ Opcodes.local_get, iTmp ],
|
143
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
131
144
|
])
|
132
145
|
],
|
133
146
|
|
@@ -153,8 +166,12 @@ export const PrototypeFuncs = function() {
|
|
153
166
|
]),
|
154
167
|
|
155
168
|
// load first element
|
169
|
+
// todo/perf: unusedValue opt
|
156
170
|
...pointer,
|
157
|
-
[ Opcodes.load,
|
171
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
172
|
+
|
173
|
+
...pointer,
|
174
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
158
175
|
|
159
176
|
// offset page by -1 ind
|
160
177
|
// ...number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
|
@@ -170,13 +187,13 @@ export const PrototypeFuncs = function() {
|
|
170
187
|
[ Opcodes.i32_add ],
|
171
188
|
|
172
189
|
// src = base array index + length size + an index
|
173
|
-
...number(ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32),
|
190
|
+
...number(ValtypeSize.i32 + ValtypeSize[valtype] + 1, Valtype.i32),
|
174
191
|
...pointer,
|
175
192
|
[ Opcodes.i32_add ],
|
176
193
|
|
177
194
|
// size = new length * sizeof element
|
178
195
|
...length.getCachedI32(),
|
179
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
196
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
180
197
|
[ Opcodes.i32_mul ],
|
181
198
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
182
199
|
|
@@ -194,7 +211,7 @@ export const PrototypeFuncs = function() {
|
|
194
211
|
// ]),
|
195
212
|
],
|
196
213
|
|
197
|
-
fill: (pointer, length, wElement, iTmp) => [
|
214
|
+
fill: (pointer, length, wElement, wType, iTmp, iTmp2) => [
|
198
215
|
...wElement,
|
199
216
|
[ Opcodes.local_set, iTmp ],
|
200
217
|
|
@@ -206,7 +223,7 @@ export const PrototypeFuncs = function() {
|
|
206
223
|
[ Opcodes.i32_sub ],
|
207
224
|
|
208
225
|
// * sizeof value
|
209
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
226
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
210
227
|
[ Opcodes.i32_mul ],
|
211
228
|
|
212
229
|
...length.setCachedI32(),
|
@@ -224,17 +241,25 @@ export const PrototypeFuncs = function() {
|
|
224
241
|
|
225
242
|
[ Opcodes.loop, Blocktype.void ],
|
226
243
|
|
227
|
-
//
|
244
|
+
// calculate offset
|
228
245
|
...length.getCachedI32(),
|
229
246
|
...pointer,
|
230
247
|
[ Opcodes.i32_add ],
|
248
|
+
[ Opcodes.local_set, iTmp2 ],
|
231
249
|
|
250
|
+
// store value
|
251
|
+
[ Opcodes.local_get, iTmp2 ],
|
232
252
|
[ Opcodes.local_get, iTmp ],
|
233
|
-
[ Opcodes.store,
|
253
|
+
[ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
254
|
+
|
255
|
+
// store type
|
256
|
+
[ Opcodes.local_get, iTmp2 ],
|
257
|
+
...wType,
|
258
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
234
259
|
|
235
260
|
// pointer - sizeof value
|
236
261
|
...length.getCachedI32(),
|
237
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
262
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
238
263
|
[ Opcodes.i32_sub ],
|
239
264
|
|
240
265
|
...length.setCachedI32(),
|
@@ -254,12 +279,16 @@ export const PrototypeFuncs = function() {
|
|
254
279
|
};
|
255
280
|
|
256
281
|
this[TYPES.array].at.local = Valtype.i32;
|
282
|
+
this[TYPES.array].push.returnType = TYPES.number;
|
257
283
|
this[TYPES.array].push.noArgRetLength = true;
|
284
|
+
this[TYPES.array].push.local = Valtype.i32;
|
285
|
+
this[TYPES.array].pop.local = Valtype.i32;
|
258
286
|
this[TYPES.array].fill.local = valtypeBinary;
|
287
|
+
this[TYPES.array].fill.local2 = Valtype.i32;
|
259
288
|
this[TYPES.array].fill.returnType = TYPES.array;
|
260
289
|
|
261
290
|
this[TYPES.string] = {
|
262
|
-
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
291
|
+
at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
|
263
292
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
264
293
|
|
265
294
|
return [
|
@@ -317,7 +346,7 @@ export const PrototypeFuncs = function() {
|
|
317
346
|
},
|
318
347
|
|
319
348
|
// todo: out of bounds properly
|
320
|
-
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
349
|
+
charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
|
321
350
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
322
351
|
|
323
352
|
return [
|
@@ -347,127 +376,124 @@ export const PrototypeFuncs = function() {
|
|
347
376
|
];
|
348
377
|
},
|
349
378
|
|
350
|
-
charCodeAt: (pointer, length, wIndex, iTmp) =>
|
351
|
-
|
352
|
-
|
353
|
-
Opcodes.i32_to,
|
354
|
-
|
355
|
-
...(zeroChecks.charcodeat ? [] : [
|
356
|
-
[ Opcodes.local_set, iTmp ],
|
379
|
+
charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
|
380
|
+
...wIndex,
|
381
|
+
Opcodes.i32_to,
|
357
382
|
|
358
|
-
|
359
|
-
|
360
|
-
[ Opcodes.local_get, iTmp ],
|
361
|
-
...number(0, Valtype.i32),
|
362
|
-
[ Opcodes.i32_lt_s ],
|
363
|
-
]),
|
383
|
+
...(zeroChecks.charcodeat ? [] : [
|
384
|
+
[ Opcodes.local_set, iTmp ],
|
364
385
|
|
365
|
-
|
386
|
+
// index < 0
|
387
|
+
...(noUnlikelyChecks ? [] : [
|
366
388
|
[ Opcodes.local_get, iTmp ],
|
367
|
-
...
|
368
|
-
[ Opcodes.
|
389
|
+
...number(0, Valtype.i32),
|
390
|
+
[ Opcodes.i32_lt_s ],
|
391
|
+
]),
|
369
392
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
[ Opcodes.end ],
|
393
|
+
// index >= length
|
394
|
+
[ Opcodes.local_get, iTmp ],
|
395
|
+
...length.getCachedI32(),
|
396
|
+
[ Opcodes.i32_ge_s ],
|
375
397
|
|
376
|
-
|
377
|
-
]
|
398
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
399
|
+
[ Opcodes.if, Blocktype.void ],
|
400
|
+
...number(valtype === 'i32' ? -1 : NaN),
|
401
|
+
[ Opcodes.br, 1 ],
|
402
|
+
[ Opcodes.end ],
|
378
403
|
|
379
|
-
|
380
|
-
|
404
|
+
[ Opcodes.local_get, iTmp ],
|
405
|
+
]),
|
381
406
|
|
382
|
-
|
383
|
-
|
407
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
408
|
+
[ Opcodes.i32_mul ],
|
384
409
|
|
385
|
-
|
386
|
-
|
387
|
-
Opcodes.i32_from_u
|
388
|
-
];
|
389
|
-
},
|
410
|
+
...pointer,
|
411
|
+
[ Opcodes.i32_add ],
|
390
412
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
[ Opcodes.local_set, iTmp ],
|
413
|
+
// load current string ind {arg}
|
414
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
415
|
+
Opcodes.i32_from_u
|
416
|
+
],
|
396
417
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
418
|
+
isWellFormed: (pointer, length, _1, _2, iTmp, iTmp2) => [
|
419
|
+
// note: we cannot presume it begins as 0 in case it was used previously
|
420
|
+
...pointer,
|
421
|
+
[ Opcodes.local_set, iTmp ],
|
422
|
+
|
423
|
+
// use cached length as end pointer
|
424
|
+
...length.getCachedI32(),
|
425
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
426
|
+
[ Opcodes.i32_mul ],
|
427
|
+
...pointer,
|
428
|
+
[ Opcodes.i32_add ],
|
429
|
+
...length.setCachedI32(),
|
404
430
|
|
405
|
-
|
431
|
+
[ Opcodes.loop, Blocktype.void ],
|
406
432
|
|
407
|
-
|
433
|
+
[ Opcodes.block, Blocktype.void ],
|
408
434
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
// if not leading surrogate, return false
|
422
|
-
[ Opcodes.local_get, iTmp2 ],
|
423
|
-
...number(0xDC00, Valtype.i32),
|
424
|
-
[ Opcodes.i32_ge_s ],
|
425
|
-
[ Opcodes.if, Blocktype.void ],
|
426
|
-
...number(0),
|
427
|
-
[ Opcodes.br, 3 ],
|
428
|
-
[ Opcodes.end ],
|
435
|
+
[ Opcodes.local_get, iTmp ],
|
436
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
437
|
+
[ Opcodes.local_set, iTmp2 ],
|
438
|
+
|
439
|
+
// if not surrogate, continue
|
440
|
+
[ Opcodes.local_get, iTmp2 ],
|
441
|
+
...number(0xF800, Valtype.i32),
|
442
|
+
[ Opcodes.i32_and ],
|
443
|
+
...number(0xD800, Valtype.i32),
|
444
|
+
[ Opcodes.i32_ne ],
|
445
|
+
[ Opcodes.br_if, 0 ],
|
429
446
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
...number(0),
|
439
|
-
[ Opcodes.br, 3 ],
|
440
|
-
[ Opcodes.end ],
|
447
|
+
// if not leading surrogate, return false
|
448
|
+
[ Opcodes.local_get, iTmp2 ],
|
449
|
+
...number(0xDC00, Valtype.i32),
|
450
|
+
[ Opcodes.i32_ge_s ],
|
451
|
+
[ Opcodes.if, Blocktype.void ],
|
452
|
+
...number(0),
|
453
|
+
[ Opcodes.br, 3 ],
|
454
|
+
[ Opcodes.end ],
|
441
455
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
456
|
+
// if not followed by trailing surrogate, return false
|
457
|
+
[ Opcodes.local_get, iTmp ],
|
458
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize.i16) ],
|
459
|
+
...number(0xFC00, Valtype.i32),
|
460
|
+
[ Opcodes.i32_and ],
|
461
|
+
...number(0xDC00, Valtype.i32),
|
462
|
+
[ Opcodes.i32_ne ],
|
463
|
+
[ Opcodes.if, Blocktype.void ],
|
464
|
+
...number(0),
|
465
|
+
[ Opcodes.br, 3 ],
|
466
|
+
[ Opcodes.end ],
|
447
467
|
|
448
|
-
|
468
|
+
// bump index again since gone through two valid chars
|
469
|
+
[ Opcodes.local_get, iTmp ],
|
470
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
471
|
+
[ Opcodes.i32_add ],
|
472
|
+
[ Opcodes.local_set, iTmp ],
|
449
473
|
|
450
|
-
|
451
|
-
[ Opcodes.local_get, iTmp ],
|
452
|
-
...number(ValtypeSize.i16, Valtype.i32),
|
453
|
-
[ Opcodes.i32_add ],
|
454
|
-
[ Opcodes.local_tee, iTmp ],
|
474
|
+
[ Opcodes.end ],
|
455
475
|
|
456
|
-
|
457
|
-
|
458
|
-
|
476
|
+
// bump pointer and loop if not at the end
|
477
|
+
[ Opcodes.local_get, iTmp ],
|
478
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
479
|
+
[ Opcodes.i32_add ],
|
480
|
+
[ Opcodes.local_tee, iTmp ],
|
459
481
|
|
460
|
-
|
482
|
+
...length.getCachedI32(), // end pointer
|
483
|
+
[ Opcodes.i32_ne ],
|
484
|
+
[ Opcodes.br_if, 0 ],
|
461
485
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
486
|
+
[ Opcodes.end ],
|
487
|
+
|
488
|
+
// return true
|
489
|
+
...number(1)
|
490
|
+
]
|
466
491
|
};
|
467
492
|
|
468
493
|
this[TYPES.string].at.local = Valtype.i32;
|
469
494
|
this[TYPES.string].at.returnType = TYPES.string;
|
470
495
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
496
|
+
this[TYPES.string].charCodeAt.returnType = TYPES.number;
|
471
497
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
472
498
|
this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
473
499
|
|
@@ -477,7 +503,7 @@ export const PrototypeFuncs = function() {
|
|
477
503
|
|
478
504
|
if (Prefs.bytestring) {
|
479
505
|
this[TYPES.bytestring] = {
|
480
|
-
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
506
|
+
at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
|
481
507
|
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
482
508
|
|
483
509
|
return [
|
@@ -533,7 +559,7 @@ export const PrototypeFuncs = function() {
|
|
533
559
|
},
|
534
560
|
|
535
561
|
// todo: out of bounds properly
|
536
|
-
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
562
|
+
charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
|
537
563
|
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
538
564
|
|
539
565
|
return [
|
@@ -560,55 +586,52 @@ export const PrototypeFuncs = function() {
|
|
560
586
|
];
|
561
587
|
},
|
562
588
|
|
563
|
-
charCodeAt: (pointer, length, wIndex, iTmp) =>
|
564
|
-
|
565
|
-
|
566
|
-
Opcodes.i32_to,
|
567
|
-
|
568
|
-
...(zeroChecks.charcodeat ? [] : [
|
569
|
-
[ Opcodes.local_set, iTmp ],
|
589
|
+
charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
|
590
|
+
...wIndex,
|
591
|
+
Opcodes.i32_to,
|
570
592
|
|
571
|
-
|
572
|
-
|
573
|
-
[ Opcodes.local_get, iTmp ],
|
574
|
-
...number(0, Valtype.i32),
|
575
|
-
[ Opcodes.i32_lt_s ],
|
576
|
-
]),
|
593
|
+
...(zeroChecks.charcodeat ? [] : [
|
594
|
+
[ Opcodes.local_set, iTmp ],
|
577
595
|
|
578
|
-
|
596
|
+
// index < 0
|
597
|
+
...(noUnlikelyChecks ? [] : [
|
579
598
|
[ Opcodes.local_get, iTmp ],
|
580
|
-
...
|
581
|
-
[ Opcodes.
|
599
|
+
...number(0, Valtype.i32),
|
600
|
+
[ Opcodes.i32_lt_s ],
|
601
|
+
]),
|
582
602
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
[ Opcodes.end ],
|
603
|
+
// index >= length
|
604
|
+
[ Opcodes.local_get, iTmp ],
|
605
|
+
...length.getCachedI32(),
|
606
|
+
[ Opcodes.i32_ge_s ],
|
588
607
|
|
589
|
-
|
590
|
-
]
|
608
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
609
|
+
[ Opcodes.if, Blocktype.void ],
|
610
|
+
...number(valtype === 'i32' ? -1 : NaN),
|
611
|
+
[ Opcodes.br, 1 ],
|
612
|
+
[ Opcodes.end ],
|
591
613
|
|
592
|
-
|
593
|
-
|
614
|
+
[ Opcodes.local_get, iTmp ],
|
615
|
+
]),
|
594
616
|
|
595
|
-
|
596
|
-
|
597
|
-
Opcodes.i32_from_u
|
598
|
-
];
|
599
|
-
},
|
617
|
+
...pointer,
|
618
|
+
[ Opcodes.i32_add ],
|
600
619
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
620
|
+
// load current string ind {arg}
|
621
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
622
|
+
Opcodes.i32_from_u
|
623
|
+
],
|
624
|
+
|
625
|
+
isWellFormed: () => [
|
626
|
+
// we know it must be true as it is a bytestring lol
|
627
|
+
...number(1)
|
628
|
+
]
|
607
629
|
};
|
608
630
|
|
609
631
|
this[TYPES.bytestring].at.local = Valtype.i32;
|
610
632
|
this[TYPES.bytestring].at.returnType = TYPES.bytestring;
|
611
633
|
this[TYPES.bytestring].charAt.returnType = TYPES.bytestring;
|
634
|
+
this[TYPES.bytestring].charCodeAt.returnType = TYPES.number;
|
612
635
|
this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
|
613
636
|
this[TYPES.bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
614
637
|
|