• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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/variableFlags.h"
21 #include "varbinder/ETSBinder.h"
22 #include "ir/astNode.h"
23 #include "ir/expressions/identifier.h"
24 #include "ir/base/decorator.h"
25 #include "ir/base/methodDefinition.h"
26 #include "ir/base/classDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classProperty.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 "public/public.h"
43 
44 #include "assembly-program.h"
45 
46 namespace ark::es2panda::compiler {
47 
48 #ifdef PANDA_WITH_ETS
49 static constexpr auto EXTENSION = panda_file::SourceLang::ETS;
50 #else
51 // NOTE: temporary dummy gn buildfix until ETS plugin has gn build support
52 static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY;
53 #endif
54 
TranslateModifierFlags(ir::ModifierFlags modifierFlags)55 static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags)
56 {
57     uint32_t accessFlags = 0;
58 
59     if ((modifierFlags & ir::ModifierFlags::PRIVATE) != 0) {
60         accessFlags = ACC_PRIVATE;
61     } else if ((modifierFlags & ir::ModifierFlags::INTERNAL) != 0) {
62         if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
63             accessFlags = ACC_PROTECTED;
64         }
65         // NOTE: torokg. Add ACC_INTERNAL access flag to libpandabase
66     } else if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
67         accessFlags = ACC_PROTECTED;
68     } else {
69         accessFlags = ACC_PUBLIC;
70     }
71 
72     if ((modifierFlags & ir::ModifierFlags::STATIC) != 0) {
73         accessFlags |= ACC_STATIC;
74     }
75     if ((modifierFlags & ir::ModifierFlags::FINAL) != 0) {
76         accessFlags |= ACC_FINAL;
77     }
78     // NOTE: should be ModifierFlags::READONLY
79     if ((modifierFlags & ir::ModifierFlags::READONLY) != 0) {
80         accessFlags |= ACC_READONLY;
81     }
82     if ((modifierFlags & ir::ModifierFlags::ABSTRACT) != 0) {
83         accessFlags |= ACC_ABSTRACT;
84     }
85     if ((modifierFlags & ir::ModifierFlags::NATIVE) != 0) {
86         accessFlags |= ACC_NATIVE;
87     }
88 
89     return accessFlags;
90 }
91 
PandasmTypeWithRank(checker::Type const * type)92 static pandasm::Type PandasmTypeWithRank(checker::Type const *type)
93 {
94     if (type->IsETSTypeParameter()) {
95         return PandasmTypeWithRank(type->AsETSTypeParameter()->GetConstraintType());
96     }
97     if (type->IsETSNonNullishType()) {
98         return PandasmTypeWithRank(type->AsETSNonNullishType()->GetUnderlying());
99     }
100     if (type->IsETSUnionType()) {
101         return PandasmTypeWithRank(type->AsETSUnionType()->GetAssemblerLUB());
102     }
103 
104     std::stringstream ss;
105     type->ToAssemblerType(ss);
106     return pandasm::Type(ss.str(), type->Rank());
107 }
108 
GenScriptFunction(const ir::ScriptFunction * scriptFunc)109 static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc)
110 {
111     auto *funcScope = scriptFunc->Scope();
112     auto *paramScope = funcScope->ParamScope();
113 
114     auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION);
115     func.params.reserve(paramScope->Params().size());
116 
117     for (const auto *var : paramScope->Params()) {
118         func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION);
119     }
120 
121     if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) {
122         func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
123     } else {
124         func.returnType = PandasmTypeWithRank(scriptFunc->Signature()->ReturnType());
125     }
126 
127     uint32_t accessFlags = 0;
128     if (!scriptFunc->IsStaticBlock()) {
129         const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc);
130         accessFlags |= TranslateModifierFlags(methodDef->Modifiers());
131     }
132     if (scriptFunc->HasRestParameter()) {
133         accessFlags |= ACC_VARARGS;
134     }
135     func.metadata->SetAccessFlags(accessFlags);
136 
137     return func;
138 }
139 
GenFunctionSignature()140 pandasm::Function *ETSFunctionEmitter::GenFunctionSignature()
141 {
142     auto func = GenScriptFunction(Cg()->RootNode()->AsScriptFunction());
143 
144     if (Cg()->RootNode()->AsScriptFunction()->IsExternal()) {
145         func.metadata->SetAttribute(Signatures::EXTERNAL);
146     }
147 
148     auto *funcElement = new pandasm::Function(func.name, func.language);
149     *funcElement = std::move(func);
150     GetProgramElement()->SetFunction(funcElement);
151     funcElement->regsNum = VReg::REG_START - Cg()->TotalRegsNum();
152 
153     return funcElement;
154 }
155 
GenVariableSignature(pandasm::debuginfo::LocalVariable & variableDebug,varbinder::LocalVariable * variable) const156 void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug,
157                                               [[maybe_unused]] varbinder::LocalVariable *variable) const
158 {
159     variableDebug.signature = Signatures::ANY;
160     variableDebug.signatureType = Signatures::ANY;
161 }
162 
GenFunctionAnnotations(pandasm::Function * func)163 void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {}
164 
165 template <typename T>
GenExternalFunction(T signature,bool isCtor)166 static pandasm::Function GenExternalFunction(T signature, bool isCtor)
167 {
168     auto iter = signature.begin();
169     std::string name(*iter++);
170 
171     auto func = pandasm::Function(name, EXTENSION);
172 
173     while (iter != signature.end()) {
174         auto paramName = *iter++;
175         func.params.emplace_back(pandasm::Type(paramName, 0), EXTENSION);
176     }
177 
178     func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
179     if (isCtor) {
180         func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
181     }
182     func.metadata->SetAttribute(Signatures::EXTERNAL);
183 
184     return func;
185 }
186 
GenExternalFunction(checker::Signature * signature,bool isCtor)187 static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor)
188 {
189     auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION);
190 
191     for (auto param : signature->Params()) {
192         func.params.emplace_back(PandasmTypeWithRank(param->TsType()), EXTENSION);
193     }
194     func.returnType = PandasmTypeWithRank(signature->ReturnType());
195 
196     if (isCtor) {
197         func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
198     }
199     func.metadata->SetAttribute(Signatures::EXTERNAL);
200 
201     return func;
202 }
203 
GenAnnotation()204 void ETSEmitter::GenAnnotation()
205 {
206     Program()->lang = EXTENSION;
207     const auto *varbinder = static_cast<varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
208 
209     auto *globalRecordTable = varbinder->GetGlobalRecordTable();
210 
211     for (auto *classDecl : globalRecordTable->ClassDefinitions()) {
212         GenClassRecord(classDecl, false);
213     }
214 
215     for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) {
216         GenInterfaceRecord(interfaceDecl, false);
217     }
218 
219     for (auto *signature : globalRecordTable->Signatures()) {
220         auto *scriptFunc = signature->Node()->AsScriptFunction();
221         auto func = scriptFunc->Declare() ? GenExternalFunction(scriptFunc->Signature(), scriptFunc->IsConstructor())
222                                           : GenScriptFunction(scriptFunc);
223         if (scriptFunc->IsAsyncFunc()) {
224             std::vector<pandasm::AnnotationData> annotations;
225             annotations.push_back(GenAnnotationAsync(scriptFunc));
226             func.metadata->SetAnnotations(std::move(annotations));
227         }
228         Program()->functionTable.emplace(func.name, std::move(func));
229     }
230 
231     for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) {
232         (void)extProg;
233         GenExternalRecord(recordTable);
234     }
235 
236     const auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
237 
238     for (auto [arrType, signature] : checker->GlobalArrayTypes()) {
239         GenGlobalArrayRecord(arrType, signature);
240     }
241 }
242 
GenExternalRecord(varbinder::RecordTable * recordTable)243 void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable)
244 {
245     bool isGenStdLib = recordTable->Program()->VarBinder()->IsGenStdLib();
246     for (auto *classDecl : recordTable->ClassDefinitions()) {
247         GenClassRecord(classDecl, !isGenStdLib);
248     }
249 
250     for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) {
251         GenInterfaceRecord(interfaceDecl, !isGenStdLib);
252     }
253 
254     for (auto *signature : recordTable->Signatures()) {
255         auto func = GenScriptFunction(signature->Node()->AsScriptFunction());
256 
257         if (!isGenStdLib) {
258             func.metadata->SetAttribute(Signatures::EXTERNAL);
259         }
260 
261         Program()->functionTable.emplace(func.name, std::move(func));
262     }
263 }
264 
265 // Helper function to reduce EmitDefaultFieldValue size and pass code check
CreateScalarValue(const checker::Type * type,checker::TypeFlag typeKind)266 static pandasm::ScalarValue CreateScalarValue(const checker::Type *type, checker::TypeFlag typeKind)
267 {
268     switch (typeKind) {
269         case checker::TypeFlag::ETS_BOOLEAN: {
270             return pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
271                 static_cast<uint8_t>(type->AsETSBooleanType()->GetValue()));
272         }
273         case checker::TypeFlag::BYTE: {
274             return pandasm::ScalarValue::Create<pandasm::Value::Type::I8>(type->AsByteType()->GetValue());
275         }
276         case checker::TypeFlag::SHORT: {
277             return pandasm::ScalarValue::Create<pandasm::Value::Type::I16>(type->AsShortType()->GetValue());
278         }
279         case checker::TypeFlag::INT: {
280             return pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(type->AsIntType()->GetValue());
281         }
282         case checker::TypeFlag::LONG: {
283             return pandasm::ScalarValue::Create<pandasm::Value::Type::I64>(type->AsLongType()->GetValue());
284         }
285         case checker::TypeFlag::FLOAT: {
286             return pandasm::ScalarValue::Create<pandasm::Value::Type::F32>(type->AsFloatType()->GetValue());
287         }
288         case checker::TypeFlag::DOUBLE: {
289             return pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(type->AsDoubleType()->GetValue());
290         }
291         case checker::TypeFlag::CHAR: {
292             return pandasm::ScalarValue::Create<pandasm::Value::Type::U16>(type->AsCharType()->GetValue());
293         }
294         case checker::TypeFlag::ETS_OBJECT: {
295             return pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
296                 type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8());
297         }
298         default: {
299             UNREACHABLE();
300         }
301     }
302 }
303 
EmitDefaultFieldValue(pandasm::Field & classField,const ir::Expression * init)304 void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init)
305 {
306     if (init == nullptr) {
307         return;
308     }
309 
310     const auto *type = init->TsType();
311 
312     if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
313         return;
314     }
315 
316     auto typeKind = checker::ETSChecker::TypeKind(type);
317     classField.metadata->SetFieldType(classField.type);
318     classField.metadata->SetValue(CreateScalarValue(type, typeKind));
319 }
320 
GenInterfaceMethodDefinition(const ir::MethodDefinition * methodDef,bool external)321 void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external)
322 {
323     auto *scriptFunc = methodDef->Function();
324     auto func = GenScriptFunction(scriptFunc);
325 
326     if (external) {
327         func.metadata->SetAttribute(Signatures::EXTERNAL);
328     }
329 
330     if (scriptFunc->Body() != nullptr) {
331         return;
332     }
333 
334     func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT);
335     Program()->functionTable.emplace(func.name, std::move(func));
336 }
337 
GenClassField(const ir::ClassProperty * field,pandasm::Record & classRecord,bool external)338 void ETSEmitter::GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external)
339 {
340     GenField({field->TsType(), field->Id()->Name(), field->Value(), TranslateModifierFlags(field->Modifiers()),
341               classRecord, external || field->IsDeclare()});
342 }
343 
GenField(const GenFieldArguments & data)344 void ETSEmitter::GenField(const GenFieldArguments &data)
345 {
346     auto field = pandasm::Field(Program()->lang);
347     field.name = data.name.Mutf8();
348     field.type = PandasmTypeWithRank(data.tsType);
349     field.metadata->SetAccessFlags(data.accesFlags);
350 
351     if (data.external) {
352         field.metadata->SetAttribute(Signatures::EXTERNAL);
353     } else if (data.tsType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) || data.tsType->IsETSStringType()) {
354         EmitDefaultFieldValue(field, data.value);
355     }
356 
357     data.record.fieldList.emplace_back(std::move(field));
358 }
359 
GenClassInheritedFields(const checker::ETSObjectType * baseType,pandasm::Record & classRecord)360 void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord)
361 {
362     std::vector<const varbinder::LocalVariable *> foreignProps = baseType->ForeignProperties();
363 
364     for (const auto *foreignProp : foreignProps) {
365         auto *declNode = foreignProp->Declaration()->Node();
366         if (!declNode->IsClassProperty()) {
367             continue;
368         }
369 
370         GenClassField(declNode->AsClassProperty(), classRecord, true);
371     }
372 }
373 
GenGlobalArrayRecord(checker::ETSArrayType * arrayType,checker::Signature * signature)374 void ETSEmitter::GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature)
375 {
376     std::stringstream ss;
377     arrayType->ToAssemblerTypeWithRank(ss);
378 
379     auto arrayRecord = pandasm::Record(ss.str(), Program()->lang);
380 
381     auto func = GenExternalFunction(signature, true);
382     func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION);
383 
384     Program()->functionTable.emplace(func.name, std::move(func));
385 
386     arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL);
387     Program()->recordTable.emplace(arrayRecord.name, std::move(arrayRecord));
388     Program()->arrayTypes.emplace(PandasmTypeWithRank(arrayType));
389 }
390 
GenInterfaceRecord(const ir::TSInterfaceDeclaration * interfaceDecl,bool external)391 void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external)
392 {
393     auto *baseType = interfaceDecl->TsType()->AsETSObjectType();
394 
395     auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang);
396 
397     if (external) {
398         interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL);
399     }
400 
401     uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE;
402 
403     if (interfaceDecl->IsStatic()) {
404         accessFlags |= ACC_STATIC;
405     }
406 
407     interfaceRecord.metadata->SetAccessFlags(accessFlags);
408     interfaceRecord.sourceFile =
409         Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
410     interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
411 
412     for (auto *it : baseType->Interfaces()) {
413         auto *declNode = it->GetDeclNode();
414         ASSERT(declNode->IsTSInterfaceDeclaration());
415         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
416         interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
417     }
418 
419     GenClassInheritedFields(baseType, interfaceRecord);
420 
421     for (const auto *prop : interfaceDecl->Body()->Body()) {
422         if (prop->IsClassProperty()) {
423             GenClassField(prop->AsClassProperty(), interfaceRecord, external);
424         } else if (prop->IsMethodDefinition()) {
425             GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external);
426         }
427     }
428 
429     Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord));
430 }
431 
GenAnnotations(const ir::ClassDefinition * classDef)432 std::vector<pandasm::AnnotationData> ETSEmitter::GenAnnotations(const ir::ClassDefinition *classDef)
433 {
434     std::vector<pandasm::AnnotationData> annotations;
435     const ir::AstNode *parent = classDef->Parent();
436     while (parent != nullptr) {
437         if (parent->IsMethodDefinition()) {
438             annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition()));
439             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
440             break;
441         }
442         if (parent->IsClassDefinition()) {
443             annotations.emplace_back(GenAnnotationEnclosingClass(
444                 parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8()));
445             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
446             break;
447         }
448         parent = parent->Parent();
449     }
450 
451     auto classIdent = classDef->Ident()->Name().Mutf8();
452     bool isConstruct = classIdent == Signatures::JSNEW_CLASS;
453     if (isConstruct || classIdent == Signatures::JSCALL_CLASS) {
454         auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct);
455         annotations.push_back(GenAnnotationDynamicCall(*callNames));
456     }
457 
458     return annotations;
459 }
460 
GetAccessFlags(const ir::ClassDefinition * classDef)461 static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef)
462 {
463     uint32_t accessFlags = ACC_PUBLIC;
464     if (classDef->IsAbstract()) {
465         accessFlags |= ACC_ABSTRACT;
466     } else if (classDef->IsFinal()) {
467         accessFlags |= ACC_FINAL;
468     }
469 
470     if (classDef->IsStatic()) {
471         accessFlags |= ACC_STATIC;
472     }
473 
474     return accessFlags;
475 }
476 
GenClassRecord(const ir::ClassDefinition * classDef,bool external)477 void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external)
478 {
479     auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang);
480     if (external) {
481         classRecord.metadata->SetAttribute(Signatures::EXTERNAL);
482     }
483 
484     uint32_t accessFlags = GetAccessFlags(classDef);
485     classRecord.metadata->SetAccessFlags(accessFlags);
486     classRecord.sourceFile = Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
487 
488     auto *baseType = classDef->TsType()->AsETSObjectType();
489     if (baseType->SuperType() != nullptr) {
490         classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE,
491                                                 baseType->SuperType()->AssemblerName().Mutf8());
492     } else {
493         // NOTE: rtakacs. Replace the whole if block (below) with assert when lambda objects have super class.
494         if (baseType->AssemblerName().Mutf8() != Signatures::BUILTIN_OBJECT) {
495             classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
496         }
497     }
498 
499     for (auto *it : baseType->Interfaces()) {
500         // We do not need to add dynamic interfaces
501         if (it->IsETSDynamicType()) {
502             continue;
503         }
504 
505         auto *declNode = it->GetDeclNode();
506         // NOTE: itrubachev. replace it with ASSERT(decl_node->IsTSInterfaceDeclaration())
507         // after adding proper creation of lambda object in ETSFunctionType::AssignmentSource
508         if (!declNode->IsTSInterfaceDeclaration()) {
509             continue;
510         }
511         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
512         classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
513     }
514 
515     GenClassInheritedFields(baseType, classRecord);
516     for (const auto *prop : classDef->Body()) {
517         if (!prop->IsClassProperty()) {
518             continue;
519         }
520 
521         GenClassField(prop->AsClassProperty(), classRecord, external);
522     }
523 
524     std::vector<pandasm::AnnotationData> annotations = GenAnnotations(classDef);
525     if (!annotations.empty()) {
526         classRecord.metadata->SetAnnotations(std::move(annotations));
527     }
528 
529     Program()->recordTable.emplace(classRecord.name, std::move(classRecord));
530 }
531 
GenAnnotationSignature(const ir::ClassDefinition * classDef)532 pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef)
533 {
534     static constexpr std::string_view OBJECT = "Lstd/core/Object";
535     std::vector<pandasm::ScalarValue> parts {};
536     std::stringstream ss {};
537     const auto &params = classDef->TypeParams()->Params();
538 
539     bool firstIteration = true;
540     for (const auto *param : params) {
541         if (firstIteration) {
542             ss << Signatures::GENERIC_BEGIN;
543             firstIteration = false;
544         }
545         ss << param->Name()->Name() << Signatures::MANGLE_BEGIN;
546         parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
547 
548         std::stringstream {}.swap(ss);
549         if (param->Constraint() == nullptr) {
550             ss << OBJECT;
551         } else {
552             param->Constraint()->TsType()->ToAssemblerTypeWithRank(ss);
553             auto str = ss.str();
554             std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(),
555                          *Signatures::NAMESPACE_SEPARATOR.begin());
556             std::stringstream {}.swap(ss);
557             ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR;
558         }
559 
560         parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
561         std::stringstream {}.swap(ss);  // cleanup
562     }
563 
564     ss << Signatures::GENERIC_END;
565     parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
566 
567     std::stringstream {}.swap(ss);
568     if (classDef->TsType()->AsETSObjectType()->SuperType() == nullptr) {
569         ss << OBJECT;
570     } else {
571         ss << Signatures::CLASS_REF_BEGIN;
572         auto superType = classDef->TsType()->AsETSObjectType()->SuperType()->AssemblerName().Mutf8();
573         std::replace(superType.begin(), superType.end(), *Signatures::METHOD_SEPARATOR.begin(),
574                      *Signatures::NAMESPACE_SEPARATOR.begin());
575         ss << superType << Signatures::MANGLE_SEPARATOR;
576     }
577     parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
578 
579     GenAnnotationRecord(Signatures::ETS_ANNOTATION_SIGNATURE);
580     pandasm::AnnotationData signature(Signatures::ETS_ANNOTATION_SIGNATURE);
581     pandasm::AnnotationElement value(
582         Signatures::ANNOTATION_KEY_VALUE,
583         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(parts)));
584     signature.AddElement(std::move(value));
585     return signature;
586 }
587 
GenAnnotationEnclosingMethod(const ir::MethodDefinition * methodDef)588 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef)
589 {
590     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
591     pandasm::AnnotationData enclosingMethod(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
592     pandasm::AnnotationElement value(
593         Signatures::ANNOTATION_KEY_VALUE,
594         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
595             methodDef->Function()->Scope()->InternalName().Mutf8())));
596     enclosingMethod.AddElement(std::move(value));
597     return enclosingMethod;
598 }
599 
GenAnnotationEnclosingClass(std::string_view className)600 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className)
601 {
602     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
603     pandasm::AnnotationData enclosingClass(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
604     pandasm::AnnotationElement value(
605         Signatures::ANNOTATION_KEY_VALUE,
606         std::make_unique<pandasm::ScalarValue>(
607             pandasm::ScalarValue::Create<pandasm::Value::Type::RECORD>(pandasm::Type::FromName(className, true))));
608     enclosingClass.AddElement(std::move(value));
609     return enclosingClass;
610 }
611 
GenAnnotationInnerClass(const ir::ClassDefinition * classDef,const ir::AstNode * parent)612 pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef,
613                                                             const ir::AstNode *parent)
614 {
615     GenAnnotationRecord(Signatures::ETS_ANNOTATION_INNER_CLASS);
616     pandasm::AnnotationData innerClass(Signatures::ETS_ANNOTATION_INNER_CLASS);
617     const bool isAnonymous = (classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS) != 0;
618     pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME,
619                                     std::make_unique<pandasm::ScalarValue>(
620                                         isAnonymous
621                                             ? pandasm::ScalarValue::Create<pandasm::Value::Type::STRING_NULLPTR>(0)
622                                             : pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
623                                                   classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8())));
624     innerClass.AddElement(std::move(name));
625 
626     pandasm::AnnotationElement accessFlags(
627         Signatures::ANNOTATION_KEY_ACCESS_FLAGS,
628         std::make_unique<pandasm::ScalarValue>(
629             pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(TranslateModifierFlags(parent->Modifiers()))));
630     innerClass.AddElement(std::move(accessFlags));
631     return innerClass;
632 }
633 
FindAsyncImpl(ir::ScriptFunction * asyncFunc)634 ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc)
635 {
636     std::string implName = checker::ETSChecker::GetAsyncImplName(asyncFunc->Id()->Name());
637     ir::AstNode *ownerNode = asyncFunc->Signature()->Owner()->GetDeclNode();
638     ASSERT(ownerNode != nullptr && ownerNode->IsClassDefinition());
639     const ir::ClassDefinition *classDef = ownerNode->AsClassDefinition();
640     ASSERT(classDef != nullptr);
641 
642     auto it = std::find_if(classDef->Body().rbegin(), classDef->Body().rend(), [&implName](ir::AstNode *node) {
643         return node->IsMethodDefinition() && node->AsMethodDefinition()->Id()->Name().Utf8() == implName;
644     });
645     if (it == classDef->Body().rend()) {
646         return nullptr;
647     }
648 
649     ir::MethodDefinition *method = (*it)->AsMethodDefinition();
650     auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
651     checker::TypeRelation *typeRel = checker->Relation();
652     checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK);
653     method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
654     auto overloadIt = method->Overloads().begin();
655     while (overloadIt != method->Overloads().end() && !typeRel->IsTrue()) {
656         method = *overloadIt;
657         method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
658         ++overloadIt;
659     }
660     return typeRel->IsTrue() ? method : nullptr;
661 }
662 
GenAnnotationAsync(ir::ScriptFunction * scriptFunc)663 pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scriptFunc)
664 {
665     GenAnnotationRecord(Signatures::ETS_COROUTINE_ASYNC);
666     const ir::MethodDefinition *impl = FindAsyncImpl(scriptFunc);
667     ASSERT(impl != nullptr);
668     pandasm::AnnotationData ann(Signatures::ETS_COROUTINE_ASYNC);
669     pandasm::AnnotationElement value(
670         Signatures::ANNOTATION_KEY_VALUE,
671         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
672             impl->Function()->Scope()->InternalName().Mutf8())));
673     ann.AddElement(std::move(value));
674     return ann;
675 }
676 
GenAnnotationDynamicCall(DynamicCallNamesMap & callNames)677 pandasm::AnnotationData ETSEmitter::GenAnnotationDynamicCall(DynamicCallNamesMap &callNames)
678 {
679     GenAnnotationRecord(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
680     pandasm::AnnotationData dynamicCallSig(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
681     std::vector<pandasm::ScalarValue> allParts {};
682     for (auto &[parts, startIdx] : callNames) {
683         startIdx = allParts.size();
684         for (const auto &str : parts) {
685             allParts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(str.Utf8()));
686         }
687     }
688     pandasm::AnnotationElement value(
689         Signatures::ANNOTATION_KEY_VALUE,
690         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(allParts)));
691     dynamicCallSig.AddElement(std::move(value));
692     return dynamicCallSig;
693 }
694 
GenAnnotationRecord(std::string_view recordNameView,bool isRuntime,bool isType)695 void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType)
696 {
697     const std::string recordName(recordNameView);
698     const auto recordIt = Program()->recordTable.find(recordName);
699     if (recordIt == Program()->recordTable.end()) {
700         pandasm::Record record(recordName, EXTENSION);
701         record.metadata->SetAttribute(Signatures::EXTERNAL);
702         record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE);
703         if (isRuntime && isType) {
704             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE,
705                                                Signatures::RUNTIME_TYPE_ANNOTATION);
706         } else if (isRuntime && !isType) {
707             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION);
708         } else if (!isRuntime && isType) {
709             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION);
710         }
711         Program()->recordTable.emplace(record.name, std::move(record));
712     }
713 }
714 }  // namespace ark::es2panda::compiler
715