• 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 "abc_code_processor.h"
17 
18 namespace panda::abc2program {
19 
AbcCodeProcessor(panda_file::File::EntityId entity_id,Abc2ProgramEntityContainer & entity_container,panda_file::File::EntityId method_id,pandasm::Function & function)20 AbcCodeProcessor::AbcCodeProcessor(panda_file::File::EntityId entity_id, Abc2ProgramEntityContainer &entity_container,
21                                    panda_file::File::EntityId method_id, pandasm::Function &function)
22     : AbcFileEntityProcessor(entity_id, entity_container), method_id_(method_id), function_(function),
23       debug_info_extractor_(entity_container.GetDebugInfoExtractor())
24 {
25     code_data_accessor_ = std::make_unique<panda_file::CodeDataAccessor>(*file_, entity_id_);
26     code_converter_ = std::make_unique<AbcCodeConverter>(entity_container_);
27 }
28 
FillProgramData()29 void AbcCodeProcessor::FillProgramData()
30 {
31     FillFunctionRegsNum();
32     FillIns();
33     FillCatchBlocks();
34     AddLabels();
35     FillLocalVariableTable();
36 }
37 
AddLabels()38 void AbcCodeProcessor::AddLabels()
39 {
40     std::vector<pandasm::InsPtr> new_ins;
41     new_ins.reserve(function_.ins.size() + inst_idx_label_map_.size());
42 
43     size_t inserted_label_cnt = 0;
44     for (size_t i = 0; i <= function_.ins.size(); i++) {
45         if (inst_idx_label_map_.find(i) != inst_idx_label_map_.end()) {
46             new_ins.emplace_back(new pandasm::LabelIns(inst_idx_label_map_[i]));
47             inserted_label_cnt++;
48         }
49         // Update inst_pc_idx_map_ to fill function's local_variable_debug correctly
50         inst_pc_idx_map_[inst_idx_pc_map_[i]] += inserted_label_cnt;
51         if (i < function_.ins.size()) {
52             new_ins.emplace_back(std::move(function_.ins[i]));
53         }
54     }
55 
56     function_.ins.swap(new_ins);
57 }
58 
FillFunctionRegsNum()59 void AbcCodeProcessor::FillFunctionRegsNum()
60 {
61     function_.regs_num = code_data_accessor_->GetNumVregs();
62 }
63 
FillIns()64 void AbcCodeProcessor::FillIns()
65 {
66     FillInsWithoutLabels();
67     if (NeedToAddDummyEndIns()) {
68         AddDummyEndIns();
69     }
70     AddJumpLabels();
71     FillInsDebug();
72 }
73 
FillInsWithoutLabels()74 void AbcCodeProcessor::FillInsWithoutLabels()
75 {
76     ins_size_ = code_data_accessor_->GetCodeSize();
77     const uint8_t *ins_arr = code_data_accessor_->GetInstructions();
78     auto bc_ins = BytecodeInstruction(ins_arr);
79     const auto bc_ins_last = bc_ins.JumpTo(ins_size_);
80     uint32_t inst_pc = 0;
81     uint32_t inst_idx = 0;
82     uint32_t inst_cnt = 0;
83     while (bc_ins.GetAddress() != bc_ins_last.GetAddress()) {
84         inst_cnt++;
85         bc_ins = bc_ins.GetNext();
86     }
87     function_.ins.reserve(inst_cnt);
88     bc_ins = BytecodeInstruction(ins_arr);
89     while (bc_ins.GetAddress() != bc_ins_last.GetAddress()) {
90         pandasm::Ins *pa_ins = code_converter_->BytecodeInstructionToPandasmInstruction(bc_ins, method_id_);
91         if (pa_ins == nullptr) {
92             LOG(FATAL, ABC2PROGRAM) << "> Failed to convert Bytecode to Pandasm.";
93         }
94         /*
95          * Private field jump_inst_idx_vec_ store all jump inst idx in a pandasm::Function.
96          * For example, a pandasm::Function has 100 pandasm::Ins with only 4 jump pandasm::Ins.
97          * When we add label for jump target and add jump id for jump inst,
98          * we only need to enumerate the 4 jump pandasm::Ins which stored in jump_inst_idx_vec_,
99          * while no need to enumerate the whole 100 pandasm::Ins.
100          * It will improve our compile performance.
101         */
102         if (pa_ins->IsJump()) {
103             jump_inst_idx_vec_.emplace_back(inst_idx);
104         }
105         function_.ins.emplace_back(pa_ins);
106         inst_pc_idx_map_.emplace(inst_pc, inst_idx);
107         inst_idx_pc_map_.emplace(inst_idx, inst_pc);
108         inst_idx++;
109         inst_pc += bc_ins.GetSize();
110         bc_ins = bc_ins.GetNext();
111     }
112 }
113 
NeedToAddDummyEndIns() const114 bool AbcCodeProcessor::NeedToAddDummyEndIns() const
115 {
116     bool need_to_add_dummy_end_ins = false;
117     code_data_accessor_->EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) {
118         try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
119             uint32_t catch_end_pc = catch_block.GetHandlerPc() + catch_block.GetCodeSize();
120             if (catch_end_pc == ins_size_) {
121                 need_to_add_dummy_end_ins = true;
122             }
123             return true;
124         });
125         return true;
126     });
127     return need_to_add_dummy_end_ins;
128 }
129 
AddDummyEndIns()130 void AbcCodeProcessor::AddDummyEndIns()
131 {
132     uint32_t inst_idx = static_cast<uint32_t>(function_.ins.size());
133     inst_pc_idx_map_.emplace(ins_size_, inst_idx);
134     inst_idx_pc_map_.emplace(inst_idx, ins_size_);
135     AddLabel4InsAtIndex(inst_idx);
136 }
137 
GetInstIdxByInstPc(uint32_t inst_pc) const138 uint32_t AbcCodeProcessor::GetInstIdxByInstPc(uint32_t inst_pc) const
139 {
140     if (inst_pc_idx_map_.empty()) {
141         return 0;
142     }
143     auto it = inst_pc_idx_map_.find(inst_pc);
144     // Locate the end of ins list of current function
145     if (it == inst_pc_idx_map_.end()) {
146         return (inst_pc_idx_map_.rbegin()->second) + 1;
147     }
148     return it->second;
149 }
150 
GetInstPcByInstIdx(uint32_t inst_idx) const151 uint32_t AbcCodeProcessor::GetInstPcByInstIdx(uint32_t inst_idx) const
152 {
153     auto it = inst_idx_pc_map_.find(inst_idx);
154     ASSERT(it != inst_idx_pc_map_.end());
155     return it->second;
156 }
157 
AddJumpLabels() const158 void AbcCodeProcessor::AddJumpLabels() const
159 {
160     for (uint32_t jump_inst_idx : jump_inst_idx_vec_) {
161         pandasm::InsPtr &jump_pa_ins = function_.ins[jump_inst_idx];
162         AddJumpLabel4InsAtIndex(jump_inst_idx, jump_pa_ins);
163     }
164 }
165 
AddJumpLabel4InsAtIndex(uint32_t curr_inst_idx,pandasm::InsPtr & curr_pa_ins) const166 void AbcCodeProcessor::AddJumpLabel4InsAtIndex(uint32_t curr_inst_idx, pandasm::InsPtr &curr_pa_ins) const
167 {
168     uint32_t curr_inst_pc = GetInstPcByInstIdx(curr_inst_idx);
169     const int32_t jmp_offset = std::stoi(curr_pa_ins->Ids().at(0));
170     uint32_t dst_inst_pc = curr_inst_pc + jmp_offset;
171     uint32_t dst_inst_idx = GetInstIdxByInstPc(dst_inst_pc);
172     AddLabel4InsAtIndex(dst_inst_idx);
173     curr_pa_ins->SetId(0, inst_idx_label_map_.at(dst_inst_idx));
174 }
175 
FillCatchBlocks()176 void AbcCodeProcessor::FillCatchBlocks()
177 {
178     code_data_accessor_->EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) {
179         HandleTryBlock(try_block);
180         try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
181             HandleCatchBlock(catch_block);
182             return true;
183         });
184         return true;
185     });
186 }
187 
HandleTryBlock(panda_file::CodeDataAccessor::TryBlock & try_block)188 void AbcCodeProcessor::HandleTryBlock(panda_file::CodeDataAccessor::TryBlock &try_block)
189 {
190     curr_try_begin_inst_pc_ = try_block.GetStartPc();
191     curr_try_end_inst_pc_ = try_block.GetStartPc() + try_block.GetLength();
192     AddLabel4InsAtPc(curr_try_begin_inst_pc_);
193     AddLabel4InsAtPc(curr_try_end_inst_pc_);
194 }
195 
HandleCatchBlock(panda_file::CodeDataAccessor::CatchBlock & catch_block)196 void AbcCodeProcessor::HandleCatchBlock(panda_file::CodeDataAccessor::CatchBlock &catch_block)
197 {
198     curr_catch_begin_pc_ = catch_block.GetHandlerPc();
199     curr_catch_end_pc_ = catch_block.GetHandlerPc() + catch_block.GetCodeSize();
200     AddLabel4InsAtPc(curr_catch_begin_pc_);
201     AddLabel4InsAtPc(curr_catch_end_pc_);
202     pandasm::Function::CatchBlock pa_catch_block{};
203     FillCatchBlockLabels(pa_catch_block);
204     FillExceptionRecord(catch_block, pa_catch_block);
205     function_.catch_blocks.emplace_back(pa_catch_block);
206 }
207 
FillCatchBlockLabels(pandasm::Function::CatchBlock & pa_catch_block) const208 void AbcCodeProcessor::FillCatchBlockLabels(pandasm::Function::CatchBlock &pa_catch_block) const
209 {
210     pa_catch_block.try_begin_label = GetLabelNameAtPc(curr_try_begin_inst_pc_);
211     pa_catch_block.try_end_label = GetLabelNameAtPc(curr_try_end_inst_pc_);
212     pa_catch_block.catch_begin_label = GetLabelNameAtPc(curr_catch_begin_pc_);
213     pa_catch_block.catch_end_label = GetLabelNameAtPc(curr_catch_end_pc_);
214 }
215 
FillExceptionRecord(panda_file::CodeDataAccessor::CatchBlock & catch_block,pandasm::Function::CatchBlock & pa_catch_block) const216 void AbcCodeProcessor::FillExceptionRecord(panda_file::CodeDataAccessor::CatchBlock &catch_block,
217                                            pandasm::Function::CatchBlock &pa_catch_block) const
218 {
219     uint32_t class_idx = catch_block.GetTypeIdx();
220     if (class_idx == panda_file::INVALID_INDEX) {
221         pa_catch_block.exception_record = "";
222     } else {
223         const panda_file::File::EntityId class_id = file_->ResolveClassIndex(method_id_, class_idx);
224         pa_catch_block.exception_record = entity_container_.GetFullRecordNameById(class_id);
225     }
226 }
227 
AddLabel4InsAtIndex(uint32_t inst_idx) const228 void AbcCodeProcessor::AddLabel4InsAtIndex(uint32_t inst_idx) const
229 {
230     inst_idx_label_map_.emplace(inst_idx, AbcFileUtils::GetLabelNameByInstIdx(inst_idx));
231 }
232 
AddLabel4InsAtPc(uint32_t inst_pc) const233 void AbcCodeProcessor::AddLabel4InsAtPc(uint32_t inst_pc) const
234 {
235     uint32_t inst_idx = GetInstIdxByInstPc(inst_pc);
236     AddLabel4InsAtIndex(inst_idx);
237 }
238 
GetLabelNameAtPc(uint32_t inst_pc) const239 std::string AbcCodeProcessor::GetLabelNameAtPc(uint32_t inst_pc) const
240 {
241     uint32_t inst_idx = GetInstIdxByInstPc(inst_pc);
242     return AbcFileUtils::GetLabelNameByInstIdx(inst_idx);
243 }
244 
FillLocalVariableTable()245 void AbcCodeProcessor::FillLocalVariableTable()
246 {
247     const std::vector<panda_file::LocalVariableInfo>& variables =
248         debug_info_extractor_.GetLocalVariableTable(method_id_);
249 
250     for (const auto &variable : variables) {
251         uint32_t start_idx = GetInstIdxByInstPc(variable.start_offset);
252         uint32_t end_idx = GetInstIdxByInstPc(variable.end_offset);
253         uint32_t length = end_idx - start_idx;
254         panda::pandasm::debuginfo::LocalVariable local_var = {variable.name,
255                                                               variable.type,
256                                                               variable.type_signature,
257                                                               variable.reg_number,
258                                                               start_idx,
259                                                               length};
260         function_.local_variable_debug.push_back(local_var);
261     }
262 }
263 
FillInsDebug()264 void AbcCodeProcessor::FillInsDebug()
265 {
266     constexpr size_t DEFAULT_LINE = -1;
267     constexpr uint32_t DEFAULT_COLUMN = -1;
268     uint32_t line_idx = 0;
269     uint32_t column_idx = 0;
270     uint32_t offset_start = UINT_MAX;
271     uint32_t offset_end = UINT_MAX;
272     size_t line = DEFAULT_LINE;
273     uint32_t column = DEFAULT_COLUMN;
274     const std::vector<panda::panda_file::LineTableEntry>& line_table =
275         debug_info_extractor_.GetLineNumberTable(method_id_);
276     const std::vector<panda::panda_file::ColumnTableEntry>& column_table =
277         debug_info_extractor_.GetColumnNumberTable(method_id_);
278 
279     for (uint32_t inst_idx = 0; inst_idx < function_.ins.size(); inst_idx++) {
280         SkipToNextEntryIfNeeded(line_idx, offset_start, offset_end, inst_idx, line_table);
281         line = line_idx > 0 ? line_table[line_idx - 1].line : line;
282         function_.ins[inst_idx]->ins_debug.line_number = line;
283     }
284 
285     // Column table may be empty if all ins of current function has default column number
286     // The first entry of column table is the offset of the first ins for which column number differs from the default
287     offset_start = 0;
288     offset_end = column_table.size() > 0 ? column_table[0].offset : UINT_MAX;
289     for (uint32_t inst_idx = 0; inst_idx < function_.ins.size(); inst_idx++) {
290         SkipToNextEntryIfNeeded(column_idx, offset_start, offset_end, inst_idx, column_table);
291         column = column_idx > 0 ? column_table[column_idx - 1].column : column;
292         function_.ins[inst_idx]->ins_debug.column_number = column;
293     }
294 }
295 
296 template <typename T>
SkipToNextEntryIfNeeded(uint32_t & idx,uint32_t & offset_start,uint32_t & offset_end,uint32_t inst_idx,const T & table)297 void AbcCodeProcessor::SkipToNextEntryIfNeeded(uint32_t &idx,
298                                                uint32_t &offset_start,
299                                                uint32_t &offset_end,
300                                                uint32_t inst_idx,
301                                                const T &table)
302 {
303     uint32_t ins_offset = GetInstPcByInstIdx(inst_idx);
304     ASSERT(ins_offset < UINT_MAX);
305     while (idx < table.size() && (ins_offset < offset_start || ins_offset >= offset_end)) {
306         offset_start = table[idx].offset;
307         ++idx;
308         offset_end = idx < table.size() ? table[idx].offset : UINT_MAX;
309     }
310 }
311 
312 }  // namespace panda::abc2program
313