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