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