// boot_miscompile_bad.cm — Documents a boot compiler miscompilation bug. // // BUG SUMMARY: // The boot compiler's optimizer (likely compress_slots, eliminate_moves, // or infer_param_types) miscompiles a specific pattern when it appears // inside streamline.cm. The pattern: an array-loaded value used as a // dynamic index for another array store, inside a guarded block: // // sv = instr[j] // if (is_number(sv) && sv >= 0 && sv < nr_slots) { // last_ref[sv] = i // <-- miscompiled: sv reads wrong slot // } // // The bug is CONTEXT-DEPENDENT on streamline.cm's exact function/closure // structure. A standalone module with the same pattern does NOT trigger it. // The boot optimizer's cross-function analysis (infer_param_types, type // propagation, etc.) makes different decisions in the full streamline.cm // context, leading to the miscompilation. // // SYMPTOMS: // - 'log' is not defined (comparison error path fires on non-comparable values) // - array index must be a number (store_dynamic with corrupted index) // - Error line has NO reference to 'log' — the reference comes from the // error-reporting code path of the < operator // - Non-deterministic: different error messages on different runs // - NOT a GC bug: persists with --heap 4GB // - NOT slot overflow: function has only 85 raw slots // // TO REPRODUCE: // In streamline.cm, replace the build_slot_liveness function body with // this version (raw operand scanning instead of get_slot_refs): // // var build_slot_liveness = function(instructions, nr_slots) { // var last_ref = array(nr_slots, -1) // var n = length(instructions) // var i = 0 // var j = 0 // var limit = 0 // var sv = 0 // var instr = null // // while (i < n) { // instr = instructions[i] // if (is_array(instr)) { // j = 1 // limit = length(instr) - 2 // while (j < limit) { // sv = instr[j] // if (is_number(sv) && sv >= 0 && sv < nr_slots) { // last_ref[sv] = i // } // j = j + 1 // } // } // i = i + 1 // } // return last_ref // } // // Then: rm -rf .cell/build && ./cell --dev vm_suite // // WORKAROUND: // Use get_slot_refs(instr) to iterate only over known slot-reference // positions. This produces different IR that the boot optimizer handles // correctly, and is also more semantically correct. // // FIXING: // To find the root cause, compare the boot-compiled bytecodes of // build_slot_liveness (in the full streamline.cm context) vs the // source-compiled bytecodes. Use disasm.ce with --optimized to see // what the source compiler produces. The boot-compiled bytecodes // would need a C-level MachCode dump to inspect. return null