1 /*
2 * Copyright (c) 2021-2025 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 ASSERT(enteredMonitorsCount_ != nullptr);
77 enteredMonitorsCount_->resize(GetGraph()->GetVectorBlocks().size());
78 marker_ = GetGraph()->NewMarker();
79 for (auto bb : GetGraph()->GetBlocksRPO()) {
80 if (checkNonCatchOnly_ && bb->IsCatch()) {
81 continue;
82 }
83 if (bb->SetMarker(marker_)) {
84 continue;
85 }
86 MarkedMonitorRec(bb, 0);
87 if (incorrectMonitors_) {
88 return false;
89 }
90 }
91 for (auto bb : GetGraph()->GetBlocksRPO()) {
92 if (checkNonCatchOnly_ && bb->IsCatch()) {
93 continue;
94 }
95 const uint32_t uninitialized = 0xFFFFFFFF;
96 uint32_t count = uninitialized;
97 for (auto prev : bb->GetPredsBlocks()) {
98 if (checkNonCatchOnly_ && prev->IsCatch()) {
99 continue;
100 }
101 if (count == uninitialized) {
102 count = enteredMonitorsCount_->at(prev->GetId());
103 } else if (count != enteredMonitorsCount_->at(prev->GetId())) {
104 COMPILER_LOG(DEBUG, MONITOR_ANALYSIS)
105 << "There is an inconsistent MonitorEntry counters in parent basic blocks";
106 return false;
107 }
108 }
109 }
110 GetGraph()->EraseMarker(marker_);
111 return true;
112 }
113 } // namespace ark::compiler
114