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