• 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 "ETSemitter.h"
17 
18 #include "compiler/core/ETSGen.h"
19 #include "varbinder/varbinder.h"
20 #include "varbinder/ETSBinder.h"
21 #include "ir/astNode.h"
22 #include "ir/expressions/identifier.h"
23 #include "ir/base/decorator.h"
24 #include "ir/base/methodDefinition.h"
25 #include "ir/base/classDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/classProperty.h"
28 #include "ir/statements/annotationDeclaration.h"
29 #include "ir/ts/tsEnumDeclaration.h"
30 #include "ir/ts/tsEnumMember.h"
31 #include "ir/ts/tsInterfaceDeclaration.h"
32 #include "ir/ts/tsInterfaceBody.h"
33 #include "ir/ts/tsTypeParameterDeclaration.h"
34 #include "ir/ts/tsTypeParameter.h"
35 #include "ir/typeNode.h"
36 #include "parser/program/program.h"
37 #include "checker/checker.h"
38 #include "checker/types/signature.h"
39 #include "checker/ETSchecker.h"
40 #include "checker/types/type.h"
41 #include "checker/types/ets/types.h"
42 #include "checker/types/ets/etsPartialTypeParameter.h"
43 #include "public/public.h"
44 
45 #include "assembly-program.h"
46 
47 namespace {
48 uint32_t g_litArrayValueCount = 0;
49 }  // namespace
50 
51 namespace ark::es2panda::compiler {
52 
53 #ifdef PANDA_WITH_ETS
54 static constexpr auto EXTENSION = panda_file::SourceLang::ETS;
55 #else
56 // NOTE: temporary dummy gn buildfix until ETS plugin has gn build support
57 static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY;
58 #endif
59 
TranslateModifierFlags(ir::ModifierFlags modifierFlags)60 static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags)
61 {
62     uint32_t accessFlags = 0;
63 
64     if ((modifierFlags & ir::ModifierFlags::PRIVATE) != 0) {
65         accessFlags = ACC_PRIVATE;
66     } else if ((modifierFlags & ir::ModifierFlags::INTERNAL) != 0) {
67         if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
68             accessFlags = ACC_PROTECTED;
69         }
70         // NOTE: torokg. Add ACC_INTERNAL access flag to libpandabase
71     } else if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
72         accessFlags = ACC_PROTECTED;
73     } else {
74         accessFlags = ACC_PUBLIC;
75     }
76 
77     if ((modifierFlags & ir::ModifierFlags::STATIC) != 0) {
78         accessFlags |= ACC_STATIC;
79     }
80     if ((modifierFlags & ir::ModifierFlags::FINAL) != 0) {
81         accessFlags |= ACC_FINAL;
82     }
83     // NOTE: should be ModifierFlags::READONLY
84     if ((modifierFlags & ir::ModifierFlags::READONLY) != 0) {
85         accessFlags |= ACC_READONLY;
86     }
87     if ((modifierFlags & ir::ModifierFlags::ABSTRACT) != 0) {
88         accessFlags |= ACC_ABSTRACT;
89     }
90     if ((modifierFlags & ir::ModifierFlags::NATIVE) != 0) {
91         accessFlags |= ACC_NATIVE;
92     }
93 
94     return accessFlags;
95 }
96 
PandasmTypeWithRank(checker::Type const * type,uint32_t rank=0)97 static pandasm::Type PandasmTypeWithRank(checker::Type const *type, uint32_t rank = 0)
98 {
99     if (type->IsETSTypeParameter()) {
100         return PandasmTypeWithRank(type->AsETSTypeParameter()->GetConstraintType());
101     }
102     if (type->IsETSNonNullishType()) {
103         return PandasmTypeWithRank(type->AsETSNonNullishType()->GetUnderlying());
104     }
105     if (type->IsETSPartialTypeParameter()) {
106         return PandasmTypeWithRank(type->AsETSPartialTypeParameter()->GetUnderlying());
107     }
108     if (type->IsETSUnionType()) {
109         return PandasmTypeWithRank(type->AsETSUnionType()->GetAssemblerLUB());
110     }
111 
112     std::stringstream ss;
113     type->ToAssemblerType(ss);
114     return pandasm::Type(ss.str(), rank == 0 ? type->Rank() : rank);
115 }
116 
GenScriptFunction(const ir::ScriptFunction * scriptFunc,ETSEmitter * emitter)117 static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, ETSEmitter *emitter)
118 {
119     ES2PANDA_ASSERT(scriptFunc != nullptr);
120     auto *funcScope = scriptFunc->Scope();
121     auto *paramScope = funcScope->ParamScope();
122 
123     auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION);
124     func.params.reserve(paramScope->Params().size());
125 
126     for (const auto *var : paramScope->Params()) {
127         func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION);
128         if (var->Declaration()->Node() == nullptr || !var->Declaration()->Node()->IsETSParameterExpression()) {
129             continue;
130         }
131         func.params.back().GetOrCreateMetadata().SetAnnotations(emitter->GenCustomAnnotations(
132             var->Declaration()->Node()->AsETSParameterExpression()->Annotations(), var->Name().Mutf8()));
133     }
134 
135     if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) {
136         func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
137     } else {
138         func.returnType = PandasmTypeWithRank(scriptFunc->Signature()->ReturnType());
139     }
140 
141     uint32_t accessFlags = 0;
142     if (!scriptFunc->IsStaticBlock()) {
143         const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc);
144         ES2PANDA_ASSERT(methodDef != nullptr);
145         accessFlags |= TranslateModifierFlags(methodDef->Modifiers());
146     }
147     if (scriptFunc->HasRestParameter()) {
148         accessFlags |= ACC_VARARGS;
149     }
150     func.metadata->SetAccessFlags(accessFlags);
151     func.metadata->SetAnnotations(emitter->GenCustomAnnotations(scriptFunc->Annotations(), func.name));
152 
153     return func;
154 }
155 
GenFunctionSignature()156 pandasm::Function *ETSFunctionEmitter::GenFunctionSignature()
157 {
158     auto *scriptFunc = Cg()->RootNode()->AsScriptFunction();
159     auto *emitter = static_cast<ETSEmitter *>(Cg()->Context()->emitter);
160     auto func = GenScriptFunction(scriptFunc, emitter);
161 
162     if (Cg()->RootNode()->AsScriptFunction()->IsExternal()) {
163         func.metadata->SetAttribute(Signatures::EXTERNAL);
164     }
165 
166     auto *funcElement = new pandasm::Function(func.name, func.language);
167     *funcElement = std::move(func);
168     GetProgramElement()->SetFunction(funcElement);
169     funcElement->regsNum = VReg::REG_START - Cg()->TotalRegsNum();
170 
171     return funcElement;
172 }
173 
GenVariableSignature(pandasm::debuginfo::LocalVariable & variableDebug,varbinder::LocalVariable * variable) const174 void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug,
175                                               [[maybe_unused]] varbinder::LocalVariable *variable) const
176 {
177     variableDebug.signature = Signatures::ANY;
178     variableDebug.signatureType = Signatures::ANY;
179 }
180 
GenSourceFileDebugInfo(pandasm::Function * func)181 void ETSFunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func)
182 {
183     func->sourceFile = std::string {Cg()->VarBinder()->Program()->RelativeFilePath()};
184 
185     if (!Cg()->IsDebug()) {
186         return;
187     }
188 
189     ES2PANDA_ASSERT(Cg()->RootNode()->IsScriptFunction());
190     auto *fn = Cg()->RootNode()->AsScriptFunction();
191     bool isInitMethod = fn->Id()->Name().Is(compiler::Signatures::INIT_METHOD);
192     // Write source code of whole file into debug-info of init method
193     if (isInitMethod) {
194         func->sourceCode = SourceCode().Utf8();
195     }
196 }
197 
GenFunctionAnnotations(pandasm::Function * func)198 void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {}
199 
GenExternalFunction(checker::Signature * signature,bool isCtor)200 static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor)
201 {
202     auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION);
203 
204     for (auto param : signature->Params()) {
205         func.params.emplace_back(PandasmTypeWithRank(param->TsType()), EXTENSION);
206     }
207     func.returnType = PandasmTypeWithRank(signature->ReturnType());
208 
209     if (isCtor) {
210         func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
211     }
212     func.metadata->SetAttribute(Signatures::EXTERNAL);
213 
214     return func;
215 }
216 
GenerateMangledName(const std::string & baseName,const std::string & propName)217 static std::string GenerateMangledName(const std::string &baseName, const std::string &propName)
218 {
219     return baseName + "$" + propName;
220 }
221 
StoreEntity(std::vector<pandasm::LiteralArray::Literal> & literals,uint8_t type)222 static void StoreEntity(std::vector<pandasm::LiteralArray::Literal> &literals, uint8_t type)
223 {
224     uint32_t emptyValue = 0;
225     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
226                                                           static_cast<uint8_t>(panda_file::LiteralTag::INTEGER)});
227     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, emptyValue});
228 
229     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
230                                                           static_cast<uint8_t>(panda_file::LiteralTag::ACCESSOR)});
231     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::ACCESSOR, type});
232 
233     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
234                                                           static_cast<uint8_t>(panda_file::LiteralTag::INTEGER)});
235     literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, emptyValue});
236 }
237 
StoreExportNodes(std::vector<std::pair<std::string,ir::AstNode * >> & declGen,pandasm::Program * program)238 static std::vector<std::pair<std::string, std::string>> StoreExportNodes(
239     std::vector<std::pair<std::string, ir::AstNode *>> &declGen, pandasm::Program *program)
240 {
241     std::vector<pandasm::LiteralArray::Literal> literals;
242     std::vector<std::pair<std::string, std::string>> result;
243 
244     for (auto &pair : declGen) {
245         auto declString = pair.first;
246         auto *node = pair.second;
247         if (node->IsClassProperty() && node->IsConst()) {
248             StoreEntity(literals, parser::EntityType::CLASS_PROPERTY);
249             result.emplace_back(declString, node->AsClassProperty()->Id()->Name().Mutf8());
250         } else if (node->IsMethodDefinition()) {
251             StoreEntity(literals, parser::EntityType::METHOD_DEFINITION);
252             ES2PANDA_ASSERT(node->AsMethodDefinition()->Function() != nullptr);
253             result.emplace_back(declString, node->AsMethodDefinition()->Function()->Scope()->InternalName());
254         } else if (node->IsClassDefinition()) {
255             StoreEntity(literals, parser::EntityType::CLASS_DEFINITION);
256             result.emplace_back(declString, node->AsClassDefinition()->InternalName().Mutf8());
257         } else if (node->IsTSInterfaceDeclaration()) {
258             StoreEntity(literals, parser::EntityType::TS_INTERFACE_DECLARATION);
259             result.emplace_back(declString, node->AsTSInterfaceDeclaration()->InternalName().Mutf8());
260         } else {
261             ES2PANDA_UNREACHABLE();
262         }
263     }
264     program->literalarrayTable.emplace("export_entities", literals);
265     return result;
266 }
267 
FilterForSimultaneous(varbinder::ETSBinder * varbinder)268 void FilterForSimultaneous(varbinder::ETSBinder *varbinder)
269 {
270     ArenaSet<ir::ClassDefinition *> &classDefinitions = varbinder->GetGlobalRecordTable()->ClassDefinitions();
271     for (auto it = classDefinitions.begin(); it != classDefinitions.end(); ++it) {
272         if ((*it)->InternalName().Is(Signatures::ETS_GLOBAL)) {
273             classDefinitions.erase(it);
274             break;
275         }
276     }
277     std::vector<std::string_view> filterFunctions = {
278         Signatures::UNUSED_ETSGLOBAL_CTOR, Signatures::UNUSED_ETSGLOBAL_INIT, Signatures::UNUSED_ETSGLOBAL_MAIN};
279     auto &functions = varbinder->Functions();
280     functions.erase(std::remove_if(functions.begin(), functions.end(),
281                                    [&filterFunctions](varbinder::FunctionScope *scope) -> bool {
282                                        return std::any_of(
283                                            filterFunctions.begin(), filterFunctions.end(),
284                                            [&scope](std::string_view &s) { return scope->InternalName().Is(s); });
285                                    }),  // CC-OFF(G.FMT.02)
286                     functions.end());
287 }
288 
GenAnnotation()289 void ETSEmitter::GenAnnotation()
290 {
291     Program()->lang = EXTENSION;
292     auto *varbinder = static_cast<varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
293 
294     if (Context()->config->options->GetCompilationMode() == CompilationMode::GEN_ABC_FOR_EXTERNAL_SOURCE) {
295         FilterForSimultaneous(varbinder);
296     }
297 
298     auto *globalRecordTable = varbinder->GetGlobalRecordTable();
299     auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8();
300     for (auto *annoDecl : globalRecordTable->AnnotationDeclarations()) {
301         auto newBaseName = GenerateMangledName(baseName, annoDecl->GetBaseName()->Name().Mutf8());
302         GenCustomAnnotationRecord(annoDecl, newBaseName, annoDecl->IsDeclare());
303     }
304 
305     for (auto *classDecl : globalRecordTable->ClassDefinitions()) {
306         GenClassRecord(classDecl, classDecl->IsDeclare());
307     }
308 
309     for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) {
310         GenInterfaceRecord(interfaceDecl, interfaceDecl->IsDeclare());
311     }
312 
313     for (auto *signature : globalRecordTable->Signatures()) {
314         auto *scriptFunc = signature->Node()->AsScriptFunction();
315         auto func = GenScriptFunction(scriptFunc, this);
316         if (scriptFunc->IsDeclare()) {
317             func.metadata->SetAttribute(Signatures::EXTERNAL);
318         }
319         if (scriptFunc->IsAsyncFunc()) {
320             std::vector<pandasm::AnnotationData> annotations;
321             annotations.push_back(GenAnnotationAsync(scriptFunc));
322             func.metadata->AddAnnotations(annotations);
323         }
324         Program()->AddToFunctionTable(std::move(func));
325     }
326 
327     for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) {
328         if (recordTable == varbinder->GetRecordTable()) {
329             continue;
330         }
331         GenExternalRecord(recordTable, extProg);
332     }
333 
334     const auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
335 
336     for (auto [arrType, signature] : checker->GlobalArrayTypes()) {
337         GenGlobalArrayRecord(arrType, signature);
338     }
339     if (Context()->config->options->WasSetWithExportTable()) {
340         auto result = StoreExportNodes(Context()->parserProgram->DeclGenExportNodes(), Program());
341         Program()->exportStrMap = std::move(result);
342     }
343 }
344 
IsFromSelfHeadFile(const std::string & name,const parser::Program * curProg,const parser::Program * extProg)345 static bool IsFromSelfHeadFile(const std::string &name, const parser::Program *curProg, const parser::Program *extProg)
346 {
347     const auto *curBinder = static_cast<const varbinder::ETSBinder *>(curProg->VarBinder());
348     return extProg->FileName() == curProg->FileName() &&
349            std::any_of(curBinder->Functions().begin(), curBinder->Functions().end(),
350                        [&](auto function) { return function->InternalName().Is(name); });
351 }
352 
GenExternalRecord(varbinder::RecordTable * recordTable,const parser::Program * extProg)353 void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const parser::Program *extProg)
354 {
355     bool isExternalFromCompile =
356         !recordTable->Program()->VarBinder()->IsGenStdLib() && !recordTable->Program()->IsGenAbcForExternal();
357     const auto *varbinder = static_cast<const varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
358     auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8();
359     for (auto *annoDecl : recordTable->AnnotationDeclarations()) {
360         auto newBaseName = GenerateMangledName(baseName, annoDecl->GetBaseName()->Name().Mutf8());
361         GenCustomAnnotationRecord(annoDecl, newBaseName, isExternalFromCompile || annoDecl->IsDeclare());
362     }
363 
364     for (auto *classDecl : recordTable->ClassDefinitions()) {
365         GenClassRecord(classDecl, isExternalFromCompile || classDecl->IsDeclare());
366     }
367 
368     for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) {
369         GenInterfaceRecord(interfaceDecl, isExternalFromCompile || interfaceDecl->IsDeclare());
370     }
371 
372     for (auto *signature : recordTable->Signatures()) {
373         auto scriptFunc = signature->Node()->AsScriptFunction();
374         auto func = GenScriptFunction(scriptFunc, this);
375 
376         if (isExternalFromCompile || scriptFunc->IsDeclare()) {
377             func.metadata->SetAttribute(Signatures::EXTERNAL);
378         }
379 
380         if (extProg->IsGenAbcForExternal() && scriptFunc->IsAsyncFunc()) {
381             std::vector<pandasm::AnnotationData> annotations;
382             annotations.push_back(GenAnnotationAsync(scriptFunc));
383             func.metadata->AddAnnotations(annotations);
384         }
385 
386         if (func.metadata->IsForeign() && IsFromSelfHeadFile(func.name, Context()->parserProgram, extProg)) {
387             return;
388         }
389 
390         if (Program()->functionStaticTable.find(func.name) == Program()->functionStaticTable.cend()) {
391             Program()->AddToFunctionTable(std::move(func));
392         }
393     }
394 }
395 
396 // Helper function to reduce EmitDefaultFieldValue size and pass code check
CreateScalarValue(const checker::Type * type,checker::TypeFlag typeKind)397 static pandasm::ScalarValue CreateScalarValue(const checker::Type *type, checker::TypeFlag typeKind)
398 {
399     switch (typeKind) {
400         case checker::TypeFlag::ETS_BOOLEAN: {
401             return pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
402                 static_cast<uint8_t>(type->AsETSBooleanType()->GetValue()));
403         }
404         case checker::TypeFlag::BYTE: {
405             return pandasm::ScalarValue::Create<pandasm::Value::Type::I8>(type->AsByteType()->GetValue());
406         }
407         case checker::TypeFlag::SHORT: {
408             return pandasm::ScalarValue::Create<pandasm::Value::Type::I16>(type->AsShortType()->GetValue());
409         }
410         case checker::TypeFlag::INT: {
411             return pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(type->AsIntType()->GetValue());
412         }
413         case checker::TypeFlag::LONG: {
414             return pandasm::ScalarValue::Create<pandasm::Value::Type::I64>(type->AsLongType()->GetValue());
415         }
416         case checker::TypeFlag::FLOAT: {
417             return pandasm::ScalarValue::Create<pandasm::Value::Type::F32>(type->AsFloatType()->GetValue());
418         }
419         case checker::TypeFlag::DOUBLE: {
420             return pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(type->AsDoubleType()->GetValue());
421         }
422         case checker::TypeFlag::CHAR: {
423             return pandasm::ScalarValue::Create<pandasm::Value::Type::U16>(type->AsCharType()->GetValue());
424         }
425         case checker::TypeFlag::ETS_OBJECT: {
426             return pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
427                 type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8());
428         }
429         default: {
430             ES2PANDA_UNREACHABLE();
431         }
432     }
433 }
434 
EmitDefaultFieldValue(pandasm::Field & classField,const ir::Expression * init)435 void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init)
436 {
437     if (init == nullptr) {
438         return;
439     }
440 
441     const auto *type = init->TsType();
442 
443     if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
444         return;
445     }
446 
447     auto typeKind = checker::ETSChecker::TypeKind(type);
448     classField.metadata->SetFieldType(classField.type);
449     classField.metadata->SetValue(CreateScalarValue(type, typeKind));
450 }
451 
GenInterfaceMethodDefinition(const ir::MethodDefinition * methodDef,bool external)452 void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external)
453 {
454     auto *scriptFunc = methodDef->Function();
455     auto func = GenScriptFunction(scriptFunc, this);
456 
457     if (external) {
458         func.metadata->SetAttribute(Signatures::EXTERNAL);
459     }
460 
461     if (scriptFunc->Body() != nullptr) {
462         return;
463     }
464 
465     func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT);
466     Program()->AddToFunctionTable(std::move(func));
467 }
468 
GenClassField(const ir::ClassProperty * prop,pandasm::Record & classRecord,bool external)469 void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &classRecord, bool external)
470 {
471     auto field = pandasm::Field(Program()->lang);
472     ES2PANDA_ASSERT(prop->Id() != nullptr);
473     field.name = prop->Id()->Name().Mutf8();
474     field.type = PandasmTypeWithRank(prop->TsType());
475     field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers()));
476 
477     if (!external) {
478         field.metadata->SetAnnotations(GenCustomAnnotations(prop->Annotations(), field.name));
479     }
480 
481     if (external || prop->IsDeclare()) {
482         field.metadata->SetAttribute(Signatures::EXTERNAL);
483     } else if (prop->TsType()->IsETSPrimitiveType() || prop->TsType()->IsETSStringType()) {
484         EmitDefaultFieldValue(field, prop->Value());
485     }
486 
487     classRecord.fieldList.emplace_back(std::move(field));
488 }
489 
GenClassInheritedFields(const checker::ETSObjectType * baseType,pandasm::Record & classRecord)490 void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord)
491 {
492     std::vector<const varbinder::LocalVariable *> foreignProps = baseType->ForeignProperties();
493 
494     for (const auto *foreignProp : foreignProps) {
495         auto *declNode = foreignProp->Declaration()->Node();
496         if (!declNode->IsClassProperty()) {
497             continue;
498         }
499 
500         GenClassField(declNode->AsClassProperty(), classRecord, true);
501     }
502 }
503 
GenGlobalArrayRecord(const checker::ETSArrayType * arrayType,checker::Signature * signature)504 void ETSEmitter::GenGlobalArrayRecord(const checker::ETSArrayType *arrayType, checker::Signature *signature)
505 {
506     std::stringstream ss;
507     arrayType->ToAssemblerTypeWithRank(ss);
508 
509     auto arrayRecord = pandasm::Record(ss.str(), Program()->lang);
510 
511     auto func = GenExternalFunction(signature, true);
512     func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION);
513 
514     Program()->AddToFunctionTable(std::move(func));
515 
516     arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL);
517     Program()->recordTable.emplace(arrayRecord.name, std::move(arrayRecord));
518     Program()->arrayTypes.emplace(PandasmTypeWithRank(arrayType));
519 }
520 
GenInterfaceRecord(const ir::TSInterfaceDeclaration * interfaceDecl,bool external)521 void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external)
522 {
523     auto *baseType = interfaceDecl->TsType()->AsETSObjectType();
524 
525     auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang);
526     if (external) {
527         interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL);
528     }
529 
530     uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE;
531 
532     if (interfaceDecl->IsStatic()) {
533         accessFlags |= ACC_STATIC;
534     }
535 
536     interfaceRecord.metadata->SetAnnotations(GenCustomAnnotations(interfaceDecl->Annotations(), interfaceRecord.name));
537     interfaceRecord.metadata->SetAccessFlags(accessFlags);
538     interfaceRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()};
539     interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
540 
541     for (auto *it : baseType->Interfaces()) {
542         auto *declNode = it->GetDeclNode();
543         ES2PANDA_ASSERT(declNode->IsTSInterfaceDeclaration());
544         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
545         interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
546     }
547 
548     GenClassInheritedFields(baseType, interfaceRecord);
549 
550     for (const auto *prop : interfaceDecl->Body()->Body()) {
551         if (prop->IsClassProperty()) {
552             GenClassField(prop->AsClassProperty(), interfaceRecord, external);
553         } else if (prop->IsMethodDefinition()) {
554             GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external);
555             for (auto *overload : prop->AsMethodDefinition()->Overloads()) {
556                 GenInterfaceMethodDefinition(overload, external);
557             }
558         }
559     }
560 
561     Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord));
562 }
563 
GenAnnotations(const ir::ClassDefinition * classDef)564 std::vector<pandasm::AnnotationData> ETSEmitter::GenAnnotations(const ir::ClassDefinition *classDef)
565 {
566     std::vector<pandasm::AnnotationData> annotations;
567     const ir::AstNode *parent = classDef->Parent();
568     while (parent != nullptr) {
569         if ((classDef->Modifiers() & ir::ClassDefinitionModifiers::FUNCTIONAL_REFERENCE) != 0U) {
570             annotations.emplace_back(GenAnnotationFunctionalReference(classDef));
571             break;
572         }
573         if (parent->IsMethodDefinition()) {
574             annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition()));
575             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
576             break;
577         }
578         if (parent->IsClassDefinition()) {
579             annotations.emplace_back(GenAnnotationEnclosingClass(
580                 parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8()));
581             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
582             break;
583         }
584         parent = parent->Parent();
585     }
586 
587     auto classIdent = classDef->Ident()->Name().Mutf8();
588     bool isConstruct = classIdent == Signatures::JSNEW_CLASS;
589     if (isConstruct || classIdent == Signatures::JSCALL_CLASS) {
590         auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct);
591         annotations.push_back(GenAnnotationDynamicCall(*callNames));
592     }
593 
594     return annotations;
595 }
596 
GetAccessFlags(const ir::ClassDefinition * classDef)597 static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef)
598 {
599     uint32_t accessFlags = ACC_PUBLIC;
600     if (classDef->IsAbstract()) {
601         accessFlags |= ACC_ABSTRACT;
602     } else if (classDef->IsFinal()) {
603         accessFlags |= ACC_FINAL;
604     }
605 
606     if (classDef->IsStatic()) {
607         accessFlags |= ACC_STATIC;
608     }
609 
610     return accessFlags;
611 }
612 
GenClassRecord(const ir::ClassDefinition * classDef,bool external)613 void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external)
614 {
615     auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang);
616     if (external) {
617         classRecord.metadata->SetAttribute(Signatures::EXTERNAL);
618     }
619 
620     classRecord.metadata->SetAnnotations(GenCustomAnnotations(classDef->Annotations(), classRecord.name));
621     uint32_t accessFlags = GetAccessFlags(classDef);
622     classRecord.metadata->SetAccessFlags(accessFlags);
623     classRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()};
624 
625     auto *baseType = classDef->TsType()->AsETSObjectType();
626     if (baseType->SuperType() != nullptr) {
627         classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE,
628                                                 baseType->SuperType()->AssemblerName().Mutf8());
629     } else {
630         // NOTE: rtakacs. Replace the whole if block (below) with assert when lambda objects have super class.
631         if (baseType->AssemblerName().Mutf8() != Signatures::BUILTIN_OBJECT) {
632             classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
633         }
634     }
635 
636     for (auto *it : baseType->Interfaces()) {
637         // We do not need to add dynamic interfaces
638         if (it->IsETSDynamicType()) {
639             continue;
640         }
641 
642         auto *declNode = it->GetDeclNode();
643         // NOTE: itrubachev. replace it with ES2PANDA_ASSERT(decl_node->IsTSInterfaceDeclaration())
644         // after adding proper creation of lambda object in ETSFunctionType::AssignmentSource
645         if (!declNode->IsTSInterfaceDeclaration()) {
646             continue;
647         }
648         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
649         classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
650     }
651 
652     GenClassInheritedFields(baseType, classRecord);
653     for (const auto *prop : classDef->Body()) {
654         if (!prop->IsClassProperty()) {
655             continue;
656         }
657 
658         GenClassField(prop->AsClassProperty(), classRecord, external);
659     }
660 
661     std::vector<pandasm::AnnotationData> annotations = GenAnnotations(classDef);
662 
663     if (classDef->IsNamespaceTransformed() || classDef->IsGlobalInitialized()) {
664         annotations.push_back(GenAnnotationModule(classDef));
665     }
666 
667     if (!annotations.empty()) {
668         classRecord.metadata->AddAnnotations(annotations);
669     }
670 
671     Program()->recordTable.emplace(classRecord.name, std::move(classRecord));
672 }
673 
674 // Helper function to check if the unary expression is a numeric literal with negation.
675 // This expression should be handled during lowering with the associated issue number.
IsNegativeLiteralNode(const ir::UnaryExpression * expr)676 static bool IsNegativeLiteralNode(const ir::UnaryExpression *expr)
677 {
678     return expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS && expr->Argument()->IsNumberLiteral();
679 }
680 
CreateEnumProp(const ir::ClassProperty * prop,pandasm::Field & field)681 void ETSEmitter::CreateEnumProp(const ir::ClassProperty *prop, pandasm::Field &field)
682 {
683     if (prop->Value() == nullptr) {
684         return;
685     }
686     field.metadata->SetFieldType(field.type);
687     ES2PANDA_ASSERT(prop != nullptr && prop->Value() != nullptr &&
688                     prop->Value()->AsMemberExpression()->PropVar() != nullptr);
689     auto declNode = prop->Value()->AsMemberExpression()->PropVar()->Declaration()->Node();
690     auto *init = declNode->AsClassProperty()->OriginEnumMember()->Init();
691     if (init->IsNumberLiteral()) {
692         auto value = init->AsNumberLiteral()->Number().GetInt();
693         field.metadata->SetValue(pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(value));
694     } else if (init->IsStringLiteral()) {
695         auto value = init->AsStringLiteral()->Str().Mutf8();
696         field.metadata->SetValue(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(value));
697     } else {
698         ES2PANDA_UNREACHABLE();
699     }
700 }
701 
ProcessArrayExpression(std::string & baseName,std::vector<std::pair<std::string,std::vector<pandasm::LiteralArray::Literal>>> & result,std::vector<pandasm::LiteralArray::Literal> & literals,const ir::Expression * elem)702 void ETSEmitter::ProcessArrayExpression(
703     std::string &baseName, std::vector<std::pair<std::string, std::vector<pandasm::LiteralArray::Literal>>> &result,
704     std::vector<pandasm::LiteralArray::Literal> &literals, const ir::Expression *elem)
705 {
706     auto litArrays = CreateLiteralArray(baseName, elem);
707     auto emplaceLiteral = [&literals](panda_file::LiteralTag tag, const auto &value) {
708         literals.emplace_back(pandasm::LiteralArray::Literal {tag, value});
709     };
710 
711     emplaceLiteral(panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::LITERALARRAY));
712     emplaceLiteral(panda_file::LiteralTag::LITERALARRAY, litArrays.back().first);
713     for (const auto &item : litArrays) {
714         result.push_back(item);
715     }
716 }
717 
ProcessEnumExpression(std::vector<pandasm::LiteralArray::Literal> & literals,const ir::Expression * elem)718 static void ProcessEnumExpression(std::vector<pandasm::LiteralArray::Literal> &literals, const ir::Expression *elem)
719 {
720     auto *memberExpr = elem->IsCallExpression() ? elem->AsCallExpression()->Arguments()[0]->AsMemberExpression()
721                                                 : elem->AsMemberExpression();
722     ES2PANDA_ASSERT(memberExpr->PropVar() != nullptr);
723     auto *init = memberExpr->PropVar()->Declaration()->Node()->AsClassProperty()->OriginEnumMember()->Init();
724     if (init->IsNumberLiteral()) {
725         auto enumValue = static_cast<uint32_t>(init->AsNumberLiteral()->Number().GetInt());
726         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
727                                                               static_cast<uint8_t>(panda_file::LiteralTag::INTEGER)});
728         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, enumValue});
729     } else {
730         auto enumValue = init->AsStringLiteral()->Str().Mutf8();
731         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
732                                                               static_cast<uint8_t>(panda_file::LiteralTag::STRING)});
733         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::STRING, enumValue});
734     }
735 }
736 
ProcessArrayElement(const ir::Expression * elem,std::vector<pandasm::LiteralArray::Literal> & literals,std::string & baseName,LiteralArrayVector & result)737 void ETSEmitter::ProcessArrayElement(const ir::Expression *elem, std::vector<pandasm::LiteralArray::Literal> &literals,
738                                      std::string &baseName, LiteralArrayVector &result)
739 {
740     switch (elem->Type()) {
741         case ir::AstNodeType::NUMBER_LITERAL: {
742             auto doubleValue = elem->AsNumberLiteral()->Number().GetDouble();
743             literals.emplace_back(pandasm::LiteralArray::Literal {
744                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::DOUBLE)});
745             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::DOUBLE, doubleValue});
746             break;
747         }
748         case ir::AstNodeType::BOOLEAN_LITERAL: {
749             bool boolValue = elem->AsBooleanLiteral()->Value();
750             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
751                                                                   static_cast<uint8_t>(panda_file::LiteralTag::BOOL)});
752             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::BOOL, boolValue});
753             break;
754         }
755         case ir::AstNodeType::STRING_LITERAL: {
756             std::string stringValue {elem->AsStringLiteral()->Str().Utf8()};
757             literals.emplace_back(pandasm::LiteralArray::Literal {
758                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::STRING)});
759             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::STRING, stringValue});
760             break;
761         }
762         case ir::AstNodeType::ARRAY_EXPRESSION: {
763             ProcessArrayExpression(baseName, result, literals, elem);
764             break;
765         }
766         case ir::AstNodeType::MEMBER_EXPRESSION:
767         case ir::AstNodeType::CALL_EXPRESSION: {
768             ProcessEnumExpression(literals, elem);
769             break;
770         }
771         case ir::AstNodeType::UNARY_EXPRESSION: {
772             double doubleValue = (-1) * elem->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number().GetDouble();
773             literals.emplace_back(pandasm::LiteralArray::Literal {
774                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::DOUBLE)});
775             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::DOUBLE, doubleValue});
776             break;
777         }
778         default:
779             ES2PANDA_UNREACHABLE();
780             break;
781     }
782 }
783 
CreateLiteralArray(std::string & baseName,const ir::Expression * array)784 LiteralArrayVector ETSEmitter::CreateLiteralArray(std::string &baseName, const ir::Expression *array)
785 {
786     LiteralArrayVector result;
787     std::vector<pandasm::LiteralArray::Literal> literals;
788     ArenaVector<ir::Expression *> elements {array->AsArrayExpression()->Elements()};
789 
790     for (const auto *elem : elements) {
791         ProcessArrayElement(elem, literals, baseName, result);
792     }
793 
794     std::string litArrayName = GenerateMangledName(baseName, std::to_string(g_litArrayValueCount));
795     ++g_litArrayValueCount;
796     result.emplace_back(litArrayName, literals);
797     return result;
798 }
799 
CreateLiteralArrayProp(const ir::ClassProperty * prop,std::string & baseName,pandasm::Field & field)800 void ETSEmitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Field &field)
801 {
802     auto *checker = Context()->checker->AsETSChecker();
803     uint8_t rank = 1;
804     auto *elemType = checker->GetElementTypeOfArray(prop->TsType());
805     while (elemType->IsETSArrayType() || elemType->IsETSResizableArrayType()) {
806         ++rank;
807         elemType = checker->GetElementTypeOfArray(elemType);
808     }
809     if (elemType->IsETSEnumType()) {
810         field.type = PandasmTypeWithRank(elemType, rank);
811     } else {
812         std::stringstream ss;
813         elemType->ToAssemblerType(ss);
814         field.type = pandasm::Type(ss.str(), rank);
815     }
816 
817     auto value = prop->Value();
818     if (value != nullptr) {
819         std::string newBaseName = GenerateMangledName(baseName, field.name);
820         auto litArray = CreateLiteralArray(newBaseName, value);
821         for (const auto &item : litArray) {
822             Program()->literalarrayTable.emplace(item.first, item.second);
823         }
824         field.metadata->SetValue(
825             pandasm::ScalarValue::Create<pandasm::Value::Type::LITERALARRAY>(std::string_view {litArray.back().first}));
826     }
827 }
828 
GenCustomAnnotationProp(const ir::ClassProperty * prop,std::string & baseName,pandasm::Record & record,bool external)829 void ETSEmitter::GenCustomAnnotationProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Record &record,
830                                          bool external)
831 {
832     auto field = pandasm::Field(Program()->lang);
833     auto *type = prop->TsType();
834     ES2PANDA_ASSERT(prop->Id() != nullptr);
835     field.name = prop->Id()->Name().Mutf8();
836     field.type = PandasmTypeWithRank(type);
837     field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers()));
838 
839     if (external) {
840         field.metadata->SetAttribute(Signatures::EXTERNAL);
841     } else if (type->IsETSEnumType()) {
842         CreateEnumProp(prop, field);
843     } else if (type->IsETSPrimitiveType() || type->IsETSStringType()) {
844         EmitDefaultFieldValue(field, prop->Value());
845     } else if (type->IsETSArrayType() || type->IsETSResizableArrayType()) {
846         CreateLiteralArrayProp(prop, baseName, field);
847     } else {
848         ES2PANDA_UNREACHABLE();
849     }
850     record.fieldList.emplace_back(std::move(field));
851 }
852 
GenCustomAnnotationRecord(const ir::AnnotationDeclaration * annoDecl,std::string & baseName,bool external)853 void ETSEmitter::GenCustomAnnotationRecord(const ir::AnnotationDeclaration *annoDecl, std::string &baseName,
854                                            bool external)
855 {
856     auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang);
857     if (Program()->recordTable.find(annoRecord.name) != Program()->recordTable.end()) {
858         return;
859     }
860 
861     if (external) {
862         annoRecord.metadata->SetAttribute(Signatures::EXTERNAL);
863     }
864 
865     uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_ANNOTATION;
866     annoRecord.metadata->SetAccessFlags(accessFlags);
867     annoRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()};
868     for (auto *it : annoDecl->Properties()) {
869         GenCustomAnnotationProp(it->AsClassProperty(), baseName, annoRecord, external);
870     }
871 
872     Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord));
873 }
874 
ProcessArrayType(const ir::ClassProperty * prop,std::string & baseName,const ir::Expression * init)875 pandasm::AnnotationElement ETSEmitter::ProcessArrayType(const ir::ClassProperty *prop, std::string &baseName,
876                                                         const ir::Expression *init)
877 {
878     ES2PANDA_ASSERT(prop->Id() != nullptr);
879     auto propName = prop->Id()->Name().Mutf8();
880     std::string newBaseName = GenerateMangledName(baseName, propName);
881     auto litArrays = CreateLiteralArray(newBaseName, init);
882 
883     for (const auto &item : litArrays) {
884         Program()->literalarrayTable.emplace(item.first, item.second);
885     }
886 
887     return pandasm::AnnotationElement {
888         propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
889                       std::string_view {litArrays.back().first}))};
890 }
891 
ProcessETSEnumType(std::string & baseName,const ir::Expression * init,const checker::Type * type)892 pandasm::AnnotationElement ETSEmitter::ProcessETSEnumType(std::string &baseName, const ir::Expression *init,
893                                                           const checker::Type *type)
894 {
895     ES2PANDA_ASSERT(init != nullptr && init->AsMemberExpression() != nullptr &&
896                     init->AsMemberExpression()->PropVar() != nullptr);
897     auto declNode = init->AsMemberExpression()->PropVar()->Declaration()->Node();
898     auto *initValue = declNode->AsClassProperty()->OriginEnumMember()->Init();
899     if (type->IsETSIntEnumType()) {
900         auto enumValue = static_cast<uint32_t>(initValue->AsNumberLiteral()->Number().GetInt());
901         auto intEnumValue = pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(enumValue);
902         return pandasm::AnnotationElement {baseName, std::make_unique<pandasm::ScalarValue>(intEnumValue)};
903     }
904     ES2PANDA_ASSERT(type->IsETSStringEnumType());
905     auto enumValue = initValue->AsStringLiteral()->Str().Mutf8();
906     auto stringValue = pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(enumValue);
907     return pandasm::AnnotationElement {baseName, std::make_unique<pandasm::ScalarValue>(stringValue)};
908 }
909 
GenCustomAnnotationElement(const ir::ClassProperty * prop,std::string & baseName)910 pandasm::AnnotationElement ETSEmitter::GenCustomAnnotationElement(const ir::ClassProperty *prop, std::string &baseName)
911 {
912     const auto *init = prop->Value();
913     const auto *type = init->TsType();
914     auto typeKind = checker::ETSChecker::TypeKind(type);
915     ES2PANDA_ASSERT(prop->Id() != nullptr);
916     auto propName = prop->Id()->Name().Mutf8();
917     if (type->IsETSArrayType() || type->IsETSResizableArrayType()) {
918         return ProcessArrayType(prop, baseName, init);
919     }
920 
921     if (type->IsETSEnumType()) {
922         return ProcessETSEnumType(baseName, init, type);
923     }
924     switch (checker::ETSChecker::TypeKind(
925         Context()->checker->AsETSChecker()->MaybeUnboxType(const_cast<checker::Type *>(type)))) {
926         case checker::TypeFlag::BYTE:
927         case checker::TypeFlag::SHORT:
928         case checker::TypeFlag::INT:
929         case checker::TypeFlag::LONG:
930         case checker::TypeFlag::FLOAT:
931         case checker::TypeFlag::DOUBLE:
932         case checker::TypeFlag::ETS_BOOLEAN:
933         case checker::TypeFlag::ETS_OBJECT: {
934             if (init->IsUnaryExpression() && IsNegativeLiteralNode(init->AsUnaryExpression())) {
935                 double negNumberValue =
936                     (-1) * init->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number().GetDouble();
937                 return pandasm::AnnotationElement {
938                     propName, std::make_unique<pandasm::ScalarValue>(
939                                   pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(negNumberValue))};
940             }
941             return pandasm::AnnotationElement {
942                 propName, std::make_unique<pandasm::ScalarValue>(CreateScalarValue(init->TsType(), typeKind))};
943         }
944         default:
945             ES2PANDA_UNREACHABLE();
946     }
947 }
948 
GenCustomAnnotation(ir::AnnotationUsage * anno,std::string & baseName)949 pandasm::AnnotationData ETSEmitter::GenCustomAnnotation(ir::AnnotationUsage *anno, std::string &baseName)
950 {
951     auto *annoDecl = anno->GetBaseName()->Variable()->Declaration()->Node()->AsAnnotationDeclaration();
952     pandasm::AnnotationData annotation(annoDecl->InternalName().Mutf8());
953     if (annoDecl->IsImportDeclaration()) {
954         auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang);
955         annoRecord.metadata->SetAttribute(Signatures::EXTERNAL);
956         uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_ANNOTATION;
957         annoRecord.metadata->SetAccessFlags(accessFlags);
958         Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord));
959     }
960 
961     for (auto *prop : anno->Properties()) {
962         annotation.AddElement(GenCustomAnnotationElement(prop->AsClassProperty(), baseName));
963     }
964     return annotation;
965 }
966 
GenCustomAnnotations(const ArenaVector<ir::AnnotationUsage * > & annotationUsages,const std::string & baseName)967 std::vector<pandasm::AnnotationData> ETSEmitter::GenCustomAnnotations(
968     const ArenaVector<ir::AnnotationUsage *> &annotationUsages, const std::string &baseName)
969 {
970     std::vector<pandasm::AnnotationData> annotations;
971     for (auto *anno : annotationUsages) {
972         auto *annoDecl = anno->GetBaseName()->Variable()->Declaration()->Node()->AsAnnotationDeclaration();
973         if (!annoDecl->IsSourceRetention()) {
974             auto newBaseName = GenerateMangledName(baseName, anno->GetBaseName()->Name().Mutf8());
975             annotations.emplace_back(GenCustomAnnotation(anno, newBaseName));
976         }
977     }
978     return annotations;
979 }
980 
GenAnnotationModule(const ir::ClassDefinition * classDef)981 pandasm::AnnotationData ETSEmitter::GenAnnotationModule(const ir::ClassDefinition *classDef)
982 {
983     std::vector<pandasm::ScalarValue> exportedClasses {};
984 
985     for (auto cls : classDef->ExportedClasses()) {
986         exportedClasses.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::RECORD>(
987             pandasm::Type::FromName(cls->Definition()->InternalName().Utf8(), true)));
988     }
989 
990     GenAnnotationRecord(Signatures::ETS_ANNOTATION_MODULE);
991     pandasm::AnnotationData moduleAnno(Signatures::ETS_ANNOTATION_MODULE);
992     pandasm::AnnotationElement value(
993         Signatures::ANNOTATION_KEY_EXPORTED,
994         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::RECORD, std::move(exportedClasses)));
995     moduleAnno.AddElement(std::move(value));
996     return moduleAnno;
997 }
998 
GenAnnotationSignature(const ir::ClassDefinition * classDef)999 pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef)
1000 {
1001     std::vector<pandasm::ScalarValue> parts {};
1002     const auto &typeParams = classDef->TypeParams()->Params();
1003 
1004     auto const addStringValue = [&parts](std::string_view str) {
1005         parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(str));
1006     };
1007 
1008     if (!typeParams.empty()) {
1009         addStringValue(Signatures::GENERIC_BEGIN);
1010 
1011         for (const auto *param : typeParams) {
1012             addStringValue(Signatures::MANGLE_BEGIN);
1013             std::stringstream ss;
1014             param->Constraint()->TsType()->ToAssemblerTypeWithRank(ss);
1015             auto asmName = util::StringView(ss.str());
1016             addStringValue(checker::ETSObjectType::NameToDescriptor(asmName));
1017         }
1018         addStringValue(Signatures::GENERIC_END);
1019     }
1020 
1021     if (auto super = classDef->TsType()->AsETSObjectType()->SuperType(); super != nullptr) {
1022         addStringValue(checker::ETSObjectType::NameToDescriptor(util::StringView(super->AssemblerName().Mutf8())));
1023     } else {
1024         addStringValue(checker::ETSObjectType::NameToDescriptor(Signatures::BUILTIN_OBJECT));
1025     }
1026 
1027     GenAnnotationRecord(Signatures::ETS_ANNOTATION_SIGNATURE);
1028     pandasm::AnnotationData signature(Signatures::ETS_ANNOTATION_SIGNATURE);
1029     pandasm::AnnotationElement value(
1030         Signatures::ANNOTATION_KEY_VALUE,
1031         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(parts)));
1032     signature.AddElement(std::move(value));
1033     return signature;
1034 }
1035 
GenAnnotationEnclosingMethod(const ir::MethodDefinition * methodDef)1036 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef)
1037 {
1038     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
1039     pandasm::AnnotationData enclosingMethod(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
1040     ES2PANDA_ASSERT(methodDef->Function() != nullptr);
1041     pandasm::AnnotationElement value(
1042         Signatures::ANNOTATION_KEY_VALUE,
1043         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
1044             methodDef->Function()->Scope()->InternalName().Mutf8())));
1045     enclosingMethod.AddElement(std::move(value));
1046     return enclosingMethod;
1047 }
1048 
GenAnnotationFunctionalReference(const ir::ClassDefinition * classDef)1049 pandasm::AnnotationData ETSEmitter::GenAnnotationFunctionalReference(const ir::ClassDefinition *classDef)
1050 {
1051     GenAnnotationRecord(Signatures::ETS_ANNOTATION_FUNCTIONAL_REFERENCE);
1052     pandasm::AnnotationData functionalReference(Signatures::ETS_ANNOTATION_FUNCTIONAL_REFERENCE);
1053     bool isStatic = classDef->FunctionalReferenceReferencedMethod()->IsStatic();
1054     ES2PANDA_ASSERT(const_cast<ir::ClassDefinition *>(classDef) != nullptr);
1055     pandasm::AnnotationElement value(
1056         Signatures::ANNOTATION_KEY_VALUE,
1057         std::make_unique<pandasm::ScalarValue>(
1058             pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(const_cast<ir::ClassDefinition *>(classDef)
1059                                                                            ->FunctionalReferenceReferencedMethod()
1060                                                                            ->Function()
1061                                                                            ->Scope()
1062                                                                            ->InternalName()
1063                                                                            .Mutf8(),
1064                                                                        isStatic)));
1065     functionalReference.AddElement(std::move(value));
1066     return functionalReference;
1067 }
1068 
GenAnnotationEnclosingClass(std::string_view className)1069 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className)
1070 {
1071     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
1072     pandasm::AnnotationData enclosingClass(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
1073     pandasm::AnnotationElement value(
1074         Signatures::ANNOTATION_KEY_VALUE,
1075         std::make_unique<pandasm::ScalarValue>(
1076             pandasm::ScalarValue::Create<pandasm::Value::Type::RECORD>(pandasm::Type::FromName(className, true))));
1077     enclosingClass.AddElement(std::move(value));
1078     return enclosingClass;
1079 }
1080 
GenAnnotationInnerClass(const ir::ClassDefinition * classDef,const ir::AstNode * parent)1081 pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef,
1082                                                             const ir::AstNode *parent)
1083 {
1084     GenAnnotationRecord(Signatures::ETS_ANNOTATION_INNER_CLASS);
1085     pandasm::AnnotationData innerClass(Signatures::ETS_ANNOTATION_INNER_CLASS);
1086     const bool isAnonymous = (classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS) != 0;
1087     pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME,
1088                                     std::make_unique<pandasm::ScalarValue>(
1089                                         isAnonymous
1090                                             ? pandasm::ScalarValue::Create<pandasm::Value::Type::STRING_NULLPTR>(0)
1091                                             : pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
1092                                                   classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8())));
1093     innerClass.AddElement(std::move(name));
1094 
1095     pandasm::AnnotationElement accessFlags(
1096         Signatures::ANNOTATION_KEY_ACCESS_FLAGS,
1097         std::make_unique<pandasm::ScalarValue>(
1098             pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(TranslateModifierFlags(parent->Modifiers()))));
1099     innerClass.AddElement(std::move(accessFlags));
1100     return innerClass;
1101 }
1102 
FindAsyncImpl(ir::ScriptFunction * asyncFunc)1103 ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc)
1104 {
1105     std::string implName = checker::ETSChecker::GetAsyncImplName(asyncFunc->Id()->Name());
1106     ir::AstNode *ownerNode = asyncFunc->Signature()->Owner()->GetDeclNode();
1107     ES2PANDA_ASSERT(ownerNode != nullptr && ownerNode->IsClassDefinition());
1108     const ir::ClassDefinition *classDef = ownerNode->AsClassDefinition();
1109     ES2PANDA_ASSERT(classDef != nullptr);
1110 
1111     auto it =
1112         std::find_if(classDef->Body().rbegin(), classDef->Body().rend(), [&implName, &asyncFunc](ir::AstNode *node) {
1113             if (!node->IsMethodDefinition()) {
1114                 return false;
1115             }
1116             bool isSameName = node->AsMethodDefinition()->Id()->Name().Utf8() == implName;
1117             bool isBothStaticOrInstance =
1118                 (node->Modifiers() & ir::ModifierFlags::STATIC) == (asyncFunc->Modifiers() & ir::ModifierFlags::STATIC);
1119             return isSameName && isBothStaticOrInstance;
1120         });
1121     if (it == classDef->Body().rend()) {
1122         return nullptr;
1123     }
1124 
1125     ir::MethodDefinition *method = (*it)->AsMethodDefinition();
1126     auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
1127     checker::TypeRelation *typeRel = checker->Relation();
1128     checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK);
1129     ES2PANDA_ASSERT(method->Function() != nullptr);
1130     method->Function()->Signature()->IsSubtypeOf(typeRel, asyncFunc->Signature());
1131     auto overloadIt = method->Overloads().begin();
1132     while (overloadIt != method->Overloads().end() && !typeRel->IsTrue()) {
1133         method = *overloadIt;
1134         method->Function()->Signature()->IsSubtypeOf(typeRel, asyncFunc->Signature());
1135         ++overloadIt;
1136     }
1137     return typeRel->IsTrue() ? method : nullptr;
1138 }
1139 
GenAnnotationAsync(ir::ScriptFunction * scriptFunc)1140 pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scriptFunc)
1141 {
1142     GenAnnotationRecord(Signatures::ETS_COROUTINE_ASYNC);
1143     const ir::MethodDefinition *impl = FindAsyncImpl(scriptFunc);
1144     ES2PANDA_ASSERT(impl != nullptr);
1145     ES2PANDA_ASSERT(impl->Function() != nullptr);
1146     pandasm::AnnotationData ann(Signatures::ETS_COROUTINE_ASYNC);
1147     pandasm::AnnotationElement value(
1148         Signatures::ANNOTATION_KEY_VALUE,
1149         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
1150             impl->Function()->Scope()->InternalName().Mutf8())));
1151     ann.AddElement(std::move(value));
1152     return ann;
1153 }
1154 
GenAnnotationDynamicCall(DynamicCallNamesMap & callNames)1155 pandasm::AnnotationData ETSEmitter::GenAnnotationDynamicCall(DynamicCallNamesMap &callNames)
1156 {
1157     GenAnnotationRecord(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
1158     pandasm::AnnotationData dynamicCallSig(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
1159     std::vector<pandasm::ScalarValue> allParts {};
1160     for (auto &[parts, startIdx] : callNames) {
1161         startIdx = allParts.size();
1162         for (const auto &str : parts) {
1163             allParts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(str.Utf8()));
1164         }
1165     }
1166     pandasm::AnnotationElement value(
1167         Signatures::ANNOTATION_KEY_VALUE,
1168         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(allParts)));
1169     dynamicCallSig.AddElement(std::move(value));
1170     return dynamicCallSig;
1171 }
1172 
GenAnnotationRecord(std::string_view recordNameView,bool isRuntime,bool isType)1173 void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType)
1174 {
1175     const std::string recordName(recordNameView);
1176     const auto recordIt = Program()->recordTable.find(recordName);
1177     if (recordIt == Program()->recordTable.end()) {
1178         pandasm::Record record(recordName, EXTENSION);
1179         record.metadata->SetAttribute(Signatures::EXTERNAL);
1180         record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE);
1181         if (isRuntime && isType) {
1182             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE,
1183                                                Signatures::RUNTIME_TYPE_ANNOTATION);
1184         } else if (isRuntime && !isType) {
1185             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION);
1186         } else if (!isRuntime && isType) {
1187             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION);
1188         }
1189         Program()->recordTable.emplace(record.name, std::move(record));
1190     }
1191 }
1192 }  // namespace ark::es2panda::compiler
1193