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 ¶ms = 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