1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::instruction::{Instruction, OpCode};
use super::super::HighLevelEmitter;
impl HighLevelEmitter {
pub(super) fn try_emit_control_flow(&mut self, instruction: &Instruction) -> bool {
use OpCode::*;
match instruction.opcode {
Ret => self.emit_return(instruction),
Abort => {
self.emit_call(instruction, "abort", 0, false);
self.stack.clear();
}
Assert => self.emit_call(instruction, "assert", 1, false),
Throw => {
self.emit_call(instruction, "throw", 1, false);
self.stack.clear();
}
Abortmsg => {
self.emit_call(instruction, "abort", 1, false);
self.stack.clear();
}
Assertmsg => self.emit_call(instruction, "assert", 2, false),
Syscall => self.emit_syscall(instruction),
Jmp => self.emit_jump(instruction),
Jmp_L => self.emit_jump(instruction),
Jmpif => {
if !self.try_emit_do_while_tail(instruction) {
self.emit_jmpif_block(instruction);
}
}
Jmpif_L => {
if !self.try_emit_do_while_tail(instruction) {
self.emit_jmpif_block(instruction);
}
}
Jmpifnot | Jmpifnot_L => {
if !self.try_emit_do_while_negated_tail(instruction) {
self.emit_if_block(instruction);
}
}
// Comparison jumps branch when the condition is TRUE, so the
// fall-through (if-body) executes when the condition is FALSE.
// We therefore pass the NEGATED operator to emit_comparison_if_block.
// For backward jumps registered as do-while tails, we use the
// ORIGINAL operator since the loop continues while the condition
// is true.
JmpEq | JmpEq_L => {
if !self.try_emit_do_while_comparison_tail(instruction, "==") {
self.emit_comparison_if_block(instruction, "!=");
}
}
JmpNe | JmpNe_L => {
if !self.try_emit_do_while_comparison_tail(instruction, "!=") {
self.emit_comparison_if_block(instruction, "==");
}
}
JmpGt | JmpGt_L => {
if !self.try_emit_do_while_comparison_tail(instruction, ">") {
self.emit_comparison_if_block(instruction, "<=");
}
}
JmpGe | JmpGe_L => {
if !self.try_emit_do_while_comparison_tail(instruction, ">=") {
self.emit_comparison_if_block(instruction, "<");
}
}
JmpLt | JmpLt_L => {
if !self.try_emit_do_while_comparison_tail(instruction, "<") {
self.emit_comparison_if_block(instruction, ">=");
}
}
JmpLe | JmpLe_L => {
if !self.try_emit_do_while_comparison_tail(instruction, "<=") {
self.emit_comparison_if_block(instruction, ">");
}
}
Endtry => self.emit_endtry(instruction),
EndtryL => self.emit_endtry(instruction),
Call => self.emit_relative_call(instruction),
Call_L => self.emit_relative_call(instruction),
CallA => self.emit_indirect_call(instruction, "calla"),
CallT => self.emit_indirect_call(instruction, "callt"),
Try | TryL => self.emit_try_block(instruction),
Endfinally => {
// When ENDFINALLY isn't already absorbed by the
// structured try/finally lift (`skip_jumps` set on
// recognised positions), surface it via the standard
// `// XXXX: ENDFINALLY` opcode-trace comment in
// verbose mode — same convention as every other
// opcode. The previous lowercase `// XXXX: endfinally`
// note clashed with the uppercase mnemonics around it.
if !self.skip_jumps.remove(&instruction.offset) {
self.push_comment(instruction);
}
}
// NOP has no observable effect on the lifted source — only
// surface the standard `// XXXX: NOP` opcode-trace comment
// (gated on emit_trace_comments). The previous `note(...,
// "noop")` produced a lowercase `// XXXX: noop` line that
// visually clashed with all the uppercase mnemonics
// surrounding it.
Nop => self.push_comment(instruction),
_ => return false,
}
true
}
}