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