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#ifndef ES2PANDA_COMPILER_CORE_ETSGEN_H 17#define ES2PANDA_COMPILER_CORE_ETSGEN_H 18 19#include "ir/astNode.h" 20#include "varbinder/ETSBinder.h" 21#include "compiler/core/codeGen.h" 22#include "compiler/core/ETSfunction.h" 23#include "compiler/core/targetTypeContext.h" 24#include "checker/ETSchecker.h" 25#include "util/helpers.h" 26 27namespace ark::es2panda::compiler { 28 29class ETSGen final : public CodeGen { 30public: 31 explicit ETSGen(ArenaAllocator *allocator, RegSpiller *spiller, public_lib::Context *context, 32 std::tuple<varbinder::FunctionScope *, ProgramElement *, AstCompiler *> toCompile) noexcept; 33 34 [[nodiscard]] const checker::ETSChecker *Checker() const noexcept; 35 [[nodiscard]] const varbinder::ETSBinder *VarBinder() const noexcept; 36 [[nodiscard]] const checker::Type *ReturnType() const noexcept; 37 [[nodiscard]] const checker::ETSObjectType *ContainingObjectType() const noexcept; 38 39 [[nodiscard]] VReg &Acc() noexcept; 40 [[nodiscard]] VReg Acc() const noexcept; 41 42 void SetAccumulatorType(const checker::Type *type); 43 [[nodiscard]] const checker::Type *GetAccumulatorType() const; 44 void CompileAndCheck(const ir::Expression *expr); 45 46 [[nodiscard]] VReg StoreException(const ir::AstNode *node); 47 void ApplyConversionAndStoreAccumulator(const ir::AstNode *node, VReg vreg, const checker::Type *targetType); 48 void StoreAccumulator(const ir::AstNode *node, VReg vreg); 49 void LoadAccumulator(const ir::AstNode *node, VReg vreg); 50 [[nodiscard]] IRNode *AllocMov(const ir::AstNode *node, VReg vd, VReg vs) override; 51 [[nodiscard]] IRNode *AllocMov(const ir::AstNode *node, OutVReg vd, VReg vs) override; 52 void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); 53 54 [[nodiscard]] checker::Type const *TypeForVar(varbinder::Variable const *var) const noexcept override; 55 56 void LoadVar(const ir::Identifier *node, varbinder::Variable const *var); 57 void LoadDynamicModuleVariable(const ir::AstNode *node, varbinder::Variable const *var); 58 void LoadDynamicNamespaceVariable(const ir::AstNode *node, varbinder::Variable const *var); 59 void StoreVar(const ir::Identifier *node, const varbinder::ConstScopeFindResult &result); 60 61 void LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); 62 void StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); 63 64 void StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &name); 65 [[nodiscard]] util::StringView FormClassPropReference(const checker::ETSObjectType *classType, 66 const util::StringView &name); 67 68 void StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 69 const util::StringView &name); 70 void LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 71 const util::StringView &fullName); 72 void StorePropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 73 const util::StringView &propName); 74 void LoadPropertyDynamic(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 75 const util::StringView &propName); 76 77 void StoreElementDynamic(const ir::AstNode *node, VReg objectReg, VReg index); 78 void LoadElementDynamic(const ir::AstNode *node, VReg objectReg); 79 80 void StoreUnionProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 81 const util::StringView &propName); 82 void LoadUnionProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, 83 const util::StringView &propName); 84 85 void LoadUndefinedDynamic(const ir::AstNode *node, Language lang); 86 87 void LoadThis(const ir::AstNode *node); 88 [[nodiscard]] VReg GetThisReg() const; 89 90 const checker::Type *LoadDefaultValue(const ir::AstNode *node, const checker::Type *type); 91 void EmitReturnVoid(const ir::AstNode *node); 92 void ReturnAcc(const ir::AstNode *node); 93 94 void BranchIfIsInstance(const ir::AstNode *node, VReg srcReg, const checker::Type *target, Label *ifTrue); 95 void IsInstance(const ir::AstNode *node, VReg srcReg, checker::Type const *target); 96 void IsInstanceDynamic(const ir::BinaryExpression *node, VReg srcReg, VReg tgtReg); 97 void EmitFailedTypeCastException(const ir::AstNode *node, VReg src, checker::Type const *target); 98 99 void BinaryLogic(const ir::AstNode *node, lexer::TokenType op, VReg lhs); 100 void BinaryArithmLogic(const ir::AstNode *node, lexer::TokenType op, VReg lhs); 101 void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); 102 void Unary(const ir::AstNode *node, lexer::TokenType op); 103 void Update(const ir::AstNode *node, lexer::TokenType op); 104 void UpdateBigInt(const ir::Expression *node, VReg arg, lexer::TokenType op); 105 106 bool TryLoadConstantExpression(const ir::Expression *node); 107 void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse); 108 109 template <typename CondCompare, bool BEFORE_LOGICAL_NOT> 110 void ResolveConditionalResultFloat(const ir::AstNode *node, Label *realEndLabel) 111 { 112 auto type = GetAccumulatorType(); 113 VReg tmpReg = AllocReg(); 114 StoreAccumulator(node, tmpReg); 115 if (type->IsFloatType()) { 116 FloatIsNaN(node); 117 } else { 118 DoubleIsNaN(node); 119 } 120 Sa().Emit<Xori>(node, 1); 121 122 BranchIfFalse(node, realEndLabel); 123 LoadAccumulator(node, tmpReg); 124 VReg zeroReg = AllocReg(); 125 126 if (type->IsFloatType()) { 127 MoveImmediateToRegister(node, zeroReg, checker::TypeFlag::FLOAT, 0); 128 BinaryNumberComparison<Fcmpl, Jeqz>(node, zeroReg, realEndLabel); 129 } else { 130 MoveImmediateToRegister(node, zeroReg, checker::TypeFlag::DOUBLE, 0); 131 BinaryNumberComparison<FcmplWide, Jeqz>(node, zeroReg, realEndLabel); 132 } 133 } 134 135 template <typename CondCompare, bool BEFORE_LOGICAL_NOT, bool USE_FALSE_LABEL> 136 void ResolveConditionalResultNumeric(const ir::AstNode *node, [[maybe_unused]] Label *ifFalse, Label **end) 137 { 138 auto type = GetAccumulatorType(); 139 ASSERT(type != nullptr); 140 auto realEndLabel = [end, ifFalse, this](bool useFalseLabel) { 141 if (useFalseLabel) { 142 return ifFalse; 143 } 144 if ((*end) == nullptr) { 145 (*end) = AllocLabel(); 146 } 147 return (*end); 148 }(USE_FALSE_LABEL); 149 if (type->IsDoubleType() || type->IsFloatType()) { 150 ResolveConditionalResultFloat<CondCompare, BEFORE_LOGICAL_NOT>(node, realEndLabel); 151 } 152 if (type->IsLongType()) { 153 VReg zeroReg = AllocReg(); 154 MoveImmediateToRegister(node, zeroReg, checker::TypeFlag::LONG, 0); 155 BinaryNumberComparison<CmpWide, CondCompare>(node, zeroReg, realEndLabel); 156 } 157 if constexpr (BEFORE_LOGICAL_NOT) { 158 Label *zeroPrimitive = AllocLabel(); 159 BranchIfFalse(node, zeroPrimitive); 160 ToBinaryResult(node, zeroPrimitive); 161 } 162 } 163 164 template <typename CondCompare, bool BEFORE_LOGICAL_NOT> 165 void ResolveConditionalResultReference(const ir::AstNode *node) 166 { 167 auto const testString = [this, node]() { 168 LoadStringLength(node); 169 if constexpr (BEFORE_LOGICAL_NOT) { 170 Label *zeroLenth = AllocLabel(); 171 BranchIfFalse(node, zeroLenth); 172 ToBinaryResult(node, zeroLenth); 173 } 174 }; 175 176 auto type = GetAccumulatorType(); 177 if (!type->PossiblyETSString()) { 178 Sa().Emit<Ldai>(node, 1); 179 return; 180 } 181 if (type->IsETSStringType()) { // should also be valid for string|null|undefined 182 testString(); 183 return; 184 } 185 186 Label *isString = AllocLabel(); 187 Label *end = AllocLabel(); 188 compiler::VReg objReg = AllocReg(); 189 StoreAccumulator(node, objReg); 190 191 Sa().Emit<Isinstance>(node, Checker()->GlobalBuiltinETSStringType()->AssemblerName()); 192 BranchIfTrue(node, isString); 193 Sa().Emit<Ldai>(node, 1); 194 Branch(node, end); 195 SetLabel(node, isString); 196 LoadAccumulator(node, objReg); 197 InternalCheckCast(node, Checker()->GlobalBuiltinETSStringType()); // help verifier 198 testString(); 199 SetLabel(node, end); 200 } 201 202 template <typename CondCompare, bool BEFORE_LOGICAL_NOT, bool USE_FALSE_LABEL> 203 void ResolveConditionalResult(const ir::AstNode *node, [[maybe_unused]] Label *ifFalse) 204 { 205 auto type = GetAccumulatorType(); 206 if (type->IsETSBooleanType()) { 207 return; 208 } 209 Label *ifNullish {nullptr}; 210 Label *end {nullptr}; 211 if (type->PossiblyETSNullish()) { 212 if constexpr (USE_FALSE_LABEL) { 213 BranchIfNullish(node, ifFalse); 214 } else { 215 ifNullish = AllocLabel(); 216 end = AllocLabel(); 217 BranchIfNullish(node, ifNullish); 218 } 219 } 220 if (type->DefinitelyETSNullish()) { 221 // skip 222 } else if (type->IsETSReferenceType()) { 223 ResolveConditionalResultReference<CondCompare, BEFORE_LOGICAL_NOT>(node); 224 } else { 225 ResolveConditionalResultNumeric<CondCompare, BEFORE_LOGICAL_NOT, USE_FALSE_LABEL>(node, ifFalse, &end); 226 } 227 if (ifNullish != nullptr) { 228 Branch(node, end); 229 SetLabel(node, ifNullish); 230 Sa().Emit<Ldai>(node, 0); 231 } 232 if (end != nullptr) { 233 SetLabel(node, end); 234 } 235 } 236 237 template <bool BEFORE_LOGICAL_NOT = false, bool FALSE_LABEL_EXISTED = true> 238 void ResolveConditionalResultIfFalse(const ir::AstNode *node, Label *ifFalse = nullptr) 239 { 240 ResolveConditionalResult<Jeqz, BEFORE_LOGICAL_NOT, FALSE_LABEL_EXISTED>(node, ifFalse); 241 } 242 243 template <bool BEFORE_LOGICAL_NOT = false, bool FALSE_LABEL_EXISTED = true> 244 void ResolveConditionalResultIfTrue(const ir::AstNode *node, Label *ifFalse = nullptr) 245 { 246 ResolveConditionalResult<Jnez, BEFORE_LOGICAL_NOT, FALSE_LABEL_EXISTED>(node, ifFalse); 247 } 248 249 void BranchIfFalse(const ir::AstNode *node, Label *ifFalse) 250 { 251 Sa().Emit<Jeqz>(node, ifFalse); 252 } 253 254 void BranchIfTrue(const ir::AstNode *node, Label *ifTrue) 255 { 256 Sa().Emit<Jnez>(node, ifTrue); 257 } 258 259 void BranchIfNull(const ir::AstNode *node, Label *ifNull) 260 { 261 Sa().Emit<JeqzObj>(node, ifNull); 262 } 263 264 void BranchIfUndefined([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] Label *ifUndefined) 265 { 266#ifdef PANDA_WITH_ETS 267 Sa().Emit<EtsIsundefined>(node); 268 Sa().Emit<Jnez>(node, ifUndefined); 269#else 270 UNREACHABLE(); 271#endif // PANDA_WITH_ETS 272 } 273 274 void BranchIfNotUndefined([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] Label *ifUndefined) 275 { 276#ifdef PANDA_WITH_ETS 277 Sa().Emit<EtsIsundefined>(node); 278 Sa().Emit<Jeqz>(node, ifUndefined); 279#else 280 UNREACHABLE(); 281#endif // PANDA_WITH_ETS 282 } 283 284 void BranchIfNotNull(const ir::AstNode *node, Label *ifNotNull) 285 { 286 Sa().Emit<JnezObj>(node, ifNotNull); 287 } 288 289 void BranchIfNullish(const ir::AstNode *node, Label *ifNullish); 290 void BranchIfNotNullish(const ir::AstNode *node, Label *ifNotNullish); 291 void AssumeNonNullish(const ir::AstNode *node, checker::Type const *targetType); 292 293 void JumpTo(const ir::AstNode *node, Label *labelTo) 294 { 295 Sa().Emit<Jmp>(node, labelTo); 296 } 297 298 void EmitThrow(const ir::AstNode *node, VReg err) 299 { 300 Ra().Emit<Throw>(node, err); 301 } 302 303 void EmitNullishException(const ir::AstNode *node); 304 void ThrowException(const ir::Expression *expr); 305 bool ExtendWithFinalizer(ir::AstNode const *node, const ir::AstNode *originalNode, Label *prevFinnaly = nullptr); 306 307 void Negate(const ir::AstNode *node); 308 void LogicalNot(const ir::AstNode *node); 309 310 void LoadAccumulatorByte(const ir::AstNode *node, int8_t number) 311 { 312 LoadAccumulatorNumber<int8_t>(node, number, checker::TypeFlag::BYTE); 313 } 314 315 void LoadAccumulatorShort(const ir::AstNode *node, int16_t number) 316 { 317 LoadAccumulatorNumber<int16_t>(node, number, checker::TypeFlag::SHORT); 318 } 319 320 void LoadAccumulatorInt(const ir::AstNode *node, int32_t number) 321 { 322 LoadAccumulatorNumber<int32_t>(node, number, checker::TypeFlag::INT); 323 } 324 325 void LoadAccumulatorWideInt(const ir::AstNode *node, int64_t number) 326 { 327 LoadAccumulatorNumber<int64_t>(node, number, checker::TypeFlag::LONG); 328 } 329 330 void LoadAccumulatorFloat(const ir::AstNode *node, float number) 331 { 332 LoadAccumulatorNumber<float>(node, number, checker::TypeFlag::FLOAT); 333 } 334 335 void LoadAccumulatorDouble(const ir::AstNode *node, double number) 336 { 337 LoadAccumulatorNumber<double>(node, number, checker::TypeFlag::DOUBLE); 338 } 339 340 void LoadAccumulatorBoolean(const ir::AstNode *node, bool value) 341 { 342 Sa().Emit<Ldai>(node, value ? 1 : 0); 343 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 344 ApplyConversion(node, Checker()->GlobalETSBooleanType()); 345 } 346 347 void LoadAccumulatorString(const ir::AstNode *node, util::StringView str) 348 { 349 Sa().Emit<LdaStr>(node, str); 350 SetAccumulatorType(Checker()->GlobalETSStringLiteralType()); 351 } 352 353 void LoadAccumulatorBigInt(const ir::AstNode *node, util::StringView str) 354 { 355 Sa().Emit<LdaStr>(node, str); 356 SetAccumulatorType(Checker()->GlobalETSBigIntType()); 357 } 358 359 void LoadAccumulatorNull(const ir::AstNode *node, const checker::Type *type) 360 { 361 Sa().Emit<LdaNull>(node); 362 SetAccumulatorType(type); 363 } 364 365 void LoadAccumulatorUndefined([[maybe_unused]] const ir::AstNode *node) 366 { 367#ifdef PANDA_WITH_ETS 368 Sa().Emit<EtsLdundefined>(node); 369 SetAccumulatorType(Checker()->GlobalETSUndefinedType()); 370#else 371 UNREACHABLE(); 372#endif // PANDA_WITH_ETS 373 } 374 375 void LoadAccumulatorChar(const ir::AstNode *node, char16_t value) 376 { 377 Sa().Emit<Ldai>(node, value); 378 SetAccumulatorType(Checker()->GlobalCharType()); 379 ApplyConversion(node, Checker()->GlobalCharType()); 380 } 381 382 void LoadAccumulatorDynamicModule(const ir::AstNode *node, const ir::ETSImportDeclaration *import); 383 384 void ApplyBoxingConversion(const ir::AstNode *node); 385 void ApplyUnboxingConversion(const ir::AstNode *node); 386 void ApplyConversion(const ir::AstNode *node) 387 { 388 if (targetType_ != nullptr) { 389 ApplyConversion(node, targetType_); 390 } 391 } 392 void ApplyConversionCast(const ir::AstNode *node, const checker::Type *targetType); 393 void ApplyConversion(const ir::AstNode *node, const checker::Type *targetType); 394 void ApplyCast(const ir::AstNode *node, const checker::Type *targetType); 395 void ApplyCastToBoxingFlags(const ir::AstNode *node, const ir::BoxingUnboxingFlags targetType); 396 void EmitUnboxingConversion(const ir::AstNode *node); 397 checker::Type *EmitBoxedType(ir::BoxingUnboxingFlags boxingFlag, const ir::AstNode *node); 398 void EmitBoxingConversion(const ir::AstNode *node); 399 void SwapBinaryOpArgs(const ir::AstNode *node, VReg lhs); 400 VReg MoveAccToReg(const ir::AstNode *node); 401 402 void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); 403 void LoadArrayElement(const ir::AstNode *node, VReg objectReg); 404 void StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index, const checker::Type *elementType); 405 406 template <typename T> 407 void MoveImmediateToRegister(const ir::AstNode *node, VReg reg, const checker::TypeFlag valueType, T const value) 408 { 409 switch (valueType) { 410 case checker::TypeFlag::ETS_BOOLEAN: 411 [[fallthrough]]; 412 case checker::TypeFlag::BYTE: { 413 Ra().Emit<Movi>(node, reg, static_cast<checker::ByteType::UType>(value)); 414 SetVRegType(reg, Checker()->GlobalByteType()); 415 break; 416 } 417 case checker::TypeFlag::CHAR: { 418 Ra().Emit<Movi>(node, reg, static_cast<checker::CharType::UType>(value)); 419 SetVRegType(reg, Checker()->GlobalCharType()); 420 break; 421 } 422 case checker::TypeFlag::SHORT: { 423 Ra().Emit<Movi>(node, reg, static_cast<checker::ShortType::UType>(value)); 424 SetVRegType(reg, Checker()->GlobalShortType()); 425 break; 426 } 427 case checker::TypeFlag::INT: { 428 Ra().Emit<Movi>(node, reg, static_cast<checker::IntType::UType>(value)); 429 SetVRegType(reg, Checker()->GlobalIntType()); 430 break; 431 } 432 case checker::TypeFlag::LONG: { 433 Ra().Emit<MoviWide>(node, reg, static_cast<checker::LongType::UType>(value)); 434 SetVRegType(reg, Checker()->GlobalLongType()); 435 break; 436 } 437 case checker::TypeFlag::FLOAT: { 438 Ra().Emit<Fmovi>(node, reg, static_cast<checker::FloatType::UType>(value)); 439 SetVRegType(reg, Checker()->GlobalFloatType()); 440 break; 441 } 442 case checker::TypeFlag::DOUBLE: { 443 Ra().Emit<FmoviWide>(node, reg, static_cast<checker::DoubleType::UType>(value)); 444 SetVRegType(reg, Checker()->GlobalDoubleType()); 445 break; 446 } 447 default: { 448 UNREACHABLE(); 449 } 450 } 451 } 452 453 template <typename T> 454 void IncrementImmediateRegister(const ir::AstNode *node, VReg reg, const checker::TypeFlag valueType, T const value) 455 { 456 switch (valueType) { 457 // NOTE: operand of increment instruction (INCI) is defined in spec as 32-bit integer, 458 // but its current implementation actually can work with 64-bit integers as well. 459 case checker::TypeFlag::INT: { 460 Ra().Emit<Inci>(node, reg, static_cast<checker::IntType::UType>(value)); 461 break; 462 } 463 case checker::TypeFlag::CHAR: { 464 Ra().Emit<Inci>(node, reg, static_cast<checker::CharType::UType>(value)); 465 break; 466 } 467 case checker::TypeFlag::SHORT: { 468 Ra().Emit<Inci>(node, reg, static_cast<checker::ShortType::UType>(value)); 469 break; 470 } 471 case checker::TypeFlag::ETS_BOOLEAN: 472 [[fallthrough]]; 473 case checker::TypeFlag::BYTE: { 474 Ra().Emit<Inci>(node, reg, static_cast<checker::ByteType::UType>(value)); 475 break; 476 } 477 default: { 478 UNREACHABLE(); 479 } 480 } 481 } 482 483 template <typename IntCompare> 484 void JumpCompareRegister(const ir::AstNode *node, VReg lhs, Label *ifFalse) 485 { 486 Ra().Emit<IntCompare>(node, lhs, ifFalse); 487 } 488 489 void LoadStringLength(const ir::AstNode *node); 490 void LoadStringChar(const ir::AstNode *node, VReg stringObj, VReg charIndex); 491 492 void FloatIsNaN(const ir::AstNode *node); 493 void DoubleIsNaN(const ir::AstNode *node); 494 495 void CompileStatements(const ArenaVector<ir::Statement *> &statements); 496 497 // Cast 498 void CastToBoolean(const ir::AstNode *node); 499 void CastToByte(const ir::AstNode *node); 500 void CastToChar(const ir::AstNode *node); 501 void CastToShort(const ir::AstNode *node); 502 void CastToDouble(const ir::AstNode *node); 503 void CastToFloat(const ir::AstNode *node); 504 void CastToLong(const ir::AstNode *node); 505 void CastToInt(const ir::AstNode *node); 506 void CastToString(const ir::AstNode *node); 507 void CastToDynamic(const ir::AstNode *node, const checker::ETSDynamicType *type); 508 void CastDynamicTo(const ir::AstNode *node, enum checker::TypeFlag typeFlag); 509 void CastToReftype(const ir::AstNode *node, const checker::Type *targetType, bool unchecked); 510 void CastDynamicToObject(const ir::AstNode *node, const checker::Type *targetType); 511 void CastUnionToFunctionType(const ir::AstNode *node, const checker::ETSUnionType *unionType, 512 checker::Signature *signatureTarget); 513 514 void InternalIsInstance(const ir::AstNode *node, const checker::Type *target); 515 void InternalCheckCast(const ir::AstNode *node, const checker::Type *target); 516 void CheckedReferenceNarrowing(const ir::AstNode *node, const checker::Type *target); 517 void GuardUncheckedType(const ir::AstNode *node, const checker::Type *unchecked, const checker::Type *target); 518 519 // Call, Construct 520 void NewArray(const ir::AstNode *node, VReg arr, VReg dim, const checker::Type *arrType); 521 void NewObject(const ir::AstNode *node, util::StringView name, VReg athis); 522 void BuildString(const ir::Expression *node); 523 void CallBigIntUnaryOperator(const ir::Expression *node, VReg arg, util::StringView signature); 524 void CallBigIntBinaryOperator(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); 525 void CallBigIntBinaryComparison(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); 526 void BuildTemplateString(const ir::TemplateLiteral *node); 527 void InitObject(const ir::AstNode *node, checker::Signature const *signature, 528 const ArenaVector<ir::Expression *> &arguments) 529 { 530 CallImpl<InitobjShort, Initobj, InitobjRange>(node, signature, arguments); 531 } 532 533 bool IsDevirtualizedSignature(const checker::Signature *signature) 534 { 535 ASSERT(!signature->HasSignatureFlag(checker::SignatureFlags::STATIC)); 536 return signature->HasSignatureFlag(checker::SignatureFlags::FINAL | checker::SignatureFlags::PRIVATE | 537 checker::SignatureFlags::CONSTRUCTOR); 538 } 539 540 void CallExact(const ir::AstNode *node, checker::Signature *signature, 541 const ArenaVector<ir::Expression *> &arguments) 542 { 543 CallImpl<CallShort, Call, CallRange>(node, signature, arguments); 544 } 545 546 void CallExact(const ir::AstNode *const node, const checker::Signature *signature, const VReg arg0, 547 const ArenaVector<ir::Expression *> &arguments) 548 { 549 CallArgStart<CallShort, Call, CallRange>(node, signature, arg0, arguments); 550 } 551 552 void CallExact(const ir::AstNode *const node, const util::StringView name) 553 { 554 Ra().Emit<CallShort, 0>(node, name, dummyReg_, dummyReg_); 555 } 556 557 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0) 558 { 559 Ra().Emit<CallShort, 1>(node, name, arg0, dummyReg_); 560 } 561 562 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1) 563 { 564 Ra().Emit<CallShort>(node, name, arg0, arg1); 565 } 566 567 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1, 568 const VReg arg2) 569 { 570 Ra().Emit<Call, 3U>(node, name, arg0, arg1, arg2, dummyReg_); 571 } 572 573 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis, 574 const ArenaVector<ir::Expression *> &arguments) 575 { 576 ASSERT(!signature->HasSignatureFlag(checker::SignatureFlags::STATIC)); 577 ASSERT(!signature->Owner()->GetDeclNode()->IsFinal() || signature->IsFinal()); 578 if (IsDevirtualizedSignature(signature)) { 579 CallArgStart<CallShort, Call, CallRange>(node, signature, athis, arguments); 580 } else { 581 CallArgStart<CallVirtShort, CallVirt, CallVirtRange>(node, signature, athis, arguments); 582 } 583 } 584 585 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis) 586 { 587 if (IsDevirtualizedSignature(signature)) { 588 CallExact(node, signature->InternalName(), athis); 589 } else { 590 CallVirtual(node, signature->InternalName(), athis); 591 } 592 } 593 594 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis, 595 const VReg arg0) 596 { 597 if (IsDevirtualizedSignature(signature)) { 598 CallExact(node, signature->InternalName(), athis, arg0); 599 } else { 600 CallVirtual(node, signature->InternalName(), athis, arg0); 601 } 602 } 603 604 void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis) 605 { 606 Ra().Emit<CallVirtShort, 1>(node, name, athis, dummyReg_); 607 } 608 609 void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis, const VReg arg0) 610 { 611 Ra().Emit<CallVirtShort>(node, name, athis, arg0); 612 } 613 614 struct CallDynamicData { 615 const ir::AstNode *node = nullptr; 616 VReg obj; 617 VReg param2; 618 }; 619 620 void CallDynamic(CallDynamicData data, checker::Signature *signature, 621 const ArenaVector<ir::Expression *> &arguments) 622 { 623 CallDynamicImpl<CallShort, Call, CallRange>(data, signature, arguments); 624 } 625 626 void CallDynamic(CallDynamicData data, VReg param3, checker::Signature *signature, 627 const ArenaVector<ir::Expression *> &arguments) 628 { 629 CallDynamicImpl<CallShort, Call, CallRange>(data, param3, signature, arguments); 630 } 631 632#ifdef PANDA_WITH_ETS 633 // The functions below use ETS specific instructions. 634 // Compilation of es2panda fails if ETS plugin is disabled 635 void LaunchExact(const ir::AstNode *node, checker::Signature *signature, 636 const ArenaVector<ir::Expression *> &arguments) 637 { 638 CallImpl<EtsLaunchShort, EtsLaunch, EtsLaunchRange>(node, signature, arguments); 639 } 640 641 void LaunchVirtual(const ir::AstNode *const node, checker::Signature *const signature, const VReg athis, 642 const ArenaVector<ir::Expression *> &arguments) 643 { 644 if (IsDevirtualizedSignature(signature)) { 645 CallArgStart<EtsLaunchShort, EtsLaunch, EtsLaunchRange>(node, signature, athis, arguments); 646 } else { 647 CallArgStart<EtsLaunchVirtShort, EtsLaunchVirt, EtsLaunchVirtRange>(node, signature, athis, arguments); 648 } 649 } 650#endif // PANDA_WITH_ETS 651 652 void CreateBigIntObject(const ir::AstNode *node, VReg arg0, 653 std::string_view signature = Signatures::BUILTIN_BIGINT_CTOR); 654 655 void GetType(const ir::AstNode *node, bool isEtsPrimitive) 656 { 657 if (isEtsPrimitive) { 658 // NOTE: SzD. LoadStaticProperty if ETS stdlib has static TYPE constants otherwise fallback to LdaType 659 } else { 660 auto classRef = GetAccumulatorType()->AsETSObjectType()->AssemblerName(); 661 Sa().Emit<LdaType>(node, classRef); 662 } 663 } 664 665 ~ETSGen() override = default; 666 NO_COPY_SEMANTIC(ETSGen); 667 NO_MOVE_SEMANTIC(ETSGen); 668 669 void EmitUnboxEnum(const ir::AstNode *node, const checker::Type *enumType); 670 671private: 672 const VReg dummyReg_ = VReg::RegStart(); 673 674 void EmitUnboxedCall(const ir::AstNode *node, std::string_view signatureFlag, const checker::Type *targetType, 675 const checker::Type *boxedType); 676 677 void LoadConstantObject(const ir::Expression *node, const checker::Type *type); 678 void StringBuilderAppend(const ir::AstNode *node, VReg builder); 679 void AppendString(const ir::Expression *binExpr, VReg builder); 680 void StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg builder); 681 util::StringView FormClassPropReference(varbinder::Variable const *var); 682 void UnaryMinus(const ir::AstNode *node); 683 void UnaryTilde(const ir::AstNode *node); 684 void UnaryDollarDollar(const ir::AstNode *node); 685 686 util::StringView ToAssemblerType(const es2panda::checker::Type *type) const; 687 void TestIsInstanceConstant(const ir::AstNode *node, Label *ifTrue, VReg srcReg, checker::Type const *target); 688 void TestIsInstanceConstituent(const ir::AstNode *node, std::tuple<Label *, Label *> label, VReg srcReg, 689 checker::Type const *target, bool acceptUndefined); 690 void CheckedReferenceNarrowingObject(const ir::AstNode *node, const checker::Type *target); 691 692 void HandleLooseNullishEquality(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse, Label *ifTrue); 693 694 void EmitIsUndefined([[maybe_unused]] const ir::AstNode *node) 695 { 696#ifdef PANDA_WITH_ETS 697 Sa().Emit<EtsIsundefined>(node); 698#else 699 UNREACHABLE(); 700#endif // PANDA_WITH_ETS 701 } 702 703 void EmitEtsEquals([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const VReg lhs, 704 [[maybe_unused]] const VReg rhs) 705 { 706#ifdef PANDA_WITH_ETS 707 Ra().Emit<EtsEquals>(node, lhs, rhs); 708#else 709 UNREACHABLE(); 710#endif // PANDA_WITH_ETS 711 } 712 713 template <typename T> 714 void StoreValueIntoArray(const ir::AstNode *const node, const VReg arr, const VReg index) 715 { 716 Ra().Emit<T>(node, arr, index); 717 } 718 719 template <typename LongOp, typename IntOp, typename DoubleOp, typename FloatOp> 720 void UpdateOperator(const ir::AstNode *node) 721 { 722 switch (checker::ETSChecker::ETSType(GetAccumulatorType())) { 723 case checker::TypeFlag::LONG: { 724 RegScope scope(this); 725 VReg reg = AllocReg(); 726 Ra().Emit<MoviWide>(node, reg, 1LL); 727 Ra().Emit<LongOp>(node, reg); 728 break; 729 } 730 case checker::TypeFlag::INT: { 731 Sa().Emit<IntOp>(node, 1); 732 break; 733 } 734 case checker::TypeFlag::CHAR: { 735 Sa().Emit<IntOp>(node, 1); 736 Sa().Emit<I32tou16>(node); 737 break; 738 } 739 case checker::TypeFlag::SHORT: { 740 Sa().Emit<IntOp>(node, 1); 741 Sa().Emit<I32toi16>(node); 742 break; 743 } 744 case checker::TypeFlag::BYTE: { 745 Sa().Emit<IntOp>(node, 1); 746 Sa().Emit<I32toi8>(node); 747 break; 748 } 749 case checker::TypeFlag::DOUBLE: { 750 RegScope scope(this); 751 VReg reg = AllocReg(); 752 Ra().Emit<FmoviWide>(node, reg, 1.0); 753 Ra().Emit<DoubleOp>(node, reg); 754 break; 755 } 756 case checker::TypeFlag::FLOAT: { 757 RegScope scope(this); 758 VReg reg = AllocReg(); 759 Ra().Emit<Fmovi>(node, reg, 1.0F); 760 Ra().Emit<FloatOp>(node, reg); 761 break; 762 } 763 default: { 764 UNREACHABLE(); 765 } 766 } 767 } 768 769 template <typename Br> 770 void InverseCondition(const ir::AstNode *node, Br const &br, Label *target, bool inverse = true) 771 { 772 if (!inverse) { 773 br(target); 774 return; 775 } 776 Label *loc = AllocLabel(); 777 br(loc); 778 JumpTo(node, target); 779 SetLabel(node, loc); 780 } 781 782 void RefEqualityLoose(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse); 783 void RefEqualityLooseDynamic(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse); 784 785 template <typename Compare, typename Cond> 786 void BinaryNumberComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) 787 { 788 Ra().Emit<Compare>(node, lhs); 789 Sa().Emit<Cond>(node, ifFalse); 790 } 791 792 template <typename DynCompare> 793 void RefEqualityStrictDynamic(const ir::AstNode *node, VReg lhs, Label *ifFalse) 794 { 795 ASSERT(GetAccumulatorType()->IsETSDynamicType() && GetVRegType(lhs)->IsETSDynamicType()); 796 RegScope scope(this); 797 Ra().Emit<CallShort, 2U>(node, Signatures::BUILTIN_JSRUNTIME_STRICT_EQUAL, lhs, MoveAccToReg(node)); 798 Ra().Emit<DynCompare>(node, ifFalse); 799 } 800 801 template <typename ObjCompare, typename IntCompare, typename CondCompare, typename DynCompare> 802 void BinaryEquality(const ir::AstNode *node, VReg lhs, Label *ifFalse) 803 { 804 BinaryEqualityCondition<ObjCompare, IntCompare, CondCompare>(node, lhs, ifFalse); 805 ToBinaryResult(node, ifFalse); 806 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 807 } 808 809 template <typename ObjCompare, typename IntCompare, typename CondCompare> 810 void BinaryEqualityCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) 811 { 812 if (targetType_->IsETSReferenceType()) { 813 RegScope rs(this); 814 VReg arg0 = AllocReg(); 815 StoreAccumulator(node, arg0); 816 InverseCondition( 817 node, [this, node, lhs, arg0](Label *tgt) { RefEqualityLoose(node, lhs, arg0, tgt); }, ifFalse, 818 std::is_same_v<CondCompare, Jeqz>); 819 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 820 return; 821 } 822 823 auto typeKind = checker::ETSChecker::TypeKind(targetType_); 824 825 switch (typeKind) { 826 case checker::TypeFlag::DOUBLE: { 827 BinaryFloatingPointComparison<FcmpgWide, FcmplWide, CondCompare>(node, lhs, ifFalse); 828 break; 829 } 830 case checker::TypeFlag::FLOAT: { 831 BinaryFloatingPointComparison<Fcmpg, Fcmpl, CondCompare>(node, lhs, ifFalse); 832 break; 833 } 834 case checker::TypeFlag::LONG: { 835 BinaryNumberComparison<CmpWide, CondCompare>(node, lhs, ifFalse); 836 break; 837 } 838 case checker::TypeFlag::ETS_INT_ENUM: 839 case checker::TypeFlag::ETS_STRING_ENUM: 840 case checker::TypeFlag::ETS_BOOLEAN: 841 case checker::TypeFlag::BYTE: 842 case checker::TypeFlag::CHAR: 843 case checker::TypeFlag::SHORT: 844 case checker::TypeFlag::INT: { 845 Ra().Emit<IntCompare>(node, lhs, ifFalse); 846 break; 847 } 848 default: { 849 UNREACHABLE(); 850 } 851 } 852 853 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 854 } 855 856 template <typename ObjCompare, typename DynCompare> 857 void RefEqualityStrict(const ir::AstNode *node, VReg lhs, Label *ifFalse) 858 { 859 if (GetAccumulatorType()->IsETSDynamicType() || GetVRegType(lhs)->IsETSDynamicType()) { 860 RefEqualityStrictDynamic<DynCompare>(node, lhs, ifFalse); 861 } else { 862 Ra().Emit<ObjCompare>(node, lhs, ifFalse); 863 } 864 865 ToBinaryResult(node, ifFalse); 866 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 867 } 868 869 template <typename IntCompare, typename CondCompare> 870 void BinaryRelation(const ir::AstNode *node, VReg lhs, Label *ifFalse) 871 { 872 BinaryRelationCondition<IntCompare, CondCompare>(node, lhs, ifFalse); 873 ToBinaryResult(node, ifFalse); 874 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 875 } 876 877 template <typename IntCompare, typename CondCompare> 878 void BinaryRelationCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) 879 { 880 auto typeKind = checker::ETSChecker::TypeKind(targetType_); 881 882 switch (typeKind) { 883 case checker::TypeFlag::DOUBLE: { 884 BinaryFloatingPointComparison<FcmpgWide, FcmplWide, CondCompare>(node, lhs, ifFalse); 885 break; 886 } 887 case checker::TypeFlag::FLOAT: { 888 BinaryFloatingPointComparison<Fcmpg, Fcmpl, CondCompare>(node, lhs, ifFalse); 889 break; 890 } 891 case checker::TypeFlag::LONG: { 892 BinaryNumberComparison<CmpWide, CondCompare>(node, lhs, ifFalse); 893 break; 894 } 895 case checker::TypeFlag::ETS_BOOLEAN: 896 case checker::TypeFlag::BYTE: 897 case checker::TypeFlag::SHORT: 898 case checker::TypeFlag::CHAR: 899 case checker::TypeFlag::INT: { 900 Ra().Emit<IntCompare>(node, lhs, ifFalse); 901 break; 902 } 903 default: { 904 UNREACHABLE(); 905 } 906 } 907 908 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 909 } 910 911 template <typename CompareGreater, typename CompareLess, typename CondCompare> 912 void BinaryFloatingPointComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) 913 { 914 if constexpr (std::is_same_v<CondCompare, Jgez> || std::is_same_v<CondCompare, Jgtz>) { 915 BinaryNumberComparison<CompareGreater, CondCompare>(node, lhs, ifFalse); 916 } else { 917 BinaryNumberComparison<CompareLess, CondCompare>(node, lhs, ifFalse); 918 } 919 } 920 921 template <typename IntOp, typename LongOp, typename FloatOp, typename DoubleOp> 922 void BinaryArithmetic(const ir::AstNode *node, VReg lhs) 923 { 924 auto typeKind = checker::ETSChecker::TypeKind(targetType_); 925 926 switch (typeKind) { 927 case checker::TypeFlag::DOUBLE: { 928 Ra().Emit<DoubleOp>(node, lhs); 929 SetAccumulatorType(Checker()->GlobalDoubleType()); 930 break; 931 } 932 case checker::TypeFlag::FLOAT: { 933 Ra().Emit<FloatOp>(node, lhs); 934 SetAccumulatorType(Checker()->GlobalFloatType()); 935 break; 936 } 937 default: { 938 BinaryBitwiseArithmetic<IntOp, LongOp>(node, lhs); 939 } 940 } 941 } 942 943 template <typename IntOp, typename LongOp> 944 void BinaryBitwiseArithmetic(const ir::AstNode *node, VReg lhs) 945 { 946 auto typeKind = checker::ETSChecker::TypeKind(targetType_); 947 948 switch (typeKind) { 949 case checker::TypeFlag::LONG: { 950 Ra().Emit<LongOp>(node, lhs); 951 SetAccumulatorType(Checker()->GlobalLongType()); 952 break; 953 } 954 case checker::TypeFlag::BYTE: 955 case checker::TypeFlag::SHORT: 956 case checker::TypeFlag::INT: { 957 Ra().Emit<IntOp>(node, lhs); 958 SetAccumulatorType(Checker()->GlobalIntType()); 959 break; 960 } 961 case checker::TypeFlag::ETS_BOOLEAN: { 962 Ra().Emit<IntOp>(node, lhs); 963 SetAccumulatorType(Checker()->GlobalETSBooleanType()); 964 break; 965 } 966 case checker::TypeFlag::CHAR: { 967 Ra().Emit<IntOp>(node, lhs); 968 SetAccumulatorType(Checker()->GlobalCharType()); 969 break; 970 } 971 default: { 972 UNREACHABLE(); 973 } 974 } 975 } 976// NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty) 977#define COMPILE_ARG(idx) \ 978 ASSERT((idx) < arguments.size()); \ 979 ASSERT((idx) < signature->Params().size() || signature->RestVar() != nullptr); \ 980 auto *param##idx = (idx) < signature->Params().size() ? signature->Params()[(idx)] : signature->RestVar(); \ 981 auto *paramType##idx = param##idx->TsType(); \ 982 auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ 983 arguments[idx]->Compile(this); \ 984 VReg arg##idx = AllocReg(); \ 985 ApplyConversion(arguments[idx], nullptr); \ 986 ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) 987 988 template <typename Short, typename General, typename Range> 989 void CallArgStart(const ir::AstNode *const node, const checker::Signature *signature, const VReg argStart, 990 const ArenaVector<ir::Expression *> &arguments) 991 { 992 RegScope rs(this); 993 const auto name = signature->InternalName(); 994 995 switch (arguments.size()) { 996 case 0U: { 997 Ra().Emit<Short, 1>(node, name, argStart, dummyReg_); 998 break; 999 } 1000 case 1U: { 1001 COMPILE_ARG(0); 1002 Ra().Emit<Short>(node, name, argStart, arg0); 1003 break; 1004 } 1005 case 2U: { 1006 COMPILE_ARG(0); 1007 COMPILE_ARG(1); 1008 Ra().Emit<General, 3U>(node, name, argStart, arg0, arg1, dummyReg_); 1009 break; 1010 } 1011 case 3U: { 1012 COMPILE_ARG(0); 1013 COMPILE_ARG(1); 1014 COMPILE_ARG(2); 1015 Ra().Emit<General>(node, name, argStart, arg0, arg1, arg2); 1016 break; 1017 } 1018 default: { 1019 for (size_t idx = 0; idx < arguments.size(); idx++) { 1020 COMPILE_ARG(idx); 1021 } 1022 1023 Rra().Emit<Range>(node, argStart, arguments.size() + 1, name, argStart); 1024 break; 1025 } 1026 } 1027 } 1028 1029 template <typename Short, typename General, typename Range> 1030 void CallImpl(const ir::AstNode *node, checker::Signature const *signature, 1031 const ArenaVector<ir::Expression *> &arguments) 1032 { 1033 ASSERT(signature != nullptr); 1034 RegScope rs(this); 1035 1036 switch (arguments.size()) { 1037 case 0U: { 1038 Ra().Emit<Short, 0U>(node, signature->InternalName(), dummyReg_, dummyReg_); 1039 break; 1040 } 1041 case 1U: { 1042 COMPILE_ARG(0); 1043 Ra().Emit<Short, 1U>(node, signature->InternalName(), arg0, dummyReg_); 1044 break; 1045 } 1046 case 2U: { 1047 COMPILE_ARG(0); 1048 COMPILE_ARG(1); 1049 Ra().Emit<Short, 2U>(node, signature->InternalName(), arg0, arg1); 1050 break; 1051 } 1052 case 3U: { 1053 COMPILE_ARG(0); 1054 COMPILE_ARG(1); 1055 COMPILE_ARG(2); 1056 Ra().Emit<General, 3U>(node, signature->InternalName(), arg0, arg1, arg2, dummyReg_); 1057 break; 1058 } 1059 case 4U: { 1060 COMPILE_ARG(0); 1061 COMPILE_ARG(1); 1062 COMPILE_ARG(2); 1063 COMPILE_ARG(3); 1064 Ra().Emit<General, 4U>(node, signature->InternalName(), arg0, arg1, arg2, arg3); 1065 break; 1066 } 1067 default: { 1068 VReg argStart = NextReg(); 1069 1070 for (size_t idx = 0; idx < arguments.size(); idx++) { 1071 COMPILE_ARG(idx); 1072 } 1073 1074 Rra().Emit<Range>(node, argStart, arguments.size(), signature->InternalName(), argStart); 1075 break; 1076 } 1077 } 1078 } 1079#undef COMPILE_ARG 1080 1081#define COMPILE_ARG(idx, shift) \ 1082 ASSERT((idx) < arguments.size()); \ 1083 ASSERT((idx) + (shift) < signature->Params().size() || signature->RestVar() != nullptr); \ 1084 auto *paramType##idx = (idx) + (shift) < signature->Params().size() \ 1085 ? signature->Params()[(idx) + (shift)]->TsType() \ 1086 : signature->RestVar()->TsType(); \ 1087 auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ 1088 VReg arg##idx = AllocReg(); \ 1089 arguments[idx]->Compile(this); \ 1090 ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) 1091 1092 template <typename Short, typename General, typename Range> 1093 void CallDynamicImpl(CallDynamicData data, checker::Signature *signature, 1094 const ArenaVector<ir::Expression *> &arguments) 1095 { 1096 RegScope rs(this); 1097 const auto name = signature->InternalName(); 1098 1099 switch (arguments.size()) { 1100 case 0U: { 1101 Ra().Emit<Short>(data.node, name, data.obj, data.param2); 1102 break; 1103 } 1104 case 1U: { 1105 COMPILE_ARG(0, 2U); 1106 Ra().Emit<General, 3U>(data.node, name, data.obj, data.param2, arg0, dummyReg_); 1107 break; 1108 } 1109 case 2U: { 1110 COMPILE_ARG(0, 2U); 1111 COMPILE_ARG(1, 2U); 1112 Ra().Emit<General>(data.node, name, data.obj, data.param2, arg0, arg1); 1113 break; 1114 } 1115 default: { 1116 for (size_t idx = 0; idx < arguments.size(); idx++) { 1117 COMPILE_ARG(idx, 2U); 1118 } 1119 1120 Rra().Emit<Range>(data.node, data.obj, arguments.size() + 2U, name, data.obj); 1121 break; 1122 } 1123 } 1124 } 1125 1126 template <typename Short, typename General, typename Range> 1127 void CallDynamicImpl(CallDynamicData data, VReg param3, checker::Signature *signature, 1128 const ArenaVector<ir::Expression *> &arguments) 1129 { 1130 RegScope rs(this); 1131 const auto name = signature->InternalName(); 1132 1133 switch (arguments.size()) { 1134 case 0U: { 1135 Ra().Emit<General, 3U>(data.node, name, data.obj, data.param2, param3, dummyReg_); 1136 break; 1137 } 1138 case 1U: { 1139 COMPILE_ARG(0, 3U); 1140 Ra().Emit<General>(data.node, name, data.obj, data.param2, param3, arg0); 1141 break; 1142 } 1143 default: { 1144 for (size_t idx = 0; idx < arguments.size(); idx++) { 1145 COMPILE_ARG(idx, 3U); 1146 } 1147 1148 Rra().Emit<Range>(data.node, data.obj, arguments.size() + 3U, name, data.obj); 1149 break; 1150 } 1151 } 1152 } 1153 1154#undef COMPILE_ARG 1155 // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty) 1156 1157 void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); 1158 1159 template <typename T> 1160 void LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType); 1161 template <typename T> 1162 void SetAccumulatorTargetType(const ir::AstNode *node, checker::TypeFlag typeKind, T number); 1163 void InitializeContainingClass(); 1164 1165 util::StringView FormDynamicModulePropReference(const varbinder::Variable *var); 1166 util::StringView FormDynamicModulePropReference(const ir::ETSImportDeclaration *import); 1167 1168 friend class TargetTypeContext; 1169 1170 VReg acc_ {}; 1171 const checker::Type *targetType_ {}; 1172 const checker::ETSObjectType *containingObjectType_ {}; 1173}; 1174 1175template <typename T> 1176void ETSGen::SetAccumulatorTargetType(const ir::AstNode *node, checker::TypeFlag typeKind, T number) 1177{ 1178 switch (typeKind) { 1179 case checker::TypeFlag::ETS_BOOLEAN: 1180 case checker::TypeFlag::BYTE: { 1181 Sa().Emit<Ldai>(node, static_cast<checker::ByteType::UType>(number)); 1182 SetAccumulatorType(Checker()->GlobalByteType()); 1183 break; 1184 } 1185 case checker::TypeFlag::CHAR: { 1186 Sa().Emit<Ldai>(node, static_cast<checker::CharType::UType>(number)); 1187 SetAccumulatorType(Checker()->GlobalCharType()); 1188 break; 1189 } 1190 case checker::TypeFlag::SHORT: { 1191 Sa().Emit<Ldai>(node, static_cast<checker::ShortType::UType>(number)); 1192 SetAccumulatorType(Checker()->GlobalShortType()); 1193 break; 1194 } 1195 case checker::TypeFlag::INT: { 1196 Sa().Emit<Ldai>(node, static_cast<checker::IntType::UType>(number)); 1197 SetAccumulatorType(Checker()->GlobalIntType()); 1198 break; 1199 } 1200 case checker::TypeFlag::LONG: { 1201 Sa().Emit<LdaiWide>(node, static_cast<checker::LongType::UType>(number)); 1202 SetAccumulatorType(Checker()->GlobalLongType()); 1203 break; 1204 } 1205 case checker::TypeFlag::FLOAT: { 1206 Sa().Emit<Fldai>(node, static_cast<checker::FloatType::UType>(number)); 1207 SetAccumulatorType(Checker()->GlobalFloatType()); 1208 break; 1209 } 1210 case checker::TypeFlag::DOUBLE: { 1211 Sa().Emit<FldaiWide>(node, static_cast<checker::DoubleType::UType>(number)); 1212 SetAccumulatorType(Checker()->GlobalDoubleType()); 1213 break; 1214 } 1215 case checker::TypeFlag::ETS_STRING_ENUM: 1216 [[fallthrough]]; 1217 case checker::TypeFlag::ETS_INT_ENUM: { 1218 Sa().Emit<Ldai>(node, static_cast<checker::ETSEnumType::UType>(number)); 1219 SetAccumulatorType(Checker()->GlobalIntType()); 1220 break; 1221 } 1222 default: { 1223 UNREACHABLE(); 1224 } 1225 } 1226} 1227 1228template <typename T> 1229void ETSGen::LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType) 1230{ 1231 auto typeKind = targetType_ && (!targetType_->IsETSObjectType() && !targetType_->IsETSUnionType() && 1232 !targetType_->IsETSArrayType()) 1233 ? checker::ETSChecker::TypeKind(targetType_) 1234 : targetType; 1235 1236 SetAccumulatorTargetType(node, typeKind, number); 1237 1238 if (targetType_ && (targetType_->IsETSObjectType() || targetType_->IsETSUnionType())) { 1239 ApplyConversion(node, targetType_); 1240 } 1241} 1242 1243} // namespace ark::es2panda::compiler 1244 1245#endif 1246