1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "optimizer/ir/basicblock.h"
17 #include "monitor_analysis.h"
18 #include "optimizer/ir/graph.h"
19 #include "compiler_logger.h"
20
21 namespace ark::compiler {
MarkedMonitorRec(BasicBlock * bb,int32_t numMonitors)22 void MonitorAnalysis::MarkedMonitorRec(BasicBlock *bb, int32_t numMonitors)
23 {
24 ASSERT(numMonitors >= 0);
25 if (numMonitors > 0) {
26 bb->SetMonitorBlock(true);
27 if (bb->IsEndBlock()) {
28 COMPILER_LOG(DEBUG, MONITOR_ANALYSIS) << "There is MonitorEntry without MonitorExit";
29 incorrectMonitors_ = true;
30 return;
31 }
32 }
33 for (auto inst : bb->Insts()) {
34 if (inst->GetOpcode() == Opcode::Throw) {
35 // The Monitor.Exit is removed from the compiled code after explicit Throw instruction
36 // in the syncronized block because the execution is switching to the interpreting mode
37 numMonitors = 0;
38 }
39 if (inst->GetOpcode() == Opcode::Monitor) {
40 bb->SetMonitorBlock(true);
41 if (inst->CastToMonitor()->IsEntry()) {
42 bb->SetMonitorEntryBlock(true);
43 ++numMonitors;
44 continue;
45 }
46 ASSERT(inst->CastToMonitor()->IsExit());
47 if (numMonitors <= 0) {
48 COMPILER_LOG(DEBUG, MONITOR_ANALYSIS) << "There is MonitorExit without MonitorEntry";
49 incorrectMonitors_ = true;
50 return;
51 }
52 bb->SetMonitorExitBlock(true);
53 --numMonitors;
54 }
55 }
56 enteredMonitorsCount_->at(bb->GetId()) = static_cast<uint32_t>(numMonitors);
57 if (numMonitors == 0) {
58 return;
59 }
60 for (auto succ : bb->GetSuccsBlocks()) {
61 if (checkNonCatchOnly_ && succ->IsCatch()) {
62 continue;
63 }
64 if (succ->SetMarker(marker_)) {
65 continue;
66 }
67 MarkedMonitorRec(succ, numMonitors);
68 }
69 }
70
RunImpl()71 bool MonitorAnalysis::RunImpl()
72 {
73 auto allocator = GetGraph()->GetLocalAllocator();
74 incorrectMonitors_ = false;
75 enteredMonitorsCount_ = allocator->New<ArenaVector<uint32_t>>(allocator->Adapter());
76 enteredMonitorsCount_->resize(GetGraph()->GetVectorBlocks().size());
77 marker_ = GetGraph()->NewMarker();
78 for (auto bb : GetGraph()->GetBlocksRPO()) {
79 if (checkNonCatchOnly_ && bb->IsCatch()) {
80 continue;
81 }
82 if (bb->SetMarker(marker_)) {
83 continue;
84 }
85 MarkedMonitorRec(bb, 0);
86 if (incorrectMonitors_) {
87 return false;
88 }
89 }
90 for (auto bb : GetGraph()->GetBlocksRPO()) {
91 if (checkNonCatchOnly_ && bb->IsCatch()) {
92 continue;
93 }
94 const uint32_t uninitialized = 0xFFFFFFFF;
95 uint32_t count = uninitialized;
96 for (auto prev : bb->GetPredsBlocks()) {
97 if (checkNonCatchOnly_ && prev->IsCatch()) {
98 continue;
99 }
100 if (count == uninitialized) {
101 count = enteredMonitorsCount_->at(prev->GetId());
102 } else if (count != enteredMonitorsCount_->at(prev->GetId())) {
103 COMPILER_LOG(DEBUG, MONITOR_ANALYSIS)
104 << "There is an inconsistent MonitorEntry counters in parent basic blocks";
105 return false;
106 }
107 }
108 }
109 GetGraph()->EraseMarker(marker_);
110 return true;
111 }
112 } // namespace ark::compiler
113