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 "binder/binder.h"
19 #include "binder/scope.h"
20 #include "compiler/base/literals.h"
21 #include "compiler/base/lreference.h"
22 #include "compiler/core/pandagen.h"
23 #include "typescript/checker.h"
24 #include "ir/astDump.h"
25 #include "ir/base/classProperty.h"
26 #include "ir/base/methodDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/expression.h"
29 #include "ir/expressions/functionExpression.h"
30 #include "ir/expressions/identifier.h"
31 #include "ir/expressions/literals/nullLiteral.h"
32 #include "ir/expressions/literals/numberLiteral.h"
33 #include "ir/expressions/literals/stringLiteral.h"
34 #include "ir/expressions/literals/taggedLiteral.h"
35 #include "ir/ts/tsClassImplements.h"
36 #include "ir/ts/tsIndexSignature.h"
37 #include "ir/ts/tsTypeParameter.h"
38 #include "ir/ts/tsTypeParameterDeclaration.h"
39 #include "ir/ts/tsTypeParameterInstantiation.h"
40 #include "ir/ts/tsUnionType.h"
41 #include "util/helpers.h"
42 
43 namespace panda::es2panda::ir {
44 
Ctor() const45 const FunctionExpression *ClassDefinition::Ctor() const
46 {
47     ASSERT(ctor_ != nullptr);
48     return ctor_->Value();
49 }
50 
GetName() const51 util::StringView ClassDefinition::GetName() const
52 {
53     if (ident_) {
54         return ident_->Name();
55     }
56 
57     if (exportDefault_) {
58         return parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME;
59     }
60 
61     return "";
62 }
63 
Iterate(const NodeTraverser &cb) const64 void ClassDefinition::Iterate(const NodeTraverser &cb) const
65 {
66     if (ident_) {
67         cb(ident_);
68     }
69 
70     if (typeParams_) {
71         cb(typeParams_);
72     }
73 
74     if (superClass_) {
75         cb(superClass_);
76     }
77 
78     if (superTypeParams_) {
79         cb(superTypeParams_);
80     }
81 
82     for (auto *it : implements_) {
83         cb(it);
84     }
85 
86     cb(ctor_);
87 
88     for (auto *it : body_) {
89         cb(it);
90     }
91 
92     for (auto *it : indexSignatures_) {
93         cb(it);
94     }
95 }
96 
Dump(ir::AstDumper *dumper) const97 void ClassDefinition::Dump(ir::AstDumper *dumper) const
98 {
99     dumper->Add({{"id", AstDumper::Nullable(ident_)},
100                  {"typeParameters", AstDumper::Optional(typeParams_)},
101                  {"superClass", AstDumper::Nullable(superClass_)},
102                  {"superTypeParameters", AstDumper::Optional(superTypeParams_)},
103                  {"implements", implements_},
104                  {"constructor", ctor_},
105                  {"body", body_},
106                  {"indexSignatures", indexSignatures_}});
107 }
108 
CompileHeritageClause(compiler::PandaGen *pg) const109 compiler::VReg ClassDefinition::CompileHeritageClause(compiler::PandaGen *pg) const
110 {
111     compiler::VReg baseReg = pg->AllocReg();
112 
113     if (superClass_) {
114         superClass_->Compile(pg);
115     } else {
116         pg->LoadConst(this, compiler::Constant::JS_HOLE);
117     }
118 
119     pg->StoreAccumulator(this, baseReg);
120     return baseReg;
121 }
122 
InitializeClassName(compiler::PandaGen *pg) const123 void ClassDefinition::InitializeClassName(compiler::PandaGen *pg) const
124 {
125     if (!ident_) {
126         return;
127     }
128 
129     compiler::LReference lref = compiler::LReference::CreateLRef(pg, ident_, true);
130     lref.SetValue();
131 }
132 
133 // NOLINTNEXTLINE(google-runtime-references)
CreateClassPublicBuffer(compiler::PandaGen *pg, util::BitSet &compiled, int32_t fieldTypeBufIdx) const134 int32_t ClassDefinition::CreateClassPublicBuffer(compiler::PandaGen *pg, util::BitSet &compiled,
135     int32_t fieldTypeBufIdx) const
136 {
137     auto *buf = pg->NewLiteralBuffer();
138     compiler::LiteralBuffer staticBuf(pg->Allocator());
139     uint32_t instancePropertyCount = 0;
140     std::unordered_map<util::StringView, size_t> propNameMap;
141     std::unordered_map<util::StringView, size_t> staticPropNameMap;
142 
143     const auto &properties = body_;
144 
145     for (size_t i = 0; i < properties.size(); i++) {
146         if (!properties[i]->IsMethodDefinition()) {
147             continue;
148         }
149         const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
150         /* If it's sendable, put the getters/setters into literal buffer.
151          * If not, break at getters/setters to be compatible with api10. */
152         if (prop->IsPrivate()) {
153             continue;
154         }
155 
156         if (prop->Computed()) {
157             break;
158         }
159 
160         if (prop->IsAccessor() && !isSendable_) {
161             break;
162         }
163 
164         if (prop->IsAbstract()) {
165             compiled.Set(i);
166             continue;
167         }
168 
169         if (prop->Value()->Function()->IsOverload()) {
170             compiled.Set(i);
171             continue;
172         }
173 
174         util::StringView name = util::Helpers::LiteralToPropName(pg->Allocator(), prop->Key());
175         compiler::LiteralBuffer *literalBuf = prop->IsStatic() ? &staticBuf : buf;
176         auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap;
177 
178         size_t bufferPos = literalBuf->Literals().size();
179         auto res = nameMap.insert({name, bufferPos});
180         if (res.second || isSendable_) {
181             if (!prop->IsStatic()) {
182                 instancePropertyCount++;
183             }
184 
185             literalBuf->Add(pg->Allocator()->New<StringLiteral>(name));
186             literalBuf->Add(nullptr); // save for method internalname
187             literalBuf->Add(nullptr); // save for method affiliate
188         } else {
189             bufferPos = res.first->second;
190         }
191 
192         const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
193         const util::StringView &internalName = func->Function()->Scope()->InternalName();
194 
195         LiteralTag litTag = (prop->Kind() == MethodDefinitionKind::METHOD) ?  LiteralTag::METHOD :
196                             ((prop->Kind() == MethodDefinitionKind::SET) ? LiteralTag::SETTER : LiteralTag::GETTER);
197 
198         Literal *value = pg->Allocator()->New<TaggedLiteral>(litTag, internalName);
199         literalBuf->ResetLiteral(bufferPos + 1, value);
200         Literal *methodAffiliate = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHODAFFILIATE,
201                                                                        func->Function()->FormalParamsLength());
202         literalBuf->ResetLiteral(bufferPos + 2, methodAffiliate); // bufferPos + 2 is saved for method affiliate
203         compiled.Set(i);
204     }
205 
206     /* Static items are stored at the end of the buffer */
207     buf->Insert(&staticBuf);
208 
209     /* The last literal item represents the offset of the first static property. The regular property literal count
210      * is divided by 2 as key/value pairs count as one. */
211     buf->Add(pg->Allocator()->New<NumberLiteral>(instancePropertyCount));
212 
213     if (IsSendable()) {
214         std::string recordName = std::string(pg->Binder()->Program()->RecordName());
215         std::string fieldTypeIdxStr = recordName + "_" + std::to_string(fieldTypeBufIdx);
216         util::UString fieldTypeLitId(fieldTypeIdxStr, pg->Allocator());
217         buf->Add(pg->Allocator()->New<TaggedLiteral>(LiteralTag::LITERALARRAY, fieldTypeLitId.View()));
218     }
219     return pg->AddLiteralBuffer(buf);
220 }
221 
CreateClassPrivateBuffer(compiler::PandaGen *pg) const222 int32_t ClassDefinition::CreateClassPrivateBuffer(compiler::PandaGen *pg) const
223 {
224     auto *buf = pg->NewLiteralBuffer();
225     compiler::LiteralBuffer staticBuf(pg->Allocator());
226     uint32_t instancePropertyCount = 0;
227 
228     for (const auto *prop : body_) {
229         if (!prop->IsMethodDefinition()) {
230             continue;
231         }
232 
233         const auto *methodDef = prop->AsMethodDefinition();
234         if (!methodDef->IsPrivate()) {
235             continue;
236         }
237 
238         compiler::LiteralBuffer *literalBuf = methodDef->IsStatic() ? &staticBuf : (instancePropertyCount++, buf);
239         const ir::FunctionExpression *func = methodDef->Value()->AsFunctionExpression();
240         const util::StringView &internalName = func->Function()->Scope()->InternalName();
241         Literal *value = nullptr;
242         Literal *methodAffiliate = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHODAFFILIATE,
243                                                                        func->Function()->FormalParamsLength());
244         switch (methodDef->Kind()) {
245             case MethodDefinitionKind::METHOD: {
246                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHOD, internalName);
247                 break;
248             }
249             case MethodDefinitionKind::GET: {
250                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::GETTER, internalName);
251                 break;
252             }
253             case MethodDefinitionKind::SET: {
254                 value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::SETTER, internalName);
255                 break;
256             }
257             default: {
258                 UNREACHABLE();
259             }
260         }
261         literalBuf->Add(value);
262         literalBuf->Add(methodAffiliate);
263     }
264 
265     buf->Insert(&staticBuf);
266     buf->Add(pg->Allocator()->New<NumberLiteral>(instancePropertyCount));
267 
268     return pg->AddLiteralBuffer(buf);
269 }
270 
CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled, compiler::VReg classReg) const271 void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled,
272                                                compiler::VReg classReg) const
273 {
274     const auto &properties = body_;
275 
276     compiler::VReg protoReg = pg->AllocReg();
277 
278     pg->LoadObjByName(this, classReg, "prototype");
279     pg->StoreAccumulator(this, protoReg);
280 
281     for (size_t i = 0; i < properties.size(); i++) {
282         if (!properties[i]->IsMethodDefinition() || compiled.Test(i)) {
283             continue;
284         }
285 
286         const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
287         if (prop->IsOptional() && prop->Value()->Function()->IsOverload()) {
288             continue;
289         }
290 
291         if (prop->IsPrivate() || prop->IsAbstract()) {
292             continue;
293         }
294 
295         compiler::VReg dest = prop->IsStatic() ? classReg : protoReg;
296         compiler::RegScope rs(pg);
297 
298         switch (prop->Kind()) {
299             case ir::MethodDefinitionKind::METHOD: {
300                 compiler::Operand key = prop->Computed() ? prop->KeyReg() :
301                     pg->ToPropertyKey(prop->Key(), false);
302 
303                 pg->LoadAccumulator(this, dest);
304                 const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
305                 func->Compile(pg);
306 
307                 pg->StoreOwnProperty(prop->Value()->Parent(), dest, key, prop->Computed());
308                 break;
309             }
310             case ir::MethodDefinitionKind::GET:
311             case ir::MethodDefinitionKind::SET: {
312                 CompileGetterOrSetter(pg, dest, prop);
313                 break;
314             }
315             default: {
316                 UNREACHABLE();
317             }
318         }
319     }
320 
321     if (NeedInstanceInitializer()) {
322         InstanceInitialize(pg, protoReg);
323     }
324 }
325 
StaticInitialize(compiler::PandaGen *pg, compiler::VReg classReg) const326 void ClassDefinition::StaticInitialize(compiler::PandaGen *pg, compiler::VReg classReg) const
327 {
328     compiler::VReg callee = pg->AllocReg();
329     compiler::VReg thisReg = pg->AllocReg();
330 
331     const ir::FunctionExpression *func = staticInitializer_->Value();
332     func->Compile(pg);
333     pg->StoreAccumulator(this, callee);
334 
335     pg->MoveVreg(this, thisReg, classReg);
336     pg->CallThis(this, callee, 1);
337 
338     pg->LoadAccumulator(this, classReg);
339 }
340 
InstanceInitialize(compiler::PandaGen *pg, compiler::VReg protoReg) const341 void ClassDefinition::InstanceInitialize(compiler::PandaGen *pg, compiler::VReg protoReg) const
342 {
343     pg->StoreAccumulator(this, protoReg);
344     instanceInitializer_->Value()->Compile(pg);
345     pg->StoreLexicalVar(instanceInitializer_, 0, GetSlot(instanceInitializer_->Key()));
346 }
347 
CompileComputedKeys(compiler::PandaGen *pg) const348 void ClassDefinition::CompileComputedKeys(compiler::PandaGen *pg) const
349 {
350     for (const auto &stmt : body_) {
351         if (stmt->IsClassProperty()) {
352             const ir::ClassProperty *prop = stmt->AsClassProperty();
353 
354             // Do not process non-static public fields when not using define semantic.
355             if (!prop->IsStatic() && !pg->Binder()->Program()->UseDefineSemantic()) {
356                 continue;
357             }
358 
359             if (prop->IsComputed() && prop->NeedCompileKey()) {
360                 prop->Key()->Compile(pg);
361                 pg->ToComputedPropertyKey(prop->Key());
362                 pg->StoreLexicalVar(prop->Key(), 0, GetSlot(prop->Key()));
363             }
364         } else if (stmt->IsMethodDefinition()) {
365             auto *methodDef = stmt->AsMethodDefinition();
366             if (methodDef->Computed()) {
367                 compiler::VReg keyReg = pg->AllocReg();
368                 methodDef->SetKeyReg(keyReg);
369                 methodDef->Key()->Compile(pg);
370                 pg->ToComputedPropertyKey(methodDef->Key());
371                 pg->StoreAccumulator(methodDef->Key(), keyReg);
372             }
373         }
374     }
375 }
376 
Compile(compiler::PandaGen *pg) const377 void ClassDefinition::Compile(compiler::PandaGen *pg) const
378 {
379     if (declare_) {
380         return;
381     }
382 
383     if (isSendable_) {
384         CompileSendableClass(pg);
385         return;
386     }
387 
388     compiler::RegScope rs(pg);
389     compiler::VReg classReg = pg->AllocReg();
390 
391     compiler::LabelTarget target(pg);
392     compiler::VariableEnvScope classEnvScope(pg, scope_, target);
393     compiler::VReg baseReg = CompileHeritageClause(pg);
394     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
395     util::BitSet compiled(body_.size());
396 
397     if (hasComputedKey_) {
398         CompileComputedKeys(pg);
399     }
400 
401     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled);
402     pg->DefineClassWithBuffer(this, ctorId, bufIdx, baseReg);
403 
404     pg->StoreAccumulator(this, classReg);
405 
406     if (HasStaticPrivateMethod()) {
407         pg->StoreLexicalVar(this, 0, scope_->staticMethodValidation_);
408     }
409 
410     InitializeClassName(pg);
411 
412     CompileMissingProperties(pg, compiled, classReg);
413 
414     if (hasPrivateElement_) {
415         int32_t bufIdx = CreateClassPrivateBuffer(pg);
416         pg->CreatePrivateProperty(this, scope_->privateFieldCnt_, bufIdx);
417     }
418 
419     pg->LoadAccumulator(this, classReg);
420 
421     if (NeedStaticInitializer()) {
422         StaticInitialize(pg, classReg);
423     }
424 }
425 
Check(checker::Checker *checker) const426 checker::Type *ClassDefinition::Check(checker::Checker *checker) const
427 {
428     return checker->GlobalAnyType();
429 }
430 
UpdateSelf(const NodeUpdater &cb, binder::Binder *binder)431 void ClassDefinition::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder)
432 {
433     auto scopeCtx = binder::LexicalScope<binder::ClassScope>::Enter(binder, scope_);
434 
435     if (ident_) {
436         ident_ = std::get<ir::AstNode *>(cb(ident_))->AsIdentifier();
437     }
438 
439     if (typeParams_) {
440         typeParams_ = std::get<ir::AstNode *>(cb(typeParams_))->AsTSTypeParameterDeclaration();
441     }
442 
443     if (superClass_) {
444         superClass_ = std::get<ir::AstNode *>(cb(superClass_))->AsExpression();
445     }
446 
447     if (superTypeParams_) {
448         superTypeParams_ = std::get<ir::AstNode *>(cb(superTypeParams_))->AsTSTypeParameterInstantiation();
449     }
450 
451     for (auto iter = implements_.begin(); iter != implements_.end(); iter++) {
452         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSClassImplements();
453     }
454 
455     ctor_ = std::get<ir::AstNode *>(cb(ctor_))->AsMethodDefinition();
456 
457     for (auto iter = body_.begin(); iter != body_.end(); iter++) {
458         *iter = std::get<ir::AstNode *>(cb(*iter))->AsStatement();
459     }
460 
461     for (auto iter = indexSignatures_.begin(); iter != indexSignatures_.end(); iter++) {
462         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSIndexSignature();
463     }
464 }
465 
466 
BuildClassEnvironment(bool useDefineSemantic)467 void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic)
468 {
469     int instancePrivateMethodCnt = 0;
470     int staticPrivateMethodCnt = 0;
471     int privateFieldCnt = 0;
472     std::vector<const Statement *> privateProperties;
473     for (const auto *stmt : body_) {
474         if (stmt->IsMethodDefinition()) {
475             auto *methodDef = stmt->AsMethodDefinition();
476             if (methodDef->IsPrivate()) {
477                 privateProperties.push_back(stmt);
478                 methodDef->IsStatic() ? staticPrivateMethodCnt ++ : instancePrivateMethodCnt++;
479             } else if (methodDef->Computed()) {
480                 hasComputedKey_ = true;
481             }
482             continue;
483         }
484 
485         if (stmt->IsClassStaticBlock()) {
486             needStaticInitializer_ = true;
487             continue;
488         }
489 
490         ASSERT(stmt->IsClassProperty());
491         const auto *prop = stmt->AsClassProperty();
492         // Do not process non-static public fields when not using define semantic.
493         if (!prop->IsPrivate() && !prop->IsStatic() && !useDefineSemantic) {
494             continue;
495         }
496 
497         prop->IsStatic() ? needStaticInitializer_ = true : needInstanceInitializer_ = true;
498 
499         if (prop->IsComputed() && prop->NeedCompileKey()) {
500             hasComputedKey_ = true;
501             scope_->AddClassVariable(prop->Key());
502         } else if (prop->IsPrivate()) {
503             privateFieldCnt++;
504             privateProperties.push_back(stmt);
505         }
506     }
507 
508     if (!privateProperties.empty()) {
509         hasPrivateElement_ = true;
510         scope_->AddPrivateName(privateProperties, privateFieldCnt, instancePrivateMethodCnt, staticPrivateMethodCnt);
511     }
512 
513     if (instancePrivateMethodCnt > 0) {
514         needInstanceInitializer_ = true;
515     }
516 
517     if (NeedInstanceInitializer()) {
518         scope_->AddClassVariable(instanceInitializer_->Key());
519     }
520 }
521 
AddFieldType(FieldType &fieldType, const Expression *typeAnnotation, compiler::PandaGen *pg) const522 void ClassDefinition::AddFieldType(FieldType &fieldType, const Expression *typeAnnotation,
523     compiler::PandaGen *pg) const
524 {
525     switch (typeAnnotation->Type()) {
526         case AstNodeType::TS_NUMBER_KEYWORD: {
527             fieldType |= FieldType::NUMBER;
528             break;
529         }
530         case AstNodeType::TS_STRING_KEYWORD: {
531             fieldType |= FieldType::STRING;
532             break;
533         }
534         case AstNodeType::TS_BOOLEAN_KEYWORD: {
535             fieldType |= FieldType::BOOLEAN;
536             break;
537         }
538         case AstNodeType::TS_TYPE_REFERENCE: {
539             AddFieldTypeForTypeReference(typeAnnotation->AsTSTypeReference(), fieldType, pg);
540             break;
541         }
542         case AstNodeType::TS_BIGINT_KEYWORD: {
543             fieldType |= FieldType::BIGINT;
544             break;
545         }
546         case AstNodeType::TS_NULL_KEYWORD: {
547             fieldType |= FieldType::TS_NULL;
548             break;
549         }
550         case AstNodeType::TS_UNDEFINED_KEYWORD: {
551             fieldType |= FieldType::TS_UNDEFINED;
552             break;
553         }
554         default: {
555             UNREACHABLE();
556         }
557     }
558 }
559 
AddFieldTypeForTypeReference(const TSTypeReference *typeReference, FieldType &fieldType, compiler::PandaGen *pg) const560 void ClassDefinition::AddFieldTypeForTypeReference(const TSTypeReference *typeReference, FieldType &fieldType,
561     compiler::PandaGen *pg) const
562 {
563     auto typeName = typeReference->TypeName();
564     ASSERT(typeName != nullptr);
565     if (!typeName->IsIdentifier()) {
566         fieldType |= FieldType::GENERIC;
567         return;
568     }
569 
570     util::StringView propertyName = typeName->AsIdentifier()->Name();
571     binder::ScopeFindResult result = scope_->Find(propertyName);
572 
573     // identify import type
574     parser::SourceTextModuleRecord *moduleRecord = pg->Binder()->Program()->TypeModuleRecord();
575     const auto &regularImportEntries = moduleRecord->GetRegularImportEntries();
576     if (regularImportEntries.find(propertyName) != regularImportEntries.end()) {
577         fieldType |= FieldType::GENERIC;
578         return;
579     }
580 
581     if (IsTypeParam(propertyName) || (result.variable != nullptr && result.variable->IsModuleVariable())) {
582         fieldType |= FieldType::GENERIC;
583         return;
584     }
585 
586     // ts enum type
587     const ir::AstNode *declNode = GetDeclNodeFromIdentifier(typeName->AsIdentifier());
588     if (declNode != nullptr) {
589         // If the result of "declNode->Original()" is nullptr, it means the declNode is original and not transformed.
590         auto originalNode = (declNode->Original() != nullptr) ? declNode->Original() : declNode;
591         if (originalNode->Type() == ir::AstNodeType::TS_ENUM_DECLARATION) {
592             fieldType |= FieldType::STRING | FieldType::NUMBER;
593             return;
594         }
595     }
596 
597     // sendable class and sendable fuction
598     fieldType |= FieldType::TS_TYPE_REF;
599 }
600 
GetDeclNodeFromIdentifier(const ir::Identifier *identifier) const601 const ir::AstNode *ClassDefinition::GetDeclNodeFromIdentifier(const ir::Identifier *identifier) const
602 {
603     if (identifier == nullptr) {
604         return nullptr;
605     }
606 
607     std::vector<binder::Variable *> variables;
608     variables.reserve(identifier->TSVariables().size() + 1U);
609     variables.emplace_back(identifier->Variable());
610     for (const auto &v : identifier->TSVariables()) {
611         variables.emplace_back(v);
612     }
613 
614     for (const auto &v : variables) {
615         if (v == nullptr || v->Declaration() == nullptr || v->Declaration()->Node() == nullptr) {
616             continue;
617         }
618 
619         auto res = v->Declaration()->Node();
620         return res;
621     }
622     return nullptr;
623 }
624 
IsTypeParam(const util::StringView &propertyName) const625 bool ClassDefinition::IsTypeParam(const util::StringView &propertyName) const
626 {
627     if (typeParams_ == nullptr) {
628         return false;
629     }
630 
631     for (auto param : typeParams_->Params()) {
632         util::StringView paramName = param->Name()->AsIdentifier()->Name();
633         if (paramName == propertyName) {
634             return true;
635         }
636     }
637     return false;
638 }
639 
CreateFieldTypeBuffer(compiler::PandaGen *pg) const640 int32_t ClassDefinition::CreateFieldTypeBuffer(compiler::PandaGen *pg) const
641 {
642     ASSERT(IsSendable());
643     auto *instanceBuf = pg->NewLiteralBuffer();
644     compiler::LiteralBuffer staticBuf(pg->Allocator());
645     uint32_t instanceFieldCnt {0};
646 
647     for (auto *prop : body_) {
648         if (!prop->IsClassProperty()) {
649             continue;
650         }
651 
652         auto *classProp = prop->AsClassProperty();
653         auto *buf = classProp->IsStatic() ? &staticBuf : (++instanceFieldCnt, instanceBuf);
654         auto name = util::Helpers::LiteralToPropName(pg->Allocator(), classProp->Key());
655         buf->Add(pg->Allocator()->New<StringLiteral>(name));
656 
657         FieldType fieldType = FieldType::NONE;
658         const auto *typeAnnotation = classProp->TypeAnnotation();
659         if (typeAnnotation == nullptr) {
660             util::Helpers::ThrowError(ErrorType::GENERIC, pg->Binder()->Program(), prop->Start(),
661                 "Field in sendable class must have type annotation");
662         }
663         if (typeAnnotation->IsTSUnionType()) {
664             for (const auto *type : typeAnnotation->AsTSUnionType()->Types()) {
665                 AddFieldType(fieldType, type, pg);
666             }
667         } else {
668             AddFieldType(fieldType, typeAnnotation, pg);
669         }
670         buf->Add(pg->Allocator()->New<NumberLiteral>(static_cast<uint8_t>(fieldType)));
671     }
672 
673     instanceBuf->Insert(&staticBuf);
674     instanceBuf->Add(pg->Allocator()->New<NumberLiteral>(instanceFieldCnt));
675     return pg->AddLiteralBuffer(instanceBuf);
676 }
677 
CompileSendableClass(compiler::PandaGen *pg) const678 void ClassDefinition::CompileSendableClass(compiler::PandaGen *pg) const
679 {
680     compiler::RegScope rs(pg);
681     compiler::VReg classReg = pg->AllocReg();
682 
683     compiler::LocalRegScope lrs(pg, scope_);
684 
685     compiler::VReg baseReg = CompileHeritageClause(pg);
686     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
687     util::BitSet compiled(body_.size());
688 
689     int32_t fieldTypeBufIdx = CreateFieldTypeBuffer(pg);
690     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled, fieldTypeBufIdx);
691     pg->DefineSendableClass(this, ctorId, bufIdx, baseReg);
692 
693     pg->StoreAccumulator(this, classReg);
694 
695     InitializeClassName(pg);
696 
697     if (NeedStaticInitializer()) {
698         StaticInitialize(pg, classReg);
699     }
700 }
701 
CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest, const MethodDefinition *prop) const702 void ClassDefinition::CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest,
703     const MethodDefinition *prop) const
704 {
705     compiler::VReg keyReg = prop->Computed() ? prop->KeyReg() : pg->LoadPropertyKey(prop->Key(), false);
706 
707     compiler::VReg undef = pg->AllocReg();
708     pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
709     pg->StoreAccumulator(this, undef);
710 
711     compiler::VReg getter = undef;
712     compiler::VReg setter = undef;
713 
714     pg->LoadAccumulator(this, dest);
715 
716     compiler::VReg accessor = pg->AllocReg();
717     prop->Value()->Compile(pg);
718     pg->StoreAccumulator(prop->Value(), accessor);
719 
720     if (prop->Kind() == ir::MethodDefinitionKind::GET) {
721         getter = accessor;
722     } else {
723         setter = accessor;
724     }
725 
726     pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed());
727 }
728 
729 }  // namespace panda::es2panda::ir
730