• 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 "program_dump.h"
17 #include "abc2program_log.h"
18 #include "common/abc_file_utils.h"
19 #include "dump_utils.h"
20 #include "os/file.h"
21 
22 namespace panda::abc2program {
23 
Dump(std::ostream & os,const pandasm::Program & program)24 void PandasmProgramDumper::Dump(std::ostream &os, const pandasm::Program &program)
25 {
26     program_ = &program;
27     os << std::flush;
28     DumpAbcFilePath(os);
29     DumpProgramLanguage(os);
30     DumpLiteralArrayTable(os);
31     DumpRecordTable(os);
32     DumpFunctionTable(os);
33     DumpStrings(os);
34 }
35 
SetAbcFilePath(const std::string & abc_file_path)36 void PandasmProgramDumper::SetAbcFilePath(const std::string &abc_file_path)
37 {
38     abc_file_path_ = abc_file_path;
39 }
40 
DumpAbcFilePath(std::ostream & os) const41 void PandasmProgramDumper::DumpAbcFilePath(std::ostream &os) const
42 {
43     if (abc_file_path_.empty()) {
44         return;
45     }
46     std::string file_abs_path = os::file::File::GetAbsolutePath(abc_file_path_).Value();
47     os << DUMP_TITLE_SOURCE_BINARY << file_abs_path << DUMP_CONTENT_DOUBLE_ENDL;
48 }
49 
DumpProgramLanguage(std::ostream & os) const50 void PandasmProgramDumper::DumpProgramLanguage(std::ostream &os) const
51 {
52     os << DUMP_TITLE_LANGUAGE;
53     if (program_->lang == panda::panda_file::SourceLang::ECMASCRIPT) {
54         os << DUMP_CONTENT_ECMASCRIPT;
55     } else {
56         os << DUMP_CONTENT_PANDA_ASSEMBLY;
57     }
58     os << DUMP_CONTENT_DOUBLE_ENDL;
59 }
60 
DumpLiteralArrayTable(std::ostream & os) const61 void PandasmProgramDumper::DumpLiteralArrayTable(std::ostream &os) const
62 {
63     os << DUMP_TITLE_SEPARATOR;
64     os << DUMP_TITLE_LITERALS;
65     os << DUMP_CONTENT_DOUBLE_ENDL;
66     auto it = program_->literalarray_table.begin();
67     auto end = program_->literalarray_table.end();
68     // In normalized mode, sort dump result of literal arrays before output.
69     if (is_normalized_) {
70         std::vector<std::string> literal_arrays;
71         for (; it != end; ++it) {
72             auto id = PandasmDumperUtils::GetLiteralArrayIdFromName(it->first);
73             auto lit_arr = SerializeLiteralArray(it->second, id);
74             lit_arr += DUMP_CONTENT_DOUBLE_ENDL;
75             literal_arrays.emplace_back(lit_arr);
76         }
77         std::sort(literal_arrays.begin(), literal_arrays.end());
78         for (auto &str : literal_arrays) {
79             os << str;
80         }
81     } else {
82         for (; it != end; ++it) {
83             os << it->first << DUMP_CONTENT_SPACE;
84             auto id = PandasmDumperUtils::GetLiteralArrayIdFromName(it->first);
85             os << SerializeLiteralArray(it->second, id);
86             os << DUMP_CONTENT_DOUBLE_ENDL;
87         }
88     }
89     os << DUMP_CONTENT_DOUBLE_ENDL;
90 }
91 
DumpRecordTable(std::ostream & os) const92 void PandasmProgramDumper::DumpRecordTable(std::ostream &os) const
93 {
94     os << DUMP_TITLE_SEPARATOR;
95     os << DUMP_TITLE_RECORDS;
96     os << DUMP_CONTENT_DOUBLE_ENDL;
97     for (const auto &it : program_->record_table) {
98         if (is_normalized_ && is_debug_ && it.first == SLOT_NUMBER_RECORD_NAME) {
99             continue;
100         }
101         DumpRecord(os, it.second);
102     }
103     os << DUMP_CONTENT_SINGLE_ENDL;
104 }
105 
DumpRecord(std::ostream & os,const pandasm::Record & record) const106 void PandasmProgramDumper::DumpRecord(std::ostream &os, const pandasm::Record &record) const
107 {
108     if (is_normalized_) {
109         if (AbcFileUtils::IsGlobalTypeName(record.name)) {
110             return;
111         }
112         if (AbcFileUtils::IsESTypeAnnotationName(record.name)) {
113             return;
114         }
115     }
116     os << DUMP_TITLE_RECORD << record.name;
117     if (DumpRecordMetaData(os, record)) {
118         DumpFieldList(os, record);
119     }
120     DumpRecordSourceFile(os, record);
121 }
122 
DumpRecordMetaData(std::ostream & os,const pandasm::Record & record) const123 bool PandasmProgramDumper::DumpRecordMetaData(std::ostream &os, const pandasm::Record &record) const
124 {
125     if (record.metadata->IsForeign()) {
126         os << DUMP_CONTENT_SPACE << DUMP_CONTENT_ATTR_EXTERNAL;
127         os << DUMP_CONTENT_SINGLE_ENDL;
128         return false;
129     }
130     return true;
131 }
132 
DumpFieldList(std::ostream & os,const pandasm::Record & record) const133 void PandasmProgramDumper::DumpFieldList(std::ostream &os, const pandasm::Record &record) const
134 {
135     os << DUMP_CONTENT_SPACE << DUMP_CONTENT_LEFT_CURLY_BRACKET << DUMP_CONTENT_SINGLE_ENDL;
136     for (const auto &it : record.field_list) {
137         DumpField(os, it);
138     }
139     os << DUMP_CONTENT_RIGHT_CURLY_BRACKET << DUMP_CONTENT_SINGLE_ENDL;
140 }
141 
DumpField(std::ostream & os,const pandasm::Field & field) const142 void PandasmProgramDumper::DumpField(std::ostream &os, const pandasm::Field &field) const
143 {
144     os << DUMP_CONTENT_TAB << field.type.GetPandasmName() << DUMP_CONTENT_SPACE << field.name;
145     DumpFieldMetaData(os, field);
146     os << DUMP_CONTENT_SINGLE_ENDL;
147 }
148 
DumpFieldMetaData(std::ostream & os,const pandasm::Field & field) const149 void PandasmProgramDumper::DumpFieldMetaData(std::ostream &os, const pandasm::Field &field) const
150 {
151     if (field.metadata->GetValue()) {
152         DumpScalarValue(os, *(field.metadata->GetValue()));
153     }
154 }
155 
DumpAnnotationData(std::ostream & os,const pandasm::AnnotationData & anno) const156 void PandasmProgramDumper::DumpAnnotationData(std::ostream &os, const pandasm::AnnotationData &anno) const
157 {
158     os << DUMP_CONTENT_SPACE << anno.GetName() << DUMP_CONTENT_SINGLE_ENDL;
159     for (const auto &element : anno.GetElements()) {
160         os << DUMP_CONTENT_SPACE << element.GetName();
161         if (element.GetValue()->IsArray()) {
162             DumpArrayValue(os, *(element.GetValue()->GetAsArray()));
163         } else {
164             DumpScalarValue(os, *(element.GetValue()->GetAsScalar()));
165         }
166     }
167 }
168 
DumpArrayValue(std::ostream & os,const pandasm::ArrayValue & array) const169 void PandasmProgramDumper::DumpArrayValue(std::ostream &os, const pandasm::ArrayValue &array) const
170 {
171     for (const auto &val : array.GetValues()) {
172         DumpScalarValue(os, val);
173     }
174 }
DumpScalarValue(std::ostream & os,const pandasm::ScalarValue & scalar) const175 void PandasmProgramDumper::DumpScalarValue(std::ostream &os, const pandasm::ScalarValue &scalar) const
176 {
177     switch (scalar.GetType()) {
178         case pandasm::Value::Type::U1:
179         case pandasm::Value::Type::I8:
180         case pandasm::Value::Type::U8:
181         case pandasm::Value::Type::I16:
182         case pandasm::Value::Type::U16:
183         case pandasm::Value::Type::I32:
184         case pandasm::Value::Type::U32:
185         case pandasm::Value::Type::I64:
186         case pandasm::Value::Type::U64:
187         case pandasm::Value::Type::STRING_NULLPTR: {
188             os << DUMP_CONTENT_SPACE << scalar.GetValue<uint64_t>();
189             break;
190         }
191         case pandasm::Value::Type::F32:
192             os << DUMP_CONTENT_SPACE << scalar.GetValue<float>();
193             break;
194         case pandasm::Value::Type::F64: {
195             os << DUMP_CONTENT_SPACE << scalar.GetValue<double>();
196             break;
197         }
198         case pandasm::Value::Type::STRING:
199         case pandasm::Value::Type::METHOD:
200         case pandasm::Value::Type::ENUM:
201         case pandasm::Value::Type::LITERALARRAY: {
202             if (!is_normalized_) {
203                 os << DUMP_CONTENT_SPACE << scalar.GetValue<std::string>();
204             } else {
205                 auto literal_array_id_name = scalar.GetValue<std::string>();
206                 auto it = program_->literalarray_table.find(literal_array_id_name);
207                 ASSERT(it != program_->literalarray_table.end());
208                 auto id = PandasmDumperUtils::GetLiteralArrayIdFromName(literal_array_id_name);
209                 os << DUMP_CONTENT_SPACE << SerializeLiteralArray(it->second, id);
210             }
211             break;
212         }
213         case pandasm::Value::Type::RECORD: {
214             pandasm::Type type = scalar.GetValue<pandasm::Type>();
215             os << DUMP_CONTENT_SPACE << type.GetComponentName() << DUMP_CONTENT_SPACE << type.GetName();
216             break;
217         }
218         case pandasm::Value::Type::ANNOTATION: {
219             DumpAnnotationData(os, scalar.GetValue<pandasm::AnnotationData>());
220             break;
221         }
222         default :
223             break;
224     }
225 }
226 
DumpRecordSourceFile(std::ostream & os,const pandasm::Record & record) const227 void PandasmProgramDumper::DumpRecordSourceFile(std::ostream &os, const pandasm::Record &record) const
228 {
229     os << DUMP_TITLE_RECORD_SOURCE_FILE << record.source_file << DUMP_CONTENT_DOUBLE_ENDL;
230 }
231 
DumpFunctionTable(std::ostream & os)232 void PandasmProgramDumper::DumpFunctionTable(std::ostream &os)
233 {
234     os << DUMP_TITLE_SEPARATOR;
235     os << DUMP_TITLE_METHODS;
236     os << DUMP_CONTENT_DOUBLE_ENDL;
237     for (const auto &it : program_->function_table) {
238         DumpFunction(os, it.second);
239     }
240 }
241 
DumpFunction(std::ostream & os,const pandasm::Function & function)242 void PandasmProgramDumper::DumpFunction(std::ostream &os, const pandasm::Function &function)
243 {
244     regs_num_ = function.regs_num;
245     DumpFunctionKind(os, function);
246     if (!is_normalized_ || !is_debug_) {
247         DumpFunctionAnnotations(os, function);
248     }
249     DumpFunctionHead(os, function);
250     DumpFunctionBody(os, function);
251 }
252 
DumpFunctionKind(std::ostream & os,const pandasm::Function & function) const253 void PandasmProgramDumper::DumpFunctionKind(std::ostream &os, const pandasm::Function &function) const
254 {
255     os << DUMP_TITLE_FUNCTION_KIND << PandasmDumperUtils::GetFunctionKindString(function.function_kind);
256     os << DUMP_CONTENT_SINGLE_ENDL;
257 }
258 
DumpFunctionAnnotations(std::ostream & os,const pandasm::Function & function) const259 void PandasmProgramDumper::DumpFunctionAnnotations(std::ostream &os, const pandasm::Function &function) const
260 {
261     for (auto &annotation : function.metadata->GetAnnotations()) {
262         DumpAnnotationData(os, annotation);
263     }
264     os << DUMP_CONTENT_SINGLE_ENDL;
265 }
266 
DumpFunctionHead(std::ostream & os,const pandasm::Function & function) const267 void PandasmProgramDumper::DumpFunctionHead(std::ostream &os, const pandasm::Function &function) const
268 {
269     os << DUMP_TITLE_FUNCTION;
270     DumpFunctionReturnType(os, function);
271     DumpFunctionName(os, function);
272     DumpFunctionParams(os, function);
273     os << DUMP_CONTENT_SPACE << DUMP_CONTENT_LEFT_CURLY_BRACKET << DUMP_CONTENT_SINGLE_ENDL;
274 }
275 
DumpFunctionReturnType(std::ostream & os,const pandasm::Function & function) const276 void PandasmProgramDumper::DumpFunctionReturnType(std::ostream &os, const pandasm::Function &function) const
277 {
278     os << function.return_type.GetPandasmName() << DUMP_CONTENT_SPACE;
279 }
280 
DumpFunctionName(std::ostream & os,const pandasm::Function & function) const281 void PandasmProgramDumper::DumpFunctionName(std::ostream &os, const pandasm::Function &function) const
282 {
283     os << function.name;
284 }
285 
DumpFunctionParams(std::ostream & os,const pandasm::Function & function) const286 void PandasmProgramDumper::DumpFunctionParams(std::ostream &os, const pandasm::Function &function) const
287 {
288     os << DUMP_CONTENT_LEFT_PARENTHESIS;
289     if (function.params.size() > 0) {
290         DumpFunctionParamAtIndex(os, function.params[0], 0);
291         for (size_t i = 1; i < function.params.size(); ++i) {
292             os << DUMP_CONTENT_COMMA << DUMP_CONTENT_SPACE;
293             DumpFunctionParamAtIndex(os, function.params[i], i);
294         }
295     }
296     os << DUMP_CONTENT_RIGHT_PARENTHESIS;
297 }
298 
DumpFunctionParamAtIndex(std::ostream & os,const pandasm::Function::Parameter & param,size_t idx) const299 void PandasmProgramDumper::DumpFunctionParamAtIndex(std::ostream &os,
300                                                     const pandasm::Function::Parameter &param,
301                                                     size_t idx) const
302 {
303     os << param.type.GetPandasmName() << DUMP_CONTENT_SPACE << DUMP_CONTENT_FUNCTION_PARAM_NAME_PREFIX << idx;
304 }
305 
DumpFunctionAttributes(std::ostream & os,const pandasm::Function & function) const306 void PandasmProgramDumper::DumpFunctionAttributes(std::ostream &os, const pandasm::Function &function) const
307 {
308     log::Unimplemented(__PRETTY_FUNCTION__);
309 }
310 
DumpFunctionBody(std::ostream & os,const pandasm::Function & function)311 void PandasmProgramDumper::DumpFunctionBody(std::ostream &os, const pandasm::Function &function)
312 {
313     DumpFunctionIns(os, function);
314     DumpFunctionCatchBlocks(os, function);
315     DumpFunctionDebugInfo(os, function);
316     os << "}" << DUMP_CONTENT_DOUBLE_ENDL;
317 }
318 
DumpFunctionIns(std::ostream & os,const pandasm::Function & function)319 void PandasmProgramDumper::DumpFunctionIns(std::ostream &os, const pandasm::Function &function)
320 {
321     if (is_normalized_) {
322         DumpNormalizedFunctionIns(os, function);
323     } else {
324         DumpOriginalFunctionIns(os, function);
325     }
326 }
327 
DumpOriginalFunctionIns(std::ostream & os,const pandasm::Function & function)328 void PandasmProgramDumper::DumpOriginalFunctionIns(std::ostream &os, const pandasm::Function &function)
329 {
330     for (const pandasm::Ins &pa_ins : function.ins) {
331         std::string insStr = pa_ins.ToString("", true, regs_num_);
332         os << DUMP_CONTENT_TAB << std::setw(LINE_WIDTH)
333            << std::left << insStr
334            << DUMP_CONTENT_LINE_NUMBER << pa_ins.ins_debug.line_number;
335         os << std::setw(COLUMN_WIDTH) << std::left << DUMP_CONTENT_SPACE
336            << DUMP_CONTENT_COLUMN_NUMBER << pa_ins.ins_debug.column_number
337            << DUMP_CONTENT_SINGLE_ENDL;
338     }
339 }
340 
DumpNormalizedFunctionIns(std::ostream & os,const pandasm::Function & function)341 void PandasmProgramDumper::DumpNormalizedFunctionIns(std::ostream &os, const pandasm::Function &function)
342 {
343     GetOriginalDumpIns(function);
344     GetInvalidOpLabelMap();
345     UpdateLabels4DumpIns(original_dump_ins_ptrs_, invalid_op_label_map_);
346     GetFinalDumpIns();
347     GetFinalLabelMap();
348     UpdateLabels4DumpIns(final_dump_ins_ptrs_, final_label_map_);
349     DumpFinalIns(os);
350 }
351 
GetOriginalDumpIns(const pandasm::Function & function)352 void PandasmProgramDumper::GetOriginalDumpIns(const pandasm::Function &function)
353 {
354     original_dump_ins_.clear();
355     original_dump_ins_ptrs_.clear();
356     original_ins_index_map_.clear();
357     for (const pandasm::Ins &pa_ins : function.ins) {
358         original_dump_ins_.emplace_back(PandasmDumperUtils::DeepCopyIns(pa_ins));
359     }
360     uint32_t idx = 0;
361     for (pandasm::Ins &pa_ins : original_dump_ins_) {
362         original_dump_ins_ptrs_.emplace_back(&pa_ins);
363         original_ins_index_map_[&pa_ins] = idx;
364         idx++;
365     }
366 }
367 
GetFinalDumpIns()368 void PandasmProgramDumper::GetFinalDumpIns()
369 {
370     final_dump_ins_ptrs_.clear();
371     final_ins_index_map_.clear();
372     uint32_t idx = 0;
373     for (pandasm::Ins *pa_ins : original_dump_ins_ptrs_) {
374         final_ins_index_map_[pa_ins] = idx;
375         if (pa_ins->opcode != pandasm::Opcode::INVALID) {
376             final_dump_ins_ptrs_.emplace_back(pa_ins);
377             idx++;
378         }
379     }
380 }
381 
DumpFinalIns(std::ostream & os)382 void PandasmProgramDumper::DumpFinalIns(std::ostream &os)
383 {
384     for (pandasm::Ins *pa_ins : final_dump_ins_ptrs_) {
385         if (PandasmDumperUtils::IsMatchLiteralId(*pa_ins)) {
386             ReplaceLiteralId4Ins(*pa_ins);
387         }
388         std::string insStr = pa_ins->ToString("", true, regs_num_);
389         os << DUMP_CONTENT_TAB << std::setw(LINE_WIDTH)
390            << std::left << insStr
391            << DUMP_CONTENT_LINE_NUMBER << pa_ins->ins_debug.line_number;
392         os << std::setw(COLUMN_WIDTH) << std::left << DUMP_CONTENT_SPACE
393            << DUMP_CONTENT_COLUMN_NUMBER << pa_ins->ins_debug.column_number
394            << DUMP_CONTENT_SINGLE_ENDL;
395     }
396 }
397 
GetInvalidOpLabelMap()398 void PandasmProgramDumper::GetInvalidOpLabelMap()
399 {
400     invalid_op_label_map_.clear();
401     size_t dump_ins_size = original_dump_ins_.size();
402     for (size_t i = 0; i < dump_ins_size; ++i) {
403         pandasm::Ins &curr_ins = original_dump_ins_[i];
404         if (curr_ins.opcode == pandasm::Opcode::INVALID) {
405             HandleInvalidopInsLabel(i, curr_ins);
406         }
407     }
408 }
409 
HandleInvalidopInsLabel(size_t invalid_op_idx,pandasm::Ins & invalid_op_ins)410 void PandasmProgramDumper::HandleInvalidopInsLabel(size_t invalid_op_idx, pandasm::Ins &invalid_op_ins)
411 {
412     if (!invalid_op_ins.set_label) {
413         return;
414     }
415     pandasm::Ins *nearest_valid_op_ins = GetNearestValidopIns4InvalidopIns(invalid_op_idx);
416     if (nearest_valid_op_ins == nullptr) {
417         return;
418     }
419     if (!nearest_valid_op_ins->set_label) {
420         // here, the invalid op ins and its nearest valid op ins has the same label
421         // the invalid op will be removed, so the label is still unique for each inst
422         nearest_valid_op_ins->label = invalid_op_ins.label;
423         nearest_valid_op_ins->set_label = true;
424     }
425     invalid_op_label_map_.emplace(invalid_op_ins.label, nearest_valid_op_ins->label);
426 }
427 
GetNearestValidopIns4InvalidopIns(size_t invalid_op_ins_idx)428 pandasm::Ins *PandasmProgramDumper::GetNearestValidopIns4InvalidopIns(size_t invalid_op_ins_idx)
429 {
430     size_t dump_ins_size = original_dump_ins_.size();
431     // search downwards
432     for (size_t i = invalid_op_ins_idx + 1; i < dump_ins_size; ++i) {
433         pandasm::Ins &curr_ins = original_dump_ins_[i];
434         if (curr_ins.opcode != pandasm::Opcode::INVALID) {
435             return &curr_ins;
436         }
437     }
438     // search upwards
439     for (size_t i = 0; i < invalid_op_ins_idx; ++i) {
440         pandasm::Ins &curr_ins = original_dump_ins_[invalid_op_ins_idx - i - 1];
441         if (curr_ins.opcode != pandasm::Opcode::INVALID) {
442             return &curr_ins;
443         }
444     }
445     return nullptr;
446 }
447 
UpdateLabels4DumpIns(std::vector<pandasm::Ins * > & dump_ins,const LabelMap & label_map) const448 void PandasmProgramDumper::UpdateLabels4DumpIns(std::vector<pandasm::Ins*> &dump_ins, const LabelMap &label_map) const
449 {
450     size_t dump_ins_size = dump_ins.size();
451     for (size_t i = 0; i < dump_ins_size; ++i) {
452         UpdateLabels4DumpInsAtIndex(i, dump_ins, label_map);
453     }
454 }
455 
UpdateLabels4DumpInsAtIndex(size_t idx,std::vector<pandasm::Ins * > & dump_ins,const LabelMap & label_map) const456 void PandasmProgramDumper::UpdateLabels4DumpInsAtIndex(size_t idx, std::vector<pandasm::Ins*> &dump_ins,
457                                                        const LabelMap &label_map) const
458 {
459     pandasm::Ins *curr_ins = dump_ins[idx];
460     std::string mapped_label = PandasmDumperUtils::GetMappedLabel(curr_ins->label, label_map);
461     if (mapped_label != "") {
462         curr_ins->label = mapped_label;
463     }
464     if (curr_ins->IsJump()) {
465         mapped_label = PandasmDumperUtils::GetMappedLabel(curr_ins->ids[0], label_map);
466         if (mapped_label != "") {
467             curr_ins->ids.clear();
468             curr_ins->ids.emplace_back(mapped_label);
469         }
470     }
471 }
472 
GetFinalLabelMap()473 void PandasmProgramDumper::GetFinalLabelMap()
474 {
475     final_label_map_.clear();
476     size_t dump_ins_size = final_dump_ins_ptrs_.size();
477     for (size_t i = 0; i < dump_ins_size; ++i) {
478         HandleFinalLabelAtIndex(i);
479     }
480 }
481 
HandleFinalLabelAtIndex(size_t idx)482 void PandasmProgramDumper::HandleFinalLabelAtIndex(size_t idx)
483 {
484     pandasm::Ins *curr_ins = final_dump_ins_ptrs_[idx];
485     std::string new_label_name = AbcFileUtils::GetLabelNameByInstIdx(idx);
486     if (curr_ins->set_label) {
487         final_label_map_.emplace(curr_ins->label, new_label_name);
488     } else {
489         curr_ins->label = new_label_name;
490         curr_ins->set_label = true;
491     }
492 }
493 
DumpFunctionCatchBlocks(std::ostream & os,const pandasm::Function & function) const494 void PandasmProgramDumper::DumpFunctionCatchBlocks(std::ostream &os, const pandasm::Function &function) const
495 {
496     if (is_normalized_) {
497         DumpNormalizedFunctionCatchBlocks(os, function);
498     } else {
499         DumpOriginalFunctionCatchBlocks(os, function);
500     }
501 }
502 
DumpOriginalFunctionCatchBlocks(std::ostream & os,const pandasm::Function & function) const503 void PandasmProgramDumper::DumpOriginalFunctionCatchBlocks(std::ostream &os,
504                                                            const pandasm::Function &function) const
505 {
506     for (const pandasm::Function::CatchBlock &catch_block : function.catch_blocks) {
507         DumpCatchBlock(os, catch_block);
508     }
509 }
510 
DumpNormalizedFunctionCatchBlocks(std::ostream & os,const pandasm::Function & function) const511 void PandasmProgramDumper::DumpNormalizedFunctionCatchBlocks(std::ostream &os,
512                                                              const pandasm::Function &function) const
513 {
514     std::vector<pandasm::Function::CatchBlock> catch_blocks;
515     for (const pandasm::Function::CatchBlock &catch_block : function.catch_blocks) {
516         catch_blocks.emplace_back(PandasmDumperUtils::DeepCopyCatchBlock(catch_block));
517     }
518     for (pandasm::Function::CatchBlock &catch_block : catch_blocks) {
519         UpdateCatchBlock(catch_block);
520     }
521     for (const pandasm::Function::CatchBlock &catch_block : catch_blocks) {
522         DumpCatchBlock(os, catch_block);
523     }
524 }
525 
UpdateCatchBlock(pandasm::Function::CatchBlock & catch_block) const526 void PandasmProgramDumper::UpdateCatchBlock(pandasm::Function::CatchBlock &catch_block) const
527 {
528     catch_block.try_begin_label = GetUpdatedCatchBlockLabel(catch_block.try_begin_label);
529     catch_block.try_end_label = GetUpdatedCatchBlockLabel(catch_block.try_end_label);
530     catch_block.catch_begin_label = GetUpdatedCatchBlockLabel(catch_block.catch_begin_label);
531     catch_block.catch_end_label = GetUpdatedCatchBlockLabel(catch_block.catch_end_label);
532 }
533 
GetUpdatedCatchBlockLabel(const std::string & orignal_label) const534 std::string PandasmProgramDumper::GetUpdatedCatchBlockLabel(const std::string &orignal_label) const
535 {
536     std::string mapped_label1 = PandasmDumperUtils::GetMappedLabel(orignal_label, invalid_op_label_map_);
537     if (mapped_label1 == "") {
538         return orignal_label;
539     }
540     std::string mapped_label2 = PandasmDumperUtils::GetMappedLabel(mapped_label1, final_label_map_);
541     if (mapped_label2 == "") {
542         return mapped_label1;
543     }
544     return mapped_label2;
545 }
546 
DumpCatchBlock(std::ostream & os,const pandasm::Function::CatchBlock & catch_block) const547 void PandasmProgramDumper::DumpCatchBlock(std::ostream &os, const pandasm::Function::CatchBlock &catch_block) const
548 {
549     if (catch_block.exception_record.empty()) {
550         os << DUMP_TITLE_CATCH_ALL << DUMP_CONTENT_SINGLE_ENDL;
551     } else {
552         os << DUMP_TITLE_CATCH << DUMP_CONTENT_SINGLE_ENDL;
553     }
554     os << DUMP_CONTENT_TAB << DUMP_CONTENT_TRY_BEGIN_LABEL
555        << catch_block.try_begin_label << DUMP_CONTENT_SINGLE_ENDL;
556     os << DUMP_CONTENT_TAB << DUMP_CONTENT_TRY_END_LABEL
557        << catch_block.try_end_label << DUMP_CONTENT_SINGLE_ENDL;
558     os << DUMP_CONTENT_TAB << DUMP_CONTENT_CATCH_BEGIN_LABEL
559        << catch_block.catch_begin_label << DUMP_CONTENT_SINGLE_ENDL;
560     if (!is_normalized_) {
561         os << DUMP_CONTENT_TAB << DUMP_CONTENT_CATCH_END_LABEL
562            << catch_block.catch_end_label << DUMP_CONTENT_SINGLE_ENDL;
563     }
564 }
565 
DumpFunctionDebugInfo(std::ostream & os,const pandasm::Function & function)566 void PandasmProgramDumper::DumpFunctionDebugInfo(std::ostream &os, const pandasm::Function &function)
567 {
568     if (function.local_variable_debug.empty()) {
569         return;
570     }
571     std::map<int32_t, panda::pandasm::debuginfo::LocalVariable> local_variable_table;
572     if (is_normalized_) {
573         UpdateLocalVarMap(function, local_variable_table);
574     } else {
575         for (const auto &variable_info : function.local_variable_debug) {
576             local_variable_table[variable_info.reg] = variable_info;
577         }
578     }
579 
580     os << DUMP_CONTENT_SINGLE_ENDL;
581     if (local_variable_table.empty()) {
582         return;
583     }
584 
585     os << DUMP_TITLE_LOCAL_VAR_TABLE;
586     os << DUMP_CONTENT_SINGLE_ENDL;
587     os << DUMP_CONTENT_LOCAL_VAR_TABLE;
588     for (const auto &iter : local_variable_table) {
589         const auto &variable_info = iter.second;
590         os << DUMP_CONTENT_TAB
591            << std::setw(START_WIDTH) << std::right << variable_info.start << DUMP_CONTENT_TRIPLE_SPACES;
592         os << std::setw(END_WIDTH) << std::right << variable_info.length << DUMP_CONTENT_DOUBLE_SPACES;
593         os << std::setw(REG_WIDTH) << std::right << variable_info.reg << DUMP_CONTENT_DOUBLE_SPACES;
594         os << std::setw(NAME_WIDTH)
595            << std::right << variable_info.name << DUMP_CONTENT_NONUPLE_SPACES << variable_info.signature;
596         if (!variable_info.signature_type.empty() && variable_info.signature_type != variable_info.signature) {
597             os << " (" << variable_info.signature_type << ")";
598         }
599         os << DUMP_CONTENT_SINGLE_ENDL;
600     }
601 }
602 
UpdateLocalVarMap(const pandasm::Function & function,std::map<int32_t,panda::pandasm::debuginfo::LocalVariable> & local_variable_table)603 void PandasmProgramDumper::UpdateLocalVarMap(const pandasm::Function &function,
604     std::map<int32_t, panda::pandasm::debuginfo::LocalVariable>& local_variable_table)
605 {
606     std::unordered_map<uint32_t, uint32_t> original_to_final_index_map_;
607     uint32_t max_original_idx = 0;
608     uint32_t max_final_idx = 0;
609     for (const auto &[key, value] : original_ins_index_map_) {
610         uint32_t final_idx = final_ins_index_map_[key];
611         original_to_final_index_map_[value] = final_idx;
612         if (value > max_original_idx) {
613             max_original_idx = value;
614             max_final_idx = final_idx;
615         }
616     }
617     original_to_final_index_map_[max_original_idx + 1] = max_final_idx;
618 
619     for (const auto &variable_info : function.local_variable_debug) {
620         uint32_t original_start = variable_info.start;
621         uint32_t original_end = variable_info.length + variable_info.start;
622         uint32_t new_start = original_to_final_index_map_[original_start];
623         uint32_t new_length = original_to_final_index_map_[original_end] - new_start;
624         panda::pandasm::debuginfo::LocalVariable local_var = {variable_info.name,
625                                                               variable_info.signature,
626                                                               variable_info.signature_type,
627                                                               variable_info.reg,
628                                                               new_start,
629                                                               new_length};
630         local_variable_table[variable_info.reg] = local_var;
631     }
632 }
633 
DumpStrings(std::ostream & os) const634 void PandasmProgramDumper::DumpStrings(std::ostream &os) const
635 {
636     if (is_normalized_) {
637         return;
638     }
639     os << DUMP_TITLE_SEPARATOR;
640     os << DUMP_TITLE_STRING;
641     for (const std::string &str : program_->strings) {
642         os << str << DUMP_CONTENT_SINGLE_ENDL;
643     }
644 }
645 
ReplaceLiteralId4Ins(pandasm::Ins & pa_ins) const646 void PandasmProgramDumper::ReplaceLiteralId4Ins(pandasm::Ins &pa_ins) const
647 {
648     size_t idx = PandasmDumperUtils::GetLiteralIdIndex4Ins(pa_ins);
649     std::string id_str = pa_ins.ids[idx];
650     auto it = program_->literalarray_table.find(id_str);
651     ASSERT(it != program_->literalarray_table.end());
652     const pandasm::LiteralArray &literal_array = it->second;
653     auto id = PandasmDumperUtils::GetLiteralArrayIdFromName(it->first);
654     std::string replaced_value = SerializeLiteralArray(literal_array, id);
655     pa_ins.ids[idx] = replaced_value;
656 }
657 
SerializeLiteralArray(const pandasm::LiteralArray & lit_array,uint32_t id) const658 std::string PandasmProgramDumper::SerializeLiteralArray(const pandasm::LiteralArray &lit_array, uint32_t id) const
659 {
660     if (lit_array.literals_.empty()) {
661         return "";
662     }
663     std::stringstream ss;
664     ss << DUMP_CONTENT_LEFT_CURLY_BRACKET << DUMP_CONTENT_SPACE;
665     ss << lit_array.literals_.size();
666     ss << DUMP_CONTENT_SPACE << DUMP_CONTENT_LEFT_SQUARE_BRACKET << DUMP_CONTENT_SPACE;
667     processing_literal_array_id_set_.emplace(id);
668     SerializeLiterals(lit_array, ss);
669     processing_literal_array_id_set_.erase(id);
670     ss << DUMP_CONTENT_RIGHT_SQUARE_BRACKET << DUMP_CONTENT_RIGHT_CURLY_BRACKET;
671     return ss.str();
672 }
673 
SerializeLiterals(const pandasm::LiteralArray & lit_array,std::stringstream & os) const674 void PandasmProgramDumper::SerializeLiterals(const pandasm::LiteralArray &lit_array, std::stringstream &os) const
675 {
676     for (size_t i = 0; i < lit_array.literals_.size(); i++) {
677         SerializeLiteralsAtIndex(lit_array, os, i);
678         os << DUMP_CONTENT_COMMA << DUMP_CONTENT_SPACE;
679     }
680 }
681 
SerializeLiteralsAtIndex(const pandasm::LiteralArray & lit_array,std::stringstream & os,size_t i) const682 void PandasmProgramDumper::SerializeLiteralsAtIndex(
683     const pandasm::LiteralArray &lit_array, std::stringstream &os, size_t i) const
684 {
685     const panda_file::LiteralTag &tag = lit_array.literals_[i].tag_;
686     os << PandasmDumperUtils::LiteralTagToString(tag) << DUMP_CONTENT_COLON;
687     const auto &val = lit_array.literals_[i].value_;
688     switch (tag) {
689         case panda_file::LiteralTag::BOOL:
690             os << (std::get<bool>(val));
691             break;
692         case panda_file::LiteralTag::LITERALBUFFERINDEX:
693         case panda_file::LiteralTag::INTEGER:
694             os << (bit_cast<int32_t>(std::get<uint32_t>(val)));
695             break;
696         case panda_file::LiteralTag::DOUBLE:
697             os << (std::get<double>(val));
698             break;
699         case panda_file::LiteralTag::STRING:
700             os << "\"" << (std::get<std::string>(val)) << "\"";
701             break;
702         case panda_file::LiteralTag::METHOD:
703         case panda_file::LiteralTag::GETTER:
704         case panda_file::LiteralTag::SETTER:
705         case panda_file::LiteralTag::GENERATORMETHOD:
706         case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
707             os << (std::get<std::string>(val));
708             break;
709         case panda_file::LiteralTag::NULLVALUE:
710         case panda_file::LiteralTag::ACCESSOR:
711             os << (static_cast<int16_t>(bit_cast<int8_t>(std::get<uint8_t>(val))));
712             break;
713         case panda_file::LiteralTag::METHODAFFILIATE:
714             os << (std::get<uint16_t>(val));
715             break;
716         case panda_file::LiteralTag::LITERALARRAY:
717             SerializeNestedLiteralArrayById(os, std::get<std::string>(val));
718             break;
719         case panda_file::LiteralTag::BUILTINTYPEINDEX:
720             os << (static_cast<int16_t>(std::get<uint8_t>(val)));
721             break;
722         case panda_file::LiteralTag::TAGVALUE:
723             os << (static_cast<int16_t>(std::get<uint8_t>(val)));
724             break;
725         default:
726             UNREACHABLE();
727     }
728 }
729 
SerializeNestedLiteralArrayById(std::stringstream & os,const std::string & literal_array_id_name) const730 void PandasmProgramDumper::SerializeNestedLiteralArrayById(
731     std::stringstream &os, const std::string &literal_array_id_name) const
732 {
733     if (!is_normalized_) {
734         os << literal_array_id_name;
735         return;
736     }
737     auto id = PandasmDumperUtils::GetLiteralArrayIdFromName(literal_array_id_name);
738     if (processing_literal_array_id_set_.find(id) == processing_literal_array_id_set_.end()) {
739         auto it = program_->literalarray_table.find(literal_array_id_name);
740         ASSERT(it != program_->literalarray_table.end());
741         os << SerializeLiteralArray(it->second, id);
742     } else {
743         UNREACHABLE();
744     }
745 }
746 
747 }  // namespace panda::abc2program
748