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 ®ularImportEntries = 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