xref: /aosp_15_r20/tools/dexter/slicer/control_flow_graph.cc (revision f0dffb02cdb5c647d21204e89a92a1ffae2dad87)
1*f0dffb02SXin Li /*
2*f0dffb02SXin Li  * Copyright (C) 2017 The Android Open Source Project
3*f0dffb02SXin Li  *
4*f0dffb02SXin Li  * Licensed under the Apache License, Version 2.0 (the "License");
5*f0dffb02SXin Li  * you may not use this file except in compliance with the License.
6*f0dffb02SXin Li  * You may obtain a copy of the License at
7*f0dffb02SXin Li  *
8*f0dffb02SXin Li  *      http://www.apache.org/licenses/LICENSE-2.0
9*f0dffb02SXin Li  *
10*f0dffb02SXin Li  * Unless required by applicable law or agreed to in writing, software
11*f0dffb02SXin Li  * distributed under the License is distributed on an "AS IS" BASIS,
12*f0dffb02SXin Li  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f0dffb02SXin Li  * See the License for the specific language governing permissions and
14*f0dffb02SXin Li  * limitations under the License.
15*f0dffb02SXin Li  */
16*f0dffb02SXin Li 
17*f0dffb02SXin Li #include "slicer/control_flow_graph.h"
18*f0dffb02SXin Li 
19*f0dffb02SXin Li namespace lir {
20*f0dffb02SXin Li 
Finish()21*f0dffb02SXin Li std::vector<BasicBlock> BasicBlocksVisitor::Finish() {
22*f0dffb02SXin Li   // the .dex format specification has the following constraint:
23*f0dffb02SXin Li   //
24*f0dffb02SXin Li   //  B17	The last reachable instruction of a method must either be a
25*f0dffb02SXin Li   //  backwards goto or branch, a return, or a throw instruction. It must not
26*f0dffb02SXin Li   //  be possible to leave the insns array at the bottom.	4.8.2.20
27*f0dffb02SXin Li   //
28*f0dffb02SXin Li   // NOTE: this is a very aggressive check though since in the LIR we also
29*f0dffb02SXin Li   //  have labels, annotations, directives, etc. For example it's possible to have
30*f0dffb02SXin Li   //  debug annotations (.line, .endlocal, ...) after the last bytecode.
31*f0dffb02SXin Li   //
32*f0dffb02SXin Li   SLICER_WEAK_CHECK(state_ == State::Outside);
33*f0dffb02SXin Li   SLICER_CHECK(state_ != State::BlockBody);
34*f0dffb02SXin Li   current_block_.region = {};
35*f0dffb02SXin Li   state_ = State::Outside;
36*f0dffb02SXin Li   return std::move(basic_blocks_);
37*f0dffb02SXin Li }
38*f0dffb02SXin Li 
Visit(Bytecode * bytecode)39*f0dffb02SXin Li bool BasicBlocksVisitor::Visit(Bytecode* bytecode) {
40*f0dffb02SXin Li   switch (state_) {
41*f0dffb02SXin Li     case State::Outside:
42*f0dffb02SXin Li       StartBlock(bytecode);
43*f0dffb02SXin Li       state_ = State::BlockBody;
44*f0dffb02SXin Li       break;
45*f0dffb02SXin Li     case State::BlockHeader:
46*f0dffb02SXin Li       state_ = State::BlockBody;
47*f0dffb02SXin Li       break;
48*f0dffb02SXin Li     case State::BlockBody:
49*f0dffb02SXin Li       // inside basic block body, nothing to do.
50*f0dffb02SXin Li       break;
51*f0dffb02SXin Li   }
52*f0dffb02SXin Li 
53*f0dffb02SXin Li   // terminate the current block?
54*f0dffb02SXin Li   bool terminate_block = false;
55*f0dffb02SXin Li   const auto flags = dex::GetFlagsFromOpcode(bytecode->opcode);
56*f0dffb02SXin Li   if (model_exceptions_) {
57*f0dffb02SXin Li     constexpr auto exit_instr_flags =
58*f0dffb02SXin Li         dex::kBranch |
59*f0dffb02SXin Li         dex::kSwitch |
60*f0dffb02SXin Li         dex::kThrow |
61*f0dffb02SXin Li         dex::kReturn;
62*f0dffb02SXin Li     terminate_block = (flags & exit_instr_flags) != 0;
63*f0dffb02SXin Li   } else {
64*f0dffb02SXin Li     constexpr auto exit_instr_flags =
65*f0dffb02SXin Li         dex::kBranch |
66*f0dffb02SXin Li         dex::kSwitch |
67*f0dffb02SXin Li         dex::kReturn;
68*f0dffb02SXin Li     terminate_block = bytecode->opcode == dex::OP_THROW || (flags & exit_instr_flags) != 0;
69*f0dffb02SXin Li   }
70*f0dffb02SXin Li   if (terminate_block) {
71*f0dffb02SXin Li       EndBlock(bytecode);
72*f0dffb02SXin Li   }
73*f0dffb02SXin Li 
74*f0dffb02SXin Li   return true;
75*f0dffb02SXin Li }
76*f0dffb02SXin Li 
Visit(Label * label)77*f0dffb02SXin Li bool BasicBlocksVisitor::Visit(Label* label) {
78*f0dffb02SXin Li   switch (state_) {
79*f0dffb02SXin Li     case State::Outside:
80*f0dffb02SXin Li       StartBlock(label);
81*f0dffb02SXin Li       break;
82*f0dffb02SXin Li     case State::BlockBody:
83*f0dffb02SXin Li       EndBlock(label->prev);
84*f0dffb02SXin Li       StartBlock(label);
85*f0dffb02SXin Li       break;
86*f0dffb02SXin Li     case State::BlockHeader:
87*f0dffb02SXin Li       break;
88*f0dffb02SXin Li   }
89*f0dffb02SXin Li   return true;
90*f0dffb02SXin Li }
91*f0dffb02SXin Li 
HandleAnnotation(Instruction * instr)92*f0dffb02SXin Li bool BasicBlocksVisitor::HandleAnnotation(Instruction* instr) {
93*f0dffb02SXin Li   if (state_ == State::Outside) {
94*f0dffb02SXin Li     StartBlock(instr);
95*f0dffb02SXin Li   }
96*f0dffb02SXin Li   return true;
97*f0dffb02SXin Li }
98*f0dffb02SXin Li 
SkipInstruction(Instruction * instr)99*f0dffb02SXin Li bool BasicBlocksVisitor::SkipInstruction(Instruction* instr) {
100*f0dffb02SXin Li   if (state_ != State::Outside) {
101*f0dffb02SXin Li     EndBlock(instr->prev);
102*f0dffb02SXin Li   }
103*f0dffb02SXin Li   return true;
104*f0dffb02SXin Li }
105*f0dffb02SXin Li 
StartBlock(Instruction * instr)106*f0dffb02SXin Li void BasicBlocksVisitor::StartBlock(Instruction* instr) {
107*f0dffb02SXin Li   assert(instr != nullptr);
108*f0dffb02SXin Li   assert(state_ == State::Outside);
109*f0dffb02SXin Li   // mark the location of the "first" instruction,
110*f0dffb02SXin Li   // "last" will be set when we end the basic block.
111*f0dffb02SXin Li   current_block_.region.first = instr;
112*f0dffb02SXin Li   current_block_.region.last = nullptr;
113*f0dffb02SXin Li   state_ = State::BlockHeader;
114*f0dffb02SXin Li }
115*f0dffb02SXin Li 
EndBlock(Instruction * instr)116*f0dffb02SXin Li void BasicBlocksVisitor::EndBlock(Instruction* instr) {
117*f0dffb02SXin Li   assert(instr != nullptr);
118*f0dffb02SXin Li   if (state_ == State::BlockBody) {
119*f0dffb02SXin Li     ++current_block_.id;
120*f0dffb02SXin Li     assert(current_block_.region.first != nullptr);
121*f0dffb02SXin Li     current_block_.region.last = instr;
122*f0dffb02SXin Li     basic_blocks_.push_back(current_block_);
123*f0dffb02SXin Li   } else {
124*f0dffb02SXin Li     assert(state_ == State::BlockHeader);
125*f0dffb02SXin Li   }
126*f0dffb02SXin Li   current_block_.region = {};
127*f0dffb02SXin Li   state_ = State::Outside;
128*f0dffb02SXin Li }
129*f0dffb02SXin Li 
CreateBasicBlocks(bool model_exceptions)130*f0dffb02SXin Li void ControlFlowGraph::CreateBasicBlocks(bool model_exceptions) {
131*f0dffb02SXin Li   BasicBlocksVisitor visitor(model_exceptions);
132*f0dffb02SXin Li   for (auto instr : code_ir->instructions) {
133*f0dffb02SXin Li     instr->Accept(&visitor);
134*f0dffb02SXin Li   }
135*f0dffb02SXin Li   basic_blocks = visitor.Finish();
136*f0dffb02SXin Li }
137*f0dffb02SXin Li 
138*f0dffb02SXin Li }  // namespace lir
139