• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 "emit-item.h"
17 
18 namespace panda::pandasm {
19 using panda::panda_file::MethodItem;
20 
21 std::mutex EmitFunctionsJob::mutex_;
22 
23 template <class T>
Find(const T & map,typename T::key_type key)24 typename T::mapped_type Find(const T &map, typename T::key_type key)
25 {
26     auto res = map.find(key);
27     ASSERT(res != map.end());
28     return res->second;
29 }
30 
Schedule()31 void EmitFunctionsQueue::Schedule()
32 {
33     ASSERT(jobsCount_ == 0);
34     std::unique_lock<std::mutex> lock(m_);
35 
36     for (auto prog : progs_) {
37         auto *fileJob = new EmitFunctionsJob(items_, *prog, emit_debug_info_, entities_);
38         jobs_.push_back(fileJob);
39         jobsCount_++;
40     }
41 
42     lock.unlock();
43     jobsAvailable_.notify_all();
44 }
45 
Run()46 bool EmitFunctionsJob::Run()
47 {
48     return EmitFunctions(entities_, emit_debug_info_);
49 }
50 
EmitFunctions(const panda::pandasm::AsmEmitter::AsmEntityCollections & entities,bool emit_debug_info)51 bool EmitFunctionsJob::EmitFunctions(const panda::pandasm::AsmEmitter::AsmEntityCollections &entities,
52     bool emit_debug_info)
53 {
54     for (const auto &f : program_.function_table) {
55         const auto &[name, func] = f;
56 
57         if (func.metadata->IsForeign()) {
58             continue;
59         }
60 
61         auto emitter = BytecodeEmitter {};
62         auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
63         if (!func.Emit(emitter, method, entities.method_items, entities.field_items, entities.class_items,
64                        entities.string_items, entities.literalarray_items)) {
65             std::unique_lock<std::mutex> lock(mutex_);
66             AsmEmitter::SetLastError("Internal error during emitting function: " + func.name);
67             return false;
68         }
69 
70         auto *code = method->GetCode();
71         code->SetNumVregs(func.regs_num);
72         code->SetNumArgs(func.GetParamsNum());
73 
74         auto num_ins = static_cast<size_t>(
75             std::count_if(func.ins.begin(), func.ins.end(), [](auto &it) { return it->opcode != Opcode::INVALID; }));
76         code->SetNumInstructions(num_ins);
77 
78         auto *bytes = code->GetInstructions();
79         auto status = emitter.Build(static_cast<std::vector<unsigned char> *>(bytes));
80         if (status != BytecodeEmitter::ErrorCode::SUCCESS) {
81             std::unique_lock<std::mutex> lock(mutex_);
82             AsmEmitter::SetLastError("Internal error during emitting binary code, status=" +
83                 std::to_string(static_cast<int>(status)));
84             return false;
85         }
86         auto try_blocks = func.BuildTryBlocks(method, entities.class_items, *bytes);
87         for (auto &try_block : try_blocks) {
88             code->AddTryBlock(try_block);
89         }
90 
91         EmitDebugInfo(bytes, method, func, name, emit_debug_info);
92     }
93     return true;
94 }
95 
EmitDebugInfo(const std::vector<uint8_t> * bytes,const panda_file::MethodItem * method,const Function & func,const std::string & name,bool emit_debug_info)96 void EmitFunctionsJob::EmitDebugInfo(const std::vector<uint8_t> *bytes, const panda_file::MethodItem *method,
97     const Function &func, const std::string &name, bool emit_debug_info)
98 {
99     auto *debug_info = method->GetDebugInfo();
100     if (debug_info == nullptr) {
101         return;
102     }
103 
104     auto *line_number_program = debug_info->GetLineNumberProgram();
105     auto *constant_pool = debug_info->GetConstantPool();
106 
107     std::string record_name = GetOwnerName(name);
108     std::string record_source_file;
109     if (!record_name.empty()) {
110         auto &rec = program_.record_table.find(record_name)->second;
111         record_source_file = rec.source_file;
112     }
113 
114     if (!func.source_file.empty() && func.source_file != record_source_file) {
115         if (!func.source_code.empty()) {
116             auto *source_code_item = items_.GetStringItem(func.source_code);
117             ASSERT(source_code_item->GetOffset() != 0);
118             line_number_program->EmitSetSourceCode(constant_pool, source_code_item);
119         }
120         auto *source_file_item = items_.GetStringItem(func.source_file);
121         ASSERT(source_file_item->GetOffset() != 0);
122         line_number_program->EmitSetFile(constant_pool, source_file_item);
123     }
124     func.BuildLineNumberProgram(debug_info, *bytes, &items_, constant_pool, emit_debug_info);
125 }
126 }