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