feat(native): add support for win arm64 unwind codes#978
Conversation
|
08f62b8 to
614ab8b
Compare
loewenheim
left a comment
There was a problem hiding this comment.
Very impressive! I basically only have some stylistic nits.
| writer: &'a mut dyn Write, | ||
| } | ||
|
|
||
| // The kinds of registers the can be saved for unwinding. |
There was a problem hiding this comment.
| // The kinds of registers the can be saved for unwinding. | |
| // The kinds of registers that can be saved for unwinding. |
| } | ||
| } | ||
|
|
||
| // Computes the memory location relative to CFI, offset above SP |
There was a problem hiding this comment.
These could all be doc comments.
| // Computes the memory location relative to CFI, offset above SP | |
| /// Computes the memory location relative to CFI, offset above SP |
| " .{typ}{first_reg}: .cfa {} + ^ .{typ}{second_reg}: .cfa {} + ^", | ||
| o1, o2 |
There was a problem hiding this comment.
| " .{typ}{first_reg}: .cfa {} + ^ .{typ}{second_reg}: .cfa {} + ^", | |
| o1, o2 | |
| " .{typ}{first_reg}: .cfa {o1} + ^ .{typ}{second_reg}: .cfa {o2} + ^" |
| " .x{reg}: .cfa {} + ^ .lr: .cfa {} + ^", | ||
| o1, o2 |
There was a problem hiding this comment.
| " .x{reg}: .cfa {} + ^ .lr: .cfa {} + ^", | |
| o1, o2 | |
| " .x{reg}: .cfa {o1} + ^ .lr: .cfa {o2} + ^" |
| let second_reg = first_reg + 1; | ||
|
|
||
| self.last_reg_kind = typ; | ||
| self.last_reg_num = first_reg + 1; |
There was a problem hiding this comment.
| self.last_reg_num = first_reg + 1; | |
| self.last_reg_num = second_reg; |
| if matches!(code.code, Arm64UnwindCode::End) | ||
| || matches!(code.code, Arm64UnwindCode::EndC) |
There was a problem hiding this comment.
| if matches!(code.code, Arm64UnwindCode::End) | |
| || matches!(code.code, Arm64UnwindCode::EndC) | |
| if matches!(code.code, Arm64UnwindCode::End | Arm64UnwindCode::EndC) |
There was a problem hiding this comment.
I did not know this form! So much nicer :)
| function.function_length(), | ||
| ); | ||
|
|
||
| for (instruction_num, code) in unwind_codes.iter().rev().enumerate() { |
There was a problem hiding this comment.
What is the reason for the rev? Are codes just generally returned in reverse order?
There was a problem hiding this comment.
They're actually stored in reverse order; I think the idea is that, because codes are in 1:1 with the instruction prolog instructions, if you crash in the prolog, a native stalk-unwinder could jump to the correct unwind code based on the crashed PC, and then just walk forward, executing unwind codes, undoing all the work the prolog did, until it encounters the "end" code.
| Arm64UnwindCode::AllocSmall { size_bytes } => { | ||
| enc.alloc_stack(size_bytes)?; | ||
| } | ||
|
|
||
| Arm64UnwindCode::AllocMedium { size_bytes } => { | ||
| enc.alloc_stack(size_bytes)?; | ||
| } | ||
|
|
||
| Arm64UnwindCode::AllocLarge { size_bytes } => { | ||
| enc.alloc_stack(size_bytes)?; | ||
| } |
There was a problem hiding this comment.
Could unify these arms:
| Arm64UnwindCode::AllocSmall { size_bytes } => { | |
| enc.alloc_stack(size_bytes)?; | |
| } | |
| Arm64UnwindCode::AllocMedium { size_bytes } => { | |
| enc.alloc_stack(size_bytes)?; | |
| } | |
| Arm64UnwindCode::AllocLarge { size_bytes } => { | |
| enc.alloc_stack(size_bytes)?; | |
| } | |
| Arm64UnwindCode::AllocSmall { size_bytes } | Arm64UnwindCode::AllocMedium { size_bytes } | Arm64UnwindCode::AllocLarge { size_bytes } => { | |
| enc.alloc_stack(size_bytes)?; | |
| } |
| first_reg, | ||
| offset_bytes, | ||
| } => { | ||
| // save pair <x(19+2*#X),lr> at [sp+#Z*8], offset <= 504 |
There was a problem hiding this comment.
Just to make sure (this applies to some of the other branches too): first_reg is already the number 19 + 2 *#X?
There was a problem hiding this comment.
Yeah, goblins did the work for us :)
| if pair { | ||
| if preindexed { | ||
| enc.save_pre_indexed_pair(typ, reg, offset_bytes)?; | ||
| } else { | ||
| enc.save_indexed_pair(typ, reg, offset_bytes)?; | ||
| } | ||
| } else { | ||
| if preindexed { | ||
| enc.save_pre_indexed(typ, reg, offset_bytes)?; | ||
| } else { | ||
| enc.save_indexed(typ, reg, offset_bytes)?; | ||
| } | ||
| } |
There was a problem hiding this comment.
Could match on (pair, preindexed) here instead.
| self.writer, | ||
| " .{typ}{first_reg}: .cfa {} + ^ .{typ}{second_reg}: .cfa {} + ^", | ||
| o1, o2 | ||
| " .{typ}{first_reg}: .cfa {o1} + ^ .{typ}{second_reg}: .cfa {o1} + ^" |
There was a problem hiding this comment.
There is a typo here which causes tests to fail:
| " .{typ}{first_reg}: .cfa {o1} + ^ .{typ}{second_reg}: .cfa {o1} + ^" | |
| " .{typ}{first_reg}: .cfa {o1} + ^ .{typ}{second_reg}: .cfa {o2} + ^" |
49c6031 to
322dbaf
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a6c067b. Configure here.

No description provided.