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