• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "classDefinition.h"
17 
18 #include "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->IsOptional() && 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     // TODO(aszilagyi)
429     return checker->GlobalAnyType();
430 }
431 
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)432 void ClassDefinition::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder)
433 {
434     auto scopeCtx = binder::LexicalScope<binder::ClassScope>::Enter(binder, scope_);
435 
436     if (ident_) {
437         ident_ = std::get<ir::AstNode *>(cb(ident_))->AsIdentifier();
438     }
439 
440     if (typeParams_) {
441         typeParams_ = std::get<ir::AstNode *>(cb(typeParams_))->AsTSTypeParameterDeclaration();
442     }
443 
444     if (superClass_) {
445         superClass_ = std::get<ir::AstNode *>(cb(superClass_))->AsExpression();
446     }
447 
448     if (superTypeParams_) {
449         superTypeParams_ = std::get<ir::AstNode *>(cb(superTypeParams_))->AsTSTypeParameterInstantiation();
450     }
451 
452     for (auto iter = implements_.begin(); iter != implements_.end(); iter++) {
453         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSClassImplements();
454     }
455 
456     ctor_ = std::get<ir::AstNode *>(cb(ctor_))->AsMethodDefinition();
457 
458     for (auto iter = body_.begin(); iter != body_.end(); iter++) {
459         *iter = std::get<ir::AstNode *>(cb(*iter))->AsStatement();
460     }
461 
462     for (auto iter = indexSignatures_.begin(); iter != indexSignatures_.end(); iter++) {
463         *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSIndexSignature();
464     }
465 }
466 
467 
BuildClassEnvironment(bool useDefineSemantic)468 void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic)
469 {
470     int instancePrivateMethodCnt = 0;
471     int staticPrivateMethodCnt = 0;
472     int privateFieldCnt = 0;
473     std::vector<const Statement *> privateProperties;
474     for (const auto *stmt : body_) {
475         if (stmt->IsMethodDefinition()) {
476             auto *methodDef = stmt->AsMethodDefinition();
477             if (methodDef->IsPrivate()) {
478                 privateProperties.push_back(stmt);
479                 methodDef->IsStatic() ? staticPrivateMethodCnt ++ : instancePrivateMethodCnt++;
480             } else if (methodDef->Computed()) {
481                 hasComputedKey_ = true;
482             }
483             continue;
484         }
485 
486         if (stmt->IsClassStaticBlock()) {
487             needStaticInitializer_ = true;
488             continue;
489         }
490 
491         ASSERT(stmt->IsClassProperty());
492         const auto *prop = stmt->AsClassProperty();
493         // Do not process non-static public fields when not using define semantic.
494         if (!prop->IsPrivate() && !prop->IsStatic() && !useDefineSemantic) {
495             continue;
496         }
497 
498         prop->IsStatic() ? needStaticInitializer_ = true : needInstanceInitializer_ = true;
499 
500         if (prop->IsComputed() && prop->NeedCompileKey()) {
501             hasComputedKey_ = true;
502             scope_->AddClassVariable(prop->Key());
503         } else if (prop->IsPrivate()) {
504             privateFieldCnt++;
505             privateProperties.push_back(stmt);
506         }
507     }
508 
509     if (!privateProperties.empty()) {
510         hasPrivateElement_ = true;
511         scope_->AddPrivateName(privateProperties, privateFieldCnt, instancePrivateMethodCnt, staticPrivateMethodCnt);
512     }
513 
514     if (instancePrivateMethodCnt > 0) {
515         needInstanceInitializer_ = true;
516     }
517 
518     if (NeedInstanceInitializer()) {
519         scope_->AddClassVariable(instanceInitializer_->Key());
520     }
521 }
522 
AddFieldType(FieldType & fieldType,const Expression * typeAnnotation)523 static void AddFieldType(FieldType &fieldType, const Expression *typeAnnotation)
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             fieldType |= FieldType::TS_TYPE_REF;
540             break;
541         }
542         default: {
543             UNREACHABLE();
544         }
545     }
546 }
547 
CreateFieldTypeBuffer(compiler::PandaGen * pg) const548 int32_t ClassDefinition::CreateFieldTypeBuffer(compiler::PandaGen *pg) const
549 {
550     ASSERT(IsSendable());
551     auto *instanceBuf = pg->NewLiteralBuffer();
552     compiler::LiteralBuffer staticBuf(pg->Allocator());
553     uint32_t instanceFieldCnt {0};
554 
555     for (auto *prop : body_) {
556         if (!prop->IsClassProperty()) {
557             continue;
558         }
559 
560         auto *classProp = prop->AsClassProperty();
561         auto *buf = classProp->IsStatic() ? &staticBuf : (++instanceFieldCnt, instanceBuf);
562         auto name = util::Helpers::LiteralToPropName(pg->Allocator(), classProp->Key());
563         buf->Add(pg->Allocator()->New<StringLiteral>(name));
564 
565         FieldType fieldType = FieldType::NONE;
566         const auto *typeAnnotation = classProp->TypeAnnotation();
567         ASSERT(typeAnnotation != nullptr);
568         if (typeAnnotation->IsTSUnionType()) {
569             for (const auto *type : typeAnnotation->AsTSUnionType()->Types()) {
570                 AddFieldType(fieldType, type);
571             }
572         } else {
573             AddFieldType(fieldType, typeAnnotation);
574         }
575         buf->Add(pg->Allocator()->New<NumberLiteral>(static_cast<uint8_t>(fieldType)));
576     }
577 
578     instanceBuf->Insert(&staticBuf);
579     instanceBuf->Add(pg->Allocator()->New<NumberLiteral>(instanceFieldCnt));
580     return pg->AddLiteralBuffer(instanceBuf);
581 }
582 
CompileSendableClass(compiler::PandaGen * pg) const583 void ClassDefinition::CompileSendableClass(compiler::PandaGen *pg) const
584 {
585     compiler::RegScope rs(pg);
586     compiler::VReg classReg = pg->AllocReg();
587 
588     compiler::LocalRegScope lrs(pg, scope_);
589 
590     compiler::VReg baseReg = CompileHeritageClause(pg);
591     util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
592     util::BitSet compiled(body_.size());
593 
594     int32_t fieldTypeBufIdx = CreateFieldTypeBuffer(pg);
595     int32_t bufIdx = CreateClassPublicBuffer(pg, compiled, fieldTypeBufIdx);
596     pg->DefineSendableClass(this, ctorId, bufIdx, baseReg);
597 
598     pg->StoreAccumulator(this, classReg);
599 
600     InitializeClassName(pg);
601 
602     if (NeedStaticInitializer()) {
603         StaticInitialize(pg, classReg);
604     }
605 }
606 
CompileGetterOrSetter(compiler::PandaGen * pg,compiler::VReg dest,const MethodDefinition * prop) const607 void ClassDefinition::CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest,
608     const MethodDefinition *prop) const
609 {
610     compiler::VReg keyReg = prop->Computed() ? prop->KeyReg() : pg->LoadPropertyKey(prop->Key(), false);
611 
612     compiler::VReg undef = pg->AllocReg();
613     pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
614     pg->StoreAccumulator(this, undef);
615 
616     compiler::VReg getter = undef;
617     compiler::VReg setter = undef;
618 
619     pg->LoadAccumulator(this, dest);
620 
621     compiler::VReg accessor = pg->AllocReg();
622     prop->Value()->Compile(pg);
623     pg->StoreAccumulator(prop->Value(), accessor);
624 
625     if (prop->Kind() == ir::MethodDefinitionKind::GET) {
626         getter = accessor;
627     } else {
628         setter = accessor;
629     }
630 
631     pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed());
632 }
633 
634 }  // namespace panda::es2panda::ir
635