MIRROR: javascript for 🐜's, a tiny runtime with big ambitions
1// Reproduce JIT crash: Array.map callback with string concatenation + upvalues
2// The callback uses OP_ADD on strings (triggers bailout) and OP_GET_UPVAL.
3
4const codes = { reset: '\x1b[0m' };
5
6function createGrid(width, height) {
7 const chars = Array(height).fill(null).map(() => Array(width).fill(' '));
8 const styles = Array(height).fill(null).map(() => Array(width).fill(''));
9 return { chars, styles };
10}
11
12function render() {
13 const width = 20;
14 const height = 10;
15 const grid = createGrid(width, height);
16
17 // Set some styled cells
18 for (let y = 0; y < height; y++) {
19 for (let x = 0; x < width; x++) {
20 if (x === 5) grid.styles[y][x] = '\x1b[32m';
21 }
22 }
23
24 // This .map() callback captures `grid` and `codes` as upvalues,
25 // and does string concatenation (OP_ADD with strings → JIT bailout).
26 const rows = grid.chars.map((row, y) => {
27 let line = '';
28 let currentStyle = '';
29 for (let x = 0; x < row.length; x++) {
30 const nextStyle = grid.styles[y][x];
31 if (nextStyle !== currentStyle) {
32 line += nextStyle || codes.reset;
33 currentStyle = nextStyle;
34 }
35 line += row[x];
36 }
37 return line + codes.reset;
38 });
39
40 return rows.join('\n');
41}
42
43// Call render() enough times to trigger JIT compilation of the .map() callback.
44// With SV_JIT_THRESHOLD=100 and 10 rows per render, ~11 renders should trigger it.
45let result;
46for (let i = 0; i < 20; i++) {
47 result = render();
48}
49
50console.log('OK: JIT map+string concat survived', result.length, 'chars');