• 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     GenSlotNumberAnnotation();
76     if (pg_->Context()->IsMergeAbc()) {
77         GenConcurrentModuleRequestsAnnotation();
78     }
79 }
80 
Strings() const81 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
82 {
83     return pg_->Strings();
84 }
85 
GenFunctionKind()86 void FunctionEmitter::GenFunctionKind()
87 {
88     func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
89 }
90 
GenIcSize()91 void FunctionEmitter::GenIcSize()
92 {
93     func_->SetSlotsNum(pg_->GetCurrentSlot());
94 }
95 
GenBufferLiterals(const LiteralBuffer * buff)96 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
97 {
98     Emitter::GenBufferLiterals(literalBuffers_, buff);
99 }
100 
SourceCode() const101 util::StringView FunctionEmitter::SourceCode() const
102 {
103     if (pg_->RootNode()->IsProgram()) {
104         return pg_->Binder()->Program()->SourceCode();
105     }
106     return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
107 }
108 
GetLineIndex() const109 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
110 {
111     return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
112 }
113 
MatchFormat(const IRNode * node,const Formats & formats)114 static Format MatchFormat(const IRNode *node, const Formats &formats)
115 {
116     std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
117     auto regCnt = node->Registers(&regs);
118     auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
119 
120     const auto *iter = formats.begin();
121 
122     for (; iter != formats.end(); iter++) {
123         auto format = *iter;
124         size_t limit = 0;
125         for (const auto &formatItem : format.GetFormatItem()) {
126             if (formatItem.IsVReg()) {
127                 limit = 1 << formatItem.Bitwidth();
128                 break;
129             }
130         }
131 
132         if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
133             return format;
134         }
135     }
136 
137     UNREACHABLE();
138     return *iter;
139 }
140 
GetIRNodeWholeLength(const IRNode * node)141 static size_t GetIRNodeWholeLength(const IRNode *node)
142 {
143     Formats formats = node->GetFormats();
144     if (formats.empty()) {
145         return 0;
146     }
147 
148     size_t len = 1;
149     constexpr size_t BIT_WIDTH = 8;
150     const auto format = MatchFormat(node, formats);
151 
152     for (auto fi : format.GetFormatItem()) {
153         len += fi.Bitwidth() / BIT_WIDTH;
154     }
155 
156     return len;
157 }
158 
WholeLine(const util::StringView & source,lexer::SourceRange range)159 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
160 {
161     return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
162 }
163 
164 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode * astNode,panda::pandasm::Ins * pandaIns)165 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
166 {
167     constexpr size_t INVALID_LINE = -1;
168     constexpr uint32_t INVALID_COL = -1;
169     // The GetLocation method calculated position starts with 1, and
170     // the column number in pandaIns->ins_debug starts with 0
171     constexpr uint32_t OFFSET_COL = 1;
172     uint32_t columnNum = INVALID_COL;
173     if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
174         while (astNode != nullptr && !astNode->IsScriptFunction()) {
175             if (astNode->IsBlockStatement() &&
176                 astNode->AsBlockStatement()->Scope() &&
177                 astNode->AsBlockStatement()->Scope()->Node() &&
178                 astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
179                 astNode = astNode->AsBlockStatement()->Scope()->Node();
180                 break;
181             }
182             astNode = astNode->Parent();
183         }
184         pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
185         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
186     } else {
187         pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
188         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
189     }
190     return columnNum;
191 }
192 
GenInstructionDebugInfo(const IRNode * ins,panda::pandasm::Ins * pandaIns)193 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
194 {
195     const ir::AstNode *astNode = ins->Node();
196     if (astNode == FIRST_NODE_OF_FUNCTION) {
197         astNode = pg_->Debuginfo().firstStmt;
198         if (!astNode) {
199             return;
200         }
201     }
202     uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
203 
204     if (pg_->IsDebug()) {
205         size_t insLen = GetIRNodeWholeLength(ins);
206         if (insLen != 0) {
207             pandaIns->ins_debug.bound_left = offset_;
208             pandaIns->ins_debug.bound_right = offset_ + insLen;
209         }
210 
211         offset_ += insLen;
212         pandaIns->ins_debug.column_number = columnNum;
213     }
214 }
215 
GenFunctionInstructions()216 void FunctionEmitter::GenFunctionInstructions()
217 {
218     func_->ins.reserve(pg_->Insns().size());
219 
220     for (const auto *ins : pg_->Insns()) {
221         auto &pandaIns = func_->ins.emplace_back();
222 
223         ins->Transform(&pandaIns);
224         GenInstructionDebugInfo(ins, &pandaIns);
225     }
226 }
227 
GenFunctionCatchTables()228 void FunctionEmitter::GenFunctionCatchTables()
229 {
230     func_->catch_blocks.reserve(pg_->CatchList().size());
231 
232     for (const auto *catchBlock : pg_->CatchList()) {
233         const auto &labelSet = catchBlock->LabelSet();
234 
235         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
236         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
237         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
238         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
239         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
240     }
241 }
242 
GenLiteralBuffers()243 void FunctionEmitter::GenLiteralBuffers()
244 {
245     for (const auto *buff : pg_->BuffStorage()) {
246         GenBufferLiterals(buff);
247     }
248 }
249 
GenSourceFileDebugInfo()250 void FunctionEmitter::GenSourceFileDebugInfo()
251 {
252     if (pg_->SourceFile().empty()) {
253         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
254     } else {
255         func_->source_file = pg_->SourceFile();
256     }
257 
258     if (!pg_->IsDebug()) {
259         return;
260     }
261 
262     if (pg_->RootNode()->IsProgram()) {
263         if (pg_->Context()->IsRecordDebugSource()) {
264             func_->source_code = SourceCode().Mutf8();
265         } else {
266             func_->source_code = "not supported";
267         }
268     }
269 }
270 
GenScopeVariableInfo(const binder::Scope * scope)271 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
272 {
273     const auto *startIns = scope->ScopeStart();
274     const auto *endIns = scope->ScopeEnd();
275 
276     uint32_t start = 0;
277     uint32_t count = 0;
278 
279     for (const auto *it : pg_->Insns()) {
280         if (startIns == it) {
281             start = count;
282         } else if (endIns == it) {
283             auto varsLength = static_cast<uint32_t>(count - start + 1);
284 
285             for (const auto &[name, variable] : scope->Bindings()) {
286                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
287                     continue;
288                 }
289 
290                 auto &variableDebug = func_->local_variable_debug.emplace_back();
291                 variableDebug.name = name.Mutf8();
292                 variableDebug.signature = "any";
293                 variableDebug.signature_type = "any";
294                 // Register spill causes an offset being applied to all registers in all instructions (refer to
295                 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
296                 // to the variable-to-register mapping before dumping it to the debug information of the abc file
297                 // (the following code).
298                 // We do not correct the original variable mapping in the scope object since it is not used after
299                 // the register spill phase, while we do not know the number of spilled registers before that phase.
300                 // If any future modifications require access to the variable mapping after the register spill,
301                 // please correct the mapping first and remove the offset increment operation in the following code.
302                 variableDebug.reg =
303                     static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
304                 variableDebug.start = start;
305                 variableDebug.length = static_cast<uint32_t>(varsLength);
306             }
307 
308             break;
309         }
310 
311         count++;
312     }
313 }
314 
GenVariablesDebugInfo()315 void FunctionEmitter::GenVariablesDebugInfo()
316 {
317     if (!pg_->IsDebug()) {
318         return;
319     }
320 
321     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
322         GenScopeVariableInfo(scope);
323     }
324 }
325 
GenConcurrentFunctionModuleRequests()326 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
327 {
328     if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
329         panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
330         return;
331     }
332 
333     std::vector<int> moduleRequests =
334         static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
335     func_->concurrent_module_requests.reserve(moduleRequests.size());
336     for (auto it : moduleRequests) {
337         func_->concurrent_module_requests.emplace_back(it);
338     }
339 }
340 
GenSlotNumberAnnotation()341 void FunctionEmitter::GenSlotNumberAnnotation()
342 {
343     static const std::string SLOT_NUMBER = "_ESSlotNumberAnnotation";
344     static const std::string ELEMENT_NAME = "SlotNumber";
345 
346     for (const auto &an : func_->metadata->GetAnnotations()) {
347         if (an.GetName() == SLOT_NUMBER) {
348             return;
349         }
350     }
351     pandasm::AnnotationData anno(SLOT_NUMBER);
352     pandasm::AnnotationElement ele(ELEMENT_NAME, std::make_unique<pandasm::ScalarValue>(
353         pandasm::ScalarValue::Create<pandasm::Value::Type::U32>(static_cast<uint32_t>(func_->GetSlotsNum()))));
354     anno.AddElement(std::move(ele));
355     std::vector<pandasm::AnnotationData> annos;
356     annos.emplace_back(anno);
357     func_->metadata->AddAnnotations(annos);
358 }
359 
GenConcurrentModuleRequestsAnnotation()360 void FunctionEmitter::GenConcurrentModuleRequestsAnnotation()
361 {
362     static const std::string CONCURRENT_MODULE_REQUESTS = "_ESConcurrentModuleRequestsAnnotation";
363     static const std::string ELEMENT_NAME = "ConcurrentModuleRequest";
364     if (func_->GetFunctionKind() != panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
365         return;
366     }
367 
368     for (const auto &an : func_->metadata->GetAnnotations()) {
369         if (an.GetName() == CONCURRENT_MODULE_REQUESTS) {
370             return;
371         }
372     }
373 
374     pandasm::AnnotationData anno(CONCURRENT_MODULE_REQUESTS);
375     for (auto &it : func_->concurrent_module_requests) {
376         panda::pandasm::AnnotationElement module_request(ELEMENT_NAME, std::make_unique<pandasm::ScalarValue>(
377             pandasm::ScalarValue::Create<pandasm::Value::Type::U32>(static_cast<uint32_t>(it))));
378         anno.AddElement(std::move(module_request));
379     }
380 
381     std::vector<pandasm::AnnotationData> annos;
382     annos.emplace_back(anno);
383     func_->metadata->AddAnnotations(annos);
384 }
385 
386 // Emitter
387 
Emitter(CompilerContext * context)388 Emitter::Emitter(CompilerContext *context)
389 {
390     prog_ = new panda::pandasm::Program();
391     prog_->lang = LANG_EXT;
392 
393     if (context->IsJsonInputFile()) {
394         GenJsonContentRecord(context);
395         return;
396     }
397 
398     if (context->IsMergeAbc()) {
399         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
400         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
401         SetPkgNameField(context->PkgName());
402         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
403     } else {
404         rec_ = nullptr;
405         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
406             GenCommonjsRecord();
407         }
408     }
409     if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
410         AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
411     }
412     AddSharedModuleRecord(context);
413     AddScopeNamesRecord(context);
414     AddSlotNumberRecord();
415     if (context->IsMergeAbc()) {
416         AddConcurrentModuleRequestsRecord();
417     }
418 }
419 
~Emitter()420 Emitter::~Emitter()
421 {
422     delete prog_;
423 }
424 
SetPkgNameField(const std::string & pkgName)425 void Emitter::SetPkgNameField(const std::string &pkgName)
426 {
427     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
428     pkgNameField.name = "pkgName@" + pkgName;
429     pkgNameField.type = panda::pandasm::Type("u8", 0);
430     pkgNameField.metadata->SetValue(
431         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
432     rec_->field_list.emplace_back(std::move(pkgNameField));
433 }
434 
GenRecordNameInfo() const435 void Emitter::GenRecordNameInfo() const
436 {
437     if (rec_) {
438         prog_->record_table.emplace(rec_->name, std::move(*rec_));
439     }
440 }
441 
GenJsonContentRecord(const CompilerContext * context)442 void Emitter::GenJsonContentRecord(const CompilerContext *context)
443 {
444     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
445     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
446     jsonContentField.name = "jsonFileContent";
447     jsonContentField.type = panda::pandasm::Type("u32", 0);
448     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
449         static_cast<std::string_view>(context->SourceFile())));
450     rec_->field_list.emplace_back(std::move(jsonContentField));
451     if (context->PatchFixHelper()) {
452         context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
453     }
454 }
455 
AddFunction(FunctionEmitter * func,CompilerContext * context)456 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
457 {
458     std::lock_guard<std::mutex> lock(m_);
459 
460     for (const auto &str : func->Strings()) {
461         prog_->strings.insert(str.Mutf8());
462     }
463 
464     for (auto &[idx, buf] : func->LiteralBuffers()) {
465         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
466         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
467         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
468     }
469 
470     auto *function = func->Function();
471     prog_->function_table.emplace(function->name, std::move(*function));
472 }
473 
AddScopeNamesRecord(CompilerContext * context)474 void Emitter::AddScopeNamesRecord(CompilerContext *context)
475 {
476     std::lock_guard<std::mutex> lock(m_);
477     // make literalarray for scope names
478     if (util::Helpers::IsDefaultApiVersion(context->Binder()->Program()->TargetApiVersion(),
479         context->Binder()->Program()->GetTargetApiSubVersion())) {
480         return;
481     }
482     const auto &scopeNamesMap = context->Binder()->GetScopeNames();
483 
484     panda::pandasm::LiteralArray array;
485     const int32_t DOUBLE_SIZE = 2;
486     array.literals_.resize(scopeNamesMap.size() * DOUBLE_SIZE);
487     auto strTag = panda_file::LiteralTag::STRING;
488     for (const auto &[scopeName, index] : scopeNamesMap) {
489         panda::pandasm::LiteralArray::Literal tag;
490         tag.tag_ = panda_file::LiteralTag::TAGVALUE;
491         tag.value_ = static_cast<uint8_t>(strTag);
492         array.literals_.at(index * DOUBLE_SIZE) = std::move(tag);
493         panda::pandasm::LiteralArray::Literal val;
494         val.tag_ = strTag;
495         val.value_ = std::string(scopeName);
496         array.literals_.at(index * DOUBLE_SIZE + 1) = std::move(val);
497     }
498     auto literalKey = std::string(context->Binder()->Program()->RecordName()) +
499                       "_" + std::to_string(context->NewLiteralIndex());
500     prog_->literalarray_table.emplace(literalKey, std::move(array));
501 
502     // ScopeNames is a literalarray in each record if it is in mergeAbc, it is a string array which put scope names.
503     // _ESScopeNamesRecord is a literalarray in the record when it is not in mergeAbc.
504     if (context->IsMergeAbc()) {
505         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
506         scopeNamesField.name = "scopeNames";
507         scopeNamesField.type = panda::pandasm::Type("u32", 0);
508         scopeNamesField.metadata->SetValue(
509             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
510             static_cast<std::string_view>(literalKey)));
511         rec_->field_list.emplace_back(std::move(scopeNamesField));
512     } else {
513         auto scopeNamesRecord = panda::pandasm::Record("_ESScopeNamesRecord", LANG_EXT);
514         scopeNamesRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
515         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
516         // If the input arg "source-file" is not specified, context->SourceFile() will be empty,
517         // in this case, use it's absolute path.
518         if (context->SourceFile().empty()) {
519             scopeNamesField.name = context->Binder()->Program()->SourceFile().Mutf8();
520         } else {
521             scopeNamesField.name = context->SourceFile();
522         }
523         scopeNamesField.type = panda::pandasm::Type("u32", 0);
524         scopeNamesField.metadata->SetValue(
525             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
526             static_cast<std::string_view>(literalKey)));
527         scopeNamesRecord.field_list.emplace_back(std::move(scopeNamesField));
528         prog_->record_table.emplace(scopeNamesRecord.name, std::move(scopeNamesRecord));
529     }
530 }
531 
AddSourceTextModuleRecord(ModuleRecordEmitter * module,CompilerContext * context)532 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
533 {
534     std::lock_guard<std::mutex> lock(m_);
535 
536     if (module->NeedEmitPhaseRecord()) {
537         AddModuleRequestPhaseRecord(module, context);
538     }
539 
540     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
541          std::to_string(module->Index());
542     if (context->IsMergeAbc()) {
543         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
544         moduleIdxField.name = "moduleRecordIdx";
545         moduleIdxField.type = panda::pandasm::Type("u32", 0);
546         moduleIdxField.metadata->SetValue(
547             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
548             static_cast<std::string_view>(moduleLiteral)));
549         rec_->field_list.emplace_back(std::move(moduleIdxField));
550 
551         if (context->PatchFixHelper()) {
552             context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
553         }
554     } else {
555         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
556         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
557 
558         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
559         moduleIdxField.name = context->Binder()->Program()->ModuleRecordFieldName().empty() ?
560                               std::string {context->Binder()->Program()->SourceFile()} :
561                               context->Binder()->Program()->ModuleRecordFieldName();
562         moduleIdxField.type = panda::pandasm::Type("u32", 0);
563         moduleIdxField.metadata->SetValue(
564             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
565             static_cast<std::string_view>(moduleLiteral)));
566         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
567 
568         if (context->PatchFixHelper()) {
569             context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
570         }
571         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
572     }
573     auto &moduleLiteralsBuffer = module->Buffer();
574     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
575     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
576     constant_local_export_slots_ = module->GetConstantLocalExportSlots();
577 }
578 
AddModuleRequestPhaseRecord(ModuleRecordEmitter * module,CompilerContext * context)579 void Emitter::AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)
580 {
581     auto phaseLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
582          std::to_string(module->PhaseIndex());
583     if (context->IsMergeAbc()) {
584         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
585         phaseIdxField.name = "moduleRequestPhaseIdx";
586         phaseIdxField.type = panda::pandasm::Type("u32", 0);
587         phaseIdxField.metadata->SetValue(
588             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
589             static_cast<std::string_view>(phaseLiteral)));
590         rec_->field_list.emplace_back(std::move(phaseIdxField));
591     } else {
592         auto moduleRequestPhaseRecord = panda::pandasm::Record("_ModuleRequestPhaseRecord", LANG_EXT);
593         moduleRequestPhaseRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
594 
595         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
596         phaseIdxField.name = "moduleRequestPhaseIdx";
597         phaseIdxField.type = panda::pandasm::Type("u32", 0);
598         phaseIdxField.metadata->SetValue(
599             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
600             static_cast<std::string_view>(phaseLiteral)));
601         moduleRequestPhaseRecord.field_list.emplace_back(std::move(phaseIdxField));
602 
603         prog_->record_table.emplace(moduleRequestPhaseRecord.name, std::move(moduleRequestPhaseRecord));
604     }
605     auto &moduleRequestPhaseLiteralsBuffer = module->PhaseBuffer();
606     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleRequestPhaseLiteralsBuffer));
607     prog_->literalarray_table.emplace(static_cast<std::string_view>(phaseLiteral), std::move(literalArrayInstance));
608 }
609 
AddHasTopLevelAwaitRecord(bool hasTLA,const CompilerContext * context)610 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
611 {
612     if (context->IsMergeAbc()) {
613         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
614         hasTLAField.name = "hasTopLevelAwait";
615         hasTLAField.type = panda::pandasm::Type("u8", 0);
616         hasTLAField.metadata->SetValue(
617             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA))
618         );
619         rec_->field_list.emplace_back(std::move(hasTLAField));
620     } else if (hasTLA) {
621         auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
622         hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
623         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
624         hasTLAField.name = "hasTopLevelAwait";
625         hasTLAField.type = panda::pandasm::Type("u8", 0);
626         hasTLAField.metadata->SetValue(
627             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true))
628         );
629         hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
630 
631         prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
632     }
633 }
634 
AddSharedModuleRecord(const CompilerContext * context)635 void Emitter::AddSharedModuleRecord(const CompilerContext *context)
636 {
637     bool isShared = context->Binder()->Program()->IsShared();
638 
639     auto sharedModuleField = panda::pandasm::Field(LANG_EXT);
640     sharedModuleField.name = "isSharedModule";
641     sharedModuleField.type = panda::pandasm::Type("u8", 0);
642     sharedModuleField.metadata->SetValue(
643         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(isShared))
644     );
645 
646     if (context->IsMergeAbc()) {
647         rec_->field_list.emplace_back(std::move(sharedModuleField));
648     } else if (isShared) {
649         auto sharedModuleRecord = panda::pandasm::Record("_SharedModuleRecord", LANG_EXT);
650         sharedModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
651         sharedModuleRecord.field_list.emplace_back(std::move(sharedModuleField));
652         prog_->record_table.emplace(sharedModuleRecord.name, std::move(sharedModuleRecord));
653     }
654 }
655 
656 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t,std::vector<Literal>>> & literalBuffers,const LiteralBuffer * buff)657 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
658                                 const LiteralBuffer *buff)
659 {
660     auto &[idx, array] = literalBuffers.emplace_back();
661     idx = buff->Index();
662     constexpr size_t ARRAY_EXPANSION = 2;
663     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
664 
665     for (const auto *literal : buff->Literals()) {
666         panda::pandasm::LiteralArray::Literal valueLit;
667         panda::pandasm::LiteralArray::Literal tagLit;
668 
669         ir::LiteralTag tag = literal->Tag();
670 
671         switch (tag) {
672             case ir::LiteralTag::BOOLEAN: {
673                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
674                 valueLit.value_ = literal->GetBoolean();
675                 break;
676             }
677             case ir::LiteralTag::INTEGER: {
678                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
679                 valueLit.value_ = literal->GetInt();
680                 break;
681             }
682             case ir::LiteralTag::DOUBLE: {
683                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
684                 valueLit.value_ = literal->GetDouble();
685                 break;
686             }
687             case ir::LiteralTag::STRING: {
688                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
689                 valueLit.value_ = literal->GetString().Mutf8();
690                 break;
691             }
692             case ir::LiteralTag::ACCESSOR: {
693                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
694                 valueLit.value_ = static_cast<uint8_t>(0);
695                 break;
696             }
697             case ir::LiteralTag::METHOD: {
698                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
699                 valueLit.value_ = literal->GetMethod().Mutf8();
700                 break;
701             }
702             case ir::LiteralTag::METHODAFFILIATE: {
703                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
704                 valueLit.value_ = literal->GetMethodAffiliate();
705                 break;
706             }
707             case ir::LiteralTag::GENERATOR_METHOD: {
708                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
709                 valueLit.value_ = literal->GetMethod().Mutf8();
710                 break;
711             }
712             case ir::LiteralTag::LITERALBUFFERINDEX: {
713                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
714                 valueLit.value_ = literal->GetInt();
715                 break;
716             }
717             case ir::LiteralTag::LITERALARRAY: {
718                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
719                 valueLit.value_ = literal->GetString().Mutf8();
720                 break;
721             }
722             case ir::LiteralTag::BUILTINTYPEINDEX: {
723                 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
724                 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
725                 break;
726             }
727             case ir::LiteralTag::GETTER: {
728                 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
729                 valueLit.value_ = literal->GetMethod().Mutf8();
730                 break;
731             }
732             case ir::LiteralTag::SETTER: {
733                 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
734                 valueLit.value_ = literal->GetMethod().Mutf8();
735                 break;
736             }
737             case ir::LiteralTag::ASYNC_GENERATOR_METHOD: {
738                 valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD;
739                 valueLit.value_ = literal->GetMethod().Mutf8();
740                 break;
741             }
742             case ir::LiteralTag::NULL_VALUE: {
743                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
744                 valueLit.value_ = static_cast<uint8_t>(0);
745                 break;
746             }
747             default:
748                 break;
749         }
750 
751         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
752         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
753 
754         array.emplace_back(tagLit);
755         array.emplace_back(valueLit);
756     }
757 }
758 
DumpAsm(const panda::pandasm::Program * prog)759 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
760 {
761     auto &ss = std::cout;
762 
763     ss << ".language ECMAScript" << std::endl << std::endl;
764 
765     for (auto &[name, func] : prog->function_table) {
766         ss << "slotNum = 0x" << std::hex << func.GetSlotsNum() << std::dec << std::endl;
767         ss << ".function any " << name << '(';
768 
769         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
770             ss << "any a" << std::to_string(i);
771 
772             if (i != func.GetParamsNum() - 1) {
773                 ss << ", ";
774             }
775         }
776 
777         ss << ") {" << std::endl;
778 
779         for (const auto &ins : func.ins) {
780             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
781         }
782 
783         ss << "}" << std::endl << std::endl;
784 
785         for (const auto &ct : func.catch_blocks) {
786             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
787                << std::endl
788                << std::endl;
789         }
790     }
791 
792     ss << std::endl;
793 }
794 
Finalize(bool dumpDebugInfo,util::PatchFix * patchFixHelper)795 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
796 {
797     if (dumpDebugInfo) {
798         debuginfo::DebugInfoDumper dumper(prog_);
799         dumper.Dump();
800     }
801 
802     if (rec_) {
803         delete rec_;
804         rec_ = nullptr;
805     }
806 
807     if (patchFixHelper) {
808         patchFixHelper->Finalize(&prog_);
809     }
810 
811     auto *prog = prog_;
812     prog_ = nullptr;
813     return prog;
814 }
815 
GetProgram() const816 panda::pandasm::Program *Emitter::GetProgram() const
817 {
818     return prog_;
819 }
820 
AddSlotNumberRecord()821 void Emitter::AddSlotNumberRecord()
822 {
823     static const std::string SLOT_NUMBER = "_ESSlotNumberAnnotation";
824     pandasm::Record record(SLOT_NUMBER, pandasm::extensions::Language::ECMASCRIPT);
825     record.metadata->AddAccessFlags(panda::ACC_ANNOTATION);
826     prog_->record_table.emplace(SLOT_NUMBER, std::move(record));
827 }
828 
AddConcurrentModuleRequestsRecord()829 void Emitter::AddConcurrentModuleRequestsRecord()
830 {
831     static const std::string CONCURRENT_MODULE_REQUESTS = "_ESConcurrentModuleRequestsAnnotation";
832     pandasm::Record record(CONCURRENT_MODULE_REQUESTS, pandasm::extensions::Language::ECMASCRIPT);
833     record.metadata->AddAccessFlags(panda::ACC_ANNOTATION);
834     prog_->record_table.emplace(CONCURRENT_MODULE_REQUESTS, std::move(record));
835 }
836 
837 }  // namespace panda::es2panda::compiler
838