• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 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     return pg->AddLiteralBuffer(buf);
216 }
217 
CreateClassPrivateBuffer(compiler::PandaGen * pg) const218 int32_t ClassDefinition::CreateClassPrivateBuffer(compiler::PandaGen *pg) const
219 {
220     auto *buf = pg->NewLiteralBuffer();
221     compiler::LiteralBuffer staticBuf(pg->Allocator());
222     uint32_t instancePropertyCount = 0;
223 
224     for (const auto *prop : body_) {
225         if (!prop->IsMethodDefinition()) {
226             continue;
227         }
228 
229         const auto *methodDef = prop->AsMethodDefinition();
230         if (!methodDef->IsPrivate()) {
231             continue;
232         }
233 
234         compiler::LiteralBuffer *literalBuf = methodDef->IsStatic() ? &staticBuf : (instancePropertyCount++, buf);
235         const ir::FunctionExpression *func = methodDef->Value()->AsFunctionExpression();
236         const util::StringView &internalName = func->Function()->Scope()->InternalName();
237         Literal *value = nullptr;
238         Literal *methodAffiliate = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHODAFFILIATE,
239                                                                        func->Function()->FormalParamsLength());
240         switch (methodDef->Kind()) {
241             case MethodDefinitionKind::METHOD: {
242                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHOD, internalName);
243                 break;
244             }
245             case MethodDefinitionKind::GET: {
246                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::GETTER, internalName);
247                 break;
248             }
249             case MethodDefinitionKind::SET: {
250                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::SETTER, internalName);
251                 break;
252             }
253             default: {
254                 UNREACHABLE();
255             }
256         }
257         literalBuf->Add(value);
258         literalBuf->Add(methodAffiliate);
259     }
260 
261     buf->Insert(&staticBuf);
262     buf->Add(pg->Allocator()->New<NumberLiteral>(instancePropertyCount));
263 
264     return pg->AddLiteralBuffer(buf);
265 }
266 
CompileMissingProperties(compiler::PandaGen * pg,const util::BitSet & compiled,compiler::VReg classReg) const267 void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled,
268                                                compiler::VReg classReg) const
269 {
270     const auto &properties = body_;
271 
272     compiler::VReg protoReg = pg->AllocReg();
273 
274     pg->LoadObjByName(this, classReg, "prototype");
275     pg->StoreAccumulator(this, protoReg);
276 
277     for (size_t i = 0; i < properties.size(); i++) {
278         if (!properties[i]->IsMethodDefinition() || compiled.Test(i)) {
279             continue;
280         }
281 
282         const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
283         if (prop->IsOptional() && prop->Value()->Function()->IsOverload()) {
284             continue;
285         }
286 
287         if (prop->IsPrivate() || prop->IsAbstract()) {
288             continue;
289         }
290 
291         compiler::VReg dest = prop->IsStatic() ? classReg : protoReg;
292         compiler::RegScope rs(pg);
293 
294         switch (prop->Kind()) {
295             case ir::MethodDefinitionKind::METHOD: {
296                 compiler::Operand key = prop->Computed() ? prop->KeyReg() :
297                     pg->ToPropertyKey(prop->Key(), false);
298 
299                 pg->LoadAccumulator(this, dest);
300                 const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
301                 func->Compile(pg);
302 
303                 pg->StoreOwnProperty(prop->Value()->Parent(), dest, key, prop->Computed());
304                 break;
305             }
306             case ir::MethodDefinitionKind::GET:
307             case ir::MethodDefinitionKind::SET: {
308                 CompileGetterOrSetter(pg, dest, prop);
309                 break;
310             }
311             default: {
312                 UNREACHABLE();
313             }
314         }
315     }
316 
317     if (NeedInstanceInitializer()) {
318         InstanceInitialize(pg, protoReg);
319     }
320 }
321 
StaticInitialize(compiler::PandaGen * pg,compiler::VReg classReg) const322 void ClassDefinition::StaticInitialize(compiler::PandaGen *pg, compiler::VReg classReg) const
323 {
324     compiler::VReg callee = pg->AllocReg();
325     compiler::VReg thisReg = pg->AllocReg();
326 
327     const ir::FunctionExpression *func = staticInitializer_->Value();
328     func->Compile(pg);
329     pg->StoreAccumulator(this, callee);
330 
331     pg->MoveVreg(this, thisReg, classReg);
332     pg->CallThis(this, callee, 1);
333 
334     pg->LoadAccumulator(this, classReg);
335 }
336 
InstanceInitialize(compiler::PandaGen * pg,compiler::VReg protoReg) const337 void ClassDefinition::InstanceInitialize(compiler::PandaGen *pg, compiler::VReg protoReg) const
338 {
339     pg->StoreAccumulator(this, protoReg);
340     instanceInitializer_->Value()->Compile(pg);
341     pg->StoreLexicalVar(instanceInitializer_, 0, GetSlot(instanceInitializer_->Key()));
342 }
343 
CompileComputedKeys(compiler::PandaGen * pg) const344 void ClassDefinition::CompileComputedKeys(compiler::PandaGen *pg) const
345 {
346     for (const auto &stmt : body_) {
347         if (stmt->IsClassProperty()) {
348             const ir::ClassProperty *prop = stmt->AsClassProperty();
349 
350             // Do not process non-static public fields when not using define semantic.
351             if (!prop->IsStatic() && !pg->Binder()->Program()->UseDefineSemantic()) {
352                 continue;
353             }
354 
355             if (prop->IsComputed() && prop->NeedCompileKey()) {
356                 prop->Key()->Compile(pg);
357                 pg->ToComputedPropertyKey(prop->Key());
358                 pg->StoreLexicalVar(prop->Key(), 0, GetSlot(prop->Key()));
359             }
360         } else if (stmt->IsMethodDefinition()) {
361             auto *methodDef = stmt->AsMethodDefinition();
362             if (methodDef->Computed()) {
363                 compiler::VReg keyReg = pg->AllocReg();
364                 methodDef->SetKeyReg(keyReg);
365                 methodDef->Key()->Compile(pg);
366                 pg->ToComputedPropertyKey(methodDef->Key());
367                 pg->StoreAccumulator(methodDef->Key(), keyReg);
368             }
369         }
370     }
371 }
372 
Compile(compiler::PandaGen * pg) const373 void ClassDefinition::Compile(compiler::PandaGen *pg) const
374 {
375     if (declare_) {
376         return;
377     }
378 
379     if (isSendable_) {
380         CompileSendableClass(pg);
381         return;
382     }
383 
384     compiler::RegScope rs(pg);
385     compiler::VReg classReg = pg->AllocReg();
386 
387     compiler::LabelTarget target(pg);
388     compiler::VariableEnvScope classEnvScope(pg, scope_, target);
389     compiler::VReg baseReg = CompileHeritageClause(pg);
390     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
391     util::BitSet compiled(body_.size());
392 
393     if (hasComputedKey_) {
394         CompileComputedKeys(pg);
395     }
396 
397     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled);
398     pg->DefineClassWithBuffer(this, ctorId, bufIdx, baseReg);
399 
400     pg->StoreAccumulator(this, classReg);
401 
402     if (HasStaticPrivateMethod()) {
403         pg->StoreLexicalVar(this, 0, scope_->staticMethodValidation_);
404     }
405 
406     InitializeClassName(pg);
407 
408     CompileMissingProperties(pg, compiled, classReg);
409 
410     if (hasPrivateElement_) {
411         int32_t bufIdx = CreateClassPrivateBuffer(pg);
412         pg->CreatePrivateProperty(this, scope_->privateFieldCnt_, bufIdx);
413     }
414 
415     pg->LoadAccumulator(this, classReg);
416 
417     if (NeedStaticInitializer()) {
418         StaticInitialize(pg, classReg);
419     }
420 }
421 
Check(checker::Checker * checker) const422 checker::Type *ClassDefinition::Check(checker::Checker *checker) const
423 {
424     return checker->GlobalAnyType();
425 }
426 
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)427 void ClassDefinition::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder)
428 {
429     auto scopeCtx = binder::LexicalScope<binder::ClassScope>::Enter(binder, scope_);
430 
431     if (ident_) {
432         ident_ = std::get<ir::AstNode *>(cb(ident_))->AsIdentifier();
433     }
434 
435     if (typeParams_) {
436         typeParams_ = std::get<ir::AstNode *>(cb(typeParams_))->AsTSTypeParameterDeclaration();
437     }
438 
439     if (superClass_) {
440         superClass_ = std::get<ir::AstNode *>(cb(superClass_))->AsExpression();
441     }
442 
443     if (superTypeParams_) {
444         superTypeParams_ = std::get<ir::AstNode *>(cb(superTypeParams_))->AsTSTypeParameterInstantiation();
445     }
446 
447     for (auto iter = implements_.begin(); iter != implements_.end(); iter++) {
448         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSClassImplements();
449     }
450 
451     ctor_ = std::get<ir::AstNode *>(cb(ctor_))->AsMethodDefinition();
452 
453     for (auto iter = body_.begin(); iter != body_.end(); iter++) {
454         *iter = std::get<ir::AstNode *>(cb(*iter))->AsStatement();
455     }
456 
457     for (auto iter = indexSignatures_.begin(); iter != indexSignatures_.end(); iter++) {
458         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSIndexSignature();
459     }
460 }
461 
462 
BuildClassEnvironment(bool useDefineSemantic)463 void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic)
464 {
465     int instancePrivateMethodCnt = 0;
466     int staticPrivateMethodCnt = 0;
467     int privateFieldCnt = 0;
468     std::vector<const Statement *> privateProperties;
469     for (const auto *stmt : body_) {
470         if (stmt->IsMethodDefinition()) {
471             auto *methodDef = stmt->AsMethodDefinition();
472             if (methodDef->IsPrivate()) {
473                 privateProperties.push_back(stmt);
474                 methodDef->IsStatic() ? staticPrivateMethodCnt ++ : instancePrivateMethodCnt++;
475             } else if (methodDef->Computed()) {
476                 hasComputedKey_ = true;
477             }
478             continue;
479         }
480 
481         if (stmt->IsClassStaticBlock()) {
482             needStaticInitializer_ = true;
483             continue;
484         }
485 
486         ASSERT(stmt->IsClassProperty());
487         const auto *prop = stmt->AsClassProperty();
488         // Do not process non-static public fields when not using define semantic.
489         if (!prop->IsPrivate() && !prop->IsStatic() && !useDefineSemantic) {
490             continue;
491         }
492 
493         prop->IsStatic() ? needStaticInitializer_ = true : needInstanceInitializer_ = true;
494 
495         if (prop->IsComputed() && prop->NeedCompileKey()) {
496             hasComputedKey_ = true;
497             scope_->AddClassVariable(prop->Key());
498         } else if (prop->IsPrivate()) {
499             privateFieldCnt++;
500             privateProperties.push_back(stmt);
501         }
502     }
503 
504     if (!privateProperties.empty()) {
505         hasPrivateElement_ = true;
506         scope_->AddPrivateName(privateProperties, privateFieldCnt, instancePrivateMethodCnt, staticPrivateMethodCnt);
507     }
508 
509     if (instancePrivateMethodCnt > 0) {
510         needInstanceInitializer_ = true;
511     }
512 
513     if (NeedInstanceInitializer()) {
514         scope_->AddClassVariable(instanceInitializer_->Key());
515     }
516 }
517 
AddFieldType(FieldType & fieldType,const Expression * typeAnnotation,compiler::PandaGen * pg) const518 void ClassDefinition::AddFieldType(FieldType &fieldType, const Expression *typeAnnotation,
519     compiler::PandaGen *pg) const
520 {
521     switch (typeAnnotation->Type()) {
522         case AstNodeType::TS_NUMBER_KEYWORD: {
523             fieldType |= FieldType::NUMBER;
524             break;
525         }
526         case AstNodeType::TS_STRING_KEYWORD: {
527             fieldType |= FieldType::STRING;
528             break;
529         }
530         case AstNodeType::TS_BOOLEAN_KEYWORD: {
531             fieldType |= FieldType::BOOLEAN;
532             break;
533         }
534         case AstNodeType::TS_TYPE_REFERENCE: {
535             AddFieldTypeForTypeReference(typeAnnotation->AsTSTypeReference(), fieldType, pg);
536             break;
537         }
538         case AstNodeType::TS_BIGINT_KEYWORD: {
539             fieldType |= FieldType::BIGINT;
540             break;
541         }
542         case AstNodeType::TS_NULL_KEYWORD: {
543             fieldType |= FieldType::TS_NULL;
544             break;
545         }
546         case AstNodeType::TS_UNDEFINED_KEYWORD: {
547             fieldType |= FieldType::TS_UNDEFINED;
548             break;
549         }
550         default: {
551             UNREACHABLE();
552         }
553     }
554 }
555 
AddFieldTypeForTypeReference(const TSTypeReference * typeReference,FieldType & fieldType,compiler::PandaGen * pg) const556 void ClassDefinition::AddFieldTypeForTypeReference(const TSTypeReference *typeReference, FieldType &fieldType,
557     compiler::PandaGen *pg) const
558 {
559     auto typeName = typeReference->TypeName();
560     ASSERT(typeName != nullptr);
561     if (!typeName->IsIdentifier()) {
562         fieldType |= FieldType::GENERIC;
563         return;
564     }
565 
566     util::StringView propertyName = typeName->AsIdentifier()->Name();
567     binder::ScopeFindResult result = scope_->Find(propertyName);
568 
569     // identify import type
570     parser::SourceTextModuleRecord *moduleRecord = pg->Binder()->Program()->TypeModuleRecord();
571     const auto &regularImportEntries = moduleRecord->GetRegularImportEntries();
572     if (regularImportEntries.find(propertyName) != regularImportEntries.end()) {
573         fieldType |= FieldType::GENERIC;
574         return;
575     }
576 
577     if (IsTypeParam(propertyName) || (result.variable != nullptr && result.variable->IsModuleVariable())) {
578         fieldType |= FieldType::GENERIC;
579         return;
580     }
581 
582     // ts enum type
583     const ir::AstNode *declNode = GetDeclNodeFromIdentifier(typeName->AsIdentifier());
584     if (declNode != nullptr && declNode->IsTSEnumDeclaration()) {
585         fieldType |= FieldType::STRING | FieldType::NUMBER;
586         return;
587     }
588 
589     // sendable class and sendable fuction
590     fieldType |= FieldType::TS_TYPE_REF;
591 }
592 
GetDeclNodeFromIdentifier(const ir::Identifier * identifier) const593 const ir::AstNode *ClassDefinition::GetDeclNodeFromIdentifier(const ir::Identifier *identifier) const
594 {
595     if (identifier == nullptr) {
596         return nullptr;
597     }
598 
599     for (const auto &v : identifier->TSVariables()) {
600         if (v == nullptr || v->Declaration() == nullptr || v->Declaration()->Node() == nullptr) {
601             continue;
602         }
603 
604         auto res = v->Declaration()->Node();
605         return res;
606     }
607 
608     // In general, the declaration node of a type node could alaways be found in ts ast.
609     // The following branch, finding declaration node in js ast, is added for some unexpected corner cases.
610     if (identifier->Variable() && identifier->Variable()->Declaration() &&
611         identifier->Variable()->Declaration()->Node()) {
612         return identifier->Variable()->Declaration()->Node()->Original();
613     }
614 
615     return nullptr;
616 }
617 
IsTypeParam(const util::StringView & propertyName) const618 bool ClassDefinition::IsTypeParam(const util::StringView &propertyName) const
619 {
620     if (typeParams_ == nullptr) {
621         return false;
622     }
623 
624     for (auto param : typeParams_->Params()) {
625         util::StringView paramName = param->Name()->AsIdentifier()->Name();
626         if (paramName == propertyName) {
627             return true;
628         }
629     }
630     return false;
631 }
632 
CreateFieldTypeBuffer(compiler::PandaGen * pg) const633 int32_t ClassDefinition::CreateFieldTypeBuffer(compiler::PandaGen *pg) const
634 {
635     ASSERT(IsSendable());
636     auto *instanceBuf = pg->NewLiteralBuffer();
637     compiler::LiteralBuffer staticBuf(pg->Allocator());
638     uint32_t instanceFieldCnt {0};
639 
640     for (auto *prop : body_) {
641         if (!prop->IsClassProperty()) {
642             continue;
643         }
644 
645         auto *classProp = prop->AsClassProperty();
646         auto *buf = classProp->IsStatic() ? &staticBuf : (++instanceFieldCnt, instanceBuf);
647         auto name = util::Helpers::LiteralToPropName(pg->Allocator(), classProp->Key());
648         buf->Add(pg->Allocator()->New<StringLiteral>(name));
649 
650         FieldType fieldType = FieldType::NONE;
651         const auto *typeAnnotation = classProp->TypeAnnotation();
652         if (typeAnnotation == nullptr) {
653             util::Helpers::ThrowError(ErrorType::GENERIC, pg->Binder()->Program(), prop->Start(),
654                 "Field in sendable class must have type annotation");
655         }
656         if (typeAnnotation->IsTSUnionType()) {
657             for (const auto *type : typeAnnotation->AsTSUnionType()->Types()) {
658                 AddFieldType(fieldType, type, pg);
659             }
660         } else {
661             AddFieldType(fieldType, typeAnnotation, pg);
662         }
663         buf->Add(pg->Allocator()->New<NumberLiteral>(static_cast<uint8_t>(fieldType)));
664     }
665 
666     instanceBuf->Insert(&staticBuf);
667     instanceBuf->Add(pg->Allocator()->New<NumberLiteral>(instanceFieldCnt));
668     return pg->AddLiteralBuffer(instanceBuf);
669 }
670 
CompileSendableClass(compiler::PandaGen * pg) const671 void ClassDefinition::CompileSendableClass(compiler::PandaGen *pg) const
672 {
673     compiler::RegScope rs(pg);
674     compiler::VReg classReg = pg->AllocReg();
675 
676     compiler::LocalRegScope lrs(pg, scope_);
677 
678     compiler::VReg baseReg = CompileHeritageClause(pg);
679     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
680     util::BitSet compiled(body_.size());
681 
682     int32_t fieldTypeBufIdx = CreateFieldTypeBuffer(pg);
683     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled, fieldTypeBufIdx);
684     pg->DefineSendableClass(this, ctorId, bufIdx, baseReg);
685 
686     pg->StoreAccumulator(this, classReg);
687 
688     InitializeClassName(pg);
689 
690     if (NeedStaticInitializer()) {
691         StaticInitialize(pg, classReg);
692     }
693 }
694 
CompileGetterOrSetter(compiler::PandaGen * pg,compiler::VReg dest,const MethodDefinition * prop) const695 void ClassDefinition::CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest,
696     const MethodDefinition *prop) const
697 {
698     compiler::VReg keyReg = prop->Computed() ? prop->KeyReg() : pg->LoadPropertyKey(prop->Key(), false);
699 
700     compiler::VReg undef = pg->AllocReg();
701     pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
702     pg->StoreAccumulator(this, undef);
703 
704     compiler::VReg getter = undef;
705     compiler::VReg setter = undef;
706 
707     pg->LoadAccumulator(this, dest);
708 
709     compiler::VReg accessor = pg->AllocReg();
710     prop->Value()->Compile(pg);
711     pg->StoreAccumulator(prop->Value(), accessor);
712 
713     if (prop->Kind() == ir::MethodDefinitionKind::GET) {
714         getter = accessor;
715     } else {
716         setter = accessor;
717     }
718 
719     pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed());
720 }
721 
CalculateClassExpectedPropertyCount()722 void ClassDefinition::CalculateClassExpectedPropertyCount()
723 {
724     // Counting more or less than the actual number does not affect execution.
725     std::unordered_set<util::StringView> propertyNames;
726     auto addPropertyName = [this, &propertyNames](const util::StringView &name) {
727         if (propertyNames.find(name) == propertyNames.end()) {
728             propertyNames.insert(name);
729             IncreasePropertyCount();
730         }
731     };
732 
733     for (const auto &stmt : Body()) {
734         if (stmt->IsClassProperty() && !stmt->AsClassProperty()->IsStatic()) {
735             ProcessClassProperty(stmt->AsClassProperty(), addPropertyName);
736         }
737     }
738 
739     auto *ctorFunc = ctor_->Function();
740     if (ctorFunc && ctorFunc->Body()) {
741         ProcessConstructorBody(ctorFunc->Body()->AsBlockStatement(), addPropertyName);
742     }
743 }
744 
ProcessClassProperty(const ClassProperty * prop,const std::function<void (const util::StringView &)> & addPropertyName)745 void ClassDefinition::ProcessClassProperty(const ClassProperty *prop,
746                                            const std::function<void(const util::StringView&)>& addPropertyName)
747 {
748     /**
749      * Private fields must be explicitly declared in the class and cannot be directly initialized in the constructor,
750      * so they only need to be accounted for in the class properties.
751      */
752     if (prop->IsPrivate()) {
753         IncreasePropertyCount();
754     } else {
755         ProcessPropertyKey(prop->Key(), addPropertyName);
756     }
757 }
758 
ProcessConstructorBody(const BlockStatement * body,const std::function<void (const util::StringView &)> & addPropertyName)759 void ClassDefinition::ProcessConstructorBody(const BlockStatement *body,
760                                              const std::function<void(const util::StringView&)>& addPropertyName)
761 {
762     for (const auto &stmt : body->Statements()) {
763         if (!stmt->IsExpressionStatement()) {
764             continue;
765         }
766 
767         auto *expr = stmt->AsExpressionStatement()->GetExpression();
768         if (!expr->IsAssignmentExpression()) {
769             continue;
770         }
771 
772         auto *assignExpr = expr->AsAssignmentExpression();
773         if (!assignExpr->Left()->IsMemberExpression()) {
774             continue;
775         }
776 
777         auto *memberExpr = assignExpr->Left()->AsMemberExpression();
778         if (memberExpr->Object()->IsThisExpression()) {
779             ProcessPropertyKey(memberExpr->Property(), addPropertyName);
780         }
781     }
782 }
783 
ProcessPropertyKey(const Expression * key,const std::function<void (const util::StringView &)> & addPropertyName)784 void ClassDefinition::ProcessPropertyKey(const Expression* key,
785                                          const std::function<void(const util::StringView&)>& addPropertyName)
786 {
787     if (key->IsIdentifier()) {
788         addPropertyName(key->AsIdentifier()->Name());
789     } else if (key->IsStringLiteral()) {
790         addPropertyName(key->AsStringLiteral()->Str());
791     } else if (key->IsNumberLiteral()) {
792         addPropertyName(key->AsNumberLiteral()->Str());
793     } else {
794         /**
795          * Currently, other situations of property keys are not counted.
796          * 1. Private properties (PrivateIdentifier)
797          * 2. Template literals (TemplateLiteral)
798          * 3. Binary expressions (BinaryExpression)
799          * 4. Other expressions that can be evaluated to a property key
800          */
801     }
802 }
803 }  // namespace panda::es2panda::ir
804