• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 "graph_analyzer.h"
17 
18 #include "compiler/optimizer/ir/basicblock.h"
19 
20 #include "function.h"
21 #include "util/assert_util.h"
22 
23 using namespace panda::guard;
24 
25 namespace {
26 constexpr std::string_view TAG = "[Graph]";
27 constexpr std::string_view UI_COMPONENT_BASE_CLASS_VIEW_PU = "ViewPU";
28 constexpr std::string_view UI_COMPONENT_BASE_CLASS_VIEW_V2 = "ViewV2";
29 
30 using IntrinsicId = panda::compiler::RuntimeInterface::IntrinsicId;
31 using InstIdFilterList = std::vector<IntrinsicId>;
32 struct InstParam {
33 public:
34     unsigned index;               // Target instruction: Index in the input instruction register list
35     InstIdFilterList filterList;  // Input instruction: Type list
36 };
37 
38 const InstIdFilterList INST_ID_LIST_DYNAMICIMPORT = {
39     IntrinsicId::DYNAMICIMPORT,
40 };
41 const InstIdFilterList INST_ID_LIST_STLEXVAR = {IntrinsicId::STLEXVAR_IMM4_IMM4, IntrinsicId::STLEXVAR_IMM8_IMM8};
42 const InstIdFilterList INST_ID_LIST_LDOBJBYVALUE = {
43     IntrinsicId::LDOBJBYVALUE_IMM8_V8,
44     IntrinsicId::LDOBJBYVALUE_IMM16_V8,
45 };
46 const InstIdFilterList INST_ID_LIST_STOBJBYVALUE = {
47     IntrinsicId::STOBJBYVALUE_IMM8_V8_V8,
48     IntrinsicId::STOBJBYVALUE_IMM16_V8_V8,
49 };
50 const InstIdFilterList INST_ID_LIST_DEFINEGETTERSETTERBYVALUE = {
51     IntrinsicId::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8,
52 };
53 const InstIdFilterList INST_ID_LIST_ISIN = {
54     IntrinsicId::ISIN_IMM8_V8,
55 };
56 const InstIdFilterList INST_ID_LIST_LDSUPERBYVALUE = {
57     IntrinsicId::LDSUPERBYVALUE_IMM16_V8,
58     IntrinsicId::LDSUPERBYVALUE_IMM8_V8,
59 };
60 const InstIdFilterList INST_ID_LIST_STSUPERBYVALUE = {
61     IntrinsicId::STSUPERBYVALUE_IMM16_V8_V8,
62     IntrinsicId::STSUPERBYVALUE_IMM8_V8_V8,
63 };
64 const InstIdFilterList INST_ID_LIST_STOWNBYNAME = {
65     IntrinsicId::STOWNBYNAME_IMM16_ID16_V8,
66     IntrinsicId::STOWNBYNAME_IMM8_ID16_V8,
67 };
68 const InstIdFilterList INST_ID_LIST_STOWNBYNAMEWITHNAMESET = {
69     IntrinsicId::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8,
70     IntrinsicId::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8,
71 };
72 const InstIdFilterList INST_ID_LIST_STOWNBYVALUE = {
73     IntrinsicId::STOWNBYVALUE_IMM16_V8_V8,
74     IntrinsicId::STOWNBYVALUE_IMM8_V8_V8,
75 };
76 const InstIdFilterList INST_ID_LIST_STOWNBYVALUEWITHNAMESET = {
77     IntrinsicId::STOWNBYVALUEWITHNAMESET_IMM16_V8_V8,
78     IntrinsicId::STOWNBYVALUEWITHNAMESET_IMM8_V8_V8,
79 };
80 const InstIdFilterList INST_ID_LIST_DEFINEMETHOD = {
81     IntrinsicId::DEFINEMETHOD_IMM16_ID16_IMM8,
82     IntrinsicId::DEFINEMETHOD_IMM8_ID16_IMM8,
83 };
84 const InstIdFilterList INST_ID_LIST_CREATEOBJECTWITHBUFFER = {
85     IntrinsicId::CREATEOBJECTWITHBUFFER_IMM16_ID16,
86     IntrinsicId::CREATEOBJECTWITHBUFFER_IMM8_ID16,
87 };
88 const InstIdFilterList INST_ID_LIST_DEFINECLASSWITHBUFFER = {
89     IntrinsicId::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8,
90     IntrinsicId::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8,
91 };
92 const InstIdFilterList INST_ID_LIST_LDOBJBYNAME = {
93     IntrinsicId::LDOBJBYNAME_IMM16_ID16,
94     IntrinsicId::LDOBJBYNAME_IMM8_ID16,
95 };
96 const InstIdFilterList INST_ID_LIST_CALLRUNTIME_TOPROPERTYKEY = {
97     IntrinsicId::CALLRUNTIME_TOPROPERTYKEY_PREF_NONE,
98 };
99 const InstIdFilterList INST_ID_LIST_TRYLDGLOBALBYNAME = {
100     IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16,
101     IntrinsicId ::TRYLDGLOBALBYNAME_IMM16_ID16,
102 };
103 const InstIdFilterList INST_ID_LIST_DEFINEPROPERTYBYNAME = {
104     IntrinsicId::DEFINEPROPERTYBYNAME_IMM8_ID16_V8,
105 };
106 const InstIdFilterList INST_ID_LIST_CALLRUNTIME_DEFINESENDABLECLASS = {
107     IntrinsicId::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8,
108 };
109 
110 const std::map<panda::pandasm::Opcode, InstParam> LDA_STA_INST_PARAM_MAP = {
111     {panda::pandasm::Opcode::DYNAMICIMPORT, {0, INST_ID_LIST_DYNAMICIMPORT}},
112     {panda::pandasm::Opcode::STLEXVAR, {0, INST_ID_LIST_STLEXVAR}},
113     {panda::pandasm::Opcode::LDOBJBYVALUE, {1, INST_ID_LIST_LDOBJBYVALUE}},
114     {panda::pandasm::Opcode::STOBJBYVALUE, {1, INST_ID_LIST_STOBJBYVALUE}},
115     {panda::pandasm::Opcode::DEFINEGETTERSETTERBYVALUE, {1, INST_ID_LIST_DEFINEGETTERSETTERBYVALUE}},
116     {panda::pandasm::Opcode::ISIN, {0, INST_ID_LIST_ISIN}},
117     {panda::pandasm::Opcode::LDSUPERBYVALUE, {1, INST_ID_LIST_LDSUPERBYVALUE}},
118     {panda::pandasm::Opcode::STSUPERBYVALUE, {1, INST_ID_LIST_STSUPERBYVALUE}},
119     {panda::pandasm::Opcode::STOWNBYVALUE, {1, INST_ID_LIST_STOWNBYVALUE}},
120     {panda::pandasm::Opcode::STOWNBYVALUEWITHNAMESET, {1, INST_ID_LIST_STOWNBYVALUEWITHNAMESET}}};
121 
122 const std::vector<InstIdFilterList> DEFINE_INST_PASS_THROUGH_LIST = {
123     INST_ID_LIST_DEFINEGETTERSETTERBYVALUE,
124     INST_ID_LIST_DEFINEMETHOD,
125 };
126 const std::vector<InstIdFilterList> DEFINE_INST_ID_LIST = {
127     INST_ID_LIST_DEFINECLASSWITHBUFFER,
128     INST_ID_LIST_CREATEOBJECTWITHBUFFER,
129     INST_ID_LIST_LDOBJBYNAME,
130     INST_ID_LIST_CALLRUNTIME_DEFINESENDABLECLASS,
131 };
132 const std::vector<InstIdFilterList> METHOD_NAME_INST_ID_LIST = {
133     INST_ID_LIST_DEFINEGETTERSETTERBYVALUE, INST_ID_LIST_STOWNBYNAME,
134     INST_ID_LIST_STOWNBYNAMEWITHNAMESET,    INST_ID_LIST_STOWNBYVALUE,
135     INST_ID_LIST_STOWNBYVALUEWITHNAMESET,
136 };
137 
138 /**
139  * Is the instruction type in the list
140  */
IsInstIdMatched(const panda::compiler::Inst * inst,const InstIdFilterList & list)141 bool IsInstIdMatched(const panda::compiler::Inst *inst, const InstIdFilterList &list)
142 {
143     if (!inst->IsIntrinsic()) {
144         return false;
145     }
146 
147     IntrinsicId instId = inst->CastToIntrinsic()->GetIntrinsicId();
148     return std::any_of(list.begin(), list.end(), [&instId](IntrinsicId filter) -> bool { return instId == filter; });
149 }
150 
IsInstIdMatched(const panda::compiler::Inst * inst,const std::vector<InstIdFilterList> & list)151 bool IsInstIdMatched(const panda::compiler::Inst *inst, const std::vector<InstIdFilterList> &list)
152 {
153     return std::any_of(list.begin(), list.end(),
154                        [&](const InstIdFilterList &filter) -> bool { return IsInstIdMatched(inst, filter); });
155 }
156 
157 /**
158  * Does the current instruction match the requirement, Consistent with InstructionInfo
159  * @param inst Graph instruction to be checked
160  * @param list The instruction type that should be matched
161  * @param targetIns The InstructionInfo that should be matched
162  */
IsInstMatched(const panda::compiler::Inst * inst,const InstructionInfo & targetIns,const InstIdFilterList & list)163 bool IsInstMatched(const panda::compiler::Inst *inst, const InstructionInfo &targetIns, const InstIdFilterList &list)
164 {
165     if (!IsInstIdMatched(inst, list)) {
166         return false;
167     }
168 
169     uint32_t pcVal = inst->GetPc();
170     auto &pcInstMap = targetIns.function_->pcInstMap_;
171     if (pcInstMap.find(pcVal) == pcInstMap.end() || pcInstMap.at(pcVal) != targetIns.index_) {
172         return false;
173     }
174 
175     return true;
176 }
177 
178 /**
179  * Traverse the Graph to find matching instructions, Converting InstructionInfo to Graph Instruction
180  * @param inIns Instructions to be found
181  * @param list instruction type
182  * @param outInst Corresponding instructions in the graph
183  */
VisitGraph(const InstructionInfo & inIns,const InstIdFilterList & list,const panda::compiler::Inst * & outInst)184 void VisitGraph(const InstructionInfo &inIns, const InstIdFilterList &list, const panda::compiler::Inst *&outInst)
185 {
186     Function *func = inIns.function_;
187     panda::compiler::Graph *graph;
188     func->GetGraph(graph);
189 
190     for (const panda::compiler::BasicBlock *bb : graph->GetBlocksLinearOrder()) {
191         for (const panda::compiler::Inst *inst : bb->AllInsts()) {
192             if (!IsInstMatched(inst, inIns, list)) {
193                 continue;
194             }
195             outInst = inst;
196             return;
197         }
198     }
199 
200     PANDA_GUARD_ABORT_PRINT(TAG, ErrorCode::GENERIC_ERROR,
201                             "not find inst: " << inIns.index_ << " in " << inIns.function_->idx_);
202 }
203 
204 /**
205  * Fill the graph instruction into InstructionInfo, Convert Graph instruction to InstructionInfo
206  * @param inIns Used to obtain background information of InstructionInfo
207  * @param target graph instruction
208  * @param outIns InstructionInfo for filling
209  */
FillInstInfo(const InstructionInfo & inIns,const panda::compiler::Inst * target,InstructionInfo & outIns)210 void FillInstInfo(const InstructionInfo &inIns, const panda::compiler::Inst *target, InstructionInfo &outIns)
211 {
212     uint32_t pcVal = target->GetPc();
213     Function *func = inIns.function_;
214     PANDA_GUARD_ASSERT_PRINT(func->pcInstMap_.find(pcVal) == func->pcInstMap_.end(), TAG, ErrorCode::GENERIC_ERROR,
215                              "no valid target ins: " << inIns.function_->idx_ << ", " << inIns.index_);
216     func->FillInstInfo(func->pcInstMap_.at(pcVal), outIns);
217 }
218 
219 /**
220  * Print Graph instruction content
221  */
PrintInst(const panda::compiler::Inst * ins)222 std::string PrintInst(const panda::compiler::Inst *ins)
223 {
224     std::stringstream stream;
225     ins->Dump(&stream, false);
226     return stream.str();
227 }
228 
229 /**
230  * Find the lda.str instruction corresponding to the input command
231  */
FindLdaStr(const panda::compiler::Inst * prevInst,const panda::compiler::Inst * & outIns)232 void FindLdaStr(const panda::compiler::Inst *prevInst, const panda::compiler::Inst *&outIns)
233 {
234     if (IsInstIdMatched(prevInst, INST_ID_LIST_CALLRUNTIME_TOPROPERTYKEY)) {
235         prevInst = prevInst->GetInput(0).GetInst();
236     }
237 
238     if (prevInst->GetOpcode() != panda::compiler::Opcode::CastValueToAnyType) {
239         return;
240     }
241     const panda::compiler::Inst *targetInst = prevInst->GetInput(0).GetInst();
242     if (targetInst->GetOpcode() != panda::compiler::Opcode::LoadString) {
243         return;
244     }
245 
246     outIns = targetInst;
247 }
248 
249 /**
250  * Find the object definition instruction corresponding to the input instruction
251  */
FindDefineInst(const panda::compiler::Inst * prevInst,const panda::compiler::Inst * & outIns)252 void FindDefineInst(const panda::compiler::Inst *prevInst, const panda::compiler::Inst *&outIns)
253 {
254     if (IsInstIdMatched(prevInst, {INST_ID_LIST_CREATEOBJECTWITHBUFFER, INST_ID_LIST_DEFINECLASSWITHBUFFER,
255                                    INST_ID_LIST_CALLRUNTIME_DEFINESENDABLECLASS})) {
256         outIns = prevInst;
257         return;
258     }
259 
260     // Try to find class define in prototype instance
261     if (!IsInstIdMatched(prevInst, INST_ID_LIST_LDOBJBYNAME)) {
262         return;
263     }
264 
265     const panda::compiler::Inst *targetIns = prevInst->GetInput(0).GetInst();
266     if (!IsInstIdMatched(targetIns, INST_ID_LIST_DEFINECLASSWITHBUFFER)) {
267         return;
268     }
269     outIns = targetIns;
270 }
271 }  // namespace
272 
GetLdaStr(const InstructionInfo & inIns,InstructionInfo & outIns,int index)273 void GraphAnalyzer::GetLdaStr(const InstructionInfo &inIns, InstructionInfo &outIns, int index /* = -1 */)
274 {
275     auto it = LDA_STA_INST_PARAM_MAP.find(inIns.ins_->opcode);
276     PANDA_GUARD_ASSERT_PRINT(it == LDA_STA_INST_PARAM_MAP.end(), TAG, ErrorCode::GENERIC_ERROR,
277                              "unsupported lda.str scene: " << inIns.ins_->ToString());
278 
279     const panda::compiler::Inst *inst;
280     VisitGraph(inIns, it->second.filterList, inst);
281 
282     unsigned targetIndex = index >= 0 ? index : it->second.index;
283     const panda::compiler::Inst *prevInst = inst->GetInput(targetIndex).GetInst();
284     const panda::compiler::Inst *targetInst = nullptr;
285     FindLdaStr(prevInst, targetInst);
286 
287     if (targetInst == nullptr) {
288         LOG(INFO, PANDAGUARD) << TAG << "GetLdaStr failed: " << inIns.function_->idx_ << ", " << inIns.index_ << ";"
289                               << PrintInst(prevInst);
290         return;
291     }
292 
293     FillInstInfo(inIns, targetInst, outIns);
294 }
295 
HandleDefineMethod(const InstructionInfo & inIns,InstructionInfo & defineIns,InstructionInfo & nameIns)296 void GraphAnalyzer::HandleDefineMethod(const InstructionInfo &inIns, InstructionInfo &defineIns,
297                                        InstructionInfo &nameIns)
298 {
299     const panda::compiler::Inst *inst;
300     VisitGraph(inIns, INST_ID_LIST_DEFINEMETHOD, inst);
301 
302     for (const auto &userIns : inst->GetUsers()) {
303         if (IsInstIdMatched(userIns.GetInst(), METHOD_NAME_INST_ID_LIST)) {
304             FillInstInfo(inIns, userIns.GetInst(), nameIns);
305             break;
306         }
307     }
308 
309     do {
310         inst = inst->GetInput(0).GetInst();
311     } while (IsInstIdMatched(inst, DEFINE_INST_PASS_THROUGH_LIST));
312     PANDA_GUARD_ASSERT_PRINT(!IsInstIdMatched(inst, DEFINE_INST_ID_LIST), TAG, ErrorCode::GENERIC_ERROR,
313                              "unexpect defineMethod scene: " << inIns.function_->idx_ << ", " << inIns.index_ << ";"
314                                                              << PrintInst(inst));
315 
316     const panda::compiler::Inst *targetInst = nullptr;
317     FindDefineInst(inst, targetInst);
318     PANDA_GUARD_ASSERT_PRINT(targetInst == nullptr, TAG, ErrorCode::GENERIC_ERROR,
319                              "HandleDefineMethod failed: " << inIns.function_->idx_ << ", " << inIns.index_ << ";"
320                                                            << PrintInst(inst));
321 
322     FillInstInfo(inIns, targetInst, defineIns);
323 }
324 
HandleDefineProperty(const panda::guard::InstructionInfo & inIns,panda::guard::InstructionInfo & defineIns)325 void GraphAnalyzer::HandleDefineProperty(const panda::guard::InstructionInfo &inIns,
326                                          panda::guard::InstructionInfo &defineIns)
327 {
328     const panda::compiler::Inst *inst;
329     VisitGraph(inIns, INST_ID_LIST_DEFINEPROPERTYBYNAME, inst);
330 
331     const panda::compiler::Inst *target = nullptr;
332     FindDefineInst(inst->GetInput(0).GetInst(), target);
333     if (target == nullptr) {
334         return;
335     }
336 
337     FillInstInfo(inIns, target, defineIns);
338 }
339 
IsComponentClass(const panda::guard::InstructionInfo & inIns)340 bool GraphAnalyzer::IsComponentClass(const panda::guard::InstructionInfo &inIns)
341 {
342     if (inIns.ins_->opcode != pandasm::Opcode::DEFINECLASSWITHBUFFER) {
343         return false;
344     }
345 
346     const panda::compiler::Inst *inst;
347     VisitGraph(inIns, INST_ID_LIST_DEFINECLASSWITHBUFFER, inst);
348 
349     const panda::compiler::Inst *tryldglobalbyname = inst->GetInput(0).GetInst();
350     if (!IsInstIdMatched(tryldglobalbyname, INST_ID_LIST_TRYLDGLOBALBYNAME)) {
351         return false;
352     }
353 
354     InstructionInfo out;
355     FillInstInfo(inIns, tryldglobalbyname, out);
356 
357     const std::string baseClassName = out.ins_->ids[0];
358     if (baseClassName != UI_COMPONENT_BASE_CLASS_VIEW_PU && baseClassName != UI_COMPONENT_BASE_CLASS_VIEW_V2) {
359         return false;
360     }
361 
362     LOG(INFO, PANDAGUARD) << TAG << "found UI component:" << inIns.ins_->ids[0];
363 
364     return true;
365 }
366