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
43namespace panda::es2panda::ir {
44
45const FunctionExpression *ClassDefinition::Ctor() const
46{
47    ASSERT(ctor_ != nullptr);
48    return ctor_->Value();
49}
50
51util::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
64void 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
97void 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
109compiler::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
123void 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)
134int32_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
222int32_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
271void 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
326void 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
341void 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
348void 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
377void 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
426checker::Type *ClassDefinition::Check(checker::Checker *checker) const
427{
428    return checker->GlobalAnyType();
429}
430
431void 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
467void 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
522void 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
560void 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
601const 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
625bool 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
640int32_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
678void 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
702void 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