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 }