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/annotation.h>
29 #include <ir/base/classDefinition.h>
30 #include <ir/base/methodDefinition.h>
31 #include <ir/base/property.h>
32 #include <ir/base/scriptFunction.h>
33 #include <ir/expressions/arrayExpression.h>
34 #include <ir/expressions/callExpression.h>
35 #include <ir/expressions/functionExpression.h>
36 #include <ir/expressions/literal.h>
37 #include <ir/expressions/literals/booleanLiteral.h>
38 #include <ir/expressions/literals/numberLiteral.h>
39 #include <ir/expressions/literals/stringLiteral.h>
40 #include <ir/expressions/newExpression.h>
41 #include <ir/expressions/unaryExpression.h>
42 #include <ir/expressions/objectExpression.h>
43 #include <ir/statements/blockStatement.h>
44 #include <ir/statements/classDeclaration.h>
45 #include <ir/ts/tsArrayType.h>
46 #include <ir/ts/tsEnumMember.h>
47 #include <ir/ts/tsTypeParameterInstantiation.h>
48 #include <ir/ts/tsTypeReference.h>
49 #include <macros.h>
50 #include <parser/program/program.h>
51 #include <util/helpers.h>
52 
53 #include <string>
54 #include <string_view>
55 #include <tuple>
56 #include <utility>
57 
58 namespace panda::es2panda::compiler {
59 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
60 
FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)61 FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
62     : pg_(pg),
63       literalBuffers_(allocator->Adapter()),
64       literalArrays_(allocator->Adapter()),
65       externalAnnotationRecords_(allocator->Adapter())
66 {
67     func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
68     CHECK_NOT_NULL(func_);
69 
70     size_t paramCount = pg->InternalParamCount();
71     func_->params.reserve(paramCount);
72 
73     for (uint32_t i = 0; i < paramCount; ++i) {
74         func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
75     }
76 
77     func_->regs_num = pg->TotalRegsNum();
78     func_->return_type = panda::pandasm::Type("any", 0);
79 }
80 
Generate(util::PatchFix *patchFixHelper)81 void FunctionEmitter::Generate(util::PatchFix *patchFixHelper)
82 {
83     GenFunctionKind();
84     GenIcSize();
85     GenFunctionInstructions();
86     GenVariablesDebugInfo();
87     GenSourceFileDebugInfo();
88     GenFunctionCatchTables();
89     GenLiteralBuffers();
90     GenConcurrentFunctionModuleRequests();
91     GenAnnotations();
92     if (patchFixHelper != nullptr) {
93         patchFixHelper->ProcessFunction(pg_, func_, literalBuffers_);
94     }
95 }
96 
Strings() const97 const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
98 {
99     return pg_->Strings();
100 }
101 
GenFunctionKind()102 void FunctionEmitter::GenFunctionKind()
103 {
104     func_->SetFunctionKind(static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()));
105 }
106 
GenIcSize()107 void FunctionEmitter::GenIcSize()
108 {
109     func_->SetSlotsNum(pg_->GetCurrentSlot());
110 }
111 
GenBufferLiterals(const LiteralBuffer *buff)112 void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
113 {
114     Emitter::GenBufferLiterals(literalBuffers_, buff);
115 }
116 
SourceCode() const117 util::StringView FunctionEmitter::SourceCode() const
118 {
119     if (pg_->RootNode()->IsProgram()) {
120         return pg_->Binder()->Program()->SourceCode();
121     }
122     return static_cast<const ir::ScriptFunction *>(pg_->RootNode())->SourceCode(pg_->Binder());
123 }
124 
GetLineIndex() const125 lexer::LineIndex &FunctionEmitter::GetLineIndex() const
126 {
127     return const_cast<lexer::LineIndex &>(pg_->Binder()->Program()->GetLineIndex());
128 }
129 
MatchFormat(const IRNode *node, const Formats &formats)130 static Format MatchFormat(const IRNode *node, const Formats &formats)
131 {
132     std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
133     auto regCnt = node->Registers(&regs);
134     auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
135 
136     const auto *iter = formats.begin();
137 
138     for (; iter != formats.end(); iter++) {
139         auto format = *iter;
140         size_t limit = 0;
141         for (const auto &formatItem : format.GetFormatItem()) {
142             if (formatItem.IsVReg()) {
143                 limit = 1 << formatItem.Bitwidth();
144                 break;
145             }
146         }
147 
148         if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
149             return format;
150         }
151     }
152 
153     UNREACHABLE();
154     return *iter;
155 }
156 
GetIRNodeWholeLength(const IRNode *node)157 static size_t GetIRNodeWholeLength(const IRNode *node)
158 {
159     Formats formats = node->GetFormats();
160     if (formats.empty()) {
161         return 0;
162     }
163 
164     size_t len = 1;
165     constexpr size_t BIT_WIDTH = 8;
166     const auto format = MatchFormat(node, formats);
167 
168     for (auto fi : format.GetFormatItem()) {
169         len += fi.Bitwidth() / BIT_WIDTH;
170     }
171 
172     return len;
173 }
174 
WholeLine(const util::StringView &source, lexer::SourceRange range)175 [[maybe_unused]] static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
176 {
177     return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
178 }
179 
180 // This is for supporting setting breakpoint on the right parenthesis of a scriptFunciton.
UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)181 uint32_t FunctionEmitter::UpdateForReturnIns(const ir::AstNode *astNode, panda::pandasm::Ins *pandaIns)
182 {
183     constexpr size_t INVALID_LINE = -1;
184     constexpr uint32_t INVALID_COL = -1;
185     // The GetLocation method calculated position starts with 1, and
186     // the column number in pandaIns->ins_debug starts with 0
187     constexpr uint32_t OFFSET_COL = 1;
188     uint32_t columnNum = INVALID_COL;
189     if (pandaIns->opcode == pandasm::Opcode::RETURNUNDEFINED || pandaIns->opcode == pandasm::Opcode::RETURN) {
190         while (astNode != nullptr && !astNode->IsScriptFunction()) {
191             if (astNode->IsBlockStatement() &&
192                 astNode->AsBlockStatement()->Scope() &&
193                 astNode->AsBlockStatement()->Scope()->Node() &&
194                 astNode->AsBlockStatement()->Scope()->Node()->IsScriptFunction()) {
195                 astNode = astNode->AsBlockStatement()->Scope()->Node();
196                 break;
197             }
198             astNode = astNode->Parent();
199         }
200         pandaIns->ins_debug.line_number = astNode ? astNode->Range().end.line : INVALID_LINE;
201         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().end).col - OFFSET_COL) : INVALID_COL;
202     } else {
203         pandaIns->ins_debug.line_number = astNode ? astNode->Range().start.line : INVALID_LINE;
204         columnNum = astNode ? (GetLineIndex().GetLocation(astNode->Range().start).col - OFFSET_COL) : INVALID_COL;
205     }
206     return columnNum;
207 }
208 
GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)209 void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
210 {
211     const ir::AstNode *astNode = ins->Node();
212     if (astNode == FIRST_NODE_OF_FUNCTION) {
213         astNode = pg_->Debuginfo().firstStmt;
214         if (!astNode) {
215             return;
216         }
217     }
218     uint32_t columnNum = UpdateForReturnIns(astNode, pandaIns);
219 
220     if (pg_->IsDebug()) {
221         size_t insLen = GetIRNodeWholeLength(ins);
222         if (insLen != 0) {
223             pandaIns->ins_debug.bound_left = offset_;
224             pandaIns->ins_debug.bound_right = offset_ + insLen;
225         }
226 
227         offset_ += insLen;
228         pandaIns->ins_debug.column_number = columnNum;
229     }
230 }
231 
ProcessNewExpressionInLiteralArray( const ir::Expression *array)232 static std::vector<panda::pandasm::LiteralArray::Literal> ProcessNewExpressionInLiteralArray(
233     const ir::Expression *array)
234 {
235     std::vector<panda::pandasm::LiteralArray::Literal> literals;
236 
237     const auto &typeParams = array->AsNewExpression()->TypeParams()->Params();
238     auto type = typeParams[0]->Type();
239     literals.emplace_back(
240         pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
241                                         static_cast<uint8_t>(panda::panda_file::LiteralTag::BUILTINTYPEINDEX)});
242     switch (type) {
243         case ir::AstNodeType::TS_NUMBER_KEYWORD: {
244             literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
245                                                               ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_NUMBER_TYPE});
246             break;
247         }
248         case ir::AstNodeType::TS_BOOLEAN_KEYWORD: {
249             literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
250                                                               ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_BOOLEAN_TYPE});
251             break;
252         }
253         case ir::AstNodeType::TS_STRING_KEYWORD: {
254             literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
255                                                               ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_STRING_TYPE});
256             break;
257         }
258         case ir::AstNodeType::TS_TYPE_REFERENCE: {
259             const auto &args = array->AsNewExpression()->Arguments();
260             uint8_t value = args[0]->AsNumberLiteral()->Number<uint8_t>();
261             if (value == ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_NUMBER_TYPE) {
262                 // By convention, this is an empty array of enums with underlying number type
263                 literals.emplace_back(pandasm::LiteralArray::Literal {
264                     panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
265                     ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_NUMBER_TYPE});
266             } else if (value == ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_STRING_TYPE) {
267                 // By convention, this is an empty array of enums with underlying string type
268                 literals.emplace_back(pandasm::LiteralArray::Literal {
269                     panda::panda_file::LiteralTag::BUILTINTYPEINDEX,
270                     ir::Annotation::EMPTY_LITERAL_ARRAY_WITH_STRING_TYPE});
271             } else {
272                 UNREACHABLE();
273             }
274             break;
275         }
276         default:
277             UNREACHABLE();
278     }
279 
280     return literals;
281 }
282 
ProcessArrayExpressionInLiteralArray( const ir::Expression *array, const std::string &baseName, std::vector<std::pair<std::string, std::vector<Literal>>> &result)283 static std::vector<panda::pandasm::LiteralArray::Literal> ProcessArrayExpressionInLiteralArray(
284     const ir::Expression *array, const std::string &baseName,
285     std::vector<std::pair<std::string, std::vector<Literal>>> &result)
286 {
287     std::vector<panda::pandasm::LiteralArray::Literal> literals;
288     ArenaVector<ir::Expression *> elements {array->AsArrayExpression()->Elements()};
289 
290     for (const auto *elem : elements) {
291         if (elem->IsArrayExpression() || elem->IsNewExpression()) {
292             auto litArrays = Emitter::CreateLiteralArray(elem, baseName);
293             literals.emplace_back(
294                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
295                                                 static_cast<uint8_t>(panda::panda_file::LiteralTag::LITERALARRAY)});
296             literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::LITERALARRAY,
297                                                                   litArrays.back().first});
298             for (auto item : litArrays) {
299                 result.push_back(item);
300             }
301         } else if (elem->IsNumberLiteral()) {
302             double doubleValue = elem->AsNumberLiteral()->Number();
303             literals.emplace_back(
304                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
305                                                 static_cast<uint8_t>(panda::panda_file::LiteralTag::DOUBLE)});
306             literals.emplace_back(
307                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::DOUBLE, doubleValue});
308         } else if (elem->IsBooleanLiteral()) {
309             bool boolValue = elem->AsBooleanLiteral()->Value();
310             literals.emplace_back(
311                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
312                                                 static_cast<uint8_t>(panda::panda_file::LiteralTag::BOOL)});
313             literals.emplace_back(pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::BOOL, boolValue});
314         } else if (elem->IsStringLiteral()) {
315             std::string stringValue {elem->AsStringLiteral()->Str().Utf8()};
316             literals.emplace_back(
317                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
318                                                 static_cast<uint8_t>(panda::panda_file::LiteralTag::STRING)});
319             literals.emplace_back(
320                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::STRING, stringValue});
321         } else if (elem->IsUnaryExpression()) {
322             ASSERT(elem->AsUnaryExpression()->IsNegativeNumber());
323             // In annotations other unary operators (+, !, ~) are evaluated in tsc.
324             // Only unary minus may be present in intermediate .ts
325             double doubleValue = (-1) * elem->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
326             literals.emplace_back(
327                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::TAGVALUE,
328                                                 static_cast<uint8_t>(panda::panda_file::LiteralTag::DOUBLE)});
329             literals.emplace_back(
330                 pandasm::LiteralArray::Literal {panda::panda_file::LiteralTag::DOUBLE, doubleValue});
331         } else {
332             UNREACHABLE();
333         }
334     }
335 
336     return literals;
337 }
338 
CreateLiteralArray(const ir::Expression *array, const std::string &baseName)339 std::vector<std::pair<std::string, std::vector<Literal>>> Emitter::CreateLiteralArray(const ir::Expression *array,
340                                                                                       const std::string &baseName)
341 {
342     std::vector<std::pair<std::string, std::vector<Literal>>> result;
343     std::vector<panda::pandasm::LiteralArray::Literal> literals;
344 
345     if (array->IsNewExpression()) {
346         // special case, when initializer is an empty array
347         literals = ProcessNewExpressionInLiteralArray(array);
348     } else {
349         literals = ProcessArrayExpressionInLiteralArray(array, baseName, result);
350     }
351 
352     static uint32_t litArrayValueCount = 0;
353     std::string litArrayName = baseName + "_" + std::to_string(litArrayValueCount);
354     ++litArrayValueCount;
355     result.push_back(std::make_pair(litArrayName, literals));
356     return result;
357 }
358 
CreateAnnotationElement(const std::string &propName, const ir::Expression *initValue)359 pandasm::AnnotationElement FunctionEmitter::CreateAnnotationElement(const std::string &propName,
360                                                                     const ir::Expression *initValue)
361 {
362     if (initValue->IsArrayExpression() || initValue->IsNewExpression()) {
363         std::string baseName {func_->name + "_" + propName};
364         auto litArrays = Emitter::CreateLiteralArray(initValue, baseName);
365         for (auto item : litArrays) {
366             literalArrays_.push_back(item);
367         }
368         return pandasm::AnnotationElement {
369             propName,
370             std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::LITERALARRAY>(
371                 std::string_view {litArrays.back().first}))};
372     } else if (initValue->IsNumberLiteral()) {
373         return pandasm::AnnotationElement {
374             propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(
375                           initValue->AsNumberLiteral()->Number()))};
376     } else if (initValue->IsBooleanLiteral()) {
377         return pandasm::AnnotationElement {
378             propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
379                           initValue->AsBooleanLiteral()->Value()))};
380     } else if (initValue->IsStringLiteral()) {
381         std::string_view stringValue {initValue->AsStringLiteral()->Str().Utf8()};
382         return pandasm::AnnotationElement {
383             propName, std::make_unique<pandasm::ScalarValue>(
384                           pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(stringValue))};
385     } else if (initValue->IsUnaryExpression()) {
386         ASSERT(initValue->AsUnaryExpression()->IsNegativeNumber());
387         // In annotations other unary operators (+, !, ~) are evaluated in tsc.
388         // Only unary minus may be present in intermediate .ts
389         double negNumberValue = (-1) * initValue->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
390         return pandasm::AnnotationElement {
391             propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(
392                           negNumberValue))};
393     } else {
394         UNREACHABLE();
395     }
396 }
397 
CreateExternalAnnotationRecord(const std::string &name)398 static pandasm::Record CreateExternalAnnotationRecord(const std::string &name)
399 {
400     pandasm::Record record(name, pandasm::extensions::Language::ECMASCRIPT);
401     record.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
402     record.metadata->SetAttribute("external");
403     return record;
404 }
405 
CreateAnnotation(const ir::Annotation *anno)406 pandasm::AnnotationData FunctionEmitter::CreateAnnotation(const ir::Annotation *anno)
407 {
408     std::string annoName = std::string(anno->Name());
409     if (pg_->Context()->IsMergeAbc()) {
410         std::string prefix = std::string(pg_->Context()->RecordName()) + ".";
411         annoName.insert(0, prefix);
412     }
413     pandasm::AnnotationData annotation(annoName);
414 
415     if (anno->IsImported()) {
416         externalAnnotationRecords_.push_back(CreateExternalAnnotationRecord(annoName));
417     }
418 
419     if (!anno->Expr()->IsCallExpression()) {
420         [[maybe_unused]] auto checkExpr = anno->Expr()->IsIdentifier() || anno->Expr()->IsMemberExpression();
421         ASSERT(checkExpr == true);
422         return annotation;
423     }
424 
425     const ir::CallExpression *callExpr = anno->Expr()->AsCallExpression();
426     if (callExpr->Arguments().size() == 0) {
427         return annotation;
428     }
429 
430     // By convention, all properties are initialized in TSC, so that we don't need to process
431     // default arguments in annotation interface declaration
432     for (auto prop : callExpr->Arguments()[0]->AsObjectExpression()->Properties()) {
433         std::string propName {prop->AsProperty()->Key()->AsIdentifier()->Name()};
434         const ir::Expression *initValue = prop->AsProperty()->Value();
435         annotation.AddElement(CreateAnnotationElement(propName, initValue));
436     }
437 
438     return annotation;
439 }
440 
GenAnnotations()441 void FunctionEmitter::GenAnnotations()
442 {
443     if (!pg_->RootNode()->IsScriptFunction()) {
444         return;
445     }
446 
447     auto *scriptFunction = pg_->RootNode()->AsScriptFunction();
448     if (!scriptFunction->Parent() || !scriptFunction->Parent()->Parent() ||
449         !scriptFunction->Parent()->Parent()->IsMethodDefinition()) {
450         return;
451     }
452 
453     auto *methodDefinition = scriptFunction->Parent()->Parent()->AsMethodDefinition();
454     std::vector<pandasm::AnnotationData> annotations;
455     for (auto *anno : methodDefinition->Annotations()) {
456         annotations.emplace_back(CreateAnnotation(anno));
457     }
458 
459     func_->metadata->AddAnnotations(annotations);
460 }
461 
GenFunctionInstructions()462 void FunctionEmitter::GenFunctionInstructions()
463 {
464     func_->ins.reserve(pg_->Insns().size());
465 
466     for (const auto *ins : pg_->Insns()) {
467         auto &pandaIns = func_->ins.emplace_back();
468 
469         ins->Transform(&pandaIns);
470         GenInstructionDebugInfo(ins, &pandaIns);
471     }
472 }
473 
GenFunctionCatchTables()474 void FunctionEmitter::GenFunctionCatchTables()
475 {
476     func_->catch_blocks.reserve(pg_->CatchList().size());
477 
478     for (const auto *catchBlock : pg_->CatchList()) {
479         const auto &labelSet = catchBlock->LabelSet();
480 
481         auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
482         pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
483         pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
484         pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
485         pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
486     }
487 }
488 
GenLiteralBuffers()489 void FunctionEmitter::GenLiteralBuffers()
490 {
491     for (const auto *buff : pg_->BuffStorage()) {
492         GenBufferLiterals(buff);
493     }
494 }
495 
GenSourceFileDebugInfo()496 void FunctionEmitter::GenSourceFileDebugInfo()
497 {
498     if (pg_->SourceFile().empty()) {
499         func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
500     } else {
501         func_->source_file = pg_->SourceFile();
502     }
503 
504     if (!pg_->IsDebug()) {
505         return;
506     }
507 
508     if (pg_->RootNode()->IsProgram()) {
509         if (pg_->Context()->IsRecordDebugSource()) {
510             func_->source_code = SourceCode().Mutf8();
511         } else {
512             func_->source_code = "not supported";
513         }
514     }
515 }
516 
GenScopeVariableInfo(const binder::Scope *scope)517 void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
518 {
519     const auto *startIns = scope->ScopeStart();
520     const auto *endIns = scope->ScopeEnd();
521 
522     uint32_t start = 0;
523     uint32_t count = 0;
524 
525     for (const auto *it : pg_->Insns()) {
526         if (startIns == it) {
527             start = count;
528         } else if (endIns == it) {
529             auto varsLength = static_cast<uint32_t>(count - start + 1);
530 
531             for (const auto &[name, variable] : scope->Bindings()) {
532                 if (!variable->IsLocalVariable() || variable->LexicalBound()) {
533                     continue;
534                 }
535 
536                 auto &variableDebug = func_->local_variable_debug.emplace_back();
537                 variableDebug.name = name.Mutf8();
538                 variableDebug.signature = "any";
539                 variableDebug.signature_type = "any";
540                 // Register spill causes an offset being applied to all registers in all instructions (refer to
541                 // RegAllocator::AdjustInsRegWhenHasSpill for more details). Therefore, we also add this offset
542                 // to the variable-to-register mapping before dumping it to the debug information of the abc file
543                 // (the following code).
544                 // We do not correct the original variable mapping in the scope object since it is not used after
545                 // the register spill phase, while we do not know the number of spilled registers before that phase.
546                 // If any future modifications require access to the variable mapping after the register spill,
547                 // please correct the mapping first and remove the offset increment operation in the following code.
548                 variableDebug.reg =
549                     static_cast<int32_t>(variable->AsLocalVariable()->Vreg()) + pg_->GetSpillRegsCount();
550                 variableDebug.start = start;
551                 variableDebug.length = static_cast<uint32_t>(varsLength);
552             }
553 
554             break;
555         }
556 
557         count++;
558     }
559 }
560 
GenVariablesDebugInfo()561 void FunctionEmitter::GenVariablesDebugInfo()
562 {
563     if (!pg_->IsDebug()) {
564         return;
565     }
566 
567     for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
568         GenScopeVariableInfo(scope);
569     }
570 }
571 
GenConcurrentFunctionModuleRequests()572 void FunctionEmitter::GenConcurrentFunctionModuleRequests()
573 {
574     if (static_cast<panda::panda_file::FunctionKind>(pg_->GetFunctionKind()) !=
575         panda::panda_file::FunctionKind::CONCURRENT_FUNCTION) {
576         return;
577     }
578 
579     std::vector<int> moduleRequests =
580         static_cast<const ir::ScriptFunction *>(pg_->RootNode())->GetConcurrentModuleRequests();
581     func_->concurrent_module_requests.reserve(moduleRequests.size());
582     for (auto it : moduleRequests) {
583         func_->concurrent_module_requests.emplace_back(it);
584     }
585 }
586 
587 // Emitter
588 
Emitter(CompilerContext *context)589 Emitter::Emitter(CompilerContext *context)
590 {
591     prog_ = new panda::pandasm::Program();
592     prog_->lang = LANG_EXT;
593 
594     if (context->IsJsonInputFile()) {
595         GenJsonContentRecord(context);
596         return;
597     }
598 
599     if (context->IsMergeAbc()) {
600         auto recordName = context->Binder()->Program()->FormatedRecordName().Mutf8();
601         rec_ = new panda::pandasm::Record(recordName.substr(0, recordName.find_last_of('.')), LANG_EXT);
602         SetPkgNameField(context->PkgName());
603         SetCommonjsField(context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS);
604     } else {
605         rec_ = nullptr;
606         if (context->Binder()->Program()->Kind() == parser::ScriptKind::COMMONJS) {
607             GenCommonjsRecord();
608         }
609     }
610     if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) {
611         AddHasTopLevelAwaitRecord(context->Binder()->Program()->HasTLA(), context);
612     }
613     AddSharedModuleRecord(context);
614     AddScopeNamesRecord(context);
615 }
616 
~Emitter()617 Emitter::~Emitter()
618 {
619     delete prog_;
620 }
621 
SetPkgNameField(const std::string &pkgName)622 void Emitter::SetPkgNameField(const std::string &pkgName)
623 {
624     auto pkgNameField = panda::pandasm::Field(LANG_EXT);
625     pkgNameField.name = "pkgName@" + pkgName;
626     pkgNameField.type = panda::pandasm::Type("u8", 0);
627     pkgNameField.metadata->SetValue(
628         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(0)));
629     rec_->field_list.emplace_back(std::move(pkgNameField));
630 }
631 
GenRecordNameInfo() const632 void Emitter::GenRecordNameInfo() const
633 {
634     if (rec_) {
635         prog_->record_table.emplace(rec_->name, std::move(*rec_));
636     }
637 }
638 
GenJsonContentRecord(const CompilerContext *context)639 void Emitter::GenJsonContentRecord(const CompilerContext *context)
640 {
641     rec_ = new panda::pandasm::Record(std::string(context->RecordName()), panda::panda_file::SourceLang::ECMASCRIPT);
642     auto jsonContentField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
643     jsonContentField.name = "jsonFileContent";
644     jsonContentField.type = panda::pandasm::Type("u32", 0);
645     jsonContentField.metadata->SetValue(panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(
646         static_cast<std::string_view>(context->SourceFile())));
647     rec_->field_list.emplace_back(std::move(jsonContentField));
648     if (context->PatchFixHelper()) {
649         context->PatchFixHelper()->ProcessJsonContentRecord(rec_->name, context->SourceFile());
650     }
651 }
652 
AddFunction(FunctionEmitter *func, CompilerContext *context)653 void Emitter::AddFunction(FunctionEmitter *func, CompilerContext *context)
654 {
655     std::lock_guard<std::mutex> lock(m_);
656 
657     for (const auto &str : func->Strings()) {
658         prog_->strings.insert(str.Mutf8());
659     }
660 
661     for (auto &[idx, buf] : func->LiteralBuffers()) {
662         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
663         auto litId = std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
664         prog_->literalarray_table.emplace(litId, std::move(literalArrayInstance));
665     }
666 
667     for (auto &[name, buf] : func->LiteralArrays()) {
668         auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
669         prog_->literalarray_table.emplace(name, std::move(literalArrayInstance));
670     }
671 
672     for (auto &&rec : func->ExternalAnnotationRecords()) {
673         prog_->record_table.emplace(rec.name, std::move(rec));
674     }
675 
676     auto *function = func->Function();
677     prog_->function_table.emplace(function->name, std::move(*function));
678 }
679 
AddScopeNamesRecord(CompilerContext *context)680 void Emitter::AddScopeNamesRecord(CompilerContext *context)
681 {
682     std::lock_guard<std::mutex> lock(m_);
683     // make literalarray for scope names
684     if (util::Helpers::IsDefaultApiVersion(context->Binder()->Program()->TargetApiVersion(),
685         context->Binder()->Program()->GetTargetApiSubVersion())) {
686         return;
687     }
688     const auto &scopeNamesMap = context->Binder()->GetScopeNames();
689 
690     panda::pandasm::LiteralArray array;
691     const int32_t DOUBLE_SIZE = 2;
692     array.literals_.resize(scopeNamesMap.size() * DOUBLE_SIZE);
693     auto strTag = panda_file::LiteralTag::STRING;
694     for (const auto &[scopeName, index] : scopeNamesMap) {
695         panda::pandasm::LiteralArray::Literal tag;
696         tag.tag_ = panda_file::LiteralTag::TAGVALUE;
697         tag.value_ = static_cast<uint8_t>(strTag);
698         array.literals_.at(index * DOUBLE_SIZE) = std::move(tag);
699         panda::pandasm::LiteralArray::Literal val;
700         val.tag_ = strTag;
701         val.value_ = std::string(scopeName);
702         array.literals_.at(index * DOUBLE_SIZE + 1) = std::move(val);
703     }
704     auto literalKey =
705         std::string(context->Binder()->Program()->RecordName()) + "_" + std::to_string(context->NewLiteralIndex());
706     prog_->literalarray_table.emplace(literalKey, std::move(array));
707 
708     // ScopeNames is a literalarray in each record if it is in mergeAbc, it is a string array which put scope names.
709     // _ESScopeNamesRecord is a literalarray in the record when it is not in mergeAbc.
710     if (context->IsMergeAbc()) {
711         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
712         scopeNamesField.name = "scopeNames";
713         scopeNamesField.type = panda::pandasm::Type("u32", 0);
714         scopeNamesField.metadata->SetValue(
715             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
716                 static_cast<std::string_view>(literalKey)));
717         rec_->field_list.emplace_back(std::move(scopeNamesField));
718     } else {
719         auto scopeNamesRecord = panda::pandasm::Record("_ESScopeNamesRecord", LANG_EXT);
720         scopeNamesRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
721         auto scopeNamesField = panda::pandasm::Field(LANG_EXT);
722         // If the input arg "source-file" is not specified, context->SourceFile() will be empty,
723         // in this case, use it's absolute path.
724         if (context->SourceFile().empty()) {
725             scopeNamesField.name = context->Binder()->Program()->SourceFile().Mutf8();
726         } else {
727             scopeNamesField.name = context->SourceFile();
728         }
729         scopeNamesField.type = panda::pandasm::Type("u32", 0);
730         scopeNamesField.metadata->SetValue(
731             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
732                 static_cast<std::string_view>(literalKey)));
733         scopeNamesRecord.field_list.emplace_back(std::move(scopeNamesField));
734         prog_->record_table.emplace(scopeNamesRecord.name, std::move(scopeNamesRecord));
735     }
736 }
737 
CreateStringClass()738 void Emitter::CreateStringClass()
739 {
740     if (prog_->record_table.find(ir::Annotation::stringClassName) == prog_->record_table.end()) {
741         pandasm::Record record(ir::Annotation::stringClassName, pandasm::extensions::Language::ECMASCRIPT);
742         record.metadata->SetAttribute("external");
743         prog_->record_table.emplace(ir::Annotation::stringClassName, std::move(record));
744     }
745 }
746 
DeduceArrayEnumType(const ir::Expression *value, uint8_t rank, bool &needToCreateArrayValue)747 panda::pandasm::Type Emitter::DeduceArrayEnumType(const ir::Expression *value, uint8_t rank,
748                                                   bool &needToCreateArrayValue)
749 {
750     // By convention, array of enum must always has initializer
751     ASSERT(value != nullptr);
752     while (value->IsArrayExpression()) {
753         const auto &elements = value->AsArrayExpression()->Elements();
754         value = elements[0];
755     }
756 
757     if (value->IsNumberLiteral()) {
758         return panda::pandasm::Type("f64", rank);
759     } else if (value->IsStringLiteral()) {
760         CreateStringClass();
761         return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
762     } else if (value->IsNewExpression()) {
763         const auto &args = value->AsNewExpression()->Arguments();
764         uint8_t value = args[0]->AsNumberLiteral()->Number<uint8_t>();
765         switch (value) {
766             // By convention, this is an array of enums with underlying number type without initializer
767             case ir::Annotation::ENUM_LITERAL_ARRAY_WITHOUT_INITIALIZER_NUMBER_TYPE: {
768                 needToCreateArrayValue = false;
769                 return panda::pandasm::Type("f64", rank);
770             }
771             case ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_NUMBER_TYPE: {
772                 // By convention, this is an array of enums with underlying number type with empty array initializer
773                 needToCreateArrayValue = true;
774                 return panda::pandasm::Type("f64", rank);
775             }
776             case ir::Annotation::ENUM_LITERAL_ARRAY_WITHOUT_INITIALIZER_STRING_TYPE: {
777                 // By convention, this is an array of enums with underlying string type without initializer
778                 needToCreateArrayValue = false;
779                 CreateStringClass();
780                 return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
781             }
782             case ir::Annotation::ENUM_LITERAL_ARRAY_WITH_EMPTY_INITIALIZER_STRING_TYPE: {
783                 // By convention, this is an array of enums with underlying string type with empty array initializer
784                 needToCreateArrayValue = true;
785                 CreateStringClass();
786                 return panda::pandasm::Type(ir::Annotation::stringClassName, rank);
787             }
788             default:
789                 UNREACHABLE();
790         }
791     }
792     UNREACHABLE();
793 }
794 
CreateLiteralArrayProp(const ir::ClassProperty *prop, const std::string &annoName, panda::pandasm::Field &annoRecordField)795 void Emitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, const std::string &annoName,
796                                      panda::pandasm::Field &annoRecordField)
797 {
798     uint8_t rank = 1;
799     auto *elemType = prop->TypeAnnotation()->AsTSArrayType()->ElementType();
800     while (elemType->Type() == ir::AstNodeType::TS_ARRAY_TYPE) {
801         ++rank;
802         elemType = elemType->AsTSArrayType()->ElementType();
803     }
804 
805     if (elemType->Type() == ir::AstNodeType::TS_NUMBER_KEYWORD) {
806         annoRecordField.type = panda::pandasm::Type("f64", rank);
807     } else if (elemType->Type() == ir::AstNodeType::TS_BOOLEAN_KEYWORD) {
808         annoRecordField.type = panda::pandasm::Type("u1", rank);
809     } else if (elemType->Type() == ir::AstNodeType::TS_STRING_KEYWORD) {
810         CreateStringClass();
811         annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, rank);
812     } else if (elemType->Type() == ir::AstNodeType::TS_TYPE_REFERENCE) {
813         bool needToCreateArrayValue = true;
814         annoRecordField.type = DeduceArrayEnumType(prop->Value(), rank, needToCreateArrayValue);
815         if (!needToCreateArrayValue) {
816             return;
817         }
818     } else {
819         UNREACHABLE();
820     }
821 
822     auto value = prop->Value();
823     if (value != nullptr) {
824         std::string baseName = annoName + "_" + annoRecordField.name;
825         auto litArray = Emitter::CreateLiteralArray(value, baseName);
826         for (auto item : litArray) {
827             prog_->literalarray_table.emplace(item.first, pandasm::LiteralArray(item.second));
828         }
829         annoRecordField.metadata->SetValue(
830             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
831                 std::string_view {litArray.back().first}));
832     }
833 }
834 
CreateEnumProp(const ir::ClassProperty *prop, const std::string &annoName, panda::pandasm::Field &annoRecordField)835 void Emitter::CreateEnumProp(const ir::ClassProperty *prop, const std::string &annoName,
836                              panda::pandasm::Field &annoRecordField)
837 {
838     auto value = prop->Value();
839     if (value == nullptr) {
840         // By convention, if annotation interface prop has no init value,
841         // then underlying type of annotation is string
842         CreateStringClass();
843         annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
844     } else if (value->IsTSAsExpression()) {
845         // By convention, if annotation interface prop has init value "new Number(0) as number",
846         // then underlying type of annotation is number
847         annoRecordField.type = panda::pandasm::Type("f64", 0);
848     } else if (value->IsStringLiteral()) {
849         CreateStringClass();
850         annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
851         std::string_view stringValue {value->AsStringLiteral()->Str().Utf8()};
852         annoRecordField.metadata->SetValue(
853             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(stringValue));
854     } else if (value->IsNumberLiteral()) {
855         annoRecordField.type = panda::pandasm::Type("f64", 0);
856         double doubleValue = value->AsNumberLiteral()->Number();
857         annoRecordField.metadata->SetValue(
858             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
859     } else if (value->IsUnaryExpression()) {
860         ASSERT(value->AsUnaryExpression()->IsNegativeNumber());
861         // In annotations other unary operators (+, !, ~) are evaluated in tsc.
862         // Only unary minus may be present in intermediate .ts
863         annoRecordField.type = panda::pandasm::Type("f64", 0);
864         double doubleValue = (-1) * value->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number();
865         annoRecordField.metadata->SetValue(
866             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
867     } else {
868         UNREACHABLE();
869     }
870 }
871 
CreateAnnotationProp(const ir::ClassProperty *prop, const std::string &annoName)872 panda::pandasm::Field Emitter::CreateAnnotationProp(const ir::ClassProperty *prop, const std::string &annoName)
873 {
874     auto annoRecordField = panda::pandasm::Field(panda::panda_file::SourceLang::ECMASCRIPT);
875     annoRecordField.name = std::string(prop->Key()->AsIdentifier()->Name());
876 
877     auto propType = prop->TypeAnnotation()->Type();
878     auto value = prop->Value();
879     if (propType == ir::AstNodeType::TS_NUMBER_KEYWORD) {
880         annoRecordField.type = panda::pandasm::Type("f64", 0);
881         if (value != nullptr) {
882             double doubleValue = 0.0;
883             if (value->IsUnaryExpression()) {
884                 ASSERT(value->AsUnaryExpression()->IsNegativeNumber());
885                 // In annotations other unary operators (+, !, ~) are evaluated in tsc.
886                 // Only unary minus may be present in intermediate .ts
887                 value = value->AsUnaryExpression()->Argument();
888                 doubleValue = (-1) * value->AsNumberLiteral()->Number();
889             } else {
890                 doubleValue = value->AsNumberLiteral()->Number();
891             }
892             annoRecordField.metadata->SetValue(
893                 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::F64>(doubleValue));
894         }
895     } else if (propType == ir::AstNodeType::TS_BOOLEAN_KEYWORD) {
896         annoRecordField.type = panda::pandasm::Type("u1", 0);
897         if (value != nullptr) {
898             bool boolValue = value->AsBooleanLiteral()->Value();
899             annoRecordField.metadata->SetValue(
900                 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U1>(boolValue));
901         }
902     } else if (propType == ir::AstNodeType::TS_STRING_KEYWORD) {
903         CreateStringClass();
904         annoRecordField.type = panda::pandasm::Type(ir::Annotation::stringClassName, 0);
905         if (value != nullptr) {
906             std::string_view stringValue {value->AsStringLiteral()->Str().Utf8()};
907             annoRecordField.metadata->SetValue(
908                 panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(stringValue));
909         }
910     } else if (propType == ir::AstNodeType::TS_ARRAY_TYPE) {
911         CreateLiteralArrayProp(prop, annoName, annoRecordField);
912     } else if (propType == ir::AstNodeType::TS_TYPE_REFERENCE) {
913         CreateEnumProp(prop, annoName, annoRecordField);
914     } else {
915         UNREACHABLE();
916     }
917 
918     return annoRecordField;
919 }
920 
AddAnnotationRecord(const std::string &annoName, const ir::ClassDeclaration *classDecl)921 void Emitter::AddAnnotationRecord(const std::string &annoName, const ir::ClassDeclaration *classDecl)
922 {
923     pandasm::Record record(annoName, pandasm::extensions::Language::ECMASCRIPT);
924     record.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
925 
926     for (auto bodyItem : classDecl->Definition()->Body()) {
927         record.field_list.emplace_back(CreateAnnotationProp(bodyItem->AsClassProperty(), annoName));
928     }
929 
930     prog_->record_table.emplace(annoName, std::move(record));
931 }
932 
AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)933 void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, CompilerContext *context)
934 {
935     std::lock_guard<std::mutex> lock(m_);
936 
937     if (module->NeedEmitPhaseRecord()) {
938         AddModuleRequestPhaseRecord(module, context);
939     }
940 
941     auto moduleLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
942          std::to_string(module->Index());
943     if (context->IsMergeAbc()) {
944         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
945         moduleIdxField.name = "moduleRecordIdx";
946         moduleIdxField.type = panda::pandasm::Type("u32", 0);
947         moduleIdxField.metadata->SetValue(
948             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
949                 static_cast<std::string_view>(moduleLiteral)));
950         rec_->field_list.emplace_back(std::move(moduleIdxField));
951 
952         if (context->PatchFixHelper()) {
953             context->PatchFixHelper()->ProcessModule(rec_->name, module->Buffer());
954         }
955     } else {
956         auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT);
957         ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
958 
959         auto moduleIdxField = panda::pandasm::Field(LANG_EXT);
960         moduleIdxField.name = context->Binder()->Program()->ModuleRecordFieldName().empty() ?
961                               std::string {context->Binder()->Program()->SourceFile()} :
962                               context->Binder()->Program()->ModuleRecordFieldName();
963         moduleIdxField.type = panda::pandasm::Type("u32", 0);
964         moduleIdxField.metadata->SetValue(
965             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
966                 static_cast<std::string_view>(moduleLiteral)));
967         ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField));
968 
969         if (context->PatchFixHelper()) {
970             context->PatchFixHelper()->ProcessModule(ecmaModuleRecord.name, module->Buffer());
971         }
972         prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord));
973     }
974     auto &moduleLiteralsBuffer = module->Buffer();
975     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer));
976     prog_->literalarray_table.emplace(static_cast<std::string_view>(moduleLiteral), std::move(literalArrayInstance));
977     constant_local_export_slots_ = module->GetConstantLocalExportSlots();
978 }
979 
AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)980 void Emitter::AddModuleRequestPhaseRecord(ModuleRecordEmitter *module, CompilerContext *context)
981 {
982     auto phaseLiteral = std::string(context->Binder()->Program()->RecordName()) + "_" +
983          std::to_string(module->PhaseIndex());
984     if (context->IsMergeAbc()) {
985         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
986         phaseIdxField.name = "moduleRequestPhaseIdx";
987         phaseIdxField.type = panda::pandasm::Type("u32", 0);
988         phaseIdxField.metadata->SetValue(
989             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
990             static_cast<std::string_view>(phaseLiteral)));
991         rec_->field_list.emplace_back(std::move(phaseIdxField));
992     } else {
993         auto moduleRequestPhaseRecord = panda::pandasm::Record("_ModuleRequestPhaseRecord", LANG_EXT);
994         moduleRequestPhaseRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
995 
996         auto phaseIdxField = panda::pandasm::Field(LANG_EXT);
997         phaseIdxField.name = "moduleRequestPhaseIdx";
998         phaseIdxField.type = panda::pandasm::Type("u32", 0);
999         phaseIdxField.metadata->SetValue(
1000             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(
1001             static_cast<std::string_view>(phaseLiteral)));
1002         moduleRequestPhaseRecord.field_list.emplace_back(std::move(phaseIdxField));
1003 
1004         prog_->record_table.emplace(moduleRequestPhaseRecord.name, std::move(moduleRequestPhaseRecord));
1005     }
1006     auto &moduleRequestPhaseLiteralsBuffer = module->PhaseBuffer();
1007     auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleRequestPhaseLiteralsBuffer));
1008     prog_->literalarray_table.emplace(static_cast<std::string_view>(phaseLiteral), std::move(literalArrayInstance));
1009 }
1010 
AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)1011 void Emitter::AddHasTopLevelAwaitRecord(bool hasTLA, const CompilerContext *context)
1012 {
1013     if (context->IsMergeAbc()) {
1014         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
1015         hasTLAField.name = "hasTopLevelAwait";
1016         hasTLAField.type = panda::pandasm::Type("u8", 0);
1017         hasTLAField.metadata->SetValue(
1018             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(hasTLA)));
1019         rec_->field_list.emplace_back(std::move(hasTLAField));
1020     } else if (hasTLA) {
1021         auto hasTLARecord = panda::pandasm::Record("_HasTopLevelAwait", LANG_EXT);
1022         hasTLARecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
1023         auto hasTLAField = panda::pandasm::Field(LANG_EXT);
1024         hasTLAField.name = "hasTopLevelAwait";
1025         hasTLAField.type = panda::pandasm::Type("u8", 0);
1026         hasTLAField.metadata->SetValue(
1027             panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(true)));
1028         hasTLARecord.field_list.emplace_back(std::move(hasTLAField));
1029 
1030         prog_->record_table.emplace(hasTLARecord.name, std::move(hasTLARecord));
1031     }
1032 }
1033 
AddSharedModuleRecord(const CompilerContext *context)1034 void Emitter::AddSharedModuleRecord(const CompilerContext *context)
1035 {
1036     bool isShared = context->Binder()->Program()->IsShared();
1037 
1038     auto sharedModuleField = panda::pandasm::Field(LANG_EXT);
1039     sharedModuleField.name = "isSharedModule";
1040     sharedModuleField.type = panda::pandasm::Type("u8", 0);
1041     sharedModuleField.metadata->SetValue(
1042         panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(isShared)));
1043 
1044     if (context->IsMergeAbc()) {
1045         rec_->field_list.emplace_back(std::move(sharedModuleField));
1046     } else if (isShared) {
1047         auto sharedModuleRecord = panda::pandasm::Record("_SharedModuleRecord", LANG_EXT);
1048         sharedModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
1049         sharedModuleRecord.field_list.emplace_back(std::move(sharedModuleField));
1050         prog_->record_table.emplace(sharedModuleRecord.name, std::move(sharedModuleRecord));
1051     }
1052 }
1053 
1054 // static
GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers, const LiteralBuffer *buff)1055 void Emitter::GenBufferLiterals(ArenaVector<std::pair<int32_t, std::vector<Literal>>> &literalBuffers,
1056                                 const LiteralBuffer *buff)
1057 {
1058     auto &[idx, array] = literalBuffers.emplace_back();
1059     idx = buff->Index();
1060     constexpr size_t ARRAY_EXPANSION = 2;
1061     array.reserve(buff->Literals().size() * ARRAY_EXPANSION);
1062 
1063     for (const auto *literal : buff->Literals()) {
1064         panda::pandasm::LiteralArray::Literal valueLit;
1065         panda::pandasm::LiteralArray::Literal tagLit;
1066 
1067         ir::LiteralTag tag = literal->Tag();
1068 
1069         switch (tag) {
1070             case ir::LiteralTag::BOOLEAN: {
1071                 valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
1072                 valueLit.value_ = literal->GetBoolean();
1073                 break;
1074             }
1075             case ir::LiteralTag::INTEGER: {
1076                 valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
1077                 valueLit.value_ = literal->GetInt();
1078                 break;
1079             }
1080             case ir::LiteralTag::DOUBLE: {
1081                 valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
1082                 valueLit.value_ = literal->GetDouble();
1083                 break;
1084             }
1085             case ir::LiteralTag::STRING: {
1086                 valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
1087                 valueLit.value_ = literal->GetString().Mutf8();
1088                 break;
1089             }
1090             case ir::LiteralTag::ACCESSOR: {
1091                 valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
1092                 valueLit.value_ = static_cast<uint8_t>(0);
1093                 break;
1094             }
1095             case ir::LiteralTag::METHOD: {
1096                 valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
1097                 valueLit.value_ = literal->GetMethod().Mutf8();
1098                 break;
1099             }
1100             case ir::LiteralTag::METHODAFFILIATE: {
1101                 valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE;
1102                 valueLit.value_ = literal->GetMethodAffiliate();
1103                 break;
1104             }
1105             case ir::LiteralTag::GENERATOR_METHOD: {
1106                 valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
1107                 valueLit.value_ = literal->GetMethod().Mutf8();
1108                 break;
1109             }
1110             case ir::LiteralTag::LITERALBUFFERINDEX: {
1111                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALBUFFERINDEX;
1112                 valueLit.value_ = literal->GetInt();
1113                 break;
1114             }
1115             case ir::LiteralTag::LITERALARRAY: {
1116                 valueLit.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
1117                 valueLit.value_ = literal->GetString().Mutf8();
1118                 break;
1119             }
1120             case ir::LiteralTag::BUILTINTYPEINDEX: {
1121                 valueLit.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
1122                 valueLit.value_ = static_cast<uint8_t>(literal->GetInt());
1123                 break;
1124             }
1125             case ir::LiteralTag::GETTER: {
1126                 valueLit.tag_ = panda::panda_file::LiteralTag::GETTER;
1127                 valueLit.value_ = literal->GetMethod().Mutf8();
1128                 break;
1129             }
1130             case ir::LiteralTag::SETTER: {
1131                 valueLit.tag_ = panda::panda_file::LiteralTag::SETTER;
1132                 valueLit.value_ = literal->GetMethod().Mutf8();
1133                 break;
1134             }
1135             case ir::LiteralTag::ASYNC_GENERATOR_METHOD: {
1136                 valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD;
1137                 valueLit.value_ = literal->GetMethod().Mutf8();
1138                 break;
1139             }
1140             case ir::LiteralTag::NULL_VALUE: {
1141                 valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
1142                 valueLit.value_ = static_cast<uint8_t>(0);
1143                 break;
1144             }
1145             default:
1146                 break;
1147         }
1148 
1149         tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
1150         tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
1151 
1152         array.emplace_back(tagLit);
1153         array.emplace_back(valueLit);
1154     }
1155 }
1156 
DumpAsm(const panda::pandasm::Program *prog)1157 void Emitter::DumpAsm(const panda::pandasm::Program *prog)
1158 {
1159     auto &ss = std::cout;
1160 
1161     ss << ".language ECMAScript" << std::endl << std::endl;
1162 
1163     for (auto &[name, func] : prog->function_table) {
1164         ss << "slotNum = 0x" << std::hex << func.GetSlotsNum() << std::dec << std::endl;
1165         ss << ".function any " << name << '(';
1166 
1167         for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
1168             ss << "any a" << std::to_string(i);
1169 
1170             if (i != func.GetParamsNum() - 1) {
1171                 ss << ", ";
1172             }
1173         }
1174 
1175         ss << ") {" << std::endl;
1176 
1177         for (const auto &ins : func.ins) {
1178             ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
1179         }
1180 
1181         ss << "}" << std::endl << std::endl;
1182 
1183         for (const auto &ct : func.catch_blocks) {
1184             ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
1185                << std::endl
1186                << std::endl;
1187         }
1188     }
1189 
1190     ss << std::endl;
1191 }
1192 
Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)1193 panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, util::PatchFix *patchFixHelper)
1194 {
1195     if (dumpDebugInfo) {
1196         debuginfo::DebugInfoDumper dumper(prog_);
1197         dumper.Dump();
1198     }
1199 
1200     if (rec_) {
1201         delete rec_;
1202         rec_ = nullptr;
1203     }
1204 
1205     if (patchFixHelper) {
1206         patchFixHelper->Finalize(&prog_);
1207     }
1208 
1209     auto *prog = prog_;
1210     prog_ = nullptr;
1211     return prog;
1212 }
1213 
GetProgram() const1214 panda::pandasm::Program *Emitter::GetProgram() const
1215 {
1216     return prog_;
1217 }
1218 
1219 }  // namespace panda::es2panda::compiler
1220