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 ¶m,
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