1 /* 2 * Copyright (c) 2021-2025 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 "compiler/core/codeGen.h" 21 #include "compiler/core/ETSfunction.h" 22 #include "compiler/core/targetTypeContext.h" 23 #include "checker/ETSchecker.h" 24 #include "util/helpers.h" 25 #include <variant> 26 27 namespace ark::es2panda::compiler { 28 29 class ETSGen final : public CodeGen { 30 public: 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 std::variant<util::StringView, const ark::es2panda::ir::Expression *> property); 76 77 void StoreElementDynamic(const ir::AstNode *node, VReg objectReg, VReg index); 78 void LoadElementDynamic(const ir::AstNode *node, VReg objectReg); 79 80 void StorePropertyByName(const ir::AstNode *node, VReg objReg, 81 checker::ETSChecker::NamedAccessMeta const &fieldMeta); 82 void LoadPropertyByName(const ir::AstNode *node, VReg objReg, 83 checker::ETSChecker::NamedAccessMeta const &fieldMeta); 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 void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse); 107 108 template <typename CondCompare, bool BEFORE_LOGICAL_NOT> 109 void ResolveConditionalResultFloat(const ir::AstNode *node, Label *realEndLabel); 110 111 template <typename CondCompare, bool BEFORE_LOGICAL_NOT, bool USE_FALSE_LABEL> 112 void ResolveConditionalResultNumeric(const ir::AstNode *node, [[maybe_unused]] Label *ifFalse, Label **end); 113 114 template <typename CondCompare, bool BEFORE_LOGICAL_NOT> 115 void ResolveConditionalResultReference(const ir::AstNode *node); 116 117 template <typename CondCompare, bool BEFORE_LOGICAL_NOT, bool USE_FALSE_LABEL> 118 void ResolveConditionalResult(const ir::AstNode *node, [[maybe_unused]] Label *ifFalse); 119 120 template <bool BEFORE_LOGICAL_NOT = false, bool FALSE_LABEL_EXISTED = true> 121 void ResolveConditionalResultIfFalse(const ir::AstNode *node, Label *ifFalse = nullptr); 122 123 template <bool BEFORE_LOGICAL_NOT = false, bool FALSE_LABEL_EXISTED = true> 124 void ResolveConditionalResultIfTrue(const ir::AstNode *node, Label *ifFalse = nullptr); 125 126 template <typename CondCompare, typename NegCondCompare> 127 void BranchConditional(const ir::AstNode *node, Label *endLabel); 128 129 void ConditionalFloat(const ir::AstNode *node); 130 131 void BranchConditionalIfFalse(const ir::AstNode *node, Label *endLabel); 132 133 void BranchConditionalIfTrue(const ir::AstNode *node, Label *endLabel); 134 BranchIfFalse(const ir::AstNode * node,Label * ifFalse)135 void BranchIfFalse(const ir::AstNode *node, Label *ifFalse) 136 { 137 Sa().Emit<Jeqz>(node, ifFalse); 138 } 139 BranchIfTrue(const ir::AstNode * node,Label * ifTrue)140 void BranchIfTrue(const ir::AstNode *node, Label *ifTrue) 141 { 142 Sa().Emit<Jnez>(node, ifTrue); 143 } 144 BranchIfUndefined(const ir::AstNode * node,Label * ifNull)145 void BranchIfUndefined(const ir::AstNode *node, Label *ifNull) 146 { 147 Sa().Emit<JeqzObj>(node, ifNull); 148 } 149 BranchIfNotUndefined(const ir::AstNode * node,Label * ifNotNull)150 void BranchIfNotUndefined(const ir::AstNode *node, Label *ifNotNull) 151 { 152 Sa().Emit<JnezObj>(node, ifNotNull); 153 } 154 BranchIfNull(const ir::AstNode * node,Label * ifTaken)155 void BranchIfNull(const ir::AstNode *node, Label *ifTaken) 156 { 157 EmitIsNull(node); 158 BranchIfTrue(node, ifTaken); 159 } 160 BranchIfNotNull(const ir::AstNode * node,Label * ifTaken)161 void BranchIfNotNull(const ir::AstNode *node, Label *ifTaken) 162 { 163 EmitIsNull(node); 164 BranchIfFalse(node, ifTaken); 165 } 166 167 void BranchIfNullish(const ir::AstNode *node, Label *ifNullish); 168 void BranchIfNotNullish(const ir::AstNode *node, Label *ifNotNullish); 169 void AssumeNonNullish(const ir::AstNode *node, checker::Type const *targetType); 170 JumpTo(const ir::AstNode * node,Label * labelTo)171 void JumpTo(const ir::AstNode *node, Label *labelTo) 172 { 173 Sa().Emit<Jmp>(node, labelTo); 174 } 175 EmitThrow(const ir::AstNode * node,VReg err)176 void EmitThrow(const ir::AstNode *node, VReg err) 177 { 178 Ra().Emit<Throw>(node, err); 179 } 180 181 void EmitNullishException(const ir::AstNode *node); 182 void ThrowException(const ir::Expression *expr); 183 bool ExtendWithFinalizer(ir::AstNode const *node, const ir::AstNode *originalNode, Label *prevFinnaly = nullptr); 184 185 void Negate(const ir::AstNode *node); 186 void LogicalNot(const ir::AstNode *node); 187 188 void LoadAccumulatorByte(const ir::AstNode *node, int8_t number); 189 190 void LoadAccumulatorShort(const ir::AstNode *node, int16_t number); 191 192 void LoadAccumulatorInt(const ir::AstNode *node, int32_t number); 193 194 void LoadAccumulatorWideInt(const ir::AstNode *node, int64_t number); 195 196 void LoadAccumulatorFloat(const ir::AstNode *node, float number); 197 198 void LoadAccumulatorDouble(const ir::AstNode *node, double number); 199 200 void LoadAccumulatorBoolean(const ir::AstNode *node, bool value); 201 202 void LoadAccumulatorString(const ir::AstNode *node, util::StringView str); 203 204 void LoadAccumulatorBigInt(const ir::AstNode *node, util::StringView str); 205 206 void LoadAccumulatorUndefined(const ir::AstNode *node); 207 208 void LoadAccumulatorNull([[maybe_unused]] const ir::AstNode *node); 209 210 void LoadAccumulatorPoison(const ir::AstNode *node, const checker::Type *type); 211 212 void LoadAccumulatorChar(const ir::AstNode *node, char16_t value); 213 214 void LoadAccumulatorDynamicModule(const ir::AstNode *node, const ir::ETSImportDeclaration *import); 215 216 void ApplyBoxingConversion(const ir::AstNode *node); 217 void ApplyUnboxingConversion(const ir::AstNode *node); ApplyConversion(const ir::AstNode * node)218 void ApplyConversion(const ir::AstNode *node) 219 { 220 if (targetType_ != nullptr) { 221 ApplyConversion(node, targetType_); 222 } 223 } 224 void ApplyConversionCast(const ir::AstNode *node, const checker::Type *targetType); 225 void ApplyConversion(const ir::AstNode *node, const checker::Type *targetType); 226 void ApplyCast(const ir::AstNode *node, const checker::Type *targetType); 227 void ApplyCastToBoxingFlags(const ir::AstNode *node, const ir::BoxingUnboxingFlags targetType); 228 void EmitBoxingConversion(ir::BoxingUnboxingFlags boxingFlag, const ir::AstNode *node); 229 void EmitBoxingConversion(const ir::AstNode *node); 230 void SwapBinaryOpArgs(const ir::AstNode *node, VReg lhs); 231 VReg MoveAccToReg(const ir::AstNode *node); 232 233 void LoadResizableArrayLength(const ir::AstNode *node); 234 void LoadResizableArrayElement(const ir::AstNode *node, const VReg arrObj, const VReg arrIndex); 235 void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); 236 void LoadArrayElement(const ir::AstNode *node, VReg objectReg); 237 void StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index, const checker::Type *elementType); 238 239 util::StringView GetTupleMemberNameForIndex(std::size_t index) const; 240 void LoadTupleElement(const ir::AstNode *node, VReg objectReg, const checker::Type *elementType, std::size_t index); 241 void StoreTupleElement(const ir::AstNode *node, VReg objectReg, const checker::Type *elementType, 242 std::size_t index); 243 244 template <typename T> 245 void MoveImmediateToRegister(const ir::AstNode *node, VReg reg, const checker::TypeFlag valueType, T const value); 246 247 template <typename T> 248 void IncrementImmediateRegister(const ir::AstNode *node, VReg reg, const checker::TypeFlag valueType, 249 T const value); 250 251 template <typename IntCompare> JumpCompareRegister(const ir::AstNode * node,VReg lhs,Label * ifFalse)252 void JumpCompareRegister(const ir::AstNode *node, VReg lhs, Label *ifFalse) 253 { 254 Ra().Emit<IntCompare>(node, lhs, ifFalse); 255 } 256 257 void LoadStringLength(const ir::AstNode *node); 258 void LoadStringChar(const ir::AstNode *node, VReg stringObj, VReg charIndex); 259 260 void FloatIsNaN(const ir::AstNode *node); 261 void DoubleIsNaN(const ir::AstNode *node); 262 263 void CompileStatements(const ArenaVector<ir::Statement *> &statements); 264 265 // Cast 266 void CastToBoolean(const ir::AstNode *node); 267 void CastToByte(const ir::AstNode *node); 268 void CastToChar(const ir::AstNode *node); 269 void CastToShort(const ir::AstNode *node); 270 void CastToDouble(const ir::AstNode *node); 271 void CastToFloat(const ir::AstNode *node); 272 void CastToLong(const ir::AstNode *node); 273 void CastToInt(const ir::AstNode *node); 274 void CastToString(const ir::AstNode *node); 275 void CastToDynamic(const ir::AstNode *node, const checker::ETSDynamicType *type); 276 void CastDynamicTo(const ir::AstNode *node, enum checker::TypeFlag typeFlag); 277 void CastToReftype(const ir::AstNode *node, const checker::Type *targetType, bool unchecked); 278 void CastDynamicToObject(const ir::AstNode *node, const checker::Type *targetType); 279 280 void InternalIsInstance(const ir::AstNode *node, const checker::Type *target); 281 void InternalCheckCast(const ir::AstNode *node, const checker::Type *target); 282 void CheckedReferenceNarrowing(const ir::AstNode *node, const checker::Type *target); 283 void GuardUncheckedType(const ir::AstNode *node, const checker::Type *unchecked, const checker::Type *target); 284 285 // Call, Construct 286 void NewArray(const ir::AstNode *node, VReg arr, VReg dim, const checker::Type *arrType); 287 void NewObject(const ir::AstNode *node, util::StringView name, VReg athis); 288 void BuildString(const ir::Expression *node); 289 void CallBigIntUnaryOperator(const ir::Expression *node, VReg arg, util::StringView signature); 290 void CallBigIntBinaryOperator(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); 291 void CallBigIntBinaryComparison(const ir::Expression *node, VReg lhs, VReg rhs, util::StringView signature); 292 void BuildTemplateString(const ir::TemplateLiteral *node); InitObject(const ir::AstNode * node,checker::Signature const * signature,const ArenaVector<ir::Expression * > & arguments)293 void InitObject(const ir::AstNode *node, checker::Signature const *signature, 294 const ArenaVector<ir::Expression *> &arguments) 295 { 296 CallImpl<InitobjShort, Initobj, InitobjRange>(node, signature, arguments); 297 } 298 IsDevirtualizedSignature(const checker::Signature * signature)299 bool IsDevirtualizedSignature(const checker::Signature *signature) 300 { 301 ES2PANDA_ASSERT(signature != nullptr && !signature->HasSignatureFlag(checker::SignatureFlags::STATIC)); 302 return signature->HasSignatureFlag(checker::SignatureFlags::FINAL | checker::SignatureFlags::PRIVATE | 303 checker::SignatureFlags::CONSTRUCTOR); 304 } 305 EmitEtsTypeof(const ir::AstNode * node,const VReg reg)306 void EmitEtsTypeof([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const VReg reg) 307 { 308 #ifdef PANDA_WITH_ETS 309 Ra().Emit<EtsTypeof>(node, reg); 310 #else 311 ES2PANDA_UNREACHABLE(); 312 #endif // PANDA_WITH_ETS 313 } 314 EmitEtsIstrue(const ir::AstNode * node,const VReg reg)315 void EmitEtsIstrue([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const VReg reg) 316 { 317 #ifdef PANDA_WITH_ETS 318 Ra().Emit<EtsIstrue>(node, reg); 319 #else 320 ES2PANDA_UNREACHABLE(); 321 #endif // PANDA_WITH_ETS 322 } 323 CallExact(const ir::AstNode * node,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)324 void CallExact(const ir::AstNode *node, checker::Signature *signature, 325 const ArenaVector<ir::Expression *> &arguments) 326 { 327 CallImpl<CallShort, Call, CallRange>(node, signature, arguments); 328 } 329 CallExact(const ir::AstNode * const node,const checker::Signature * signature,const VReg arg0,const ArenaVector<ir::Expression * > & arguments)330 void CallExact(const ir::AstNode *const node, const checker::Signature *signature, const VReg arg0, 331 const ArenaVector<ir::Expression *> &arguments) 332 { 333 CallArgStart<CallShort, Call, CallRange>(node, signature, arg0, arguments); 334 } 335 CallExact(const ir::AstNode * const node,const util::StringView name)336 void CallExact(const ir::AstNode *const node, const util::StringView name) 337 { 338 Ra().Emit<CallShort, 0>(node, name, dummyReg_, dummyReg_); 339 } 340 CallExact(const ir::AstNode * const node,const util::StringView name,const VReg arg0)341 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0) 342 { 343 Ra().Emit<CallShort, 1>(node, name, arg0, dummyReg_); 344 } 345 CallExact(const ir::AstNode * const node,const util::StringView name,const VReg arg0,const VReg arg1)346 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1) 347 { 348 Ra().Emit<CallShort>(node, name, arg0, arg1); 349 } 350 CallExact(const ir::AstNode * const node,const util::StringView name,const VReg arg0,const VReg arg1,const VReg arg2)351 void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1, 352 const VReg arg2) 353 { 354 Ra().Emit<Call, 3U>(node, name, arg0, arg1, arg2, dummyReg_); 355 } 356 CallByName(const ir::AstNode * const node,const checker::Signature * signature,const VReg arg0,const ArenaVector<ir::Expression * > & arguments)357 void CallByName([[maybe_unused]] const ir::AstNode *const node, 358 [[maybe_unused]] const checker::Signature *signature, [[maybe_unused]] const VReg arg0, 359 [[maybe_unused]] const ArenaVector<ir::Expression *> &arguments) 360 { 361 #ifdef PANDA_WITH_ETS 362 CallArgStart<EtsCallNameShort, EtsCallName, EtsCallNameRange>(node, signature, arg0, arguments); 363 #else 364 ES2PANDA_UNREACHABLE(); 365 #endif 366 } 367 CallVirtual(const ir::AstNode * const node,const checker::Signature * signature,const VReg athis,const ArenaVector<ir::Expression * > & arguments)368 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis, 369 const ArenaVector<ir::Expression *> &arguments) 370 { 371 ES2PANDA_ASSERT(!signature->HasSignatureFlag(checker::SignatureFlags::STATIC)); 372 ES2PANDA_ASSERT(!signature->Owner()->GetDeclNode()->IsFinal() || signature->IsFinal()); 373 if (IsDevirtualizedSignature(signature)) { 374 CallArgStart<CallShort, Call, CallRange>(node, signature, athis, arguments); 375 } else { 376 CallArgStart<CallVirtShort, CallVirt, CallVirtRange>(node, signature, athis, arguments); 377 } 378 } 379 CallVirtual(const ir::AstNode * const node,const checker::Signature * signature,const VReg athis)380 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis) 381 { 382 if (IsDevirtualizedSignature(signature)) { 383 CallExact(node, signature->InternalName(), athis); 384 } else { 385 CallVirtual(node, signature->InternalName(), athis); 386 } 387 } 388 CallVirtual(const ir::AstNode * const node,const checker::Signature * signature,const VReg athis,const VReg arg0)389 void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis, 390 const VReg arg0) 391 { 392 if (IsDevirtualizedSignature(signature)) { 393 CallExact(node, signature->InternalName(), athis, arg0); 394 } else { 395 CallVirtual(node, signature->InternalName(), athis, arg0); 396 } 397 } 398 CallVirtual(const ir::AstNode * const node,const util::StringView name,const VReg athis)399 void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis) 400 { 401 Ra().Emit<CallVirtShort, 1>(node, name, athis, dummyReg_); 402 } 403 CallVirtual(const ir::AstNode * const node,const util::StringView name,const VReg athis,const VReg arg0)404 void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis, const VReg arg0) 405 { 406 Ra().Emit<CallVirtShort>(node, name, athis, arg0); 407 } 408 409 struct CallDynamicData { 410 const ir::AstNode *node = nullptr; 411 VReg obj; 412 VReg param2; 413 }; 414 CallDynamic(CallDynamicData data,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)415 void CallDynamic(CallDynamicData data, checker::Signature *signature, 416 const ArenaVector<ir::Expression *> &arguments) 417 { 418 CallDynamicImpl<CallShort, Call, CallRange>(data, signature, arguments); 419 } 420 CallDynamic(CallDynamicData data,VReg param3,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)421 void CallDynamic(CallDynamicData data, VReg param3, checker::Signature *signature, 422 const ArenaVector<ir::Expression *> &arguments) 423 { 424 CallDynamicImpl<CallShort, Call, CallRange>(data, param3, signature, arguments); 425 } 426 427 // until a lowering for implicit super is available 428 void CallRangeFillUndefined(const ir::AstNode *const node, checker::Signature *const signature, const VReg thisReg); 429 430 void CreateBigIntObject(const ir::AstNode *node, VReg arg0, 431 std::string_view signature = Signatures::BUILTIN_BIGINT_CTOR); 432 GetType(const ir::AstNode * node,bool isEtsPrimitive)433 void GetType(const ir::AstNode *node, bool isEtsPrimitive) 434 { 435 if (isEtsPrimitive) { 436 // NOTE: SzD. LoadStaticProperty if ETS stdlib has static TYPE constants otherwise fallback to LdaType 437 } else { 438 ES2PANDA_ASSERT(GetAccumulatorType() != nullptr); 439 auto classRef = GetAccumulatorType()->AsETSObjectType()->AssemblerName(); 440 Sa().Emit<LdaType>(node, classRef); 441 } 442 } 443 444 ~ETSGen() override = default; 445 NO_COPY_SEMANTIC(ETSGen); 446 NO_MOVE_SEMANTIC(ETSGen); 447 448 private: 449 const VReg dummyReg_ = VReg::RegStart(); 450 451 void EmitUnboxedCall(const ir::AstNode *node, std::string_view signatureFlag, const checker::Type *targetType, 452 const checker::Type *boxedType); 453 454 void LoadConstantObject(const ir::Expression *node, const checker::Type *type); 455 void StringBuilderAppend(const ir::AstNode *node, VReg builder); 456 void AppendString(const ir::Expression *binExpr, VReg builder); 457 void StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg builder); 458 util::StringView FormClassPropReference(varbinder::Variable const *var); 459 void UnaryMinus(const ir::AstNode *node); 460 void UnaryTilde(const ir::AstNode *node); 461 462 util::StringView ToAssemblerType(const es2panda::checker::Type *type) const; 463 void TestIsInstanceConstituent(const ir::AstNode *node, std::tuple<Label *, Label *> label, 464 checker::Type const *target, bool acceptNull); 465 void CheckedReferenceNarrowingObject(const ir::AstNode *node, const checker::Type *target); 466 467 template <bool IS_SRTICT = false> 468 void HandleDefinitelyNullishEquality(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse); 469 template <bool IS_SRTICT = false> 470 void HandlePossiblyNullishEquality(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse, Label *ifTrue); 471 EmitIsNull(const ir::AstNode * node)472 void EmitIsNull([[maybe_unused]] const ir::AstNode *node) 473 { 474 #ifdef PANDA_WITH_ETS 475 Sa().Emit<EtsIsnullvalue>(node); 476 #else 477 ES2PANDA_UNREACHABLE(); 478 #endif // PANDA_WITH_ETS 479 } 480 EmitCheckCast(const ir::AstNode * node,util::StringView target)481 void EmitCheckCast(const ir::AstNode *node, util::StringView target) 482 { 483 if (target != Signatures::BUILTIN_OBJECT) { 484 Sa().Emit<Checkcast>(node, target); 485 } 486 } 487 EmitIsInstance(const ir::AstNode * node,util::StringView target)488 void EmitIsInstance(const ir::AstNode *node, util::StringView target) 489 { 490 if (target != Signatures::BUILTIN_OBJECT) { 491 Sa().Emit<Isinstance>(node, target); 492 } else { 493 LoadAccumulatorBoolean(node, true); 494 } 495 } 496 497 template <bool IS_SRTICT = false> EmitEtsEquals(const ir::AstNode * node,const VReg lhs,const VReg rhs)498 void EmitEtsEquals([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const VReg lhs, 499 [[maybe_unused]] const VReg rhs) 500 { 501 #ifdef PANDA_WITH_ETS 502 if constexpr (IS_SRTICT) { 503 Ra().Emit<EtsStrictequals>(node, lhs, rhs); 504 } else { 505 Ra().Emit<EtsEquals>(node, lhs, rhs); 506 } 507 #else 508 ES2PANDA_UNREACHABLE(); 509 #endif // PANDA_WITH_ETS 510 } 511 512 template <typename T> StoreValueIntoArray(const ir::AstNode * const node,const VReg arr,const VReg index)513 void StoreValueIntoArray(const ir::AstNode *const node, const VReg arr, const VReg index) 514 { 515 Ra().Emit<T>(node, arr, index); 516 } 517 518 template <typename LongOp, typename IntOp, typename DoubleOp, typename FloatOp> 519 void UpdateOperator(const ir::AstNode *node); 520 521 template <typename Br> 522 void InverseCondition(const ir::AstNode *node, Br const &br, Label *target, bool inverse = true) 523 { 524 if (!inverse) { 525 br(target); 526 return; 527 } 528 Label *loc = AllocLabel(); 529 br(loc); 530 JumpTo(node, target); 531 SetLabel(node, loc); 532 } 533 534 template <bool IS_SRTICT = false> 535 void RefEqualityLoose(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse); 536 template <bool IS_SRTICT = false> 537 void RefEqualityLooseDynamic(const ir::AstNode *node, VReg lhs, VReg rhs, Label *ifFalse); 538 539 template <typename Compare, typename Cond> BinaryNumberComparison(const ir::AstNode * node,VReg lhs,Label * ifFalse)540 void BinaryNumberComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) 541 { 542 Ra().Emit<Compare>(node, lhs); 543 Sa().Emit<Cond>(node, ifFalse); 544 } 545 546 template <typename IntCompare, typename CondCompare, typename DynCompare, bool IS_STRICT = false> 547 void BinaryEquality(const ir::AstNode *node, VReg lhs, Label *ifFalse); 548 549 template <typename IntCompare, typename CondCompare, bool IS_STRICT = false> 550 void BinaryEqualityCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse); 551 552 template <typename IntCompare, typename CondCompare> 553 void BinaryRelation(const ir::AstNode *node, VReg lhs, Label *ifFalse); 554 555 template <typename IntCompare, typename CondCompare> 556 void BinaryRelationCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse); 557 558 template <typename CompareGreater, typename CompareLess, typename CondCompare> BinaryFloatingPointComparison(const ir::AstNode * node,VReg lhs,Label * ifFalse)559 void BinaryFloatingPointComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) 560 { 561 if constexpr (std::is_same_v<CondCompare, Jgez> || std::is_same_v<CondCompare, Jgtz>) { 562 BinaryNumberComparison<CompareGreater, CondCompare>(node, lhs, ifFalse); 563 } else { 564 BinaryNumberComparison<CompareLess, CondCompare>(node, lhs, ifFalse); 565 } 566 } 567 568 template <typename IntOp, typename LongOp, typename FloatOp, typename DoubleOp> 569 void BinaryArithmetic(const ir::AstNode *node, VReg lhs); 570 571 template <typename IntOp, typename LongOp> 572 void BinaryBitwiseArithmetic(const ir::AstNode *node, VReg lhs); 573 574 // NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty) 575 #define COMPILE_ARG(idx) \ 576 ES2PANDA_ASSERT((idx) < arguments.size()); \ 577 ES2PANDA_ASSERT((idx) < signature->Params().size() || signature->RestVar() != nullptr); \ 578 auto *param##idx = (idx) < signature->Params().size() ? signature->Params()[(idx)] : signature->RestVar(); \ 579 auto *paramType##idx = param##idx->TsType(); \ 580 auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ 581 arguments[idx]->Compile(this); \ 582 VReg arg##idx = AllocReg(); \ 583 ApplyConversion(arguments[idx], nullptr); \ 584 ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) 585 586 template <typename Short, typename General, typename Range> CallArgStart(const ir::AstNode * const node,const checker::Signature * signature,const VReg argStart,const ArenaVector<ir::Expression * > & arguments)587 void CallArgStart(const ir::AstNode *const node, const checker::Signature *signature, const VReg argStart, 588 const ArenaVector<ir::Expression *> &arguments) 589 { 590 RegScope rs(this); 591 const auto name = signature->InternalName(); 592 593 switch (arguments.size()) { 594 case 0U: { 595 Ra().Emit<Short, 1>(node, name, argStart, dummyReg_); 596 break; 597 } 598 case 1U: { 599 COMPILE_ARG(0); 600 Ra().Emit<Short>(node, name, argStart, arg0); 601 break; 602 } 603 case 2U: { 604 COMPILE_ARG(0); 605 COMPILE_ARG(1); 606 Ra().Emit<General, 3U>(node, name, argStart, arg0, arg1, dummyReg_); 607 break; 608 } 609 case 3U: { 610 COMPILE_ARG(0); 611 COMPILE_ARG(1); 612 COMPILE_ARG(2); 613 Ra().Emit<General>(node, name, argStart, arg0, arg1, arg2); 614 break; 615 } 616 default: { 617 for (size_t idx = 0; idx < arguments.size(); idx++) { 618 COMPILE_ARG(idx); 619 } 620 621 Rra().Emit<Range>(node, argStart, arguments.size() + 1, name, argStart); 622 break; 623 } 624 } 625 } 626 627 template <typename Short, typename General, typename Range> CallImpl(const ir::AstNode * node,checker::Signature const * signature,const ArenaVector<ir::Expression * > & arguments)628 void CallImpl(const ir::AstNode *node, checker::Signature const *signature, 629 const ArenaVector<ir::Expression *> &arguments) 630 { 631 ES2PANDA_ASSERT(signature != nullptr); 632 RegScope rs(this); 633 634 switch (arguments.size()) { 635 case 0U: { 636 Ra().Emit<Short, 0U>(node, signature->InternalName(), dummyReg_, dummyReg_); 637 break; 638 } 639 case 1U: { 640 COMPILE_ARG(0); 641 Ra().Emit<Short, 1U>(node, signature->InternalName(), arg0, dummyReg_); 642 break; 643 } 644 case 2U: { 645 COMPILE_ARG(0); 646 COMPILE_ARG(1); 647 Ra().Emit<Short, 2U>(node, signature->InternalName(), arg0, arg1); 648 break; 649 } 650 case 3U: { 651 COMPILE_ARG(0); 652 COMPILE_ARG(1); 653 COMPILE_ARG(2); 654 Ra().Emit<General, 3U>(node, signature->InternalName(), arg0, arg1, arg2, dummyReg_); 655 break; 656 } 657 case 4U: { 658 COMPILE_ARG(0); 659 COMPILE_ARG(1); 660 COMPILE_ARG(2); 661 COMPILE_ARG(3); 662 Ra().Emit<General, 4U>(node, signature->InternalName(), arg0, arg1, arg2, arg3); 663 break; 664 } 665 default: { 666 VReg argStart = NextReg(); 667 668 for (size_t idx = 0; idx < arguments.size(); idx++) { 669 COMPILE_ARG(idx); 670 } 671 672 Rra().Emit<Range>(node, argStart, arguments.size(), signature->InternalName(), argStart); 673 break; 674 } 675 } 676 } 677 #undef COMPILE_ARG 678 679 #define COMPILE_ARG(idx, shift) \ 680 ES2PANDA_ASSERT((idx) < arguments.size()); \ 681 ES2PANDA_ASSERT((idx) + (shift) < signature->Params().size() || signature->RestVar() != nullptr); \ 682 auto *paramType##idx = (idx) + (shift) < signature->Params().size() \ 683 ? signature->Params()[(idx) + (shift)]->TsType() \ 684 : signature->RestVar()->TsType(); \ 685 auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ 686 VReg arg##idx = AllocReg(); \ 687 arguments[idx]->Compile(this); \ 688 ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) 689 690 template <typename Short, typename General, typename Range> CallDynamicImpl(CallDynamicData data,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)691 void CallDynamicImpl(CallDynamicData data, checker::Signature *signature, 692 const ArenaVector<ir::Expression *> &arguments) 693 { 694 RegScope rs(this); 695 const auto name = signature->InternalName(); 696 697 switch (arguments.size()) { 698 case 0U: { 699 Ra().Emit<Short>(data.node, name, data.obj, data.param2); 700 break; 701 } 702 case 1U: { 703 COMPILE_ARG(0, 2U); 704 Ra().Emit<General, 3U>(data.node, name, data.obj, data.param2, arg0, dummyReg_); 705 break; 706 } 707 case 2U: { 708 COMPILE_ARG(0, 2U); 709 COMPILE_ARG(1, 2U); 710 Ra().Emit<General>(data.node, name, data.obj, data.param2, arg0, arg1); 711 break; 712 } 713 default: { 714 for (size_t idx = 0; idx < arguments.size(); idx++) { 715 COMPILE_ARG(idx, 2U); 716 } 717 718 Rra().Emit<Range>(data.node, data.obj, arguments.size() + 2U, name, data.obj); 719 break; 720 } 721 } 722 } 723 724 template <typename Short, typename General, typename Range> CallDynamicImpl(CallDynamicData data,VReg param3,checker::Signature * signature,const ArenaVector<ir::Expression * > & arguments)725 void CallDynamicImpl(CallDynamicData data, VReg param3, checker::Signature *signature, 726 const ArenaVector<ir::Expression *> &arguments) 727 { 728 RegScope rs(this); 729 const auto name = signature->InternalName(); 730 731 switch (arguments.size()) { 732 case 0U: { 733 Ra().Emit<General, 3U>(data.node, name, data.obj, data.param2, param3, dummyReg_); 734 break; 735 } 736 case 1U: { 737 COMPILE_ARG(0, 3U); 738 Ra().Emit<General>(data.node, name, data.obj, data.param2, param3, arg0); 739 break; 740 } 741 default: { 742 for (size_t idx = 0; idx < arguments.size(); idx++) { 743 COMPILE_ARG(idx, 3U); 744 } 745 746 Rra().Emit<Range>(data.node, data.obj, arguments.size() + 3U, name, data.obj); 747 break; 748 } 749 } 750 } 751 752 #undef COMPILE_ARG 753 // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty) 754 755 void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); 756 757 template <typename T> 758 void LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType); 759 template <typename T> 760 void SetAccumulatorTargetType(const ir::AstNode *node, checker::TypeFlag typeKind, T number); 761 void InitializeContainingClass(); 762 763 util::StringView FormDynamicModulePropReference(const varbinder::Variable *var); 764 util::StringView FormDynamicModulePropReference(const ir::ETSImportDeclaration *import); 765 766 friend class TargetTypeContext; 767 768 VReg acc_ {}; 769 const checker::Type *targetType_ {}; 770 const checker::ETSObjectType *containingObjectType_ {}; 771 }; 772 773 } // namespace ark::es2panda::compiler 774 775 #endif 776