porffor 0.2.0-e562242 → 0.2.0-eeb45f8
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 +6 -3
- package/compiler/builtins.js +134 -6
- package/compiler/codeGen.js +168 -47
- package/compiler/decompile.js +3 -3
- package/compiler/opt.js +1 -0
- package/compiler/prototype.js +171 -16
- package/compiler/wasmSpec.js +3 -0
- package/compiler/wrap.js +103 -10
- package/package.json +1 -1
- package/node_trace.1.log +0 -1
package/README.md
CHANGED
@@ -143,8 +143,8 @@ No particular order and no guarentees, just what could happen soon™
|
|
143
143
|
- [`do` expressions](https://github.com/tc39/proposal-do-expressions)
|
144
144
|
- [String Trim Characters](https://github.com/Kingwl/proposal-string-trim-characters)
|
145
145
|
- Posts
|
146
|
-
- Type annotations for performance
|
147
146
|
- Inlining investigation
|
147
|
+
- Self hosted testing?
|
148
148
|
|
149
149
|
## Performance
|
150
150
|
*For the things it supports most of the time*, Porffor is blazingly fast compared to most interpreters, and common engines running without JIT. For those with JIT, it is not that much slower like a traditional interpreter would be; mostly the same or a bit faster/slower depending on what.
|
@@ -209,10 +209,13 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
209
209
|
- `test262`: test262 runner and utils
|
210
210
|
|
211
211
|
## Usecases
|
212
|
-
Basically none (other than giving people headaches). Potential ideas
|
212
|
+
Basically none right now (other than giving people headaches). Potential ideas:
|
213
|
+
- Safety. As Porffor is written in JS, a memory-safe language\*, and compiles JS to Wasm, a fully sandboxed environment\*, it is quite safe. (\* These rely on the underlying implementations being secure. You could also run Wasm, or even Porffor itself, with an interpreter instead of a JIT for bonus security points too.)
|
214
|
+
- Compiling JS to native binaries. This is still very early, [`2c`](#2c) is not that good yet :(
|
215
|
+
- More in future probably?
|
213
216
|
|
214
217
|
## Usage
|
215
|
-
Basically nothing will work :). See files in `test` for examples.
|
218
|
+
Basically nothing will work :). See files in `test` and `bench` for examples.
|
216
219
|
|
217
220
|
1. Clone repo
|
218
221
|
2. `npm install`
|
package/compiler/builtins.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype } from "./wasmSpec.js";
|
1
|
+
import { Blocktype, Opcodes, Valtype, ValtypeSize } from "./wasmSpec.js";
|
2
2
|
import { number, i32x4 } from "./embedding.js";
|
3
3
|
|
4
4
|
export const importedFuncs = [
|
@@ -29,6 +29,21 @@ for (let i = 0; i < importedFuncs.length; i++) {
|
|
29
29
|
|
30
30
|
const char = c => number(c.charCodeAt(0));
|
31
31
|
|
32
|
+
const printStaticStr = str => {
|
33
|
+
const out = [];
|
34
|
+
|
35
|
+
for (let i = 0; i < str.length; i++) {
|
36
|
+
out.push(
|
37
|
+
// ...number(str.charCodeAt(i)),
|
38
|
+
...number(str.charCodeAt(i), Valtype.i32),
|
39
|
+
Opcodes.i32_from_u,
|
40
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
41
|
+
);
|
42
|
+
}
|
43
|
+
|
44
|
+
return out;
|
45
|
+
};
|
46
|
+
|
32
47
|
// todo: somehow diff between these (undefined != null) while remaining falsey in wasm as a number value
|
33
48
|
export const UNDEFINED = 0;
|
34
49
|
export const NULL = 0;
|
@@ -187,12 +202,125 @@ export const BuiltinFuncs = function() {
|
|
187
202
|
|
188
203
|
|
189
204
|
this.__console_log = {
|
190
|
-
params: [ valtypeBinary ],
|
191
|
-
|
205
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
206
|
+
typedParams: true,
|
207
|
+
locals: [ Valtype.i32, Valtype.i32 ],
|
192
208
|
returns: [],
|
193
|
-
wasm: [
|
194
|
-
[ Opcodes.local_get,
|
195
|
-
|
209
|
+
wasm: (scope, { TYPES, typeSwitch }) => [
|
210
|
+
...typeSwitch(scope, [ [ Opcodes.local_get, 1 ] ], {
|
211
|
+
[TYPES.number]: [
|
212
|
+
[ Opcodes.local_get, 0 ],
|
213
|
+
[ Opcodes.call, importedFuncs.print ],
|
214
|
+
],
|
215
|
+
[TYPES.boolean]: [
|
216
|
+
[ Opcodes.local_get, 0 ],
|
217
|
+
Opcodes.i32_to_u,
|
218
|
+
[ Opcodes.if, Blocktype.void ],
|
219
|
+
...printStaticStr('true'),
|
220
|
+
[ Opcodes.else ],
|
221
|
+
...printStaticStr('false'),
|
222
|
+
[ Opcodes.end ]
|
223
|
+
],
|
224
|
+
[TYPES.string]: [
|
225
|
+
// simply print a string :))
|
226
|
+
// cache input pointer as i32
|
227
|
+
[ Opcodes.local_get, 0 ],
|
228
|
+
Opcodes.i32_to_u,
|
229
|
+
[ Opcodes.local_tee, 2 ],
|
230
|
+
|
231
|
+
// make end pointer
|
232
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
233
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
234
|
+
[ Opcodes.i32_mul ],
|
235
|
+
|
236
|
+
[ Opcodes.local_get, 2 ],
|
237
|
+
[ Opcodes.i32_add ],
|
238
|
+
[ Opcodes.local_set, 3 ],
|
239
|
+
|
240
|
+
[ Opcodes.loop, Blocktype.void ],
|
241
|
+
|
242
|
+
// print current char
|
243
|
+
[ Opcodes.local_get, 2 ],
|
244
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
245
|
+
Opcodes.i32_from_u,
|
246
|
+
[ Opcodes.call, importedFuncs.printChar ],
|
247
|
+
|
248
|
+
// increment pointer by sizeof i16
|
249
|
+
[ Opcodes.local_get, 2 ],
|
250
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
251
|
+
[ Opcodes.i32_add ],
|
252
|
+
[ Opcodes.local_tee, 2 ],
|
253
|
+
|
254
|
+
// if pointer != end pointer, loop
|
255
|
+
[ Opcodes.local_get, 3 ],
|
256
|
+
[ Opcodes.i32_ne ],
|
257
|
+
[ Opcodes.br_if, 0 ],
|
258
|
+
|
259
|
+
[ Opcodes.end ]
|
260
|
+
],
|
261
|
+
[TYPES._array]: [
|
262
|
+
...printStaticStr('[ '),
|
263
|
+
|
264
|
+
// cache input pointer as i32
|
265
|
+
[ Opcodes.local_get, 0 ],
|
266
|
+
Opcodes.i32_to_u,
|
267
|
+
[ Opcodes.local_tee, 2 ],
|
268
|
+
|
269
|
+
// make end pointer
|
270
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
271
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
272
|
+
[ Opcodes.i32_mul ],
|
273
|
+
|
274
|
+
[ Opcodes.local_get, 2 ],
|
275
|
+
[ Opcodes.i32_add ],
|
276
|
+
[ Opcodes.local_set, 3 ],
|
277
|
+
|
278
|
+
[ Opcodes.loop, Blocktype.void ],
|
279
|
+
|
280
|
+
// print current char
|
281
|
+
[ Opcodes.local_get, 2 ],
|
282
|
+
[ Opcodes.load, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
|
283
|
+
[ Opcodes.call, importedFuncs.print ],
|
284
|
+
|
285
|
+
// increment pointer by sizeof valtype
|
286
|
+
[ Opcodes.local_get, 2 ],
|
287
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
288
|
+
[ Opcodes.i32_add ],
|
289
|
+
[ Opcodes.local_tee, 2 ],
|
290
|
+
|
291
|
+
// if pointer != end pointer, print separator and loop
|
292
|
+
[ Opcodes.local_get, 3 ],
|
293
|
+
[ Opcodes.i32_ne ],
|
294
|
+
[ Opcodes.if, Blocktype.void ],
|
295
|
+
...printStaticStr(', '),
|
296
|
+
[ Opcodes.br, 1 ],
|
297
|
+
[ Opcodes.end ],
|
298
|
+
|
299
|
+
[ Opcodes.end ],
|
300
|
+
|
301
|
+
...printStaticStr(' ]'),
|
302
|
+
],
|
303
|
+
[TYPES.undefined]: [
|
304
|
+
...printStaticStr('undefined')
|
305
|
+
],
|
306
|
+
[TYPES.function]: [
|
307
|
+
...printStaticStr('function () {}')
|
308
|
+
],
|
309
|
+
[TYPES.object]: [
|
310
|
+
[ Opcodes.local_get, 0 ],
|
311
|
+
Opcodes.i32_to_u,
|
312
|
+
[ Opcodes.if, Blocktype.void ],
|
313
|
+
...printStaticStr('{}'),
|
314
|
+
[ Opcodes.else ],
|
315
|
+
...printStaticStr('null'),
|
316
|
+
[ Opcodes.end ]
|
317
|
+
],
|
318
|
+
default: [
|
319
|
+
[ Opcodes.local_get, 0 ],
|
320
|
+
[ Opcodes.call, importedFuncs.print ],
|
321
|
+
]
|
322
|
+
}, Blocktype.void),
|
323
|
+
|
196
324
|
...char('\n'),
|
197
325
|
[ Opcodes.call, importedFuncs.printChar ]
|
198
326
|
]
|
package/compiler/codeGen.js
CHANGED
@@ -55,7 +55,7 @@ const todo = msg => {
|
|
55
55
|
};
|
56
56
|
|
57
57
|
const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
58
|
-
const generate = (scope, decl, global = false, name = undefined) => {
|
58
|
+
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
59
59
|
switch (decl.type) {
|
60
60
|
case 'BinaryExpression':
|
61
61
|
return generateBinaryExp(scope, decl, global, name);
|
@@ -68,7 +68,12 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
68
68
|
|
69
69
|
case 'ArrowFunctionExpression':
|
70
70
|
case 'FunctionDeclaration':
|
71
|
-
generateFunc(scope, decl);
|
71
|
+
const func = generateFunc(scope, decl);
|
72
|
+
|
73
|
+
if (decl.type.endsWith('Expression')) {
|
74
|
+
return number(func.index);
|
75
|
+
}
|
76
|
+
|
72
77
|
return [];
|
73
78
|
|
74
79
|
case 'BlockStatement':
|
@@ -81,7 +86,7 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
81
86
|
return generateExp(scope, decl);
|
82
87
|
|
83
88
|
case 'CallExpression':
|
84
|
-
return generateCall(scope, decl, global, name);
|
89
|
+
return generateCall(scope, decl, global, name, valueUnused);
|
85
90
|
|
86
91
|
case 'NewExpression':
|
87
92
|
return generateNew(scope, decl, global, name);
|
@@ -680,6 +685,15 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
680
685
|
[ Opcodes.i32_eqz ], */
|
681
686
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
682
687
|
],
|
688
|
+
[TYPES._bytestring]: [ // duplicate of string
|
689
|
+
[ Opcodes.local_get, tmp ],
|
690
|
+
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
691
|
+
|
692
|
+
// get length
|
693
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
694
|
+
|
695
|
+
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
696
|
+
],
|
683
697
|
default: def
|
684
698
|
}, intOut ? Valtype.i32 : valtypeBinary)
|
685
699
|
];
|
@@ -707,6 +721,17 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
707
721
|
[ Opcodes.i32_eqz ],
|
708
722
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
709
723
|
],
|
724
|
+
[TYPES._bytestring]: [ // duplicate of string
|
725
|
+
[ Opcodes.local_get, tmp ],
|
726
|
+
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
727
|
+
|
728
|
+
// get length
|
729
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
730
|
+
|
731
|
+
// if length == 0
|
732
|
+
[ Opcodes.i32_eqz ],
|
733
|
+
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
734
|
+
],
|
710
735
|
default: [
|
711
736
|
// if value == 0
|
712
737
|
[ Opcodes.local_get, tmp ],
|
@@ -947,6 +972,18 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
947
972
|
locals[nameParam(i)] = { idx: i, type: allLocals[i] };
|
948
973
|
}
|
949
974
|
|
975
|
+
if (typeof wasm === 'function') {
|
976
|
+
const scope = {
|
977
|
+
name,
|
978
|
+
params,
|
979
|
+
locals,
|
980
|
+
returns,
|
981
|
+
localInd: allLocals.length,
|
982
|
+
};
|
983
|
+
|
984
|
+
wasm = wasm(scope, { TYPES, typeSwitch, makeArray });
|
985
|
+
}
|
986
|
+
|
950
987
|
let baseGlobalIdx, i = 0;
|
951
988
|
for (const type of globalTypes) {
|
952
989
|
if (baseGlobalIdx === undefined) baseGlobalIdx = globalInd;
|
@@ -1027,7 +1064,8 @@ const TYPES = {
|
|
1027
1064
|
|
1028
1065
|
// these are not "typeof" types but tracked internally
|
1029
1066
|
_array: 0x10,
|
1030
|
-
_regexp: 0x11
|
1067
|
+
_regexp: 0x11,
|
1068
|
+
_bytestring: 0x12
|
1031
1069
|
};
|
1032
1070
|
|
1033
1071
|
const TYPE_NAMES = {
|
@@ -1041,7 +1079,8 @@ const TYPE_NAMES = {
|
|
1041
1079
|
[TYPES.bigint]: 'BigInt',
|
1042
1080
|
|
1043
1081
|
[TYPES._array]: 'Array',
|
1044
|
-
[TYPES._regexp]: 'RegExp'
|
1082
|
+
[TYPES._regexp]: 'RegExp',
|
1083
|
+
[TYPES._bytestring]: 'ByteString'
|
1045
1084
|
};
|
1046
1085
|
|
1047
1086
|
const getType = (scope, _name) => {
|
@@ -1094,6 +1133,8 @@ const getNodeType = (scope, node) => {
|
|
1094
1133
|
if (node.type === 'Literal') {
|
1095
1134
|
if (node.regex) return TYPES._regexp;
|
1096
1135
|
|
1136
|
+
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
|
1137
|
+
|
1097
1138
|
return TYPES[typeof node.value];
|
1098
1139
|
}
|
1099
1140
|
|
@@ -1107,6 +1148,15 @@ const getNodeType = (scope, node) => {
|
|
1107
1148
|
|
1108
1149
|
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
1109
1150
|
const name = node.callee.name;
|
1151
|
+
if (!name) {
|
1152
|
+
// iife
|
1153
|
+
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1154
|
+
|
1155
|
+
// presume
|
1156
|
+
// todo: warn here?
|
1157
|
+
return TYPES.number;
|
1158
|
+
}
|
1159
|
+
|
1110
1160
|
const func = funcs.find(x => x.name === name);
|
1111
1161
|
|
1112
1162
|
if (func) {
|
@@ -1201,7 +1251,7 @@ const getNodeType = (scope, node) => {
|
|
1201
1251
|
if (node.operator === '!') return TYPES.boolean;
|
1202
1252
|
if (node.operator === 'void') return TYPES.undefined;
|
1203
1253
|
if (node.operator === 'delete') return TYPES.boolean;
|
1204
|
-
if (node.operator === 'typeof') return TYPES.string;
|
1254
|
+
if (node.operator === 'typeof') return process.argv.includes('-bytestring') ? TYPES._bytestring : TYPES.string;
|
1205
1255
|
|
1206
1256
|
return TYPES.number;
|
1207
1257
|
}
|
@@ -1210,7 +1260,9 @@ const getNodeType = (scope, node) => {
|
|
1210
1260
|
// hack: if something.length, number type
|
1211
1261
|
if (node.property.name === 'length') return TYPES.number;
|
1212
1262
|
|
1213
|
-
|
1263
|
+
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1264
|
+
|
1265
|
+
// presume
|
1214
1266
|
return TYPES.number;
|
1215
1267
|
}
|
1216
1268
|
|
@@ -1261,16 +1313,7 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
1261
1313
|
return number(decl.value ? 1 : 0);
|
1262
1314
|
|
1263
1315
|
case 'string':
|
1264
|
-
|
1265
|
-
const rawElements = new Array(str.length);
|
1266
|
-
let j = 0;
|
1267
|
-
for (let i = 0; i < str.length; i++) {
|
1268
|
-
rawElements[i] = str.charCodeAt(i);
|
1269
|
-
}
|
1270
|
-
|
1271
|
-
return makeArray(scope, {
|
1272
|
-
rawElements
|
1273
|
-
}, global, name, false, 'i16')[0];
|
1316
|
+
return makeString(scope, decl.value, global, name);
|
1274
1317
|
|
1275
1318
|
default:
|
1276
1319
|
return todo(`cannot generate literal of type ${typeof decl.value}`);
|
@@ -1291,9 +1334,9 @@ const countLeftover = wasm => {
|
|
1291
1334
|
|
1292
1335
|
if (depth === 0)
|
1293
1336
|
if ([Opcodes.throw,Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1294
|
-
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
|
1337
|
+
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
|
1295
1338
|
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const].includes(inst[0])) count++;
|
1296
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16].includes(inst[0])) count -= 2;
|
1339
|
+
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1297
1340
|
else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
|
1298
1341
|
else if (inst[0] === Opcodes.return) count = 0;
|
1299
1342
|
else if (inst[0] === Opcodes.call) {
|
@@ -1319,7 +1362,7 @@ const disposeLeftover = wasm => {
|
|
1319
1362
|
const generateExp = (scope, decl) => {
|
1320
1363
|
const expression = decl.expression;
|
1321
1364
|
|
1322
|
-
const out = generate(scope, expression);
|
1365
|
+
const out = generate(scope, expression, undefined, undefined, true);
|
1323
1366
|
disposeLeftover(out);
|
1324
1367
|
|
1325
1368
|
return out;
|
@@ -1377,7 +1420,7 @@ const RTArrayUtil = {
|
|
1377
1420
|
]
|
1378
1421
|
};
|
1379
1422
|
|
1380
|
-
const generateCall = (scope, decl, _global, _name) => {
|
1423
|
+
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1381
1424
|
/* const callee = decl.callee;
|
1382
1425
|
const args = decl.arguments;
|
1383
1426
|
|
@@ -1496,10 +1539,18 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1496
1539
|
// use local for cached i32 length as commonly used
|
1497
1540
|
const lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
1498
1541
|
const pointerLocal = localTmp(scope, '__proto_pointer_cache', Valtype.i32);
|
1499
|
-
const getPointer = [ [ Opcodes.local_get, pointerLocal ] ];
|
1500
1542
|
|
1501
1543
|
// TODO: long-term, prototypes should be their individual separate funcs
|
1502
1544
|
|
1545
|
+
const rawPointer = [
|
1546
|
+
...generate(scope, target),
|
1547
|
+
Opcodes.i32_to_u
|
1548
|
+
];
|
1549
|
+
|
1550
|
+
const usePointerCache = !Object.values(protoCands).every(x => x.noPointerCache === true);
|
1551
|
+
const getPointer = usePointerCache ? [ [ Opcodes.local_get, pointerLocal ] ] : rawPointer;
|
1552
|
+
|
1553
|
+
let allOptUnused = true;
|
1503
1554
|
let lengthI32CacheUsed = false;
|
1504
1555
|
const protoBC = {};
|
1505
1556
|
for (const x in protoCands) {
|
@@ -1519,6 +1570,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1519
1570
|
const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
|
1520
1571
|
const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
|
1521
1572
|
|
1573
|
+
let optUnused = false;
|
1522
1574
|
const protoOut = protoFunc(getPointer, {
|
1523
1575
|
getCachedI32: () => {
|
1524
1576
|
lengthI32CacheUsed = true;
|
@@ -1533,10 +1585,15 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1533
1585
|
return makeArray(scope, {
|
1534
1586
|
rawElements: new Array(length)
|
1535
1587
|
}, _global, _name, true, itemType);
|
1588
|
+
}, () => {
|
1589
|
+
optUnused = true;
|
1590
|
+
return unusedValue;
|
1536
1591
|
});
|
1537
1592
|
|
1593
|
+
if (!optUnused) allOptUnused = false;
|
1594
|
+
|
1538
1595
|
protoBC[x] = [
|
1539
|
-
[ Opcodes.block, valtypeBinary ],
|
1596
|
+
[ Opcodes.block, unusedValue && optUnused ? Blocktype.void : valtypeBinary ],
|
1540
1597
|
...protoOut,
|
1541
1598
|
|
1542
1599
|
...number(protoFunc.returnType ?? TYPES.number, Valtype.i32),
|
@@ -1545,11 +1602,13 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1545
1602
|
];
|
1546
1603
|
}
|
1547
1604
|
|
1548
|
-
|
1549
|
-
...generate(scope, target),
|
1605
|
+
// todo: if some cands use optUnused and some don't, we will probably crash
|
1550
1606
|
|
1551
|
-
|
1552
|
-
|
1607
|
+
return [
|
1608
|
+
...(usePointerCache ? [
|
1609
|
+
...rawPointer,
|
1610
|
+
[ Opcodes.local_set, pointerLocal ],
|
1611
|
+
] : []),
|
1553
1612
|
|
1554
1613
|
...(!lengthI32CacheUsed ? [] : [
|
1555
1614
|
...RTArrayUtil.getLengthI32(getPointer),
|
@@ -1561,7 +1620,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1561
1620
|
|
1562
1621
|
// TODO: error better
|
1563
1622
|
default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`)
|
1564
|
-
}, valtypeBinary),
|
1623
|
+
}, allOptUnused && unusedValue ? Blocktype.void : valtypeBinary),
|
1565
1624
|
];
|
1566
1625
|
}
|
1567
1626
|
}
|
@@ -1608,7 +1667,9 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1608
1667
|
const func = funcs.find(x => x.index === idx);
|
1609
1668
|
|
1610
1669
|
const userFunc = (funcIndex[name] && !importedFuncs[name] && !builtinFuncs[name] && !internalConstrs[name]) || idx === -1;
|
1611
|
-
const
|
1670
|
+
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1671
|
+
const typedReturn = userFunc || builtinFuncs[name]?.typedReturn;
|
1672
|
+
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1612
1673
|
|
1613
1674
|
let args = decl.arguments;
|
1614
1675
|
if (func && args.length < paramCount) {
|
@@ -1626,12 +1687,12 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1626
1687
|
let out = [];
|
1627
1688
|
for (const arg of args) {
|
1628
1689
|
out = out.concat(generate(scope, arg));
|
1629
|
-
if (
|
1690
|
+
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
1630
1691
|
}
|
1631
1692
|
|
1632
1693
|
out.push([ Opcodes.call, idx ]);
|
1633
1694
|
|
1634
|
-
if (!
|
1695
|
+
if (!typedReturn) {
|
1635
1696
|
// let type;
|
1636
1697
|
// if (builtinFuncs[name]) type = TYPES[builtinFuncs[name].returnType ?? 'number'];
|
1637
1698
|
// if (internalConstrs[name]) type = internalConstrs[name].type;
|
@@ -1767,6 +1828,8 @@ const brTable = (input, bc, returns) => {
|
|
1767
1828
|
};
|
1768
1829
|
|
1769
1830
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
1831
|
+
if (!process.argv.includes('-bytestring')) delete bc[TYPES._bytestring];
|
1832
|
+
|
1770
1833
|
const known = knownType(scope, type);
|
1771
1834
|
if (known != null) {
|
1772
1835
|
return bc[known] ?? bc.default;
|
@@ -2157,6 +2220,8 @@ const generateUnary = (scope, decl) => {
|
|
2157
2220
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2158
2221
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2159
2222
|
|
2223
|
+
[TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2224
|
+
|
2160
2225
|
// object and internal types
|
2161
2226
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
2162
2227
|
});
|
@@ -2338,13 +2403,14 @@ const generateForOf = (scope, decl) => {
|
|
2338
2403
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2339
2404
|
// hack: this is naughty and will break things!
|
2340
2405
|
let newOut = number(0, Valtype.f64), newPointer = -1;
|
2341
|
-
if (pages.
|
2406
|
+
if (pages.hasAnyString) {
|
2342
2407
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2343
2408
|
rawElements: new Array(1)
|
2344
2409
|
}, isGlobal, leftName, true, 'i16');
|
2345
2410
|
}
|
2346
2411
|
|
2347
2412
|
// set type for local
|
2413
|
+
// todo: optimize away counter and use end pointer
|
2348
2414
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2349
2415
|
[TYPES._array]: [
|
2350
2416
|
...setType(scope, leftName, TYPES.number),
|
@@ -2530,6 +2596,8 @@ const allocPage = (reason, type) => {
|
|
2530
2596
|
|
2531
2597
|
if (reason.startsWith('array:')) pages.hasArray = true;
|
2532
2598
|
if (reason.startsWith('string:')) pages.hasString = true;
|
2599
|
+
if (reason.startsWith('bytestring:')) pages.hasByteString = true;
|
2600
|
+
if (reason.includes('string:')) pages.hasAnyString = true;
|
2533
2601
|
|
2534
2602
|
const ind = pages.size;
|
2535
2603
|
pages.set(reason, { ind, type });
|
@@ -2563,7 +2631,8 @@ const StoreOps = {
|
|
2563
2631
|
f64: Opcodes.f64_store,
|
2564
2632
|
|
2565
2633
|
// expects i32 input!
|
2566
|
-
|
2634
|
+
i8: Opcodes.i32_store8,
|
2635
|
+
i16: Opcodes.i32_store16,
|
2567
2636
|
};
|
2568
2637
|
|
2569
2638
|
let data = [];
|
@@ -2582,6 +2651,15 @@ const compileBytes = (val, itemType, signed = true) => {
|
|
2582
2651
|
}
|
2583
2652
|
};
|
2584
2653
|
|
2654
|
+
const getAllocType = itemType => {
|
2655
|
+
switch (itemType) {
|
2656
|
+
case 'i8': return 'bytestring';
|
2657
|
+
case 'i16': return 'string';
|
2658
|
+
|
2659
|
+
default: return 'array';
|
2660
|
+
}
|
2661
|
+
};
|
2662
|
+
|
2585
2663
|
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
|
2586
2664
|
const out = [];
|
2587
2665
|
|
@@ -2591,7 +2669,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2591
2669
|
|
2592
2670
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
2593
2671
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
2594
|
-
arrays.set(name, allocPage(`${itemType
|
2672
|
+
arrays.set(name, allocPage(`${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
2595
2673
|
}
|
2596
2674
|
|
2597
2675
|
const pointer = arrays.get(name);
|
@@ -2637,7 +2715,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2637
2715
|
out.push(
|
2638
2716
|
...number(0, Valtype.i32),
|
2639
2717
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
2640
|
-
[ storeOp, Math.log2(ValtypeSize[itemType]) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
2718
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
2641
2719
|
);
|
2642
2720
|
}
|
2643
2721
|
|
@@ -2647,15 +2725,29 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2647
2725
|
return [ out, pointer ];
|
2648
2726
|
};
|
2649
2727
|
|
2728
|
+
const byteStringable = str => {
|
2729
|
+
if (!process.argv.includes('-bytestring')) return false;
|
2730
|
+
|
2731
|
+
for (let i = 0; i < str.length; i++) {
|
2732
|
+
if (str.charCodeAt(i) > 0xFF) return false;
|
2733
|
+
}
|
2734
|
+
|
2735
|
+
return true;
|
2736
|
+
};
|
2737
|
+
|
2650
2738
|
const makeString = (scope, str, global = false, name = '$undeclared') => {
|
2651
2739
|
const rawElements = new Array(str.length);
|
2740
|
+
let byteStringable = process.argv.includes('-bytestring');
|
2652
2741
|
for (let i = 0; i < str.length; i++) {
|
2653
|
-
|
2742
|
+
const c = str.charCodeAt(i);
|
2743
|
+
rawElements[i] = c;
|
2744
|
+
|
2745
|
+
if (byteStringable && c > 0xFF) byteStringable = false;
|
2654
2746
|
}
|
2655
2747
|
|
2656
2748
|
return makeArray(scope, {
|
2657
2749
|
rawElements
|
2658
|
-
}, global, name, false, 'i16')[0];
|
2750
|
+
}, global, name, false, byteStringable ? 'i8' : 'i16')[0];
|
2659
2751
|
};
|
2660
2752
|
|
2661
2753
|
let arrays = new Map();
|
@@ -2683,10 +2775,13 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2683
2775
|
];
|
2684
2776
|
}
|
2685
2777
|
|
2778
|
+
const object = generate(scope, decl.object);
|
2779
|
+
const property = generate(scope, decl.property);
|
2780
|
+
|
2686
2781
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2687
2782
|
// hack: this is naughty and will break things!
|
2688
2783
|
let newOut = number(0, valtypeBinary), newPointer = -1;
|
2689
|
-
if (pages.
|
2784
|
+
if (pages.hasAnyString) {
|
2690
2785
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2691
2786
|
rawElements: new Array(1)
|
2692
2787
|
}, _global, _name, true, 'i16');
|
@@ -2695,7 +2790,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2695
2790
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
2696
2791
|
[TYPES._array]: [
|
2697
2792
|
// get index as valtype
|
2698
|
-
...
|
2793
|
+
...property,
|
2699
2794
|
|
2700
2795
|
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2701
2796
|
Opcodes.i32_to_u,
|
@@ -2703,7 +2798,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2703
2798
|
[ Opcodes.i32_mul ],
|
2704
2799
|
|
2705
2800
|
...(aotPointer ? [] : [
|
2706
|
-
...
|
2801
|
+
...object,
|
2707
2802
|
Opcodes.i32_to_u,
|
2708
2803
|
[ Opcodes.i32_add ]
|
2709
2804
|
]),
|
@@ -2722,14 +2817,14 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2722
2817
|
|
2723
2818
|
...number(0, Valtype.i32), // base 0 for store later
|
2724
2819
|
|
2725
|
-
...
|
2726
|
-
|
2820
|
+
...property,
|
2727
2821
|
Opcodes.i32_to_u,
|
2822
|
+
|
2728
2823
|
...number(ValtypeSize.i16, Valtype.i32),
|
2729
2824
|
[ Opcodes.i32_mul ],
|
2730
2825
|
|
2731
2826
|
...(aotPointer ? [] : [
|
2732
|
-
...
|
2827
|
+
...object,
|
2733
2828
|
Opcodes.i32_to_u,
|
2734
2829
|
[ Opcodes.i32_add ]
|
2735
2830
|
]),
|
@@ -2746,6 +2841,34 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2746
2841
|
...number(TYPES.string, Valtype.i32),
|
2747
2842
|
setLastType(scope)
|
2748
2843
|
],
|
2844
|
+
[TYPES._bytestring]: [
|
2845
|
+
// setup new/out array
|
2846
|
+
...newOut,
|
2847
|
+
[ Opcodes.drop ],
|
2848
|
+
|
2849
|
+
...number(0, Valtype.i32), // base 0 for store later
|
2850
|
+
|
2851
|
+
...property,
|
2852
|
+
Opcodes.i32_to_u,
|
2853
|
+
|
2854
|
+
...(aotPointer ? [] : [
|
2855
|
+
...object,
|
2856
|
+
Opcodes.i32_to_u,
|
2857
|
+
[ Opcodes.i32_add ]
|
2858
|
+
]),
|
2859
|
+
|
2860
|
+
// load current string ind {arg}
|
2861
|
+
[ Opcodes.i32_load8_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
2862
|
+
|
2863
|
+
// store to new string ind 0
|
2864
|
+
[ Opcodes.i32_store8, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
2865
|
+
|
2866
|
+
// return new string (page)
|
2867
|
+
...number(newPointer),
|
2868
|
+
|
2869
|
+
...number(TYPES._bytestring, Valtype.i32),
|
2870
|
+
setLastType(scope)
|
2871
|
+
],
|
2749
2872
|
|
2750
2873
|
default: [ [ Opcodes.unreachable ] ]
|
2751
2874
|
});
|
@@ -2827,10 +2950,8 @@ const generateFunc = (scope, decl) => {
|
|
2827
2950
|
const func = {
|
2828
2951
|
name,
|
2829
2952
|
params: Object.values(innerScope.locals).slice(0, params.length * 2).map(x => x.type),
|
2830
|
-
|
2831
|
-
|
2832
|
-
throws: innerScope.throws,
|
2833
|
-
index: currentFuncIndex++
|
2953
|
+
index: currentFuncIndex++,
|
2954
|
+
...innerScope
|
2834
2955
|
};
|
2835
2956
|
funcIndex[name] = func.index;
|
2836
2957
|
|
package/compiler/decompile.js
CHANGED
@@ -15,7 +15,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
15
15
|
if (name) out += `${makeSignature(params, returns)} ;; $${name} (${ind})\n`;
|
16
16
|
|
17
17
|
const justLocals = Object.values(locals).sort((a, b) => a.idx - b.idx).slice(params.length);
|
18
|
-
if (justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
|
18
|
+
if (name && justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
|
19
19
|
|
20
20
|
let i = -1, lastInst;
|
21
21
|
let byte = 0;
|
@@ -32,7 +32,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
32
32
|
inst = [ [ inst[0], inst[1] ], ...inst.slice(2) ];
|
33
33
|
}
|
34
34
|
|
35
|
-
if (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all) depth--;
|
35
|
+
if (depth > 0 && (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all)) depth--;
|
36
36
|
|
37
37
|
out += ' '.repeat(Math.max(0, depth * 2));
|
38
38
|
|
@@ -119,7 +119,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
119
119
|
export const highlightAsm = asm => asm
|
120
120
|
.replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
|
121
121
|
.replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
|
122
|
-
.replace(/
|
122
|
+
.replace(/(i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `\x1B[36m${_}\x1B[0m`)
|
123
123
|
.replace(/(return_call|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
|
124
124
|
.replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
|
125
125
|
.replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
|
package/compiler/opt.js
CHANGED
@@ -192,6 +192,7 @@ export default (funcs, globals, pages, tags) => {
|
|
192
192
|
let missing = false;
|
193
193
|
if (type === 'Array') missing = !pages.hasArray;
|
194
194
|
if (type === 'String') missing = !pages.hasString;
|
195
|
+
if (type === 'ByteString') missing = !pages.hasByteString;
|
195
196
|
|
196
197
|
if (missing) {
|
197
198
|
let j = i, depth = 0;
|
package/compiler/prototype.js
CHANGED
@@ -16,7 +16,8 @@ const TYPES = {
|
|
16
16
|
|
17
17
|
// these are not "typeof" types but tracked internally
|
18
18
|
_array: 0x10,
|
19
|
-
_regexp: 0x11
|
19
|
+
_regexp: 0x11,
|
20
|
+
_bytestring: 0x12
|
20
21
|
};
|
21
22
|
|
22
23
|
// todo: turn these into built-ins once arrays and these become less hacky
|
@@ -71,7 +72,7 @@ export const PrototypeFuncs = function() {
|
|
71
72
|
],
|
72
73
|
|
73
74
|
// todo: only for 1 argument
|
74
|
-
push: (pointer, length, wNewMember) => [
|
75
|
+
push: (pointer, length, wNewMember, _1, _2, _3, unusedValue) => [
|
75
76
|
// get memory offset of array at last index (length)
|
76
77
|
...length.getCachedI32(),
|
77
78
|
...number(ValtypeSize[valtype], Valtype.i32),
|
@@ -92,22 +93,28 @@ export const PrototypeFuncs = function() {
|
|
92
93
|
...number(1, Valtype.i32),
|
93
94
|
[ Opcodes.i32_add ],
|
94
95
|
|
95
|
-
...
|
96
|
-
|
96
|
+
...(unusedValue() ? [] : [
|
97
|
+
...length.setCachedI32(),
|
98
|
+
...length.getCachedI32(),
|
99
|
+
])
|
97
100
|
]),
|
98
101
|
|
99
|
-
...
|
100
|
-
|
102
|
+
...(unusedValue() ? [] : [
|
103
|
+
...length.getCachedI32(),
|
104
|
+
Opcodes.i32_from_u
|
105
|
+
])
|
101
106
|
|
102
107
|
// ...length.get()
|
103
108
|
],
|
104
109
|
|
105
|
-
pop: (pointer, length) => [
|
110
|
+
pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
|
106
111
|
// if length == 0, noop
|
107
112
|
...length.getCachedI32(),
|
108
113
|
[ Opcodes.i32_eqz ],
|
109
114
|
[ Opcodes.if, Blocktype.void ],
|
110
|
-
...
|
115
|
+
...(unusedValue() ? [] : [
|
116
|
+
...number(UNDEFINED),
|
117
|
+
]),
|
111
118
|
[ Opcodes.br, 1 ],
|
112
119
|
[ Opcodes.end ],
|
113
120
|
|
@@ -119,19 +126,23 @@ export const PrototypeFuncs = function() {
|
|
119
126
|
...number(1, Valtype.i32),
|
120
127
|
[ Opcodes.i32_sub ],
|
121
128
|
|
122
|
-
...
|
123
|
-
|
129
|
+
...(unusedValue() ? [] : [
|
130
|
+
...length.setCachedI32(),
|
131
|
+
...length.getCachedI32(),
|
132
|
+
])
|
124
133
|
]),
|
125
134
|
|
126
135
|
// load last element
|
127
|
-
...
|
128
|
-
|
129
|
-
|
136
|
+
...(unusedValue() ? [] : [
|
137
|
+
...length.getCachedI32(),
|
138
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
139
|
+
[ Opcodes.i32_mul ],
|
130
140
|
|
131
|
-
|
132
|
-
|
141
|
+
...pointer,
|
142
|
+
[ Opcodes.i32_add ],
|
133
143
|
|
134
|
-
|
144
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
145
|
+
])
|
135
146
|
],
|
136
147
|
|
137
148
|
shift: (pointer, length) => [
|
@@ -472,8 +483,152 @@ export const PrototypeFuncs = function() {
|
|
472
483
|
this[TYPES.string].at.returnType = TYPES.string;
|
473
484
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
474
485
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
486
|
+
this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
475
487
|
|
476
488
|
this[TYPES.string].isWellFormed.local = Valtype.i32;
|
477
489
|
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
478
490
|
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
491
|
+
|
492
|
+
if (process.argv.includes('-bytestring')) {
|
493
|
+
this[TYPES._bytestring] = {
|
494
|
+
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
495
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
496
|
+
|
497
|
+
return [
|
498
|
+
// setup new/out array
|
499
|
+
...newOut,
|
500
|
+
[ Opcodes.drop ],
|
501
|
+
|
502
|
+
...number(0, Valtype.i32), // base 0 for store later
|
503
|
+
|
504
|
+
...wIndex,
|
505
|
+
Opcodes.i32_to_u,
|
506
|
+
[ Opcodes.local_tee, iTmp ],
|
507
|
+
|
508
|
+
// if index < 0: access index + array length
|
509
|
+
...number(0, Valtype.i32),
|
510
|
+
[ Opcodes.i32_lt_s ],
|
511
|
+
[ Opcodes.if, Blocktype.void ],
|
512
|
+
[ Opcodes.local_get, iTmp ],
|
513
|
+
...length.getCachedI32(),
|
514
|
+
[ Opcodes.i32_add ],
|
515
|
+
[ Opcodes.local_set, iTmp ],
|
516
|
+
[ Opcodes.end ],
|
517
|
+
|
518
|
+
// if still < 0 or >= length: return undefined
|
519
|
+
[ Opcodes.local_get, iTmp ],
|
520
|
+
...number(0, Valtype.i32),
|
521
|
+
[ Opcodes.i32_lt_s ],
|
522
|
+
|
523
|
+
[ Opcodes.local_get, iTmp ],
|
524
|
+
...length.getCachedI32(),
|
525
|
+
[ Opcodes.i32_ge_s ],
|
526
|
+
[ Opcodes.i32_or ],
|
527
|
+
|
528
|
+
[ Opcodes.if, Blocktype.void ],
|
529
|
+
...number(UNDEFINED),
|
530
|
+
[ Opcodes.br, 1 ],
|
531
|
+
[ Opcodes.end ],
|
532
|
+
|
533
|
+
[ Opcodes.local_get, iTmp ],
|
534
|
+
|
535
|
+
...pointer,
|
536
|
+
[ Opcodes.i32_add ],
|
537
|
+
|
538
|
+
// load current string ind {arg}
|
539
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
540
|
+
|
541
|
+
// store to new string ind 0
|
542
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
543
|
+
|
544
|
+
// return new string (pointer)
|
545
|
+
...number(newPointer)
|
546
|
+
];
|
547
|
+
},
|
548
|
+
|
549
|
+
// todo: out of bounds properly
|
550
|
+
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
551
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
552
|
+
|
553
|
+
return [
|
554
|
+
// setup new/out array
|
555
|
+
...newOut,
|
556
|
+
[ Opcodes.drop ],
|
557
|
+
|
558
|
+
...number(0, Valtype.i32), // base 0 for store later
|
559
|
+
|
560
|
+
...wIndex,
|
561
|
+
|
562
|
+
Opcodes.i32_to,
|
563
|
+
|
564
|
+
...pointer,
|
565
|
+
[ Opcodes.i32_add ],
|
566
|
+
|
567
|
+
// load current string ind {arg}
|
568
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
569
|
+
|
570
|
+
// store to new string ind 0
|
571
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
572
|
+
|
573
|
+
// return new string (page)
|
574
|
+
...number(newPointer)
|
575
|
+
];
|
576
|
+
},
|
577
|
+
|
578
|
+
charCodeAt: (pointer, length, wIndex, iTmp) => {
|
579
|
+
return [
|
580
|
+
...wIndex,
|
581
|
+
Opcodes.i32_to,
|
582
|
+
|
583
|
+
...(zeroChecks.charcodeat ? [] : [
|
584
|
+
[ Opcodes.local_set, iTmp ],
|
585
|
+
|
586
|
+
// index < 0
|
587
|
+
...(noUnlikelyChecks ? [] : [
|
588
|
+
[ Opcodes.local_get, iTmp ],
|
589
|
+
...number(0, Valtype.i32),
|
590
|
+
[ Opcodes.i32_lt_s ],
|
591
|
+
]),
|
592
|
+
|
593
|
+
// index >= length
|
594
|
+
[ Opcodes.local_get, iTmp ],
|
595
|
+
...length.getCachedI32(),
|
596
|
+
[ Opcodes.i32_ge_s ],
|
597
|
+
|
598
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
599
|
+
[ Opcodes.if, Blocktype.void ],
|
600
|
+
...number(NaN),
|
601
|
+
[ Opcodes.br, 1 ],
|
602
|
+
[ Opcodes.end ],
|
603
|
+
|
604
|
+
[ Opcodes.local_get, iTmp ],
|
605
|
+
]),
|
606
|
+
|
607
|
+
...pointer,
|
608
|
+
[ Opcodes.i32_add ],
|
609
|
+
|
610
|
+
// load current string ind {arg}
|
611
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
612
|
+
Opcodes.i32_from_u
|
613
|
+
];
|
614
|
+
},
|
615
|
+
|
616
|
+
isWellFormed: () => {
|
617
|
+
return [
|
618
|
+
// we know it must be true as it is a bytestring lol
|
619
|
+
...number(1)
|
620
|
+
]
|
621
|
+
}
|
622
|
+
};
|
623
|
+
|
624
|
+
this[TYPES._bytestring].at.local = Valtype.i32;
|
625
|
+
this[TYPES._bytestring].at.returnType = TYPES._bytestring;
|
626
|
+
this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
|
627
|
+
this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
|
628
|
+
this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
629
|
+
|
630
|
+
this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
|
631
|
+
this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
|
632
|
+
this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
|
633
|
+
}
|
479
634
|
};
|
package/compiler/wasmSpec.js
CHANGED
package/compiler/wrap.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import compile from './index.js';
|
2
2
|
import decompile from './decompile.js';
|
3
|
-
import
|
3
|
+
import { encodeVector, encodeLocal } from './encoding.js';
|
4
|
+
// import fs from 'node:fs';
|
4
5
|
|
5
6
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
6
7
|
|
@@ -18,7 +19,8 @@ const TYPES = {
|
|
18
19
|
|
19
20
|
// internal
|
20
21
|
[internalTypeBase]: '_array',
|
21
|
-
[internalTypeBase + 1]: '_regexp'
|
22
|
+
[internalTypeBase + 1]: '_regexp',
|
23
|
+
[internalTypeBase + 2]: '_bytestring'
|
22
24
|
};
|
23
25
|
|
24
26
|
export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
@@ -29,20 +31,104 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
29
31
|
|
30
32
|
if (source.includes('export function')) flags.push('module');
|
31
33
|
|
32
|
-
fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
34
|
+
// fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
33
35
|
|
34
36
|
times.push(performance.now() - t1);
|
35
37
|
if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
36
38
|
|
37
39
|
const t2 = performance.now();
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
|
41
|
+
let instance;
|
42
|
+
try {
|
43
|
+
0, { instance } = await WebAssembly.instantiate(wasm, {
|
44
|
+
'': {
|
45
|
+
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
46
|
+
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
47
|
+
t: _ => performance.now(),
|
48
|
+
...customImports
|
49
|
+
}
|
50
|
+
});
|
51
|
+
} catch (e) {
|
52
|
+
// only backtrace for runner, not test262/etc
|
53
|
+
if (!process.argv[1].includes('/runner')) throw e;
|
54
|
+
|
55
|
+
const funcInd = parseInt(e.message.match(/function #([0-9]+) /)[1]);
|
56
|
+
const blobOffset = parseInt(e.message.split('@')[1]);
|
57
|
+
|
58
|
+
// convert blob offset -> function wasm offset.
|
59
|
+
// this is not good code and is somewhat duplicated
|
60
|
+
// I just want it to work for debugging, I don't care about perf/yes
|
61
|
+
|
62
|
+
const func = funcs.find(x => x.index === funcInd);
|
63
|
+
const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
|
64
|
+
|
65
|
+
let localDecl = [], typeCount = 0, lastType;
|
66
|
+
for (let i = 0; i < locals.length; i++) {
|
67
|
+
const local = locals[i];
|
68
|
+
if (i !== 0 && local.type !== lastType) {
|
69
|
+
localDecl.push(encodeLocal(typeCount, lastType));
|
70
|
+
typeCount = 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
typeCount++;
|
74
|
+
lastType = local.type;
|
75
|
+
}
|
76
|
+
|
77
|
+
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
78
|
+
|
79
|
+
const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 40));
|
80
|
+
|
81
|
+
let i = 0;
|
82
|
+
for (; i < wasm.length; i++) {
|
83
|
+
let mismatch = false;
|
84
|
+
for (let j = 0; j < toFind.length; j++) {
|
85
|
+
if (wasm[i + j] !== toFind[j]) {
|
86
|
+
mismatch = true;
|
87
|
+
break;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
if (!mismatch) break;
|
92
|
+
}
|
93
|
+
|
94
|
+
if (i === wasm.length) throw e;
|
95
|
+
|
96
|
+
const offset = (blobOffset - i) + encodeVector(localDecl).length;
|
97
|
+
|
98
|
+
let cumLen = 0;
|
99
|
+
i = 0;
|
100
|
+
for (; i < func.wasm.length; i++) {
|
101
|
+
cumLen += func.wasm[i].filter(x => x != null && x <= 0xff).length;
|
102
|
+
if (cumLen === offset) break;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (cumLen !== offset) throw e;
|
106
|
+
|
107
|
+
i -= 1;
|
108
|
+
|
109
|
+
console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
|
110
|
+
|
111
|
+
console.log('\x1B[4m' + func.name + '\x1B[0m');
|
112
|
+
|
113
|
+
const surrounding = 6;
|
114
|
+
|
115
|
+
const decomp = decompile(func.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
|
116
|
+
|
117
|
+
const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
|
118
|
+
let longest = 0;
|
119
|
+
for (let j = 0; j < decomp.length; j++) {
|
120
|
+
longest = Math.max(longest, noAnsi(decomp[j]).length);
|
44
121
|
}
|
45
|
-
|
122
|
+
|
123
|
+
const middle = Math.floor(decomp.length / 2);
|
124
|
+
decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
|
125
|
+
|
126
|
+
console.log('\x1B[90m...\x1B[0m');
|
127
|
+
console.log(decomp.join('\n'));
|
128
|
+
console.log('\x1B[90m...\x1B[0m\n');
|
129
|
+
|
130
|
+
throw e;
|
131
|
+
}
|
46
132
|
|
47
133
|
times.push(performance.now() - t2);
|
48
134
|
if (flags.includes('info')) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
@@ -95,6 +181,13 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
95
181
|
return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
96
182
|
}
|
97
183
|
|
184
|
+
case '_bytestring': {
|
185
|
+
const pointer = ret;
|
186
|
+
const length = new Int32Array(memory.buffer, pointer, 1);
|
187
|
+
|
188
|
+
return Array.from(new Uint8Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
189
|
+
}
|
190
|
+
|
98
191
|
case 'function': {
|
99
192
|
// wasm func index, including all imports
|
100
193
|
const func = funcs.find(x => (x.originalIndex ?? x.index) === ret);
|
package/package.json
CHANGED
package/node_trace.1.log
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"traceEvents":[{"pid":13264,"tid":15096,"ts":95423117674,"tts":0,"ph":"X","cat":"v8","name":"V8.DeserializeIsolate","dur":4531,"tdur":0,"args":{}},{"pid":13264,"tid":15096,"ts":95423122578,"tts":0,"ph":"X","cat":"v8","name":"V8.DeserializeContext","dur":3271,"tdur":0,"args":{}},{"pid":13264,"tid":15096,"ts":95423130539,"tts":0,"ph":"X","cat":"v8","name":"V8.DeserializeContext","dur":346,"tdur":0,"args":{}},{"pid":13264,"tid":15096,"ts":95423152512,"tts":0,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":4996680,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423152519,"tts":0,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":431,"tdur":0,"args":{}},{"pid":13264,"tid":15096,"ts":95423152969,"tts":0,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":4389296}},{"pid":13264,"tid":15096,"ts":95423160029,"tts":0,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":4924936,"type":"task"}},{"pid":13264,"tid":15096,"ts":95423160032,"tts":0,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":324,"tdur":0,"args":{}},{"pid":13264,"tid":15096,"ts":95423160367,"tts":0,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":4440256}},{"pid":13264,"tid":15096,"ts":95423175256,"tts":67346,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":6472768,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423175267,"tts":67356,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":299,"tdur":300,"args":{}},{"pid":13264,"tid":15096,"ts":95423175578,"tts":67667,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":5881080}},{"pid":13264,"tid":15096,"ts":95423188220,"tts":80241,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":6928320,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423188222,"tts":80243,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":363,"tdur":362,"args":{}},{"pid":13264,"tid":15096,"ts":95423188596,"tts":80616,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":6372328}},{"pid":13264,"tid":15096,"ts":95423191843,"tts":83862,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":8430312,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423191845,"tts":83864,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":258,"tdur":239,"args":{}},{"pid":13264,"tid":15096,"ts":95423192113,"tts":84113,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":6741768}},{"pid":13264,"tid":15096,"ts":95423199261,"tts":91198,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":8882104,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423199264,"tts":91200,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":256,"tdur":220,"args":{}},{"pid":13264,"tid":15096,"ts":95423199530,"tts":91430,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":6991296}},{"pid":13264,"tid":15096,"ts":95423203033,"tts":94931,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":9582528,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423203035,"tts":94933,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":147,"tdur":128,"args":{}},{"pid":13264,"tid":15096,"ts":95423203191,"tts":95069,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":7206184}},{"pid":13264,"tid":15096,"ts":95423207062,"tts":98940,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":10032360,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423207063,"tts":98941,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":98,"tdur":98,"args":{}},{"pid":13264,"tid":15096,"ts":95423207169,"tts":99046,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":7617064}},{"pid":13264,"tid":15096,"ts":95423210148,"tts":102008,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":10442184,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95423210149,"tts":102009,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":83,"tdur":82,"args":{}},{"pid":13264,"tid":15096,"ts":95423210241,"tts":102101,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":7743728}},{"pid":13264,"tid":15096,"ts":95598120854,"tts":172740055,"ph":"B","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":10650144,"type":"allocation failure"}},{"pid":13264,"tid":15096,"ts":95598120861,"tts":172740060,"ph":"X","cat":"v8","name":"V8.GCScavenger","dur":188,"tdur":189,"args":{}},{"pid":13264,"tid":15096,"ts":95598121065,"tts":172740264,"ph":"E","cat":"devtools.timeline,v8","name":"MinorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":8016624}},{"pid":13264,"tid":15096,"ts":95707243189,"tts":280108308,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":20,"tdur":19,"args":{}},{"pid":13264,"tid":15096,"ts":95707243201,"tts":280108319,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":8,"tdur":8,"args":{}},{"pid":13264,"tid":15096,"ts":95707244259,"tts":280109369,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":10,"tdur":8,"args":{}},{"pid":13264,"tid":15096,"ts":95707244265,"tts":280109374,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":3,"tdur":3,"args":{}},{"pid":13264,"tid":15096,"ts":95707244376,"tts":280109452,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":9,"tdur":8,"args":{}},{"pid":13264,"tid":15096,"ts":95707244381,"tts":280109456,"ph":"X","cat":"v8","name":"V8.DeoptimizeCode","dur":3,"tdur":4,"args":{}},{"pid":13264,"tid":15096,"ts":95707245192,"tts":280110267,"ph":"X","cat":"v8","name":"V8.GCIncrementalMarkingStart","dur":214,"tdur":214,"args":{"epoch":11,"reason":"memory reducer"}},{"pid":13264,"tid":15096,"ts":95707245464,"tts":280110540,"ph":"X","cat":"v8","name":"V8.GCIncrementalMarking","dur":7,"tdur":6,"args":{"epoch":11}},{"pid":13264,"tid":15096,"ts":95707245559,"tts":280110634,"ph":"B","cat":"devtools.timeline,v8","name":"MajorGC","dur":0,"tdur":0,"args":{"usedHeapSizeBefore":8366408,"type":"external finalize"}},{"pid":13264,"tid":15096,"ts":95707245561,"tts":280110635,"ph":"X","cat":"v8","name":"V8.GCFinalizeMCReduceMemory","dur":1914,"tdur":1617,"args":{}},{"pid":13264,"tid":15096,"ts":95707247497,"tts":280112273,"ph":"E","cat":"devtools.timeline,v8","name":"MajorGC","dur":0,"tdur":0,"args":{"usedHeapSizeAfter":6173808}},{"pid":13264,"tid":15096,"ts":95423116966,"tts":0,"ph":"M","cat":"__metadata","name":"process_name","dur":0,"tdur":0,"args":{"name":"Command Prompt - node --trace-event-categories v8 runner/index.js bench/bf.js"}},{"pid":13264,"tid":15096,"ts":95423116967,"tts":0,"ph":"M","cat":"__metadata","name":"version","dur":0,"tdur":0,"args":{"node":"21.6.0"}},{"pid":13264,"tid":15096,"ts":95423116968,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"JavaScriptMainThread"}},{"pid":13264,"tid":15096,"ts":95423116978,"tts":0,"ph":"M","cat":"__metadata","name":"node","dur":0,"tdur":0,"args":{"process":{"versions":{"node":"21.6.0","v8":"11.8.172.17-node.19","uv":"1.47.0","zlib":"1.3.0.1-motley-40e35a7","brotli":"1.1.0","ares":"1.20.1","modules":"120","nghttp2":"1.58.0","napi":"9","llhttp":"9.1.3","uvwasi":"0.0.19","acorn":"8.11.3","simdjson":"3.6.3","simdutf":"4.0.8","ada":"2.7.4","undici":"5.28.2","cjs_module_lexer":"1.2.2","base64":"0.5.1","openssl":"3.0.12+quic","cldr":"44.0","icu":"74.1","tz":"2023c","unicode":"15.1","ngtcp2":"0.8.1","nghttp3":"0.7.0"},"arch":"x64","platform":"win32","release":{"name":"node"}}}},{"pid":13264,"tid":9152,"ts":95423117058,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"WorkerThreadsTaskRunner::DelayedTaskScheduler"}},{"pid":13264,"tid":12304,"ts":95423117145,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":11816,"ts":95423117184,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":5044,"ts":95423117206,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":4032,"ts":95423117236,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":15096,"ts":95423116966,"tts":0,"ph":"M","cat":"__metadata","name":"process_name","dur":0,"tdur":0,"args":{"name":"Command Prompt - node --trace-event-categories v8 runner/index.js bench/bf.js"}},{"pid":13264,"tid":15096,"ts":95423116967,"tts":0,"ph":"M","cat":"__metadata","name":"version","dur":0,"tdur":0,"args":{"node":"21.6.0"}},{"pid":13264,"tid":15096,"ts":95423116968,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"JavaScriptMainThread"}},{"pid":13264,"tid":15096,"ts":95423116978,"tts":0,"ph":"M","cat":"__metadata","name":"node","dur":0,"tdur":0,"args":{"process":{"versions":{"node":"21.6.0","v8":"11.8.172.17-node.19","uv":"1.47.0","zlib":"1.3.0.1-motley-40e35a7","brotli":"1.1.0","ares":"1.20.1","modules":"120","nghttp2":"1.58.0","napi":"9","llhttp":"9.1.3","uvwasi":"0.0.19","acorn":"8.11.3","simdjson":"3.6.3","simdutf":"4.0.8","ada":"2.7.4","undici":"5.28.2","cjs_module_lexer":"1.2.2","base64":"0.5.1","openssl":"3.0.12+quic","cldr":"44.0","icu":"74.1","tz":"2023c","unicode":"15.1","ngtcp2":"0.8.1","nghttp3":"0.7.0"},"arch":"x64","platform":"win32","release":{"name":"node"}}}},{"pid":13264,"tid":9152,"ts":95423117058,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"WorkerThreadsTaskRunner::DelayedTaskScheduler"}},{"pid":13264,"tid":12304,"ts":95423117145,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":11816,"ts":95423117184,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":5044,"ts":95423117206,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}},{"pid":13264,"tid":4032,"ts":95423117236,"tts":0,"ph":"M","cat":"__metadata","name":"thread_name","dur":0,"tdur":0,"args":{"name":"PlatformWorkerThread"}}]}
|