porffor 0.2.0-c7b7423 → 0.2.0-e562242
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 -10
- package/compiler/2c.js +6 -1
- package/compiler/codeGen.js +239 -139
- package/compiler/encoding.js +2 -116
- package/compiler/index.js +1 -1
- package/compiler/opt.js +23 -2
- package/compiler/parse.js +11 -12
- package/compiler/sections.js +1 -1
- package/compiler/wasmSpec.js +3 -2
- package/compiler/wrap.js +2 -2
- package/node_trace.1.log +1 -0
- package/package.json +1 -1
- package/runner/repl.js +2 -2
- package/tmp.c +0 -69
package/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Porffor <sup><sub>/ˈpɔrfɔr/ *(poor-for)*</sup></sub>
|
2
|
-
A from-scratch experimental **AOT** optimizing JS -> Wasm/C engine/compiler/runtime in JS. Not serious/intended for (real) use. (this is a straight forward, honest readme)<br>
|
2
|
+
A from-scratch experimental **AOT** optimizing JS/TS -> Wasm/C engine/compiler/runtime in JS. Not serious/intended for (real) use. (this is a straight forward, honest readme)<br>
|
3
3
|
Age: ~6 months (very on and off)
|
4
4
|
|
5
5
|
## Design
|
@@ -118,7 +118,7 @@ No particular order and no guarentees, just what could happen soon™
|
|
118
118
|
- Objects
|
119
119
|
- Basic object expressions (eg `{}`, `{ a: 0 }`)
|
120
120
|
- Wasm
|
121
|
-
- *Basic* Wasm engine (interpreter) in
|
121
|
+
- *Basic* Wasm engine (interpreter) in JS
|
122
122
|
- More math operators (`**`, etc)
|
123
123
|
- `do { ... } while (...)`
|
124
124
|
- Rewrite `console.log` to work with strings/arrays
|
@@ -130,7 +130,21 @@ No particular order and no guarentees, just what could happen soon™
|
|
130
130
|
- Rewrite local indexes per func for smallest local header and remove unused idxs
|
131
131
|
- Smarter inline selection (snapshots?)
|
132
132
|
- Remove const ifs (`if (true)`, etc)
|
133
|
-
-
|
133
|
+
- Experiment with byte strings?
|
134
|
+
- Runtime
|
135
|
+
- WASI target
|
136
|
+
- Run precompiled Wasm file if given
|
137
|
+
- Cool proposals
|
138
|
+
- [Optional Chaining Assignment](https://github.com/tc39/proposal-optional-chaining-assignment)
|
139
|
+
- [Modulus and Additional Integer Math](https://github.com/tc39/proposal-integer-and-modulus-math)
|
140
|
+
- [Array Equality](https://github.com/tc39/proposal-array-equality)
|
141
|
+
- [Declarations in Conditionals](https://github.com/tc39/proposal-Declarations-in-Conditionals)
|
142
|
+
- [Seeded Pseudo-Random Numbers](https://github.com/tc39/proposal-seeded-random)
|
143
|
+
- [`do` expressions](https://github.com/tc39/proposal-do-expressions)
|
144
|
+
- [String Trim Characters](https://github.com/Kingwl/proposal-string-trim-characters)
|
145
|
+
- Posts
|
146
|
+
- Type annotations for performance
|
147
|
+
- Inlining investigation
|
134
148
|
|
135
149
|
## Performance
|
136
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.
|
@@ -157,10 +171,12 @@ Mostly for reducing size. I do not really care about compiler perf/time as long
|
|
157
171
|
- Remove unneeded blocks (no `br`s inside)
|
158
172
|
- Remove unused imports
|
159
173
|
- Use data segments for initing arrays/strings
|
174
|
+
- (Likely more not documented yet, todo)
|
160
175
|
|
161
176
|
### Wasm module
|
162
177
|
- Type cache/index (no repeated types)
|
163
178
|
- No main func if empty (and other exports)
|
179
|
+
- No tags if unused/optimized out
|
164
180
|
|
165
181
|
## Test262
|
166
182
|
Porffor can run Test262 via some hacks/transforms which remove unsupported features whilst still doing the same asserts (eg simpler error messages using literals only). It currently passes >10% (see latest commit desc for latest and details). Use `node test262` to test, it will also show a difference of overall results between the last commit and current results.
|
@@ -180,7 +196,7 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
180
196
|
- `wasmSpec.js`: "enums"/info from wasm spec
|
181
197
|
- `wrap.js`: wrapper for compiler which instantiates and produces nice exports
|
182
198
|
|
183
|
-
- `runner`: contains utils for running
|
199
|
+
- `runner`: contains utils for running JS with the compiler
|
184
200
|
- `index.js`: the main file, you probably want to use this
|
185
201
|
- `info.js`: runs with extra info printed
|
186
202
|
- `repl.js`: basic repl (uses `node:repl`)
|
@@ -212,11 +228,14 @@ You can also use Deno (`deno run -A ...` instead of `node ...`), or Bun (`bun ..
|
|
212
228
|
- `-target=native` only:
|
213
229
|
- `-compiler=clang` to set compiler binary (path/name) to use to compile
|
214
230
|
- `-cO=O3` to set compiler opt argument
|
231
|
+
- `-parser=acorn|@babel/parser|meriyah|hermes-parser` (default: `acorn`) to set which parser to use
|
232
|
+
- `-parse-types` to enable parsing type annotations/typescript. if `-parser` is unset, changes default to `@babel/parser`. does not type check
|
233
|
+
- `-opt-types` to perform optimizations using type annotations as compiler hints. does not type check
|
215
234
|
- `-valtype=i32|i64|f64` (default: `f64`) to set valtype
|
216
235
|
- `-O0` to disable opt
|
217
236
|
- `-O1` (default) to enable basic opt (simplify insts, treeshake wasm imports)
|
218
|
-
- `-O2` to enable advanced opt (inlining)
|
219
|
-
- `-O3` to enable advanceder opt (precompute const math)
|
237
|
+
- `-O2` to enable advanced opt (inlining). unstable
|
238
|
+
- `-O3` to enable advanceder opt (precompute const math). unstable
|
220
239
|
- `-no-run` to not run wasm output, just compile
|
221
240
|
- `-opt-log` to log some opts
|
222
241
|
- `-code-log` to log some codegen (you probably want `-funcs`)
|
@@ -230,20 +249,20 @@ You can also use Deno (`deno run -A ...` instead of `node ...`), or Bun (`bun ..
|
|
230
249
|
- `-compile-hints` to enable V8 compilation hints (experimental + doesn't seem to do much?)
|
231
250
|
|
232
251
|
## VSCode extension
|
233
|
-
There is a vscode extension in `porffor-for-vscode` which tweaks
|
252
|
+
There is a vscode extension in `porffor-for-vscode` which tweaks JS syntax highlighting to be nicer with porffor features (eg highlighting wasm inside of inline asm).
|
234
253
|
|
235
254
|
## Isn't this the same as AssemblyScript/other Wasm langs?
|
236
255
|
No. they are not alike at all internally and have very different goals/ideals:
|
237
256
|
- Porffor is made as a generic JS engine, not for Wasm stuff specifically
|
238
|
-
- Porffor
|
239
|
-
- Porffor is
|
257
|
+
- Porffor primarily consumes JS
|
258
|
+
- Porffor is written in pure JS and compiles itself, not using Binaryen/etc
|
240
259
|
- (Also I didn't know it existed when I started this, lol)
|
241
260
|
|
242
261
|
## FAQ
|
243
262
|
|
244
263
|
### 1. Why the name?
|
245
264
|
`purple` in Welsh is `porffor`. Why purple?
|
246
|
-
- No other
|
265
|
+
- No other JS engine is purple colored
|
247
266
|
- Purple is pretty cool
|
248
267
|
- Purple apparently represents "ambition", which is.. one word to describe this project
|
249
268
|
- The hard to speak name is also the noise your brain makes in reaction to this idea!
|
package/compiler/2c.js
CHANGED
@@ -124,7 +124,7 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
124
124
|
const returns = f.returns.length > 0;
|
125
125
|
|
126
126
|
const shouldInline = f.internal;
|
127
|
-
out += `${f.name === 'main' ? 'int' : (f.internal ? 'double' : 'struct ReturnValue')} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
|
127
|
+
out += `${f.name === 'main' ? 'int' : (f.internal ? (returns ? 'double' : 'void') : 'struct ReturnValue')} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
|
128
128
|
|
129
129
|
const localKeys = Object.keys(f.locals).sort((a, b) => f.locals[a].idx - f.locals[b].idx).slice(f.params.length).sort((a, b) => f.locals[a].idx - f.locals[b].idx);
|
130
130
|
for (const x of localKeys) {
|
@@ -367,6 +367,11 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
367
367
|
line(`return ${vals.pop()}`);
|
368
368
|
}
|
369
369
|
|
370
|
+
if (f.name === 'main') {
|
371
|
+
out += '\n';
|
372
|
+
line(`return 0`);
|
373
|
+
}
|
374
|
+
|
370
375
|
out += '}\n\n';
|
371
376
|
}
|
372
377
|
|
package/compiler/codeGen.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
|
2
|
-
import { ieee754_binary64, signedLEB128, unsignedLEB128 } from "./encoding.js";
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from "./encoding.js";
|
3
3
|
import { operatorOpcode } from "./expression.js";
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./builtins.js";
|
5
5
|
import { PrototypeFuncs } from "./prototype.js";
|
@@ -214,6 +214,11 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
214
214
|
}
|
215
215
|
|
216
216
|
default:
|
217
|
+
if (decl.type.startsWith('TS')) {
|
218
|
+
// ignore typescript nodes
|
219
|
+
return [];
|
220
|
+
}
|
221
|
+
|
217
222
|
return todo(`no generation for ${decl.type}!`);
|
218
223
|
}
|
219
224
|
};
|
@@ -360,12 +365,12 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
360
365
|
...right,
|
361
366
|
// note type
|
362
367
|
...rightType,
|
363
|
-
|
368
|
+
setLastType(scope),
|
364
369
|
[ Opcodes.else ],
|
365
370
|
[ Opcodes.local_get, localTmp(scope, 'logictmpi', Valtype.i32) ],
|
366
371
|
// note type
|
367
372
|
...leftType,
|
368
|
-
|
373
|
+
setLastType(scope),
|
369
374
|
[ Opcodes.end ],
|
370
375
|
Opcodes.i32_from
|
371
376
|
];
|
@@ -379,12 +384,12 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
379
384
|
...right,
|
380
385
|
// note type
|
381
386
|
...rightType,
|
382
|
-
|
387
|
+
setLastType(scope),
|
383
388
|
[ Opcodes.else ],
|
384
389
|
[ Opcodes.local_get, localTmp(scope, 'logictmp') ],
|
385
390
|
// note type
|
386
391
|
...leftType,
|
387
|
-
|
392
|
+
setLastType(scope),
|
388
393
|
[ Opcodes.end ]
|
389
394
|
];
|
390
395
|
};
|
@@ -852,7 +857,16 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
852
857
|
|
853
858
|
let tmpLeft, tmpRight;
|
854
859
|
// if equal op, check if strings for compareStrings
|
855
|
-
if (op === '===' || op === '==' || op === '!==' || op === '!=') {
|
860
|
+
if (op === '===' || op === '==' || op === '!==' || op === '!=') (() => {
|
861
|
+
const knownLeft = knownType(scope, leftType);
|
862
|
+
const knownRight = knownType(scope, rightType);
|
863
|
+
|
864
|
+
// todo: intelligent partial skip later
|
865
|
+
// if neither known are string, stop this madness
|
866
|
+
if ((knownLeft != null && knownLeft !== TYPES.string) && (knownRight != null && knownRight !== TYPES.string)) {
|
867
|
+
return;
|
868
|
+
}
|
869
|
+
|
856
870
|
tmpLeft = localTmp(scope, '__tmpop_left');
|
857
871
|
tmpRight = localTmp(scope, '__tmpop_right');
|
858
872
|
|
@@ -902,7 +916,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
902
916
|
// endOut.push(stringOnly([ Opcodes.end ]));
|
903
917
|
endOut.unshift(stringOnly([ Opcodes.end ]));
|
904
918
|
// }
|
905
|
-
}
|
919
|
+
})();
|
906
920
|
|
907
921
|
return finalise([
|
908
922
|
...left,
|
@@ -1051,11 +1065,13 @@ const setType = (scope, _name, type) => {
|
|
1051
1065
|
|
1052
1066
|
const out = typeof type === 'number' ? number(type, Valtype.i32) : type;
|
1053
1067
|
|
1068
|
+
if (typedInput && scope.locals[name]?.metadata?.type != null) return [];
|
1054
1069
|
if (scope.locals[name]) return [
|
1055
1070
|
...out,
|
1056
1071
|
[ Opcodes.local_set, scope.locals[name + '#type'].idx ]
|
1057
1072
|
];
|
1058
1073
|
|
1074
|
+
if (typedInput && globals[name]?.metadata?.type != null) return [];
|
1059
1075
|
if (globals[name]) return [
|
1060
1076
|
...out,
|
1061
1077
|
[ Opcodes.global_set, globals[name + '#type'].idx ]
|
@@ -1064,6 +1080,15 @@ const setType = (scope, _name, type) => {
|
|
1064
1080
|
// throw new Error('could not find var');
|
1065
1081
|
};
|
1066
1082
|
|
1083
|
+
const getLastType = scope => {
|
1084
|
+
scope.gotLastType = true;
|
1085
|
+
return [ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ];
|
1086
|
+
};
|
1087
|
+
|
1088
|
+
const setLastType = scope => {
|
1089
|
+
return [ Opcodes.local_set, localTmp(scope, '#last_type', Valtype.i32) ];
|
1090
|
+
};
|
1091
|
+
|
1067
1092
|
const getNodeType = (scope, node) => {
|
1068
1093
|
const inner = () => {
|
1069
1094
|
if (node.type === 'Literal') {
|
@@ -1092,7 +1117,19 @@ const getNodeType = (scope, node) => {
|
|
1092
1117
|
if (builtinFuncs[name]) return TYPES[builtinFuncs[name].returnType ?? 'number'];
|
1093
1118
|
if (internalConstrs[name]) return internalConstrs[name].type;
|
1094
1119
|
|
1095
|
-
|
1120
|
+
// check if this is a prototype function
|
1121
|
+
// if so and there is only one impl (eg charCodeAt)
|
1122
|
+
// use that return type as that is the only possibility
|
1123
|
+
// (if non-matching type it would error out)
|
1124
|
+
if (name.startsWith('__')) {
|
1125
|
+
const spl = name.slice(2).split('_');
|
1126
|
+
|
1127
|
+
const func = spl[spl.length - 1];
|
1128
|
+
const protoFuncs = Object.values(prototypeFuncs).filter(x => x[func] != null);
|
1129
|
+
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1096
1133
|
|
1097
1134
|
// presume
|
1098
1135
|
// todo: warn here?
|
@@ -1177,7 +1214,7 @@ const getNodeType = (scope, node) => {
|
|
1177
1214
|
return TYPES.number;
|
1178
1215
|
}
|
1179
1216
|
|
1180
|
-
if (scope.locals['#last_type']) return [
|
1217
|
+
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1181
1218
|
|
1182
1219
|
// presume
|
1183
1220
|
// todo: warn here?
|
@@ -1190,6 +1227,23 @@ const getNodeType = (scope, node) => {
|
|
1190
1227
|
return ret;
|
1191
1228
|
};
|
1192
1229
|
|
1230
|
+
const toString = (scope, wasm, type) => {
|
1231
|
+
const tmp = localTmp(scope, '#tostring_tmp');
|
1232
|
+
return [
|
1233
|
+
...wasm,
|
1234
|
+
[ Opcodes.local_set, tmp ],
|
1235
|
+
|
1236
|
+
...typeSwitch(scope, type, {
|
1237
|
+
[TYPES.string]: [
|
1238
|
+
[ Opcodes.local_get, tmp ]
|
1239
|
+
],
|
1240
|
+
[TYPES.undefined]: [
|
1241
|
+
// [ Opcodes.]
|
1242
|
+
]
|
1243
|
+
})
|
1244
|
+
]
|
1245
|
+
};
|
1246
|
+
|
1193
1247
|
const generateLiteral = (scope, decl, global, name) => {
|
1194
1248
|
if (decl.value === null) return number(NULL);
|
1195
1249
|
|
@@ -1356,13 +1410,13 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1356
1410
|
const finalStatement = parsed.body[parsed.body.length - 1];
|
1357
1411
|
out.push(
|
1358
1412
|
...getNodeType(scope, finalStatement),
|
1359
|
-
|
1413
|
+
setLastType(scope)
|
1360
1414
|
);
|
1361
1415
|
} else if (countLeftover(out) === 0) {
|
1362
1416
|
out.push(...number(UNDEFINED));
|
1363
1417
|
out.push(
|
1364
1418
|
...number(TYPES.undefined, Valtype.i32),
|
1365
|
-
|
1419
|
+
setLastType(scope)
|
1366
1420
|
);
|
1367
1421
|
}
|
1368
1422
|
|
@@ -1380,8 +1434,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1380
1434
|
if (name && name.startsWith('__')) {
|
1381
1435
|
const spl = name.slice(2).split('_');
|
1382
1436
|
|
1383
|
-
|
1384
|
-
protoName = func;
|
1437
|
+
protoName = spl[spl.length - 1];
|
1385
1438
|
|
1386
1439
|
target = { ...decl.callee };
|
1387
1440
|
target.name = spl.slice(0, -1).join('_');
|
@@ -1407,12 +1460,11 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1407
1460
|
Opcodes.i32_from_u,
|
1408
1461
|
|
1409
1462
|
...number(TYPES.boolean, Valtype.i32),
|
1410
|
-
|
1463
|
+
setLastType(scope)
|
1411
1464
|
];
|
1412
1465
|
}
|
1413
1466
|
|
1414
|
-
|
1415
|
-
protoName = func;
|
1467
|
+
protoName = decl.callee.property.name;
|
1416
1468
|
|
1417
1469
|
target = decl.callee.object;
|
1418
1470
|
}
|
@@ -1457,7 +1509,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1457
1509
|
...RTArrayUtil.getLength(getPointer),
|
1458
1510
|
|
1459
1511
|
...number(TYPES.number, Valtype.i32),
|
1460
|
-
|
1512
|
+
setLastType(scope)
|
1461
1513
|
];
|
1462
1514
|
continue;
|
1463
1515
|
}
|
@@ -1488,7 +1540,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1488
1540
|
...protoOut,
|
1489
1541
|
|
1490
1542
|
...number(protoFunc.returnType ?? TYPES.number, Valtype.i32),
|
1491
|
-
|
1543
|
+
setLastType(scope),
|
1492
1544
|
[ Opcodes.end ]
|
1493
1545
|
];
|
1494
1546
|
}
|
@@ -1589,7 +1641,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1589
1641
|
// ...number(type, Valtype.i32),
|
1590
1642
|
// [ Opcodes.local_set, localTmp(scope, '#last_type', Valtype.i32) ]
|
1591
1643
|
// );
|
1592
|
-
} else out.push(
|
1644
|
+
} else out.push(setLastType(scope));
|
1593
1645
|
|
1594
1646
|
return out;
|
1595
1647
|
};
|
@@ -1614,9 +1666,116 @@ const unhackName = name => {
|
|
1614
1666
|
return name;
|
1615
1667
|
};
|
1616
1668
|
|
1669
|
+
const knownType = (scope, type) => {
|
1670
|
+
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
1671
|
+
return type[0][1];
|
1672
|
+
}
|
1673
|
+
|
1674
|
+
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
1675
|
+
const idx = type[0][1];
|
1676
|
+
|
1677
|
+
// type idx = var idx + 1
|
1678
|
+
const v = Object.values(scope.locals).find(x => x.idx === idx - 1);
|
1679
|
+
if (v.metadata?.type != null) return v.metadata.type;
|
1680
|
+
}
|
1681
|
+
|
1682
|
+
return null;
|
1683
|
+
};
|
1684
|
+
|
1685
|
+
const brTable = (input, bc, returns) => {
|
1686
|
+
const out = [];
|
1687
|
+
const keys = Object.keys(bc);
|
1688
|
+
const count = keys.length;
|
1689
|
+
|
1690
|
+
if (count === 1) {
|
1691
|
+
// return [
|
1692
|
+
// ...input,
|
1693
|
+
// ...bc[keys[0]]
|
1694
|
+
// ];
|
1695
|
+
return bc[keys[0]];
|
1696
|
+
}
|
1697
|
+
|
1698
|
+
if (count === 2) {
|
1699
|
+
// just use if else
|
1700
|
+
const other = keys.find(x => x !== 'default');
|
1701
|
+
return [
|
1702
|
+
...input,
|
1703
|
+
...number(other, Valtype.i32),
|
1704
|
+
[ Opcodes.i32_eq ],
|
1705
|
+
[ Opcodes.if, returns ],
|
1706
|
+
...bc[other],
|
1707
|
+
[ Opcodes.else ],
|
1708
|
+
...bc.default,
|
1709
|
+
[ Opcodes.end ]
|
1710
|
+
];
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
for (let i = 0; i < count; i++) {
|
1714
|
+
if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
|
1715
|
+
else out.push([ Opcodes.block, Blocktype.void ]);
|
1716
|
+
}
|
1717
|
+
|
1718
|
+
const nums = keys.filter(x => +x);
|
1719
|
+
const offset = Math.min(...nums);
|
1720
|
+
const max = Math.max(...nums);
|
1721
|
+
|
1722
|
+
const table = [];
|
1723
|
+
let br = 1;
|
1724
|
+
|
1725
|
+
for (let i = offset; i <= max; i++) {
|
1726
|
+
// if branch for this num, go to that block
|
1727
|
+
if (bc[i]) {
|
1728
|
+
table.push(br);
|
1729
|
+
br++;
|
1730
|
+
continue;
|
1731
|
+
}
|
1732
|
+
|
1733
|
+
// else default
|
1734
|
+
table.push(0);
|
1735
|
+
}
|
1736
|
+
|
1737
|
+
out.push(
|
1738
|
+
[ Opcodes.block, Blocktype.void ],
|
1739
|
+
...input,
|
1740
|
+
...(offset > 0 ? [
|
1741
|
+
...number(offset, Valtype.i32),
|
1742
|
+
[ Opcodes.i32_sub ]
|
1743
|
+
] : []),
|
1744
|
+
[ Opcodes.br_table, ...encodeVector(table), 0 ]
|
1745
|
+
);
|
1746
|
+
|
1747
|
+
// if you can guess why we sort the wrong way and then reverse
|
1748
|
+
// (instead of just sorting the correct way)
|
1749
|
+
// dm me and if you are correct and the first person
|
1750
|
+
// I will somehow shout you out or something
|
1751
|
+
const orderedBc = keys.sort((a, b) => b - a).reverse();
|
1752
|
+
|
1753
|
+
br = count - 1;
|
1754
|
+
for (const x of orderedBc) {
|
1755
|
+
out.push(
|
1756
|
+
[ Opcodes.end ],
|
1757
|
+
...bc[x],
|
1758
|
+
...(br === 0 ? [] : [ [ Opcodes.br, br ] ])
|
1759
|
+
);
|
1760
|
+
br--;
|
1761
|
+
}
|
1762
|
+
|
1763
|
+
return [
|
1764
|
+
...out,
|
1765
|
+
[ Opcodes.end, 'br table end' ]
|
1766
|
+
];
|
1767
|
+
};
|
1768
|
+
|
1617
1769
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
1618
|
-
const
|
1770
|
+
const known = knownType(scope, type);
|
1771
|
+
if (known != null) {
|
1772
|
+
return bc[known] ?? bc.default;
|
1773
|
+
}
|
1619
1774
|
|
1775
|
+
if (process.argv.includes('-typeswitch-use-brtable'))
|
1776
|
+
return brTable(type, bc, returns);
|
1777
|
+
|
1778
|
+
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
1620
1779
|
const out = [
|
1621
1780
|
...type,
|
1622
1781
|
[ Opcodes.local_set, tmp ],
|
@@ -1668,6 +1827,49 @@ const allocVar = (scope, name, global = false) => {
|
|
1668
1827
|
return idx;
|
1669
1828
|
};
|
1670
1829
|
|
1830
|
+
const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
1831
|
+
const target = global ? globals : scope.locals;
|
1832
|
+
|
1833
|
+
target[name].metadata ??= {};
|
1834
|
+
for (const x in metadata) {
|
1835
|
+
if (metadata[x] != null) target[name].metadata[x] = metadata[x];
|
1836
|
+
}
|
1837
|
+
};
|
1838
|
+
|
1839
|
+
const typeAnnoToPorfType = x => {
|
1840
|
+
if (TYPES[x]) return TYPES[x];
|
1841
|
+
if (TYPES['_' + x]) return TYPES['_' + x];
|
1842
|
+
|
1843
|
+
switch (x) {
|
1844
|
+
case 'i32':
|
1845
|
+
return TYPES.number;
|
1846
|
+
}
|
1847
|
+
|
1848
|
+
return null;
|
1849
|
+
};
|
1850
|
+
|
1851
|
+
const extractTypeAnnotation = decl => {
|
1852
|
+
let a = decl;
|
1853
|
+
while (a.typeAnnotation) a = a.typeAnnotation;
|
1854
|
+
|
1855
|
+
let type, elementType;
|
1856
|
+
if (a.typeName) {
|
1857
|
+
type = a.typeName.name;
|
1858
|
+
} else if (a.type.endsWith('Keyword')) {
|
1859
|
+
type = a.type.slice(2, -7).toLowerCase();
|
1860
|
+
} else if (a.type === 'TSArrayType') {
|
1861
|
+
type = 'array';
|
1862
|
+
elementType = extractTypeAnnotation(a.elementType).type;
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
const typeName = type;
|
1866
|
+
type = typeAnnoToPorfType(type);
|
1867
|
+
|
1868
|
+
// if (decl.name) console.log(decl.name, { type, elementType });
|
1869
|
+
|
1870
|
+
return { type, typeName, elementType };
|
1871
|
+
};
|
1872
|
+
|
1671
1873
|
const generateVar = (scope, decl) => {
|
1672
1874
|
let out = [];
|
1673
1875
|
|
@@ -1695,6 +1897,11 @@ const generateVar = (scope, decl) => {
|
|
1695
1897
|
}
|
1696
1898
|
|
1697
1899
|
let idx = allocVar(scope, name, global);
|
1900
|
+
|
1901
|
+
if (typedInput && x.id.typeAnnotation) {
|
1902
|
+
addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
|
1903
|
+
}
|
1904
|
+
|
1698
1905
|
if (x.init) {
|
1699
1906
|
out = out.concat(generate(scope, x.init, global, name));
|
1700
1907
|
|
@@ -1858,7 +2065,7 @@ const generateAssign = (scope, decl) => {
|
|
1858
2065
|
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
1859
2066
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1860
2067
|
|
1861
|
-
|
2068
|
+
getLastType(scope),
|
1862
2069
|
// hack: type is idx+1
|
1863
2070
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx + 1 ],
|
1864
2071
|
];
|
@@ -2025,7 +2232,7 @@ const generateConditional = (scope, decl) => {
|
|
2025
2232
|
// note type
|
2026
2233
|
out.push(
|
2027
2234
|
...getNodeType(scope, decl.consequent),
|
2028
|
-
|
2235
|
+
setLastType(scope)
|
2029
2236
|
);
|
2030
2237
|
|
2031
2238
|
out.push([ Opcodes.else ]);
|
@@ -2034,7 +2241,7 @@ const generateConditional = (scope, decl) => {
|
|
2034
2241
|
// note type
|
2035
2242
|
out.push(
|
2036
2243
|
...getNodeType(scope, decl.alternate),
|
2037
|
-
|
2244
|
+
setLastType(scope)
|
2038
2245
|
);
|
2039
2246
|
|
2040
2247
|
out.push([ Opcodes.end ]);
|
@@ -2478,7 +2685,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2478
2685
|
|
2479
2686
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2480
2687
|
// hack: this is naughty and will break things!
|
2481
|
-
let newOut = number(0,
|
2688
|
+
let newOut = number(0, valtypeBinary), newPointer = -1;
|
2482
2689
|
if (pages.hasString) {
|
2483
2690
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2484
2691
|
rawElements: new Array(1)
|
@@ -2505,7 +2712,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2505
2712
|
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
2506
2713
|
|
2507
2714
|
...number(TYPES.number, Valtype.i32),
|
2508
|
-
|
2715
|
+
setLastType(scope)
|
2509
2716
|
],
|
2510
2717
|
|
2511
2718
|
[TYPES.string]: [
|
@@ -2537,7 +2744,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2537
2744
|
...number(newPointer),
|
2538
2745
|
|
2539
2746
|
...number(TYPES.string, Valtype.i32),
|
2540
|
-
|
2747
|
+
setLastType(scope)
|
2541
2748
|
],
|
2542
2749
|
|
2543
2750
|
default: [ [ Opcodes.unreachable ] ]
|
@@ -2586,7 +2793,7 @@ const generateFunc = (scope, decl) => {
|
|
2586
2793
|
if (decl.generator) return todo('generator functions are not supported');
|
2587
2794
|
|
2588
2795
|
const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
|
2589
|
-
const params = decl.params
|
2796
|
+
const params = decl.params ?? [];
|
2590
2797
|
|
2591
2798
|
// const innerScope = { ...scope };
|
2592
2799
|
// TODO: share scope/locals between !!!
|
@@ -2600,7 +2807,11 @@ const generateFunc = (scope, decl) => {
|
|
2600
2807
|
};
|
2601
2808
|
|
2602
2809
|
for (let i = 0; i < params.length; i++) {
|
2603
|
-
allocVar(innerScope, params[i], false);
|
2810
|
+
allocVar(innerScope, params[i].name, false);
|
2811
|
+
|
2812
|
+
if (typedInput && params[i].typeAnnotation) {
|
2813
|
+
addVarMetadata(innerScope, params[i].name, false, extractTypeAnnotation(params[i]));
|
2814
|
+
}
|
2604
2815
|
}
|
2605
2816
|
|
2606
2817
|
let body = objectHack(decl.body);
|
@@ -2639,117 +2850,6 @@ const generateFunc = (scope, decl) => {
|
|
2639
2850
|
);
|
2640
2851
|
}
|
2641
2852
|
|
2642
|
-
// change v128 params into many <type> (i32x4 -> i32/etc) instead as unsupported param valtype
|
2643
|
-
let offset = 0, vecParams = 0;
|
2644
|
-
for (let i = 0; i < params.length; i++) {
|
2645
|
-
const name = params[i];
|
2646
|
-
const local = func.locals[name];
|
2647
|
-
if (local.type === Valtype.v128) {
|
2648
|
-
vecParams++;
|
2649
|
-
|
2650
|
-
/* wasm.unshift( // add v128 load for param
|
2651
|
-
[ Opcodes.i32_const, 0 ],
|
2652
|
-
[ ...Opcodes.v128_load, 0, i * 16 ],
|
2653
|
-
[ Opcodes.local_set, local.idx ]
|
2654
|
-
); */
|
2655
|
-
|
2656
|
-
// using params and replace_lane is noticably faster than just loading from memory (above) somehow
|
2657
|
-
|
2658
|
-
// extract valtype and lane count from vec type (i32x4 = i32 4, i8x16 = i8 16, etc)
|
2659
|
-
const { vecType } = local;
|
2660
|
-
let [ type, lanes ] = vecType.split('x');
|
2661
|
-
if (!type || !lanes) throw new Error('bad metadata from vec params'); // sanity check
|
2662
|
-
|
2663
|
-
lanes = parseInt(lanes);
|
2664
|
-
type = Valtype[type];
|
2665
|
-
|
2666
|
-
const name = params[i]; // get original param name
|
2667
|
-
|
2668
|
-
func.params.splice(offset, 1, ...new Array(lanes).fill(type)); // add new params of {type}, {lanes} times
|
2669
|
-
|
2670
|
-
// update index of original local
|
2671
|
-
// delete func.locals[name];
|
2672
|
-
|
2673
|
-
// add new locals for params
|
2674
|
-
for (let j = 0; j < lanes; j++) {
|
2675
|
-
func.locals[name + j] = { idx: offset + j, type, vecParamAutogen: true };
|
2676
|
-
}
|
2677
|
-
|
2678
|
-
// prepend wasm to generate expected v128 locals
|
2679
|
-
wasm.splice(i * 2 + offset * 2, 0,
|
2680
|
-
...i32x4(0, 0, 0, 0),
|
2681
|
-
...new Array(lanes).fill(0).flatMap((_, j) => [
|
2682
|
-
[ Opcodes.local_get, offset + j ],
|
2683
|
-
[ ...Opcodes[vecType + '_replace_lane'], j ]
|
2684
|
-
]),
|
2685
|
-
[ Opcodes.local_set, i ]
|
2686
|
-
);
|
2687
|
-
|
2688
|
-
offset += lanes;
|
2689
|
-
|
2690
|
-
// note: wrapping is disabled for now due to perf/dx concerns (so this will never run)
|
2691
|
-
/* if (!func.name.startsWith('#')) func.name = '##' + func.name;
|
2692
|
-
|
2693
|
-
// add vec type index to hash name prefix for wrapper to know how to wrap
|
2694
|
-
const vecTypeIdx = [ 'i8x16', 'i16x8', 'i32x4', 'i64x2', 'f32x4', 'f64x2' ].indexOf(local.vecType);
|
2695
|
-
const secondHash = func.name.slice(1).indexOf('#');
|
2696
|
-
func.name = '#' + func.name.slice(1, secondHash) + vecTypeIdx + func.name.slice(secondHash); */
|
2697
|
-
}
|
2698
|
-
}
|
2699
|
-
|
2700
|
-
if (offset !== 0) {
|
2701
|
-
// bump local indexes for all other locals after
|
2702
|
-
for (const x in func.locals) {
|
2703
|
-
const local = func.locals[x];
|
2704
|
-
if (!local.vecParamAutogen) local.idx += offset;
|
2705
|
-
}
|
2706
|
-
|
2707
|
-
// bump local indexes in wasm local.get/set
|
2708
|
-
for (let j = 0; j < wasm.length; j++) {
|
2709
|
-
const inst = wasm[j];
|
2710
|
-
if (j < offset * 2 + vecParams * 2) {
|
2711
|
-
if (inst[0] === Opcodes.local_set) inst[1] += offset;
|
2712
|
-
continue;
|
2713
|
-
}
|
2714
|
-
|
2715
|
-
if (inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set) inst[1] += offset;
|
2716
|
-
}
|
2717
|
-
}
|
2718
|
-
|
2719
|
-
// change v128 return into many <type> instead as unsupported return valtype
|
2720
|
-
const lastReturnLocal = wasm.length > 2 && wasm[wasm.length - 1][0] === Opcodes.return && Object.values(func.locals).find(x => x.idx === wasm[wasm.length - 2][1]);
|
2721
|
-
if (lastReturnLocal && lastReturnLocal.type === Valtype.v128) {
|
2722
|
-
const name = Object.keys(func.locals)[Object.values(func.locals).indexOf(lastReturnLocal)];
|
2723
|
-
// extract valtype and lane count from vec type (i32x4 = i32 4, i8x16 = i8 16, etc)
|
2724
|
-
const { vecType } = lastReturnLocal;
|
2725
|
-
let [ type, lanes ] = vecType.split('x');
|
2726
|
-
if (!type || !lanes) throw new Error('bad metadata from vec params'); // sanity check
|
2727
|
-
|
2728
|
-
lanes = parseInt(lanes);
|
2729
|
-
type = Valtype[type];
|
2730
|
-
|
2731
|
-
const vecIdx = lastReturnLocal.idx;
|
2732
|
-
|
2733
|
-
const lastIdx = Math.max(0, ...Object.values(func.locals).map(x => x.idx));
|
2734
|
-
const tmpIdx = [];
|
2735
|
-
for (let i = 0; i < lanes; i++) {
|
2736
|
-
const idx = lastIdx + i + 1;
|
2737
|
-
tmpIdx.push(idx);
|
2738
|
-
func.locals[name + i] = { idx, type, vecReturnAutogen: true };
|
2739
|
-
}
|
2740
|
-
|
2741
|
-
wasm.splice(wasm.length - 1, 1,
|
2742
|
-
...new Array(lanes).fill(0).flatMap((_, i) => [
|
2743
|
-
i === 0 ? null : [ Opcodes.local_get, vecIdx ],
|
2744
|
-
[ ...Opcodes[vecType + '_extract_lane'], i ],
|
2745
|
-
[ Opcodes.local_set, tmpIdx[i] ],
|
2746
|
-
].filter(x => x !== null)),
|
2747
|
-
...new Array(lanes).fill(0).map((_, i) => [ Opcodes.local_get, tmpIdx[i]])
|
2748
|
-
);
|
2749
|
-
|
2750
|
-
func.returns = new Array(lanes).fill(type);
|
2751
|
-
}
|
2752
|
-
|
2753
2853
|
func.wasm = wasm;
|
2754
2854
|
|
2755
2855
|
funcs.push(func);
|
package/compiler/encoding.js
CHANGED
@@ -105,119 +105,5 @@ export const read_unsignedLEB128 = _input => {
|
|
105
105
|
};
|
106
106
|
|
107
107
|
// ieee 754 binary64
|
108
|
-
|
109
|
-
|
110
|
-
// BSD 3-Clause. Copyright 2008 Fair Oaks Labs, Inc. (https://github.com/feross/ieee754/blob/master/LICENSE)
|
111
|
-
export const ieee754_binary64 = value => {
|
112
|
-
return [...new Uint8Array(new Float64Array([ value ]).buffer)];
|
113
|
-
|
114
|
-
let isLE = true, mLen = 52, nBytes = 8, offset = 0;
|
115
|
-
let buffer = new Array(nBytes).fill(0);
|
116
|
-
|
117
|
-
let e, m, c
|
118
|
-
let eLen = (nBytes * 8) - mLen - 1
|
119
|
-
const eMax = (1 << eLen) - 1
|
120
|
-
const eBias = eMax >> 1
|
121
|
-
const rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
|
122
|
-
let i = isLE ? 0 : (nBytes - 1)
|
123
|
-
const d = isLE ? 1 : -1
|
124
|
-
const s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
|
125
|
-
|
126
|
-
value = Math.abs(value)
|
127
|
-
|
128
|
-
if (isNaN(value) || value === Infinity) {
|
129
|
-
m = isNaN(value) ? 1 : 0
|
130
|
-
e = eMax
|
131
|
-
} else {
|
132
|
-
e = Math.floor(Math.log(value) / Math.LN2)
|
133
|
-
if (value * (c = Math.pow(2, -e)) < 1) {
|
134
|
-
e--
|
135
|
-
c *= 2
|
136
|
-
}
|
137
|
-
if (e + eBias >= 1) {
|
138
|
-
value += rt / c
|
139
|
-
} else {
|
140
|
-
value += rt * Math.pow(2, 1 - eBias)
|
141
|
-
}
|
142
|
-
if (value * c >= 2) {
|
143
|
-
e++
|
144
|
-
c /= 2
|
145
|
-
}
|
146
|
-
|
147
|
-
if (e + eBias >= eMax) {
|
148
|
-
m = 0
|
149
|
-
e = eMax
|
150
|
-
} else if (e + eBias >= 1) {
|
151
|
-
m = ((value * c) - 1) * Math.pow(2, mLen)
|
152
|
-
e = e + eBias
|
153
|
-
} else {
|
154
|
-
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
|
155
|
-
e = 0
|
156
|
-
}
|
157
|
-
}
|
158
|
-
|
159
|
-
while (mLen >= 8) {
|
160
|
-
buffer[offset + i] = m & 0xff
|
161
|
-
i += d
|
162
|
-
m /= 256
|
163
|
-
mLen -= 8
|
164
|
-
}
|
165
|
-
|
166
|
-
e = (e << mLen) | m
|
167
|
-
eLen += mLen
|
168
|
-
while (eLen > 0) {
|
169
|
-
buffer[offset + i] = e & 0xff
|
170
|
-
i += d
|
171
|
-
e /= 256
|
172
|
-
eLen -= 8
|
173
|
-
}
|
174
|
-
|
175
|
-
buffer[offset + i - d] |= s * 128
|
176
|
-
|
177
|
-
return buffer;
|
178
|
-
};
|
179
|
-
|
180
|
-
export const read_ieee754_binary64 = buffer => {
|
181
|
-
return new Float64Array(new Uint8Array(buffer).buffer)[0];
|
182
|
-
|
183
|
-
let isLE = true, mLen = 52, nBytes = 8, offset = 0;
|
184
|
-
|
185
|
-
let e, m
|
186
|
-
const eLen = (nBytes * 8) - mLen - 1
|
187
|
-
const eMax = (1 << eLen) - 1
|
188
|
-
const eBias = eMax >> 1
|
189
|
-
let nBits = -7
|
190
|
-
let i = isLE ? (nBytes - 1) : 0
|
191
|
-
const d = isLE ? -1 : 1
|
192
|
-
let s = buffer[offset + i]
|
193
|
-
|
194
|
-
i += d
|
195
|
-
|
196
|
-
e = s & ((1 << (-nBits)) - 1)
|
197
|
-
s >>= (-nBits)
|
198
|
-
nBits += eLen
|
199
|
-
while (nBits > 0) {
|
200
|
-
e = (e * 256) + buffer[offset + i]
|
201
|
-
i += d
|
202
|
-
nBits -= 8
|
203
|
-
}
|
204
|
-
|
205
|
-
m = e & ((1 << (-nBits)) - 1)
|
206
|
-
e >>= (-nBits)
|
207
|
-
nBits += mLen
|
208
|
-
while (nBits > 0) {
|
209
|
-
m = (m * 256) + buffer[offset + i]
|
210
|
-
i += d
|
211
|
-
nBits -= 8
|
212
|
-
}
|
213
|
-
|
214
|
-
if (e === 0) {
|
215
|
-
e = 1 - eBias
|
216
|
-
} else if (e === eMax) {
|
217
|
-
return m ? NaN : ((s ? -1 : 1) * Infinity)
|
218
|
-
} else {
|
219
|
-
m = m + Math.pow(2, mLen)
|
220
|
-
e = e - eBias
|
221
|
-
}
|
222
|
-
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
|
223
|
-
};
|
108
|
+
export const ieee754_binary64 = value => [...new Uint8Array(new Float64Array([ value ]).buffer)];
|
109
|
+
export const read_ieee754_binary64 = buffer => new Float64Array(new Uint8Array(buffer).buffer)[0];
|
package/compiler/index.js
CHANGED
@@ -52,7 +52,7 @@ export default (code, flags) => {
|
|
52
52
|
if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
|
53
53
|
|
54
54
|
const t2 = performance.now();
|
55
|
-
opt(funcs, globals, pages);
|
55
|
+
opt(funcs, globals, pages, tags);
|
56
56
|
if (flags.includes('info')) console.log(`3. optimized code in ${(performance.now() - t2).toFixed(2)}ms`);
|
57
57
|
|
58
58
|
if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
|
package/compiler/opt.js
CHANGED
@@ -11,7 +11,7 @@ const performWasmOp = (op, a, b) => {
|
|
11
11
|
}
|
12
12
|
};
|
13
13
|
|
14
|
-
export default (funcs, globals, pages) => {
|
14
|
+
export default (funcs, globals, pages, tags) => {
|
15
15
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
16
16
|
if (optLevel === 0) return;
|
17
17
|
|
@@ -99,10 +99,14 @@ export default (funcs, globals, pages) => {
|
|
99
99
|
|
100
100
|
if (process.argv.includes('-opt-inline-only')) return;
|
101
101
|
|
102
|
+
const tagUse = tags.reduce((acc, x) => { acc[x.idx] = 0; return acc; }, {});
|
103
|
+
|
102
104
|
// wasm transform pass
|
103
105
|
for (const f of funcs) {
|
104
106
|
const wasm = f.wasm;
|
105
107
|
|
108
|
+
const lastType = f.locals['#last_type'];
|
109
|
+
|
106
110
|
let runs = 2; // how many by default? add arg?
|
107
111
|
while (runs > 0) {
|
108
112
|
runs--;
|
@@ -125,6 +129,8 @@ export default (funcs, globals, pages) => {
|
|
125
129
|
if (inst[0] === Opcodes.local_get) getCount[inst[1]]++;
|
126
130
|
if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) setCount[inst[1]]++;
|
127
131
|
|
132
|
+
if (inst[0] === Opcodes.throw) tagUse[inst[1]]++;
|
133
|
+
|
128
134
|
if (inst[0] === Opcodes.block) {
|
129
135
|
// remove unneeded blocks (no brs inside)
|
130
136
|
// block
|
@@ -141,7 +147,7 @@ export default (funcs, globals, pages) => {
|
|
141
147
|
depth--;
|
142
148
|
if (depth <= 0) break;
|
143
149
|
}
|
144
|
-
if (op === Opcodes.br || op === Opcodes.br_if) {
|
150
|
+
if (op === Opcodes.br || op === Opcodes.br_if || op === Opcodes.br_table) {
|
145
151
|
hasBranch = true;
|
146
152
|
break;
|
147
153
|
}
|
@@ -221,6 +227,7 @@ export default (funcs, globals, pages) => {
|
|
221
227
|
}
|
222
228
|
|
223
229
|
if (checks === 0) {
|
230
|
+
// todo: review indexes below
|
224
231
|
wasm.splice(j - 1, 2, [ Opcodes.drop ]); // remove typeswitch start
|
225
232
|
wasm.splice(i - 1, 1); // remove this inst
|
226
233
|
|
@@ -231,6 +238,13 @@ export default (funcs, globals, pages) => {
|
|
231
238
|
}
|
232
239
|
}
|
233
240
|
|
241
|
+
// remove setting last type if it is never gotten
|
242
|
+
if (!f.gotLastType && inst[0] === Opcodes.local_set && inst[1] === lastType?.idx) {
|
243
|
+
// replace this inst with drop
|
244
|
+
wasm.splice(i, 1, [ Opcodes.drop ]); // remove this and last inst
|
245
|
+
if (i > 0) i--;
|
246
|
+
}
|
247
|
+
|
234
248
|
if (i < 1) continue;
|
235
249
|
let lastInst = wasm[i - 1];
|
236
250
|
|
@@ -531,5 +545,12 @@ export default (funcs, globals, pages) => {
|
|
531
545
|
}
|
532
546
|
}
|
533
547
|
|
548
|
+
for (const x in tagUse) {
|
549
|
+
if (tagUse[x] === 0) {
|
550
|
+
const el = tags.find(y => y.idx === x);
|
551
|
+
tags.splice(tags.indexOf(el), 1);
|
552
|
+
}
|
553
|
+
}
|
554
|
+
|
534
555
|
// return funcs;
|
535
556
|
};
|
package/compiler/parse.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { log } from "./log.js";
|
2
|
+
// import { parse } from 'acorn';
|
2
3
|
|
3
4
|
// deno compat
|
4
5
|
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
@@ -6,16 +7,9 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
|
6
7
|
globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
|
7
8
|
}
|
8
9
|
|
9
|
-
//
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
const loadParser = async () => {
|
14
|
-
parser = process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? 'acorn';
|
15
|
-
0, { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
|
16
|
-
};
|
17
|
-
globalThis._porf_loadParser = loadParser;
|
18
|
-
await loadParser();
|
10
|
+
// should we try to support types (while parsing)
|
11
|
+
const types = process.argv.includes('-parse-types');
|
12
|
+
globalThis.typedInput = types && process.argv.includes('-opt-types');
|
19
13
|
|
20
14
|
// todo: review which to use by default
|
21
15
|
// supported parsers:
|
@@ -24,8 +18,13 @@ await loadParser();
|
|
24
18
|
// - hermes-parser
|
25
19
|
// - @babel/parser
|
26
20
|
|
27
|
-
|
28
|
-
const
|
21
|
+
let parser, parse;
|
22
|
+
const loadParser = async (fallbackParser = 'acorn', forceParser) => {
|
23
|
+
parser = forceParser ?? process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? fallbackParser;
|
24
|
+
0, { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
|
25
|
+
};
|
26
|
+
globalThis._porf_loadParser = loadParser;
|
27
|
+
await loadParser(types ? '@babel/parser' : undefined);
|
29
28
|
|
30
29
|
if (types && !['@babel/parser', 'hermes-parser'].includes(parser)) log.warning('parser', `passed -types with a parser (${parser}) which does not support`);
|
31
30
|
|
package/compiler/sections.js
CHANGED
@@ -150,7 +150,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
150
150
|
|
151
151
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
152
152
|
|
153
|
-
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x <= 0xff), Opcodes.end ]);
|
153
|
+
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x != null && x <= 0xff), Opcodes.end ]);
|
154
154
|
}))
|
155
155
|
);
|
156
156
|
|
package/compiler/wasmSpec.js
CHANGED
@@ -32,8 +32,6 @@ export const Opcodes = {
|
|
32
32
|
throw: 0x08,
|
33
33
|
rethrow: 0x09,
|
34
34
|
|
35
|
-
return: 0x0F,
|
36
|
-
|
37
35
|
call: 0x10,
|
38
36
|
call_indirect: 0x11,
|
39
37
|
return_call: 0x12,
|
@@ -42,7 +40,10 @@ export const Opcodes = {
|
|
42
40
|
end: 0x0b,
|
43
41
|
br: 0x0c,
|
44
42
|
br_if: 0x0d,
|
43
|
+
br_table: 0x0e,
|
44
|
+
return: 0x0f,
|
45
45
|
call: 0x10,
|
46
|
+
|
46
47
|
drop: 0x1a,
|
47
48
|
|
48
49
|
local_get: 0x20,
|
package/compiler/wrap.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import compile from './index.js';
|
2
2
|
import decompile from './decompile.js';
|
3
|
-
|
3
|
+
import fs from 'node:fs';
|
4
4
|
|
5
5
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
6
6
|
|
@@ -29,7 +29,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
29
29
|
|
30
30
|
if (source.includes('export function')) flags.push('module');
|
31
31
|
|
32
|
-
|
32
|
+
fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
33
33
|
|
34
34
|
times.push(performance.now() - t1);
|
35
35
|
if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
package/node_trace.1.log
ADDED
@@ -0,0 +1 @@
|
|
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"}}]}
|
package/package.json
CHANGED
package/runner/repl.js
CHANGED
@@ -45,9 +45,9 @@ let prev = '';
|
|
45
45
|
const run = async (source, _context, _filename, callback, run = true) => {
|
46
46
|
// hack: print "secret" before latest code ran to only enable printing for new code
|
47
47
|
|
48
|
-
let toRun = prev + `;\nprint(-0x1337);\n` + source.trim();
|
48
|
+
let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source.trim();
|
49
49
|
|
50
|
-
let shouldPrint =
|
50
|
+
let shouldPrint = !prev;
|
51
51
|
const { exports, wasm, pages } = await compile(toRun, [], {}, str => {
|
52
52
|
if (shouldPrint) process.stdout.write(str);
|
53
53
|
if (str === '-4919') shouldPrint = true;
|
package/tmp.c
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
|
2
|
-
#include <stdio.h>
|
3
|
-
|
4
|
-
struct ReturnValue {
|
5
|
-
double value;
|
6
|
-
long type;
|
7
|
-
};
|
8
|
-
|
9
|
-
double sum = 0;
|
10
|
-
long sumdtype = 0;
|
11
|
-
double counter = 0;
|
12
|
-
long counterdtype = 0;
|
13
|
-
|
14
|
-
double inline f64_f(double x, double y) {
|
15
|
-
return (x - ((int)(x / y) * y));
|
16
|
-
}
|
17
|
-
|
18
|
-
struct ReturnValue isPrime(double number, long numberdtype) {
|
19
|
-
double i = 0;
|
20
|
-
long idtype = 0;
|
21
|
-
double __tmpop_left = 0;
|
22
|
-
double __tmpop_right = 0;
|
23
|
-
long compare_left_pointer = 0;
|
24
|
-
long compare_left_length = 0;
|
25
|
-
long compare_right_pointer = 0;
|
26
|
-
long compare_right_length = 0;
|
27
|
-
long compare_index = 0;
|
28
|
-
long compare_index_end = 0;
|
29
|
-
|
30
|
-
if (number < 2e+0) {
|
31
|
-
return (struct ReturnValue){ 1, 0e+0 };
|
32
|
-
}
|
33
|
-
i = 2e+0;
|
34
|
-
idtype = 0;
|
35
|
-
while (i < number) {
|
36
|
-
if (f64_f(number, i) == 0e+0) {
|
37
|
-
return (struct ReturnValue){ 1, 0e+0 };
|
38
|
-
}
|
39
|
-
i = i + 1e+0;
|
40
|
-
}
|
41
|
-
return (struct ReturnValue){ 1, 1e+0 };
|
42
|
-
}
|
43
|
-
|
44
|
-
double inline __console_log(double x) {
|
45
|
-
printf("%f\n", x);
|
46
|
-
printf("%c", (int)(1e+1));
|
47
|
-
}
|
48
|
-
|
49
|
-
int main() {
|
50
|
-
long dlast_type = 0;
|
51
|
-
double elogicinner_tmp = 0;
|
52
|
-
long dtypeswitch_tmp = 0;
|
53
|
-
|
54
|
-
sum = 0e+0;
|
55
|
-
sumdtype = 0;
|
56
|
-
counter = 0e+0;
|
57
|
-
counterdtype = 0;
|
58
|
-
while (counter <= 1e+5) {
|
59
|
-
const struct ReturnValue _ = isPrime(counter, counterdtype);
|
60
|
-
dlast_type = _.type;
|
61
|
-
if ((unsigned long)(elogicinner_tmp = _.value) == 1e+0) {
|
62
|
-
sum = sum + counter;
|
63
|
-
sumdtype = 0;
|
64
|
-
}
|
65
|
-
counter = counter + 1e+0;
|
66
|
-
}
|
67
|
-
__console_log(sum);
|
68
|
-
}
|
69
|
-
|