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