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