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