1 /*
2  * Copyright (c) 2022 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 "abc_file.h"
17 #include "libpandabase/mem/pool_manager.h"
18 #include "libpandafile/class_data_accessor-inl.h"
19 #include "libpandafile/code_data_accessor-inl.h"
20 #include "libpandafile/method_data_accessor-inl.h"
21 #include "libpandafile/literal_data_accessor-inl.h"
22 #include "libpandafile/field_data_accessor-inl.h"
23 #include "libpandafile/module_data_accessor-inl.h"
24 #include "compiler/optimizer/ir_builder/ir_builder.h"
25 #include "bytecode_optimizer/common.h"
26 #include "bytecode_optimizer/runtime_adapter.h"
27 #include "callee_info.h"
28 #include "class.h"
29 #include "function.h"
30 #include "module_record.h"
31 
32 namespace panda::defect_scan_aux {
33 using EntityId = panda_file::File::EntityId;
34 using StringData = panda_file::StringData;
35 using LiteralTag = panda_file::LiteralTag;
36 using ModuleDataAccessor = panda_file::ModuleDataAccessor;
37 using ModuleTag = panda_file::ModuleTag;
38 
AbcFile(std::string_view filename, std::unique_ptr<const panda_file::File> &&panda_file)39 AbcFile::AbcFile(std::string_view filename, std::unique_ptr<const panda_file::File> &&panda_file)
40     : filename_(filename), panda_file_(std::forward<std::unique_ptr<const panda_file::File>>(panda_file))
41 {
42     PoolManager::Initialize(PoolType::MALLOC);
43     allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER);
44     local_allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
45 }
46 
~AbcFile()47 AbcFile::~AbcFile()
48 {
49     PoolManager::Finalize();
50 }
51 
Open(std::string_view abc_filename)52 std::unique_ptr<const AbcFile> AbcFile::Open(std::string_view abc_filename)
53 {
54     auto panda_file = panda_file::OpenPandaFile(abc_filename);
55     if (panda_file == nullptr) {
56         LOG(ERROR, DEFECT_SCAN_AUX) << "Can not open binary file '" << abc_filename << "'";
57         return nullptr;
58     }
59 
60     std::unique_ptr<AbcFile> abc_file(new (std::nothrow) AbcFile(abc_filename, std::move(panda_file)));
61     if (abc_file == nullptr) {
62         LOG(ERROR, DEFECT_SCAN_AUX) << "Can not create AbcFile instance for '" << abc_filename << "'";
63         return nullptr;
64     }
65 
66     abc_file->ExtractDebugInfo();
67     abc_file->ExtractModuleInfo();
68     abc_file->InitializeAllDefinedFunction();
69     abc_file->ExtractDefinedClassAndFunctionInfo();
70     abc_file->ExtractClassAndFunctionExportList();
71     return abc_file;
72 }
73 
IsModule(std::string_view record_name) const74 bool AbcFile::IsModule(std::string_view record_name) const
75 {
76     if (IsMergeAbc() && record_name == "") {
77         LOG(FATAL, DEFECT_SCAN_AUX) <<
78             "For merge abc, need to specify record name to check if it has module info";
79     }
80     return GetModuleRecordByName(std::string(record_name)) != nullptr;
81 }
82 
IsMergeAbc() const83 bool AbcFile::IsMergeAbc() const
84 {
85     return is_merge_abc_;
86 }
87 
GetAbcFileName() const88 const std::string &AbcFile::GetAbcFileName() const
89 {
90     return filename_;
91 }
92 
GetDefinedFunctionCount() const93 size_t AbcFile::GetDefinedFunctionCount() const
94 {
95     if (IsMergeAbc()) {
96         return merged_def_func_list_.size();
97     }
98     return def_func_list_.size();
99 }
100 
GetDefinedClassCount() const101 size_t AbcFile::GetDefinedClassCount() const
102 {
103     if (IsMergeAbc()) {
104         return merged_def_class_list_.size();
105     }
106     return def_class_list_.size();
107 }
108 
GetClassList() const109 const std::vector<std::shared_ptr<Class>> &AbcFile::GetClassList() const
110 {
111     if (IsMergeAbc()) {
112         return merged_def_class_list_;
113     }
114     return def_class_list_;
115 }
116 
GetDefinedFunctionByIndex(size_t index) const117 const Function *AbcFile::GetDefinedFunctionByIndex(size_t index) const
118 {
119     if (IsMergeAbc()) {
120         ASSERT(index < merged_def_func_list_.size());
121         return merged_def_func_list_[index].get();
122     }
123     ASSERT(index < def_func_list_.size());
124     return def_func_list_[index].get();
125 }
126 
127 const Function *AbcFile::GetFunctionByName(std::string_view func_name) const
128 {
129     return GetFunctionByNameImpl(func_name);
130 }
131 
132 const Function *AbcFile::GetExportFunctionByExportName(std::string_view export_func_name,
133                                                        std::string_view record_name) const
134 {
135     if (!IsModule(record_name)) {
136         return nullptr;
137     }
138 
139     if (IsMergeAbc() && record_name == "") {
140         LOG(FATAL, DEFECT_SCAN_AUX) <<
141             "Failed to GetExportFunctionByExportName from merge abc, need to specify record name";
142     }
143     std::string inter_func_name = GetLocalNameByExportName(export_func_name, record_name);
144     auto export_func_list = export_func_list_;
145     if (IsMergeAbc()) {
146         const std::string record_name_str = std::string(record_name);
147         auto it = merge_export_func_map_.find(record_name_str);
148         if (it == merge_export_func_map_.end()) {
149             return nullptr;
150         }
151         export_func_list = it->second;
152     }
153     for (auto &export_func : export_func_list) {
154         const std::string &ex_func_name = export_func->GetFunctionName();
155         std::string_view no_hashtag_name = GetNameWithoutHashtag(ex_func_name, record_name);
156         if (no_hashtag_name == inter_func_name) {
157             return export_func;
158         }
159     }
160     return nullptr;
161 }
162 
163 const Class *AbcFile::GetDefinedClassByIndex(size_t index) const
164 {
165     if (IsMergeAbc()) {
166         ASSERT(index < merged_def_class_list_.size());
167         return merged_def_class_list_[index].get();
168     }
169     ASSERT(index < def_class_list_.size());
170     return def_class_list_[index].get();
171 }
172 
173 const Class *AbcFile::GetClassByName(std::string_view class_name) const
174 {
175     return GetClassByNameImpl(class_name);
176 }
177 
178 const Class *AbcFile::GetExportClassByExportName(std::string_view export_class_name,
179                                                  std::string_view record_name) const
180 {
181     if (!IsModule(record_name)) {
182         return nullptr;
183     }
184 
185     if (IsMergeAbc() && record_name == "") {
186         LOG(FATAL, DEFECT_SCAN_AUX) <<
187             "Failed to GetExportClassByExportName from merge abc, need to specify record name";
188     }
189     if (!IsMergeAbc()) {
190         record_name = std::string(MODULE_CLASS);
191     }
192     std::string inter_class_name = GetLocalNameByExportName(export_class_name, record_name);
193     auto export_class_list = export_class_list_;
194     if (IsMergeAbc()) {
195         const std::string record_name_str = std::string(record_name);
196         auto it = merge_export_class_map_.find(record_name_str);
197         if (it == merge_export_class_map_.end()) {
198             return nullptr;
199         }
200         export_class_list = it->second;
201     }
202     for (auto export_class : export_class_list) {
203         const std::string &ex_class_name = export_class->GetClassName();
204         std::string_view no_hashtag_name = GetNameWithoutHashtag(ex_class_name, record_name);
205         if (no_hashtag_name == inter_class_name) {
206             return export_class;
207         }
208     }
209     return nullptr;
210 }
211 
212 ssize_t AbcFile::GetLineNumberByInst(const Function *func, const Inst &inst) const
213 {
214     auto &line_number_table = debug_info_->GetLineNumberTable(func->GetMethodId());
215     if (!line_number_table.empty()) {
216         uint32_t inst_pc = inst.GetPc();
217         // line_number_table is in ascending order, find the element that satisfies e1.pc <= inst_pc < e2.pc
218         auto comp = [](size_t value, const panda_file::LineTableEntry &entry) { return value >= entry.offset; };
219         auto iter = std::upper_bound(line_number_table.rbegin(), line_number_table.rend(), inst_pc, comp);
220         if (iter != line_number_table.rend()) {
221             // line number written in a .abc file starts from 0
222             return iter->line + 1;
223         }
224     }
225     return -1;
226 }
227 
228 const std::set<std::string> AbcFile::GetFileRecordList() const
229 {
230     return record_name_set_;
231 }
232 
233 size_t AbcFile::GetFileRecordCount() const
234 {
235     return record_name_set_.size();
236 }
237 
238 std::string AbcFile::GetLocalNameByExportName(std::string_view export_name, std::string_view record_name) const
239 {
240     if (!IsModule(record_name)) {
241         return EMPTY_STR;
242     }
243     if (IsMergeAbc() && record_name == "") {
244         LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetLocalNameByExportName from merge abc, need to specify record name";
245     }
246     if (!IsMergeAbc()) {
247         record_name = std::string(MODULE_CLASS);
248     }
249     auto module_record = GetModuleRecordByName(std::string(record_name));
250     return module_record->GetLocalNameByExportName(export_name);
251 }
252 
253 std::string AbcFile::GetImportNameByExportName(std::string_view export_name, std::string_view record_name) const
254 {
255     if (!IsModule(record_name)) {
256         return EMPTY_STR;
257     }
258     if (IsMergeAbc() && record_name == "") {
259         LOG(FATAL, DEFECT_SCAN_AUX)
260             << "Failed to GetImportNameByExportName from merge abc, need to specify record name";
261     }
262     if (!IsMergeAbc()) {
263         record_name = std::string(MODULE_CLASS);
264     }
265     auto module_record = GetModuleRecordByName(std::string(record_name));
266     return  module_record->GetImportNameByExportName(export_name);
267 }
268 
269 std::string AbcFile::GetModuleNameByExportName(std::string_view export_name, std::string_view record_name) const
270 {
271     if (!IsModule(record_name)) {
272         return EMPTY_STR;
273     }
274     if (IsMergeAbc() && record_name == "") {
275         LOG(FATAL, DEFECT_SCAN_AUX)
276             << "Failed to GetModuleNameByExportName from merge abc, need to specify record name";
277     }
278     if (!IsMergeAbc()) {
279         record_name = std::string(MODULE_CLASS);
280     }
281     auto module_record = GetModuleRecordByName(std::string(record_name));
282     return module_record->GetModuleNameByExportName(export_name);
283 }
284 
285 std::string AbcFile::GetModuleNameByLocalName(std::string_view local_name, std::string_view record_name) const
286 {
287     if (!IsModule(record_name)) {
288         return EMPTY_STR;
289     }
290     if (IsMergeAbc() && record_name == "") {
291         LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetModuleNameByLocalName from merge abc, need to specify record name";
292     }
293     if (!IsMergeAbc()) {
294         record_name = std::string(MODULE_CLASS);
295     }
296     auto module_record = GetModuleRecordByName(std::string(record_name));
297     return module_record->GetModuleNameByLocalName(local_name);
298 }
299 
300 std::string AbcFile::GetImportNameByLocalName(std::string_view local_name, std::string_view record_name) const
301 {
302     if (!IsModule(record_name)) {
303         return EMPTY_STR;
304     }
305     if (IsMergeAbc() && record_name == "") {
306         LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetImportNameByLocalName from merge abc, need to specify record name";
307     }
308     if (!IsMergeAbc()) {
309         record_name = std::string(MODULE_CLASS);
310     }
311     auto module_record = GetModuleRecordByName(std::string(record_name));
312     return module_record->GetImportNameByLocalName(local_name);
313 }
314 
315 std::string_view AbcFile::GetNameWithoutHashtag(std::string_view full_name, std::string_view record_name) const
316 {
317     size_t pos = full_name.find(record_name);
318     std::string_view name = pos == std::string::npos ? full_name : full_name.substr(pos + record_name.length());
319     if (name[0] == '#') {
320         size_t sec_hashtag_idx = name.find_first_of('#', 1);
321         if (sec_hashtag_idx != std::string::npos && (sec_hashtag_idx + 1) <= name.size()) {
322             return name.substr(sec_hashtag_idx + 1);
323         }
324     }
325     return name;
326 }
327 
328 std::string AbcFile::GetStringByInst(const Inst &inst) const
329 {
330     auto type = inst.GetType();
331     switch (type) {
332         case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
333         case InstType::DEFINEFUNC_IMM16_ID16_IMM8:
334         case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
335         case InstType::DEFINEMETHOD_IMM16_ID16_IMM8:
336         case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
337         case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
338         case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
339             uint32_t method_id = inst.GetImms()[1];
340             return GetStringByMethodId(EntityId(method_id));
341         }
342         case InstType::TRYLDGLOBALBYNAME_IMM8_ID16:
343         case InstType::TRYSTGLOBALBYNAME_IMM8_ID16:
344         case InstType::TRYLDGLOBALBYNAME_IMM16_ID16:
345         case InstType::TRYSTGLOBALBYNAME_IMM16_ID16:
346         case InstType::STCONSTTOGLOBALRECORD_IMM16_ID16:
347         case InstType::STTOGLOBALRECORD_IMM16_ID16:
348         case InstType::LDGLOBALVAR_IMM16_ID16:
349         case InstType::STGLOBALVAR_IMM16_ID16:
350         case InstType::LDOBJBYNAME_IMM8_ID16:
351         case InstType::LDOBJBYNAME_IMM16_ID16:
352         case InstType::STOBJBYNAME_IMM8_ID16_V8:
353         case InstType::STOBJBYNAME_IMM16_ID16_V8:
354         case InstType::LDSUPERBYNAME_IMM8_ID16:
355         case InstType::LDSUPERBYNAME_IMM16_ID16:
356         case InstType::STSUPERBYNAME_IMM8_ID16_V8:
357         case InstType::STSUPERBYNAME_IMM16_ID16_V8:
358         case InstType::LDTHISBYNAME_IMM8_ID16:
359         case InstType::LDTHISBYNAME_IMM16_ID16:
360         case InstType::STTHISBYNAME_IMM8_ID16:
361         case InstType::STTHISBYNAME_IMM16_ID16:
362         case InstType::STOWNBYNAME_IMM8_ID16_V8:
363         case InstType::STOWNBYNAME_IMM16_ID16_V8:
364         case InstType::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
365         case InstType::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8: {
366             uint32_t string_id = inst.GetImms()[1];
367             return GetStringByStringId(EntityId(string_id));
368         }
369         default:
370             return EMPTY_STR;
371     }
372 }
373 
374 // TODO(wangyantian): may match multiple stlex inst when considering control flow
375 std::optional<FuncInstPair> AbcFile::GetStLexInstByLdLexInst(FuncInstPair func_inst_pair) const
376 {
377     Function *func = func_inst_pair.first;
378     const Inst &ld_lex_inst = func_inst_pair.second;
379     if (func == nullptr || !ld_lex_inst.IsInstLdLexVar()) {
380         return std::nullopt;
381     }
382 
383     auto ld_imms = ld_lex_inst.GetImms();
384     uint32_t ld_level = ld_imms[0];
385     uint32_t ld_slot_id = ld_imms[1];
386     Function *cur_func = func;
387     uint32_t i = 0;
388     while (true) {
389         bool has_new_lexenv = false;
390         const auto &graph = cur_func->GetGraph();
391         // TODO: Multiple newlexenv instructions and poplexenv instruction are not correctly supported in
392         //  the following code. Future fixes are required.
393         graph.VisitAllInstructions([&has_new_lexenv](const Inst &inst) {
394             if (inst.GetType() == InstType::NEWLEXENV_IMM8 || inst.GetType() == InstType::WIDE_NEWLEXENV_PREF_IMM16) {
395                 has_new_lexenv = true;
396             }
397         });
398         if (has_new_lexenv) {
399             i++;
400         }
401         if (i == ld_level + 1) {
402             break;
403         }
404         cur_func = cur_func->GetParentFunction();
405         if (cur_func == nullptr) {
406             return std::nullopt;
407         }
408     }
409     auto &graph = cur_func->GetGraph();
410     Inst st_lex_inst = ld_lex_inst;
411     bool is_same_func = (cur_func == func_inst_pair.first);
412     graph.VisitAllInstructions([is_same_func, ld_lex_inst, ld_slot_id, &st_lex_inst](const Inst &inst) {
413         if (inst.IsInstStLexVar()) {
414             auto st_imms = inst.GetImms();
415             uint32_t st_level = st_imms[0];
416             uint32_t st_slot_id = st_imms[1];
417             if (st_level == 0 && st_slot_id == ld_slot_id) {
418                 // Best effort to avoid the case where ld_lex_inst is some input of st_lex_inst
419                 // Current heuristics for choosing a valid st_lex_inst (or relationship between conditions):
420                 // 1. If no valid st_lex_inst is found (which is necessary to make the search process more sound).
421                 // 2. If they are not in the same function.
422                 // 3. If they are in the same function, but current st_lex_inst appears before ld_lex_inst (by PC).
423                 // More advanced heuristics (e.g. preforming dfs on all inputs of st_lex_inst) should be considered.
424                 if (st_lex_inst == ld_lex_inst || !is_same_func || inst.GetPc() < ld_lex_inst.GetPc()) {
425                     st_lex_inst = inst;
426                 }
427             }
428         }
429     });
430     if (st_lex_inst != ld_lex_inst) {
431         return FuncInstPair(cur_func, st_lex_inst);
432     }
433 
434     return std::nullopt;
435 }
436 
437 std::optional<FuncInstPair> AbcFile::GetStGlobalInstByLdGlobalInst(FuncInstPair func_inst_pair) const
438 {
439     const Function *func = func_inst_pair.first;
440     const Inst &ld_global_inst = func_inst_pair.second;
441     if (func == nullptr || !ld_global_inst.IsInstLdGlobal()) {
442         return std::nullopt;
443     }
444 
445     uint32_t ld_str_id = ld_global_inst.GetImms()[0];
446     std::string record_name = func->GetRecordName();
447     Function *func_main;
448     // TODO(wangyantian): only consider that func_main_0 has StGlobal inst for now, what about other cases?
449     if (IsMergeAbc()) {
450         ASSERT(merge_def_func_map_.find(record_name) != merge_def_func_map_.end());
451         func_main = merge_def_func_map_.find(record_name)->second[0].get();
452     } else {
453         func_main = def_func_list_[0].get();
454     }
455     auto &graph = func_main->GetGraph();
456     Inst st_global_inst = ld_global_inst;
457     graph.VisitAllInstructions([ld_str_id, &st_global_inst](const Inst &inst) {
458         if (inst.IsInstStGlobal()) {
459             uint32_t st_str_id = inst.GetImms()[0];
460             if (st_str_id == ld_str_id) {
461                 st_global_inst = inst;
462             }
463         }
464     });
465     if (st_global_inst != ld_global_inst) {
466         return FuncInstPair(func_main, st_global_inst);
467     }
468 
469     return std::nullopt;
470 }
471 
472 void AbcFile::ExtractDebugInfo()
473 {
474     debug_info_ = std::make_unique<const panda_file::DebugInfoExtractor>(panda_file_.get());
475     if (debug_info_ == nullptr) {
476         LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to extract debug info";
477     }
478 }
479 
480 void AbcFile::ExtractModuleInfo()
481 {
482     int module_offset = -1;
483     is_merge_abc_ = true;
484     for (uint32_t id : panda_file_->GetClasses()) {
485         EntityId class_id(id);
486         if (panda_file_->IsExternal(class_id)) {
487             continue;
488         }
489         panda_file::ClassDataAccessor cda(*panda_file_, class_id);
490         const char *desc = utf::Mutf8AsCString(cda.GetDescriptor());
491         if (std::strcmp(MODULE_CLASS, desc) == 0) {
492             is_merge_abc_ = false;
493             cda.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
494                 EntityId field_name_id = field_accessor.GetNameId();
495                 StringData sd = panda_file_->GetStringData(field_name_id);
496                 if (std::strcmp(utf::Mutf8AsCString(sd.data), filename_.data())) {
497                     module_offset = field_accessor.GetValue<int32_t>().value();
498                     return;
499                 }
500             });
501             break;
502         }
503     }
504     if (is_merge_abc_) {
505         ExtractMergeAbcModuleInfo();
506         return;
507     } else if (module_offset == -1) {
508         return;
509     }
510 
511     std::unique_ptr<ModuleRecord> module_record = std::make_unique<ModuleRecord>(filename_);
512     if (module_record == nullptr) {
513         LOG(FATAL, DEFECT_SCAN_AUX) << "Can not create ModuleRecord instance for '" << filename_ << "'";
514     }
515     ExtractModuleRecord(EntityId(module_offset), module_record);
516     AddModuleRecord(MODULE_CLASS, std::move(module_record));
517 }
518 
519 void AbcFile::ExtractMergeAbcModuleInfo()
520 {
521     for (uint32_t id : panda_file_->GetClasses()) {
522         EntityId class_id(id);
523         if (panda_file_->IsExternal(class_id)) {
524             continue;
525         }
526         panda_file::ClassDataAccessor cda(*panda_file_, class_id);
527         const char *desc = utf::Mutf8AsCString(cda.GetDescriptor());
528         cda.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
529             EntityId field_name_id = field_accessor.GetNameId();
530             StringData sd = panda_file_->GetStringData(field_name_id);
531             if (std::strcmp(utf::Mutf8AsCString(sd.data), MODULE_IDX_FIELD_NAME) != 0) {
532                 return;
533             }
534             auto module_offset = field_accessor.GetValue<int32_t>().value();
535             std::unique_ptr<ModuleRecord> module_record = std::make_unique<ModuleRecord>(desc);
536             ASSERT(module_record != nullptr);
537             ExtractModuleRecord(EntityId(module_offset), module_record);
538             AddModuleRecord(std::string(desc), std::move(module_record));
539         });
540     }
541 }
542 
543 void AbcFile::ExtractModuleRecord(EntityId module_id, std::unique_ptr<ModuleRecord> &module_record)
544 {
545     ModuleDataAccessor mda(*panda_file_, module_id);
546     const std::vector<uint32_t> &request_modules_idx = mda.getRequestModules();
547     std::vector<std::string> request_modules;
548     for (size_t idx = 0; idx < request_modules_idx.size(); ++idx) {
549         request_modules.push_back(GetStringByStringId(EntityId(request_modules_idx[idx])));
550     }
551     module_record->SetRequestModules(request_modules);
552 
553     size_t regular_import_num = 0;
554     size_t local_export_num = 0;
555     mda.EnumerateModuleRecord([&](const ModuleTag &tag, uint32_t export_name_offset, uint32_t module_request_idx,
556                                   uint32_t import_name_offset, uint32_t local_name_offset) {
557         size_t request_num = request_modules.size();
558         ASSERT(request_num == 0 || module_request_idx < request_num);
559         std::string module_request = EMPTY_STR;
560         if (request_num != 0) {
561             module_request = request_modules[module_request_idx];
562         }
563         switch (tag) {
564             case ModuleTag::REGULAR_IMPORT: {
565                 ++regular_import_num;
566                 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
567                 std::string import_name = GetStringByStringId(EntityId(import_name_offset));
568                 module_record->AddImportEntry({module_request, import_name, local_name});
569                 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds a regular import: [" << module_request << ", "
570                                             << import_name << ", " << local_name << "]";
571                 break;
572             }
573             case ModuleTag::NAMESPACE_IMPORT: {
574                 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
575                 module_record->AddImportEntry({module_request, "*", local_name});
576                 LOG(DEBUG, DEFECT_SCAN_AUX)
577                     << "ModuleRecord adds a namespace import: [" << module_request << ", *, " << local_name << "]";
578                 break;
579             }
580             case ModuleTag::LOCAL_EXPORT: {
581                 ++local_export_num;
582                 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
583                 std::string export_name = GetStringByStringId(EntityId(export_name_offset));
584                 module_record->AddExportEntry({export_name, EMPTY_STR, EMPTY_STR, local_name});
585                 LOG(DEBUG, DEFECT_SCAN_AUX)
586                     << "ModuleRecord adds a local export: [" << export_name << ", null, null, " << local_name << "]";
587                 break;
588             }
589             case ModuleTag::INDIRECT_EXPORT: {
590                 std::string export_name = GetStringByStringId(EntityId(export_name_offset));
591                 std::string import_name = GetStringByStringId(EntityId(import_name_offset));
592                 module_record->AddExportEntry({export_name, module_request, import_name, EMPTY_STR});
593                 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds an indirect export: [" << export_name << ", "
594                                             << module_request << ", " << import_name << ", null]";
595                 break;
596             }
597             case ModuleTag::STAR_EXPORT: {
598                 module_record->AddExportEntry({EMPTY_STR, module_request, "*", EMPTY_STR});
599                 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds a start export: ["
600                                             << "null, " << module_request << "*, null]";
601                 break;
602             }
603             default: {
604                 UNREACHABLE();
605                 break;
606             }
607         }
608     });
609     module_record->SetRegularImportNum(regular_import_num);
610     module_record->SetLocalExportNum(local_export_num);
611 }
612 
613 void AbcFile::AddModuleRecord(std::string record_name, std::unique_ptr<ModuleRecord> &&module_record)
614 {
615     ASSERT(module_record_map_.find(record_name) == module_record_map_.end());
616     module_record_map_[record_name] = module_record.get();
617     module_record_list_.emplace_back(std::move(module_record));
618 }
619 
620 void AbcFile::InitializeAllDefinedFunction()
621 {
622     for (uint32_t id : panda_file_->GetClasses()) {
623         EntityId class_id {id};
624         if (panda_file_->IsExternal(class_id)) {
625             continue;
626         }
627 
628         panda_file::ClassDataAccessor cda {*panda_file_, class_id};
629         cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
630             if (!mda.IsExternal()) {
631                 std::string func_name = GetStringByStringId(mda.GetNameId());
632                 std::string record_name = "";
633                 std::string name = func_name;
634                 if (IsMergeAbc()) {
635                     record_name = std::string(utf::Mutf8AsCString(cda.GetName().data));
636                     record_name_set_.insert(record_name);
637                     func_name = record_name + func_name;
638                 }
639                 EntityId m_id = mda.GetMethodId();
640                 panda_file::CodeDataAccessor cda {*panda_file_, mda.GetCodeId().value()};
641                 uint32_t arg_count = cda.GetNumArgs();
642                 compiler::Graph *graph = GenerateFunctionGraph(mda, func_name);
643                 if (graph == nullptr) {
644                     return;
645                 }
646                 std::unique_ptr<Function> func =
647                     std::make_unique<Function>(record_name, func_name, m_id, arg_count, Graph(graph), this);
648                 if (func == nullptr) {
649                     LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
650                 }
651                 LOG(DEBUG, DEFECT_SCAN_AUX) << "Create a new function: " << func_name;
652                 if (IsMergeAbc()) {
653                     AddMergedDefinedFunction(std::move(func));
654                 } else {
655                     AddDefinedFunction(std::move(func));
656                 }
657             }
658         });
659     }
660 }
661 
662 void AbcFile::ExtractDefinedClassAndFunctionInfo()
663 {
664     if (IsMergeAbc()) {
665         ExtractMergedDefinedClassAndFunctionInfo();
666     } else {
667         ExtractSingleDefinedClassAndFunctionInfo();
668     }
669 }
670 
671 void AbcFile::ExtractMergedDefinedClassAndFunctionInfo()
672 {
673     for (auto &merge_def_func_pair : merge_def_func_map_) {
674         for (auto &func : merge_def_func_pair.second) {
675             ExtractMergedClassAndFunctionInfo(func.get());
676         }
677     }
678     std::unordered_set<const Function *> processed_func;
679     for (auto &merge_def_class_pair : merge_def_class_map_) {
680         for (auto &def_class : merge_def_class_pair.second) {
681             Function *def_func = def_class->GetDefiningFunction();
682             if (def_func != nullptr && processed_func.count(def_func) == 0) {
683                 ExtractClassInheritInfo(def_func);
684                 processed_func.insert(def_func);
685             }
686         }
687     }
688     for (auto &merge_def_func_pair : merge_def_func_map_) {
689         for (auto &func : merge_def_func_pair.second) {
690             ExtractFunctionCalleeInfo(func.get());
691         }
692     }
693 }
694 
695 void AbcFile::ExtractSingleDefinedClassAndFunctionInfo()
696 {
697     for (auto &func : def_func_list_) {
698         ExtractClassAndFunctionInfo(func.get());
699     }
700 
701     std::unordered_set<const Function *> processed_func;
702     for (auto &def_class : def_class_list_) {
703         Function *def_func = def_class->GetDefiningFunction();
704         if (def_func != nullptr && processed_func.count(def_func) == 0) {
705             ExtractClassInheritInfo(def_func);
706             processed_func.insert(def_func);
707         }
708     }
709 
710     for (auto &func : def_func_list_) {
711         ExtractFunctionCalleeInfo(func.get());
712     }
713 }
714 
715 void AbcFile::ExtractClassAndFunctionInfo(Function *func)
716 {
717     auto &graph = func->GetGraph();
718     graph.VisitAllInstructions([&](const Inst &inst) {
719         auto type = inst.GetType();
720         switch (type) {
721             case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
722             case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
723             case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
724                 auto def_class = ResolveDefineClassWithBufferInst(func, inst);
725                 AddDefinedClass(std::move(def_class));
726                 break;
727             }
728             case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
729             case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
730                 Function *def_func = ResolveDefineFuncInstCommon(func, inst);
731                 BuildFunctionDefineChain(func, def_func);
732                 break;
733             }
734             case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
735             case InstType::DEFINEMETHOD_IMM16_ID16_IMM8: {
736                 auto member_func = ResolveDefineFuncInstCommon(func, inst);
737                 BuildFunctionDefineChain(func, member_func);
738                 // resolve the class where it's defined
739                 ResolveDefineMethodInst(member_func, inst);
740                 break;
741             }
742             case InstType::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16: {
743                 ResolveDefineMethodWithBufferInst(func, inst);
744                 break;
745             }
746             default:
747                 break;
748         }
749     });
750 }
751 
752 void AbcFile::ExtractMergedClassAndFunctionInfo(Function *func)
753 {
754     auto &graph = func->GetGraph();
755     std::string record_name = func->GetRecordName();
756     graph.VisitAllInstructions([&](const Inst &inst) {
757         auto type = inst.GetType();
758         switch (type) {
759             case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
760             case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
761             case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
762                 auto def_class = ResolveDefineClassWithBufferInst(func, inst);
763                 AddMergedDefinedClass(std::move(def_class), record_name);
764                 break;
765             }
766             case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
767             case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
768                 Function *def_func = ResolveDefineFuncInstCommon(func, inst);
769                 BuildFunctionDefineChain(func, def_func);
770                 break;
771             }
772             case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
773             case InstType::DEFINEMETHOD_IMM16_ID16_IMM8: {
774                 auto member_func = ResolveDefineFuncInstCommon(func, inst);
775                 BuildFunctionDefineChain(func, member_func);
776                 // resolve the class where it's defined
777                 ResolveDefineMethodInst(member_func, inst);
778                 break;
779             }
780             case InstType::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16: {
781                 ResolveDefineMethodWithBufferInst(func, inst);
782                 break;
783             }
784             default:
785                 break;
786         }
787     });
788 }
789 
790 void AbcFile::ExtractClassInheritInfo(Function *func) const
791 {
792     auto &graph = func->GetGraph();
793     std::string record_name = func->GetRecordName();
794     graph.VisitAllInstructions([&](const Inst &inst) {
795         if (inst.GetType() != InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 &&
796             inst.GetType() != InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 &&
797             inst.GetType() != InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) {
798             return;
799         }
800 
801         Class *cur_class = GetClassByNameImpl(record_name + GetStringByInst(inst));
802         ASSERT(cur_class != nullptr);
803         Inst def_class_input1 = inst.GetInputInsts()[0];
804         auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(func, def_class_input1);
805         if (ret_ptr != nullptr && ret_type == ResolveType::CLASS_OBJECT) {
806             auto par_class = reinterpret_cast<const Class *>(ret_ptr);
807             cur_class->SetParentClass(par_class);
808             return;
809         }
810         size_t first_delim_idx = ret_sym.find_first_of(DELIM);
811         size_t last_delim_idx = ret_sym.find_last_of(DELIM);
812         std::string par_class_name = ret_sym;
813         std::string var_name = EMPTY_STR;
814         if (last_delim_idx != std::string::npos) {
815             par_class_name = ret_sym.substr(last_delim_idx + 1);
816             var_name = ret_sym.substr(0, first_delim_idx);
817             cur_class->SetParentClassName(record_name + par_class_name);
818         }
819         std::string record_name = func->GetRecordName();
820         if (ret_type == ResolveType::UNRESOLVED_MODULE) {
821             std::string imp_par_class_name = GetImportNameByLocalName(par_class_name, record_name);
822             if (!imp_par_class_name.empty()) {
823                 cur_class->SetParentClassName(record_name + imp_par_class_name);
824             }
825             std::string inter_name = var_name.empty() ? par_class_name : var_name;
826             std::string module_name = GetModuleNameByLocalName(inter_name, record_name);
827             if (!module_name.empty()) {
828                 cur_class->SetParClassExternalModuleName(module_name);
829             }
830         }
831         if (ret_type == ResolveType::UNRESOLVED_GLOBAL_VAR) {
832             cur_class->SetParentClassName(record_name + par_class_name);
833             var_name = var_name.empty() ? var_name : ret_sym.substr(0, last_delim_idx);
834             cur_class->SetParClassGlobalVarName(var_name);
835         }
836     });
837 }
838 
839 void AbcFile::ExtractFunctionCalleeInfo(Function *func)
840 {
841     auto &graph = func->GetGraph();
842     graph.VisitAllInstructions([&](const Inst &inst) {
843         std::unique_ptr<CalleeInfo> callee_info {nullptr};
844         switch (inst.GetType()) {
845             case InstType::CALLARG0_IMM8: {
846                 callee_info = ResolveCallInstCommon(func, inst);
847                 callee_info->SetCalleeArgCount(0);
848                 break;
849             }
850             case InstType::CALLARG1_IMM8_V8: {
851                 callee_info = ResolveCallInstCommon(func, inst, 1);
852                 callee_info->SetCalleeArgCount(1);
853                 break;
854             }
855             case InstType::CALLARGS2_IMM8_V8_V8: {
856                 constexpr int ARG_COUNT = 2;
857                 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT);
858                 callee_info->SetCalleeArgCount(ARG_COUNT);
859                 break;
860             }
861             case InstType::CALLARGS3_IMM8_V8_V8_V8: {
862                 constexpr int ARG_COUNT = 3;
863                 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT);
864                 callee_info->SetCalleeArgCount(ARG_COUNT);
865                 break;
866             }
867             case InstType::CALLRANGE_IMM8_IMM8_V8: {
868                 uint32_t arg_count = inst.GetImms()[1];
869                 callee_info = ResolveCallInstCommon(func, inst, arg_count);
870                 callee_info->SetCalleeArgCount(arg_count);
871                 break;
872             }
873             case InstType::WIDE_CALLRANGE_PREF_IMM16_V8: {
874                 uint32_t arg_count = inst.GetImms()[0];
875                 callee_info = ResolveCallInstCommon(func, inst, arg_count);
876                 callee_info->SetCalleeArgCount(arg_count);
877                 break;
878             }
879             case InstType::SUPERCALLSPREAD_IMM8_V8: {
880                 callee_info = ResolveCallInstCommon(func, inst, 1);
881                 break;
882             }
883             case InstType::APPLY_IMM8_V8_V8: {
884                 constexpr uint32_t FUNC_OBJ_INDEX = 2;
885                 callee_info = ResolveCallInstCommon(func, inst, FUNC_OBJ_INDEX);
886                 break;
887             }
888             case InstType::CALLTHIS0_IMM8_V8: {
889                 callee_info = ResolveCallInstCommon(func, inst, 1);
890                 callee_info->SetCalleeArgCount(0);
891                 break;
892             }
893             case InstType::CALLTHIS1_IMM8_V8_V8: {
894                 constexpr int ARG_COUNT = 1;
895                 // 1 represents the this pointer
896                 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
897                 callee_info->SetCalleeArgCount(ARG_COUNT);
898                 break;
899             }
900             case InstType::CALLTHIS2_IMM8_V8_V8_V8: {
901                 constexpr int ARG_COUNT = 2;
902                 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
903                 callee_info->SetCalleeArgCount(ARG_COUNT);
904                 break;
905             }
906             case InstType::CALLTHIS3_IMM8_V8_V8_V8_V8: {
907                 constexpr int ARG_COUNT = 3;
908                 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
909                 callee_info->SetCalleeArgCount(ARG_COUNT);
910                 break;
911             }
912             case InstType::CALLTHISRANGE_IMM8_IMM8_V8: {
913                 uint32_t arg_count = inst.GetImms()[1];
914                 callee_info = ResolveCallInstCommon(func, inst, arg_count + 1);
915                 callee_info->SetCalleeArgCount(arg_count);
916                 break;
917             }
918             case InstType::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
919                 uint32_t arg_count = inst.GetImms()[0];
920                 callee_info = ResolveCallInstCommon(func, inst, arg_count + 1);
921                 callee_info->SetCalleeArgCount(arg_count);
922                 break;
923             }
924             case InstType::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
925             case InstType::SUPERCALLARROWRANGE_IMM8_IMM8_V8: {
926                 uint32_t arg_count = inst.GetImms()[1];
927                 callee_info = ResolveSuperCallInst(func, inst);
928                 callee_info->SetCalleeArgCount(arg_count);
929                 break;
930             }
931             case InstType::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
932             case InstType::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8: {
933                 uint32_t arg_count = inst.GetImms()[0];
934                 callee_info = ResolveSuperCallInst(func, inst);
935                 callee_info->SetCalleeArgCount(arg_count);
936                 break;
937             }
938             default:
939                 break;
940         }
941         if (callee_info != nullptr) {
942             AddCalleeInfo(std::move(callee_info));
943         }
944     });
945 }
946 
947 void AbcFile::BuildFunctionDefineChain(Function *parent_func, Function *child_func) const
948 {
949     if (parent_func == nullptr || child_func == nullptr || child_func->GetParentFunction() == parent_func) {
950         return;
951     }
952     child_func->SetParentFunction(parent_func);
953     parent_func->AddDefinedFunction(child_func);
954 }
955 
956 void AbcFile::BuildClassAndMemberFuncRelation(Class *clazz, Function *member_func) const
957 {
958     if (clazz == nullptr || member_func == nullptr || member_func->GetClass() == clazz) {
959         return;
960     }
961     clazz->AddMemberFunction(member_func);
962     member_func->SetClass(clazz);
963 }
964 
965 void AbcFile::ExtractClassAndFunctionExportList()
966 {
967     if (IsMergeAbc()) {
968         ExtractMergedClassAndFunctionExportList();
969     } else {
970         ExtractSingleClassAndFunctionExportList();
971     }
972 }
973 
974 void AbcFile::ExtractMergedClassAndFunctionExportList()
975 {
976     if (merge_def_func_map_.empty()) {
977         return;
978     }
979 
980     for (auto &merge_def_func_pair : merge_def_func_map_) {
981         if (merge_def_func_pair.second.empty()) {
982             continue;
983         }
984         const Function *func_main = merge_def_func_pair.second[0].get();
985         auto &graph = func_main->GetGraph();
986         graph.VisitAllInstructions([&](const Inst &inst) {
987             auto type = inst.GetType();
988             if (type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16) {
989                 AddExportListForMerge(func_main, inst);
990             }
991         });
992     }
993 }
994 
995 void AbcFile::AddExportListForMerge(const Function *func_main, const Inst &inst)
996 {
997     [[maybe_unused]] auto type = inst.GetType();
998     ASSERT(type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16);
999 
1000     std::string record_name = func_main->GetRecordName();
1001     Inst st_module_input0 = inst.GetInputInsts()[0];
1002     switch (st_module_input0.GetType()) {
1003         case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1004         case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1005             auto export_func = ResolveDefineFuncInstCommon(func_main, st_module_input0);
1006             ASSERT(export_func != nullptr);
1007             if (merge_export_func_map_.find(record_name) == merge_export_func_map_.end()) {
1008                 merge_export_func_map_.emplace(record_name, std::vector<const Function *>());
1009             }
1010             merge_export_func_map_[record_name].push_back(export_func);
1011             break;
1012         }
1013         case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1014         case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1015         case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1016             Class *export_clazz = GetClassByNameImpl(record_name + GetStringByInst(st_module_input0));
1017             ASSERT(export_clazz != nullptr);
1018             if (merge_export_class_map_.find(record_name) == merge_export_class_map_.end()) {
1019                 merge_export_class_map_.emplace(record_name, std::vector<const Class *>());
1020             }
1021             merge_export_class_map_[record_name].push_back(export_clazz);
1022             break;
1023         }
1024         default:
1025             break;
1026     }
1027 }
1028 
1029 void AbcFile::ExtractSingleClassAndFunctionExportList()
1030 {
1031     if (!IsModule() || def_func_list_.empty()) {
1032         return;
1033     }
1034     const Function *func_main = def_func_list_[0].get();
1035     ASSERT(func_main->GetFunctionName() == ENTRY_FUNCTION_NAME);
1036     auto &graph = func_main->GetGraph();
1037     std::string record_name = func_main->GetRecordName();
1038     graph.VisitAllInstructions([&](const Inst &inst) {
1039         auto type = inst.GetType();
1040         if (type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16) {
1041             AddExportListForSingle(func_main, inst);
1042         }
1043     });
1044 }
1045 
1046 void AbcFile::AddExportListForSingle(const Function *func_main, const Inst &inst)
1047 {
1048     [[maybe_unused]] auto type = inst.GetType();
1049     ASSERT(type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16);
1050     Inst st_module_input0 = inst.GetInputInsts()[0];
1051     switch (st_module_input0.GetType()) {
1052         case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1053         case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1054             auto export_func = ResolveDefineFuncInstCommon(func_main, st_module_input0);
1055             ASSERT(export_func != nullptr);
1056             export_func_list_.push_back(export_func);
1057             break;
1058         }
1059         case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1060         case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1061         case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1062             Class *export_clazz = GetClassByNameImpl(GetStringByInst(st_module_input0));
1063             ASSERT(export_clazz != nullptr);
1064             export_class_list_.push_back(export_clazz);
1065             break;
1066         }
1067         default:
1068             break;
1069     }
1070 }
1071 
1072 compiler::Graph *AbcFile::GenerateFunctionGraph(const panda_file::MethodDataAccessor &mda, std::string_view func_name)
1073 {
1074     panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
1075     auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
1076     compiler::options.SetCompilerUseSafepoint(false);
1077     compiler::options.SetCompilerMaxBytecodeSize(bytecodeopt::MAX_BYTECODE_SIZE);
1078     compiler::Graph *graph = allocator_->New<compiler::Graph>(allocator_.get(), local_allocator_.get(), Arch::NONE,
1079                                                               method_ptr, &adapter, false, nullptr, true, true);
1080     if ((graph == nullptr) || !graph->RunPass<compiler::IrBuilder>()) {
1081         LOG(FATAL, DEFECT_SCAN_AUX) << "Cannot generate graph for function '" << func_name << "'";
1082     }
1083     return graph;
1084 }
1085 
1086 ResolveResult AbcFile::ResolveInstCommon(Function *func, Inst inst) const
1087 {
1088     auto type = inst.GetType();
1089     std::string record_name = func->GetRecordName();
1090     switch (type) {
1091         case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1092         case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1093             std::string func_name = record_name + GetStringByInst(inst);
1094             const Function *func = GetFunctionByName(func_name);
1095             ASSERT(func != nullptr);
1096             return std::make_tuple(func, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1097         }
1098         case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1099         case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1100         case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1101             std::string class_name = record_name + GetStringByInst(inst);
1102             const Class *clazz = GetClassByName(class_name);
1103             ASSERT(clazz != nullptr);
1104             return std::make_tuple(clazz, EMPTY_STR, ResolveType::CLASS_OBJECT);
1105         }
1106         case InstType::NEWOBJAPPLY_IMM8_V8:
1107         case InstType::NEWOBJAPPLY_IMM16_V8:
1108         case InstType::NEWOBJRANGE_IMM8_IMM8_V8:
1109         case InstType::NEWOBJRANGE_IMM16_IMM8_V8:
1110         case InstType::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
1111             Inst newobj_input0 = inst.GetInputInsts()[0];
1112             auto resolve_res = ResolveInstCommon(func, newobj_input0);
1113             return HandleNewObjInstResolveResultCommon(resolve_res);
1114         }
1115         case InstType::LDOBJBYNAME_IMM8_ID16:
1116         case InstType::LDOBJBYNAME_IMM16_ID16: {
1117             Inst ld_obj_input0 = inst.GetInputInsts()[0];
1118             auto resolve_res = ResolveInstCommon(func, ld_obj_input0);
1119             return HandleLdObjByNameInstResolveResult(inst, resolve_res, record_name);
1120         }
1121         case InstType::LDLEXVAR_IMM4_IMM4:
1122         case InstType::LDLEXVAR_IMM8_IMM8:
1123         case InstType::WIDE_LDLEXVAR_PREF_IMM16_IMM16: {
1124             auto p = GetStLexInstByLdLexInst({func, inst});
1125             if (p == std::nullopt) {
1126                 return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1127             }
1128             return ResolveInstCommon(p.value().first, p.value().second);
1129         }
1130         case InstType::STLEXVAR_IMM4_IMM4:
1131         case InstType::STLEXVAR_IMM8_IMM8:
1132         case InstType::WIDE_STLEXVAR_PREF_IMM16_IMM16: {
1133             Inst stlex_input0 = inst.GetInputInsts()[0];
1134             return ResolveInstCommon(func, stlex_input0);
1135         }
1136         case InstType::LDLOCALMODULEVAR_IMM8:
1137         case InstType::WIDE_LDLOCALMODULEVAR_PREF_IMM16: {
1138             size_t index = inst.GetImms()[0];
1139             auto module_record = GetModuleRecordByName(record_name);
1140             const std::string &export_name = module_record->GetExportNameByIndex(index);
1141             const Function *func = GetExportFunctionByExportName(export_name, record_name);
1142             if (func != nullptr) {
1143                 return std::make_tuple(func, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1144             }
1145             const Class *clazz = GetExportClassByExportName(export_name, record_name);
1146             if (clazz != nullptr) {
1147                 return std::make_tuple(clazz, EMPTY_STR, ResolveType::CLASS_OBJECT);
1148             }
1149             return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1150         }
1151         case InstType::LDEXTERNALMODULEVAR_IMM8:
1152         case InstType::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: {
1153             size_t index = inst.GetImms()[0];
1154             auto module_record = GetModuleRecordByName(func->GetRecordName());
1155             const std::string &inter_name = module_record->GetImportLocalNameByIndex(index);
1156             return std::make_tuple(nullptr, inter_name, ResolveType::UNRESOLVED_MODULE);
1157         }
1158         case InstType::GETMODULENAMESPACE_IMM8:
1159         case InstType::WIDE_GETMODULENAMESPACE_PREF_IMM16: {
1160             size_t index = inst.GetImms()[0];
1161             auto module_record = GetModuleRecordByName(func->GetRecordName());
1162             const std::string &str = module_record->GetImportNamespaceNameByIndex(index);
1163             return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_MODULE);
1164         }
1165         case InstType::LDGLOBAL: {
1166             // TODO(wangyantian): load a specific global variable, namely 'globalThis'
1167             return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1168         }
1169         case InstType::LDGLOBALVAR_IMM16_ID16:
1170         case InstType::TRYLDGLOBALBYNAME_IMM8_ID16:
1171         case InstType::TRYLDGLOBALBYNAME_IMM16_ID16: {
1172             std::string str = GetStringByInst(inst);
1173             auto p = GetStGlobalInstByLdGlobalInst({func, inst});
1174             if (p == std::nullopt) {
1175                 return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_GLOBAL_VAR);
1176             }
1177             auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(p.value().first, p.value().second);
1178             if (ret_ptr != nullptr) {
1179                 return std::make_tuple(ret_ptr, str, ret_type);
1180             }
1181             return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_GLOBAL_VAR);
1182         }
1183         case InstType::TRYSTGLOBALBYNAME_IMM8_ID16:
1184         case InstType::TRYSTGLOBALBYNAME_IMM16_ID16:
1185         case InstType::STGLOBALVAR_IMM16_ID16:
1186         case InstType::STCONSTTOGLOBALRECORD_IMM16_ID16:
1187         case InstType::STTOGLOBALRECORD_IMM16_ID16: {
1188             Inst stglobal_input0 = inst.GetInputInsts()[0];
1189             return ResolveInstCommon(func, stglobal_input0);
1190         }
1191         case InstType::OPCODE_PHI: {
1192             // TODO: only the next unvisited path is considered for now, what about other paths?
1193             // TODO: when all inputs of the phi instruction contain a path to the phi instruction itself,
1194             //  the current solution still causes infinite recursion and stack overflow. However, this case
1195             //  should not occur in real-world applications. However, the following part needs to be redesigned
1196             //  when encountering such scenarios.
1197             auto phi_input_idx = func->GetAndUpdateToVisitInputForInst(inst);
1198             return ResolveInstCommon(func, inst.GetInputInsts()[phi_input_idx]);
1199         }
1200         // don't deal with the situation that func obj comes from parameter or the output of another call inst
1201         default: {
1202             return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1203         }
1204     }
1205 }
1206 
1207 ResolveResult AbcFile::HandleLdObjByNameInstResolveResult(const Inst &ldobjbyname_inst,
1208                                                           const ResolveResult &resolve_res,
1209                                                           const std::string record_name) const
1210 {
1211     auto &[ret_ptr, ret_sym, ret_type] = resolve_res;
1212     std::string name = GetStringByInst(ldobjbyname_inst);
1213     switch (ret_type) {
1214         case ResolveType::UNRESOLVED_MODULE:
1215         case ResolveType::UNRESOLVED_GLOBAL_VAR: {
1216             return std::make_tuple(nullptr, ret_sym + "." + name, ret_type);
1217         }
1218         case ResolveType::FUNCTION_OBJECT: {
1219             ASSERT(ret_ptr != nullptr);
1220             if (name == CALL || name == APPLY) {
1221                 return std::make_tuple(ret_ptr, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1222             }
1223             return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1224         }
1225         case ResolveType::CLASS_OBJECT:
1226         case ResolveType::CLASS_INSTANCE: {
1227             ASSERT(ret_ptr != nullptr);
1228             // TODO(wangyantian): distinguish static func from member func in a class
1229             const void *member_func =
1230                 reinterpret_cast<const Class *>(ret_ptr)->GetMemberFunctionByName(record_name + name);
1231             if (member_func != nullptr) {
1232                 return std::make_tuple(member_func, name, ResolveType::FUNCTION_OBJECT);
1233             }
1234             return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1235         }
1236         default: {
1237             return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1238         }
1239     }
1240 }
1241 
1242 ResolveResult AbcFile::HandleNewObjInstResolveResultCommon(const ResolveResult &resolve_res) const
1243 {
1244     auto &[ret_ptr, ret_sym, ret_type] = resolve_res;
1245     switch (ret_type) {
1246         case ResolveType::CLASS_OBJECT: {
1247             ASSERT(ret_ptr != nullptr);
1248             return std::make_tuple(ret_ptr, EMPTY_STR, ResolveType::CLASS_INSTANCE);
1249         }
1250         case ResolveType::UNRESOLVED_GLOBAL_VAR:
1251         case ResolveType::UNRESOLVED_MODULE: {
1252             return std::make_tuple(nullptr, ret_sym, ret_type);
1253         }
1254         default: {
1255             return std::make_tuple(nullptr, ret_sym, ResolveType::UNRESOLVED_OTHER);
1256         }
1257     }
1258 }
1259 
1260 Function *AbcFile::ResolveDefineFuncInstCommon(const Function *func, const Inst &def_func_inst) const
1261 {
1262     std::string record_name = func->GetRecordName();
1263     std::string def_func_name = record_name + GetStringByInst(def_func_inst);
1264     Function *def_func = GetFunctionByNameImpl(def_func_name);
1265     ASSERT(def_func != nullptr);
1266     return def_func;
1267 }
1268 
1269 std::unique_ptr<Class> AbcFile::ResolveDefineClassWithBufferInst(Function *func, const Inst &define_class_inst) const
1270 {
1271     auto imms = define_class_inst.GetImms();
1272     auto m_id = EntityId(imms[1]);
1273     std::string record_name = func->GetRecordName();
1274     std::string class_name = record_name + GetStringByMethodId(m_id);
1275     std::unique_ptr<Class> def_class = std::make_unique<Class>(class_name, record_name, this, func);
1276     if (def_class == nullptr) {
1277         LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1278     }
1279     LOG(DEBUG, DEFECT_SCAN_AUX) << "Create a new class: " << class_name;
1280     func->AddDefinedClass(def_class.get());
1281 
1282     // handle ctor of the class
1283     std::string ctor_name = record_name + GetStringByInst(define_class_inst);
1284     HandleMemberFunctionFromClassBuf(ctor_name, func, def_class.get());
1285 
1286     auto literal_array_id = EntityId(imms[2]);
1287     panda_file::LiteralDataAccessor lit_array_accessor(*panda_file_, panda_file_->GetLiteralArraysId());
1288     lit_array_accessor.EnumerateLiteralVals(
1289         literal_array_id, [&](const panda_file::LiteralDataAccessor::LiteralValue &value, const LiteralTag &tag) {
1290             if (tag == LiteralTag::METHOD || tag == panda_file::LiteralTag::GETTER ||
1291                 tag == panda_file::LiteralTag::SETTER || tag == LiteralTag::GENERATORMETHOD ||
1292                 tag == LiteralTag::ASYNCGENERATORMETHOD) {
1293                 auto method_id = EntityId(std::get<uint32_t>(value));
1294                 std::string member_func_name = record_name + GetStringByMethodId(method_id);
1295                 HandleMemberFunctionFromClassBuf(member_func_name, func, def_class.get());
1296             }
1297         });
1298 
1299     return def_class;
1300 }
1301 
1302 void AbcFile::ResolveDefineMethodWithBufferInst(Function *func, const Inst &define_class_inst) const
1303 {
1304     auto imms = define_class_inst.GetImms();
1305     auto literal_array_id = EntityId(imms[1]);
1306     std::string record_name = func->GetRecordName();
1307 
1308     panda_file::LiteralDataAccessor lit_array_accessor(*panda_file_, panda_file_->GetLiteralArraysId());
1309     lit_array_accessor.EnumerateLiteralVals(
1310         literal_array_id, [&](const panda_file::LiteralDataAccessor::LiteralValue &value, const LiteralTag &tag) {
1311             if (tag == LiteralTag::METHOD || tag == panda_file::LiteralTag::GETTER ||
1312                 tag == panda_file::LiteralTag::SETTER || tag == LiteralTag::GENERATORMETHOD ||
1313                 tag == LiteralTag::ASYNCGENERATORMETHOD) {
1314                 auto method_id = EntityId(std::get<uint32_t>(value));
1315                 std::string member_func_name = record_name + GetStringByMethodId(method_id);
1316                 Class *def_class = GetClassFromMemberFunctionName(member_func_name);
1317                 if (def_class == nullptr) {
1318                     LOG(ERROR, DEFECT_SCAN_AUX) << "Unable to find class for private property '" <<
1319                                                    member_func_name << "'";
1320                     return;
1321                 }
1322                 HandleMemberFunctionFromClassBuf(member_func_name, func, def_class);
1323             }
1324         });
1325 }
1326 
1327 Class *AbcFile::GetClassFromMemberFunctionName(const std::string &member_func_name) const
1328 {
1329     // The character > indicates the instance function scope of a class
1330     // The character < indicates the static function scope of a class
1331     size_t pos = member_func_name.find_first_of("><");
1332     if (pos == std::string::npos) {
1333         return nullptr;
1334     }
1335     std::string processed_name = member_func_name.substr(0, pos);
1336     // Concatenate constructor prefixes
1337     // The character = represents the constructor scope of a class
1338     processed_name += '=';
1339 
1340     std::vector<std::shared_ptr<Class>> class_list = GetClassList();
1341     for (const auto &cls : class_list) {
1342         const std::string &class_name = cls->GetClassName();
1343         if (class_name.find(processed_name) == 0) {
1344             return cls.get();
1345         }
1346     }
1347 
1348     return nullptr;
1349 }
1350 
1351 std::unique_ptr<CalleeInfo> AbcFile::ResolveCallInstCommon(Function *func, const Inst &call_inst,
1352                                                            uint32_t func_obj_idx) const
1353 {
1354     std::unique_ptr<CalleeInfo> callee_info = std::make_unique<CalleeInfo>(call_inst, func);
1355     if (callee_info == nullptr) {
1356         LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1357     }
1358 
1359     Inst call_input0 = call_inst.GetInputInsts()[func_obj_idx];
1360     auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(func, call_input0);
1361     std::string record_name = func->GetRecordName();
1362     if (ret_ptr != nullptr && ret_type == ResolveType::FUNCTION_OBJECT) {
1363         auto callee = reinterpret_cast<const Function *>(ret_ptr);
1364         callee_info->SetCallee(callee);
1365     } else {
1366         size_t first_delim_idx = ret_sym.find_first_of(DELIM);
1367         size_t last_delim_idx = ret_sym.find_last_of(DELIM);
1368         std::string callee_name = ret_sym;
1369         std::string var_name = EMPTY_STR;
1370         if (first_delim_idx != std::string::npos) {
1371             callee_name = ret_sym.substr(last_delim_idx + 1);
1372             var_name = ret_sym.substr(0, first_delim_idx);
1373             callee_info->SetFunctionName(record_name + callee_name);
1374         }
1375         if (ret_type == ResolveType::UNRESOLVED_MODULE) {
1376             std::string imp_callee_name = GetImportNameByLocalName(callee_name, record_name);
1377             if (!imp_callee_name.empty()) {
1378                 callee_info->SetFunctionName(record_name + imp_callee_name);
1379             }
1380             std::string inter_name = var_name.empty() ? callee_name : var_name;
1381             std::string module_name = GetModuleNameByLocalName(inter_name, record_name);
1382             if (!module_name.empty()) {
1383                 callee_info->SetExternalModuleName(module_name);
1384             }
1385         } else if (ret_type == ResolveType::UNRESOLVED_GLOBAL_VAR) {
1386             callee_info->SetFunctionName(record_name + callee_name);
1387             var_name = var_name.empty() ? var_name : ret_sym.substr(0, last_delim_idx);
1388             callee_info->SetGlobalVarName(var_name);
1389         }
1390     }
1391     func->AddCalleeInfo(callee_info.get());
1392     return callee_info;
1393 }
1394 
1395 std::unique_ptr<CalleeInfo> AbcFile::ResolveSuperCallInst(Function *func, const Inst &call_inst) const
1396 {
1397     std::unique_ptr<CalleeInfo> callee_info = std::make_unique<CalleeInfo>(call_inst, func);
1398     if (callee_info == nullptr) {
1399         LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1400     }
1401     const Class *clazz = func->GetClass();
1402     if (clazz != nullptr && clazz->GetParentClass() != nullptr) {
1403         const std::string &parent_ctor_name = clazz->GetParentClass()->GetClassName();
1404         const Function *parent_ctor = GetFunctionByName(parent_ctor_name);
1405         ASSERT(parent_ctor != nullptr);
1406         callee_info->SetCallee(parent_ctor);
1407     }
1408     // TODO(wangyantian): deal with situations when above if doesn't hold
1409     func->AddCalleeInfo(callee_info.get());
1410     return callee_info;
1411 }
1412 
1413 void AbcFile::ResolveDefineMethodInst(Function *member_func, const Inst &define_method_inst)
1414 {
1415     std::string record_name = member_func->GetRecordName();
1416     Inst def_method_input0 = define_method_inst.GetInputInsts()[0];
1417     if ((def_method_input0.GetType() == InstType::LDOBJBYNAME_IMM8_ID16 ||
1418          def_method_input0.GetType() == InstType::LDOBJBYNAME_IMM16_ID16) &&
1419         GetStringByInst(def_method_input0) == PROTOTYPE) {
1420         Inst ld_obj_input0 = def_method_input0.GetInputInsts()[0];
1421         if (ld_obj_input0.GetType() == InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 ||
1422             ld_obj_input0.GetType() == InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 ||
1423             ld_obj_input0.GetType() == InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) {
1424             auto clazz = GetClassByNameImpl(record_name + GetStringByInst(ld_obj_input0));
1425             if (clazz != nullptr) {
1426                 BuildClassAndMemberFuncRelation(clazz, member_func);
1427             }
1428         }
1429     }
1430 }
1431 
1432 void AbcFile::HandleMemberFunctionFromClassBuf(const std::string &func_name, Function *def_func, Class *def_class) const
1433 {
1434     Function *member_func = GetFunctionByNameImpl(func_name);
1435     ASSERT(member_func != nullptr);
1436     BuildFunctionDefineChain(def_func, member_func);
1437     BuildClassAndMemberFuncRelation(def_class, member_func);
1438 }
1439 
1440 void AbcFile::AddDefinedClass(std::shared_ptr<Class> &&def_class)
1441 {
1442     auto &class_name = def_class->GetClassName();
1443     ASSERT(def_class_map_.find(class_name) == def_class_map_.end());
1444     def_class_map_[class_name] = def_class.get();
1445     def_class_list_.emplace_back(std::move(def_class));
1446 }
1447 
1448 void AbcFile::AddMergedDefinedClass(std::shared_ptr<Class> &&def_class, std::string record_name)
1449 {
1450     auto &class_name = def_class->GetClassName();
1451     ASSERT(def_class_map_.find(class_name) == def_class_map_.end());
1452     def_class_map_[class_name] = def_class.get();
1453     if (merge_def_class_map_.find(record_name) == merge_def_class_map_.end()) {
1454         merge_def_class_map_.emplace(record_name, std::vector<std::shared_ptr<Class>>());
1455     }
1456     merge_def_class_map_[record_name].push_back(def_class);
1457     merged_def_class_list_.push_back(def_class);
1458 }
1459 
1460 void AbcFile::AddDefinedFunction(std::shared_ptr<Function> &&def_func)
1461 {
1462     const std::string &func_name = def_func->GetFunctionName();
1463     ASSERT(def_func_map_.find(func_name) == def_func_map_.end());
1464     def_func_map_[func_name] = def_func.get();
1465     if (func_name != ENTRY_FUNCTION_NAME) {
1466         def_func_list_.emplace_back(std::move(def_func));
1467     } else {
1468         def_func_list_.insert(def_func_list_.begin(), std::move(def_func));
1469     }
1470 }
1471 
1472 void AbcFile::AddMergedDefinedFunction(std::shared_ptr<Function> &&def_func)
1473 {
1474     const std::string &record_name = def_func->GetRecordName();
1475     const std::string &func_name = def_func->GetFunctionName();
1476     ASSERT(def_func_map_.find(func_name) == def_func_map_.end());
1477     def_func_map_[func_name] = def_func.get();
1478     merged_def_func_list_.push_back(def_func);
1479     if (merge_def_func_map_.find(record_name) == merge_def_func_map_.end()) {
1480         merge_def_func_map_.emplace(record_name, std::vector<std::shared_ptr<Function>>());
1481     }
1482 
1483     if (func_name.find(ENTRY_FUNCTION_NAME) == std::string::npos) {
1484         merge_def_func_map_[record_name].push_back(def_func);
1485     } else {
1486         merge_def_func_map_[record_name].insert(merge_def_func_map_[record_name].begin(), def_func);
1487     }
1488 }
1489 
1490 void AbcFile::AddCalleeInfo(std::unique_ptr<CalleeInfo> &&callee_info)
1491 {
1492     callee_info_list_.emplace_back(std::move(callee_info));
1493 }
1494 
1495 Function *AbcFile::GetFunctionByNameImpl(std::string_view func_name) const
1496 {
1497     auto iter = def_func_map_.find(std::string(func_name));
1498     if (iter != def_func_map_.end()) {
1499         return iter->second;
1500     }
1501     return nullptr;
1502 }
1503 
1504 const ModuleRecord *AbcFile::GetModuleRecordByName(std::string record_name) const
1505 {
1506     if (!IsMergeAbc()) {
1507         record_name = std::string(MODULE_CLASS);
1508     }
1509 
1510     auto iter = module_record_map_.find(record_name);
1511     if (iter != module_record_map_.end()) {
1512         return iter->second;
1513     }
1514     return nullptr;
1515 }
1516 
1517 Class *AbcFile::GetClassByNameImpl(std::string_view class_name) const
1518 {
1519     auto iter = def_class_map_.find(std::string(class_name));
1520     if (iter != def_class_map_.end()) {
1521         return iter->second;
1522     }
1523     return nullptr;
1524 }
1525 
1526 std::string AbcFile::GetStringByMethodId(EntityId method_id) const
1527 {
1528     panda_file::MethodDataAccessor mda {*panda_file_, method_id};
1529     return GetStringByStringId(mda.GetNameId());
1530 }
1531 
1532 std::string AbcFile::GetStringByStringId(EntityId string_id) const
1533 {
1534     StringData sd = panda_file_->GetStringData(string_id);
1535     // TODO(wangyantian): what if sd.is_ascii equals false?
1536     return std::string(utf::Mutf8AsCString(sd.data));
1537 }
1538 }  // namespace panda::defect_scan_aux
1539