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