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