• 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     GenConcurrentFunctionModuleRequests();
73     if (patchFixHelper != nullptr) {
74         patchFixHelper->ProcessFunction(pg_, func_, literalBuffers_);
75     }
76 }
77 
Strings() const78 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
79 {
80     return pg_->Strings();
81 }
82 
GenFunctionKind()83 void FunctionEmitter::GenFunctionKind()
84 {
85     func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
86 }
87 
GenIcSize()88 void FunctionEmitter::GenIcSize()
89 {
90     func_->SetSlotsNum(pg_->GetCurrentSlot());
91 }
92 
GenBufferLiterals(const LiteralBuffer * buff)93 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
94 {
95     Emitter::GenBufferLiterals(literalBuffers_, buff);
96 }
97 
SourceCode() const98 util::StringView FunctionEmitter::SourceCode() const
99 {
100     if (pg_->RootNode()->IsProgram()) {
101         return pg_->Binder()->Program()->SourceCode();
102     }
103     return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
104 }
105 
GetLineIndex() const106 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
107 {
108     return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
109 }
110 
MatchFormat(const IRNode * node,const Formats & formats)111 static Format MatchFormat(const IRNode *node, const Formats &formats)
112 {
113     std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
114     auto regCnt = node->Registers(&regs);
115     auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
116 
117     const auto *iter = formats.begin();
118 
119     for (; iter != formats.end(); iter++) {
120         auto format = *iter;
121         size_t limit = 0;
122         for (const auto &formatItem : format.GetFormatItem()) {
123             if (formatItem.IsVReg()) {
124                 limit = 1 << formatItem.Bitwidth();
125                 break;
126             }
127         }
128 
129         if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
130             return format;
131         }
132     }
133 
134     UNREACHABLE();
135     return *iter;
136 }
137 
GetIRNodeWholeLength(const IRNode * node)138 static size_t GetIRNodeWholeLength(const IRNode *node)
139 {
140     Formats formats = node->GetFormats();
141     if (formats.empty()) {
142         return 0;
143     }
144 
145     size_t len = 1;
146     constexpr size_t BIT_WIDTH = 8;
147     const auto format = MatchFormat(node, formats);
148 
149     for (auto fi : format.GetFormatItem()) {
150         len += fi.Bitwidth() / BIT_WIDTH;
151     }
152 
153     return len;
154 }
155 
WholeLine(const util::StringView & source,lexer::SourceRange range)156 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
157 {
158     return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
159 }
160 
161 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode * astNode,panda::pandasm::Ins * pandaIns)162 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
163 {
164     constexpr size_t INVALID_LINE = -1;
165     constexpr uint32_t INVALID_COL = -1;
166     // The GetLocation method calculated position starts with 1, and
167     // the column number in pandaIns->ins_debug starts with 0
168     constexpr uint32_t OFFSET_COL = 1;
169     uint32_t columnNum = INVALID_COL;
170     if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
171         while (astNode != nullptr && !astNode->IsScriptFunction()) {
172             if (astNode->IsBlockStatement() && astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
173                 astNode = astNode->AsBlockStatement()->Scope()->Node();
174                 break;
175             }
176             astNode = astNode->Parent();
177         }
178         pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
179         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
180     } else {
181         pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
182         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
183     }
184     return columnNum;
185 }
186 
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)187 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
188 {
189     const ir::AstNode *astNode = ins->Node();
190     if (astNode == FIRST_NODE_OF_FUNCTION) {
191         astNode = pg_->Debuginfo().firstStmt;
192         if (!astNode) {
193             return;
194         }
195     }
196     uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
197 
198     if (pg_->IsDebug()) {
199         size_t insLen = GetIRNodeWholeLength(ins);
200         if (insLen != 0) {
201             pandaIns->ins_debug.bound_left = offset_;
202             pandaIns->ins_debug.bound_right = offset_ + insLen;
203         }
204 
205         offset_ += insLen;
206         pandaIns->ins_debug.column_number = columnNum;
207     }
208 }
209 
GenFunctionInstructions()210 void FunctionEmitter::GenFunctionInstructions()
211 {
212     func_->ins.reserve(pg_->Insns().size());
213 
214     for (const auto *ins : pg_->Insns()) {
215         auto &pandaIns = func_->ins.emplace_back();
216 
217         ins->Transform(&pandaIns);
218         GenInstructionDebugInfo(ins, &pandaIns);
219     }
220 
221     if (pg_->Context()->IsTypeExtractorEnabled()) {
222         TypeExtractorEmitter(pg_, func_);
223     }
224 }
225 
GenFunctionCatchTables()226 void FunctionEmitter::GenFunctionCatchTables()
227 {
228     func_->catch_blocks.reserve(pg_->CatchList().size());
229 
230     for (const auto *catchBlock : pg_->CatchList()) {
231         const auto &labelSet = catchBlock->LabelSet();
232 
233         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
234         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
235         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
236         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
237         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
238     }
239 }
240 
GenLiteralBuffers()241 void FunctionEmitter::GenLiteralBuffers()
242 {
243     for (const auto *buff : pg_->BuffStorage()) {
244         GenBufferLiterals(buff);
245     }
246 }
247 
GenSourceFileDebugInfo()248 void FunctionEmitter::GenSourceFileDebugInfo()
249 {
250     if (pg_->SourceFile().empty()) {
251         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
252     } else {
253         func_->source_file = pg_->SourceFile();
254     }
255 
256     if (!pg_->IsDebug()) {
257         return;
258     }
259 
260     if (pg_->RootNode()->IsProgram()) {
261         func_->source_code = SourceCode().Mutf8();
262     }
263 }
264 
GenFunctionSource()265 void FunctionEmitter::GenFunctionSource()
266 {
267     if (pg_->RootNode()->IsProgram()) {
268         return;
269     }
270 
271     if (pg_->Context()->IsRecordSource() || (static_cast<const ir::ScriptFunction *>(pg_->RootNode()))->ShowSource()) {
272         func_->source_code = SourceCode().Mutf8();
273     }
274 }
275 
GenScopeVariableInfo(const binder::Scope * scope)276 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
277 {
278     const auto *startIns = scope->ScopeStart();
279     const auto *endIns = scope->ScopeEnd();
280 
281     uint32_t start = 0;
282     uint32_t count = 0;
283 
284     for (const auto *it : pg_->Insns()) {
285         if (startIns == it) {
286             start = count;
287         } else if (endIns == it) {
288             auto varsLength = static_cast<uint32_t>(count - start + 1);
289 
290             for (const auto &[name, variable] : scope->Bindings()) {
291                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
292                     continue;
293                 }
294 
295                 auto &variableDebug = func_->local_variable_debug.emplace_back();
296                 variableDebug.name = name.Mutf8();
297                 variableDebug.signature = "any";
298                 variableDebug.signature_type = "any";
299                 // Register spill causes an offset being applied to all registers in all instructions (refer to
300                 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
301                 // to the variable-to-register mapping before dumping it to the debug information of the abc file
302                 // (the following code).
303                 // We do not correct the original variable mapping in the scope object since it is not used after
304                 // the register spill phase, while we do not know the number of spilled registers before that phase.
305                 // If any future modifications require access to the variable mapping after the register spill,
306                 // please correct the mapping first and remove the offset increment operation in the following code.
307                 variableDebug.reg =
308                     static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
309                 variableDebug.start = start;
310                 variableDebug.length = static_cast<uint32_t>(varsLength);
311             }
312 
313             break;
314         }
315 
316         count++;
317     }
318 }
319 
GenVariablesDebugInfo()320 void FunctionEmitter::GenVariablesDebugInfo()
321 {
322     if (!pg_->IsDebug()) {
323         return;
324     }
325 
326     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
327         GenScopeVariableInfo(scope);
328     }
329 }
330 
GenConcurrentFunctionModuleRequests()331 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
332 {
333     if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
334         panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
335         return;
336     }
337 
338     std::vector<int> moduleRequests =
339         static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
340     func_->concurrent_module_requests.reserve(moduleRequests.size());
341     for (auto it : moduleRequests) {
342         func_->concurrent_module_requests.emplace_back(it);
343     }
344 }
345 
346 // Emitter
347 
Emitter(const CompilerContext * context)348 Emitter::Emitter(const CompilerContext *context)
349 {
350     prog_ = new panda::pandasm::Program();
351     prog_->lang = LANG_EXT;
352 
353     if (context->IsJsonInputFile()) {
354         GenJsonContentRecord(context);
355         return;
356     }
357 
358     GenESTypeAnnotationRecord();
359     if (context->IsMergeAbc()) {
360         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
361         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
362         SetPkgNameField(context->PkgName());
363         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
364     } else {
365         rec_ = nullptr;
366         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
367             GenCommonjsRecord();
368         }
369     }
370     if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
371         AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
372     }
373 }
374 
~Emitter()375 Emitter::~Emitter()
376 {
377     delete prog_;
378 }
379 
SetPkgNameField(std::string pkgName)380 void Emitter::SetPkgNameField(std::string pkgName)
381 {
382     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
383     pkgNameField.name = "pkgName@" + pkgName;
384     pkgNameField.type = panda::pandasm::Type("u8", 0);
385     pkgNameField.metadata->SetValue(
386         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
387     rec_->field_list.emplace_back(std::move(pkgNameField));
388 }
389 
GenRecordNameInfo() const390 void Emitter::GenRecordNameInfo() const
391 {
392     if (rec_) {
393         prog_->record_table.emplace(rec_->name, std::move(*rec_));
394     }
395 }
396 
GenTypeInfoRecord() const397 void Emitter::GenTypeInfoRecord() const
398 {
399     auto typeInfoRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_INFO_RECORD, LANG_EXT);
400     typeInfoRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
401     prog_->record_table.emplace(typeInfoRecord.name, std::move(typeInfoRecord));
402 }
403 
GenESTypeAnnotationRecord() const404 void Emitter::GenESTypeAnnotationRecord() const
405 {
406     auto typeAnnotationRecord = panda::pandasm::Record(TypeExtractorEmitter::TYPE_ANNOTATION, LANG_EXT);
407     typeAnnotationRecord.metadata->SetAttribute("external");
408     typeAnnotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
409     prog_->record_table.emplace(typeAnnotationRecord.name, std::move(typeAnnotationRecord));
410 }
411 
GenJsonContentRecord(const CompilerContext * context)412 void Emitter::GenJsonContentRecord(const CompilerContext *context)
413 {
414     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
415     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
416     jsonContentField.name = "jsonFileContent";
417     jsonContentField.type = panda::pandasm::Type("u32", 0);
418     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
419         static_cast<std::string_view>(context->SourceFile())));
420     rec_->field_list.emplace_back(std::move(jsonContentField));
421     if (context->PatchFixHelper()) {
422         context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
423     }
424 }
425 
AddFunction(FunctionEmitter * func,CompilerContext * context)426 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
427 {
428     std::lock_guard<std::mutex> lock(m_);
429 
430     for (const auto &str : func->Strings()) {
431         prog_->strings.insert(str.Mutf8());
432     }
433 
434     for (auto &[idx, buf] : func->LiteralBuffers()) {
435         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
436         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
437         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
438     }
439 
440     auto *function = func->Function();
441     prog_->function_table.emplace(function->name, std::move(*function));
442 }
443 
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)444 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
445 {
446     std::lock_guard<std::mutex> lock(m_);
447 
448     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
449          std::to_string(module->Index());
450     if (context->IsMergeAbc()) {
451         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
452         moduleIdxField.name = "moduleRecordIdx";
453         moduleIdxField.type = panda::pandasm::Type("u32", 0);
454         moduleIdxField.metadata->SetValue(
455             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
456             static_cast<std::string_view>(moduleLiteral)));
457         rec_->field_list.emplace_back(std::move(moduleIdxField));
458 
459         if (context->PatchFixHelper()) {
460             context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
461         }
462     } else {
463         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
464         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
465 
466         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
467         moduleIdxField.name = std::string {context->Binder()->Program()->SourceFile()};
468         moduleIdxField.type = panda::pandasm::Type("u32", 0);
469         moduleIdxField.metadata->SetValue(
470             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
471             static_cast<std::string_view>(moduleLiteral)));
472         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
473 
474         if (context->PatchFixHelper()) {
475             context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
476         }
477         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
478     }
479     auto &moduleLiteralsBuffer = module->Buffer();
480     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
481     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
482 }
483 
AddHasTopLevelAwaitRecord(bool hasTLA,const CompilerContext * context)484 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
485 {
486     if (context->IsMergeAbc()) {
487         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
488         hasTLAField.name = "hasTopLevelAwait";
489         hasTLAField.type = panda::pandasm::Type("u8", 0);
490         hasTLAField.metadata->SetValue(
491             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA))
492         );
493         rec_->field_list.emplace_back(std::move(hasTLAField));
494     } else if (hasTLA) {
495         auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
496         hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
497         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
498         hasTLAField.name = "hasTopLevelAwait";
499         hasTLAField.type = panda::pandasm::Type("u8", 0);
500         hasTLAField.metadata->SetValue(
501             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true))
502         );
503         hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
504 
505         prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
506     }
507 }
508 
FillTypeInfoRecord(CompilerContext * context,bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName) const509 void Emitter::FillTypeInfoRecord(CompilerContext *context, bool typeFlag, int64_t typeSummaryIndex,
510     const std::string &recordName) const
511 {
512     if (!context->IsMergeAbc()) {
513         TypeExtractorEmitter::GenTypeInfoRecord(prog_, typeFlag, typeSummaryIndex, recordName);
514     } else {
515         TypeExtractorEmitter::GenTypeInfoRecordForMergeABC(prog_, typeFlag, typeSummaryIndex, recordName);
516     }
517 }
518 
FillTypeLiteralBuffers(const extractor::TypeRecorder * recorder) const519 void Emitter::FillTypeLiteralBuffers(const extractor::TypeRecorder *recorder) const
520 {
521     TypeExtractorEmitter::GenTypeLiteralBuffers(prog_, recorder);
522 }
523 
524 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)525 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
526                                 const LiteralBuffer *buff)
527 {
528     auto &[idx, array] = literalBuffers.emplace_back();
529     idx = buff->Index();
530     constexpr size_t ARRAY_EXPANSION = 2;
531     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
532 
533     for (const auto *literal : buff->Literals()) {
534         panda::pandasm::LiteralArray::Literal valueLit;
535         panda::pandasm::LiteralArray::Literal tagLit;
536 
537         ir::LiteralTag tag = literal->Tag();
538 
539         switch (tag) {
540             case ir::LiteralTag::BOOLEAN: {
541                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
542                 valueLit.value_ = literal->GetBoolean();
543                 break;
544             }
545             case ir::LiteralTag::INTEGER: {
546                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
547                 valueLit.value_ = literal->GetInt();
548                 break;
549             }
550             case ir::LiteralTag::DOUBLE: {
551                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
552                 valueLit.value_ = literal->GetDouble();
553                 break;
554             }
555             case ir::LiteralTag::STRING: {
556                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
557                 valueLit.value_ = literal->GetString().Mutf8();
558                 break;
559             }
560             case ir::LiteralTag::ACCESSOR: {
561                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
562                 valueLit.value_ = static_cast<uint8_t>(0);
563                 break;
564             }
565             case ir::LiteralTag::METHOD: {
566                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
567                 valueLit.value_ = literal->GetMethod().Mutf8();
568                 break;
569             }
570             case ir::LiteralTag::METHODAFFILIATE: {
571                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
572                 valueLit.value_ = literal->GetMethodAffiliate();
573                 break;
574             }
575             case ir::LiteralTag::GENERATOR_METHOD: {
576                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
577                 valueLit.value_ = literal->GetMethod().Mutf8();
578                 break;
579             }
580             case ir::LiteralTag::LITERALBUFFERINDEX: {
581                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
582                 valueLit.value_ = literal->GetInt();
583                 break;
584             }
585             case ir::LiteralTag::LITERALARRAY: {
586                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
587                 valueLit.value_ = literal->GetString().Mutf8();
588                 break;
589             }
590             case ir::LiteralTag::BUILTINTYPEINDEX: {
591                 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
592                 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
593                 break;
594             }
595             case ir::LiteralTag::GETTER: {
596                 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
597                 valueLit.value_ = literal->GetMethod().Mutf8();
598                 break;
599             }
600             case ir::LiteralTag::SETTER: {
601                 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
602                 valueLit.value_ = literal->GetMethod().Mutf8();
603                 break;
604             }
605             // TODO: support ir::LiteralTag::ASYNC_GENERATOR_METHOD
606             case ir::LiteralTag::NULL_VALUE: {
607                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
608                 valueLit.value_ = static_cast<uint8_t>(0);
609                 break;
610             }
611             default:
612                 break;
613         }
614 
615         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
616         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
617 
618         array.emplace_back(tagLit);
619         array.emplace_back(valueLit);
620     }
621 }
622 
DumpAsm(const panda::pandasm::Program * prog)623 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
624 {
625     auto &ss = std::cout;
626 
627     ss << ".language ECMAScript" << std::endl << std::endl;
628 
629     for (auto &[name, func] : prog->function_table) {
630         ss << ".function any " << name << '(';
631 
632         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
633             ss << "any a" << std::to_string(i);
634 
635             if (i != func.GetParamsNum() - 1) {
636                 ss << ", ";
637             }
638         }
639 
640         ss << ") {" << std::endl;
641 
642         for (const auto &ins : func.ins) {
643             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
644         }
645 
646         ss << "}" << std::endl << std::endl;
647 
648         for (const auto &ct : func.catch_blocks) {
649             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
650                << std::endl
651                << std::endl;
652         }
653     }
654 
655     ss << std::endl;
656 }
657 
Finalize(bool dumpDebugInfo,util::PatchFix * patchFixHelper)658 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
659 {
660     if (dumpDebugInfo) {
661         debuginfo::DebugInfoDumper dumper(prog_);
662         dumper.Dump();
663     }
664 
665     if (rec_) {
666         delete rec_;
667         rec_ = nullptr;
668     }
669 
670     if (patchFixHelper) {
671         patchFixHelper->Finalize(&prog_);
672     }
673 
674     auto *prog = prog_;
675     prog_ = nullptr;
676     return prog;
677 }
678 
GetProgram() const679 panda::pandasm::Program *Emitter::GetProgram() const
680 {
681     return prog_;
682 }
683 
684 }  // namespace panda::es2panda::compiler
685