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