···10919109191092010920 loop_block_clear(js, &loop_ctx);
1092110921 v = loop_block_exec(js, &loop_ctx);
1092210922- if (is_err(v)) res = v; break;
1092210922+ if (is_err(v)) { res = v; break; }
10923109231092410924 if (label_flags & F_CONTINUE_LABEL) {
1092510925 if (is_this_loop_continue_target(marker_index)) {
+116
tests/bench_gc.js
···11+// GC Benchmark - tests forwarding table and compaction performance
22+33+function formatBytes(bytes) {
44+ if (bytes < 1024) return bytes + ' B';
55+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
66+ return (bytes / 1024 / 1024).toFixed(2) + ' MB';
77+}
88+99+function bench(name, fn, iterations = 1) {
1010+ // Warmup
1111+ fn();
1212+ Ant.gc();
1313+1414+ let totalTime = 0;
1515+ let totalFreed = 0;
1616+1717+ for (let iter = 0; iter < iterations; iter++) {
1818+ fn(); // Create garbage
1919+2020+ const t0 = Date.now();
2121+ const result = Ant.gc();
2222+ const elapsed = Date.now() - t0;
2323+2424+ totalTime += elapsed;
2525+ totalFreed += result.arenaFreed;
2626+ }
2727+2828+ console.log(`${name}:`);
2929+ console.log(` Time: ${totalTime}ms (${iterations} iterations, avg ${(totalTime / iterations).toFixed(2)}ms)`);
3030+ console.log(` Freed: ${formatBytes(totalFreed)} total`);
3131+ console.log('');
3232+}
3333+3434+// Test 1: Many small objects (stresses forwarding table with many entries)
3535+function manySmallObjects() {
3636+ const objects = [];
3737+ for (let i = 0; i < 1000; i++) {
3838+ objects.push({ id: i, value: i * 2 });
3939+ }
4040+ // Let half become garbage
4141+ objects.length = 5000;
4242+}
4343+4444+// Test 2: Deep object graph (stresses recursive copying)
4545+function deepObjectGraph() {
4646+ let obj = { value: 0 };
4747+ for (let i = 1; i < 1000; i++) {
4848+ obj = { value: i, child: obj };
4949+ }
5050+ return obj;
5151+}
5252+5353+// Test 3: Wide object (many properties)
5454+function wideObject() {
5555+ const obj = {};
5656+ for (let i = 0; i < 1000; i++) {
5757+ obj['prop' + i] = i;
5858+ }
5959+ return obj;
6060+}
6161+6262+// Test 4: Array of strings (tests string copying)
6363+function stringArray() {
6464+ const arr = [];
6565+ for (let i = 0; i < 5000; i++) {
6666+ arr.push('string_value_' + i + '_with_some_extra_content');
6767+ }
6868+ arr.length = 2500; // Half become garbage
6969+}
7070+7171+// Test 5: Mixed workload
7272+function mixedWorkload() {
7373+ const data = {
7474+ objects: [],
7575+ strings: [],
7676+ nested: null
7777+ };
7878+7979+ for (let i = 0; i < 2000; i++) {
8080+ data.objects.push({ x: i, y: i * 2, name: 'obj' + i });
8181+ data.strings.push('item_' + i);
8282+ }
8383+8484+ // Create some nested structure
8585+ let nested = { level: 0 };
8686+ for (let i = 1; i < 100; i++) {
8787+ nested = { level: i, prev: nested, data: { a: i, b: i * 2 } };
8888+ }
8989+ data.nested = nested;
9090+9191+ // Make some garbage
9292+ data.objects.length = 1000;
9393+ data.strings.length = 1000;
9494+}
9595+9696+// Test 6: Repeated GC cycles (tests table reuse efficiency)
9797+function repeatedGcCycles() {
9898+ for (let cycle = 0; cycle < 10; cycle++) {
9999+ const temp = [];
100100+ for (let i = 0; i < 1000; i++) {
101101+ temp.push({ cycle, i, data: 'x'.repeat(50) });
102102+ }
103103+ }
104104+}
105105+106106+console.log('=== GC Benchmark ===\n');
107107+console.log('Initial state:', Ant.alloc(), '\n');
108108+109109+bench('Many small objects (10k objects, 5k garbage)', manySmallObjects, 5);
110110+bench('Deep object graph (1000 levels)', deepObjectGraph, 5);
111111+bench('Wide object (1000 properties)', wideObject, 5);
112112+bench('String array (5000 strings, 2500 garbage)', stringArray, 5);
113113+bench('Mixed workload', mixedWorkload, 5);
114114+bench('Repeated GC cycles (10 cycles x 1000 objects)', repeatedGcCycles, 3);
115115+116116+console.log('Final state:', Ant.alloc());