• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "classDefinition.h"
17 
18 #include "compiler/base/literals.h"
19 #include "compiler/base/lreference.h"
20 #include "compiler/core/pandagen.h"
21 #include "typescript/checker.h"
22 #include "ir/astDump.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/expressions/assignmentExpression.h"
25 #include "ir/expressions/functionExpression.h"
26 #include "ir/expressions/literals/numberLiteral.h"
27 #include "ir/expressions/literals/stringLiteral.h"
28 #include "ir/expressions/literals/taggedLiteral.h"
29 #include "ir/expressions/memberExpression.h"
30 #include "ir/statements/blockStatement.h"
31 #include "ir/statements/expressionStatement.h"
32 #include "ir/ts/tsClassImplements.h"
33 #include "ir/ts/tsIndexSignature.h"
34 #include "ir/ts/tsTypeParameter.h"
35 #include "ir/ts/tsTypeParameterDeclaration.h"
36 #include "ir/ts/tsTypeParameterInstantiation.h"
37 #include "ir/ts/tsUnionType.h"
38 
39 namespace panda::es2panda::ir {
40 
Ctor() const41 const FunctionExpression *ClassDefinition::Ctor() const
42 {
43     ASSERT(ctor_ != nullptr);
44     return ctor_->Value();
45 }
46 
GetName() const47 util::StringView ClassDefinition::GetName() const
48 {
49     if (ident_) {
50         return ident_->Name();
51     }
52 
53     if (exportDefault_) {
54         return parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME;
55     }
56 
57     return "";
58 }
59 
Iterate(const NodeTraverser & cb) const60 void ClassDefinition::Iterate(const NodeTraverser &cb) const
61 {
62     if (ident_) {
63         cb(ident_);
64     }
65 
66     if (typeParams_) {
67         cb(typeParams_);
68     }
69 
70     if (superClass_) {
71         cb(superClass_);
72     }
73 
74     if (superTypeParams_) {
75         cb(superTypeParams_);
76     }
77 
78     for (auto *it : implements_) {
79         cb(it);
80     }
81 
82     cb(ctor_);
83 
84     for (auto *it : body_) {
85         cb(it);
86     }
87 
88     for (auto *it : indexSignatures_) {
89         cb(it);
90     }
91 }
92 
Dump(ir::AstDumper * dumper) const93 void ClassDefinition::Dump(ir::AstDumper *dumper) const
94 {
95     dumper->Add({{"id", AstDumper::Nullable(ident_)},
96                  {"typeParameters", AstDumper::Optional(typeParams_)},
97                  {"superClass", AstDumper::Nullable(superClass_)},
98                  {"superTypeParameters", AstDumper::Optional(superTypeParams_)},
99                  {"implements", implements_},
100                  {"constructor", ctor_},
101                  {"body", body_},
102                  {"indexSignatures", indexSignatures_}});
103 }
104 
CompileHeritageClause(compiler::PandaGen * pg) const105 compiler::VReg ClassDefinition::CompileHeritageClause(compiler::PandaGen *pg) const
106 {
107     compiler::VReg baseReg = pg->AllocReg();
108 
109     if (superClass_) {
110         superClass_->Compile(pg);
111     } else {
112         pg->LoadConst(this, compiler::Constant::JS_HOLE);
113     }
114 
115     pg->StoreAccumulator(this, baseReg);
116     return baseReg;
117 }
118 
InitializeClassName(compiler::PandaGen * pg) const119 void ClassDefinition::InitializeClassName(compiler::PandaGen *pg) const
120 {
121     if (!ident_) {
122         return;
123     }
124 
125     compiler::LReference lref = compiler::LReference::CreateLRef(pg, ident_, true);
126     lref.SetValue();
127 }
128 
129 // NOLINTNEXTLINE(google-runtime-references)
CreateClassPublicBuffer(compiler::PandaGen * pg,util::BitSet & compiled,int32_t fieldTypeBufIdx) const130 int32_t ClassDefinition::CreateClassPublicBuffer(compiler::PandaGen *pg, util::BitSet &compiled,
131     int32_t fieldTypeBufIdx) const
132 {
133     auto *buf = pg->NewLiteralBuffer();
134     compiler::LiteralBuffer staticBuf(pg->Allocator());
135     uint32_t instancePropertyCount = 0;
136     std::unordered_map<util::StringView, size_t> propNameMap;
137     std::unordered_map<util::StringView, size_t> staticPropNameMap;
138 
139     const auto &properties = body_;
140 
141     for (size_t i = 0; i < properties.size(); i++) {
142         if (!properties[i]->IsMethodDefinition()) {
143             continue;
144         }
145         const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
146         /* If it's sendable, put the getters/setters into literal buffer.
147          * If not, break at getters/setters to be compatible with api10. */
148         if (prop->IsPrivate()) {
149             continue;
150         }
151 
152         if (prop->Computed()) {
153             break;
154         }
155 
156         if (prop->IsAccessor() && !isSendable_) {
157             break;
158         }
159 
160         if (prop->IsAbstract()) {
161             compiled.Set(i);
162             continue;
163         }
164 
165         if (prop->Value()->Function()->IsOverload()) {
166             compiled.Set(i);
167             continue;
168         }
169 
170         util::StringView name = util::Helpers::LiteralToPropName(pg->Allocator(), prop->Key());
171         compiler::LiteralBuffer *literalBuf = prop->IsStatic() ? &staticBuf : buf;
172         auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap;
173 
174         size_t bufferPos = literalBuf->Literals().size();
175         auto res = nameMap.insert({name, bufferPos});
176         if (res.second || isSendable_) {
177             if (!prop->IsStatic()) {
178                 instancePropertyCount++;
179             }
180 
181             literalBuf->Add(pg->Allocator()->New<StringLiteral>(name));
182             literalBuf->Add(nullptr); // save for method internalname
183             literalBuf->Add(nullptr); // save for method affiliate
184         } else {
185             bufferPos = res.first->second;
186         }
187 
188         const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
189         const util::StringView &internalName = func->Function()->Scope()->InternalName();
190 
191         LiteralTag litTag = (prop->Kind() == MethodDefinitionKind::METHOD) ?  LiteralTag::METHOD :
192                             ((prop->Kind() == MethodDefinitionKind::SET) ? LiteralTag::SETTER : LiteralTag::GETTER);
193 
194         Literal *value = pg->Allocator()->New<TaggedLiteral>(litTag, internalName);
195         literalBuf->ResetLiteral(bufferPos + 1, value);
196         Literal *methodAffiliate = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHODAFFILIATE,
197                                                                        func->Function()->FormalParamsLength());
198         literalBuf->ResetLiteral(bufferPos + 2, methodAffiliate); // bufferPos + 2 is saved for method affiliate
199         compiled.Set(i);
200     }
201 
202     /* Static items are stored at the end of the buffer */
203     buf->Insert(&staticBuf);
204 
205     /* The last literal item represents the offset of the first static property. The regular property literal count
206      * is divided by 2 as key/value pairs count as one. */
207     buf->Add(pg->Allocator()->New<NumberLiteral>(instancePropertyCount));
208 
209     if (IsSendable()) {
210         std::string recordName = std::string(pg->Binder()->Program()->RecordName());
211         std::string fieldTypeIdxStr = recordName + "_" + std::to_string(fieldTypeBufIdx);
212         util::UString fieldTypeLitId(fieldTypeIdxStr, pg->Allocator());
213         buf->Add(pg->Allocator()->New<TaggedLiteral>(LiteralTag::LITERALARRAY, fieldTypeLitId.View()));
214     }
215 
216     if (IsImplementFromEts()) {
217         buf->Add(pg->Allocator()->New<TaggedLiteral>(LiteralTag::ETS_IMPLEMENTS, etsImplementsMessage_));
218     }
219 
220     return pg->AddLiteralBuffer(buf);
221 }
222 
CreateClassPrivateBuffer(compiler::PandaGen * pg) const223 int32_t ClassDefinition::CreateClassPrivateBuffer(compiler::PandaGen *pg) const
224 {
225     auto *buf = pg->NewLiteralBuffer();
226     compiler::LiteralBuffer staticBuf(pg->Allocator());
227     uint32_t instancePropertyCount = 0;
228 
229     for (const auto *prop : body_) {
230         if (!prop->IsMethodDefinition()) {
231             continue;
232         }
233 
234         const auto *methodDef = prop->AsMethodDefinition();
235         if (!methodDef->IsPrivate()) {
236             continue;
237         }
238 
239         compiler::LiteralBuffer *literalBuf = methodDef->IsStatic() ? &staticBuf : (instancePropertyCount++, buf);
240         const ir::FunctionExpression *func = methodDef->Value()->AsFunctionExpression();
241         const util::StringView &internalName = func->Function()->Scope()->InternalName();
242         Literal *value = nullptr;
243         Literal *methodAffiliate = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHODAFFILIATE,
244                                                                        func->Function()->FormalParamsLength());
245         switch (methodDef->Kind()) {
246             case MethodDefinitionKind::METHOD: {
247                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHOD, internalName);
248                 break;
249             }
250             case MethodDefinitionKind::GET: {
251                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::GETTER, internalName);
252                 break;
253             }
254             case MethodDefinitionKind::SET: {
255                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::SETTER, internalName);
256                 break;
257             }
258             default: {
259                 UNREACHABLE();
260             }
261         }
262         literalBuf->Add(value);
263         literalBuf->Add(methodAffiliate);
264     }
265 
266     buf->Insert(&staticBuf);
267     buf->Add(pg->Allocator()->New<NumberLiteral>(instancePropertyCount));
268 
269     return pg->AddLiteralBuffer(buf);
270 }
271 
CompileMissingProperties(compiler::PandaGen * pg,const util::BitSet & compiled,compiler::VReg classReg) const272 void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled,
273                                                compiler::VReg classReg) const
274 {
275     const auto &properties = body_;
276 
277     compiler::VReg protoReg = pg->AllocReg();
278 
279     pg->LoadObjByName(this, classReg, "prototype");
280     pg->StoreAccumulator(this, protoReg);
281 
282     for (size_t i = 0; i < properties.size(); i++) {
283         if (!properties[i]->IsMethodDefinition() || compiled.Test(i)) {
284             continue;
285         }
286 
287         const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
288         if (prop->IsOptional() && prop->Value()->Function()->IsOverload()) {
289             continue;
290         }
291 
292         if (prop->IsPrivate() || prop->IsAbstract()) {
293             continue;
294         }
295 
296         compiler::VReg dest = prop->IsStatic() ? classReg : protoReg;
297         compiler::RegScope rs(pg);
298 
299         switch (prop->Kind()) {
300             case ir::MethodDefinitionKind::METHOD: {
301                 compiler::Operand key = prop->Computed() ? prop->KeyReg() :
302                     pg->ToPropertyKey(prop->Key(), false);
303 
304                 pg->LoadAccumulator(this, dest);
305                 const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
306                 func->Compile(pg);
307 
308                 pg->StoreOwnProperty(prop->Value()->Parent(), dest, key, prop->Computed());
309                 break;
310             }
311             case ir::MethodDefinitionKind::GET:
312             case ir::MethodDefinitionKind::SET: {
313                 CompileGetterOrSetter(pg, dest, prop);
314                 break;
315             }
316             default: {
317                 UNREACHABLE();
318             }
319         }
320     }
321 
322     if (NeedInstanceInitializer()) {
323         InstanceInitialize(pg, protoReg);
324     }
325 }
326 
StaticInitialize(compiler::PandaGen * pg,compiler::VReg classReg) const327 void ClassDefinition::StaticInitialize(compiler::PandaGen *pg, compiler::VReg classReg) const
328 {
329     compiler::VReg callee = pg->AllocReg();
330     compiler::VReg thisReg = pg->AllocReg();
331 
332     const ir::FunctionExpression *func = staticInitializer_->Value();
333     func->Compile(pg);
334     pg->StoreAccumulator(this, callee);
335 
336     pg->MoveVreg(this, thisReg, classReg);
337     pg->CallThis(this, callee, 1);
338 
339     pg->LoadAccumulator(this, classReg);
340 }
341 
InstanceInitialize(compiler::PandaGen * pg,compiler::VReg protoReg) const342 void ClassDefinition::InstanceInitialize(compiler::PandaGen *pg, compiler::VReg protoReg) const
343 {
344     pg->StoreAccumulator(this, protoReg);
345     instanceInitializer_->Value()->Compile(pg);
346     pg->StoreLexicalVar(instanceInitializer_, 0, GetSlot(instanceInitializer_->Key()));
347 }
348 
CompileComputedKeys(compiler::PandaGen * pg) const349 void ClassDefinition::CompileComputedKeys(compiler::PandaGen *pg) const
350 {
351     for (const auto &stmt : body_) {
352         if (stmt->IsClassProperty()) {
353             const ir::ClassProperty *prop = stmt->AsClassProperty();
354 
355             // Do not process non-static public fields when not using define semantic.
356             if (!prop->IsStatic() && !pg->Binder()->Program()->UseDefineSemantic()) {
357                 continue;
358             }
359 
360             if (prop->IsComputed() && prop->NeedCompileKey()) {
361                 prop->Key()->Compile(pg);
362                 pg->ToComputedPropertyKey(prop->Key());
363                 pg->StoreLexicalVar(prop->Key(), 0, GetSlot(prop->Key()));
364             }
365         } else if (stmt->IsMethodDefinition()) {
366             auto *methodDef = stmt->AsMethodDefinition();
367             if (methodDef->Computed()) {
368                 compiler::VReg keyReg = pg->AllocReg();
369                 methodDef->SetKeyReg(keyReg);
370                 methodDef->Key()->Compile(pg);
371                 pg->ToComputedPropertyKey(methodDef->Key());
372                 pg->StoreAccumulator(methodDef->Key(), keyReg);
373             }
374         }
375     }
376 }
377 
Compile(compiler::PandaGen * pg) const378 void ClassDefinition::Compile(compiler::PandaGen *pg) const
379 {
380     if (declare_) {
381         return;
382     }
383 
384     if (isSendable_) {
385         CompileSendableClass(pg);
386         return;
387     }
388 
389     compiler::RegScope rs(pg);
390     compiler::VReg classReg = pg->AllocReg();
391 
392     compiler::LabelTarget target(pg);
393     compiler::VariableEnvScope classEnvScope(pg, scope_, target);
394     compiler::VReg baseReg = CompileHeritageClause(pg);
395     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
396     util::BitSet compiled(body_.size());
397 
398     if (hasComputedKey_) {
399         CompileComputedKeys(pg);
400     }
401 
402     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled);
403     pg->DefineClassWithBuffer(this, ctorId, bufIdx, baseReg);
404 
405     pg->StoreAccumulator(this, classReg);
406 
407     if (HasStaticPrivateMethod()) {
408         pg->StoreLexicalVar(this, 0, scope_->staticMethodValidation_);
409     }
410 
411     InitializeClassName(pg);
412 
413     CompileMissingProperties(pg, compiled, classReg);
414 
415     if (hasPrivateElement_) {
416         int32_t bufIdx = CreateClassPrivateBuffer(pg);
417         pg->CreatePrivateProperty(this, scope_->privateFieldCnt_, bufIdx);
418     }
419 
420     pg->LoadAccumulator(this, classReg);
421 
422     if (NeedStaticInitializer()) {
423         StaticInitialize(pg, classReg);
424     }
425 }
426 
Check(checker::Checker * checker) const427 checker::Type *ClassDefinition::Check(checker::Checker *checker) const
428 {
429     return checker->GlobalAnyType();
430 }
431 
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)432 void ClassDefinition::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder)
433 {
434     auto scopeCtx = binder::LexicalScope<binder::ClassScope>::Enter(binder, scope_);
435 
436     if (ident_) {
437         ident_ = std::get<ir::AstNode *>(cb(ident_))->AsIdentifier();
438     }
439 
440     if (typeParams_) {
441         typeParams_ = std::get<ir::AstNode *>(cb(typeParams_))->AsTSTypeParameterDeclaration();
442     }
443 
444     if (superClass_) {
445         superClass_ = std::get<ir::AstNode *>(cb(superClass_))->AsExpression();
446     }
447 
448     if (superTypeParams_) {
449         superTypeParams_ = std::get<ir::AstNode *>(cb(superTypeParams_))->AsTSTypeParameterInstantiation();
450     }
451 
452     for (auto iter = implements_.begin(); iter != implements_.end(); iter++) {
453         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSClassImplements();
454     }
455 
456     ctor_ = std::get<ir::AstNode *>(cb(ctor_))->AsMethodDefinition();
457 
458     for (auto iter = body_.begin(); iter != body_.end(); iter++) {
459         *iter = std::get<ir::AstNode *>(cb(*iter))->AsStatement();
460     }
461 
462     for (auto iter = indexSignatures_.begin(); iter != indexSignatures_.end(); iter++) {
463         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSIndexSignature();
464     }
465 }
466 
467 
BuildClassEnvironment(bool useDefineSemantic)468 void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic)
469 {
470     int instancePrivateMethodCnt = 0;
471     int staticPrivateMethodCnt = 0;
472     int privateFieldCnt = 0;
473     std::vector<const Statement *> privateProperties;
474     for (const auto *stmt : body_) {
475         if (stmt->IsMethodDefinition()) {
476             auto *methodDef = stmt->AsMethodDefinition();
477             if (methodDef->IsPrivate()) {
478                 privateProperties.push_back(stmt);
479                 methodDef->IsStatic() ? staticPrivateMethodCnt ++ : instancePrivateMethodCnt++;
480             } else if (methodDef->Computed()) {
481                 hasComputedKey_ = true;
482             }
483             continue;
484         }
485 
486         if (stmt->IsClassStaticBlock()) {
487             needStaticInitializer_ = true;
488             continue;
489         }
490 
491         ASSERT(stmt->IsClassProperty());
492         const auto *prop = stmt->AsClassProperty();
493         // Do not process non-static public fields when not using define semantic.
494         if (!prop->IsPrivate() && !prop->IsStatic() && !useDefineSemantic) {
495             continue;
496         }
497 
498         prop->IsStatic() ? needStaticInitializer_ = true : needInstanceInitializer_ = true;
499 
500         if (prop->IsComputed() && prop->NeedCompileKey()) {
501             hasComputedKey_ = true;
502             scope_->AddClassVariable(prop->Key());
503         } else if (prop->IsPrivate()) {
504             privateFieldCnt++;
505             privateProperties.push_back(stmt);
506         }
507     }
508 
509     if (!privateProperties.empty()) {
510         hasPrivateElement_ = true;
511         scope_->AddPrivateName(privateProperties, privateFieldCnt, instancePrivateMethodCnt, staticPrivateMethodCnt);
512     }
513 
514     if (instancePrivateMethodCnt > 0) {
515         needInstanceInitializer_ = true;
516     }
517 
518     if (NeedInstanceInitializer()) {
519         scope_->AddClassVariable(instanceInitializer_->Key());
520     }
521 }
522 
AddFieldType(FieldType & fieldType,const Expression * typeAnnotation,compiler::PandaGen * pg) const523 void ClassDefinition::AddFieldType(FieldType &fieldType, const Expression *typeAnnotation,
524     compiler::PandaGen *pg) const
525 {
526     switch (typeAnnotation->Type()) {
527         case AstNodeType::TS_NUMBER_KEYWORD: {
528             fieldType |= FieldType::NUMBER;
529             break;
530         }
531         case AstNodeType::TS_STRING_KEYWORD: {
532             fieldType |= FieldType::STRING;
533             break;
534         }
535         case AstNodeType::TS_BOOLEAN_KEYWORD: {
536             fieldType |= FieldType::BOOLEAN;
537             break;
538         }
539         case AstNodeType::TS_TYPE_REFERENCE: {
540             AddFieldTypeForTypeReference(typeAnnotation->AsTSTypeReference(), fieldType, pg);
541             break;
542         }
543         case AstNodeType::TS_BIGINT_KEYWORD: {
544             fieldType |= FieldType::BIGINT;
545             break;
546         }
547         case AstNodeType::TS_NULL_KEYWORD: {
548             fieldType |= FieldType::TS_NULL;
549             break;
550         }
551         case AstNodeType::TS_UNDEFINED_KEYWORD: {
552             fieldType |= FieldType::TS_UNDEFINED;
553             break;
554         }
555         default: {
556             UNREACHABLE();
557         }
558     }
559 }
560 
AddFieldTypeForTypeReference(const TSTypeReference * typeReference,FieldType & fieldType,compiler::PandaGen * pg) const561 void ClassDefinition::AddFieldTypeForTypeReference(const TSTypeReference *typeReference, FieldType &fieldType,
562     compiler::PandaGen *pg) const
563 {
564     auto typeName = typeReference->TypeName();
565     ASSERT(typeName != nullptr);
566     if (!typeName->IsIdentifier()) {
567         fieldType |= FieldType::GENERIC;
568         return;
569     }
570 
571     util::StringView propertyName = typeName->AsIdentifier()->Name();
572     binder::ScopeFindResult result = scope_->Find(propertyName);
573 
574     // identify import type
575     parser::SourceTextModuleRecord *moduleRecord = pg->Binder()->Program()->TypeModuleRecord();
576     const auto &regularImportEntries = moduleRecord->GetRegularImportEntries();
577     if (regularImportEntries.find(propertyName) != regularImportEntries.end()) {
578         fieldType |= FieldType::GENERIC;
579         return;
580     }
581 
582     if (IsTypeParam(propertyName) || (result.variable != nullptr && result.variable->IsModuleVariable())) {
583         fieldType |= FieldType::GENERIC;
584         return;
585     }
586 
587     // ts enum type
588     const ir::AstNode *declNode = GetDeclNodeFromIdentifier(typeName->AsIdentifier());
589     if (declNode != nullptr && declNode->IsTSEnumDeclaration()) {
590         fieldType |= FieldType::STRING | FieldType::NUMBER;
591         return;
592     }
593 
594     // sendable class and sendable fuction
595     fieldType |= FieldType::TS_TYPE_REF;
596 }
597 
GetDeclNodeFromIdentifier(const ir::Identifier * identifier) const598 const ir::AstNode *ClassDefinition::GetDeclNodeFromIdentifier(const ir::Identifier *identifier) const
599 {
600     if (identifier == nullptr) {
601         return nullptr;
602     }
603 
604     for (const auto &v : identifier->TSVariables()) {
605         if (v == nullptr || v->Declaration() == nullptr || v->Declaration()->Node() == nullptr) {
606             continue;
607         }
608 
609         auto res = v->Declaration()->Node();
610         return res;
611     }
612 
613     // In general, the declaration node of a type node could alaways be found in ts ast.
614     // The following branch, finding declaration node in js ast, is added for some unexpected corner cases.
615     if (identifier->Variable() && identifier->Variable()->Declaration() &&
616         identifier->Variable()->Declaration()->Node()) {
617         return identifier->Variable()->Declaration()->Node()->Original();
618     }
619 
620     return nullptr;
621 }
622 
IsTypeParam(const util::StringView & propertyName) const623 bool ClassDefinition::IsTypeParam(const util::StringView &propertyName) const
624 {
625     if (typeParams_ == nullptr) {
626         return false;
627     }
628 
629     for (auto param : typeParams_->Params()) {
630         util::StringView paramName = param->Name()->AsIdentifier()->Name();
631         if (paramName == propertyName) {
632             return true;
633         }
634     }
635     return false;
636 }
637 
CreateFieldTypeBuffer(compiler::PandaGen * pg) const638 int32_t ClassDefinition::CreateFieldTypeBuffer(compiler::PandaGen *pg) const
639 {
640     ASSERT(IsSendable());
641     auto *instanceBuf = pg->NewLiteralBuffer();
642     compiler::LiteralBuffer staticBuf(pg->Allocator());
643     uint32_t instanceFieldCnt {0};
644 
645     for (auto *prop : body_) {
646         if (!prop->IsClassProperty()) {
647             continue;
648         }
649 
650         auto *classProp = prop->AsClassProperty();
651         auto *buf = classProp->IsStatic() ? &staticBuf : (++instanceFieldCnt, instanceBuf);
652         auto name = util::Helpers::LiteralToPropName(pg->Allocator(), classProp->Key());
653         buf->Add(pg->Allocator()->New<StringLiteral>(name));
654 
655         FieldType fieldType = FieldType::NONE;
656         const auto *typeAnnotation = classProp->TypeAnnotation();
657         if (typeAnnotation == nullptr) {
658             util::Helpers::ThrowError(ErrorType::GENERIC, pg->Binder()->Program(), prop->Start(),
659                 "Field in sendable class must have type annotation");
660         }
661         if (typeAnnotation->IsTSUnionType()) {
662             for (const auto *type : typeAnnotation->AsTSUnionType()->Types()) {
663                 AddFieldType(fieldType, type, pg);
664             }
665         } else {
666             AddFieldType(fieldType, typeAnnotation, pg);
667         }
668         buf->Add(pg->Allocator()->New<NumberLiteral>(static_cast<uint8_t>(fieldType)));
669     }
670 
671     instanceBuf->Insert(&staticBuf);
672     instanceBuf->Add(pg->Allocator()->New<NumberLiteral>(instanceFieldCnt));
673     return pg->AddLiteralBuffer(instanceBuf);
674 }
675 
CompileSendableClass(compiler::PandaGen * pg) const676 void ClassDefinition::CompileSendableClass(compiler::PandaGen *pg) const
677 {
678     compiler::RegScope rs(pg);
679     compiler::VReg classReg = pg->AllocReg();
680 
681     compiler::LocalRegScope lrs(pg, scope_);
682 
683     compiler::VReg baseReg = CompileHeritageClause(pg);
684     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
685     util::BitSet compiled(body_.size());
686 
687     int32_t fieldTypeBufIdx = CreateFieldTypeBuffer(pg);
688     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled, fieldTypeBufIdx);
689     pg->DefineSendableClass(this, ctorId, bufIdx, baseReg);
690 
691     pg->StoreAccumulator(this, classReg);
692 
693     InitializeClassName(pg);
694 
695     if (NeedStaticInitializer()) {
696         StaticInitialize(pg, classReg);
697     }
698 }
699 
CompileGetterOrSetter(compiler::PandaGen * pg,compiler::VReg dest,const MethodDefinition * prop) const700 void ClassDefinition::CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest,
701     const MethodDefinition *prop) const
702 {
703     compiler::VReg keyReg = prop->Computed() ? prop->KeyReg() : pg->LoadPropertyKey(prop->Key(), false);
704 
705     compiler::VReg undef = pg->AllocReg();
706     pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
707     pg->StoreAccumulator(this, undef);
708 
709     compiler::VReg getter = undef;
710     compiler::VReg setter = undef;
711 
712     pg->LoadAccumulator(this, dest);
713 
714     compiler::VReg accessor = pg->AllocReg();
715     prop->Value()->Compile(pg);
716     pg->StoreAccumulator(prop->Value(), accessor);
717 
718     if (prop->Kind() == ir::MethodDefinitionKind::GET) {
719         getter = accessor;
720     } else {
721         setter = accessor;
722     }
723 
724     pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed());
725 }
726 
CalculateClassExpectedPropertyCount()727 void ClassDefinition::CalculateClassExpectedPropertyCount()
728 {
729     // Counting more or less than the actual number does not affect execution.
730     std::unordered_set<util::StringView> propertyNames;
731     auto addPropertyName = [this, &propertyNames](const util::StringView &name) {
732         if (propertyNames.find(name) == propertyNames.end()) {
733             propertyNames.insert(name);
734             IncreasePropertyCount();
735         }
736     };
737 
738     for (const auto &stmt : Body()) {
739         if (stmt->IsClassProperty() && !stmt->AsClassProperty()->IsStatic()) {
740             ProcessClassProperty(stmt->AsClassProperty(), addPropertyName);
741         }
742     }
743 
744     auto *ctorFunc = ctor_->Function();
745     if (ctorFunc && ctorFunc->Body()) {
746         ProcessConstructorBody(ctorFunc->Body()->AsBlockStatement(), addPropertyName);
747     }
748 }
749 
ProcessClassProperty(const ClassProperty * prop,const std::function<void (const util::StringView &)> & addPropertyName)750 void ClassDefinition::ProcessClassProperty(const ClassProperty *prop,
751                                            const std::function<void(const util::StringView&)>& addPropertyName)
752 {
753     /**
754      * Private fields must be explicitly declared in the class and cannot be directly initialized in the constructor,
755      * so they only need to be accounted for in the class properties.
756      */
757     if (prop->IsPrivate()) {
758         IncreasePropertyCount();
759     } else {
760         ProcessPropertyKey(prop->Key(), addPropertyName);
761     }
762 }
763 
ProcessConstructorBody(const BlockStatement * body,const std::function<void (const util::StringView &)> & addPropertyName)764 void ClassDefinition::ProcessConstructorBody(const BlockStatement *body,
765                                              const std::function<void(const util::StringView&)>& addPropertyName)
766 {
767     for (const auto &stmt : body->Statements()) {
768         if (!stmt->IsExpressionStatement()) {
769             continue;
770         }
771 
772         auto *expr = stmt->AsExpressionStatement()->GetExpression();
773         if (!expr->IsAssignmentExpression()) {
774             continue;
775         }
776 
777         auto *assignExpr = expr->AsAssignmentExpression();
778         if (!assignExpr->Left()->IsMemberExpression()) {
779             continue;
780         }
781 
782         auto *memberExpr = assignExpr->Left()->AsMemberExpression();
783         if (memberExpr->Object()->IsThisExpression()) {
784             ProcessPropertyKey(memberExpr->Property(), addPropertyName);
785         }
786     }
787 }
788 
ProcessPropertyKey(const Expression * key,const std::function<void (const util::StringView &)> & addPropertyName)789 void ClassDefinition::ProcessPropertyKey(const Expression* key,
790                                          const std::function<void(const util::StringView&)>& addPropertyName)
791 {
792     if (key->IsIdentifier()) {
793         addPropertyName(key->AsIdentifier()->Name());
794     } else if (key->IsStringLiteral()) {
795         addPropertyName(key->AsStringLiteral()->Str());
796     } else if (key->IsNumberLiteral()) {
797         addPropertyName(key->AsNumberLiteral()->Str());
798     } else {
799         /**
800          * Currently, other situations of property keys are not counted.
801          * 1. Private properties (PrivateIdentifier)
802          * 2. Template literals (TemplateLiteral)
803          * 3. Binary expressions (BinaryExpression)
804          * 4. Other expressions that can be evaluated to a property key
805          */
806     }
807 }
808 }  // namespace panda::es2panda::ir
809