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