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