• 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/pandagen.h>
24 #include <compiler/debugger/debuginfoDumper.h>
25 #include <compiler/base/catchTable.h>
26 #include <es2panda.h>
27 #include <gen/isa.h>
28 #include <ir/base/methodDefinition.h>
29 #include <ir/base/scriptFunction.h>
30 #include <ir/expressions/functionExpression.h>
31 #include <ir/expressions/literal.h>
32 #include <ir/statements/blockStatement.h>
33 #include <macros.h>
34 #include <parser/program/program.h>
35 #include <util/helpers.h>
36 
37 #include <string>
38 #include <string_view>
39 #include <tuple>
40 #include <utility>
41 
42 namespace panda::es2panda::compiler {
43 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
44 
FunctionEmitter(ArenaAllocator * allocator,const PandaGen * pg)45 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
46     : pg_(pg), literalBuffers_(allocator->Adapter())
47 {
48     func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
49     CHECK_NOT_NULL(func_);
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     GenConcurrentFunctionModuleRequests();
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 
160 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode * astNode,panda::pandasm::Ins * pandaIns)161 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
162 {
163     constexpr size_t INVALID_LINE = -1;
164     constexpr uint32_t INVALID_COL = -1;
165     // The GetLocation method calculated position starts with 1, and
166     // the column number in pandaIns->ins_debug starts with 0
167     constexpr uint32_t OFFSET_COL = 1;
168     uint32_t columnNum = INVALID_COL;
169     if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
170         while (astNode != nullptr && !astNode->IsScriptFunction()) {
171             if (astNode->IsBlockStatement() &&
172                 astNode->AsBlockStatement()->Scope() &&
173                 astNode->AsBlockStatement()->Scope()->Node() &&
174                 astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
175                 astNode = astNode->AsBlockStatement()->Scope()->Node();
176                 break;
177             }
178             astNode = astNode->Parent();
179         }
180         pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
181         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
182     } else {
183         pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
184         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
185     }
186     return columnNum;
187 }
188 
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)189 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
190 {
191     const ir::AstNode *astNode = ins->Node();
192     if (astNode == FIRST_NODE_OF_FUNCTION) {
193         astNode = pg_->Debuginfo().firstStmt;
194         if (!astNode) {
195             return;
196         }
197     }
198     uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
199 
200     if (pg_->IsDebug()) {
201         size_t insLen = GetIRNodeWholeLength(ins);
202         if (insLen != 0) {
203             pandaIns->ins_debug.bound_left = offset_;
204             pandaIns->ins_debug.bound_right = offset_ + insLen;
205         }
206 
207         offset_ += insLen;
208         pandaIns->ins_debug.column_number = columnNum;
209     }
210 }
211 
GenFunctionInstructions()212 void FunctionEmitter::GenFunctionInstructions()
213 {
214     func_->ins.reserve(pg_->Insns().size());
215 
216     for (const auto *ins : pg_->Insns()) {
217         auto &pandaIns = func_->ins.emplace_back();
218 
219         ins->Transform(&pandaIns);
220         GenInstructionDebugInfo(ins, &pandaIns);
221     }
222 }
223 
GenFunctionCatchTables()224 void FunctionEmitter::GenFunctionCatchTables()
225 {
226     func_->catch_blocks.reserve(pg_->CatchList().size());
227 
228     for (const auto *catchBlock : pg_->CatchList()) {
229         const auto &labelSet = catchBlock->LabelSet();
230 
231         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
232         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
233         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
234         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
235         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
236     }
237 }
238 
GenLiteralBuffers()239 void FunctionEmitter::GenLiteralBuffers()
240 {
241     for (const auto *buff : pg_->BuffStorage()) {
242         GenBufferLiterals(buff);
243     }
244 }
245 
GenSourceFileDebugInfo()246 void FunctionEmitter::GenSourceFileDebugInfo()
247 {
248     if (pg_->SourceFile().empty()) {
249         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
250     } else {
251         func_->source_file = pg_->SourceFile();
252     }
253 
254     if (!pg_->IsDebug()) {
255         return;
256     }
257 
258     if (pg_->RootNode()->IsProgram()) {
259         if (pg_->Context()->IsRecordDebugSource()) {
260             func_->source_code = SourceCode().Mutf8();
261         } else {
262             func_->source_code = "not supported";
263         }
264     }
265 }
266 
GenScopeVariableInfo(const binder::Scope * scope)267 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
268 {
269     const auto *startIns = scope->ScopeStart();
270     const auto *endIns = scope->ScopeEnd();
271 
272     uint32_t start = 0;
273     uint32_t count = 0;
274 
275     for (const auto *it : pg_->Insns()) {
276         if (startIns == it) {
277             start = count;
278         } else if (endIns == it) {
279             auto varsLength = static_cast<uint32_t>(count - start + 1);
280 
281             for (const auto &[name, variable] : scope->Bindings()) {
282                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
283                     continue;
284                 }
285 
286                 auto &variableDebug = func_->local_variable_debug.emplace_back();
287                 variableDebug.name = name.Mutf8();
288                 variableDebug.signature = "any";
289                 variableDebug.signature_type = "any";
290                 // Register spill causes an offset being applied to all registers in all instructions (refer to
291                 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
292                 // to the variable-to-register mapping before dumping it to the debug information of the abc file
293                 // (the following code).
294                 // We do not correct the original variable mapping in the scope object since it is not used after
295                 // the register spill phase, while we do not know the number of spilled registers before that phase.
296                 // If any future modifications require access to the variable mapping after the register spill,
297                 // please correct the mapping first and remove the offset increment operation in the following code.
298                 variableDebug.reg =
299                     static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
300                 variableDebug.start = start;
301                 variableDebug.length = static_cast<uint32_t>(varsLength);
302             }
303 
304             break;
305         }
306 
307         count++;
308     }
309 }
310 
GenVariablesDebugInfo()311 void FunctionEmitter::GenVariablesDebugInfo()
312 {
313     if (!pg_->IsDebug()) {
314         return;
315     }
316 
317     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
318         GenScopeVariableInfo(scope);
319     }
320 }
321 
GenConcurrentFunctionModuleRequests()322 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
323 {
324     if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
325         panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
326         return;
327     }
328 
329     std::vector<int> moduleRequests =
330         static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
331     func_->concurrent_module_requests.reserve(moduleRequests.size());
332     for (auto it : moduleRequests) {
333         func_->concurrent_module_requests.emplace_back(it);
334     }
335 }
336 
337 // Emitter
338 
Emitter(CompilerContext * context)339 Emitter::Emitter(CompilerContext *context)
340 {
341     prog_ = new panda::pandasm::Program();
342     prog_->lang = LANG_EXT;
343 
344     if (context->IsJsonInputFile()) {
345         GenJsonContentRecord(context);
346         return;
347     }
348 
349     if (context->IsMergeAbc()) {
350         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
351         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
352         SetPkgNameField(context->PkgName());
353         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
354     } else {
355         rec_ = nullptr;
356         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
357             GenCommonjsRecord();
358         }
359     }
360     if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
361         AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
362     }
363     AddSharedModuleRecord(context);
364     AddScopeNamesRecord(context);
365 }
366 
~Emitter()367 Emitter::~Emitter()
368 {
369     delete prog_;
370 }
371 
SetPkgNameField(const std::string & pkgName)372 void Emitter::SetPkgNameField(const std::string &pkgName)
373 {
374     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
375     pkgNameField.name = "pkgName@" + pkgName;
376     pkgNameField.type = panda::pandasm::Type("u8", 0);
377     pkgNameField.metadata->SetValue(
378         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
379     rec_->field_list.emplace_back(std::move(pkgNameField));
380 }
381 
GenRecordNameInfo() const382 void Emitter::GenRecordNameInfo() const
383 {
384     if (rec_) {
385         prog_->record_table.emplace(rec_->name, std::move(*rec_));
386     }
387 }
388 
GenJsonContentRecord(const CompilerContext * context)389 void Emitter::GenJsonContentRecord(const CompilerContext *context)
390 {
391     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
392     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
393     jsonContentField.name = "jsonFileContent";
394     jsonContentField.type = panda::pandasm::Type("u32", 0);
395     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
396         static_cast<std::string_view>(context->SourceFile())));
397     rec_->field_list.emplace_back(std::move(jsonContentField));
398     if (context->PatchFixHelper()) {
399         context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
400     }
401 }
402 
AddFunction(FunctionEmitter * func,CompilerContext * context)403 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
404 {
405     std::lock_guard<std::mutex> lock(m_);
406 
407     for (const auto &str : func->Strings()) {
408         prog_->strings.insert(str.Mutf8());
409     }
410 
411     for (auto &[idx, buf] : func->LiteralBuffers()) {
412         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
413         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
414         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
415     }
416 
417     auto *function = func->Function();
418     prog_->function_table.emplace(function->name, std::move(*function));
419 }
420 
AddScopeNamesRecord(CompilerContext * context)421 void Emitter::AddScopeNamesRecord(CompilerContext *context)
422 {
423     std::lock_guard<std::mutex> lock(m_);
424     // make literalarray for scope names
425     if (util::Helpers::IsDefaultApiVersion(context->Binder()->Program()->TargetApiVersion(),
426         context->Binder()->Program()->GetTargetApiSubVersion())) {
427         return;
428     }
429     const auto &scopeNamesMap = context->Binder()->GetScopeNames();
430 
431     panda::pandasm::LiteralArray array;
432     const int32_t DOUBLE_SIZE = 2;
433     array.literals_.resize(scopeNamesMap.size() * DOUBLE_SIZE);
434     auto strTag = panda_file::LiteralTag::STRING;
435     for (const auto &[scopeName, index] : scopeNamesMap) {
436         panda::pandasm::LiteralArray::Literal tag;
437         tag.tag_ = panda_file::LiteralTag::TAGVALUE;
438         tag.value_ = static_cast<uint8_t>(strTag);
439         array.literals_.at(index * DOUBLE_SIZE) = std::move(tag);
440         panda::pandasm::LiteralArray::Literal val;
441         val.tag_ = strTag;
442         val.value_ = std::string(scopeName);
443         array.literals_.at(index * DOUBLE_SIZE + 1) = std::move(val);
444     }
445     auto literalKey = std::string(context->Binder()->Program()->RecordName()) +
446                       "_" + std::to_string(context->NewLiteralIndex());
447     prog_->literalarray_table.emplace(literalKey, std::move(array));
448 
449     // ScopeNames is a literalarray in each record if it is in mergeAbc, it is a string array which put scope names.
450     // _ESScopeNamesRecord is a literalarray in the record when it is not in mergeAbc.
451     if (context->IsMergeAbc()) {
452         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
453         scopeNamesField.name = "scopeNames";
454         scopeNamesField.type = panda::pandasm::Type("u32", 0);
455         scopeNamesField.metadata->SetValue(
456             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
457             static_cast<std::string_view>(literalKey)));
458         rec_->field_list.emplace_back(std::move(scopeNamesField));
459     } else {
460         auto scopeNamesRecord = panda::pandasm::Record("_ESScopeNamesRecord", LANG_EXT);
461         scopeNamesRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
462         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
463         // If the input arg "source-file" is not specified, context->SourceFile() will be empty,
464         // in this case, use it's absolute path.
465         if (context->SourceFile().empty()) {
466             scopeNamesField.name = context->Binder()->Program()->SourceFile().Mutf8();
467         } else {
468             scopeNamesField.name = context->SourceFile();
469         }
470         scopeNamesField.type = panda::pandasm::Type("u32", 0);
471         scopeNamesField.metadata->SetValue(
472             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
473             static_cast<std::string_view>(literalKey)));
474         scopeNamesRecord.field_list.emplace_back(std::move(scopeNamesField));
475         prog_->record_table.emplace(scopeNamesRecord.name, std::move(scopeNamesRecord));
476     }
477 }
478 
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)479 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
480 {
481     std::lock_guard<std::mutex> lock(m_);
482 
483     if (module->NeedEmitPhaseRecord()) {
484         AddModuleRequestPhaseRecord(module, context);
485     }
486 
487     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
488          std::to_string(module->Index());
489     if (context->IsMergeAbc()) {
490         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
491         moduleIdxField.name = "moduleRecordIdx";
492         moduleIdxField.type = panda::pandasm::Type("u32", 0);
493         moduleIdxField.metadata->SetValue(
494             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
495             static_cast<std::string_view>(moduleLiteral)));
496         rec_->field_list.emplace_back(std::move(moduleIdxField));
497 
498         if (context->PatchFixHelper()) {
499             context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
500         }
501     } else {
502         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
503         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
504 
505         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
506         moduleIdxField.name = context->Binder()->Program()->ModuleRecordFieldName().empty() ?
507                               std::string {context->Binder()->Program()->SourceFile()} :
508                               context->Binder()->Program()->ModuleRecordFieldName();
509         moduleIdxField.type = panda::pandasm::Type("u32", 0);
510         moduleIdxField.metadata->SetValue(
511             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
512             static_cast<std::string_view>(moduleLiteral)));
513         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
514 
515         if (context->PatchFixHelper()) {
516             context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
517         }
518         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
519     }
520     auto &moduleLiteralsBuffer = module->Buffer();
521     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
522     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
523     constant_local_export_slots_ = module->GetConstantLocalExportSlots();
524 }
525 
AddModuleRequestPhaseRecord(ModuleRecordEmitter * module,CompilerContext * context)526 void Emitter::AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)
527 {
528     auto phaseLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
529          std::to_string(module->PhaseIndex());
530     if (context->IsMergeAbc()) {
531         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
532         phaseIdxField.name = "moduleRequestPhaseIdx";
533         phaseIdxField.type = panda::pandasm::Type("u32", 0);
534         phaseIdxField.metadata->SetValue(
535             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
536             static_cast<std::string_view>(phaseLiteral)));
537         rec_->field_list.emplace_back(std::move(phaseIdxField));
538     } else {
539         auto moduleRequestPhaseRecord = panda::pandasm::Record("_ModuleRequestPhaseRecord", LANG_EXT);
540         moduleRequestPhaseRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
541 
542         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
543         phaseIdxField.name = "moduleRequestPhaseIdx";
544         phaseIdxField.type = panda::pandasm::Type("u32", 0);
545         phaseIdxField.metadata->SetValue(
546             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
547             static_cast<std::string_view>(phaseLiteral)));
548         moduleRequestPhaseRecord.field_list.emplace_back(std::move(phaseIdxField));
549 
550         prog_->record_table.emplace(moduleRequestPhaseRecord.name, std::move(moduleRequestPhaseRecord));
551     }
552     auto &moduleRequestPhaseLiteralsBuffer = module->PhaseBuffer();
553     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleRequestPhaseLiteralsBuffer));
554     prog_->literalarray_table.emplace(static_cast<std::string_view>(phaseLiteral), std::move(literalArrayInstance));
555 }
556 
AddHasTopLevelAwaitRecord(bool hasTLA,const CompilerContext * context)557 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
558 {
559     if (context->IsMergeAbc()) {
560         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
561         hasTLAField.name = "hasTopLevelAwait";
562         hasTLAField.type = panda::pandasm::Type("u8", 0);
563         hasTLAField.metadata->SetValue(
564             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA))
565         );
566         rec_->field_list.emplace_back(std::move(hasTLAField));
567     } else if (hasTLA) {
568         auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
569         hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
570         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
571         hasTLAField.name = "hasTopLevelAwait";
572         hasTLAField.type = panda::pandasm::Type("u8", 0);
573         hasTLAField.metadata->SetValue(
574             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true))
575         );
576         hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
577 
578         prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
579     }
580 }
581 
AddSharedModuleRecord(const CompilerContext * context)582 void Emitter::AddSharedModuleRecord(const CompilerContext *context)
583 {
584     bool isShared = context->Binder()->Program()->IsShared();
585 
586     auto sharedModuleField = panda::pandasm::Field(LANG_EXT);
587     sharedModuleField.name = "isSharedModule";
588     sharedModuleField.type = panda::pandasm::Type("u8", 0);
589     sharedModuleField.metadata->SetValue(
590         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(isShared))
591     );
592 
593     if (context->IsMergeAbc()) {
594         rec_->field_list.emplace_back(std::move(sharedModuleField));
595     } else if (isShared) {
596         auto sharedModuleRecord = panda::pandasm::Record("_SharedModuleRecord", LANG_EXT);
597         sharedModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
598         sharedModuleRecord.field_list.emplace_back(std::move(sharedModuleField));
599         prog_->record_table.emplace(sharedModuleRecord.name, std::move(sharedModuleRecord));
600     }
601 }
602 
603 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)604 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
605                                 const LiteralBuffer *buff)
606 {
607     auto &[idx, array] = literalBuffers.emplace_back();
608     idx = buff->Index();
609     constexpr size_t ARRAY_EXPANSION = 2;
610     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
611 
612     for (const auto *literal : buff->Literals()) {
613         panda::pandasm::LiteralArray::Literal valueLit;
614         panda::pandasm::LiteralArray::Literal tagLit;
615 
616         ir::LiteralTag tag = literal->Tag();
617 
618         switch (tag) {
619             case ir::LiteralTag::BOOLEAN: {
620                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
621                 valueLit.value_ = literal->GetBoolean();
622                 break;
623             }
624             case ir::LiteralTag::INTEGER: {
625                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
626                 valueLit.value_ = literal->GetInt();
627                 break;
628             }
629             case ir::LiteralTag::DOUBLE: {
630                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
631                 valueLit.value_ = literal->GetDouble();
632                 break;
633             }
634             case ir::LiteralTag::STRING: {
635                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
636                 valueLit.value_ = literal->GetString().Mutf8();
637                 break;
638             }
639             case ir::LiteralTag::ACCESSOR: {
640                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
641                 valueLit.value_ = static_cast<uint8_t>(0);
642                 break;
643             }
644             case ir::LiteralTag::METHOD: {
645                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
646                 valueLit.value_ = literal->GetMethod().Mutf8();
647                 break;
648             }
649             case ir::LiteralTag::METHODAFFILIATE: {
650                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
651                 valueLit.value_ = literal->GetMethodAffiliate();
652                 break;
653             }
654             case ir::LiteralTag::GENERATOR_METHOD: {
655                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
656                 valueLit.value_ = literal->GetMethod().Mutf8();
657                 break;
658             }
659             case ir::LiteralTag::LITERALBUFFERINDEX: {
660                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
661                 valueLit.value_ = literal->GetInt();
662                 break;
663             }
664             case ir::LiteralTag::LITERALARRAY: {
665                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
666                 valueLit.value_ = literal->GetString().Mutf8();
667                 break;
668             }
669             case ir::LiteralTag::BUILTINTYPEINDEX: {
670                 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
671                 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
672                 break;
673             }
674             case ir::LiteralTag::GETTER: {
675                 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
676                 valueLit.value_ = literal->GetMethod().Mutf8();
677                 break;
678             }
679             case ir::LiteralTag::SETTER: {
680                 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
681                 valueLit.value_ = literal->GetMethod().Mutf8();
682                 break;
683             }
684             case ir::LiteralTag::ASYNC_GENERATOR_METHOD: {
685                 valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD;
686                 valueLit.value_ = literal->GetMethod().Mutf8();
687                 break;
688             }
689             case ir::LiteralTag::NULL_VALUE: {
690                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
691                 valueLit.value_ = static_cast<uint8_t>(0);
692                 break;
693             }
694             default:
695                 break;
696         }
697 
698         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
699         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
700 
701         array.emplace_back(tagLit);
702         array.emplace_back(valueLit);
703     }
704 }
705 
DumpAsm(const panda::pandasm::Program * prog)706 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
707 {
708     auto &ss = std::cout;
709 
710     ss << ".language ECMAScript" << std::endl << std::endl;
711 
712     for (auto &[name, func] : prog->function_table) {
713         ss << "slotNum = 0x" << std::hex << func.GetSlotsNum() << std::dec << std::endl;
714         ss << ".function any " << name << '(';
715 
716         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
717             ss << "any a" << std::to_string(i);
718 
719             if (i != func.GetParamsNum() - 1) {
720                 ss << ", ";
721             }
722         }
723 
724         ss << ") {" << std::endl;
725 
726         for (const auto &ins : func.ins) {
727             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
728         }
729 
730         ss << "}" << std::endl << std::endl;
731 
732         for (const auto &ct : func.catch_blocks) {
733             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
734                << std::endl
735                << std::endl;
736         }
737     }
738 
739     ss << std::endl;
740 }
741 
Finalize(bool dumpDebugInfo,util::PatchFix * patchFixHelper)742 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
743 {
744     if (dumpDebugInfo) {
745         debuginfo::DebugInfoDumper dumper(prog_);
746         dumper.Dump();
747     }
748 
749     if (rec_) {
750         delete rec_;
751         rec_ = nullptr;
752     }
753 
754     if (patchFixHelper) {
755         patchFixHelper->Finalize(&prog_);
756     }
757 
758     auto *prog = prog_;
759     prog_ = nullptr;
760     return prog;
761 }
762 
GetProgram() const763 panda::pandasm::Program *Emitter::GetProgram() const
764 {
765     return prog_;
766 }
767 
768 }  // namespace panda::es2panda::compiler
769