{"record":{"id":"52a5b7e0afe519bf","repo":"ruby/ruby","slug":"destination-register-has-multiple-copies","errorCode":null,"errorMessage":"Destination register {:?} has multiple copies.","messagePattern":"Destination register (.+?) has multiple copies\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"zjit/src/backend/parcopy.rs","lineNumber":64,"sourceCode":"pub fn sequentialize_register<T: PartialEq + Eq + Hash + Ord + std::fmt::Debug + Clone + Copy>(parallel_copies: &[RegisterCopy<T>], spare: T) -> Vec<RegisterCopy<T>> {\n    let mut sequentialized = Vec::new();\n    // `resource` in the original code, this point to the current register\n    // holding a particular initial value.\n    // If a given Register is no longer needed, the value might be inaccurate.\n    let mut current_holder = std::collections::HashMap::new();\n    // Copies that are pending, indexed by destination register.\n    // Use btree map to stay deterministic.\n    let mut pending = std::collections::BTreeMap::new();\n    // If a copy can be materialized (nothing depends on the destination), we\n    // move it from pending into available.\n    let mut available = Vec::new();\n\n    for copy in parallel_copies {\n        if copy.source == spare || copy.destination == spare {\n            panic!(\"Spare register cannot be a source or destination of a copy\");\n        }\n        if let Some(_old_value) = pending.insert(copy.destination, copy) {\n            panic!(\n                \"Destination register {:?} has multiple copies.\",\n                copy.destination\n            );\n        }\n        current_holder.insert(copy.source, copy.source);\n    }\n    for copy in parallel_copies {\n        // If we didn't record it, this means nothing depends on that register.\n        if !current_holder.contains_key(&copy.destination) {\n            pending.remove(&copy.destination);\n            available.push(copy);\n        }\n    }\n    while !pending.is_empty() || !available.is_empty() {\n        while let Some(copy) = available.pop() {\n            if let Some(source) = current_holder.get_mut(&copy.source) {\n                // Materialize the copy.\n                sequentialized.push(RegisterCopy {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/ruby/ruby/blob/0e5b888e1c355f3f728f2659f085820937dada48/zjit/src/backend/parcopy.rs#L46-L82","documentation":"In a parallel copy set every destination register must be written exactly once; two copies into the same destination are ambiguous (which source wins?) and cannot be sequentialized. sequentialize_register() detects this when inserting into the pending map keyed by destination and the insert returns the previous entry, panicking with 'Destination register has multiple copies'.","triggerScenarios":"The register allocator emitting two moves into the same physical register at one block boundary (a live-range split or coalescing bug); hand-built copy lists containing a duplicated destination; block-argument moves duplicated with restore moves.","commonSituations":"Coalescing changes that merge live ranges but leave both moves behind; insertion of an extra restore move for a register that also receives a block-argument move; copy-paste errors when assembling move lists manually.","solutions":["Deduplicate by destination before calling: keep exactly one winning copy per destination register.","Audit allocator move-insertion points (live-range splits, block-argument resolution, restore moves) for double moves into the same register.","Log the copy list when the pre-check finds a duplicate so the offending pass can be identified from the register numbers."],"exampleFix":"// before - two moves target r10 in one parallel set\nlet copies = vec![copy(r1, r10), copy(r2, r10)];\nlet seq = sequentialize_register(&copies, spare); // panics: multiple copies to r10\n\n// after - one copy per destination; the loser is rewritten first\nlet copies = vec![copy(r1, r9), copy(r2, r10)];\nlet seq = sequentialize_register(&copies, spare);","handlingStrategy":"validation","validationCode":"fn unique_destinations(copies: &[RegisterCopy<Reg>]) -> bool {\n    let mut seen = std::collections::HashSet::new();\n    copies.iter().all(|c| seen.insert(c.destination))\n}\nassert!(unique_destinations(&copies),\n    \"each destination must be written exactly once\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate moves by destination before calling sequentialize_register","Audit allocator move-insertion points (splits, coalescing, block arguments) for double moves","Log the copy list on validation failure so the responsible pass is identifiable"],"tags":["jit","register-allocation","parallel-copy","duplicate-destination","panic"],"backgroundTag":"parallel-copy-sequentialization","analyzedSha":"0e5b888e1c355f3f728f2659f085820937dada48","analyzedAt":"2026-08-21T14:25:43.473Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}