• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ETSGen.h"
17 
18 #include "ir/base/scriptFunction.h"
19 #include "ir/base/classDefinition.h"
20 #include "ir/statement.h"
21 #include "ir/expressions/assignmentExpression.h"
22 #include "ir/expressions/identifier.h"
23 #include "ir/expressions/binaryExpression.h"
24 #include "ir/expressions/callExpression.h"
25 #include "ir/expressions/memberExpression.h"
26 #include "ir/expressions/templateLiteral.h"
27 #include "ir/statements/breakStatement.h"
28 #include "ir/statements/continueStatement.h"
29 #include "ir/statements/tryStatement.h"
30 #include "ir/ts/tsInterfaceDeclaration.h"
31 #include "varbinder/variableFlags.h"
32 #include "compiler/base/lreference.h"
33 #include "compiler/base/catchTable.h"
34 #include "compiler/core/dynamicContext.h"
35 #include "compiler/core/compilerContext.h"
36 #include "varbinder/ETSBinder.h"
37 #include "varbinder/variable.h"
38 #include "checker/types/type.h"
39 #include "checker/types/typeFlag.h"
40 #include "checker/checker.h"
41 #include "checker/ETSchecker.h"
42 #include "checker/ets/boxingConverter.h"
43 #include "checker/types/ets/etsObjectType.h"
44 #include "checker/types/ets/types.h"
45 #include "parser/program/program.h"
46 
47 namespace panda::es2panda::compiler {
48 
49 static constexpr auto TYPE_FLAG_BYTECODE_REF =
50     checker::TypeFlag::ETS_ARRAY_OR_OBJECT | checker::TypeFlag::ETS_UNION | checker::TypeFlag::ETS_TYPE_PARAMETER;
51 
ETSGen(ArenaAllocator * allocator,RegSpiller * spiller,CompilerContext * context,varbinder::FunctionScope * scope,ProgramElement * programElement,AstCompiler * astcompiler)52 ETSGen::ETSGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context,
53                varbinder::FunctionScope *scope, ProgramElement *programElement, AstCompiler *astcompiler) noexcept
54     : CodeGen(allocator, spiller, context, scope, programElement, astcompiler),
55       containingObjectType_(util::Helpers::GetContainingObjectType(RootNode()))
56 {
57     ETSFunction::Compile(this);
58 }
59 
SetAccumulatorType(const checker::Type * type)60 void ETSGen::SetAccumulatorType(const checker::Type *type)
61 {
62     SetVRegType(acc_, type);
63 }
64 
GetAccumulatorType() const65 const checker::Type *ETSGen::GetAccumulatorType() const
66 {
67     return GetVRegType(acc_);
68 }
69 
CompileAndCheck(const ir::Expression * expr)70 void ETSGen::CompileAndCheck(const ir::Expression *expr)
71 {
72     // NOTE: vpukhov. bad accumulator type leads to terrible bugs in codegen
73     // make exact types match mandatory
74     expr->Compile(this);
75 
76     if (expr->TsType()->IsETSTupleType()) {
77         // This piece of code is necessary to handle multidimensional tuples. As a tuple is stored as an
78         // array of `Objects`. If we make an array inside of the tuple type, then we won't be able to derefer a
79         // 2 dimensional array, with an array that expects to return `Object` after index access.
80         CheckedReferenceNarrowing(expr, expr->TsType());
81     }
82 
83     auto const *const accType = GetAccumulatorType();
84     if (accType == expr->TsType()) {
85         return;
86     }
87 
88     if (accType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) &&
89         ((accType->TypeFlags() ^ expr->TsType()->TypeFlags()) & ~checker::TypeFlag::CONSTANT) == 0) {
90         return;
91     }
92 
93     ASSERT(!"Type mismatch after Expression::Compile");
94 }
95 
Checker() const96 const checker::ETSChecker *ETSGen::Checker() const noexcept
97 {
98     return Context()->Checker()->AsETSChecker();
99 }
100 
VarBinder() const101 const varbinder::ETSBinder *ETSGen::VarBinder() const noexcept
102 {
103     return Context()->VarBinder()->AsETSBinder();
104 }
105 
ReturnType() const106 const checker::Type *ETSGen::ReturnType() const noexcept
107 {
108     return RootNode()->AsScriptFunction()->Signature()->ReturnType();
109 }
110 
ContainingObjectType() const111 const checker::ETSObjectType *ETSGen::ContainingObjectType() const noexcept
112 {
113     return containingObjectType_;
114 }
115 
Acc()116 VReg &ETSGen::Acc() noexcept
117 {
118     return acc_;
119 }
120 
Acc() const121 VReg ETSGen::Acc() const noexcept
122 {
123     return acc_;
124 }
125 
ApplyConversionAndStoreAccumulator(const ir::AstNode * const node,const VReg vreg,const checker::Type * const targetType)126 void ETSGen::ApplyConversionAndStoreAccumulator(const ir::AstNode *const node, const VReg vreg,
127                                                 const checker::Type *const targetType)
128 {
129     ApplyConversion(node, targetType);
130     StoreAccumulator(node, vreg);
131 }
132 
StoreException(const ir::AstNode * node)133 VReg ETSGen::StoreException(const ir::AstNode *node)
134 {
135     VReg exception = AllocReg();
136     Ra().Emit<StaObj>(node, exception);
137 
138     SetAccumulatorType(Checker()->GlobalBuiltinExceptionType());
139     SetVRegType(exception, GetAccumulatorType());
140     return exception;
141 }
142 
StoreAccumulator(const ir::AstNode * const node,const VReg vreg)143 void ETSGen::StoreAccumulator(const ir::AstNode *const node, const VReg vreg)
144 {
145     const auto *const accType = GetAccumulatorType();
146 
147     if (accType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
148         Ra().Emit<StaObj>(node, vreg);
149     } else if (accType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
150         Ra().Emit<StaWide>(node, vreg);
151     } else {
152         Ra().Emit<Sta>(node, vreg);
153     }
154 
155     SetVRegType(vreg, accType);
156 }
157 
LoadAccumulator(const ir::AstNode * node,VReg vreg)158 void ETSGen::LoadAccumulator(const ir::AstNode *node, VReg vreg)
159 {
160     const auto *const vregType = GetVRegType(vreg);
161 
162     if (vregType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
163         Ra().Emit<LdaObj>(node, vreg);
164     } else if (vregType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
165         Ra().Emit<LdaWide>(node, vreg);
166     } else {
167         Ra().Emit<Lda>(node, vreg);
168     }
169 
170     SetAccumulatorType(vregType);
171 }
172 
AllocMov(const ir::AstNode * const node,const VReg vd,const VReg vs)173 IRNode *ETSGen::AllocMov(const ir::AstNode *const node, const VReg vd, const VReg vs)
174 {
175     const auto *const sourceType = GetVRegType(vs);
176 
177     auto *const mov = [this, sourceType, node, vd, vs]() -> IRNode * {
178         if (sourceType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
179             return Allocator()->New<MovObj>(node, vd, vs);
180         }
181         if (sourceType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
182             return Allocator()->New<MovWide>(node, vd, vs);
183         }
184         return Allocator()->New<Mov>(node, vd, vs);
185     }();
186 
187     SetVRegType(vd, sourceType);
188     return mov;
189 }
190 
AllocMov(const ir::AstNode * const node,OutVReg vd,const VReg vs)191 IRNode *ETSGen::AllocMov(const ir::AstNode *const node, OutVReg vd, const VReg vs)
192 {
193     ASSERT(vd.type != OperandType::ANY && vd.type != OperandType::NONE);
194 
195     switch (vd.type) {
196         case OperandType::REF:
197             return Allocator()->New<MovObj>(node, *vd.reg, vs);
198         case OperandType::B64:
199             return Allocator()->New<MovWide>(node, *vd.reg, vs);
200         default:
201             break;
202     }
203 
204     return Allocator()->New<Mov>(node, *vd.reg, vs);
205 }
206 
TypeForVar(varbinder::Variable const * var) const207 checker::Type const *ETSGen::TypeForVar(varbinder::Variable const *var) const noexcept
208 {
209     return Checker()->MaybeBoxedType(var, Allocator());
210 }
211 
MoveVreg(const ir::AstNode * const node,const VReg vd,const VReg vs)212 void ETSGen::MoveVreg(const ir::AstNode *const node, const VReg vd, const VReg vs)
213 {
214     const auto *const sourceType = GetVRegType(vs);
215 
216     if (sourceType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
217         Ra().Emit<MovObj>(node, vd, vs);
218     } else if (sourceType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
219         Ra().Emit<MovWide>(node, vd, vs);
220     } else {
221         Ra().Emit<Mov>(node, vd, vs);
222     }
223 
224     SetVRegType(vd, sourceType);
225 }
226 
FormDynamicModulePropReference(const varbinder::Variable * var)227 util::StringView ETSGen::FormDynamicModulePropReference(const varbinder::Variable *var)
228 {
229     ASSERT(VarBinder()->IsDynamicModuleVariable(var) || VarBinder()->IsDynamicNamespaceVariable(var));
230 
231     auto *data = VarBinder()->DynamicImportDataForVar(var);
232     ASSERT(data != nullptr);
233 
234     auto *import = data->import;
235 
236     return FormDynamicModulePropReference(import);
237 }
238 
LoadAccumulatorDynamicModule(const ir::AstNode * node,const ir::ETSImportDeclaration * import)239 void ETSGen::LoadAccumulatorDynamicModule(const ir::AstNode *node, const ir::ETSImportDeclaration *import)
240 {
241     ASSERT(import->Language().IsDynamic());
242     LoadStaticProperty(node, Checker()->GlobalBuiltinDynamicType(import->Language()),
243                        FormDynamicModulePropReference(import));
244 }
245 
FormDynamicModulePropReference(const ir::ETSImportDeclaration * import)246 util::StringView ETSGen::FormDynamicModulePropReference(const ir::ETSImportDeclaration *import)
247 {
248     std::stringstream ss;
249     auto pkgName = VarBinder()->Program()->GetPackageName();
250     if (!pkgName.Empty()) {
251         ss << pkgName << '.';
252     }
253     ss << compiler::Signatures::DYNAMIC_MODULE_CLASS;
254     ss << '.';
255     ss << import->AssemblerName();
256 
257     return util::UString(ss.str(), Allocator()).View();
258 }
259 
LoadDynamicModuleVariable(const ir::AstNode * node,varbinder::Variable const * const var)260 void ETSGen::LoadDynamicModuleVariable(const ir::AstNode *node, varbinder::Variable const *const var)
261 {
262     RegScope rs(this);
263 
264     auto *data = VarBinder()->DynamicImportDataForVar(var);
265     auto *import = data->import;
266 
267     LoadStaticProperty(node, var->TsType(), FormDynamicModulePropReference(var));
268 
269     auto objReg = AllocReg();
270     StoreAccumulator(node, objReg);
271 
272     auto *id = data->specifier->AsImportSpecifier()->Imported();
273     auto lang = import->Language();
274     LoadPropertyDynamic(node, Checker()->GlobalBuiltinDynamicType(lang), objReg, id->Name());
275 
276     ApplyConversion(node);
277 }
278 
LoadDynamicNamespaceVariable(const ir::AstNode * node,varbinder::Variable const * const var)279 void ETSGen::LoadDynamicNamespaceVariable(const ir::AstNode *node, varbinder::Variable const *const var)
280 {
281     LoadStaticProperty(node, var->TsType(), FormDynamicModulePropReference(var));
282 }
283 
LoadVar(const ir::AstNode * node,varbinder::Variable const * const var)284 void ETSGen::LoadVar(const ir::AstNode *node, varbinder::Variable const *const var)
285 {
286     if (VarBinder()->IsDynamicModuleVariable(var)) {
287         LoadDynamicModuleVariable(node, var);
288         return;
289     }
290 
291     if (VarBinder()->IsDynamicNamespaceVariable(var)) {
292         LoadDynamicNamespaceVariable(node, var);
293         return;
294     }
295 
296     auto *local = var->AsLocalVariable();
297 
298     switch (ETSLReference::ResolveReferenceKind(var)) {
299         case ReferenceKind::STATIC_FIELD: {
300             auto fullName = FormClassPropReference(var);
301             LoadStaticProperty(node, var->TsType(), fullName);
302             break;
303         }
304         case ReferenceKind::FIELD: {
305             const auto fullName = FormClassPropReference(GetVRegType(GetThisReg())->AsETSObjectType(), var->Name());
306             LoadProperty(node, var->TsType(), GetThisReg(), fullName);
307             break;
308         }
309         case ReferenceKind::METHOD:
310         case ReferenceKind::STATIC_METHOD:
311         case ReferenceKind::CLASS:
312         case ReferenceKind::STATIC_CLASS: {
313             SetAccumulatorType(var->TsType());
314             break;
315         }
316         case ReferenceKind::LOCAL: {
317             LoadAccumulator(node, local->Vreg());
318             SetAccumulatorType(var->TsType());
319             break;
320         }
321         default: {
322             UNREACHABLE();
323         }
324     }
325 
326     if (var->HasFlag(varbinder::VariableFlags::BOXED) && !node->AsIdentifier()->IsIgnoreBox()) {
327         EmitLocalBoxGet(node, var->TsType());
328     }
329 }
330 
StoreVar(const ir::AstNode * node,const varbinder::ConstScopeFindResult & result)331 void ETSGen::StoreVar(const ir::AstNode *node, const varbinder::ConstScopeFindResult &result)
332 {
333     auto *local = result.variable->AsLocalVariable();
334     ApplyConversion(node, local->TsType());
335 
336     switch (ETSLReference::ResolveReferenceKind(result.variable)) {
337         case ReferenceKind::STATIC_FIELD: {
338             auto fullName = FormClassPropReference(result.variable);
339             StoreStaticProperty(node, result.variable->TsType(), fullName);
340             break;
341         }
342         case ReferenceKind::FIELD: {
343             StoreProperty(node, result.variable->TsType(), GetThisReg(), result.name);
344             break;
345         }
346         case ReferenceKind::LOCAL: {
347             if (local->HasFlag(varbinder::VariableFlags::BOXED)) {
348                 EmitLocalBoxSet(node, local);
349             } else {
350                 StoreAccumulator(node, local->Vreg());
351                 SetVRegType(local->Vreg(), local->TsType());
352             }
353             break;
354         }
355         default: {
356             UNREACHABLE();
357         }
358     }
359 }
360 
FormClassPropReference(const checker::ETSObjectType * classType,const util::StringView & name)361 util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name)
362 {
363     std::stringstream ss;
364 
365     auto *iter = classType;
366     std::string fullName = classType->AssemblerName().Mutf8();
367     while (iter->EnclosingType() != nullptr) {
368         auto enclosingName = iter->EnclosingType()->Name().Mutf8().append(".").append(fullName);
369         fullName = enclosingName;
370         iter = iter->EnclosingType();
371     }
372 
373     if (fullName != classType->AssemblerName().Mutf8()) {
374         fullName.append(".").append(Signatures::ETS_GLOBAL);
375     }
376     ss << fullName << '.' << name;
377     auto res = ProgElement()->Strings().emplace(ss.str());
378 
379     return util::StringView(*res.first);
380 }
381 
FormClassPropReference(varbinder::Variable const * const var)382 util::StringView ETSGen::FormClassPropReference(varbinder::Variable const *const var)
383 {
384     auto containingObjectType = util::Helpers::GetContainingObjectType(var->Declaration()->Node());
385     return FormClassPropReference(containingObjectType, var->Name());
386 }
387 
StoreStaticOwnProperty(const ir::AstNode * node,const checker::Type * propType,const util::StringView & name)388 void ETSGen::StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType,
389                                     const util::StringView &name)
390 {
391     util::StringView fullName = FormClassPropReference(containingObjectType_, name);
392     StoreStaticProperty(node, propType, fullName);
393 }
394 
StoreStaticProperty(const ir::AstNode * const node,const checker::Type * propType,const util::StringView & fullName)395 void ETSGen::StoreStaticProperty(const ir::AstNode *const node, const checker::Type *propType,
396                                  const util::StringView &fullName)
397 {
398     if (propType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
399         Sa().Emit<StstaticObj>(node, fullName);
400     } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
401         Sa().Emit<StstaticWide>(node, fullName);
402     } else {
403         Sa().Emit<Ststatic>(node, fullName);
404     }
405 }
406 
LoadStaticProperty(const ir::AstNode * const node,const checker::Type * propType,const util::StringView & fullName)407 void ETSGen::LoadStaticProperty(const ir::AstNode *const node, const checker::Type *propType,
408                                 const util::StringView &fullName)
409 {
410     if (propType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
411         Sa().Emit<LdstaticObj>(node, fullName);
412     } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
413         Sa().Emit<LdstaticWide>(node, fullName);
414     } else {
415         Sa().Emit<Ldstatic>(node, fullName);
416     }
417 
418     SetAccumulatorType(propType);
419 }
420 
StoreProperty(const ir::AstNode * const node,const checker::Type * propType,const VReg objReg,const util::StringView & name)421 void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *propType, const VReg objReg,
422                            const util::StringView &name)
423 {
424     const auto fullName = FormClassPropReference(GetVRegType(objReg)->AsETSObjectType(), name);
425 
426     if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(varbinder::VariableFlags::BOXED)) {
427         propType = Checker()->GlobalBuiltinBoxType(propType);
428     }
429     if (propType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
430         Ra().Emit<StobjObj>(node, objReg, fullName);
431     } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
432         Ra().Emit<StobjWide>(node, objReg, fullName);
433     } else {
434         Ra().Emit<Stobj>(node, objReg, fullName);
435     }
436 }
437 
LoadProperty(const ir::AstNode * const node,const checker::Type * propType,const VReg objReg,const util::StringView & fullName)438 void ETSGen::LoadProperty(const ir::AstNode *const node, const checker::Type *propType, const VReg objReg,
439                           const util::StringView &fullName)
440 {
441     if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(varbinder::VariableFlags::BOXED)) {
442         propType = Checker()->GlobalBuiltinBoxType(propType);
443     }
444     if (propType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
445         Ra().Emit<LdobjObj>(node, objReg, fullName);
446     } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
447         Ra().Emit<LdobjWide>(node, objReg, fullName);
448     } else {
449         Ra().Emit<Ldobj>(node, objReg, fullName);
450     }
451 
452     SetAccumulatorType(propType);
453 }
454 
StoreUnionProperty(const ir::AstNode * node,VReg objReg,const util::StringView & propName)455 void ETSGen::StoreUnionProperty([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] VReg objReg,
456                                 [[maybe_unused]] const util::StringView &propName)
457 {
458 #ifdef PANDA_WITH_ETS
459     Ra().Emit<EtsStobjName>(node, objReg, propName);
460 #else
461     UNREACHABLE();
462 #endif  // PANDA_WITH_ETS
463 }
464 
LoadUnionProperty(const ir::AstNode * const node,const checker::Type * propType,const VReg objReg,const util::StringView & propName)465 void ETSGen::LoadUnionProperty([[maybe_unused]] const ir::AstNode *const node,
466                                [[maybe_unused]] const checker::Type *propType, [[maybe_unused]] const VReg objReg,
467                                [[maybe_unused]] const util::StringView &propName)
468 {
469 #ifdef PANDA_WITH_ETS
470     Ra().Emit<EtsLdobjName>(node, objReg, propName);
471     SetAccumulatorType(propType);
472 #else
473     UNREACHABLE();
474 #endif  // PANDA_WITH_ETS
475 }
476 
StorePropertyDynamic(const ir::AstNode * node,const checker::Type * propType,VReg objReg,const util::StringView & propName)477 void ETSGen::StorePropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg,
478                                   const util::StringView &propName)
479 {
480     auto const lang = GetVRegType(objReg)->AsETSDynamicType()->Language();
481     std::string_view methodName {};
482     if (propType->IsETSBooleanType()) {
483         methodName = Signatures::Dynamic::SetPropertyBooleanBuiltin(lang);
484     } else if (propType->IsByteType()) {
485         methodName = Signatures::Dynamic::SetPropertyByteBuiltin(lang);
486     } else if (propType->IsCharType()) {
487         methodName = Signatures::Dynamic::SetPropertyCharBuiltin(lang);
488     } else if (propType->IsShortType()) {
489         methodName = Signatures::Dynamic::SetPropertyShortBuiltin(lang);
490     } else if (propType->IsIntType()) {
491         methodName = Signatures::Dynamic::SetPropertyIntBuiltin(lang);
492     } else if (propType->IsLongType()) {
493         methodName = Signatures::Dynamic::SetPropertyLongBuiltin(lang);
494     } else if (propType->IsFloatType()) {
495         methodName = Signatures::Dynamic::SetPropertyFloatBuiltin(lang);
496     } else if (propType->IsDoubleType()) {
497         methodName = Signatures::Dynamic::SetPropertyDoubleBuiltin(lang);
498     } else if (propType->IsETSStringType()) {
499         methodName = Signatures::Dynamic::SetPropertyStringBuiltin(lang);
500     } else if (propType->IsETSObjectType() || propType->IsETSTypeParameter()) {
501         methodName = Signatures::Dynamic::SetPropertyDynamicBuiltin(lang);
502         // NOTE: vpukhov. add non-dynamic builtin
503         if (!propType->IsETSDynamicType()) {
504             CastToDynamic(node, Checker()->GlobalBuiltinDynamicType(lang)->AsETSDynamicType());
505         }
506     } else {
507         ASSERT_PRINT(false, "Unsupported property type");
508     }
509 
510     RegScope rs(this);
511     VReg propValueReg = AllocReg();
512     VReg propNameReg = AllocReg();
513 
514     StoreAccumulator(node, propValueReg);
515 
516     // Load property name
517     LoadAccumulatorString(node, propName);
518     StoreAccumulator(node, propNameReg);
519 
520     // Set property by name
521     Ra().Emit<Call, 3U>(node, methodName, objReg, propNameReg, propValueReg, dummyReg_);
522     SetAccumulatorType(nullptr);
523 }
524 
LoadPropertyDynamic(const ir::AstNode * node,const checker::Type * propType,VReg objReg,const util::StringView & propName)525 void ETSGen::LoadPropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg,
526                                  const util::StringView &propName)
527 {
528     auto const lang = GetVRegType(objReg)->AsETSDynamicType()->Language();
529     auto *type = propType;
530     std::string_view methodName {};
531     if (propType->IsETSBooleanType()) {
532         methodName = Signatures::Dynamic::GetPropertyBooleanBuiltin(lang);
533     } else if (propType->IsByteType()) {
534         methodName = Signatures::Dynamic::GetPropertyByteBuiltin(lang);
535     } else if (propType->IsCharType()) {
536         methodName = Signatures::Dynamic::GetPropertyCharBuiltin(lang);
537     } else if (propType->IsShortType()) {
538         methodName = Signatures::Dynamic::GetPropertyShortBuiltin(lang);
539     } else if (propType->IsIntType()) {
540         methodName = Signatures::Dynamic::GetPropertyIntBuiltin(lang);
541     } else if (propType->IsLongType()) {
542         methodName = Signatures::Dynamic::GetPropertyLongBuiltin(lang);
543     } else if (propType->IsFloatType()) {
544         methodName = Signatures::Dynamic::GetPropertyFloatBuiltin(lang);
545     } else if (propType->IsDoubleType()) {
546         methodName = Signatures::Dynamic::GetPropertyDoubleBuiltin(lang);
547     } else if (propType->IsETSStringType()) {
548         methodName = Signatures::Dynamic::GetPropertyStringBuiltin(lang);
549     } else if (propType->IsETSObjectType() || propType->IsETSTypeParameter()) {
550         methodName = Signatures::Dynamic::GetPropertyDynamicBuiltin(lang);
551         type = Checker()->GlobalBuiltinDynamicType(lang);
552     } else {
553         ASSERT_PRINT(false, "Unsupported property type");
554     }
555 
556     RegScope rs(this);
557 
558     // Load property name
559     LoadAccumulatorString(node, propName);
560     VReg propNameObject = AllocReg();
561     StoreAccumulator(node, propNameObject);
562 
563     // Get property by name
564     Ra().Emit<CallShort, 2U>(node, methodName, objReg, propNameObject);
565     SetAccumulatorType(type);
566 
567     if (propType != type && !propType->IsETSDynamicType()) {
568         CastDynamicToObject(node, propType);
569     }
570 }
571 
StoreElementDynamic(const ir::AstNode * node,VReg objectReg,VReg index)572 void ETSGen::StoreElementDynamic(const ir::AstNode *node, VReg objectReg, VReg index)
573 {
574     auto const lang = GetVRegType(objectReg)->AsETSDynamicType()->Language();
575     std::string_view methodName = Signatures::Dynamic::SetElementDynamicBuiltin(lang);
576 
577     RegScope rs(this);
578 
579     VReg valueReg = AllocReg();
580     StoreAccumulator(node, valueReg);
581 
582     // Set property by index
583     Ra().Emit<Call, 3U>(node, methodName, objectReg, index, valueReg, dummyReg_);
584     SetAccumulatorType(Checker()->GlobalVoidType());
585 }
586 
LoadElementDynamic(const ir::AstNode * node,VReg objectReg)587 void ETSGen::LoadElementDynamic(const ir::AstNode *node, VReg objectReg)
588 {
589     auto const lang = GetVRegType(objectReg)->AsETSDynamicType()->Language();
590     std::string_view methodName = Signatures::Dynamic::GetElementDynamicBuiltin(lang);
591 
592     RegScope rs(this);
593 
594     VReg indexReg = AllocReg();
595     StoreAccumulator(node, indexReg);
596 
597     // Get property by index
598     Ra().Emit<CallShort, 2U>(node, methodName, objectReg, indexReg);
599     SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(lang));
600 }
601 
LoadUndefinedDynamic(const ir::AstNode * node,Language lang)602 void ETSGen::LoadUndefinedDynamic(const ir::AstNode *node, Language lang)
603 {
604     RegScope rs(this);
605     Ra().Emit<CallShort, 0>(node, Signatures::Dynamic::GetUndefinedBuiltin(lang), dummyReg_, dummyReg_);
606     SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(lang));
607 }
608 
LoadThis(const ir::AstNode * node)609 void ETSGen::LoadThis(const ir::AstNode *node)
610 {
611     LoadAccumulator(node, GetThisReg());
612 }
613 
CreateBigIntObject(const ir::AstNode * node,VReg arg0)614 void ETSGen::CreateBigIntObject(const ir::AstNode *node, VReg arg0)
615 {
616     Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_BIGINT_CTOR, arg0, dummyReg_);
617 }
618 
CreateLambdaObjectFromIdentReference(const ir::AstNode * node,ir::ClassDefinition * lambdaObj)619 void ETSGen::CreateLambdaObjectFromIdentReference(const ir::AstNode *node, ir::ClassDefinition *lambdaObj)
620 {
621     auto *ctor = lambdaObj->TsType()->AsETSObjectType()->ConstructSignatures()[0];
622 
623     if (ctor->Params().empty()) {
624         Ra().Emit<InitobjShort>(node, ctor->InternalName(), VReg::RegStart(), VReg::RegStart());
625     } else {
626         Ra().Emit<InitobjShort>(node, ctor->InternalName(), GetThisReg(), VReg::RegStart());
627     }
628 
629     SetAccumulatorType(lambdaObj->TsType());
630 }
631 
CreateLambdaObjectFromMemberReference(const ir::AstNode * node,ir::Expression * obj,ir::ClassDefinition * lambdaObj)632 void ETSGen::CreateLambdaObjectFromMemberReference(const ir::AstNode *node, ir::Expression *obj,
633                                                    ir::ClassDefinition *lambdaObj)
634 {
635     auto *ctor = lambdaObj->TsType()->AsETSObjectType()->ConstructSignatures()[0];
636     ArenaVector<ir::Expression *> args(Allocator()->Adapter());
637 
638     if (!ctor->Params().empty()) {
639         args.push_back(obj);
640     }
641 
642     InitObject(node, ctor, args);
643     SetAccumulatorType(lambdaObj->TsType());
644 }
645 
646 // NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty)
647 #define CONV_LAMBDA_CTOR_ARG(idx)                              \
648     ASSERT((idx) < arguments.size());                          \
649     auto *paramType##idx = signature->Params()[idx]->TsType(); \
650     auto ttctx##idx = TargetTypeContext(this, paramType##idx); \
651     ApplyConversion(node, paramType##idx)
652 
InitLambdaObject(const ir::AstNode * node,checker::Signature * signature,std::vector<VReg> & arguments)653 void ETSGen::InitLambdaObject(const ir::AstNode *node, checker::Signature *signature, std::vector<VReg> &arguments)
654 {
655     RegScope rs(this);
656     util::StringView name = signature->InternalName();
657 
658     switch (arguments.size()) {
659         case 0: {
660             Ra().Emit<InitobjShort>(node, name, VReg::RegStart(), VReg::RegStart());
661             break;
662         }
663         case 1: {
664             CONV_LAMBDA_CTOR_ARG(0);
665             Ra().Emit<InitobjShort>(node, name, arguments[0], VReg::RegStart());
666             break;
667         }
668         case 2U: {
669             CONV_LAMBDA_CTOR_ARG(0);
670             CONV_LAMBDA_CTOR_ARG(1);
671             Ra().Emit<InitobjShort>(node, name, arguments[0], arguments[1]);
672             break;
673         }
674         case 3U: {
675             CONV_LAMBDA_CTOR_ARG(0);
676             CONV_LAMBDA_CTOR_ARG(1);
677             CONV_LAMBDA_CTOR_ARG(2);
678             Ra().Emit<Initobj>(node, name, arguments[0], arguments[1], arguments[2U], VReg::RegStart());
679             break;
680         }
681         case 4U: {
682             CONV_LAMBDA_CTOR_ARG(0);
683             CONV_LAMBDA_CTOR_ARG(1);
684             CONV_LAMBDA_CTOR_ARG(2);
685             CONV_LAMBDA_CTOR_ARG(3);
686             Ra().Emit<Initobj>(node, name, arguments[0], arguments[1], arguments[2U], arguments[3U]);
687             break;
688         }
689         default: {
690             VReg argStart = NextReg();
691 
692             for (size_t i = 0; i < arguments.size(); i++) {
693                 auto ttctx = TargetTypeContext(this, signature->Params()[i]->TsType());
694                 VReg argReg = AllocReg();
695                 MoveVreg(node, argReg, arguments[i]);
696             }
697 
698             Rra().Emit<InitobjRange>(node, argStart, arguments.size(), name, argStart);
699             break;
700         }
701     }
702 }
703 
704 #undef CONV_LAMBDA_CTOR_ARG
705 // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty)
706 
GetThisReg() const707 VReg ETSGen::GetThisReg() const
708 {
709     const auto res = Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS);
710     return res.variable->AsLocalVariable()->Vreg();
711 }
712 
LoadDefaultValue(const ir::AstNode * node,const checker::Type * type)713 void ETSGen::LoadDefaultValue([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const checker::Type *type)
714 {
715     if (type->IsETSUnionType()) {
716         type = Checker()->GetGlobalTypesHolder()->GlobalETSObjectType();
717     }
718     if (type->IsETSObjectType() || type->IsETSArrayType() || type->IsETSTypeParameter()) {
719         LoadAccumulatorNull(node, type);
720     } else if (type->IsETSBooleanType()) {
721         LoadAccumulatorBoolean(node, type->AsETSBooleanType()->GetValue());
722     } else {
723         const auto ttctx = TargetTypeContext(this, type);
724         LoadAccumulatorInt(node, 0);
725     }
726 }
727 
EmitReturnVoid(const ir::AstNode * node)728 void ETSGen::EmitReturnVoid(const ir::AstNode *node)
729 {
730     Sa().Emit<ReturnVoid>(node);
731 }
732 
LoadBuiltinVoid(const ir::AstNode * node)733 void ETSGen::LoadBuiltinVoid(const ir::AstNode *node)
734 {
735     LoadStaticProperty(node, Checker()->GlobalBuiltinVoidType(),
736                        FormClassPropReference(Checker()->GlobalBuiltinVoidType(), "void_instance"));
737 }
738 
ReturnAcc(const ir::AstNode * node)739 void ETSGen::ReturnAcc(const ir::AstNode *node)
740 {
741     const auto *const accType = GetAccumulatorType();
742 
743     if (accType->HasTypeFlag(TYPE_FLAG_BYTECODE_REF)) {
744         Sa().Emit<ReturnObj>(node);
745     } else if (accType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) {
746         Sa().Emit<ReturnWide>(node);
747     } else {
748         Sa().Emit<Return>(node);
749     }
750 }
751 
EmitIsInstanceNonNullish(const ir::AstNode * const node,const VReg objReg,checker::ETSObjectType const * clsType)752 void ETSGen::EmitIsInstanceNonNullish([[maybe_unused]] const ir::AstNode *const node,
753                                       [[maybe_unused]] const VReg objReg,
754                                       [[maybe_unused]] checker::ETSObjectType const *clsType)
755 {
756 #ifdef PANDA_WITH_ETS
757     auto const objType = GetVRegType(objReg);
758     // undefined is implemented as Object instance, so "instanceof Object" must be treated carefully
759     if (!Checker()->MayHaveUndefinedValue(objType) || clsType != Checker()->GlobalETSObjectType()) {
760         LoadAccumulator(node, objReg);
761         Sa().Emit<Isinstance>(node, clsType->AssemblerName());
762         SetAccumulatorType(Checker()->GlobalETSBooleanType());
763         return;
764     }
765 
766     Label *lundef = AllocLabel();
767     Label *lend = AllocLabel();
768 
769     LoadAccumulator(node, objReg);
770     Sa().Emit<EtsIsundefined>(node);
771     BranchIfTrue(node, lundef);
772 
773     LoadAccumulator(node, objReg);
774     Sa().Emit<Isinstance>(node, clsType->AssemblerName());
775     JumpTo(node, lend);
776 
777     SetLabel(node, lundef);
778     LoadAccumulatorBoolean(node, false);
779 
780     SetLabel(node, lend);
781 #else
782     UNREACHABLE();
783 #endif  // PANDA_WITH_ETS
784 }
785 
EmitIsInstance(const ir::AstNode * const node,const VReg objReg)786 void ETSGen::EmitIsInstance([[maybe_unused]] const ir::AstNode *const node, [[maybe_unused]] const VReg objReg)
787 {
788 #ifdef PANDA_WITH_ETS
789     auto const *rhsType = node->AsBinaryExpression()->Right()->TsType()->AsETSObjectType();
790     auto const *lhsType = GetVRegType(objReg);
791 
792     if (rhsType->IsETSDynamicType() || lhsType->IsETSDynamicType()) {
793         ASSERT(rhsType->IsETSDynamicType() && lhsType->IsETSDynamicType());
794         Ra().Emit<CallShort, 2U>(node, Signatures::BUILTIN_JSRUNTIME_INSTANCE_OF, objReg, MoveAccToReg(node));
795         SetAccumulatorType(Checker()->GlobalETSBooleanType());
796         return;
797     }
798 
799     if (!Checker()->MayHaveNulllikeValue(rhsType)) {
800         EmitIsInstanceNonNullish(node, objReg, rhsType);
801         return;
802     }
803 
804     auto ifTrue = AllocLabel();
805     auto end = AllocLabel();
806 
807     LoadAccumulator(node, objReg);
808 
809     // Iterate union members
810     if (Checker()->MayHaveNullValue(rhsType)) {
811         BranchIfNull(node, ifTrue);
812     }
813     if (Checker()->MayHaveUndefinedValue(rhsType)) {
814         Sa().Emit<EtsIsundefined>(node);
815         BranchIfTrue(node, ifTrue);
816         LoadAccumulator(node, objReg);
817     }
818     if (rhsType->IsETSNullLike()) {
819         LoadAccumulatorBoolean(node, false);
820     } else {
821         EmitIsInstanceNonNullish(node, objReg, Checker()->GetNonNullishType(rhsType)->AsETSObjectType());
822     }
823     JumpTo(node, end);
824 
825     SetLabel(node, ifTrue);
826     LoadAccumulatorBoolean(node, true);
827     SetLabel(node, end);
828 #else
829     UNREACHABLE();
830 #endif  // PANDA_WITH_ETS
831 }
832 
InternalCheckCast(const ir::AstNode * node,const es2panda::checker::Type * target)833 void ETSGen::InternalCheckCast(const ir::AstNode *node, const es2panda::checker::Type *target)
834 {
835     ASSERT(target->IsETSObjectType() && !target->IsNullishOrNullLike());
836     Sa().Emit<Checkcast>(node, ToAssemblerType(target));
837     SetAccumulatorType(target);
838 }
839 
CheckedReferenceNarrowing(const ir::AstNode * node,const checker::Type * target)840 void ETSGen::CheckedReferenceNarrowing(const ir::AstNode *node, const checker::Type *target)
841 {
842     ASSERT(target->HasTypeFlag(TYPE_FLAG_BYTECODE_REF) && !target->IsETSNullLike());
843     // NOTE(vpukhov): implement for nulllike and union targets
844     if (target == Checker()->GlobalETSNullishObjectType()) {
845         SetAccumulatorType(target);
846         return;
847     }
848 
849     Sa().Emit<Checkcast>(node, ToAssemblerType(target));
850     SetAccumulatorType(target);
851 }
852 
GuardUncheckedType(const ir::AstNode * node,const checker::Type * unchecked,const checker::Type * target)853 void ETSGen::GuardUncheckedType(const ir::AstNode *node, const checker::Type *unchecked, const checker::Type *target)
854 {
855     if (unchecked != nullptr) {
856         SetAccumulatorType(unchecked);
857         CheckedReferenceNarrowing(node, target);
858     } else {
859         SetAccumulatorType(target);
860     }
861 }
862 
LoadConstantObject(const ir::Expression * node,const checker::Type * type)863 void ETSGen::LoadConstantObject(const ir::Expression *node, const checker::Type *type)
864 {
865     if (type->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) {
866         LoadAccumulatorBigInt(node, type->AsETSObjectType()->AsETSBigIntType()->GetValue());
867         const VReg value = AllocReg();
868         StoreAccumulator(node, value);
869         CreateBigIntObject(node, value);
870     } else {
871         LoadAccumulatorString(node, type->AsETSObjectType()->AsETSStringType()->GetValue());
872         SetAccumulatorType(node->TsType());
873     }
874 }
875 
TryLoadConstantExpression(const ir::Expression * node)876 bool ETSGen::TryLoadConstantExpression(const ir::Expression *node)
877 {
878     const auto *type = node->TsType();
879 
880     if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
881         return false;
882     }
883 
884     auto typeKind = checker::ETSChecker::TypeKind(type);
885 
886     switch (typeKind) {
887         case checker::TypeFlag::CHAR: {
888             LoadAccumulatorChar(node, type->AsCharType()->GetValue());
889             break;
890         }
891         case checker::TypeFlag::ETS_BOOLEAN: {
892             LoadAccumulatorBoolean(node, type->AsETSBooleanType()->GetValue());
893             break;
894         }
895         case checker::TypeFlag::BYTE: {
896             LoadAccumulatorByte(node, type->AsByteType()->GetValue());
897             break;
898         }
899         case checker::TypeFlag::SHORT: {
900             LoadAccumulatorShort(node, type->AsShortType()->GetValue());
901             break;
902         }
903         case checker::TypeFlag::INT: {
904             LoadAccumulatorInt(node, type->AsIntType()->GetValue());
905             break;
906         }
907         case checker::TypeFlag::LONG: {
908             LoadAccumulatorWideInt(node, type->AsLongType()->GetValue());
909             break;
910         }
911         case checker::TypeFlag::FLOAT: {
912             LoadAccumulatorFloat(node, type->AsFloatType()->GetValue());
913             break;
914         }
915         case checker::TypeFlag::DOUBLE: {
916             LoadAccumulatorDouble(node, type->AsDoubleType()->GetValue());
917             break;
918         }
919         case checker::TypeFlag::ETS_OBJECT: {
920             LoadConstantObject(node, type);
921             break;
922         }
923         default: {
924             UNREACHABLE();
925         }
926     }
927 
928     return true;
929 }
930 
ApplyConversionCast(const ir::AstNode * node,const checker::Type * targetType)931 void ETSGen::ApplyConversionCast(const ir::AstNode *node, const checker::Type *targetType)
932 {
933     switch (checker::ETSChecker::TypeKind(targetType)) {
934         case checker::TypeFlag::DOUBLE: {
935             CastToDouble(node);
936             break;
937         }
938         case checker::TypeFlag::FLOAT: {
939             CastToFloat(node);
940             break;
941         }
942         case checker::TypeFlag::LONG: {
943             CastToLong(node);
944             break;
945         }
946         case checker::TypeFlag::ETS_ARRAY:
947         case checker::TypeFlag::ETS_OBJECT:
948         case checker::TypeFlag::ETS_TYPE_PARAMETER: {
949             if (GetAccumulatorType() != nullptr && GetAccumulatorType()->IsETSDynamicType()) {
950                 CastDynamicToObject(node, targetType);
951             }
952             break;
953         }
954         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
955             CastToDynamic(node, targetType->AsETSDynamicType());
956             break;
957         }
958         default: {
959             break;
960         }
961     }
962 }
963 
ApplyBoxingConversion(const ir::AstNode * node)964 void ETSGen::ApplyBoxingConversion(const ir::AstNode *node)
965 {
966     EmitBoxingConversion(node);
967     node->SetBoxingUnboxingFlags(
968         static_cast<ir::BoxingUnboxingFlags>(node->GetBoxingUnboxingFlags() & ~(ir::BoxingUnboxingFlags::BOXING_FLAG)));
969 }
970 
ApplyUnboxingConversion(const ir::AstNode * node)971 void ETSGen::ApplyUnboxingConversion(const ir::AstNode *node)
972 {
973     if (Checker()->MayHaveNulllikeValue(GetAccumulatorType())) {  // NOTE: vpukhov. should be a CTE
974         EmitNullishGuardian(node);
975     }
976     EmitUnboxingConversion(node);
977     node->SetBoxingUnboxingFlags(static_cast<ir::BoxingUnboxingFlags>(node->GetBoxingUnboxingFlags() &
978                                                                       ~(ir::BoxingUnboxingFlags::UNBOXING_FLAG)));
979 }
980 
ApplyConversion(const ir::AstNode * node,const checker::Type * targetType)981 void ETSGen::ApplyConversion(const ir::AstNode *node, const checker::Type *targetType)
982 {
983     auto ttctx = TargetTypeContext(this, targetType);
984 
985     if ((node->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::BOXING_FLAG) != 0U) {
986         ApplyBoxingConversion(node);
987         return;
988     }
989 
990     if ((node->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U) {
991         ApplyUnboxingConversion(node);
992     }
993 
994     if (targetType == nullptr) {
995         return;
996     }
997 
998     if (targetType->IsETSUnionType()) {
999         SetAccumulatorType(targetType);
1000         return;
1001     }
1002 
1003     ApplyConversionCast(node, targetType);
1004 }
1005 
ApplyCast(const ir::AstNode * node,const checker::Type * targetType)1006 void ETSGen::ApplyCast(const ir::AstNode *node, const checker::Type *targetType)
1007 {
1008     auto typeKind = checker::ETSChecker::TypeKind(targetType);
1009 
1010     switch (typeKind) {
1011         case checker::TypeFlag::DOUBLE: {
1012             CastToDouble(node);
1013             break;
1014         }
1015         case checker::TypeFlag::FLOAT: {
1016             CastToFloat(node);
1017             break;
1018         }
1019         case checker::TypeFlag::LONG: {
1020             CastToLong(node);
1021             break;
1022         }
1023         case checker::TypeFlag::INT: {
1024             CastToInt(node);
1025             break;
1026         }
1027         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1028             CastToDynamic(node, targetType->AsETSDynamicType());
1029             break;
1030         }
1031         default: {
1032             break;
1033         }
1034     }
1035 }
1036 
EmitUnboxedCall(const ir::AstNode * node,std::string_view signatureFlag,const checker::Type * const targetType,const checker::Type * const boxedType)1037 void ETSGen::EmitUnboxedCall(const ir::AstNode *node, std::string_view signatureFlag,
1038                              const checker::Type *const targetType, const checker::Type *const boxedType)
1039 {
1040     if (node->HasAstNodeFlags(ir::AstNodeFlags::CHECKCAST)) {
1041         CheckedReferenceNarrowing(node, boxedType);
1042     }
1043 
1044     Ra().Emit<CallVirtAccShort, 0>(node, signatureFlag, dummyReg_, 0);
1045     SetAccumulatorType(targetType);
1046 }
1047 
EmitUnboxingConversion(const ir::AstNode * node)1048 void ETSGen::EmitUnboxingConversion(const ir::AstNode *node)
1049 {
1050     const auto unboxingFlag =
1051         static_cast<ir::BoxingUnboxingFlags>(ir::BoxingUnboxingFlags::UNBOXING_FLAG & node->GetBoxingUnboxingFlags());
1052 
1053     RegScope rs(this);
1054 
1055     switch (unboxingFlag) {
1056         case ir::BoxingUnboxingFlags::UNBOX_TO_BOOLEAN: {
1057             EmitUnboxedCall(node, Signatures::BUILTIN_BOOLEAN_UNBOXED, Checker()->GlobalETSBooleanType(),
1058                             Checker()->GetGlobalTypesHolder()->GlobalETSBooleanBuiltinType());
1059             break;
1060         }
1061         case ir::BoxingUnboxingFlags::UNBOX_TO_BYTE: {
1062             EmitUnboxedCall(node, Signatures::BUILTIN_BYTE_UNBOXED, Checker()->GlobalByteType(),
1063                             Checker()->GetGlobalTypesHolder()->GlobalByteBuiltinType());
1064             break;
1065         }
1066         case ir::BoxingUnboxingFlags::UNBOX_TO_CHAR: {
1067             EmitUnboxedCall(node, Signatures::BUILTIN_CHAR_UNBOXED, Checker()->GlobalCharType(),
1068                             Checker()->GetGlobalTypesHolder()->GlobalCharBuiltinType());
1069             break;
1070         }
1071         case ir::BoxingUnboxingFlags::UNBOX_TO_SHORT: {
1072             EmitUnboxedCall(node, Signatures::BUILTIN_SHORT_UNBOXED, Checker()->GlobalShortType(),
1073                             Checker()->GetGlobalTypesHolder()->GlobalShortBuiltinType());
1074             break;
1075         }
1076         case ir::BoxingUnboxingFlags::UNBOX_TO_INT: {
1077             EmitUnboxedCall(node, Signatures::BUILTIN_INT_UNBOXED, Checker()->GlobalIntType(),
1078                             Checker()->GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
1079             break;
1080         }
1081         case ir::BoxingUnboxingFlags::UNBOX_TO_LONG: {
1082             EmitUnboxedCall(node, Signatures::BUILTIN_LONG_UNBOXED, Checker()->GlobalLongType(),
1083                             Checker()->GetGlobalTypesHolder()->GlobalLongBuiltinType());
1084             break;
1085         }
1086         case ir::BoxingUnboxingFlags::UNBOX_TO_FLOAT: {
1087             EmitUnboxedCall(node, Signatures::BUILTIN_FLOAT_UNBOXED, Checker()->GlobalFloatType(),
1088                             Checker()->GetGlobalTypesHolder()->GlobalFloatBuiltinType());
1089             break;
1090         }
1091         case ir::BoxingUnboxingFlags::UNBOX_TO_DOUBLE: {
1092             EmitUnboxedCall(node, Signatures::BUILTIN_DOUBLE_UNBOXED, Checker()->GlobalDoubleType(),
1093                             Checker()->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
1094             break;
1095         }
1096         default:
1097             UNREACHABLE();
1098     }
1099 }
1100 
EmitBoxingConversion(const ir::AstNode * node)1101 void ETSGen::EmitBoxingConversion(const ir::AstNode *node)
1102 {
1103     auto boxingFlag =
1104         static_cast<ir::BoxingUnboxingFlags>(ir::BoxingUnboxingFlags::BOXING_FLAG & node->GetBoxingUnboxingFlags());
1105 
1106     RegScope rs(this);
1107 
1108     switch (boxingFlag) {
1109         case ir::BoxingUnboxingFlags::BOX_TO_BOOLEAN: {
1110             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_BOOLEAN_VALUE_OF, dummyReg_, 0);
1111             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalETSBooleanBuiltinType());
1112             break;
1113         }
1114         case ir::BoxingUnboxingFlags::BOX_TO_BYTE: {
1115             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_BYTE_VALUE_OF, dummyReg_, 0);
1116             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalByteBuiltinType());
1117             break;
1118         }
1119         case ir::BoxingUnboxingFlags::BOX_TO_CHAR: {
1120             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_CHAR_VALUE_OF, dummyReg_, 0);
1121             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalCharBuiltinType());
1122             break;
1123         }
1124         case ir::BoxingUnboxingFlags::BOX_TO_SHORT: {
1125             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_SHORT_VALUE_OF, dummyReg_, 0);
1126             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalShortBuiltinType());
1127             break;
1128         }
1129         case ir::BoxingUnboxingFlags::BOX_TO_INT: {
1130             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_INT_VALUE_OF, dummyReg_, 0);
1131             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalIntegerBuiltinType());
1132             break;
1133         }
1134         case ir::BoxingUnboxingFlags::BOX_TO_LONG: {
1135             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_LONG_VALUE_OF, dummyReg_, 0);
1136             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalLongBuiltinType());
1137             break;
1138         }
1139         case ir::BoxingUnboxingFlags::BOX_TO_FLOAT: {
1140             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_FLOAT_VALUE_OF, dummyReg_, 0);
1141             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalFloatBuiltinType());
1142             break;
1143         }
1144         case ir::BoxingUnboxingFlags::BOX_TO_DOUBLE: {
1145             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_DOUBLE_VALUE_OF, dummyReg_, 0);
1146             SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalDoubleBuiltinType());
1147             break;
1148         }
1149         default:
1150             UNREACHABLE();
1151     }
1152 }
1153 
SwapBinaryOpArgs(const ir::AstNode * const node,const VReg lhs)1154 void ETSGen::SwapBinaryOpArgs(const ir::AstNode *const node, const VReg lhs)
1155 {
1156     const RegScope rs(this);
1157     const auto tmp = AllocReg();
1158 
1159     StoreAccumulator(node, tmp);
1160     LoadAccumulator(node, lhs);
1161     MoveVreg(node, lhs, tmp);
1162 }
1163 
MoveAccToReg(const ir::AstNode * const node)1164 VReg ETSGen::MoveAccToReg(const ir::AstNode *const node)
1165 {
1166     const auto newReg = AllocReg();
1167     StoreAccumulator(node, newReg);
1168     return newReg;
1169 }
1170 
EmitLocalBoxCtor(ir::AstNode const * node)1171 void ETSGen::EmitLocalBoxCtor(ir::AstNode const *node)
1172 {
1173     auto *contentType = node->AsIdentifier()->Variable()->TsType();
1174     switch (checker::ETSChecker::TypeKind(contentType)) {
1175         case checker::TypeFlag::ETS_BOOLEAN:
1176             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_BOOLEAN_BOX_CTOR, dummyReg_, dummyReg_);
1177             break;
1178         case checker::TypeFlag::BYTE:
1179             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_BYTE_BOX_CTOR, dummyReg_, dummyReg_);
1180             break;
1181         case checker::TypeFlag::CHAR:
1182             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_CHAR_BOX_CTOR, dummyReg_, dummyReg_);
1183             break;
1184         case checker::TypeFlag::SHORT:
1185             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_SHORT_BOX_CTOR, dummyReg_, dummyReg_);
1186             break;
1187         case checker::TypeFlag::INT:
1188             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_INT_BOX_CTOR, dummyReg_, dummyReg_);
1189             break;
1190         case checker::TypeFlag::LONG:
1191             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_LONG_BOX_CTOR, dummyReg_, dummyReg_);
1192             break;
1193         case checker::TypeFlag::FLOAT:
1194             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_FLOAT_BOX_CTOR, dummyReg_, dummyReg_);
1195             break;
1196         case checker::TypeFlag::DOUBLE:
1197             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_DOUBLE_BOX_CTOR, dummyReg_, dummyReg_);
1198             break;
1199         default:
1200             Ra().Emit<InitobjShort>(node, Signatures::BUILTIN_BOX_CTOR, dummyReg_, dummyReg_);
1201             break;
1202     }
1203     SetAccumulatorType(Checker()->GlobalBuiltinBoxType(contentType));
1204 }
1205 
EmitLocalBoxGet(ir::AstNode const * node,checker::Type const * contentType)1206 void ETSGen::EmitLocalBoxGet(ir::AstNode const *node, checker::Type const *contentType)
1207 {
1208     switch (checker::ETSChecker::TypeKind(contentType)) {
1209         case checker::TypeFlag::ETS_BOOLEAN:
1210             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_BOOLEAN_BOX_GET, dummyReg_, 0);
1211             break;
1212         case checker::TypeFlag::BYTE:
1213             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_BYTE_BOX_GET, dummyReg_, 0);
1214             break;
1215         case checker::TypeFlag::CHAR:
1216             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_CHAR_BOX_GET, dummyReg_, 0);
1217             break;
1218         case checker::TypeFlag::SHORT:
1219             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_SHORT_BOX_GET, dummyReg_, 0);
1220             break;
1221         case checker::TypeFlag::INT:
1222             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_INT_BOX_GET, dummyReg_, 0);
1223             break;
1224         case checker::TypeFlag::LONG:
1225             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_LONG_BOX_GET, dummyReg_, 0);
1226             break;
1227         case checker::TypeFlag::FLOAT:
1228             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_FLOAT_BOX_GET, dummyReg_, 0);
1229             break;
1230         case checker::TypeFlag::DOUBLE:
1231             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_DOUBLE_BOX_GET, dummyReg_, 0);
1232             break;
1233         default:
1234             Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_BOX_GET, dummyReg_, 0);
1235             CheckedReferenceNarrowing(node, contentType);
1236             break;
1237     }
1238     SetAccumulatorType(contentType);
1239 }
1240 
EmitLocalBoxSet(ir::AstNode const * node,varbinder::LocalVariable * lhsVar)1241 void ETSGen::EmitLocalBoxSet(ir::AstNode const *node, varbinder::LocalVariable *lhsVar)
1242 {
1243     auto *contentType = lhsVar->TsType();
1244     auto vreg = lhsVar->Vreg();
1245     switch (checker::ETSChecker::TypeKind(contentType)) {
1246         case checker::TypeFlag::ETS_BOOLEAN:
1247             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_BOOLEAN_BOX_SET, vreg, 1);
1248             break;
1249         case checker::TypeFlag::BYTE:
1250             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_BYTE_BOX_SET, vreg, 1);
1251             break;
1252         case checker::TypeFlag::CHAR:
1253             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_CHAR_BOX_SET, vreg, 1);
1254             break;
1255         case checker::TypeFlag::SHORT:
1256             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_SHORT_BOX_SET, vreg, 1);
1257             break;
1258         case checker::TypeFlag::INT:
1259             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_INT_BOX_SET, vreg, 1);
1260             break;
1261         case checker::TypeFlag::LONG:
1262             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_LONG_BOX_SET, vreg, 1);
1263             break;
1264         case checker::TypeFlag::FLOAT:
1265             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_FLOAT_BOX_SET, vreg, 1);
1266             break;
1267         case checker::TypeFlag::DOUBLE:
1268             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_DOUBLE_BOX_SET, vreg, 1);
1269             break;
1270         default:
1271             Ra().Emit<CallAccShort, 1>(node, Signatures::BUILTIN_BOX_SET, vreg, 1);
1272             break;
1273     }
1274     SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalVoidType());
1275 }
1276 
CastToBoolean(const ir::AstNode * node)1277 void ETSGen::CastToBoolean([[maybe_unused]] const ir::AstNode *node)
1278 {
1279     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1280     switch (typeKind) {
1281         case checker::TypeFlag::ETS_BOOLEAN: {
1282             return;
1283         }
1284         case checker::TypeFlag::CHAR: {
1285             Sa().Emit<U32tou1>(node);
1286             break;
1287         }
1288         case checker::TypeFlag::BYTE:
1289         case checker::TypeFlag::SHORT:
1290         case checker::TypeFlag::INT: {
1291             Sa().Emit<I32tou1>(node);
1292             return;
1293         }
1294         case checker::TypeFlag::LONG: {
1295             Sa().Emit<I64tou1>(node);
1296             break;
1297         }
1298         case checker::TypeFlag::FLOAT: {
1299             Sa().Emit<F32toi32>(node);
1300             Sa().Emit<I32tou1>(node);
1301             break;
1302         }
1303         case checker::TypeFlag::DOUBLE: {
1304             Sa().Emit<F64toi32>(node);
1305             Sa().Emit<I32tou1>(node);
1306             break;
1307         }
1308         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1309             CastDynamicTo(node, checker::TypeFlag::ETS_BOOLEAN);
1310             ASSERT(GetAccumulatorType() == Checker()->GlobalETSBooleanType());
1311             break;
1312         }
1313         default: {
1314             UNREACHABLE();
1315         }
1316     }
1317 
1318     SetAccumulatorType(Checker()->GlobalETSBooleanType());
1319 }
1320 
CastToByte(const ir::AstNode * node)1321 void ETSGen::CastToByte([[maybe_unused]] const ir::AstNode *node)
1322 {
1323     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1324     switch (typeKind) {
1325         case checker::TypeFlag::BYTE: {
1326             return;
1327         }
1328         case checker::TypeFlag::ETS_BOOLEAN:
1329         case checker::TypeFlag::CHAR: {
1330             Sa().Emit<U32toi8>(node);
1331             break;
1332         }
1333         case checker::TypeFlag::SHORT:
1334         case checker::TypeFlag::INT: {
1335             Sa().Emit<I32toi8>(node);
1336             break;
1337         }
1338         case checker::TypeFlag::LONG: {
1339             Sa().Emit<I64toi32>(node);
1340             Sa().Emit<I32toi8>(node);
1341             break;
1342         }
1343         case checker::TypeFlag::FLOAT: {
1344             Sa().Emit<F32toi32>(node);
1345             Sa().Emit<I32toi8>(node);
1346             break;
1347         }
1348         case checker::TypeFlag::DOUBLE: {
1349             Sa().Emit<F64toi32>(node);
1350             Sa().Emit<I32toi8>(node);
1351             break;
1352         }
1353         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1354             CastDynamicTo(node, checker::TypeFlag::BYTE);
1355             ASSERT(GetAccumulatorType() == Checker()->GlobalByteType());
1356             break;
1357         }
1358         default: {
1359             UNREACHABLE();
1360         }
1361     }
1362 
1363     SetAccumulatorType(Checker()->GlobalByteType());
1364 }
1365 
CastToChar(const ir::AstNode * node)1366 void ETSGen::CastToChar([[maybe_unused]] const ir::AstNode *node)
1367 {
1368     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1369     switch (typeKind) {
1370         case checker::TypeFlag::CHAR: {
1371             return;
1372         }
1373         case checker::TypeFlag::ETS_BOOLEAN: {
1374             break;
1375         }
1376         case checker::TypeFlag::BYTE:
1377         case checker::TypeFlag::SHORT:
1378         case checker::TypeFlag::INT: {
1379             Sa().Emit<I32tou16>(node);
1380             break;
1381         }
1382         case checker::TypeFlag::LONG: {
1383             Sa().Emit<I64toi32>(node);
1384             Sa().Emit<I32tou16>(node);
1385             break;
1386         }
1387         case checker::TypeFlag::FLOAT: {
1388             Sa().Emit<F32toi32>(node);
1389             Sa().Emit<I32tou16>(node);
1390             break;
1391         }
1392         case checker::TypeFlag::DOUBLE: {
1393             Sa().Emit<F64toi32>(node);
1394             Sa().Emit<I32tou16>(node);
1395             break;
1396         }
1397         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1398             CastDynamicTo(node, checker::TypeFlag::CHAR);
1399             ASSERT(GetAccumulatorType() == Checker()->GlobalCharType());
1400             break;
1401         }
1402         default: {
1403             UNREACHABLE();
1404         }
1405     }
1406 
1407     SetAccumulatorType(Checker()->GlobalCharType());
1408 }
1409 
CastToShort(const ir::AstNode * node)1410 void ETSGen::CastToShort([[maybe_unused]] const ir::AstNode *node)
1411 {
1412     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1413     switch (typeKind) {
1414         case checker::TypeFlag::SHORT: {
1415             return;
1416         }
1417         case checker::TypeFlag::ETS_BOOLEAN:
1418         case checker::TypeFlag::CHAR: {
1419             Sa().Emit<U32toi16>(node);
1420             break;
1421         }
1422         case checker::TypeFlag::BYTE: {
1423             break;
1424         }
1425         case checker::TypeFlag::INT: {
1426             Sa().Emit<I32toi16>(node);
1427             break;
1428         }
1429         case checker::TypeFlag::LONG: {
1430             Sa().Emit<I64toi32>(node);
1431             Sa().Emit<I32toi16>(node);
1432             break;
1433         }
1434         case checker::TypeFlag::FLOAT: {
1435             Sa().Emit<F32toi32>(node);
1436             Sa().Emit<I32toi16>(node);
1437             break;
1438         }
1439         case checker::TypeFlag::DOUBLE: {
1440             Sa().Emit<F64toi32>(node);
1441             Sa().Emit<I32toi16>(node);
1442             break;
1443         }
1444         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1445             CastDynamicTo(node, checker::TypeFlag::SHORT);
1446             ASSERT(GetAccumulatorType() == Checker()->GlobalShortType());
1447             break;
1448         }
1449         default: {
1450             UNREACHABLE();
1451         }
1452     }
1453 
1454     SetAccumulatorType(Checker()->GlobalShortType());
1455 }
1456 
CastToDouble(const ir::AstNode * node)1457 void ETSGen::CastToDouble(const ir::AstNode *node)
1458 {
1459     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1460     switch (typeKind) {
1461         case checker::TypeFlag::DOUBLE: {
1462             return;
1463         }
1464         case checker::TypeFlag::ETS_BOOLEAN:
1465         case checker::TypeFlag::CHAR: {
1466             Sa().Emit<U32tof64>(node);
1467             break;
1468         }
1469         case checker::TypeFlag::BYTE:
1470         case checker::TypeFlag::SHORT:
1471         case checker::TypeFlag::INT: {
1472             Sa().Emit<I32tof64>(node);
1473             break;
1474         }
1475         case checker::TypeFlag::LONG: {
1476             Sa().Emit<I64tof64>(node);
1477             break;
1478         }
1479         case checker::TypeFlag::FLOAT: {
1480             Sa().Emit<F32tof64>(node);
1481             break;
1482         }
1483         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1484             CastDynamicTo(node, checker::TypeFlag::DOUBLE);
1485             ASSERT(GetAccumulatorType() == Checker()->GlobalDoubleType());
1486             break;
1487         }
1488         default: {
1489             UNREACHABLE();
1490         }
1491     }
1492 
1493     SetAccumulatorType(Checker()->GlobalDoubleType());
1494 }
1495 
CastToFloat(const ir::AstNode * node)1496 void ETSGen::CastToFloat(const ir::AstNode *node)
1497 {
1498     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1499     switch (typeKind) {
1500         case checker::TypeFlag::FLOAT: {
1501             return;
1502         }
1503         case checker::TypeFlag::ETS_BOOLEAN:
1504         case checker::TypeFlag::CHAR: {
1505             Sa().Emit<U32tof32>(node);
1506             break;
1507         }
1508         case checker::TypeFlag::BYTE:
1509         case checker::TypeFlag::SHORT:
1510         case checker::TypeFlag::INT: {
1511             Sa().Emit<I32tof32>(node);
1512             break;
1513         }
1514         case checker::TypeFlag::LONG: {
1515             Sa().Emit<I64tof32>(node);
1516             break;
1517         }
1518         case checker::TypeFlag::DOUBLE: {
1519             Sa().Emit<F64tof32>(node);
1520             break;
1521         }
1522         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1523             CastDynamicTo(node, checker::TypeFlag::FLOAT);
1524             ASSERT(GetAccumulatorType() == Checker()->GlobalFloatType());
1525             break;
1526         }
1527         default: {
1528             UNREACHABLE();
1529         }
1530     }
1531 
1532     SetAccumulatorType(Checker()->GlobalFloatType());
1533 }
1534 
CastToLong(const ir::AstNode * node)1535 void ETSGen::CastToLong(const ir::AstNode *node)
1536 {
1537     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1538     switch (typeKind) {
1539         case checker::TypeFlag::LONG: {
1540             return;
1541         }
1542         case checker::TypeFlag::ETS_BOOLEAN:
1543         case checker::TypeFlag::CHAR: {
1544             Sa().Emit<U32toi64>(node);
1545             break;
1546         }
1547         case checker::TypeFlag::BYTE:
1548         case checker::TypeFlag::SHORT:
1549         case checker::TypeFlag::INT: {
1550             Sa().Emit<I32toi64>(node);
1551             break;
1552         }
1553         case checker::TypeFlag::FLOAT: {
1554             Sa().Emit<F32toi64>(node);
1555             break;
1556         }
1557         case checker::TypeFlag::DOUBLE: {
1558             Sa().Emit<F64toi64>(node);
1559             break;
1560         }
1561         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1562             CastDynamicTo(node, checker::TypeFlag::LONG);
1563             ASSERT(GetAccumulatorType() == Checker()->GlobalLongType());
1564             break;
1565         }
1566         default: {
1567             UNREACHABLE();
1568         }
1569     }
1570 
1571     SetAccumulatorType(Checker()->GlobalLongType());
1572 }
1573 
CastToInt(const ir::AstNode * node)1574 void ETSGen::CastToInt(const ir::AstNode *node)
1575 {
1576     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1577     switch (typeKind) {
1578         case checker::TypeFlag::INT: {
1579             return;
1580         }
1581         case checker::TypeFlag::ETS_BOOLEAN:
1582         case checker::TypeFlag::CHAR:
1583         case checker::TypeFlag::ETS_ENUM:
1584         case checker::TypeFlag::ETS_STRING_ENUM:
1585         case checker::TypeFlag::BYTE:
1586         case checker::TypeFlag::SHORT: {
1587             break;
1588         }
1589         case checker::TypeFlag::LONG: {
1590             Sa().Emit<I64toi32>(node);
1591             break;
1592         }
1593         case checker::TypeFlag::FLOAT: {
1594             Sa().Emit<F32toi32>(node);
1595             break;
1596         }
1597         case checker::TypeFlag::DOUBLE: {
1598             Sa().Emit<F64toi32>(node);
1599             break;
1600         }
1601         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1602             CastDynamicTo(node, checker::TypeFlag::INT);
1603             ASSERT(GetAccumulatorType() == Checker()->GlobalIntType());
1604             break;
1605         }
1606         default: {
1607             UNREACHABLE();
1608         }
1609     }
1610 
1611     SetAccumulatorType(Checker()->GlobalIntType());
1612 }
1613 
CastToArrayOrObject(const ir::AstNode * const node,const checker::Type * const targetType,const bool unchecked)1614 void ETSGen::CastToArrayOrObject(const ir::AstNode *const node, const checker::Type *const targetType,
1615                                  const bool unchecked)
1616 {
1617     ASSERT(GetAccumulatorType()->HasTypeFlag(TYPE_FLAG_BYTECODE_REF));
1618 
1619     const auto *const sourceType = GetAccumulatorType();
1620 
1621     if (sourceType->IsETSDynamicType()) {
1622         CastDynamicToObject(node, targetType);
1623         return;
1624     }
1625 
1626     if (targetType->IsETSDynamicType()) {
1627         CastToDynamic(node, targetType->AsETSDynamicType());
1628         return;
1629     }
1630 
1631     if (!unchecked) {
1632         CheckedReferenceNarrowing(node, targetType);
1633         return;
1634     }
1635 
1636     if (targetType->IsETSTypeParameter()) {
1637         CheckedReferenceNarrowing(node, targetType->AsETSTypeParameter()->GetConstraintType());
1638     } else if (targetType->IsETSObjectType()) {
1639         CheckedReferenceNarrowing(node, targetType->AsETSObjectType()->GetConstOriginalBaseType());
1640     }
1641     SetAccumulatorType(targetType);
1642 }
1643 
CastDynamicToObject(const ir::AstNode * node,const checker::Type * targetType)1644 void ETSGen::CastDynamicToObject(const ir::AstNode *node, const checker::Type *targetType)
1645 {
1646     if (targetType->IsETSStringType()) {
1647         CastDynamicTo(node, checker::TypeFlag::STRING);
1648         return;
1649     }
1650 
1651     // NOTE(vpukhov): #14626 remove, replace targetType with interface
1652     if (targetType->IsLambdaObject()) {
1653         VReg dynObjReg = AllocReg();
1654         StoreAccumulator(node, dynObjReg);
1655         Ra().Emit<InitobjShort>(node, targetType->AsETSObjectType()->ConstructSignatures()[0]->InternalName(),
1656                                 dynObjReg, dummyReg_);
1657         SetAccumulatorType(targetType);
1658         return;
1659     }
1660 
1661     if (targetType == Checker()->GlobalETSObjectType()) {
1662         SetAccumulatorType(targetType);
1663         return;
1664     }
1665 
1666     if (targetType->IsETSDynamicType()) {
1667         SetAccumulatorType(targetType);
1668         return;
1669     }
1670 
1671     if (targetType->IsETSArrayType() || targetType->IsETSObjectType() || targetType->IsETSTypeParameter()) {
1672         auto lang = GetAccumulatorType()->AsETSDynamicType()->Language();
1673         auto methodName = compiler::Signatures::Dynamic::GetObjectBuiltin(lang);
1674 
1675         RegScope rs(this);
1676         VReg dynObjReg = AllocReg();
1677         StoreAccumulator(node, dynObjReg);
1678 
1679         VReg typeReg = AllocReg();
1680         std::stringstream ss;
1681         targetType->ToAssemblerTypeWithRank(ss);
1682         Sa().Emit<LdaType>(node, util::UString(ss.str(), Allocator()).View());
1683         StoreAccumulator(node, typeReg);
1684 
1685         Ra().Emit<CallShort, 2U>(node, methodName, dynObjReg, typeReg);
1686         Sa().Emit<Checkcast>(node, util::UString(ss.str(), Allocator()).View());  // trick verifier
1687         SetAccumulatorType(targetType);
1688         return;
1689     }
1690 
1691     UNREACHABLE();
1692 }
1693 
CastToString(const ir::AstNode * const node)1694 void ETSGen::CastToString(const ir::AstNode *const node)
1695 {
1696     const auto *const sourceType = GetAccumulatorType();
1697     if (sourceType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1698         EmitBoxingConversion(node);
1699     } else {
1700         ASSERT(sourceType->HasTypeFlag(checker::TypeFlag::ETS_OBJECT));
1701     }
1702     Ra().Emit<CallVirtAccShort, 0>(node, Signatures::BUILTIN_OBJECT_TO_STRING, dummyReg_, 0);
1703     SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalETSStringBuiltinType());
1704 }
1705 
CastToDynamic(const ir::AstNode * node,const checker::ETSDynamicType * type)1706 void ETSGen::CastToDynamic(const ir::AstNode *node, const checker::ETSDynamicType *type)
1707 {
1708     std::string_view methodName {};
1709     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
1710     switch (typeKind) {
1711         case checker::TypeFlag::ETS_BOOLEAN: {
1712             methodName = compiler::Signatures::Dynamic::NewBooleanBuiltin(type->Language());
1713             break;
1714         }
1715         case checker::TypeFlag::BYTE: {
1716             methodName = compiler::Signatures::Dynamic::NewByteBuiltin(type->Language());
1717             break;
1718         }
1719         case checker::TypeFlag::CHAR: {
1720             methodName = compiler::Signatures::Dynamic::NewCharBuiltin(type->Language());
1721             break;
1722         }
1723         case checker::TypeFlag::SHORT: {
1724             methodName = compiler::Signatures::Dynamic::NewShortBuiltin(type->Language());
1725             break;
1726         }
1727         case checker::TypeFlag::INT: {
1728             methodName = compiler::Signatures::Dynamic::NewIntBuiltin(type->Language());
1729             break;
1730         }
1731         case checker::TypeFlag::LONG: {
1732             methodName = compiler::Signatures::Dynamic::NewLongBuiltin(type->Language());
1733             break;
1734         }
1735         case checker::TypeFlag::FLOAT: {
1736             methodName = compiler::Signatures::Dynamic::NewFloatBuiltin(type->Language());
1737             break;
1738         }
1739         case checker::TypeFlag::DOUBLE: {
1740             methodName = compiler::Signatures::Dynamic::NewDoubleBuiltin(type->Language());
1741             break;
1742         }
1743         case checker::TypeFlag::ETS_OBJECT:
1744         case checker::TypeFlag::ETS_TYPE_PARAMETER: {
1745             if (GetAccumulatorType()->IsETSStringType()) {
1746                 methodName = compiler::Signatures::Dynamic::NewStringBuiltin(type->Language());
1747                 break;
1748             }
1749             if (GetAccumulatorType()->IsLambdaObject()) {
1750                 methodName = Signatures::BUILTIN_JSRUNTIME_CREATE_LAMBDA_PROXY;
1751                 break;
1752             }
1753             [[fallthrough]];
1754         }
1755         case checker::TypeFlag::ETS_ARRAY: {
1756             methodName = compiler::Signatures::Dynamic::NewObjectBuiltin(type->Language());
1757             break;
1758         }
1759         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
1760             SetAccumulatorType(type);
1761             return;
1762         }
1763         default: {
1764             UNREACHABLE();
1765         }
1766     }
1767 
1768     ASSERT(!methodName.empty());
1769 
1770     RegScope rs(this);
1771     // Load value
1772     VReg valReg = AllocReg();
1773     StoreAccumulator(node, valReg);
1774 
1775     // Create new JSValue and initialize it
1776     Ra().Emit<CallShort, 1>(node, methodName, valReg, dummyReg_);
1777     SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(type->Language()));
1778 }
1779 
CastDynamicTo(const ir::AstNode * node,enum checker::TypeFlag typeFlag)1780 void ETSGen::CastDynamicTo(const ir::AstNode *node, enum checker::TypeFlag typeFlag)
1781 {
1782     std::string_view methodName {};
1783     checker::Type *objectType {};
1784     auto type = GetAccumulatorType()->AsETSDynamicType();
1785     switch (typeFlag) {
1786         case checker::TypeFlag::ETS_BOOLEAN: {
1787             methodName = compiler::Signatures::Dynamic::GetBooleanBuiltin(type->Language());
1788             objectType = Checker()->GlobalETSBooleanType();
1789             break;
1790         }
1791         case checker::TypeFlag::BYTE: {
1792             methodName = compiler::Signatures::Dynamic::GetByteBuiltin(type->Language());
1793             objectType = Checker()->GlobalByteType();
1794             break;
1795         }
1796         case checker::TypeFlag::CHAR: {
1797             methodName = compiler::Signatures::Dynamic::GetCharBuiltin(type->Language());
1798             objectType = Checker()->GlobalCharType();
1799             break;
1800         }
1801         case checker::TypeFlag::SHORT: {
1802             methodName = compiler::Signatures::Dynamic::GetShortBuiltin(type->Language());
1803             objectType = Checker()->GlobalShortType();
1804             break;
1805         }
1806         case checker::TypeFlag::INT: {
1807             methodName = compiler::Signatures::Dynamic::GetIntBuiltin(type->Language());
1808             objectType = Checker()->GlobalIntType();
1809             break;
1810         }
1811         case checker::TypeFlag::LONG: {
1812             methodName = compiler::Signatures::Dynamic::GetLongBuiltin(type->Language());
1813             objectType = Checker()->GlobalLongType();
1814             break;
1815         }
1816         case checker::TypeFlag::FLOAT: {
1817             methodName = compiler::Signatures::Dynamic::GetFloatBuiltin(type->Language());
1818             objectType = Checker()->GlobalFloatType();
1819             break;
1820         }
1821         case checker::TypeFlag::DOUBLE: {
1822             methodName = compiler::Signatures::Dynamic::GetDoubleBuiltin(type->Language());
1823             objectType = Checker()->GlobalDoubleType();
1824             break;
1825         }
1826         case checker::TypeFlag::STRING: {
1827             methodName = compiler::Signatures::Dynamic::GetStringBuiltin(type->Language());
1828             objectType = Checker()->GlobalBuiltinETSStringType();
1829             break;
1830         }
1831         default: {
1832             UNREACHABLE();
1833         }
1834     }
1835 
1836     RegScope rs(this);
1837     // Load dynamic object
1838     VReg dynObjReg = AllocReg();
1839     StoreAccumulator(node, dynObjReg);
1840 
1841     // Get value from dynamic object
1842     Ra().Emit<CallShort, 1>(node, methodName, dynObjReg, dummyReg_);
1843     SetAccumulatorType(objectType);
1844 }
1845 
ToBinaryResult(const ir::AstNode * node,Label * ifFalse)1846 void ETSGen::ToBinaryResult(const ir::AstNode *node, Label *ifFalse)
1847 {
1848     Label *end = AllocLabel();
1849     Sa().Emit<Ldai>(node, 1);
1850     Sa().Emit<Jmp>(node, end);
1851     SetLabel(node, ifFalse);
1852     Sa().Emit<Ldai>(node, 0);
1853     SetLabel(node, end);
1854     SetAccumulatorType(Checker()->GlobalETSBooleanType());
1855 }
1856 
Binary(const ir::AstNode * node,lexer::TokenType op,VReg lhs)1857 void ETSGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs)
1858 {
1859     switch (op) {
1860         case lexer::TokenType::PUNCTUATOR_EQUAL: {
1861             Label *ifFalse = AllocLabel();
1862             BinaryEquality<JneObj, Jne, Jnez, Jeqz>(node, lhs, ifFalse);
1863             break;
1864         }
1865         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
1866             Label *ifFalse = AllocLabel();
1867             BinaryEquality<JeqObj, Jeq, Jeqz, Jnez>(node, lhs, ifFalse);
1868             break;
1869         }
1870         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: {
1871             Label *ifFalse = AllocLabel();
1872             BinaryStrictEquality<JneObj, Jeqz>(node, lhs, ifFalse);
1873             break;
1874         }
1875         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
1876             Label *ifFalse = AllocLabel();
1877             BinaryStrictEquality<JeqObj, Jnez>(node, lhs, ifFalse);
1878             break;
1879         }
1880         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
1881             Label *ifFalse = AllocLabel();
1882             BinaryRelation<Jle, Jlez>(node, lhs, ifFalse);
1883             break;
1884         }
1885         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
1886             Label *ifFalse = AllocLabel();
1887             BinaryRelation<Jlt, Jltz>(node, lhs, ifFalse);
1888             break;
1889         }
1890         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
1891             Label *ifFalse = AllocLabel();
1892             BinaryRelation<Jge, Jgez>(node, lhs, ifFalse);
1893             break;
1894         }
1895         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
1896             Label *ifFalse = AllocLabel();
1897             BinaryRelation<Jgt, Jgtz>(node, lhs, ifFalse);
1898             break;
1899         }
1900         case lexer::TokenType::PUNCTUATOR_PLUS:
1901         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
1902             SwapBinaryOpArgs(node, lhs);
1903             BinaryArithmetic<Add2, Add2Wide, Fadd2, Fadd2Wide>(node, lhs);
1904             break;
1905         }
1906         case lexer::TokenType::PUNCTUATOR_MINUS:
1907         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: {
1908             SwapBinaryOpArgs(node, lhs);
1909             BinaryArithmetic<Sub2, Sub2Wide, Fsub2, Fsub2Wide>(node, lhs);
1910             break;
1911         }
1912         case lexer::TokenType::PUNCTUATOR_MULTIPLY:
1913         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: {
1914             SwapBinaryOpArgs(node, lhs);
1915             BinaryArithmetic<Mul2, Mul2Wide, Fmul2, Fmul2Wide>(node, lhs);
1916             break;
1917         }
1918         case lexer::TokenType::PUNCTUATOR_DIVIDE:
1919         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
1920             SwapBinaryOpArgs(node, lhs);
1921             BinaryArithmetic<Div2, Div2Wide, Fdiv2, Fdiv2Wide>(node, lhs);
1922             break;
1923         }
1924         case lexer::TokenType::PUNCTUATOR_MOD:
1925         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: {
1926             SwapBinaryOpArgs(node, lhs);
1927             BinaryArithmetic<Mod2, Mod2Wide, Fmod2, Fmod2Wide>(node, lhs);
1928             break;
1929         }
1930         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
1931         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: {
1932             SwapBinaryOpArgs(node, lhs);
1933             BinaryBitwiseArithmetic<Shl2, Shl2Wide>(node, lhs);
1934             break;
1935         }
1936         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
1937         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: {
1938             SwapBinaryOpArgs(node, lhs);
1939             BinaryBitwiseArithmetic<Ashr2, Ashr2Wide>(node, lhs);
1940             break;
1941         }
1942         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
1943         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: {
1944             SwapBinaryOpArgs(node, lhs);
1945             BinaryBitwiseArithmetic<Shr2, Shr2Wide>(node, lhs);
1946             break;
1947         }
1948         case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
1949         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: {
1950             BinaryBitwiseArithmetic<And2, And2Wide>(node, lhs);
1951             break;
1952         }
1953         case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
1954         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
1955             BinaryBitwiseArithmetic<Or2, Or2Wide>(node, lhs);
1956             break;
1957         }
1958         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
1959         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: {
1960             BinaryBitwiseArithmetic<Xor2, Xor2Wide>(node, lhs);
1961             break;
1962         }
1963         case lexer::TokenType::KEYW_INSTANCEOF: {
1964             EmitIsInstance(node, lhs);
1965             break;
1966         }
1967         default: {
1968             UNREACHABLE();
1969         }
1970     }
1971     ASSERT(node->IsAssignmentExpression() || node->IsBinaryExpression());
1972     ASSERT(GetAccumulatorType() == node->AsExpression()->TsType());
1973 }
1974 
Condition(const ir::AstNode * node,lexer::TokenType op,VReg lhs,Label * ifFalse)1975 void ETSGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse)
1976 {
1977     switch (op) {
1978         case lexer::TokenType::PUNCTUATOR_EQUAL: {
1979             BinaryEqualityCondition<JneObj, Jne, Jnez>(node, lhs, ifFalse);
1980             break;
1981         }
1982         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
1983             BinaryEqualityCondition<JeqObj, Jeq, Jeqz>(node, lhs, ifFalse);
1984             break;
1985         }
1986         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
1987             BinaryRelationCondition<Jle, Jlez>(node, lhs, ifFalse);
1988             break;
1989         }
1990         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
1991             BinaryRelationCondition<Jlt, Jltz>(node, lhs, ifFalse);
1992             break;
1993         }
1994         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
1995             BinaryRelationCondition<Jge, Jgez>(node, lhs, ifFalse);
1996             break;
1997         }
1998         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
1999             BinaryRelationCondition<Jgt, Jgtz>(node, lhs, ifFalse);
2000             break;
2001         }
2002         case lexer::TokenType::KEYW_INSTANCEOF: {
2003             EmitIsInstance(node, lhs);
2004             BranchIfFalse(node, ifFalse);
2005             break;
2006         }
2007         default: {
2008             UNREACHABLE();
2009         }
2010     }
2011 }
2012 
BranchIfNullish(const ir::AstNode * node,Label * ifNullish)2013 void ETSGen::BranchIfNullish([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] Label *ifNullish)
2014 {
2015 #ifdef PANDA_WITH_ETS
2016     auto *const type = GetAccumulatorType();
2017 
2018     if (!Checker()->MayHaveNulllikeValue(type)) {
2019         return;
2020     }
2021     if (type->IsETSNullLike()) {
2022         Sa().Emit<Jmp>(node, ifNullish);
2023         return;
2024     }
2025     if (!Checker()->MayHaveUndefinedValue(type)) {
2026         Sa().Emit<JeqzObj>(node, ifNullish);
2027         return;
2028     }
2029 
2030     Sa().Emit<JeqzObj>(node, ifNullish);
2031 
2032     auto tmpObj = AllocReg();
2033     auto notTaken = AllocLabel();
2034 
2035     Sa().Emit<StaObj>(node, tmpObj);
2036     Sa().Emit<EtsIsundefined>(node);
2037     Sa().Emit<Jeqz>(node, notTaken);
2038 
2039     Sa().Emit<LdaObj>(node, tmpObj);
2040     Sa().Emit<Jmp>(node, ifNullish);
2041 
2042     SetLabel(node, notTaken);
2043     Sa().Emit<LdaObj>(node, tmpObj);
2044 #else
2045     UNREACHABLE();
2046 #endif  // PANDA_WITH_ETS
2047 }
2048 
BranchIfNotNullish(const ir::AstNode * node,Label * ifNotNullish)2049 void ETSGen::BranchIfNotNullish([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] Label *ifNotNullish)
2050 {
2051 #ifdef PANDA_WITH_ETS
2052     auto *const type = GetAccumulatorType();
2053 
2054     if (!Checker()->MayHaveNulllikeValue(type)) {
2055         Sa().Emit<Jmp>(node, ifNotNullish);
2056         return;
2057     }
2058     if (type->IsETSNullLike()) {
2059         return;
2060     }
2061     if (!Checker()->MayHaveUndefinedValue(type)) {
2062         Sa().Emit<JnezObj>(node, ifNotNullish);
2063         return;
2064     }
2065 
2066     auto end = AllocLabel();
2067     auto tmpObj = AllocReg();
2068     auto notTaken = AllocLabel();
2069 
2070     Sa().Emit<JeqzObj>(node, end);
2071 
2072     Sa().Emit<StaObj>(node, tmpObj);
2073     Sa().Emit<EtsIsundefined>(node);
2074     Sa().Emit<Jnez>(node, notTaken);
2075 
2076     Sa().Emit<LdaObj>(node, tmpObj);
2077     Sa().Emit<Jmp>(node, ifNotNullish);
2078 
2079     SetLabel(node, notTaken);
2080     Sa().Emit<LdaObj>(node, tmpObj);
2081     SetLabel(node, end);
2082 #else
2083     UNREACHABLE();
2084 #endif  // PANDA_WITH_ETS
2085 }
2086 
ConvertToNonNullish(const ir::AstNode * node)2087 void ETSGen::ConvertToNonNullish(const ir::AstNode *node)
2088 {
2089     auto const *nullishType = GetAccumulatorType();
2090     auto const *targetType = Checker()->GetNonNullishType(nullishType);
2091     if (Checker()->MayHaveUndefinedValue(nullishType) && targetType != Checker()->GlobalETSObjectType()) {
2092         CheckedReferenceNarrowing(node, targetType);
2093     }
2094     SetAccumulatorType(targetType);
2095 }
2096 
EmitNullishGuardian(const ir::AstNode * node)2097 void ETSGen::EmitNullishGuardian(const ir::AstNode *node)
2098 {
2099     auto const *nullishType = GetAccumulatorType();
2100     ASSERT(Checker()->MayHaveNulllikeValue(nullishType));
2101 
2102     compiler::Label *ifNotNullish = AllocLabel();
2103     BranchIfNotNullish(node, ifNotNullish);
2104     EmitNullishException(node);
2105 
2106     SetLabel(node, ifNotNullish);
2107     SetAccumulatorType(nullishType);
2108     ConvertToNonNullish(node);
2109 }
2110 
EmitNullishException(const ir::AstNode * node)2111 void ETSGen::EmitNullishException(const ir::AstNode *node)
2112 {
2113     VReg exception = StoreException(node);
2114     NewObject(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION);
2115     CallThisStatic0(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION_CTOR);
2116     EmitThrow(node, exception);
2117     SetAccumulatorType(nullptr);
2118 }
2119 
BinaryEqualityRefDynamic(const ir::AstNode * node,bool testEqual,VReg lhs,VReg rhs,Label * ifFalse)2120 void ETSGen::BinaryEqualityRefDynamic(const ir::AstNode *node, bool testEqual, VReg lhs, VReg rhs, Label *ifFalse)
2121 {
2122     // NOTE: vpukhov. implement
2123     LoadAccumulator(node, lhs);
2124     if (testEqual) {
2125         Ra().Emit<JneObj>(node, rhs, ifFalse);
2126     } else {
2127         Ra().Emit<JeqObj>(node, rhs, ifFalse);
2128     }
2129 }
2130 
BinaryEqualityRef(const ir::AstNode * node,bool testEqual,VReg lhs,VReg rhs,Label * ifFalse)2131 void ETSGen::BinaryEqualityRef(const ir::AstNode *node, bool testEqual, VReg lhs, VReg rhs, Label *ifFalse)
2132 {
2133     Label *ifTrue = AllocLabel();
2134     if (GetVRegType(lhs)->IsETSDynamicType() || GetVRegType(rhs)->IsETSDynamicType()) {
2135         BinaryEqualityRefDynamic(node, testEqual, lhs, rhs, ifFalse);
2136         return;
2137     }
2138 
2139     if (GetVRegType(lhs)->IsETSNullLike() || GetVRegType(rhs)->IsETSNullLike()) {
2140         LoadAccumulator(node, GetVRegType(lhs)->IsETSNullLike() ? rhs : lhs);
2141         testEqual ? BranchIfNotNullish(node, ifFalse) : BranchIfNullish(node, ifFalse);
2142     } else {
2143         Label *ifLhsNullish = AllocLabel();
2144 
2145         auto const rhsNullishType = GetVRegType(rhs);
2146 
2147         LoadAccumulator(node, lhs);
2148         BranchIfNullish(node, ifLhsNullish);
2149         ConvertToNonNullish(node);
2150         StoreAccumulator(node, lhs);
2151 
2152         LoadAccumulator(node, rhs);
2153         BranchIfNullish(node, testEqual ? ifFalse : ifTrue);
2154         ConvertToNonNullish(node);
2155         StoreAccumulator(node, rhs);
2156 
2157         LoadAccumulator(node, lhs);
2158 
2159         if (GetVRegType(lhs)->IsETSBigIntType()) {
2160             CallThisStatic1(node, lhs, Signatures::BUILTIN_BIGINT_EQUALS, rhs);
2161         } else if (GetVRegType(lhs)->IsETSStringType()) {
2162             CallThisStatic1(node, lhs, Signatures::BUILTIN_STRING_EQUALS, rhs);
2163         } else {
2164             CallThisVirtual1(node, lhs, Signatures::BUILTIN_OBJECT_EQUALS, rhs);
2165         }
2166         testEqual ? BranchIfFalse(node, ifFalse) : BranchIfTrue(node, ifFalse);
2167         JumpTo(node, ifTrue);
2168 
2169         SetLabel(node, ifLhsNullish);
2170         LoadAccumulator(node, rhs);
2171         SetAccumulatorType(rhsNullishType);
2172         testEqual ? BranchIfNotNullish(node, ifFalse) : BranchIfNullish(node, ifFalse);
2173         // fallthrough
2174     }
2175     SetLabel(node, ifTrue);
2176     SetAccumulatorType(nullptr);
2177 }
2178 
CompileStatements(const ArenaVector<ir::Statement * > & statements)2179 void ETSGen::CompileStatements(const ArenaVector<ir::Statement *> &statements)
2180 {
2181     for (const auto *stmt : statements) {
2182         stmt->Compile(this);
2183     }
2184 }
2185 
Negate(const ir::AstNode * node)2186 void ETSGen::Negate(const ir::AstNode *node)
2187 {
2188     auto typeKind = checker::ETSChecker::TypeKind(GetAccumulatorType());
2189 
2190     switch (typeKind) {
2191         case checker::TypeFlag::BYTE:
2192         case checker::TypeFlag::SHORT:
2193         case checker::TypeFlag::CHAR:
2194         case checker::TypeFlag::INT: {
2195             Sa().Emit<Neg>(node);
2196             return;
2197         }
2198         case checker::TypeFlag::LONG: {
2199             Sa().Emit<NegWide>(node);
2200             break;
2201         }
2202         case checker::TypeFlag::FLOAT: {
2203             Sa().Emit<Fneg>(node);
2204             break;
2205         }
2206         case checker::TypeFlag::DOUBLE: {
2207             Sa().Emit<FnegWide>(node);
2208             break;
2209         }
2210         default: {
2211             UNREACHABLE();
2212         }
2213     }
2214 }
2215 
LogicalNot(const ir::AstNode * node)2216 void ETSGen::LogicalNot(const ir::AstNode *node)
2217 {
2218     ASSERT(GetAccumulatorType()->IsConditionalExprType());
2219     ResolveConditionalResultIfFalse<true, false>(node);
2220     Sa().Emit<Xori>(node, 1);
2221     SetAccumulatorType(Checker()->GlobalETSBooleanType());
2222 }
2223 
Unary(const ir::AstNode * node,lexer::TokenType op)2224 void ETSGen::Unary(const ir::AstNode *node, lexer::TokenType op)
2225 {
2226     switch (op) {
2227         case lexer::TokenType::PUNCTUATOR_PLUS: {
2228             break;  // NOP -> Unary numeric promotion is performed
2229         }
2230         case lexer::TokenType::PUNCTUATOR_MINUS: {
2231             UnaryMinus(node);
2232             break;
2233         }
2234         case lexer::TokenType::PUNCTUATOR_TILDE: {
2235             UnaryTilde(node);
2236             break;
2237         }
2238         case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
2239             LogicalNot(node);
2240             break;
2241         }
2242         case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: {
2243             UnaryDollarDollar(node);
2244             break;
2245         }
2246         default: {
2247             UNREACHABLE();
2248         }
2249     }
2250 }
2251 
UnaryMinus(const ir::AstNode * node)2252 void ETSGen::UnaryMinus(const ir::AstNode *node)
2253 {
2254     if (GetAccumulatorType()->IsETSBigIntType()) {
2255         const VReg value = AllocReg();
2256         StoreAccumulator(node, value);
2257         CallThisStatic0(node, value, Signatures::BUILTIN_BIGINT_NEGATE);
2258         return;
2259     }
2260 
2261     switch (checker::ETSChecker::ETSType(GetAccumulatorType())) {
2262         case checker::TypeFlag::LONG: {
2263             Sa().Emit<NegWide>(node);
2264             break;
2265         }
2266         case checker::TypeFlag::INT:
2267         case checker::TypeFlag::SHORT:
2268         case checker::TypeFlag::CHAR:
2269         case checker::TypeFlag::BYTE: {
2270             Sa().Emit<Neg>(node);
2271             break;
2272         }
2273         case checker::TypeFlag::DOUBLE: {
2274             Sa().Emit<FnegWide>(node);
2275             break;
2276         }
2277         case checker::TypeFlag::FLOAT: {
2278             Sa().Emit<Fneg>(node);
2279             break;
2280         }
2281         default: {
2282             UNREACHABLE();
2283         }
2284     }
2285 }
2286 
UnaryTilde(const ir::AstNode * node)2287 void ETSGen::UnaryTilde(const ir::AstNode *node)
2288 {
2289     if (GetAccumulatorType()->IsETSBigIntType()) {
2290         const VReg value = AllocReg();
2291         StoreAccumulator(node, value);
2292         CallThisStatic0(node, value, Signatures::BUILTIN_BIGINT_OPERATOR_BITWISE_NOT);
2293         SetAccumulatorType(Checker()->GlobalETSBigIntType());
2294         return;
2295     }
2296 
2297     switch (checker::ETSChecker::ETSType(GetAccumulatorType())) {
2298         case checker::TypeFlag::LONG: {
2299             Sa().Emit<NotWide>(node);
2300             break;
2301         }
2302         case checker::TypeFlag::INT:
2303         case checker::TypeFlag::SHORT:
2304         case checker::TypeFlag::CHAR:
2305         case checker::TypeFlag::BYTE: {
2306             Sa().Emit<Not>(node);
2307             break;
2308         }
2309         default: {
2310             UNREACHABLE();
2311         }
2312     }
2313 }
2314 
UnaryDollarDollar(const ir::AstNode * node)2315 void ETSGen::UnaryDollarDollar(const ir::AstNode *node)
2316 {
2317     RegScope rs(this);
2318     VReg exception = StoreException(node);
2319     Sa().Emit<LdaStr>(node, "$$ operator can only be used with ARKUI plugin");
2320     StoreAccumulator(node, exception);
2321     EmitThrow(node, exception);
2322 }
2323 
Update(const ir::AstNode * node,lexer::TokenType op)2324 void ETSGen::Update(const ir::AstNode *node, lexer::TokenType op)
2325 {
2326     switch (op) {
2327         case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: {
2328             UpdateOperator<Add2Wide, Addi, Fadd2Wide, Fadd2>(node);
2329             break;
2330         }
2331         case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: {
2332             UpdateOperator<Sub2Wide, Subi, Fsub2Wide, Fsub2>(node);
2333             break;
2334         }
2335         default: {
2336             UNREACHABLE();
2337         }
2338     }
2339 }
2340 
UpdateBigInt(const ir::Expression * node,VReg arg,lexer::TokenType op)2341 void ETSGen::UpdateBigInt(const ir::Expression *node, VReg arg, lexer::TokenType op)
2342 {
2343     switch (op) {
2344         case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: {
2345             CallBigIntUnaryOperator(node, arg, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_INCREMENT);
2346             break;
2347         }
2348         case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: {
2349             CallBigIntUnaryOperator(node, arg, compiler::Signatures::BUILTIN_BIGINT_OPERATOR_DECREMENT);
2350             break;
2351         }
2352         default: {
2353             UNREACHABLE();
2354         }
2355     }
2356 }
2357 
StringBuilderAppend(const ir::AstNode * node,VReg builder)2358 void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder)
2359 {
2360     RegScope rs(this);
2361     util::StringView signature {};
2362 
2363     node->Compile(this);
2364 
2365     std::unordered_map<checker::TypeFlag, std::string_view> typeFlagToSignaturesMap {
2366         {checker::TypeFlag::ETS_BOOLEAN, Signatures::BUILTIN_STRING_BUILDER_APPEND_BOOLEAN},
2367         {checker::TypeFlag::CHAR, Signatures::BUILTIN_STRING_BUILDER_APPEND_CHAR},
2368         {checker::TypeFlag::SHORT, Signatures::BUILTIN_STRING_BUILDER_APPEND_INT},
2369         {checker::TypeFlag::BYTE, Signatures::BUILTIN_STRING_BUILDER_APPEND_INT},
2370         {checker::TypeFlag::INT, Signatures::BUILTIN_STRING_BUILDER_APPEND_INT},
2371         {checker::TypeFlag::LONG, Signatures::BUILTIN_STRING_BUILDER_APPEND_LONG},
2372         {checker::TypeFlag::FLOAT, Signatures::BUILTIN_STRING_BUILDER_APPEND_FLOAT},
2373         {checker::TypeFlag::DOUBLE, Signatures::BUILTIN_STRING_BUILDER_APPEND_DOUBLE},
2374     };
2375 
2376     auto search = typeFlagToSignaturesMap.find(checker::ETSChecker::ETSType(GetAccumulatorType()));
2377     if (search != typeFlagToSignaturesMap.end()) {
2378         signature = search->second;
2379     } else {
2380         signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BUILTIN_STRING;
2381     }
2382 
2383     if ((GetAccumulatorType()->IsETSObjectType() || GetAccumulatorType()->IsETSTypeParameter()) &&
2384         !GetAccumulatorType()->IsETSStringType()) {
2385         if (Checker()->MayHaveNullValue(GetAccumulatorType())) {
2386             Label *ifnull = AllocLabel();
2387             Label *end = AllocLabel();
2388             BranchIfNull(node, ifnull);
2389             Ra().Emit<CallVirtAccShort, 0>(node, Signatures::BUILTIN_OBJECT_TO_STRING, dummyReg_, 0);
2390             JumpTo(node, end);
2391 
2392             SetLabel(node, ifnull);
2393             LoadAccumulatorString(node, "null");
2394 
2395             SetLabel(node, end);
2396         } else {
2397             Ra().Emit<CallVirtAccShort, 0>(node, Signatures::BUILTIN_OBJECT_TO_STRING, dummyReg_, 0);
2398         }
2399     }
2400 
2401     VReg arg0 = AllocReg();
2402     StoreAccumulator(node, arg0);
2403 
2404     CallThisStatic1(node, builder, signature, arg0);
2405     SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalStringBuilderBuiltinType());
2406 }
2407 
AppendString(const ir::Expression * const expr,const VReg builder)2408 void ETSGen::AppendString(const ir::Expression *const expr, const VReg builder)
2409 {
2410     ASSERT((expr->IsBinaryExpression() &&
2411             expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) ||
2412            (expr->IsAssignmentExpression() &&
2413             expr->AsAssignmentExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS_EQUAL));
2414 
2415     if (expr->IsBinaryExpression()) {
2416         StringBuilder(expr->AsBinaryExpression()->Left(), expr->AsBinaryExpression()->Right(), builder);
2417     } else {
2418         StringBuilder(expr->AsAssignmentExpression()->Left(), expr->AsAssignmentExpression()->Right(), builder);
2419     }
2420 }
2421 
StringBuilder(const ir::Expression * const left,const ir::Expression * const right,const VReg builder)2422 void ETSGen::StringBuilder(const ir::Expression *const left, const ir::Expression *const right, const VReg builder)
2423 {
2424     if (left->IsBinaryExpression()) {
2425         AppendString(left->AsBinaryExpression(), builder);
2426     } else {
2427         StringBuilderAppend(left, builder);
2428     }
2429 
2430     StringBuilderAppend(right, builder);
2431 }
2432 
BuildString(const ir::Expression * node)2433 void ETSGen::BuildString(const ir::Expression *node)
2434 {
2435     RegScope rs(this);
2436 
2437     Ra().Emit<InitobjShort, 0>(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, dummyReg_, dummyReg_);
2438     SetAccumulatorType(Checker()->GlobalStringBuilderBuiltinType());
2439 
2440     auto builder = AllocReg();
2441     StoreAccumulator(node, builder);
2442 
2443     AppendString(node, builder);
2444     CallThisStatic0(node, builder, Signatures::BUILTIN_STRING_BUILDER_TO_STRING);
2445 
2446     SetAccumulatorType(node->TsType());
2447 }
2448 
CallBigIntUnaryOperator(const ir::Expression * node,VReg arg,const util::StringView signature)2449 void ETSGen::CallBigIntUnaryOperator(const ir::Expression *node, VReg arg, const util::StringView signature)
2450 {
2451     LoadAccumulator(node, arg);
2452     CallThisStatic0(node, arg, signature);
2453     SetAccumulatorType(Checker()->GlobalETSBigIntType());
2454 }
2455 
CallBigIntBinaryOperator(const ir::Expression * node,VReg lhs,VReg rhs,const util::StringView signature)2456 void ETSGen::CallBigIntBinaryOperator(const ir::Expression *node, VReg lhs, VReg rhs, const util::StringView signature)
2457 {
2458     LoadAccumulator(node, lhs);
2459     CallThisStatic1(node, lhs, signature, rhs);
2460     SetAccumulatorType(Checker()->GlobalETSBigIntType());
2461 }
2462 
CallBigIntBinaryComparison(const ir::Expression * node,VReg lhs,VReg rhs,const util::StringView signature)2463 void ETSGen::CallBigIntBinaryComparison(const ir::Expression *node, VReg lhs, VReg rhs,
2464                                         const util::StringView signature)
2465 {
2466     LoadAccumulator(node, lhs);
2467     CallThisStatic1(node, lhs, signature, rhs);
2468     SetAccumulatorType(Checker()->GlobalETSBooleanType());
2469 }
2470 
BuildTemplateString(const ir::TemplateLiteral * node)2471 void ETSGen::BuildTemplateString(const ir::TemplateLiteral *node)
2472 {
2473     RegScope rs(this);
2474 
2475     Ra().Emit<InitobjShort, 0>(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, dummyReg_, dummyReg_);
2476     SetAccumulatorType(Checker()->GlobalStringBuilderBuiltinType());
2477 
2478     auto builder = AllocReg();
2479     StoreAccumulator(node, builder);
2480 
2481     // Just to reduce extra nested level(s):
2482     auto const appendExpressions = [this, &builder](ArenaVector<ir::Expression *> const &expressions,
2483                                                     ArenaVector<ir::TemplateElement *> const &quasis) -> void {
2484         auto const num = expressions.size();
2485         std::size_t i = 0U;
2486 
2487         while (i < num) {
2488             StringBuilderAppend(expressions[i], builder);
2489             if (!quasis[++i]->Raw().Empty()) {
2490                 StringBuilderAppend(quasis[i], builder);
2491             }
2492         }
2493     };
2494 
2495     if (auto const &quasis = node->Quasis(); !quasis.empty()) {
2496         if (!quasis[0]->Raw().Empty()) {
2497             StringBuilderAppend(quasis[0], builder);
2498         }
2499 
2500         if (auto const &expressions = node->Expressions(); !expressions.empty()) {
2501             appendExpressions(expressions, quasis);
2502         }
2503     }
2504 
2505     CallThisStatic0(node, builder, Signatures::BUILTIN_STRING_BUILDER_TO_STRING);
2506 
2507     SetAccumulatorType(Checker()->GlobalBuiltinETSStringType());
2508 }
2509 
NewObject(const ir::AstNode * const node,const VReg ctor,const util::StringView name)2510 void ETSGen::NewObject(const ir::AstNode *const node, const VReg ctor, const util::StringView name)
2511 {
2512     Ra().Emit<Newobj>(node, ctor, name);
2513     SetVRegType(ctor, Checker()->GlobalETSObjectType());
2514 }
2515 
NewArray(const ir::AstNode * const node,const VReg arr,const VReg dim,const checker::Type * const arrType)2516 void ETSGen::NewArray(const ir::AstNode *const node, const VReg arr, const VReg dim, const checker::Type *const arrType)
2517 {
2518     std::stringstream ss;
2519     arrType->ToAssemblerTypeWithRank(ss);
2520     const auto res = ProgElement()->Strings().emplace(ss.str());
2521 
2522     Ra().Emit<Newarr>(node, arr, dim, util::StringView(*res.first));
2523     SetVRegType(arr, arrType);
2524 }
2525 
LoadArrayLength(const ir::AstNode * node,VReg arrayReg)2526 void ETSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg)
2527 {
2528     Ra().Emit<Lenarr>(node, arrayReg);
2529     SetAccumulatorType(Checker()->GlobalIntType());
2530 }
2531 
LoadArrayElement(const ir::AstNode * node,VReg objectReg)2532 void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg)
2533 {
2534     auto *elementType = GetVRegType(objectReg)->AsETSArrayType()->ElementType();
2535     switch (checker::ETSChecker::ETSType(elementType)) {
2536         case checker::TypeFlag::ETS_BOOLEAN:
2537         case checker::TypeFlag::BYTE: {
2538             Ra().Emit<Ldarr8>(node, objectReg);
2539             break;
2540         }
2541         case checker::TypeFlag::CHAR: {
2542             Ra().Emit<Ldarru16>(node, objectReg);
2543             break;
2544         }
2545         case checker::TypeFlag::SHORT: {
2546             Ra().Emit<Ldarr16>(node, objectReg);
2547             break;
2548         }
2549         case checker::TypeFlag::ETS_STRING_ENUM:
2550             [[fallthrough]];
2551         case checker::TypeFlag::ETS_ENUM:
2552         case checker::TypeFlag::INT: {
2553             Ra().Emit<Ldarr>(node, objectReg);
2554             break;
2555         }
2556         case checker::TypeFlag::LONG: {
2557             Ra().Emit<LdarrWide>(node, objectReg);
2558             break;
2559         }
2560         case checker::TypeFlag::FLOAT: {
2561             Ra().Emit<Fldarr32>(node, objectReg);
2562             break;
2563         }
2564         case checker::TypeFlag::DOUBLE: {
2565             Ra().Emit<FldarrWide>(node, objectReg);
2566             break;
2567         }
2568         case checker::TypeFlag::ETS_ARRAY:
2569         case checker::TypeFlag::ETS_OBJECT:
2570         case checker::TypeFlag::ETS_TYPE_PARAMETER:
2571         case checker::TypeFlag::ETS_UNION:
2572         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
2573             Ra().Emit<LdarrObj>(node, objectReg);
2574             break;
2575         }
2576 
2577         default: {
2578             UNREACHABLE();
2579         }
2580     }
2581 
2582     SetAccumulatorType(elementType);
2583 }
2584 
StoreArrayElement(const ir::AstNode * node,VReg objectReg,VReg index,const checker::Type * elementType)2585 void ETSGen::StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index, const checker::Type *elementType)
2586 {
2587     switch (checker::ETSChecker::ETSType(elementType)) {
2588         case checker::TypeFlag::ETS_BOOLEAN:
2589         case checker::TypeFlag::BYTE: {
2590             Ra().Emit<Starr8>(node, objectReg, index);
2591             break;
2592         }
2593         case checker::TypeFlag::CHAR:
2594         case checker::TypeFlag::SHORT: {
2595             Ra().Emit<Starr16>(node, objectReg, index);
2596             break;
2597         }
2598         case checker::TypeFlag::ETS_STRING_ENUM:
2599             [[fallthrough]];
2600         case checker::TypeFlag::ETS_ENUM:
2601         case checker::TypeFlag::INT: {
2602             Ra().Emit<Starr>(node, objectReg, index);
2603             break;
2604         }
2605         case checker::TypeFlag::LONG: {
2606             Ra().Emit<StarrWide>(node, objectReg, index);
2607             break;
2608         }
2609         case checker::TypeFlag::FLOAT: {
2610             Ra().Emit<Fstarr32>(node, objectReg, index);
2611             break;
2612         }
2613         case checker::TypeFlag::DOUBLE: {
2614             Ra().Emit<FstarrWide>(node, objectReg, index);
2615             break;
2616         }
2617         case checker::TypeFlag::ETS_ARRAY:
2618         case checker::TypeFlag::ETS_OBJECT:
2619         case checker::TypeFlag::ETS_TYPE_PARAMETER:
2620         case checker::TypeFlag::ETS_UNION:
2621         case checker::TypeFlag::ETS_DYNAMIC_TYPE: {
2622             Ra().Emit<StarrObj>(node, objectReg, index);
2623             break;
2624         }
2625 
2626         default: {
2627             UNREACHABLE();
2628         }
2629     }
2630 
2631     SetAccumulatorType(elementType);
2632 }
2633 
LoadStringLength(const ir::AstNode * node)2634 void ETSGen::LoadStringLength(const ir::AstNode *node)
2635 {
2636     Ra().Emit<CallVirtAccShort, 0>(node, Signatures::BUILTIN_STRING_LENGTH, dummyReg_, 0);
2637     SetAccumulatorType(Checker()->GlobalIntType());
2638 }
2639 
FloatIsNaN(const ir::AstNode * node)2640 void ETSGen::FloatIsNaN(const ir::AstNode *node)
2641 {
2642     Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_FLOAT_IS_NAN, dummyReg_, 0);
2643     SetAccumulatorType(Checker()->GlobalETSBooleanType());
2644 }
2645 
DoubleIsNaN(const ir::AstNode * node)2646 void ETSGen::DoubleIsNaN(const ir::AstNode *node)
2647 {
2648     Ra().Emit<CallAccShort, 0>(node, Signatures::BUILTIN_DOUBLE_IS_NAN, dummyReg_, 0);
2649     SetAccumulatorType(Checker()->GlobalETSBooleanType());
2650 }
2651 
LoadStringChar(const ir::AstNode * node,const VReg stringObj,const VReg charIndex)2652 void ETSGen::LoadStringChar(const ir::AstNode *node, const VReg stringObj, const VReg charIndex)
2653 {
2654     Ra().Emit<CallVirtShort>(node, Signatures::BUILTIN_STRING_CHAR_AT, stringObj, charIndex);
2655     SetAccumulatorType(Checker()->GlobalCharType());
2656 }
2657 
ThrowException(const ir::Expression * expr)2658 void ETSGen::ThrowException(const ir::Expression *expr)
2659 {
2660     RegScope rs(this);
2661 
2662     expr->Compile(this);
2663     VReg arg = AllocReg();
2664     StoreAccumulator(expr, arg);
2665     EmitThrow(expr, arg);
2666 }
2667 
ExtendWithFinalizer(ir::AstNode * node,const ir::AstNode * originalNode,Label * prevFinnaly)2668 bool ETSGen::ExtendWithFinalizer(ir::AstNode *node, const ir::AstNode *originalNode, Label *prevFinnaly)
2669 {
2670     ASSERT(originalNode != nullptr);
2671 
2672     if (node == nullptr || !node->IsStatement()) {
2673         return false;
2674     }
2675 
2676     if ((originalNode->IsContinueStatement() && originalNode->AsContinueStatement()->Target() == node) ||
2677         (originalNode->IsBreakStatement() && originalNode->AsBreakStatement()->Target() == node)) {
2678         return false;
2679     }
2680 
2681     if (node->IsTryStatement() && node->AsTryStatement()->HasFinalizer()) {
2682         auto *tryStm = node->AsTryStatement();
2683 
2684         Label *beginLabel = nullptr;
2685 
2686         if (prevFinnaly == nullptr) {
2687             beginLabel = AllocLabel();
2688             Branch(originalNode, beginLabel);
2689         } else {
2690             beginLabel = prevFinnaly;
2691         }
2692 
2693         Label *endLabel = AllocLabel();
2694 
2695         if (node->Parent() != nullptr && node->Parent()->IsStatement()) {
2696             if (!ExtendWithFinalizer(node->Parent(), originalNode, endLabel)) {
2697                 endLabel = nullptr;
2698             }
2699         } else {
2700             endLabel = nullptr;
2701         }
2702 
2703         LabelPair insertion = compiler::LabelPair(beginLabel, endLabel);
2704 
2705         tryStm->AddFinalizerInsertion(insertion, originalNode->AsStatement());
2706 
2707         return true;
2708     }
2709 
2710     auto *parent = node->Parent();
2711 
2712     if (parent == nullptr || !parent->IsStatement()) {
2713         return false;
2714     }
2715 
2716     if (parent->IsTryStatement() && node->IsBlockStatement() &&
2717         parent->AsTryStatement()->FinallyBlock() == node->AsBlockStatement()) {
2718         parent = parent->Parent();
2719     }
2720 
2721     return ExtendWithFinalizer(parent, originalNode, prevFinnaly);
2722 }
2723 
ToAssemblerType(const es2panda::checker::Type * type) const2724 util::StringView ETSGen::ToAssemblerType(const es2panda::checker::Type *type) const
2725 {
2726     ASSERT(type->HasTypeFlag(TYPE_FLAG_BYTECODE_REF) && !type->IsETSNullLike());
2727 
2728     std::stringstream ss;
2729     type->ToAssemblerTypeWithRank(ss);
2730     return util::UString(ss.str(), Allocator()).View();
2731 }
2732 
2733 }  // namespace panda::es2panda::compiler
2734