• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "ETSCompiler.h"
17 
18 #include "compiler/base/catchTable.h"
19 #include "checker/ets/dynamic/dynamicCall.h"
20 #include "compiler/base/condition.h"
21 #include "compiler/core/ETSGen-inl.h"
22 #include "compiler/base/lreference.h"
23 #include "compiler/core/switchBuilder.h"
24 #include "compiler/function/functionBuilder.h"
25 #include "checker/ETSchecker.h"
26 #include "checker/types/ets/etsDynamicFunctionType.h"
27 #include "checker/types/ets/etsTupleType.h"
28 
29 namespace ark::es2panda::compiler {
30 
GetETSGen() const31 ETSGen *ETSCompiler::GetETSGen() const
32 {
33     return static_cast<ETSGen *>(GetCodeGen());
34 }
35 
Compile(const ir::CatchClause * st) const36 void ETSCompiler::Compile(const ir::CatchClause *st) const
37 {
38     ETSGen *etsg = GetETSGen();
39     compiler::LocalRegScope lrs(etsg, st->Scope()->ParamScope());
40     etsg->SetAccumulatorType(st->TsType());
41     auto lref = compiler::ETSLReference::Create(etsg, st->Param(), true);
42     lref.SetValue();
43     st->Body()->Compile(etsg);
44 }
45 
Compile(const ir::ClassProperty * st) const46 void ETSCompiler::Compile(const ir::ClassProperty *st) const
47 {
48     ETSGen *etsg = GetETSGen();
49     if (st->Value() == nullptr && st->TsType()->IsETSPrimitiveType()) {
50         return;
51     }
52 
53     auto ttctx = compiler::TargetTypeContext(etsg, st->TsType());
54     compiler::RegScope rs(etsg);
55 
56     ir::BoxingUnboxingFlags flags =
57         (st->Value() != nullptr) ? st->Value()->GetBoxingUnboxingFlags() : ir::BoxingUnboxingFlags::NONE;
58 
59     if (st->Value() == nullptr) {
60         etsg->LoadDefaultValue(st, st->TsType());
61     } else {
62         st->Value()->Compile(etsg);
63         etsg->ApplyConversion(st->Value(), st->TsType());
64         st->Value()->SetBoxingUnboxingFlags(flags);
65     }
66 
67     if (st->IsStatic()) {
68         etsg->StoreStaticOwnProperty(st, st->TsType(), st->Key()->AsIdentifier()->Name());
69     } else {
70         etsg->StoreProperty(st, st->TsType(), etsg->GetThisReg(), st->Key()->AsIdentifier()->Name());
71     }
72 }
73 
Compile(const ir::TemplateElement * expr) const74 void ETSCompiler::Compile(const ir::TemplateElement *expr) const
75 {
76     ETSGen *etsg = GetETSGen();
77     etsg->LoadAccumulatorString(expr, expr->Cooked());
78     etsg->SetAccumulatorType(expr->TsType());
79     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
80 }
81 
Compile(const ir::ETSClassLiteral * expr) const82 void ETSCompiler::Compile(const ir::ETSClassLiteral *expr) const
83 {
84     ETSGen *etsg = GetETSGen();
85 
86     auto *literal = expr->Expr();
87     auto *literalType = literal->TsType();
88 
89     bool const isPrimitive = !literalType->IsETSReferenceType();
90     if (!isPrimitive) {
91         literal->Compile(etsg);
92     } else {
93         ES2PANDA_ASSERT(literalType->IsETSPrimitiveType());
94         etsg->SetAccumulatorType(literalType);
95     }
96 
97     etsg->GetType(expr, isPrimitive);
98     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
99 }
100 
Compile(const ir::ETSFunctionType * node) const101 void ETSCompiler::Compile(const ir::ETSFunctionType *node) const
102 {
103     ETSGen *etsg = GetETSGen();
104     etsg->LoadAccumulatorPoison(node, node->TsType());
105 }
106 
Compile(const ir::ETSNewArrayInstanceExpression * expr) const107 void ETSCompiler::Compile(const ir::ETSNewArrayInstanceExpression *expr) const
108 {
109     ETSGen *etsg = GetETSGen();
110     auto const checker = const_cast<checker::ETSChecker *>(etsg->Checker());
111     compiler::RegScope rs(etsg);
112     compiler::TargetTypeContext ttctx(etsg, checker->GlobalIntType());
113 
114     expr->Dimension()->Compile(etsg);
115 
116     compiler::VReg arr = etsg->AllocReg();
117     compiler::VReg dim = etsg->AllocReg();
118     etsg->ApplyConversionAndStoreAccumulator(expr, dim, expr->Dimension()->TsType());
119     etsg->NewArray(expr, arr, dim, expr->TsType());
120 
121     const auto *elementType = expr->TypeReference()->TsType();
122     const bool undefAssignable = checker->Relation()->IsSupertypeOf(elementType, checker->GlobalETSUndefinedType());
123     if (elementType->IsETSPrimitiveType() || undefAssignable) {
124         // no-op
125     } else {
126         compiler::VReg countReg = etsg->AllocReg();
127         auto *startLabel = etsg->AllocLabel();
128         auto *endLabel = etsg->AllocLabel();
129         etsg->MoveImmediateToRegister(expr, countReg, checker::TypeFlag::INT, static_cast<std::int32_t>(0));
130         const auto indexReg = etsg->AllocReg();
131 
132         etsg->SetLabel(expr, startLabel);
133         etsg->LoadAccumulator(expr, dim);
134         etsg->JumpCompareRegister<compiler::Jle>(expr, countReg, endLabel);
135 
136         etsg->LoadAccumulator(expr, countReg);
137         etsg->StoreAccumulator(expr, indexReg);
138 
139         if (expr->Signature() != nullptr) {
140             const compiler::TargetTypeContext ttctx2(etsg, elementType);
141             ArenaVector<ir::Expression *> arguments(GetCodeGen()->Allocator()->Adapter());
142             etsg->InitObject(expr, expr->Signature(), arguments);
143         } else {
144             etsg->LoadAccumulatorPoison(expr, elementType);
145         }
146         etsg->StoreArrayElement(expr, arr, indexReg, elementType);
147 
148         etsg->IncrementImmediateRegister(expr, countReg, checker::TypeFlag::INT, static_cast<std::int32_t>(1));
149         etsg->JumpTo(expr, startLabel);
150         etsg->SetLabel(expr, endLabel);
151     }
152 
153     etsg->SetVRegType(arr, expr->TsType());
154     etsg->LoadAccumulator(expr, arr);
155 
156     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
157 }
158 
LoadDynamicName(compiler::ETSGen * etsg,const ir::AstNode * node,const ArenaVector<util::StringView> & dynName,bool isConstructor)159 static std::pair<VReg, VReg> LoadDynamicName(compiler::ETSGen *etsg, const ir::AstNode *node,
160                                              const ArenaVector<util::StringView> &dynName, bool isConstructor)
161 {
162     auto *checker = const_cast<checker::ETSChecker *>(etsg->Checker()->AsETSChecker());
163     auto *callNames = checker->DynamicCallNames(isConstructor);
164 
165     auto qnameStart = etsg->AllocReg();
166     auto qnameLen = etsg->AllocReg();
167 
168     TargetTypeContext ttctx(etsg, nullptr);  // without this ints will be cast to JSValue
169     etsg->LoadAccumulatorInt(node, callNames->at(dynName));
170     etsg->StoreAccumulator(node, qnameStart);
171     etsg->LoadAccumulatorInt(node, dynName.size());
172     etsg->StoreAccumulator(node, qnameLen);
173     return {qnameStart, qnameLen};
174 }
175 
CreateDynamicObject(const ir::AstNode * node,compiler::ETSGen * etsg,const ir::Expression * typeRef,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)176 static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, const ir::Expression *typeRef,
177                                 checker::Signature *signature, const ArenaVector<ir::Expression *> &arguments)
178 {
179     auto objReg = etsg->AllocReg();
180 
181     auto callInfo = checker::DynamicCall::ResolveCall(etsg->VarBinder(), typeRef);
182     if (callInfo.obj->IsETSImportDeclaration()) {
183         etsg->LoadAccumulatorDynamicModule(node, callInfo.obj->AsETSImportDeclaration());
184     } else {
185         callInfo.obj->Compile(etsg);
186     }
187 
188     etsg->StoreAccumulator(node, objReg);
189 
190     auto [qnameStart, qnameLen] = LoadDynamicName(etsg, node, callInfo.name, true);
191     etsg->CallDynamic(ETSGen::CallDynamicData {node, objReg, qnameStart}, qnameLen, signature, arguments);
192 }
193 
ConvertRestArguments(checker::ETSChecker * const checker,const ir::ETSNewClassInstanceExpression * expr)194 static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::ETSNewClassInstanceExpression *expr)
195 {
196     if (expr->GetSignature()->RestVar() != nullptr && (expr->GetSignature()->RestVar()->TsType()->IsETSArrayType() ||
197                                                        expr->GetSignature()->RestVar()->TsType()->IsETSTupleType())) {
198         std::size_t const argumentCount = expr->GetArguments().size();
199         std::size_t const parameterCount = expr->GetSignature()->Params().size();
200         ES2PANDA_ASSERT(argumentCount >= parameterCount);
201 
202         auto &arguments = const_cast<ArenaVector<ir::Expression *> &>(expr->GetArguments());
203         std::size_t i = parameterCount;
204 
205         if (i < argumentCount && expr->GetArguments()[i]->IsSpreadElement()) {
206             arguments[i] = expr->GetArguments()[i]->AsSpreadElement()->Argument();
207         } else if (!expr->GetSignature()->RestVar()->TsType()->IsETSTupleType()) {
208             ArenaVector<ir::Expression *> elements(checker->Allocator()->Adapter());
209             for (; i < argumentCount; ++i) {
210                 elements.emplace_back(expr->GetArguments()[i]);
211             }
212             auto *arrayExpression = checker->AllocNode<ir::ArrayExpression>(std::move(elements), checker->Allocator());
213             ES2PANDA_ASSERT(arrayExpression != nullptr);
214             arrayExpression->SetParent(const_cast<ir::ETSNewClassInstanceExpression *>(expr));
215             auto restType = expr->GetSignature()->RestVar()->TsType()->AsETSArrayType();
216             arrayExpression->SetTsType(restType);
217             arrayExpression->SetPreferredType(restType->ElementType());
218             arguments.erase(expr->GetArguments().begin() + parameterCount, expr->GetArguments().end());
219             arguments.emplace_back(arrayExpression);
220         }
221     }
222 }
223 
HandleUnionTypeInForOf(compiler::ETSGen * etsg,checker::Type const * const exprType,const ir::ForOfStatement * st,VReg objReg,VReg * countReg)224 static void HandleUnionTypeInForOf(compiler::ETSGen *etsg, checker::Type const *const exprType,
225                                    const ir::ForOfStatement *st, VReg objReg, VReg *countReg)
226 {
227     ArenaVector<Label *> labels(etsg->Allocator()->Adapter());
228 
229     for (auto it : exprType->AsETSUnionType()->ConstituentTypes()) {
230         labels.push_back(etsg->AllocLabel());
231         etsg->LoadAccumulator(st->Right(), objReg);
232         etsg->IsInstance(st->Right(), objReg, it);
233         etsg->BranchIfTrue(st, labels.back());
234     }
235 
236     labels.push_back(etsg->AllocLabel());
237 
238     for (size_t i = 0; i < exprType->AsETSUnionType()->ConstituentTypes().size(); i++) {
239         compiler::VReg unionReg = etsg->AllocReg();
240         auto currentType = exprType->AsETSUnionType()->ConstituentTypes()[i];
241         etsg->SetLabel(st->Right(), labels[i]);
242         etsg->LoadAccumulator(st, objReg);
243         etsg->CastToReftype(st->Right(), currentType, false);
244         etsg->StoreAccumulator(st, unionReg);
245         etsg->LoadAccumulator(st, unionReg);
246         if (countReg == nullptr) {
247             if (currentType->IsETSArrayType()) {
248                 etsg->LoadArrayLength(st, unionReg);
249             } else if (currentType->IsETSResizableArrayType()) {
250                 etsg->LoadResizableArrayLength(st);
251             } else {
252                 etsg->LoadStringLength(st);
253             }
254         } else {
255             if (currentType->IsETSArrayType()) {
256                 etsg->LoadAccumulator(st, *countReg);
257                 etsg->LoadArrayElement(st, unionReg);
258             } else if (currentType->IsETSResizableArrayType()) {
259                 etsg->LoadResizableArrayElement(st, unionReg, *countReg);
260             } else {
261                 etsg->LoadStringChar(st, unionReg, *countReg);
262                 // NOTE(vpukhov): #20510 use a single unboxing convertor
263                 etsg->ApplyCastToBoxingFlags(st, ir::BoxingUnboxingFlags::BOX_TO_CHAR);
264                 etsg->EmitBoxingConversion(ir::BoxingUnboxingFlags::BOX_TO_CHAR, st);
265                 etsg->CastToChar(st);
266             }
267         }
268 
269         if (i + 1 != exprType->AsETSUnionType()->ConstituentTypes().size()) {
270             etsg->Branch(st, labels.back());
271         }
272     }
273 
274     etsg->SetLabel(st->Right(), labels.back());
275 }
276 
GetSizeInForOf(compiler::ETSGen * etsg,checker::Type const * const exprType,const ir::ForOfStatement * st,VReg objReg)277 static void GetSizeInForOf(compiler::ETSGen *etsg, checker::Type const *const exprType, const ir::ForOfStatement *st,
278                            VReg objReg)
279 {
280     if (exprType->IsETSArrayType()) {
281         etsg->LoadArrayLength(st, objReg);
282     } else if (exprType->IsETSUnionType()) {
283         HandleUnionTypeInForOf(etsg, exprType, st, objReg, nullptr);
284     } else {
285         etsg->LoadStringLength(st);
286     }
287 }
288 
Compile(const ir::ETSNewClassInstanceExpression * expr) const289 void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const
290 {
291     ETSGen *etsg = GetETSGen();
292     if (expr->TsType()->IsETSDynamicType()) {
293         compiler::RegScope rs(etsg);
294         auto *name = expr->GetTypeRef();
295         CreateDynamicObject(expr, etsg, name, expr->signature_, expr->GetArguments());
296     } else {
297         ConvertRestArguments(const_cast<checker::ETSChecker *>(etsg->Checker()->AsETSChecker()), expr);
298         etsg->InitObject(expr, expr->signature_, expr->GetArguments());
299     }
300 
301     etsg->SetAccumulatorType(expr->TsType());
302 }
303 
Compile(const ir::ETSNewMultiDimArrayInstanceExpression * expr) const304 void ETSCompiler::Compile(const ir::ETSNewMultiDimArrayInstanceExpression *expr) const
305 {
306     ETSGen *etsg = GetETSGen();
307     etsg->InitObject(expr, expr->Signature(), expr->Dimensions());
308     etsg->SetAccumulatorType(expr->TsType());
309 }
310 
Compile(const ir::ETSParameterExpression * expr) const311 void ETSCompiler::Compile(const ir::ETSParameterExpression *expr) const
312 {
313     ETSGen *etsg = GetETSGen();
314     expr->Ident()->Compile(etsg);
315 
316     if (auto *const paramType = expr->TsType();
317         !etsg->Checker()->AsETSChecker()->Relation()->IsIdenticalTo(paramType, etsg->GetAccumulatorType())) {
318         etsg->SetAccumulatorType(paramType);
319     }
320 
321     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
322 }
323 
Compile(const ir::ETSTypeReference * node) const324 void ETSCompiler::Compile(const ir::ETSTypeReference *node) const
325 {
326     ETSGen *etsg = GetETSGen();
327     node->Part()->Compile(etsg);
328     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), node->TsType()));
329 }
330 
Compile(const ir::ETSTypeReferencePart * node) const331 void ETSCompiler::Compile(const ir::ETSTypeReferencePart *node) const
332 {
333     ETSGen *etsg = GetETSGen();
334     node->Name()->Compile(etsg);
335     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), node->TsType()));
336 }
337 
Compile(const ir::ETSWildcardType * node) const338 void ETSCompiler::Compile([[maybe_unused]] const ir::ETSWildcardType *node) const
339 {
340     ES2PANDA_UNREACHABLE();
341 }
342 
CompileTupleCreation(const ir::ArrayExpression * tupleInitializer) const343 void ETSCompiler::CompileTupleCreation(const ir::ArrayExpression *tupleInitializer) const
344 {
345     ETSGen *etsg = GetETSGen();
346 
347     etsg->InitObject(tupleInitializer,
348                      tupleInitializer->TsType()->AsETSTupleType()->GetWrapperType()->ConstructSignatures().front(),
349                      tupleInitializer->Elements());
350     etsg->SetAccumulatorType(tupleInitializer->TsType());
351 }
352 
CompileArrayCreation(const ir::ArrayExpression * expr) const353 void ETSCompiler::CompileArrayCreation(const ir::ArrayExpression *expr) const
354 {
355     ETSGen *etsg = GetETSGen();
356 
357     const auto arr = etsg->AllocReg();
358     const auto dim = etsg->AllocReg();
359 
360     const auto *const arrayExprType = expr->TsType();
361 
362     const compiler::TargetTypeContext ttctx(etsg, etsg->Checker()->GlobalIntType());
363     etsg->LoadAccumulatorInt(expr, static_cast<std::int32_t>(expr->Elements().size()));
364     etsg->StoreAccumulator(expr, dim);
365     etsg->NewArray(expr, arr, dim, expr->TsType());
366 
367     const auto indexReg = etsg->AllocReg();
368     auto const *const elementType = arrayExprType->AsETSArrayType()->ElementType();
369 
370     for (std::uint32_t i = 0; i < expr->Elements().size(); ++i) {
371         const auto *const expression = expr->Elements()[i];
372         etsg->LoadAccumulatorInt(expr, i);
373         etsg->StoreAccumulator(expr, indexReg);
374 
375         const compiler::TargetTypeContext ttctx2(etsg, elementType);
376         expression->Compile(etsg);
377         etsg->ApplyConversion(expression, elementType);
378 
379         if (expression->TsType()->IsETSArrayType()) {
380             etsg->StoreArrayElement(expr, arr, indexReg, expression->TsType());
381         } else {
382             etsg->StoreArrayElement(expr, arr, indexReg, arrayExprType->AsETSArrayType()->ElementType());
383         }
384     }
385 
386     etsg->LoadAccumulator(expr, arr);
387     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), arrayExprType));
388 }
389 
Compile(const ir::ArrayExpression * expr) const390 void ETSCompiler::Compile(const ir::ArrayExpression *expr) const
391 {
392     ETSGen *etsg = GetETSGen();
393     const compiler::RegScope rs(etsg);
394 
395     if (expr->TsType()->IsETSTupleType()) {
396         CompileTupleCreation(expr);
397     } else {
398         CompileArrayCreation(expr);
399     }
400 }
401 
Compile(const ir::AssignmentExpression * expr) const402 void ETSCompiler::Compile(const ir::AssignmentExpression *expr) const
403 {
404     ETSGen *etsg = GetETSGen();
405     // All other operations are handled in OpAssignmentLowering
406     ES2PANDA_ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
407     const auto *const exprType = expr->TsType();
408 
409     compiler::RegScope rs(etsg);
410     auto lref = compiler::ETSLReference::Create(etsg, expr->Left(), false);
411     auto ttctx = compiler::TargetTypeContext(etsg, exprType);
412 
413     expr->Right()->Compile(etsg);
414     etsg->ApplyConversion(expr->Right(), exprType);
415     etsg->SetAccumulatorType(exprType);
416 
417     if (expr->Right()->TsType()->IsETSBigIntType()) {
418         // For bigints we have to copy the bigint object when performing an assignment operation
419         const VReg value = etsg->AllocReg();
420         etsg->StoreAccumulator(expr, value);
421         etsg->CreateBigIntObject(expr, value, Signatures::BUILTIN_BIGINT_CTOR_BIGINT);
422     }
423 
424     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), exprType) ||
425                     etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(),
426                                                                etsg->Checker()->GlobalBuiltinJSValueType()));
427     lref.SetValue();
428 }
429 
Compile(const ir::AwaitExpression * expr) const430 void ETSCompiler::Compile(const ir::AwaitExpression *expr) const
431 {
432     ETSGen *etsg = GetETSGen();
433     static constexpr bool IS_UNCHECKED_CAST = false;
434     compiler::RegScope rs(etsg);
435     compiler::VReg argumentReg = etsg->AllocReg();
436     expr->Argument()->Compile(etsg);
437     etsg->StoreAccumulator(expr, argumentReg);
438     etsg->CallVirtual(expr->Argument(), compiler::Signatures::BUILTIN_PROMISE_AWAIT_RESOLUTION, argumentReg);
439     etsg->CastToReftype(expr->Argument(), expr->TsType(), IS_UNCHECKED_CAST);
440     etsg->SetAccumulatorType(expr->TsType());
441 }
442 
Compile(const ir::ImportExpression * expr) const443 void ETSCompiler::Compile([[maybe_unused]] const ir::ImportExpression *expr) const
444 {
445     ES2PANDA_UNREACHABLE();
446 }
447 
CompileNullishCoalescing(compiler::ETSGen * etsg,ir::BinaryExpression const * const node)448 static void CompileNullishCoalescing(compiler::ETSGen *etsg, ir::BinaryExpression const *const node)
449 {
450     auto const compileOperand = [etsg, optype = node->OperationType()](ir::Expression const *expr) {
451         etsg->CompileAndCheck(expr);
452         etsg->ApplyConversion(expr, nullptr);
453     };
454 
455     compileOperand(node->Left());
456 
457     if (node->Left()->TsType()->DefinitelyNotETSNullish()) {
458         // fallthrough
459     } else if (node->Left()->TsType()->DefinitelyETSNullish()) {
460         compileOperand(node->Right());
461     } else {
462         auto *ifLeftNullish = etsg->AllocLabel();
463         auto *endLabel = etsg->AllocLabel();
464 
465         etsg->BranchIfNullish(node, ifLeftNullish);
466 
467         etsg->AssumeNonNullish(node, node->OperationType());
468         etsg->ApplyConversion(node->Left(), node->OperationType());
469         etsg->JumpTo(node, endLabel);
470 
471         etsg->SetLabel(node, ifLeftNullish);
472         compileOperand(node->Right());
473 
474         etsg->SetLabel(node, endLabel);
475     }
476     etsg->SetAccumulatorType(node->TsType());
477 }
478 
CompileLogical(compiler::ETSGen * etsg,const ir::BinaryExpression * expr)479 static void CompileLogical(compiler::ETSGen *etsg, const ir::BinaryExpression *expr)
480 {
481     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) {
482         CompileNullishCoalescing(etsg, expr);
483         return;
484     }
485     ES2PANDA_ASSERT(expr->IsLogicalExtended());
486     // Always compile the left hand side
487     etsg->CompileAndCheck(expr->Left());
488 
489     // If the Result is given, we can optimize the process.
490     if (expr->Result() != nullptr) {
491         if (expr->Result() != expr->Left()) {
492             ES2PANDA_ASSERT(expr->Result() == expr->Right());
493             expr->Result()->Compile(etsg);
494         }
495         etsg->ApplyConversion(expr->Result(), expr->OperationType());
496         etsg->ApplyConversion(expr, expr->TsType());
497         etsg->SetAccumulatorType(expr->TsType());
498         ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
499         return;
500     }
501     auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType());
502     compiler::RegScope rs(etsg);
503     auto endValue = etsg->AllocReg();
504     auto orgValue = etsg->AllocReg();
505 
506     etsg->StoreAccumulator(expr->Left(), orgValue);
507     etsg->ApplyConversionAndStoreAccumulator(expr->Left(), endValue, expr->OperationType());
508     auto *endLabel = etsg->AllocLabel();
509 
510     etsg->LoadAccumulator(expr, orgValue);
511     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
512         etsg->BranchConditionalIfFalse(expr->Left(), endLabel);
513     } else {
514         ES2PANDA_ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
515         etsg->BranchConditionalIfTrue(expr->Left(), endLabel);
516     }
517 
518     etsg->CompileAndCheck(expr->Right());
519     etsg->ApplyConversionAndStoreAccumulator(expr->Right(), endValue, expr->OperationType());
520     etsg->SetLabel(expr, endLabel);
521     etsg->LoadAccumulator(expr, endValue);
522     etsg->ApplyConversion(expr, expr->TsType());
523 
524     etsg->SetAccumulatorType(expr->TsType());
525 }
526 
CompileInstanceof(compiler::ETSGen * etsg,const ir::BinaryExpression * expr)527 static void CompileInstanceof(compiler::ETSGen *etsg, const ir::BinaryExpression *expr)
528 {
529     ES2PANDA_ASSERT(expr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF);
530     auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType());
531     compiler::RegScope rs(etsg);
532     auto lhs = etsg->AllocReg();
533 
534     expr->Left()->Compile(etsg);
535     etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType());
536 
537     if (expr->Left()->TsType()->IsETSDynamicType() || expr->Right()->TsType()->IsETSDynamicType()) {
538         auto rhs = etsg->AllocReg();
539         expr->Right()->Compile(etsg);
540         etsg->StoreAccumulator(expr, rhs);
541         etsg->IsInstanceDynamic(expr, lhs, rhs);
542     } else {
543         auto target = expr->Right()->TsType();
544         etsg->IsInstance(expr, lhs, target);
545     }
546     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
547 }
548 
GetBigintSignatures()549 std::map<lexer::TokenType, std::string_view> &GetBigintSignatures()
550 {
551     static std::map<lexer::TokenType, std::string_view> bigintSignatures = {
552         {lexer::TokenType::PUNCTUATOR_PLUS, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_ADD},
553         {lexer::TokenType::PUNCTUATOR_MINUS, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_SUBTRACT},
554         {lexer::TokenType::PUNCTUATOR_MULTIPLY, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_MULTIPLY},
555         {lexer::TokenType::PUNCTUATOR_DIVIDE, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_DIVIDE},
556         {lexer::TokenType::PUNCTUATOR_MOD, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_MODULE},
557         {lexer::TokenType::PUNCTUATOR_BITWISE_OR, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_OR},
558         {lexer::TokenType::PUNCTUATOR_BITWISE_AND, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_AND},
559         {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_XOR},
560         {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LEFT_SHIFT},
561         {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_RIGHT_SHIFT},
562         {lexer::TokenType::PUNCTUATOR_GREATER_THAN, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN},
563         {lexer::TokenType::PUNCTUATOR_LESS_THAN, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN},
564         {lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL,
565          compiler::Signatures::BUILTIN_BIGINT_OPERATOR_GREATER_THAN_EQUAL},
566         {lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_LESS_THAN_EQUAL},
567     };
568 
569     return bigintSignatures;
570 }
571 
CompileBigInt(compiler::ETSGen * etsg,const ir::BinaryExpression * expr)572 static bool CompileBigInt(compiler::ETSGen *etsg, const ir::BinaryExpression *expr)
573 {
574     if ((expr->Left()->TsType() == nullptr) || (expr->Right()->TsType() == nullptr)) {
575         return false;
576     }
577 
578     if (!expr->Left()->TsType()->IsETSBigIntType()) {
579         return false;
580     }
581 
582     if (!expr->Right()->TsType()->IsETSBigIntType()) {
583         return false;
584     }
585 
586     auto map = GetBigintSignatures();
587     if (map.find(expr->OperatorType()) == map.end()) {
588         return false;
589     }
590 
591     const checker::Type *operationType = expr->OperationType();
592     auto ttctx = compiler::TargetTypeContext(etsg, operationType);
593     compiler::RegScope rs(etsg);
594     compiler::VReg lhs = etsg->AllocReg();
595     expr->Left()->Compile(etsg);
596     etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, operationType);
597     expr->Right()->Compile(etsg);
598     etsg->ApplyConversion(expr->Right(), operationType);
599     compiler::VReg rhs = etsg->AllocReg();
600     etsg->StoreAccumulator(expr, rhs);
601 
602     std::string_view signature = map.at(expr->OperatorType());
603     switch (expr->OperatorType()) {
604         case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
605         case lexer::TokenType::PUNCTUATOR_LESS_THAN:
606         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
607         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
608             etsg->CallBigIntBinaryComparison(expr, lhs, rhs, signature);
609             break;
610         default:
611             etsg->CallBigIntBinaryOperator(expr, lhs, rhs, signature);
612             break;
613     }
614 
615     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
616     return true;
617 }
618 
Compile(const ir::BinaryExpression * expr) const619 void ETSCompiler::Compile(const ir::BinaryExpression *expr) const
620 {
621     ETSGen *etsg = GetETSGen();
622 
623     if (CompileBigInt(etsg, expr)) {
624         return;
625     }
626 
627     if (expr->IsLogical()) {
628         CompileLogical(etsg, expr);
629         return;
630     }
631     if (expr->OperatorType() == lexer::TokenType::KEYW_INSTANCEOF) {
632         CompileInstanceof(etsg, expr);
633         return;
634     }
635 
636     auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType());
637     compiler::RegScope rs(etsg);
638     compiler::VReg lhs = etsg->AllocReg();
639 
640     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS && expr->OperationType()->IsETSStringType()) {
641         etsg->BuildString(expr);
642         return;
643     }
644 
645     expr->CompileOperands(etsg, lhs);
646     if (expr->OperationType()->IsIntType()) {
647         etsg->ApplyCast(expr->Right(), expr->OperationType());
648     }
649 
650     etsg->Binary(expr, expr->OperatorType(), lhs);
651     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
652 }
653 
ConvertRestArguments(checker::ETSChecker * const checker,const ir::CallExpression * expr,checker::Signature * signature)654 static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::CallExpression *expr,
655                                  checker::Signature *signature)
656 {
657     if (signature->RestVar() != nullptr &&
658         (signature->RestVar()->TsType()->IsETSArrayType() || signature->RestVar()->TsType()->IsETSTupleType())) {
659         std::size_t const argumentCount = expr->Arguments().size();
660         std::size_t const parameterCount = signature->Params().size();
661         ES2PANDA_ASSERT(argumentCount >= parameterCount);
662 
663         auto &arguments = const_cast<ArenaVector<ir::Expression *> &>(expr->Arguments());
664         std::size_t i = parameterCount;
665 
666         if (i < argumentCount && expr->Arguments()[i]->IsSpreadElement()) {
667             arguments[i] = expr->Arguments()[i]->AsSpreadElement()->Argument();
668         } else if (i < argumentCount && expr->Arguments()[i]->IsTSAsExpression() &&
669                    expr->Arguments()[i]->AsTSAsExpression()->Expr()->Type() == ir::AstNodeType::SPREAD_ELEMENT) {
670             arguments[i] = expr->Arguments()[i]->AsTSAsExpression()->Expr()->AsSpreadElement()->Argument();
671         } else if (!signature->RestVar()->TsType()->IsETSTupleType()) {
672             ArenaVector<ir::Expression *> elements(checker->Allocator()->Adapter());
673             for (; i < argumentCount; ++i) {
674                 elements.emplace_back(expr->Arguments()[i]);
675             }
676             auto *arrayExpression = checker->AllocNode<ir::ArrayExpression>(std::move(elements), checker->Allocator());
677             ES2PANDA_ASSERT(arrayExpression != nullptr);
678             arrayExpression->SetParent(const_cast<ir::CallExpression *>(expr));
679             auto restType = signature->RestVar()->TsType()->AsETSArrayType();
680             arrayExpression->SetTsType(restType);
681             arrayExpression->SetPreferredType(restType->ElementType());
682             arguments.erase(expr->Arguments().begin() + parameterCount, expr->Arguments().end());
683             arguments.emplace_back(arrayExpression);
684         }
685     }
686 }
687 
Compile(const ir::BlockExpression * expr) const688 void ETSCompiler::Compile(const ir::BlockExpression *expr) const
689 {
690     ETSGen *etsg = GetETSGen();
691 
692     // Nasty hack: current sccope may not be expr's parent scope.
693     // For example. when expr is a field initializer, the current scope will
694     // be a constructor's scope, not the class scope where the field definition resides.
695     auto *oldParent = expr->Scope()->Parent();
696     expr->Scope()->SetParent(const_cast<varbinder::Scope *>(etsg->Scope()));
697 
698     compiler::LocalRegScope lrs(etsg, expr->Scope());
699 
700     etsg->CompileStatements(expr->Statements());
701 
702     expr->Scope()->SetParent(oldParent);
703 }
704 
CompileDynamic(const ir::CallExpression * expr,compiler::VReg & calleeReg) const705 void ETSCompiler::CompileDynamic(const ir::CallExpression *expr, compiler::VReg &calleeReg) const
706 {
707     ETSGen *etsg = GetETSGen();
708     auto callInfo = checker::DynamicCall::ResolveCall(etsg->VarBinder(), expr->Callee());
709     if (callInfo.obj->IsETSImportDeclaration()) {
710         etsg->LoadAccumulatorDynamicModule(expr, callInfo.obj->AsETSImportDeclaration());
711     } else {
712         callInfo.obj->Compile(etsg);
713     }
714     etsg->StoreAccumulator(expr, calleeReg);
715 
716     if (!callInfo.name.empty()) {
717         auto [qnameStart, qnameLen] = LoadDynamicName(etsg, expr, callInfo.name, false);
718         etsg->CallDynamic(ETSGen::CallDynamicData {expr, calleeReg, qnameStart}, qnameLen, expr->Signature(),
719                           expr->Arguments());
720     } else {
721         compiler::VReg dynParam2 = etsg->AllocReg();
722 
723         auto lang = expr->Callee()->TsType()->IsETSDynamicFunctionType()
724                         ? expr->Callee()->TsType()->AsETSDynamicFunctionType()->Language()
725                         : expr->Callee()->TsType()->AsETSDynamicType()->Language();
726         etsg->LoadUndefinedDynamic(expr, lang);
727         etsg->StoreAccumulator(expr, dynParam2);
728         etsg->CallDynamic(ETSGen::CallDynamicData {expr, calleeReg, dynParam2}, expr->Signature(), expr->Arguments());
729     }
730     etsg->SetAccumulatorType(expr->Signature()->ReturnType());
731 
732     if (etsg->GetAccumulatorType() != expr->TsType()) {
733         etsg->ApplyConversion(expr, expr->TsType());
734     }
735 }
736 
EmitCall(const ir::CallExpression * expr,compiler::VReg & calleeReg,checker::Signature * signature) const737 void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &calleeReg,
738                            checker::Signature *signature) const
739 {
740     ETSGen *etsg = GetETSGen();
741     if (expr->Callee()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) {
742         etsg->ApplyConversionAndStoreAccumulator(expr->Callee(), calleeReg, nullptr);
743     }
744     if (signature->HasSignatureFlag(checker::SignatureFlags::STATIC)) {
745         etsg->CallExact(expr, expr->Signature(), expr->Arguments());
746     } else if (expr->Callee()->IsMemberExpression()) {
747         auto me = expr->Callee()->AsMemberExpression();
748         auto obj = me->Object();
749         if (obj->IsSuperExpression()) {
750             etsg->CallExact(expr, signature, calleeReg, expr->Arguments());
751             // NOTE: need to refactor: type of member expression object can be obtained via
752             // me->ObjType() or me->Object()->TsType() and they may differ!!!!
753         } else if (me->ObjType() == etsg->Checker()->GlobalETSObjectType() &&
754                    (etsg->Checker()->GetApparentType(me->Object()->TsType()) != nullptr) &&
755                    (etsg->Checker()->GetApparentType(me->Object()->TsType())->IsETSUnionType())) {
756             etsg->CallByName(expr, signature, calleeReg, expr->Arguments());
757         } else {
758             etsg->CallVirtual(expr, signature, calleeReg, expr->Arguments());
759         }
760     } else {
761         etsg->CallVirtual(expr, signature, calleeReg, expr->Arguments());
762     }
763 
764     etsg->GuardUncheckedType(expr, expr->UncheckedType(), expr->TsType());
765 }
766 
Compile(const ir::CallExpression * expr) const767 void ETSCompiler::Compile(const ir::CallExpression *expr) const
768 {
769     ETSGen *etsg = GetETSGen();
770     compiler::RegScope rs(etsg);
771     compiler::VReg calleeReg = etsg->AllocReg();
772 
773     auto const callee = expr->Callee();
774     checker::Signature *const signature = expr->Signature();
775 
776     ES2PANDA_ASSERT(!callee->TsType()->IsETSArrowType());  // should have been lowered
777 
778     bool const isStatic = signature->HasSignatureFlag(checker::SignatureFlags::STATIC);
779 
780     ConvertRestArguments(const_cast<checker::ETSChecker *>(etsg->Checker()->AsETSChecker()), expr, signature);
781 
782     if (callee->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)) {
783         CompileDynamic(expr, calleeReg);
784     } else if (callee->IsIdentifier()) {
785         if (!isStatic) {
786             etsg->LoadThis(expr);
787             etsg->StoreAccumulator(expr, calleeReg);
788         }
789         EmitCall(expr, calleeReg, signature);
790     } else if (callee->IsMemberExpression()) {
791         if (!isStatic) {
792             callee->AsMemberExpression()->Object()->Compile(etsg);
793             etsg->StoreAccumulator(expr, calleeReg);
794         }
795         EmitCall(expr, calleeReg, signature);
796     } else if (callee->IsSuperExpression() || callee->IsThisExpression()) {
797         ES2PANDA_ASSERT(expr->IsETSConstructorCall());
798         callee->Compile(etsg);  // ctor is not a value!
799         etsg->StoreAccumulator(expr, calleeReg);
800         EmitCall(expr, calleeReg, signature);
801     } else {
802         ES2PANDA_UNREACHABLE();
803     }
804 
805     if (expr->HasBoxingUnboxingFlags(ir::BoxingUnboxingFlags::UNBOXING_FLAG | ir::BoxingUnboxingFlags::BOXING_FLAG)) {
806         etsg->ApplyConversion(expr, expr->TsType());
807     }
808 }
809 
Compile(const ir::ConditionalExpression * expr) const810 void ETSCompiler::Compile(const ir::ConditionalExpression *expr) const
811 {
812     ETSGen *etsg = GetETSGen();
813 
814     auto *falseLabel = etsg->AllocLabel();
815     auto *endLabel = etsg->AllocLabel();
816 
817     compiler::Condition::Compile(etsg, expr->Test(), falseLabel);
818 
819     auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
820 
821     expr->Consequent()->Compile(etsg);
822     etsg->ApplyConversion(expr->Consequent());
823     etsg->Branch(expr, endLabel);
824 
825     etsg->SetLabel(expr, falseLabel);
826     expr->Alternate()->Compile(etsg);
827     etsg->ApplyConversion(expr->Alternate());
828 
829     etsg->SetLabel(expr, endLabel);
830     etsg->ApplyConversion(expr, expr->TsType());
831     etsg->SetAccumulatorType(expr->TsType());
832 }
833 
Compile(const ir::Identifier * expr) const834 void ETSCompiler::Compile(const ir::Identifier *expr) const
835 {
836     ETSGen *etsg = GetETSGen();
837 
838     auto const *smartType = expr->TsType();
839     ES2PANDA_ASSERT(smartType != nullptr);
840     if (smartType->IsETSTypeParameter() || smartType->IsETSPartialTypeParameter() || smartType->IsETSNonNullishType()) {
841         smartType = etsg->Checker()->GetApparentType(smartType);
842     }
843     auto ttctx = compiler::TargetTypeContext(etsg, smartType);
844 
845     ES2PANDA_ASSERT(expr->Variable() != nullptr);
846     if (!expr->Variable()->HasFlag(varbinder::VariableFlags::TYPE_ALIAS)) {
847         etsg->LoadVar(expr, expr->Variable());
848     }
849 
850     if (smartType->IsETSReferenceType()) {
851         //  In case when smart cast type of identifier differs from initial variable type perform cast if required
852         if (!etsg->Checker()->AsETSChecker()->Relation()->IsSupertypeOf(smartType, etsg->GetAccumulatorType())) {
853             etsg->CastToReftype(expr, smartType, false);
854         }
855     } else if (smartType->IsETSPrimitiveType()) {
856         etsg->ApplyConversionCast(expr, smartType);
857     }
858     etsg->SetAccumulatorType(smartType);
859 }
860 
LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen * etsg,const ir::MemberExpression * expr,compiler::VReg objReg)861 static void LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::MemberExpression *expr,
862                                              compiler::VReg objReg)
863 {
864     if (etsg->Checker()->AsETSChecker()->Relation()->IsSupertypeOf(etsg->Checker()->GlobalBuiltinETSStringType(),
865                                                                    expr->Property()->TsType())) {
866         etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, expr->Property());
867     } else {
868         etsg->LoadElementDynamic(expr, objReg);
869     }
870 }
871 
CompileComputed(compiler::ETSGen * etsg,const ir::MemberExpression * expr)872 bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpression *expr)
873 {
874     if (!expr->IsComputed()) {
875         return false;
876     }
877     auto *const objectType = expr->Object()->TsType();
878 
879     auto ottctx = compiler::TargetTypeContext(etsg, objectType);
880     etsg->CompileAndCheck(expr->Object());
881 
882     compiler::VReg objReg = etsg->AllocReg();
883     etsg->StoreAccumulator(expr, objReg);
884 
885     auto pttctx = compiler::TargetTypeContext(etsg, expr->Property()->TsType());
886 
887     etsg->CompileAndCheck(expr->Property());
888     etsg->ApplyConversion(expr->Property(), expr->Property()->TsType());
889 
890     auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
891 
892     if (objectType->IsETSTupleType()) {
893         ES2PANDA_ASSERT(expr->GetTupleIndexValue().has_value());
894         auto indexValue = *expr->GetTupleIndexValue();
895         auto *tupleElementType = objectType->AsETSTupleType()->GetTypeAtIndex(indexValue);
896         etsg->LoadTupleElement(expr, objReg, tupleElementType, indexValue);
897     } else if (objectType->IsETSDynamicType()) {
898         LoadETSDynamicTypeFromMemberExpr(etsg, expr, objReg);
899     } else {
900         ES2PANDA_ASSERT(objectType->IsETSArrayType());
901         etsg->LoadArrayElement(expr, objReg);
902     }
903 
904     etsg->GuardUncheckedType(expr, expr->UncheckedType(), expr->TsType());
905     etsg->ApplyConversion(expr);
906 
907     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
908     return true;
909 }
910 
Compile(const ir::MemberExpression * expr) const911 void ETSCompiler::Compile(const ir::MemberExpression *expr) const
912 {
913     ETSGen *etsg = GetETSGen();
914 
915     compiler::RegScope rs(etsg);
916 
917     if (CompileComputed(etsg, expr)) {
918         return;
919     }
920 
921     if (HandleArrayTypeLengthProperty(expr, etsg)) {
922         return;
923     }
924 
925     if (HandleStaticProperties(expr, etsg)) {
926         return;
927     }
928 
929     auto *const objectType = etsg->Checker()->GetApparentType(expr->Object()->TsType());
930     auto &propName = expr->Property()->AsIdentifier()->Name();
931 
932     auto ottctx = compiler::TargetTypeContext(etsg, expr->Object()->TsType());
933     etsg->CompileAndCheck(expr->Object());
934 
935     etsg->ApplyConversion(expr->Object());
936     compiler::VReg objReg = etsg->AllocReg();
937     etsg->StoreAccumulator(expr, objReg);
938 
939     auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
940     ES2PANDA_ASSERT(expr->PropVar()->TsType() != nullptr);
941     const checker::Type *const variableType = expr->PropVar()->TsType();
942     if (variableType->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) {
943         if (expr->Object()->IsSuperExpression()) {
944             etsg->CallExact(expr, variableType->AsETSFunctionType()->FindGetter()->InternalName(), objReg);
945         } else {
946             etsg->CallVirtual(expr, variableType->AsETSFunctionType()->FindGetter(), objReg);
947         }
948     } else if (objectType->IsETSDynamicType()) {
949         etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, propName);
950     } else if (objectType->IsETSUnionType()) {
951         etsg->LoadPropertyByName(expr, objReg, checker::ETSChecker::FormNamedAccessMetadata(expr->PropVar()));
952     } else {
953         const auto fullName = etsg->FormClassPropReference(objectType->AsETSObjectType(), propName);
954         etsg->LoadProperty(expr, variableType, objReg, fullName);
955     }
956     etsg->GuardUncheckedType(expr, expr->UncheckedType(), expr->TsType());
957 
958     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
959 }
960 
HandleArrayTypeLengthProperty(const ir::MemberExpression * expr,ETSGen * etsg) const961 bool ETSCompiler::HandleArrayTypeLengthProperty(const ir::MemberExpression *expr, ETSGen *etsg) const
962 {
963     auto *const objectType = etsg->Checker()->GetApparentType(expr->Object()->TsType());
964     ES2PANDA_ASSERT(objectType != nullptr);
965     auto &propName = expr->Property()->AsIdentifier()->Name();
966     if (objectType->IsETSArrayType() && propName.Is("length")) {
967         auto ottctx = compiler::TargetTypeContext(etsg, objectType);
968         etsg->CompileAndCheck(expr->Object());
969 
970         compiler::VReg objReg = etsg->AllocReg();
971         etsg->StoreAccumulator(expr, objReg);
972 
973         auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
974         etsg->LoadArrayLength(expr, objReg);
975         etsg->ApplyConversion(expr, expr->TsType());
976         return true;
977     }
978     return false;
979 }
980 
HandleStaticProperties(const ir::MemberExpression * expr,ETSGen * etsg) const981 bool ETSCompiler::HandleStaticProperties(const ir::MemberExpression *expr, ETSGen *etsg) const
982 {
983     if (auto const *const variable = expr->PropVar(); checker::ETSChecker::IsVariableStatic(variable)) {
984         auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
985 
986         if (auto const *const varType = variable->TsType(); varType->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) {
987             checker::Signature *sig = varType->AsETSFunctionType()->FindGetter();
988             ES2PANDA_ASSERT(sig != nullptr);
989             etsg->CallExact(expr, sig->InternalName());
990             etsg->SetAccumulatorType(expr->TsType());
991         } else {
992             util::StringView const fullName =
993                 etsg->FormClassPropReference(expr->Object()->TsType()->AsETSObjectType(), variable->Name());
994             etsg->LoadStaticProperty(expr, varType, fullName);
995             etsg->ApplyConversion(expr, expr->TsType());
996         }
997 
998         ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
999 
1000         return true;
1001     }
1002 
1003     return false;
1004 }
1005 
Compile(const ir::ObjectExpression * expr) const1006 void ETSCompiler::Compile(const ir::ObjectExpression *expr) const
1007 {
1008     ETSGen *etsg = GetETSGen();
1009     compiler::RegScope rs {etsg};
1010     compiler::VReg objReg = etsg->AllocReg();
1011 
1012     // NOTE: object expressions of dynamic type are not handled in objectLiteralLowering phase
1013     ES2PANDA_ASSERT(expr->TsType()->IsETSDynamicType());
1014 
1015     auto *signatureInfo = etsg->Allocator()->New<checker::SignatureInfo>(etsg->Allocator());
1016     auto *createObjSig = etsg->Allocator()->New<checker::Signature>(signatureInfo, nullptr, nullptr);
1017     ES2PANDA_ASSERT(createObjSig != nullptr);
1018     createObjSig->SetInternalName(compiler::Signatures::BUILTIN_JSRUNTIME_CREATE_OBJECT);
1019     compiler::VReg dummyReg = compiler::VReg::RegStart();
1020     etsg->CallDynamic(ETSGen::CallDynamicData {expr, dummyReg, dummyReg}, createObjSig,
1021                       ArenaVector<ir::Expression *>(etsg->Allocator()->Adapter()));
1022 
1023     etsg->SetAccumulatorType(expr->TsType());
1024     etsg->StoreAccumulator(expr, objReg);
1025 
1026     for (ir::Expression *propExpr : expr->Properties()) {
1027         ES2PANDA_ASSERT(propExpr->IsProperty());
1028         ir::Property *prop = propExpr->AsProperty();
1029         ir::Expression *key = prop->Key();
1030         ir::Expression *value = prop->Value();
1031 
1032         util::StringView pname;
1033         if (key->IsStringLiteral()) {
1034             pname = key->AsStringLiteral()->Str();
1035         } else if (key->IsIdentifier()) {
1036             pname = key->AsIdentifier()->Name();
1037         } else {
1038             ES2PANDA_UNREACHABLE();
1039         }
1040 
1041         value->Compile(etsg);
1042         etsg->ApplyConversion(value, key->TsType());
1043         if (expr->TsType()->IsETSDynamicType()) {
1044             etsg->StorePropertyDynamic(expr, value->TsType(), objReg, pname);
1045         } else {
1046             etsg->StoreProperty(expr, key->TsType(), objReg, pname);
1047         }
1048     }
1049 
1050     etsg->LoadAccumulator(expr, objReg);
1051     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1052 }
1053 
Compile(const ir::SequenceExpression * expr) const1054 void ETSCompiler::Compile(const ir::SequenceExpression *expr) const
1055 {
1056     ETSGen *etsg = GetETSGen();
1057     for (const auto *it : expr->Sequence()) {
1058         it->Compile(etsg);
1059     }
1060 }
1061 
Compile(const ir::SuperExpression * expr) const1062 void ETSCompiler::Compile(const ir::SuperExpression *expr) const
1063 {
1064     ETSGen *etsg = GetETSGen();
1065     etsg->LoadThis(expr);
1066     etsg->SetAccumulatorType(etsg->GetAccumulatorType()->AsETSObjectType()->SuperType());
1067     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1068 }
1069 
Compile(const ir::TemplateLiteral * expr) const1070 void ETSCompiler::Compile(const ir::TemplateLiteral *expr) const
1071 {
1072     ETSGen *etsg = GetETSGen();
1073     etsg->BuildTemplateString(expr);
1074     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1075 }
1076 
Compile(const ir::ThisExpression * expr) const1077 void ETSCompiler::Compile(const ir::ThisExpression *expr) const
1078 {
1079     ETSGen *etsg = GetETSGen();
1080     etsg->LoadThis(expr);
1081     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1082 }
1083 
Compile(const ir::TypeofExpression * expr) const1084 void ETSCompiler::Compile([[maybe_unused]] const ir::TypeofExpression *expr) const
1085 {
1086     ETSGen *etsg = GetETSGen();
1087     ir::Expression *arg = expr->Argument();
1088     arg->Compile(etsg);
1089     if (expr->TsType()->IsETSStringType() && expr->TsType()->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
1090         etsg->LoadAccumulatorString(expr, expr->TsType()->AsETSStringType()->GetValue());
1091         return;
1092     }
1093     auto argReg = etsg->AllocReg();
1094     etsg->StoreAccumulator(expr, argReg);
1095     etsg->EmitEtsTypeof(expr, argReg);
1096     etsg->SetAccumulatorType(expr->TsType());
1097 }
1098 
Compile(const ir::UnaryExpression * expr) const1099 void ETSCompiler::Compile(const ir::UnaryExpression *expr) const
1100 {
1101     ETSGen *etsg = GetETSGen();
1102     auto ttctx = compiler::TargetTypeContext(etsg, expr->Argument()->TsType());
1103 
1104     expr->Argument()->Compile(etsg);
1105     etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType());
1106 
1107     etsg->Unary(expr, expr->OperatorType());
1108     etsg->ApplyConversion(expr, expr->TsType());
1109 
1110     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1111 }
1112 
Compile(const ir::BigIntLiteral * expr) const1113 void ETSCompiler::Compile([[maybe_unused]] const ir::BigIntLiteral *expr) const
1114 {
1115     ETSGen *etsg = GetETSGen();
1116     compiler::TargetTypeContext ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
1117     compiler::RegScope rs {etsg};
1118     etsg->LoadAccumulatorBigInt(expr, expr->Str());
1119     const compiler::VReg value = etsg->AllocReg();
1120     etsg->StoreAccumulator(expr, value);
1121     etsg->CreateBigIntObject(expr, value);
1122     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1123 }
1124 
Compile(const ir::BooleanLiteral * expr) const1125 void ETSCompiler::Compile(const ir::BooleanLiteral *expr) const
1126 {
1127     ETSGen *etsg = GetETSGen();
1128     etsg->LoadAccumulatorBoolean(expr, expr->Value());
1129     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1130 }
1131 
Compile(const ir::CharLiteral * expr) const1132 void ETSCompiler::Compile(const ir::CharLiteral *expr) const
1133 {
1134     ETSGen *etsg = GetETSGen();
1135     etsg->LoadAccumulatorChar(expr, expr->Char());
1136     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1137 }
1138 
Compile(const ir::NullLiteral * expr) const1139 void ETSCompiler::Compile(const ir::NullLiteral *expr) const
1140 {
1141     ETSGen *etsg = GetETSGen();
1142     etsg->LoadAccumulatorNull(expr);
1143 }
1144 
Compile(const ir::NumberLiteral * expr) const1145 void ETSCompiler::Compile(const ir::NumberLiteral *expr) const
1146 {
1147     ETSGen *etsg = GetETSGen();
1148     auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType());
1149 
1150     if (expr->Number().IsInt()) {
1151         if (util::Helpers::IsTargetFitInSourceRange<checker::ByteType::UType, checker::IntType::UType>(
1152                 expr->Number().GetInt())) {  // CC-OFF(G.FMT.06-CPP) project code style
1153             etsg->LoadAccumulatorByte(expr, static_cast<int8_t>(expr->Number().GetInt()));
1154         } else if (util::Helpers::IsTargetFitInSourceRange<checker::ShortType::UType, checker::IntType::UType>(
1155                        expr->Number().GetInt())) {  // CC-OFF(G.FMT.06-CPP) project code style
1156             etsg->LoadAccumulatorShort(expr, static_cast<int16_t>(expr->Number().GetInt()));
1157         } else {
1158             etsg->LoadAccumulatorInt(expr, static_cast<int32_t>(expr->Number().GetInt()));
1159         }
1160     } else if (expr->Number().IsLong()) {
1161         etsg->LoadAccumulatorWideInt(expr, expr->Number().GetLong());
1162     } else if (expr->Number().IsFloat()) {
1163         etsg->LoadAccumulatorFloat(expr, expr->Number().GetFloat());
1164     } else {
1165         etsg->LoadAccumulatorDouble(expr, expr->Number().GetDouble());
1166     }
1167 
1168     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType()));
1169 }
1170 
Compile(const ir::StringLiteral * expr) const1171 void ETSCompiler::Compile(const ir::StringLiteral *expr) const
1172 {
1173     ETSGen *etsg = GetETSGen();
1174     etsg->LoadAccumulatorString(expr, expr->Str());
1175     etsg->SetAccumulatorType(expr->TsType());
1176 }
1177 
Compile(const ir::AssertStatement * st) const1178 void ETSCompiler::Compile([[maybe_unused]] const ir::AssertStatement *st) const
1179 {
1180     ES2PANDA_UNREACHABLE();
1181 }
1182 
Compile(const ir::BlockStatement * st) const1183 void ETSCompiler::Compile(const ir::BlockStatement *st) const
1184 {
1185     ETSGen *etsg = GetETSGen();
1186     compiler::LocalRegScope lrs(etsg, st->Scope());
1187 
1188     etsg->CompileStatements(st->Statements());
1189 }
1190 
1191 template <typename CodeGen>
CompileImpl(const ir::BreakStatement * self,CodeGen * cg)1192 static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg)
1193 {
1194     compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident());
1195     cg->Branch(self, target);
1196 }
1197 
Compile(const ir::BreakStatement * st) const1198 void ETSCompiler::Compile(const ir::BreakStatement *st) const
1199 {
1200     ETSGen *etsg = GetETSGen();
1201     if (etsg->ExtendWithFinalizer(st->Parent(), st)) {
1202         return;
1203     }
1204     CompileImpl(st, etsg);
1205 }
1206 
Compile(const ir::ClassDeclaration * st) const1207 void ETSCompiler::Compile([[maybe_unused]] const ir::ClassDeclaration *st) const {}
Compile(const ir::AnnotationDeclaration * st) const1208 void ETSCompiler::Compile([[maybe_unused]] const ir::AnnotationDeclaration *st) const {}
Compile(const ir::AnnotationUsage * st) const1209 void ETSCompiler::Compile([[maybe_unused]] const ir::AnnotationUsage *st) const {}
1210 
CompileImpl(const ir::ContinueStatement * self,ETSGen * etsg)1211 static void CompileImpl(const ir::ContinueStatement *self, ETSGen *etsg)
1212 {
1213     compiler::Label *target = etsg->ControlFlowChangeContinue(self->Ident());
1214     etsg->Branch(self, target);
1215 }
1216 
Compile(const ir::ContinueStatement * st) const1217 void ETSCompiler::Compile(const ir::ContinueStatement *st) const
1218 {
1219     ETSGen *etsg = GetETSGen();
1220     if (etsg->ExtendWithFinalizer(st->Parent(), st)) {
1221         return;
1222     }
1223     CompileImpl(st, etsg);
1224 }
1225 
CompileImpl(const ir::DoWhileStatement * self,ETSGen * etsg)1226 void CompileImpl(const ir::DoWhileStatement *self, ETSGen *etsg)
1227 {
1228     auto *startLabel = etsg->AllocLabel();
1229     compiler::LabelTarget labelTarget(etsg);
1230 
1231     etsg->SetLabel(self, startLabel);
1232 
1233     {
1234         compiler::LocalRegScope regScope(etsg, self->Scope());
1235         compiler::LabelContext labelCtx(etsg, labelTarget);
1236         self->Body()->Compile(etsg);
1237     }
1238 
1239     etsg->SetLabel(self, labelTarget.ContinueTarget());
1240     compiler::Condition::Compile(etsg, self->Test(), labelTarget.BreakTarget());
1241 
1242     etsg->Branch(self, startLabel);
1243     etsg->SetLabel(self, labelTarget.BreakTarget());
1244 }
1245 
Compile(const ir::DoWhileStatement * st) const1246 void ETSCompiler::Compile(const ir::DoWhileStatement *st) const
1247 {
1248     ETSGen *etsg = GetETSGen();
1249     CompileImpl(st, etsg);
1250 }
1251 
Compile(const ir::EmptyStatement * st) const1252 void ETSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {}
1253 
Compile(const ir::ExpressionStatement * st) const1254 void ETSCompiler::Compile(const ir::ExpressionStatement *st) const
1255 {
1256     ETSGen *etsg = GetETSGen();
1257     st->GetExpression()->Compile(etsg);
1258 }
1259 
Compile(const ir::ForOfStatement * st) const1260 void ETSCompiler::Compile(const ir::ForOfStatement *st) const
1261 {
1262     ETSGen *etsg = GetETSGen();
1263     compiler::LocalRegScope declRegScope(etsg, st->Scope()->DeclScope()->InitScope());
1264 
1265     checker::Type const *const exprType = st->Right()->TsType();
1266     ES2PANDA_ASSERT(exprType->IsETSResizableArrayType() || exprType->IsETSArrayType() || exprType->IsETSStringType() ||
1267                     exprType->IsETSUnionType());
1268 
1269     st->Right()->Compile(etsg);
1270     compiler::VReg objReg = etsg->AllocReg();
1271     etsg->StoreAccumulator(st, objReg);
1272 
1273     GetSizeInForOf(etsg, exprType, st, objReg);
1274 
1275     compiler::VReg sizeReg = etsg->AllocReg();
1276     etsg->StoreAccumulator(st, sizeReg);
1277 
1278     compiler::LabelTarget labelTarget(etsg);
1279     auto labelCtx = compiler::LabelContext(etsg, labelTarget);
1280 
1281     etsg->BranchIfFalse(st, labelTarget.BreakTarget());
1282 
1283     compiler::VReg countReg = etsg->AllocReg();
1284     etsg->MoveImmediateToRegister(st, countReg, checker::TypeFlag::INT, static_cast<std::int32_t>(0));
1285     etsg->LoadAccumulatorInt(st, static_cast<std::int32_t>(0));
1286 
1287     auto *const startLabel = etsg->AllocLabel();
1288     etsg->SetLabel(st, startLabel);
1289 
1290     auto lref = compiler::ETSLReference::Create(etsg, st->Left(), false);
1291 
1292     if (exprType->IsETSArrayType()) {
1293         etsg->LoadArrayElement(st, objReg);
1294     } else if (exprType->IsETSUnionType()) {
1295         HandleUnionTypeInForOf(etsg, exprType, st, objReg, &countReg);
1296     } else {
1297         etsg->LoadStringChar(st, objReg, countReg);
1298     }
1299 
1300     lref.SetValue();
1301     st->Body()->Compile(etsg);
1302 
1303     etsg->SetLabel(st, labelTarget.ContinueTarget());
1304 
1305     etsg->IncrementImmediateRegister(st, countReg, checker::TypeFlag::INT, static_cast<std::int32_t>(1));
1306     etsg->LoadAccumulator(st, countReg);
1307 
1308     etsg->JumpCompareRegister<compiler::Jlt>(st, sizeReg, startLabel);
1309     etsg->SetLabel(st, labelTarget.BreakTarget());
1310 }
1311 
Compile(const ir::ForUpdateStatement * st) const1312 void ETSCompiler::Compile(const ir::ForUpdateStatement *st) const
1313 {
1314     ETSGen *etsg = GetETSGen();
1315     compiler::LocalRegScope declRegScope(etsg, st->Scope()->DeclScope()->InitScope());
1316 
1317     if (st->Init() != nullptr) {
1318         ES2PANDA_ASSERT(st->Init()->IsVariableDeclaration() || st->Init()->IsExpression());
1319         st->Init()->Compile(etsg);
1320     }
1321 
1322     auto *startLabel = etsg->AllocLabel();
1323     compiler::LabelTarget labelTarget(etsg);
1324     auto labelCtx = compiler::LabelContext(etsg, labelTarget);
1325     etsg->SetLabel(st, startLabel);
1326 
1327     {
1328         compiler::LocalRegScope regScope(etsg, st->Scope());
1329 
1330         if (st->Test() != nullptr) {
1331             compiler::Condition::Compile(etsg, st->Test(), labelTarget.BreakTarget());
1332         }
1333 
1334         st->Body()->Compile(etsg);
1335         etsg->SetLabel(st, labelTarget.ContinueTarget());
1336     }
1337 
1338     if (st->Update() != nullptr) {
1339         st->Update()->Compile(etsg);
1340     }
1341 
1342     etsg->Branch(st, startLabel);
1343     etsg->SetLabel(st, labelTarget.BreakTarget());
1344 }
1345 
Compile(const ir::IfStatement * st) const1346 void ETSCompiler::Compile(const ir::IfStatement *st) const
1347 {
1348     ETSGen *etsg = GetETSGen();
1349 
1350     auto *consequentEnd = etsg->AllocLabel();
1351     compiler::Label *statementEnd = consequentEnd;
1352 
1353     compiler::Condition::Compile(etsg, st->Test(), consequentEnd);
1354 
1355     st->Consequent()->Compile(etsg);
1356 
1357     if (st->Alternate() != nullptr) {
1358         statementEnd = etsg->AllocLabel();
1359         etsg->Branch(etsg->Insns().back()->Node(), statementEnd);
1360 
1361         etsg->SetLabel(st, consequentEnd);
1362         st->Alternate()->Compile(etsg);
1363     }
1364 
1365     etsg->SetLabel(st, statementEnd);
1366 }
1367 
CompileImpl(const ir::LabelledStatement * self,ETSGen * cg)1368 void CompileImpl(const ir::LabelledStatement *self, ETSGen *cg)
1369 {
1370     compiler::LabelContext labelCtx(cg, self);
1371     self->Body()->Compile(cg);
1372 }
1373 
Compile(const ir::LabelledStatement * st) const1374 void ETSCompiler::Compile(const ir::LabelledStatement *st) const
1375 {
1376     ETSGen *etsg = GetETSGen();
1377     CompileImpl(st, etsg);
1378 }
1379 
Compile(const ir::ReturnStatement * st) const1380 void ETSCompiler::Compile(const ir::ReturnStatement *st) const
1381 {
1382     ETSGen *etsg = GetETSGen();
1383 
1384     bool isAsyncImpl = st->IsAsyncImplReturn();
1385     auto *const argument = st->Argument();
1386 
1387     if (argument == nullptr) {
1388         if (etsg->ExtendWithFinalizer(st->Parent(), st)) {
1389             return;
1390         }
1391 
1392         if (etsg->CheckControlFlowChange()) {
1393             etsg->ControlFlowChangeBreak();
1394         }
1395 
1396         if (isAsyncImpl) {
1397             etsg->LoadAccumulatorUndefined(st);
1398             etsg->ReturnAcc(st);
1399             return;
1400         }
1401 
1402         etsg->EmitReturnVoid(st);
1403 
1404         return;
1405     }
1406 
1407     if (argument->IsCallExpression() && argument->AsCallExpression()->Signature()->ReturnType()->IsETSVoidType()) {
1408         argument->Compile(etsg);
1409 
1410         if (etsg->ReturnType()->IsETSVoidType()) {
1411             if (isAsyncImpl) {
1412                 etsg->LoadAccumulatorUndefined(st);
1413                 etsg->ReturnAcc(st);
1414             } else {
1415                 etsg->EmitReturnVoid(st);
1416             }
1417         } else {
1418             etsg->LoadDefaultValue(st, etsg->ReturnType());
1419             etsg->ReturnAcc(st);
1420         }
1421         return;
1422     }
1423 
1424     auto ttctx = compiler::TargetTypeContext(etsg, etsg->ReturnType());
1425     argument->Compile(etsg);
1426     etsg->ApplyConversion(argument, etsg->ReturnType());
1427 
1428     if (etsg->ExtendWithFinalizer(st->Parent(), st)) {
1429         return;
1430     }
1431 
1432     if (etsg->CheckControlFlowChange()) {
1433         compiler::RegScope rs(etsg);
1434         compiler::VReg res = etsg->AllocReg();
1435 
1436         etsg->StoreAccumulator(st, res);
1437         etsg->ControlFlowChangeBreak();
1438         etsg->LoadAccumulator(st, res);
1439     }
1440 
1441     etsg->ReturnAcc(st);
1442 }
1443 
CompileImpl(const ir::SwitchStatement * self,ETSGen * etsg)1444 static void CompileImpl(const ir::SwitchStatement *self, ETSGen *etsg)
1445 {
1446     compiler::LocalRegScope lrs(etsg, self->Scope());
1447     compiler::SwitchBuilder builder(etsg, self);
1448     compiler::VReg tag = etsg->AllocReg();
1449 
1450     builder.CompileTagOfSwitch(tag);
1451     uint32_t defaultIndex = 0;
1452 
1453     for (size_t i = 0; i < self->Cases().size(); i++) {
1454         const auto *clause = self->Cases()[i];
1455 
1456         if (clause->Test() == nullptr) {
1457             defaultIndex = i;
1458             continue;
1459         }
1460 
1461         builder.JumpIfCase(tag, i);
1462     }
1463 
1464     if (defaultIndex > 0) {
1465         builder.JumpToDefault(defaultIndex);
1466     } else {
1467         builder.Break();
1468     }
1469 
1470     for (size_t i = 0; i < self->Cases().size(); i++) {
1471         builder.SetCaseTarget(i);
1472         builder.CompileCaseStatements(i);
1473     }
1474 }
1475 
Compile(const ir::SwitchStatement * st) const1476 void ETSCompiler::Compile(const ir::SwitchStatement *st) const
1477 {
1478     ETSGen *etsg = GetETSGen();
1479     CompileImpl(st, etsg);
1480 }
1481 
Compile(const ir::ThrowStatement * st) const1482 void ETSCompiler::Compile(const ir::ThrowStatement *st) const
1483 {
1484     ETSGen *etsg = GetETSGen();
1485     etsg->ThrowException(st->Argument());
1486 }
1487 
Compile(const ir::TryStatement * st) const1488 void ETSCompiler::Compile(const ir::TryStatement *st) const
1489 {
1490     ETSGen *etsg = GetETSGen();
1491 
1492     compiler::ETSTryContext tryCtx(etsg, etsg->Allocator(), st, st->FinallyBlock() != nullptr);
1493 
1494     compiler::LabelPair tryLabelPair(etsg->AllocLabel(), etsg->AllocLabel());
1495 
1496     for (ir::CatchClause *clause : st->CatchClauses()) {
1497         tryCtx.AddNewCathTable(clause->TsType()->AsETSObjectType()->AssemblerName(), tryLabelPair);
1498     }
1499 
1500     compiler::Label *statementEnd = etsg->AllocLabel();
1501     auto catchTables = tryCtx.GetETSCatchTable();
1502 
1503     etsg->SetLabel(st, tryLabelPair.Begin());
1504     st->Block()->Compile(etsg);
1505     etsg->Branch(st, statementEnd);
1506     etsg->SetLabel(st, tryLabelPair.End());
1507 
1508     ES2PANDA_ASSERT(st->CatchClauses().size() == catchTables.size());
1509 
1510     for (uint32_t i = 0; i < st->CatchClauses().size(); i++) {
1511         etsg->SetLabel(st, catchTables.at(i)->LabelSet().CatchBegin());
1512 
1513         st->CatchClauses().at(i)->Compile(etsg);
1514 
1515         etsg->Branch(st, statementEnd);
1516     }
1517 
1518     etsg->SetLabel(st, statementEnd);
1519 
1520     auto trycatchLabelPair = compiler::LabelPair(tryLabelPair.Begin(), statementEnd);
1521 
1522     tryCtx.EmitFinalizer(trycatchLabelPair, st->finalizerInsertions_);
1523 }
1524 
Compile(const ir::VariableDeclarator * st) const1525 void ETSCompiler::Compile(const ir::VariableDeclarator *st) const
1526 {
1527     ETSGen *etsg = GetETSGen();
1528     auto lref = compiler::ETSLReference::Create(etsg, st->Id(), true);
1529     auto ttctx = compiler::TargetTypeContext(etsg, st->TsType());
1530 
1531     if (st->Init() != nullptr) {
1532         st->Init()->Compile(etsg);
1533         etsg->ApplyConversion(st->Init(), st->Id()->AsIdentifier()->Variable()->TsType());
1534     } else {
1535         etsg->LoadDefaultValue(st, st->Id()->AsIdentifier()->Variable()->TsType());
1536     }
1537 
1538     etsg->ApplyConversion(st, st->TsType());
1539     lref.SetValue();
1540 }
1541 
Compile(const ir::VariableDeclaration * st) const1542 void ETSCompiler::Compile(const ir::VariableDeclaration *st) const
1543 {
1544     ETSGen *etsg = GetETSGen();
1545     for (const auto *it : st->Declarators()) {
1546         it->Compile(etsg);
1547     }
1548 }
1549 
1550 template <typename CodeGen>
CompileImpl(const ir::WhileStatement * whileStmt,CodeGen * cg)1551 void CompileImpl(const ir::WhileStatement *whileStmt, [[maybe_unused]] CodeGen *cg)
1552 {
1553     compiler::LabelTarget labelTarget(cg);
1554 
1555     cg->SetLabel(whileStmt, labelTarget.ContinueTarget());
1556     compiler::Condition::Compile(cg, whileStmt->Test(), labelTarget.BreakTarget());
1557 
1558     {
1559         compiler::LocalRegScope regScope(cg, whileStmt->Scope());
1560         compiler::LabelContext labelCtx(cg, labelTarget);
1561         whileStmt->Body()->Compile(cg);
1562     }
1563 
1564     cg->Branch(whileStmt, labelTarget.ContinueTarget());
1565     cg->SetLabel(whileStmt, labelTarget.BreakTarget());
1566 }
1567 
Compile(const ir::WhileStatement * st) const1568 void ETSCompiler::Compile(const ir::WhileStatement *st) const
1569 {
1570     ETSGen *etsg = GetETSGen();
1571     CompileImpl(st, etsg);
1572 }
1573 
Compile(const ir::TSArrayType * node) const1574 void ETSCompiler::Compile(const ir::TSArrayType *node) const
1575 {
1576     ETSGen *etsg = GetETSGen();
1577     etsg->LoadAccumulatorPoison(node, node->TsType());
1578 }
1579 
CompileCastUnboxable(const ir::TSAsExpression * expr) const1580 void ETSCompiler::CompileCastUnboxable(const ir::TSAsExpression *expr) const
1581 {
1582     ETSGen *etsg = GetETSGen();
1583     auto *targetType = etsg->Checker()->GetApparentType(expr->TsType());
1584     ES2PANDA_ASSERT(targetType != nullptr && targetType->IsETSObjectType());
1585 
1586     switch (targetType->AsETSObjectType()->UnboxableKind()) {
1587         case checker::ETSObjectFlags::BUILTIN_BOOLEAN:
1588             etsg->CastToBoolean(expr);
1589             break;
1590         case checker::ETSObjectFlags::BUILTIN_BYTE:
1591             etsg->CastToByte(expr);
1592             break;
1593         case checker::ETSObjectFlags::BUILTIN_CHAR:
1594             etsg->CastToChar(expr);
1595             break;
1596         case checker::ETSObjectFlags::BUILTIN_SHORT:
1597             etsg->CastToShort(expr);
1598             break;
1599         case checker::ETSObjectFlags::BUILTIN_INT:
1600             etsg->CastToInt(expr);
1601             break;
1602         case checker::ETSObjectFlags::BUILTIN_LONG:
1603             etsg->CastToLong(expr);
1604             break;
1605         case checker::ETSObjectFlags::BUILTIN_FLOAT:
1606             etsg->CastToFloat(expr);
1607             break;
1608         case checker::ETSObjectFlags::BUILTIN_DOUBLE:
1609             etsg->CastToDouble(expr);
1610             break;
1611         default:
1612             ES2PANDA_UNREACHABLE();
1613     }
1614 }
1615 
CompileCastPrimitives(const ir::TSAsExpression * expr) const1616 void ETSCompiler::CompileCastPrimitives(const ir::TSAsExpression *expr) const
1617 {
1618     ETSGen *etsg = GetETSGen();
1619     auto *targetType = etsg->Checker()->GetApparentType(expr->TsType());
1620 
1621     switch (checker::ETSChecker::TypeKind(targetType)) {
1622         case checker::TypeFlag::ETS_BOOLEAN: {
1623             etsg->CastToBoolean(expr);
1624             break;
1625         }
1626         case checker::TypeFlag::CHAR: {
1627             etsg->CastToChar(expr);
1628             break;
1629         }
1630         case checker::TypeFlag::BYTE: {
1631             etsg->CastToByte(expr);
1632             break;
1633         }
1634         case checker::TypeFlag::SHORT: {
1635             etsg->CastToShort(expr);
1636             break;
1637         }
1638         case checker::TypeFlag::INT: {
1639             etsg->CastToInt(expr);
1640             break;
1641         }
1642         case checker::TypeFlag::LONG: {
1643             etsg->CastToLong(expr);
1644             break;
1645         }
1646         case checker::TypeFlag::FLOAT: {
1647             etsg->CastToFloat(expr);
1648             break;
1649         }
1650         case checker::TypeFlag::DOUBLE: {
1651             etsg->CastToDouble(expr);
1652             break;
1653         }
1654         default: {
1655             ES2PANDA_UNREACHABLE();
1656         }
1657     }
1658 }
1659 
CompileCast(const ir::TSAsExpression * expr) const1660 void ETSCompiler::CompileCast(const ir::TSAsExpression *expr) const
1661 {
1662     ETSGen *etsg = GetETSGen();
1663     auto *targetType = etsg->Checker()->GetApparentType(expr->TsType());
1664 
1665     switch (checker::ETSChecker::TypeKind(targetType)) {
1666         case checker::TypeFlag::ETS_ARRAY:
1667         case checker::TypeFlag::ETS_TUPLE:
1668         case checker::TypeFlag::FUNCTION:
1669         case checker::TypeFlag::ETS_OBJECT:
1670         case checker::TypeFlag::ETS_TYPE_PARAMETER:
1671         case checker::TypeFlag::ETS_NONNULLISH:
1672         case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER:
1673         case checker::TypeFlag::ETS_UNION:
1674         case checker::TypeFlag::ETS_ANY:
1675         case checker::TypeFlag::ETS_NULL:
1676         case checker::TypeFlag::ETS_UNDEFINED: {
1677             etsg->CastToReftype(expr, targetType, expr->isUncheckedCast_);
1678             break;
1679         }
1680         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1681             etsg->CastToDynamic(expr, targetType->AsETSDynamicType());
1682             break;
1683         }
1684         default: {
1685             CompileCastPrimitives(expr);
1686         }
1687     }
1688 }
1689 
Compile(const ir::TSAsExpression * expr) const1690 void ETSCompiler::Compile(const ir::TSAsExpression *expr) const
1691 {
1692     ETSGen *etsg = GetETSGen();
1693     expr->Expr()->Compile(etsg);
1694 
1695     const auto *const targetType = etsg->Checker()->GetApparentType(expr->TsType());
1696 
1697     auto ttctx = compiler::TargetTypeContext(etsg, nullptr);
1698     if ((expr->Expr()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U) {
1699         etsg->ApplyUnboxingConversion(expr->Expr());
1700     }
1701 
1702     if (targetType->IsETSObjectType() &&
1703         ((expr->Expr()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U ||
1704          (expr->Expr()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::BOXING_FLAG) != 0U) &&
1705         checker::ETSChecker::TypeKind(etsg->GetAccumulatorType()) != checker::TypeFlag::ETS_OBJECT) {
1706         if (targetType->IsETSUnboxableObject()) {
1707             CompileCastUnboxable(expr);
1708         }
1709     }
1710 
1711     if ((expr->Expr()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::BOXING_FLAG) != 0U) {
1712         etsg->ApplyBoxingConversion(expr->Expr());
1713     }
1714 
1715     CompileCast(expr);
1716     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), targetType));
1717 }
1718 
Compile(const ir::TSInterfaceDeclaration * st) const1719 void ETSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceDeclaration *st) const {}
1720 
Compile(const ir::TSNonNullExpression * expr) const1721 void ETSCompiler::Compile(const ir::TSNonNullExpression *expr) const
1722 {
1723     ETSGen *etsg = GetETSGen();
1724     compiler::RegScope rs(etsg);
1725 
1726     expr->Expr()->Compile(etsg);
1727 
1728     if (etsg->GetAccumulatorType()->PossiblyETSNullish()) {
1729         auto arg = etsg->AllocReg();
1730         etsg->StoreAccumulator(expr, arg);
1731         etsg->LoadAccumulator(expr, arg);
1732 
1733         auto endLabel = etsg->AllocLabel();
1734 
1735         etsg->BranchIfNotNullish(expr, endLabel);
1736         etsg->EmitNullishException(expr);
1737 
1738         etsg->SetLabel(expr, endLabel);
1739         etsg->LoadAccumulator(expr, arg);
1740         etsg->AssumeNonNullish(expr, expr->OriginalType());
1741     }
1742 
1743     ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->OriginalType()));
1744 }
1745 
Compile(const ir::TSTypeAliasDeclaration * st) const1746 void ETSCompiler::Compile([[maybe_unused]] const ir::TSTypeAliasDeclaration *st) const {}
1747 
1748 }  // namespace ark::es2panda::compiler
1749