• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 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 "emitter.h"
17 
18 #include <binder/binder.h>
19 #include <binder/scope.h>
20 #include <binder/variable.h>
21 #include <compiler/base/literals.h>
22 #include <compiler/core/compilerContext.h>
23 #include <compiler/core/emitter/typeExtractorEmitter.h>
24 #include <compiler/core/pandagen.h>
25 #include <compiler/debugger/debuginfoDumper.h>
26 #include <compiler/base/catchTable.h>
27 #include <es2panda.h>
28 #include <gen/isa.h>
29 #include <ir/base/methodDefinition.h>
30 #include <ir/base/scriptFunction.h>
31 #include <ir/expressions/functionExpression.h>
32 #include <ir/expressions/literal.h>
33 #include <ir/statements/blockStatement.h>
34 #include <macros.h>
35 #include <parser/program/program.h>
36 #include <util/helpers.h>
37 
38 #include <string>
39 #include <string_view>
40 #include <tuple>
41 #include <utility>
42 
43 namespace panda::es2panda::compiler {
44 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
45 
FunctionEmitter(ArenaAllocator * allocator,const PandaGen * pg)46 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
47     : pg_(pg), literalBuffers_(allocator->Adapter())
48 {
49     func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
50 
51     size_t paramCount = pg->InternalParamCount();
52     func_->params.reserve(paramCount);
53 
54     for (uint32_t i = 0; i < paramCount; ++i) {
55         func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
56     }
57 
58     func_->regs_num = pg->TotalRegsNum();
59     func_->return_type = panda::pandasm::Type("any", 0);
60 }
61 
Generate(util::PatchFix * patchFixHelper)62 void FunctionEmitter::Generate(util::PatchFix *patchFixHelper)
63 {
64     GenFunctionKind();
65     GenIcSize();
66     GenFunctionInstructions();
67     GenVariablesDebugInfo();
68     GenSourceFileDebugInfo();
69     GenFunctionCatchTables();
70     GenLiteralBuffers();
71     GenFunctionSource();
72     if (patchFixHelper != nullptr) {
73         patchFixHelper->ProcessFunction(pg_, func_, literalBuffers_);
74     }
75 }
76 
Strings() const77 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
78 {
79     return pg_->Strings();
80 }
81 
GenFunctionKind()82 void FunctionEmitter::GenFunctionKind()
83 {
84     func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
85 }
86 
GenIcSize()87 void FunctionEmitter::GenIcSize()
88 {
89     func_->SetSlotsNum(pg_->GetCurrentSlot());
90 }
91 
GenBufferLiterals(const LiteralBuffer * buff)92 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
93 {
94     Emitter::GenBufferLiterals(literalBuffers_, buff);
95 }
96 
SourceCode() const97 util::StringView FunctionEmitter::SourceCode() const
98 {
99     if (pg_->RootNode()->IsProgram()) {
100         return pg_->Binder()->Program()->SourceCode();
101     }
102     return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
103 }
104 
GetLineIndex() const105 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
106 {
107     return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
108 }
109 
MatchFormat(const IRNode * node,const Formats & formats)110 static Format MatchFormat(const IRNode *node, const Formats &formats)
111 {
112     std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
113     auto regCnt = node->Registers(&regs);
114     auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
115 
116     const auto *iter = formats.begin();
117 
118     for (; iter != formats.end(); iter++) {
119         auto format = *iter;
120         size_t limit = 0;
121         for (const auto &formatItem : format.GetFormatItem()) {
122             if (formatItem.IsVReg()) {
123                 limit = 1 << formatItem.Bitwidth();
124                 break;
125             }
126         }
127 
128         if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
129             return format;
130         }
131     }
132 
133     UNREACHABLE();
134     return *iter;
135 }
136 
GetIRNodeWholeLength(const IRNode * node)137 static size_t GetIRNodeWholeLength(const IRNode *node)
138 {
139     Formats formats = node->GetFormats();
140     if (formats.empty()) {
141         return 0;
142     }
143 
144     size_t len = 1;
145     constexpr size_t BIT_WIDTH = 8;
146     const auto format = MatchFormat(node, formats);
147 
148     for (auto fi : format.GetFormatItem()) {
149         len += fi.Bitwidth() / BIT_WIDTH;
150     }
151 
152     return len;
153 }
154 
WholeLine(const util::StringView & source,lexer::SourceRange range)155 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
156 {
157     return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
158 }
159 
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)160 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
161 {
162     const ir::AstNode *astNode = ins->Node();
163     constexpr size_t INVALID_LINE = -1;
164     constexpr uint32_t INVALID_COL = -1;
165 
166     if (astNode == FIRST_NODE_OF_FUNCTION) {
167         astNode = pg_->Debuginfo().firstStmt;
168         if (!astNode) {
169             return;
170         }
171     }
172 
173     pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
174 
175     if (pg_->IsDebug()) {
176         size_t insLen = GetIRNodeWholeLength(ins);
177         if (insLen != 0) {
178             pandaIns->ins_debug.bound_left = offset_;
179             pandaIns->ins_debug.bound_right = offset_ + insLen;
180         }
181 
182         offset_ += insLen;
183 
184         pandaIns->ins_debug.column_number = astNode ?
185             (GetLineIndex().GetLocation(astNode->Range().start).col - 1) : INVALID_COL;
186     }
187 }
188 
GenFunctionInstructions()189 void FunctionEmitter::GenFunctionInstructions()
190 {
191     func_->ins.reserve(pg_->Insns().size());
192 
193     for (const auto *ins : pg_->Insns()) {
194         auto &pandaIns = func_->ins.emplace_back();
195 
196         ins->Transform(&pandaIns);
197         GenInstructionDebugInfo(ins, &pandaIns);
198     }
199 
200     if (pg_->Context()->IsTypeExtractorEnabled()) {
201         TypeExtractorEmitter(pg_, func_);
202     }
203 }
204 
GenFunctionCatchTables()205 void FunctionEmitter::GenFunctionCatchTables()
206 {
207     func_->catch_blocks.reserve(pg_->CatchList().size());
208 
209     for (const auto *catchBlock : pg_->CatchList()) {
210         const auto &labelSet = catchBlock->LabelSet();
211 
212         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
213         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
214         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
215         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
216         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
217     }
218 }
219 
GenLiteralBuffers()220 void FunctionEmitter::GenLiteralBuffers()
221 {
222     for (const auto *buff : pg_->BuffStorage()) {
223         GenBufferLiterals(buff);
224     }
225 }
226 
GenSourceFileDebugInfo()227 void FunctionEmitter::GenSourceFileDebugInfo()
228 {
229     if (pg_->SourceFile().empty()) {
230         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
231     } else {
232         func_->source_file = pg_->SourceFile();
233     }
234 
235     if (!pg_->IsDebug()) {
236         return;
237     }
238 
239     if (pg_->RootNode()->IsProgram()) {
240         func_->source_code = SourceCode().Mutf8();
241     }
242 }
243 
GenFunctionSource()244 void FunctionEmitter::GenFunctionSource()
245 {
246     if (pg_->RootNode()->IsProgram()) {
247         return;
248     }
249 
250     if (!(static_cast<const ir::ScriptFunction *>(pg_->RootNode()))->ShowSource()) {
251         return;
252     }
253 
254     func_->source_code = SourceCode().Mutf8();
255 }
256 
GenScopeVariableInfo(const binder::Scope * scope)257 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
258 {
259     const auto *startIns = scope->ScopeStart();
260     const auto *endIns = scope->ScopeEnd();
261 
262     uint32_t start = 0;
263     uint32_t count = 0;
264 
265     for (const auto *it : pg_->Insns()) {
266         if (startIns == it) {
267             start = count;
268         } else if (endIns == it) {
269             auto varsLength = static_cast<uint32_t>(count - start + 1);
270 
271             for (const auto &[name, variable] : scope->Bindings()) {
272                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
273                     continue;
274                 }
275 
276                 auto &variableDebug = func_->local_variable_debug.emplace_back();
277                 variableDebug.name = name.Mutf8();
278                 variableDebug.signature = "any";
279                 variableDebug.signature_type = "any";
280                 variableDebug.reg = static_cast<int32_t>(variable->AsLocalVariable()->Vreg());
281                 variableDebug.start = start;
282                 variableDebug.length = static_cast<uint32_t>(varsLength);
283             }
284 
285             break;
286         }
287 
288         count++;
289     }
290 }
291 
GenVariablesDebugInfo()292 void FunctionEmitter::GenVariablesDebugInfo()
293 {
294     if (!pg_->IsDebug()) {
295         return;
296     }
297 
298     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
299         GenScopeVariableInfo(scope);
300     }
301 }
302 
303 // Emitter
304 
Emitter(const CompilerContext * context)305 Emitter::Emitter(const CompilerContext *context)
306 {
307     prog_ = new panda::pandasm::Program();
308     prog_->lang = LANG_EXT;
309 
310     if (context->IsJsonInputFile()) {
311         GenJsonContentRecord(context);
312         return;
313     }
314 
315     GenESTypeAnnotationRecord();
316 
317     if (context->IsMergeAbc()) {
318         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
319         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
320         SetPkgNameField(context->PkgName());
321         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
322     } else {
323         rec_ = nullptr;
324         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
325             GenCommonjsRecord();
326         }
327     }
328 }
329 
~Emitter()330 Emitter::~Emitter()
331 {
332     delete prog_;
333 }
334 
SetPkgNameField(std::string pkgName)335 void Emitter::SetPkgNameField(std::string pkgName)
336 {
337     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
338     pkgNameField.name = "pkgName@" + pkgName;
339     pkgNameField.type = panda::pandasm::Type("u8", 0);
340     pkgNameField.metadata->SetValue(
341         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
342     rec_->field_list.emplace_back(std::move(pkgNameField));
343 }
344 
GenRecordNameInfo() const345 void Emitter::GenRecordNameInfo() const
346 {
347     if (rec_) {
348         prog_->record_table.emplace(rec_->name, std::move(*rec_));
349     }
350 }
351 
GenTypeInfoRecord() const352 void Emitter::GenTypeInfoRecord() const
353 {
354     auto typeInfoRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_INFO_RECORD, LANG_EXT);
355     typeInfoRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
356     prog_->record_table.emplace(typeInfoRecord.name, std::move(typeInfoRecord));
357 }
358 
GenESTypeAnnotationRecord() const359 void Emitter::GenESTypeAnnotationRecord() const
360 {
361     auto typeAnnotationRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_ANNOTATION, LANG_EXT);
362     typeAnnotationRecord.metadata->SetAttribute("external");
363     typeAnnotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
364     prog_->record_table.emplace(typeAnnotationRecord.name, std::move(typeAnnotationRecord));
365 }
366 
GenJsonContentRecord(const CompilerContext * context)367 void Emitter::GenJsonContentRecord(const CompilerContext *context)
368 {
369     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
370     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
371     jsonContentField.name = "jsonFileContent";
372     jsonContentField.type = panda::pandasm::Type("u32", 0);
373     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
374         static_cast<std::string_view>(context->SourceFile())));
375     rec_->field_list.emplace_back(std::move(jsonContentField));
376     if (context->PatchFixHelper()) {
377         context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
378     }
379 }
380 
AddFunction(FunctionEmitter * func,CompilerContext * context)381 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
382 {
383     std::lock_guard<std::mutex> lock(m_);
384 
385     for (const auto &str : func->Strings()) {
386         prog_->strings.insert(str.Mutf8());
387     }
388 
389     for (auto &[idx, buf] : func->LiteralBuffers()) {
390         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
391         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
392         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
393     }
394 
395     auto *function = func->Function();
396     prog_->function_table.emplace(function->name, std::move(*function));
397 }
398 
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)399 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
400 {
401     std::lock_guard<std::mutex> lock(m_);
402 
403     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
404          std::to_string(module->Index());
405     if (context->IsMergeAbc()) {
406         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
407         moduleIdxField.name = "moduleRecordIdx";
408         moduleIdxField.type = panda::pandasm::Type("u32", 0);
409         moduleIdxField.metadata->SetValue(
410             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
411             static_cast<std::string_view>(moduleLiteral)));
412         rec_->field_list.emplace_back(std::move(moduleIdxField));
413 
414         if (context->PatchFixHelper()) {
415             context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
416         }
417     } else {
418         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
419         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
420 
421         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
422         moduleIdxField.name = std::string {context->Binder()->Program()->SourceFile()};
423         moduleIdxField.type = panda::pandasm::Type("u32", 0);
424         moduleIdxField.metadata->SetValue(
425             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
426             static_cast<std::string_view>(moduleLiteral)));
427         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
428 
429         if (context->PatchFixHelper()) {
430             context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
431         }
432         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
433     }
434     auto &moduleLiteralsBuffer = module->Buffer();
435     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
436     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
437 }
438 
FillTypeInfoRecord(CompilerContext * context,bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName) const439 void Emitter::FillTypeInfoRecord(CompilerContext *context, bool typeFlag, int64_t typeSummaryIndex,
440     const std::string &recordName) const
441 {
442     if (!context->IsMergeAbc()) {
443         TypeExtractorEmitter::GenTypeInfoRecord(prog_, typeFlag, typeSummaryIndex, recordName);
444     } else {
445         TypeExtractorEmitter::GenTypeInfoRecordForMergeABC(prog_, typeFlag, typeSummaryIndex, recordName);
446     }
447 }
448 
FillTypeLiteralBuffers(const extractor::TypeRecorder * recorder) const449 void Emitter::FillTypeLiteralBuffers(const extractor::TypeRecorder *recorder) const
450 {
451     TypeExtractorEmitter::GenTypeLiteralBuffers(prog_, recorder);
452 }
453 
454 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)455 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
456                                 const LiteralBuffer *buff)
457 {
458     auto &[idx, array] = literalBuffers.emplace_back();
459     idx = buff->Index();
460     constexpr size_t ARRAY_EXPANSION = 2;
461     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
462 
463     for (const auto *literal : buff->Literals()) {
464         panda::pandasm::LiteralArray::Literal valueLit;
465         panda::pandasm::LiteralArray::Literal tagLit;
466 
467         ir::LiteralTag tag = literal->Tag();
468 
469         switch (tag) {
470             case ir::LiteralTag::BOOLEAN: {
471                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
472                 valueLit.value_ = literal->GetBoolean();
473                 break;
474             }
475             case ir::LiteralTag::INTEGER: {
476                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
477                 valueLit.value_ = literal->GetInt();
478                 break;
479             }
480             case ir::LiteralTag::DOUBLE: {
481                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
482                 valueLit.value_ = literal->GetDouble();
483                 break;
484             }
485             case ir::LiteralTag::STRING: {
486                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
487                 valueLit.value_ = literal->GetString().Mutf8();
488                 break;
489             }
490             case ir::LiteralTag::ACCESSOR: {
491                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
492                 valueLit.value_ = static_cast<uint8_t>(0);
493                 break;
494             }
495             case ir::LiteralTag::METHOD: {
496                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
497                 valueLit.value_ = literal->GetMethod().Mutf8();
498                 break;
499             }
500             case ir::LiteralTag::METHODAFFILIATE: {
501                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
502                 valueLit.value_ = literal->GetMethodAffiliate();
503                 break;
504             }
505             case ir::LiteralTag::GENERATOR_METHOD: {
506                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
507                 valueLit.value_ = literal->GetMethod().Mutf8();
508                 break;
509             }
510             case ir::LiteralTag::LITERALBUFFERINDEX: {
511                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
512                 valueLit.value_ = literal->GetInt();
513                 break;
514             }
515             case ir::LiteralTag::LITERALARRAY: {
516                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
517                 valueLit.value_ = literal->GetString().Mutf8();
518                 break;
519             }
520             case ir::LiteralTag::BUILTINTYPEINDEX: {
521                 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
522                 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
523                 break;
524             }
525             // TODO: support ir::LiteralTag::ASYNC_GENERATOR_METHOD
526             case ir::LiteralTag::NULL_VALUE: {
527                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
528                 valueLit.value_ = static_cast<uint8_t>(0);
529                 break;
530             }
531             default:
532                 break;
533         }
534 
535         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
536         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
537 
538         array.emplace_back(tagLit);
539         array.emplace_back(valueLit);
540     }
541 }
542 
DumpAsm(const panda::pandasm::Program * prog)543 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
544 {
545     auto &ss = std::cout;
546 
547     ss << ".language ECMAScript" << std::endl << std::endl;
548 
549     for (auto &[name, func] : prog->function_table) {
550         ss << ".function any " << name << '(';
551 
552         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
553             ss << "any a" << std::to_string(i);
554 
555             if (i != func.GetParamsNum() - 1) {
556                 ss << ", ";
557             }
558         }
559 
560         ss << ") {" << std::endl;
561 
562         for (const auto &ins : func.ins) {
563             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
564         }
565 
566         ss << "}" << std::endl << std::endl;
567 
568         for (const auto &ct : func.catch_blocks) {
569             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
570                << std::endl
571                << std::endl;
572         }
573     }
574 
575     ss << std::endl;
576 }
577 
Finalize(bool dumpDebugInfo,util::PatchFix * patchFixHelper)578 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
579 {
580     if (dumpDebugInfo) {
581         debuginfo::DebugInfoDumper dumper(prog_);
582         dumper.Dump();
583     }
584 
585     if (rec_) {
586         delete rec_;
587         rec_ = nullptr;
588     }
589 
590     if (patchFixHelper) {
591         patchFixHelper->Finalize(&prog_);
592     }
593 
594     auto *prog = prog_;
595     prog_ = nullptr;
596     return prog;
597 }
598 
GetProgram() const599 panda::pandasm::Program *Emitter::GetProgram() const
600 {
601     return prog_;
602 }
603 
604 }  // namespace panda::es2panda::compiler
605