fix merge error
This commit is contained in:
74
boot_miscompile_bad.cm
Normal file
74
boot_miscompile_bad.cm
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user