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