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