1/* 2 * Copyright (c) 2021-2022 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 "pandagen.h" 17 18#include <binder/binder.h> 19#include <binder/scope.h> 20#include <binder/variable.h> 21#include <compiler/base/catchTable.h> 22#include <compiler/base/lexenv.h> 23#include <compiler/base/literals.h> 24#include <compiler/core/compilerContext.h> 25#include <compiler/core/labelTarget.h> 26#include <compiler/core/regAllocator.h> 27#include <compiler/function/asyncFunctionBuilder.h> 28#include <compiler/function/asyncGeneratorFunctionBuilder.h> 29#include <compiler/function/functionBuilder.h> 30#include <compiler/function/generatorFunctionBuilder.h> 31#include <es2panda.h> 32#include <gen/isa.h> 33#include <ir/base/classDefinition.h> 34#include <ir/base/methodDefinition.h> 35#include <ir/base/scriptFunction.h> 36#include <ir/base/spreadElement.h> 37#include <ir/expressions/callExpression.h> 38#include <ir/expressions/functionExpression.h> 39#include <ir/expressions/identifier.h> 40#include <ir/expressions/literals/numberLiteral.h> 41#include <ir/expressions/literals/stringLiteral.h> 42#include <ir/expressions/newExpression.h> 43#include <ir/module/importSpecifier.h> 44#include <ir/statement.h> 45#include <util/concurrent.h> 46#include <util/helpers.h> 47#include <util/patchFix.h> 48 49namespace panda::es2panda::compiler { 50 51// PandaGen 52 53void PandaGen::SetFunctionKind() 54{ 55 int targetApiVersion = Binder()->Program()->TargetApiVersion(); 56 if (rootNode_->IsProgram()) { 57 funcKind_ = panda::panda_file::FunctionKind::FUNCTION; 58 return; 59 } 60 61 auto *func = rootNode_->AsScriptFunction(); 62 if (func->IsConcurrent()) { 63 funcKind_ = panda::panda_file::FunctionKind::CONCURRENT_FUNCTION; 64 return; 65 } 66 67 if (func->IsMethod()) { 68 if (func->IsAsync()) { 69 funcKind_ = panda::panda_file::FunctionKind::ASYNC_FUNCTION; 70 } 71 return; 72 } 73 74 if (func->IsAsync()) { 75 if (func->IsGenerator()) { 76 funcKind_ = panda::panda_file::FunctionKind::ASYNC_GENERATOR_FUNCTION; 77 return; 78 } 79 80 if (func->IsArrow()) { 81 funcKind_ = panda::panda_file::FunctionKind::ASYNC_NC_FUNCTION; 82 return; 83 } 84 85 funcKind_ = panda::panda_file::FunctionKind::ASYNC_FUNCTION; 86 87 if (func->IsSendable() && targetApiVersion >= util::Helpers::SENDABLE_FUNCTION_MIN_SUPPORTED_API_VERSION) { 88 funcKind_ |= panda::panda_file::FunctionKind::SENDABLE_FUNCTION; 89 } 90 return; 91 } 92 93 if (func->IsGenerator()) { 94 funcKind_ = panda::panda_file::FunctionKind::GENERATOR_FUNCTION; 95 return; 96 } 97 98 if (func->IsArrow()) { 99 funcKind_ = panda::panda_file::FunctionKind::NC_FUNCTION; 100 return; 101 } 102 103 funcKind_ = panda::panda_file::FunctionKind::FUNCTION; 104 105 if (func->IsSendable() && targetApiVersion >= util::Helpers::SENDABLE_FUNCTION_MIN_SUPPORTED_API_VERSION) { 106 funcKind_ |= panda::panda_file::FunctionKind::SENDABLE_FUNCTION; 107 } 108} 109 110void PandaGen::SetInSendable() 111{ 112 if (rootNode_->IsProgram()) { 113 return; 114 } 115 116 auto *func = rootNode_->AsScriptFunction(); 117 inSendable_ = func->InSendable(); 118} 119 120Label *PandaGen::AllocLabel() 121{ 122 std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); 123 return ra_.AllocLabel(std::move(id)); 124} 125 126bool PandaGen::IsDebug() const 127{ 128 return context_->IsDebug(); 129} 130 131bool PandaGen::isDebuggerEvaluateExpressionMode() const 132{ 133 return context_->isDebuggerEvaluateExpressionMode(); 134} 135 136std::string PandaGen::SourceFile() const 137{ 138 return context_->SourceFile(); 139} 140 141uint32_t PandaGen::ParamCount() const 142{ 143 if (rootNode_->IsProgram()) { 144 return 0; 145 } 146 147 return rootNode_->AsScriptFunction()->Params().size(); 148} 149 150uint32_t PandaGen::FormalParametersCount() const 151{ 152 if (rootNode_->IsProgram()) { 153 return 0; 154 } 155 156 ASSERT(rootNode_->IsScriptFunction()); 157 158 return rootNode_->AsScriptFunction()->FormalParamsLength(); 159} 160 161uint32_t PandaGen::InternalParamCount() const 162{ 163 if (rootNode_->IsProgram() && context_->Binder()->Program()->IsCommonjs()) { 164 return binder::Binder::CJS_MANDATORY_PARAMS_NUMBER; 165 } 166 return ParamCount() + binder::Binder::MANDATORY_PARAMS_NUMBER; 167} 168 169const util::StringView &PandaGen::InternalName() const 170{ 171 return topScope_->InternalName(); 172} 173 174const util::StringView &PandaGen::FunctionName() const 175{ 176 return topScope_->Name(); 177} 178 179binder::Binder *PandaGen::Binder() const 180{ 181 return context_->Binder(); 182} 183 184void PandaGen::FunctionInit(CatchTable *catchTable) 185{ 186 if (rootNode_->IsProgram()) { 187 if (context_->Binder()->Program()->HasTLA()) { 188 builder_ = allocator_->New<AsyncFunctionBuilder>(this, catchTable); 189 } else { 190 builder_ = allocator_->New<FunctionBuilder>(this, catchTable); 191 } 192 return; 193 } 194 195 const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); 196 197 if (func->IsAsync()) { 198 if (func->IsGenerator()) { 199 builder_ = allocator_->New<AsyncGeneratorFunctionBuilder>(this, catchTable); 200 return; 201 } 202 203 builder_ = allocator_->New<AsyncFunctionBuilder>(this, catchTable); 204 return; 205 } 206 207 if (func->IsGenerator()) { 208 builder_ = allocator_->New<GeneratorFunctionBuilder>(this, catchTable); 209 return; 210 } 211 212 builder_ = allocator_->New<FunctionBuilder>(this, catchTable); 213} 214 215bool PandaGen::FunctionHasFinalizer() const 216{ 217 if (rootNode_->IsProgram()) { 218 return context_->Binder()->Program()->HasTLA(); 219 } 220 221 const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); 222 223 return func->IsAsync() || func->IsGenerator(); 224} 225 226bool PandaGen::IsAsyncFunction() const 227{ 228 if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) { 229 return true; 230 } 231 const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); 232 return func->IsAsync() && !func->IsGenerator(); 233} 234 235void PandaGen::FunctionEnter() 236{ 237 if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) { 238 builder_->Prepare(nullptr); 239 return; 240 } 241 builder_->Prepare(rootNode_->AsScriptFunction()); 242} 243 244void PandaGen::FunctionExit() 245{ 246 if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) { 247 builder_->CleanUp(nullptr); 248 return; 249 } 250 builder_->CleanUp(rootNode_->AsScriptFunction()); 251} 252 253void PandaGen::InitializeLexEnv(const ir::AstNode *node) 254{ 255 FrontAllocator fa(this); 256 257 if (topScope_->NeedLexEnv()) { 258 NewLexicalEnv(node, topScope_->LexicalSlots(), topScope_); 259 } 260 261 if (topScope_->NeedSendableEnv()) { 262 NewSendableEnv(node, topScope_->SendableSlots()); 263 } 264} 265 266void PandaGen::CopyFunctionArguments(const ir::AstNode *node) 267{ 268 FrontAllocator fa(this); 269 VReg targetReg = totalRegs_; 270 271 for (const auto *param : topScope_->ParamScope()->Params()) { 272 if (param->LexicalBound()) { 273 StoreLexicalVar(node, 0, param->LexIdx(), targetReg++); 274 continue; 275 } 276 MoveVreg(node, param->Vreg(), targetReg++); 277 } 278} 279 280LiteralBuffer *PandaGen::NewLiteralBuffer() 281{ 282 LiteralBuffer *buf = allocator_->New<LiteralBuffer>(allocator_); 283 CHECK_NOT_NULL(buf); 284 return buf; 285} 286 287int32_t PandaGen::AddLiteralBuffer(LiteralBuffer *buf) 288{ 289 CHECK_NOT_NULL(buf); 290 buffStorage_.push_back(buf); 291 buf->SetIndex(context_->NewLiteralIndex()); 292 return buf->Index(); 293} 294 295int32_t PandaGen::AddLexicalVarNamesForDebugInfo(ArenaMap<uint32_t, std::pair<util::StringView, int>> &lexicalVars) 296{ 297 auto *buf = NewLiteralBuffer(); 298 buf->Add(Allocator()->New<ir::NumberLiteral>(lexicalVars.size())); 299 for (auto &iter : lexicalVars) { 300 // The slot is set to UINT32_MAX when the variable is a patchvar while its value is not stored in the slot 301 // The patchvar info should not be added to the DebugInfo since its value cannot be found in slot UINT32_MAX 302 if (iter.first != UINT32_MAX) { 303 buf->Add(Allocator()->New<ir::StringLiteral>(iter.second.first)); 304 buf->Add(Allocator()->New<ir::NumberLiteral>(iter.first)); 305 } 306 } 307 return AddLiteralBuffer(buf); 308} 309 310void PandaGen::GetFunctionObject(const ir::AstNode *node) 311{ 312 LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_FUNC)); 313} 314 315void PandaGen::GetNewTarget(const ir::AstNode *node) 316{ 317 LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_NEW_TARGET)); 318} 319 320void PandaGen::GetThis(const ir::AstNode *node) 321{ 322 LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS)); 323} 324 325void PandaGen::SetThis(const ir::AstNode *node) 326{ 327 StoreAccToLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS), true); 328} 329 330void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result) 331{ 332 auto *var = result.variable; 333 334 if (!var || var->Declaration()->IsDeclare()) { 335 TryLoadGlobalByName(node, result.name); 336 return; 337 } 338 339 if (var->IsGlobalVariable()) { 340 LoadGlobalVar(node, var->Name()); 341 return; 342 } 343 344 if (var->IsModuleVariable()) { 345 var->HasFlag(binder::VariableFlags::LOCAL_EXPORT) ? LoadLocalModuleVariable(node, var->AsModuleVariable()) : 346 LoadExternalModuleVariable(node, var->AsModuleVariable()); 347 if (var->Declaration()->IsLetOrConstOrClassDecl()) { 348 ThrowUndefinedIfHole(node, var->Name()); 349 } 350 return; 351 } 352 353 ASSERT(var->IsLocalVariable()); 354 355 if (var->Declaration()->IsLetOrConstOrClassDecl() && result.scope->IsGlobalScope()) { 356 TryLoadGlobalByName(node, result.name); 357 return; 358 } 359 360 LoadAccFromLexEnv(node, result); 361} 362 363void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration) 364{ 365 binder::Variable *var = result.variable; 366 367 if (!var) { 368 TryStoreGlobalByName(node, result.name); 369 return; 370 } 371 372 if (var->IsGlobalVariable()) { 373 StoreGlobalVar(node, var->Name()); 374 return; 375 } 376 377 if (var->IsModuleVariable()) { 378 if (!isDeclaration && var->Declaration()->IsConstDecl()) { 379 ThrowConstAssignment(node, var->Name()); 380 return; 381 } 382 383 if (!isDeclaration && 384 (var->Declaration()->IsLetDecl() || var->Declaration()->IsClassDecl())) { 385 RegScope rs(this); 386 VReg valueReg = AllocReg(); 387 StoreAccumulator(node, valueReg); 388 LoadLocalModuleVariable(node, var->AsModuleVariable()); 389 ThrowUndefinedIfHole(node, var->Name()); 390 LoadAccumulator(node, valueReg); 391 } 392 393 StoreModuleVariable(node, var->AsModuleVariable()); 394 return; 395 } 396 397 ASSERT(var->IsLocalVariable()); 398 399 if (var->Declaration()->IsLetOrConstOrClassDecl() && result.scope->IsGlobalScope()) { 400 if (!isDeclaration) { 401 TryStoreGlobalByName(node, var->Name()); 402 } else if (var->Declaration()->IsLetDecl() || var->Declaration()->IsClassDecl()) { 403 StLetOrClassToGlobalRecord(node, var->Name()); 404 } else if (var->Declaration()->IsConstDecl()) { 405 StConstToGlobalRecord(node, var->Name()); 406 } 407 408 return; 409 } 410 411 StoreAccToLexEnv(node, result, isDeclaration); 412} 413 414void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) 415{ 416 ra_.Emit<Sta>(node, vreg); 417} 418 419void PandaGen::LoadAccFromArgs(const ir::AstNode *node) 420{ 421 const auto *varScope = scope_->AsVariableScope(); 422 423 if (!varScope->HasFlag(binder::VariableScopeFlags::USE_ARGS)) { 424 return; 425 } 426 427 binder::ScopeFindResult res = scope_->Find(binder::Binder::FUNCTION_ARGUMENTS); 428 ASSERT(res.scope); 429 430 GetUnmappedArgs(node); 431 StoreAccToLexEnv(node, res, true); 432} 433 434void PandaGen::LoadObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 435{ 436 if (std::holds_alternative<VReg>(prop)) { 437 LoadAccumulator(node, std::get<VReg>(prop)); 438 LoadObjByValue(node, obj); 439 return; 440 } 441 442 if (std::holds_alternative<int64_t>(prop)) { 443 LoadObjByIndex(node, obj, std::get<int64_t>(prop)); 444 return; 445 } 446 447 ASSERT(std::holds_alternative<util::StringView>(prop)); 448 LoadObjByName(node, obj, std::get<util::StringView>(prop)); 449} 450 451void PandaGen::StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 452{ 453 if (std::holds_alternative<VReg>(prop)) { 454 StoreObjByValue(node, obj, std::get<VReg>(prop)); 455 return; 456 } 457 458 if (std::holds_alternative<int64_t>(prop)) { 459 StoreObjByIndex(node, obj, std::get<int64_t>(prop)); 460 return; 461 } 462 463 ASSERT(std::holds_alternative<util::StringView>(prop)); 464 StoreObjByName(node, obj, std::get<util::StringView>(prop)); 465} 466 467void PandaGen::DefineOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 468{ 469 if (std::holds_alternative<VReg>(prop)) { 470 DefineFieldByValue(node, obj, std::get<VReg>(prop)); 471 return; 472 } 473 474 if (std::holds_alternative<int64_t>(prop)) { 475 DefineFieldByIndex(node, obj, std::get<int64_t>(prop)); 476 return; 477 } 478 479 ASSERT(std::holds_alternative<util::StringView>(prop)); 480 DefineFieldByName(node, obj, std::get<util::StringView>(prop)); 481} 482 483void PandaGen::DefineClassPrivateField(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg obj) 484{ 485 ra_.Emit<CallruntimeDefineprivateproperty>(node, 0, level, slot, obj); 486} 487 488void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop, bool nameSetting) 489{ 490 if (std::holds_alternative<VReg>(prop)) { 491 StOwnByValue(node, obj, std::get<VReg>(prop), nameSetting); 492 return; 493 } 494 495 if (std::holds_alternative<int64_t>(prop)) { 496 StOwnByIndex(node, obj, std::get<int64_t>(prop)); 497 return; 498 } 499 500 ASSERT(std::holds_alternative<util::StringView>(prop)); 501 StOwnByName(node, obj, std::get<util::StringView>(prop), nameSetting); 502} 503 504constexpr size_t DEBUGGER_GET_SET_ARGS_NUM = 2; 505 506void PandaGen::LoadObjByNameViaDebugger(const ir::AstNode *node, const util::StringView &name, 507 bool throwUndefinedIfHole) 508{ 509 RegScope rs(this); 510 VReg global = AllocReg(); 511 LoadConst(node, compiler::Constant::JS_GLOBAL); 512 StoreAccumulator(node, global); 513 LoadObjByName(node, global, "debuggerGetValue"); 514 VReg debuggerGetValueReg = AllocReg(); 515 StoreAccumulator(node, debuggerGetValueReg); 516 VReg variableReg = AllocReg(); 517 LoadAccumulatorString(node, name); 518 StoreAccumulator(node, variableReg); 519 VReg boolFlag = AllocReg(); 520 if (throwUndefinedIfHole) { 521 LoadConst(node, compiler::Constant::JS_TRUE); 522 } else { 523 LoadConst(node, compiler::Constant::JS_FALSE); 524 } 525 StoreAccumulator(node, boolFlag); 526 Call(node, debuggerGetValueReg, DEBUGGER_GET_SET_ARGS_NUM); 527} 528 529void PandaGen::TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name) 530{ 531 if (isDebuggerEvaluateExpressionMode()) { 532 LoadObjByNameViaDebugger(node, name, true); 533 } else { 534 ra_.Emit<Tryldglobalbyname>(node, 0, name); 535 } 536 strings_.insert(name); 537} 538 539void PandaGen::StoreObjByNameViaDebugger(const ir::AstNode *node, const util::StringView &name) 540{ 541 RegScope rs(this); 542 VReg valueReg = AllocReg(); 543 StoreAccumulator(node, valueReg); 544 VReg global = AllocReg(); 545 LoadConst(node, compiler::Constant::JS_GLOBAL); 546 StoreAccumulator(node, global); 547 LoadObjByName(node, global, "debuggerSetValue"); 548 VReg debuggerSetValueReg = AllocReg(); 549 StoreAccumulator(node, debuggerSetValueReg); 550 VReg variableReg = AllocReg(); 551 LoadAccumulatorString(node, name); 552 StoreAccumulator(node, variableReg); 553 MoveVreg(node, AllocReg(), valueReg); 554 Call(node, debuggerSetValueReg, DEBUGGER_GET_SET_ARGS_NUM); 555} 556 557void PandaGen::TryStoreGlobalByName(const ir::AstNode *node, const util::StringView &name) 558{ 559 if (isDebuggerEvaluateExpressionMode()) { 560 StoreObjByNameViaDebugger(node, name); 561 } else { 562 ra_.Emit<Trystglobalbyname>(node, 0, name); 563 } 564 strings_.insert(name); 565} 566 567void PandaGen::LoadObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) 568{ 569 LoadAccumulator(node, obj); // object is load to acc 570 ra_.Emit<Ldobjbyname>(node, 0, prop); 571 strings_.insert(prop); 572} 573 574void PandaGen::StoreObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) 575{ 576 ra_.Emit<Stobjbyname>(node, 0, prop, obj); 577 strings_.insert(prop); 578} 579 580void PandaGen::DefineFieldByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) 581{ 582 if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(), 583 Binder()->Program()->GetTargetApiSubVersion())) { 584 ra_.Emit<Definefieldbyname>(node, 0, prop, obj); 585 strings_.insert(prop); 586 return; 587 } 588 589 ra_.Emit<Definepropertybyname>(node, 0, prop, obj); 590 strings_.insert(prop); 591} 592 593void PandaGen::LoadObjByIndex(const ir::AstNode *node, VReg obj, int64_t index) 594{ 595 LoadAccumulator(node, obj); // object is load to acc 596 if (index <= util::Helpers::MAX_INT16) { 597 ra_.Emit<Ldobjbyindex>(node, 0, index); 598 return; 599 } 600 601 ra_.Emit<WideLdobjbyindex>(node, index); 602} 603 604void PandaGen::LoadObjByValue(const ir::AstNode *node, VReg obj) 605{ 606 ra_.Emit<Ldobjbyvalue>(node, 0, obj); // prop is in acc 607} 608 609void PandaGen::StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop) 610{ 611 ra_.Emit<Stobjbyvalue>(node, 0, obj, prop); 612} 613 614void PandaGen::StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index) 615{ 616 if (index <= util::Helpers::MAX_INT16) { 617 ra_.Emit<Stobjbyindex>(node, 0, obj, index); 618 return; 619 } 620 621 ra_.Emit<WideStobjbyindex>(node, obj, index); 622} 623 624void PandaGen::DefineFieldByValue(const ir::AstNode *node, VReg obj, VReg prop) 625{ 626 ra_.Emit<CallruntimeDefinefieldbyvalue>(node, 0, prop, obj); 627} 628 629void PandaGen::DefineFieldByIndex(const ir::AstNode *node, VReg obj, int64_t index) 630{ 631 ra_.Emit<CallruntimeDefinefieldbyindex>(node, 0, index, obj); 632} 633 634void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop, bool nameSetting) 635{ 636 nameSetting ? ra_.Emit<Stownbynamewithnameset>(node, 0, prop, obj) : 637 ra_.Emit<Stownbyname>(node, 0, prop, obj); 638 strings_.insert(prop); 639} 640 641void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop, bool nameSetting) 642{ 643 nameSetting ? ra_.Emit<Stownbyvaluewithnameset>(node, 0, obj, prop) : 644 ra_.Emit<Stownbyvalue>(node, 0, obj, prop); 645} 646 647void PandaGen::StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index) 648{ 649 if (index <= util::Helpers::MAX_INT16) { 650 ra_.Emit<Stownbyindex>(node, 0, obj, index); 651 return; 652 } 653 654 ra_.Emit<WideStownbyindex>(node, obj, index); 655} 656 657void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 658{ 659 if (std::holds_alternative<VReg>(prop)) { 660 LoadAccumulator(node, std::get<VReg>(prop)); 661 } else if (std::holds_alternative<int64_t>(prop)) { 662 LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop))); 663 } else { 664 ASSERT(std::holds_alternative<util::StringView>(prop)); 665 LoadAccumulatorString(node, std::get<util::StringView>(prop)); 666 } 667 668 ra_.Emit<Delobjprop>(node, obj); // property is load to acc 669} 670 671void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) 672{ 673 ra_.Emit<Lda>(node, reg); 674} 675 676void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name) 677{ 678 ra_.Emit<Ldglobalvar>(node, 0, name); 679 strings_.insert(name); 680} 681 682void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &name) 683{ 684 ra_.Emit<Stglobalvar>(node, 0, name); 685 strings_.insert(name); 686} 687 688void PandaGen::LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result) 689{ 690 VirtualLoadVar::Expand(this, node, result); 691} 692 693void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration) 694{ 695 VirtualStoreVar::Expand(this, node, result, isDeclaration); 696} 697 698void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) 699{ 700 ra_.Emit<LdaStr>(node, str); 701 strings_.insert(str); 702} 703 704void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) 705{ 706 ra_.Emit<Fldai>(node, num); 707} 708 709void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) 710{ 711 ra_.Emit<Ldai>(node, num); 712} 713 714void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) 715{ 716 ra_.Emit<Ldai>(node, static_cast<int64_t>(num)); 717} 718 719void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num) 720{ 721 ra_.Emit<Ldbigint>(node, num); 722 strings_.insert(num); 723} 724 725void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) 726{ 727 LoadConst(node, id); 728 StoreAccumulator(node, reg); 729} 730 731void PandaGen::LoadConst(const ir::AstNode *node, Constant id) 732{ 733 switch (id) { 734 case Constant::JS_HOLE: { 735 ra_.Emit<Ldhole>(node); 736 break; 737 } 738 case Constant::JS_NAN: { 739 ra_.Emit<Ldnan>(node); 740 break; 741 } 742 case Constant::JS_INFINITY: { 743 ra_.Emit<Ldinfinity>(node); 744 break; 745 } 746 case Constant::JS_GLOBAL: { 747 ra_.Emit<Ldglobal>(node); 748 break; 749 } 750 case Constant::JS_UNDEFINED: { 751 ra_.Emit<Ldundefined>(node); 752 break; 753 } 754 case Constant::JS_SYMBOL: { 755 ra_.Emit<Ldsymbol>(node); 756 break; 757 } 758 case Constant::JS_NULL: { 759 ra_.Emit<Ldnull>(node); 760 break; 761 } 762 case Constant::JS_TRUE: { 763 ra_.Emit<Ldtrue>(node); 764 break; 765 } 766 case Constant::JS_FALSE: { 767 ra_.Emit<Ldfalse>(node); 768 break; 769 } 770 default: { 771 UNREACHABLE(); 772 } 773 } 774} 775 776void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) 777{ 778 ra_.Emit<Mov>(node, vd, vs); 779} 780 781void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) 782{ 783 ra_.AddLabel(label); 784} 785 786void PandaGen::Branch(const ir::AstNode *node, Label *label) 787{ 788 ra_.Emit<Jmp>(node, label); 789} 790 791bool PandaGen::CheckControlFlowChange() const 792{ 793 const auto *iter = dynamicContext_; 794 795 while (iter) { 796 if (iter->HasFinalizer()) { 797 return true; 798 } 799 800 iter = iter->Prev(); 801 } 802 803 return false; 804} 805 806Label *PandaGen::ControlFlowChangeBreak(const ir::Identifier *label) 807{ 808 auto *iter = dynamicContext_; 809 810 util::StringView labelName = label ? label->Name() : LabelTarget::BREAK_LABEL; 811 Label *breakTarget = nullptr; 812 813 while (iter) { 814 iter->AbortContext(ControlFlowChange::BREAK, labelName); 815 816 const auto &labelTargetName = iter->Target().BreakLabel(); 817 818 if (iter->Target().BreakTarget()) { 819 breakTarget = iter->Target().BreakTarget(); 820 } 821 822 if (labelTargetName == labelName) { 823 break; 824 } 825 826 iter = iter->Prev(); 827 } 828 829 return breakTarget; 830} 831 832Label *PandaGen::ControlFlowChangeContinue(const ir::Identifier *label) 833{ 834 auto *iter = dynamicContext_; 835 util::StringView labelName = label ? label->Name() : LabelTarget::CONTINUE_LABEL; 836 Label *continueTarget = nullptr; 837 838 while (iter) { 839 iter->AbortContext(ControlFlowChange::CONTINUE, labelName); 840 841 const auto &labelTargetName = iter->Target().ContinueLabel(); 842 843 if (iter->Target().ContinueTarget()) { 844 continueTarget = iter->Target().ContinueTarget(); 845 } 846 847 if (labelTargetName == labelName) { 848 break; 849 } 850 851 iter = iter->Prev(); 852 } 853 854 return continueTarget; 855} 856 857void PandaGen::ControlFlowChangeReturn() 858{ 859 auto *iter = dynamicContext_; 860 while (iter) { 861 iter->AbortContext(ControlFlowChange::BREAK, LabelTarget::RETURN_LABEL); 862 iter = iter->Prev(); 863 } 864} 865 866void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) 867{ 868 switch (op) { 869 case lexer::TokenType::PUNCTUATOR_EQUAL: { 870 Equal(node, lhs); 871 break; 872 } 873 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { 874 NotEqual(node, lhs); 875 break; 876 } 877 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: { 878 StrictEqual(node, lhs); 879 break; 880 } 881 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { 882 StrictNotEqual(node, lhs); 883 break; 884 } 885 case lexer::TokenType::PUNCTUATOR_LESS_THAN: { 886 LessThan(node, lhs); 887 break; 888 } 889 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { 890 LessEqual(node, lhs); 891 break; 892 } 893 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { 894 GreaterThan(node, lhs); 895 break; 896 } 897 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { 898 GreaterEqual(node, lhs); 899 break; 900 } 901 default: { 902 UNREACHABLE(); 903 } 904 } 905 906 ra_.Emit<Jeqz>(node, ifFalse); 907} 908 909void PandaGen::Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand) 910{ 911 switch (op) { 912 case lexer::TokenType::PUNCTUATOR_PLUS: { 913 ToNumber(node, operand); 914 break; 915 } 916 case lexer::TokenType::PUNCTUATOR_MINUS: { 917 LoadAccumulator(node, operand); 918 ra_.Emit<Neg>(node, 0); 919 break; 920 } 921 case lexer::TokenType::PUNCTUATOR_TILDE: { 922 LoadAccumulator(node, operand); 923 ra_.Emit<Not>(node, 0); 924 break; 925 } 926 case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { 927 Negate(node); 928 break; 929 } 930 case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { 931 LoadAccumulator(node, operand); 932 ra_.Emit<Inc>(node, 0); 933 break; 934 } 935 case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { 936 LoadAccumulator(node, operand); 937 ra_.Emit<Dec>(node, 0); 938 break; 939 } 940 case lexer::TokenType::KEYW_VOID: 941 case lexer::TokenType::KEYW_DELETE: { 942 LoadConst(node, Constant::JS_UNDEFINED); 943 break; 944 } 945 default: { 946 UNREACHABLE(); 947 } 948 } 949} 950 951void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) 952{ 953 switch (op) { 954 case lexer::TokenType::PUNCTUATOR_EQUAL: { 955 Equal(node, lhs); 956 break; 957 } 958 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { 959 NotEqual(node, lhs); 960 break; 961 } 962 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: { 963 StrictEqual(node, lhs); 964 break; 965 } 966 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { 967 StrictNotEqual(node, lhs); 968 break; 969 } 970 case lexer::TokenType::PUNCTUATOR_LESS_THAN: { 971 LessThan(node, lhs); 972 break; 973 } 974 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { 975 LessEqual(node, lhs); 976 break; 977 } 978 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { 979 GreaterThan(node, lhs); 980 break; 981 } 982 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { 983 GreaterEqual(node, lhs); 984 break; 985 } 986 case lexer::TokenType::PUNCTUATOR_PLUS: 987 case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { 988 ra_.Emit<Add2>(node, 0, lhs); 989 break; 990 } 991 case lexer::TokenType::PUNCTUATOR_MINUS: 992 case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { 993 ra_.Emit<Sub2>(node, 0, lhs); 994 break; 995 } 996 case lexer::TokenType::PUNCTUATOR_MULTIPLY: 997 case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { 998 ra_.Emit<Mul2>(node, 0, lhs); 999 break; 1000 } 1001 case lexer::TokenType::PUNCTUATOR_DIVIDE: 1002 case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { 1003 ra_.Emit<Div2>(node, 0, lhs); 1004 break; 1005 } 1006 case lexer::TokenType::PUNCTUATOR_MOD: 1007 case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { 1008 ra_.Emit<Mod2>(node, 0, lhs); 1009 break; 1010 } 1011 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL: 1012 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { 1013 ra_.Emit<Exp>(node, 0, lhs); 1014 break; 1015 } 1016 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: 1017 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { 1018 ra_.Emit<Shl2>(node, 0, lhs); 1019 break; 1020 } 1021 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: 1022 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { 1023 ra_.Emit<Ashr2>(node, 0, lhs); 1024 break; 1025 } 1026 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: 1027 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { 1028 ra_.Emit<Shr2>(node, 0, lhs); 1029 break; 1030 } 1031 case lexer::TokenType::PUNCTUATOR_BITWISE_AND: 1032 case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { 1033 ra_.Emit<And2>(node, 0, lhs); 1034 break; 1035 } 1036 case lexer::TokenType::PUNCTUATOR_BITWISE_OR: 1037 case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { 1038 ra_.Emit<Or2>(node, 0, lhs); 1039 break; 1040 } 1041 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: 1042 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { 1043 ra_.Emit<Xor2>(node, 0, lhs); 1044 break; 1045 } 1046 case lexer::TokenType::KEYW_IN: { 1047 ra_.Emit<Isin>(node, 0, lhs); 1048 break; 1049 } 1050 case lexer::TokenType::KEYW_INSTANCEOF: { 1051 ra_.Emit<Instanceof>(node, 0, lhs); 1052 break; 1053 } 1054 default: { 1055 UNREACHABLE(); 1056 } 1057 } 1058} 1059 1060void PandaGen::Equal(const ir::AstNode *node, VReg lhs) 1061{ 1062 ra_.Emit<Eq>(node, 0, lhs); 1063} 1064 1065void PandaGen::NotEqual(const ir::AstNode *node, VReg lhs) 1066{ 1067 ra_.Emit<Noteq>(node, 0, lhs); 1068} 1069 1070void PandaGen::StrictEqual(const ir::AstNode *node, VReg lhs) 1071{ 1072 ra_.Emit<Stricteq>(node, 0, lhs); 1073} 1074 1075void PandaGen::StrictNotEqual(const ir::AstNode *node, VReg lhs) 1076{ 1077 ra_.Emit<Strictnoteq>(node, 0, lhs); 1078} 1079 1080void PandaGen::LessThan(const ir::AstNode *node, VReg lhs) 1081{ 1082 ra_.Emit<Less>(node, 0, lhs); 1083} 1084 1085void PandaGen::LessEqual(const ir::AstNode *node, VReg lhs) 1086{ 1087 ra_.Emit<Lesseq>(node, 0, lhs); 1088} 1089 1090void PandaGen::GreaterThan(const ir::AstNode *node, VReg lhs) 1091{ 1092 ra_.Emit<Greater>(node, 0, lhs); 1093} 1094 1095void PandaGen::GreaterEqual(const ir::AstNode *node, VReg lhs) 1096{ 1097 ra_.Emit<Greatereq>(node, 0, lhs); 1098} 1099 1100void PandaGen::IsTrue(const ir::AstNode *node) 1101{ 1102 if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(), 1103 Binder()->Program()->GetTargetApiSubVersion())) { 1104 ra_.Emit<Istrue>(node); 1105 return; 1106 } 1107 1108 ra_.Emit<CallruntimeIstrue>(node, 0); 1109} 1110 1111void PandaGen::BranchIfUndefined(const ir::AstNode *node, Label *target) 1112{ 1113 RegScope rs(this); 1114 VReg tmp = AllocReg(); 1115 StoreAccumulator(node, tmp); 1116 LoadConst(node, Constant::JS_UNDEFINED); 1117 Equal(node, tmp); 1118 ra_.Emit<Jnez>(node, target); 1119} 1120 1121void PandaGen::BranchIfStrictUndefined(const ir::AstNode *node, class Label *target) 1122{ 1123 RegScope rs(this); 1124 VReg tmp = AllocReg(); 1125 StoreAccumulator(node, tmp); 1126 LoadConst(node, Constant::JS_UNDEFINED); 1127 StrictEqual(node, tmp); 1128 ra_.Emit<Jnez>(node, target); 1129} 1130 1131void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target) 1132{ 1133 RegScope rs(this); 1134 VReg tmp = AllocReg(); 1135 StoreAccumulator(node, tmp); 1136 LoadConst(node, Constant::JS_UNDEFINED); 1137 Equal(node, tmp); 1138 ra_.Emit<Jeqz>(node, target); 1139} 1140 1141void PandaGen::BranchIfStrictNotUndefined(const ir::AstNode *node, class Label *target) 1142{ 1143 RegScope rs(this); 1144 VReg tmp = AllocReg(); 1145 StoreAccumulator(node, tmp); 1146 LoadConst(node, Constant::JS_UNDEFINED); 1147 StrictEqual(node, tmp); 1148 ra_.Emit<Jeqz>(node, target); 1149} 1150 1151void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target) 1152{ 1153 IsTrue(node); 1154 ra_.Emit<Jnez>(node, target); 1155} 1156 1157void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) 1158{ 1159 IsTrue(node); 1160 BranchIfFalse(node, target); 1161} 1162 1163void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target) 1164{ 1165 if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(), 1166 Binder()->Program()->GetTargetApiSubVersion())) { 1167 ra_.Emit<Isfalse>(node); 1168 ra_.Emit<Jnez>(node, target); 1169 return; 1170 } 1171 1172 ra_.Emit<CallruntimeIsfalse>(node, 0); 1173 ra_.Emit<Jnez>(node, target); 1174} 1175 1176void PandaGen::BranchIfStrictNull(const ir::AstNode *node, class Label *target) 1177{ 1178 RegScope rs(this); 1179 VReg tmp = AllocReg(); 1180 StoreAccumulator(node, tmp); 1181 LoadConst(node, Constant::JS_NULL); 1182 ra_.Emit<Stricteq>(node, 0, tmp); 1183 ra_.Emit<Jnez>(node, target); 1184} 1185 1186void PandaGen::EmitThrow(const ir::AstNode *node) 1187{ 1188 ra_.Emit<Throw>(node); 1189} 1190 1191void PandaGen::EmitRethrow(const ir::AstNode *node) 1192{ 1193 RegScope rs(this); 1194 auto *skipThrow = AllocLabel(); 1195 auto *doThrow = AllocLabel(); 1196 1197 VReg exception = AllocReg(); 1198 StoreAccumulator(node, exception); 1199 1200 VReg hole = AllocReg(); 1201 StoreConst(node, hole, Constant::JS_HOLE); 1202 1203 LoadAccumulator(node, exception); 1204 NotEqual(node, hole); 1205 ra_.Emit<Jeqz>(node, skipThrow); 1206 1207 SetLabel(node, doThrow); 1208 LoadAccumulator(node, exception); 1209 EmitThrow(node); 1210 1211 SetLabel(node, skipThrow); 1212} 1213 1214void PandaGen::EmitReturn(const ir::AstNode *node) 1215{ 1216 ra_.Emit<Return>(node); 1217} 1218 1219void PandaGen::EmitReturnUndefined(const ir::AstNode *node) 1220{ 1221 ra_.Emit<Returnundefined>(node); 1222} 1223 1224void PandaGen::ImplicitReturn(const ir::AstNode *node) 1225{ 1226 builder_->ImplicitReturn(node); 1227} 1228 1229void PandaGen::DirectReturn(const ir::AstNode *node) 1230{ 1231 builder_->DirectReturn(node); 1232} 1233 1234void PandaGen::ExplicitReturn(const ir::AstNode *node) 1235{ 1236 builder_->ExplicitReturn(node); 1237} 1238 1239void PandaGen::ValidateClassDirectReturn(const ir::AstNode *node) 1240{ 1241 const ir::ScriptFunction *func = util::Helpers::GetContainingFunction(node); 1242 1243 if (!func || !func->IsConstructor()) { 1244 return; 1245 } 1246 1247 RegScope rs(this); 1248 VReg value = AllocReg(); 1249 StoreAccumulator(node, value); 1250 1251 auto *notUndefined = AllocLabel(); 1252 auto *condEnd = AllocLabel(); 1253 1254 BranchIfStrictNotUndefined(node, notUndefined); 1255 GetThis(func); 1256 ThrowIfSuperNotCorrectCall(func, 0); 1257 Branch(node, condEnd); 1258 1259 SetLabel(node, notUndefined); 1260 LoadAccumulator(node, value); 1261 1262 SetLabel(node, condEnd); 1263} 1264 1265void PandaGen::EmitAwait(const ir::AstNode *node) 1266{ 1267 builder_->Await(node); 1268} 1269 1270void PandaGen::CallThis(const ir::AstNode *node, VReg startReg, size_t argCount) 1271{ 1272 LoadAccumulator(node, startReg); // callee is load to acc 1273 VReg thisReg = startReg + 1; // This dependency is used in other places, do not modify. 1274 switch (argCount) { 1275 case 1: { // no args 1276 ra_.Emit<Callthis0>(node, 0, thisReg); 1277 break; 1278 } 1279 case 2: { // 1 arg 1280 VReg arg0 = thisReg + 1; 1281 ra_.Emit<Callthis1>(node, 0, thisReg, arg0); 1282 break; 1283 } 1284 case 3: { // 2 args 1285 VReg arg0 = thisReg + 1; 1286 VReg arg1 = arg0 + 1; 1287 ra_.Emit<Callthis2>(node, 0, thisReg, arg0, arg1); 1288 break; 1289 } 1290 case 4: { // 3 args 1291 VReg arg0 = thisReg + 1; 1292 VReg arg1 = arg0 + 1; 1293 VReg arg2 = arg1 + 1; 1294 ra_.Emit<Callthis3>(node, 0, thisReg, arg0, arg1, arg2); 1295 break; 1296 } 1297 default: { 1298 int64_t actualArgs = static_cast<int64_t>(argCount) - 1; 1299 if (actualArgs <= util::Helpers::MAX_INT8) { 1300 ra_.EmitRange<Callthisrange>(node, argCount, 0, actualArgs, thisReg); 1301 break; 1302 } 1303 1304 ra_.EmitRange<WideCallthisrange>(node, argCount, actualArgs, thisReg); 1305 break; 1306 } 1307 } 1308} 1309 1310void PandaGen::Call(const ir::AstNode *node, VReg startReg, size_t argCount) 1311{ 1312 LoadAccumulator(node, startReg); // callee is load to acc 1313 switch (argCount) { 1314 case 0: { // 0 args 1315 ra_.Emit<Callarg0>(node, 0); 1316 break; 1317 } 1318 case 1: { // 1 arg 1319 VReg arg0 = startReg + 1; 1320 ra_.Emit<Callarg1>(node, 0, arg0); 1321 break; 1322 } 1323 case 2: { // 2 args 1324 VReg arg0 = startReg + 1; 1325 VReg arg1 = arg0 + 1; 1326 ra_.Emit<Callargs2>(node, 0, arg0, arg1); 1327 break; 1328 } 1329 case 3: { // 3 args 1330 VReg arg0 = startReg + 1; 1331 VReg arg1 = arg0 + 1; 1332 VReg arg2 = arg1 + 1; 1333 ra_.Emit<Callargs3>(node, 0, arg0, arg1, arg2); 1334 break; 1335 } 1336 default: { 1337 VReg arg0 = startReg + 1; 1338 if (argCount <= util::Helpers::MAX_INT8) { 1339 ra_.EmitRange<Callrange>(node, argCount, 0, argCount, arg0); 1340 break; 1341 } 1342 1343 ra_.EmitRange<WideCallrange>(node, argCount, argCount, arg0); 1344 break; 1345 } 1346 } 1347} 1348 1349void PandaGen::SuperCall(const ir::AstNode *node, VReg startReg, size_t argCount) 1350{ 1351 if (RootNode()->AsScriptFunction()->IsArrow()) { 1352 GetFunctionObject(node); // load funcobj to acc for super call in arrow function 1353 if (argCount <= util::Helpers::MAX_INT8) { 1354 ra_.EmitRange<Supercallarrowrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg); 1355 } else { 1356 ra_.EmitRange<WideSupercallarrowrange>(node, argCount, static_cast<int64_t>(argCount), startReg); 1357 } 1358 return; 1359 } 1360 1361 if (argCount <= util::Helpers::MAX_INT8) { 1362 // no need to load funcobj to acc for super call in other kinds of functions 1363 ra_.EmitRange<Supercallthisrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg); 1364 return; 1365 } 1366 1367 ra_.EmitRange<WideSupercallthisrange>(node, argCount, static_cast<int64_t>(argCount), startReg); 1368} 1369 1370void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs) 1371{ 1372 ra_.Emit<Supercallspread>(node, 0, vs); 1373} 1374 1375void PandaGen::SuperCallForwardAllArgs(const ir::AstNode *node, VReg funcObj) 1376{ 1377 ra_.Emit<CallruntimeSupercallforwardallargs>(node, funcObj); 1378} 1379 1380void PandaGen::NotifyConcurrentResult(const ir::AstNode *node) 1381{ 1382 if (IsConcurrent()) { 1383 ra_.Emit<CallruntimeNotifyconcurrentresult>(node); 1384 } 1385} 1386 1387void PandaGen::CallInit(const ir::AstNode *node, VReg thisReg) 1388{ 1389 // callee is in acc 1390 ra_.Emit<CallruntimeCallinit>(node, 0, thisReg); 1391} 1392 1393void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount) 1394{ 1395 if (argCount <= util::Helpers::MAX_INT8) { 1396 ra_.EmitRange<Newobjrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg); 1397 return; 1398 } 1399 1400 ra_.EmitRange<WideNewobjrange>(node, argCount, static_cast<int64_t>(argCount), startReg); 1401} 1402 1403void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) 1404{ 1405 if (realNode->IsOverload() || realNode->Declare()) { 1406 return; 1407 } 1408 1409 auto formalParamCnt = realNode->FormalParamsLength(); 1410 if (realNode->IsMethod()) { 1411 ra_.Emit<Definemethod>(node, 0, name, static_cast<int64_t>(formalParamCnt)); 1412 } else { 1413 ra_.Emit<Definefunc>(node, 0, name, static_cast<int64_t>(formalParamCnt)); 1414 } 1415 1416 strings_.insert(name); 1417} 1418 1419void PandaGen::TypeOf(const ir::AstNode *node) 1420{ 1421 ra_.Emit<Typeof>(node, 0); 1422} 1423 1424void PandaGen::CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args) 1425{ 1426 LoadAccumulator(node, func); // callee is load to acc 1427 ra_.Emit<Apply>(node, 0, thisReg, args); 1428} 1429 1430void PandaGen::NewObjSpread(const ir::AstNode *node, VReg obj) 1431{ 1432 ra_.Emit<Newobjapply>(node, 0, obj); 1433} 1434 1435void PandaGen::GetUnmappedArgs(const ir::AstNode *node) 1436{ 1437 ra_.Emit<Getunmappedargs>(node); 1438} 1439 1440void PandaGen::Negate(const ir::AstNode *node) 1441{ 1442 auto *falseLabel = AllocLabel(); 1443 auto *endLabel = AllocLabel(); 1444 BranchIfTrue(node, falseLabel); 1445 LoadConst(node, Constant::JS_TRUE); 1446 Branch(node, endLabel); 1447 SetLabel(node, falseLabel); 1448 LoadConst(node, Constant::JS_FALSE); 1449 SetLabel(node, endLabel); 1450} 1451 1452void PandaGen::ToNumber(const ir::AstNode *node, VReg arg) 1453{ 1454 LoadAccumulator(node, arg); 1455 ra_.Emit<Tonumber>(node, 0); 1456} 1457 1458void PandaGen::ToNumeric(const ir::AstNode *node, VReg arg) 1459{ 1460 LoadAccumulator(node, arg); 1461 ra_.Emit<Tonumeric>(node, 0); 1462} 1463 1464void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj) 1465{ 1466 ra_.Emit<Creategeneratorobj>(node, funcObj); 1467} 1468 1469void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj) 1470{ 1471 ra_.Emit<Createasyncgeneratorobj>(node, funcObj); 1472} 1473 1474void PandaGen::CreateIterResultObject(const ir::AstNode *node, VReg value, VReg done) 1475{ 1476 ra_.Emit<Createiterresultobj>(node, value, done); 1477} 1478 1479void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj) 1480{ 1481 ra_.Emit<Suspendgenerator>(node, genObj); // iterResult is in acc 1482} 1483 1484void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj) 1485{ 1486 LoadAccumulator(node, genObj); 1487 ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::SUSPENDED_YIELD)); 1488} 1489 1490void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj) 1491{ 1492 LoadAccumulator(node, genObj); 1493 ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::COMPLETED)); 1494} 1495 1496void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj) 1497{ 1498 LoadAccumulator(node, genObj); 1499 ra_.Emit<Resumegenerator>(node); 1500} 1501 1502void PandaGen::GetResumeMode(const ir::AstNode *node, VReg genObj) 1503{ 1504 LoadAccumulator(node, genObj); 1505 ra_.Emit<Getresumemode>(node); 1506} 1507 1508void PandaGen::AsyncFunctionEnter(const ir::AstNode *node) 1509{ 1510 ra_.Emit<Asyncfunctionenter>(node); 1511} 1512 1513void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj) 1514{ 1515 ra_.Emit<Asyncfunctionawaituncaught>(node, asyncFuncObj); // receivedValue is in acc 1516} 1517 1518void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj) 1519{ 1520 ra_.Emit<Asyncfunctionresolve>(node, asyncFuncObj); // use retVal in acc 1521} 1522 1523void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj) 1524{ 1525 ra_.Emit<Asyncfunctionreject>(node, asyncFuncObj); // exception is in acc 1526} 1527 1528void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj, VReg value, VReg canSuspend) 1529{ 1530 ra_.Emit<Asyncgeneratorresolve>(node, asyncGenObj, value, canSuspend); 1531} 1532 1533void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj) 1534{ 1535 ra_.Emit<Asyncgeneratorreject>(node, asyncGenObj); // value is in acc 1536} 1537 1538void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value) 1539{ 1540 LoadAccumulator(node, value); 1541 ra_.Emit<Gettemplateobject>(node, 0); 1542} 1543 1544void PandaGen::CopyRestArgs(const ir::AstNode *node, uint32_t index) 1545{ 1546 index <= util::Helpers::MAX_INT8 ? ra_.Emit<Copyrestargs>(node, index) : ra_.Emit<WideCopyrestargs>(node, index); 1547} 1548 1549void PandaGen::GetPropIterator(const ir::AstNode *node) 1550{ 1551 ra_.Emit<Getpropiterator>(node); 1552} 1553 1554void PandaGen::GetNextPropName(const ir::AstNode *node, VReg iter) 1555{ 1556 ra_.Emit<Getnextpropname>(node, iter); 1557} 1558 1559void PandaGen::CreateEmptyObject(const ir::AstNode *node) 1560{ 1561 ra_.Emit<Createemptyobject>(node); 1562} 1563 1564void PandaGen::CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx) 1565{ 1566 ASSERT(util::Helpers::IsInteger<uint32_t>(idx)); 1567 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx); 1568 util::UString litId(idxStr, allocator_); 1569 ra_.Emit<Createobjectwithbuffer>(node, 0, litId.View()); 1570} 1571 1572void PandaGen::SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj) 1573{ 1574 LoadAccumulator(node, obj); 1575 ra_.Emit<Setobjectwithproto>(node, 0, proto); 1576} 1577 1578void PandaGen::CopyDataProperties(const ir::AstNode *node, VReg dst) 1579{ 1580 ra_.Emit<Copydataproperties>(node, dst); // use acc as srcObj 1581} 1582 1583void PandaGen::DefineGetterSetterByValue(const ir::AstNode *node, VReg obj, VReg name, VReg getter, VReg setter, 1584 bool setName) 1585{ 1586 LoadConst(node, setName ? Constant::JS_TRUE : Constant::JS_FALSE); 1587 ra_.Emit<Definegettersetterbyvalue>(node, obj, name, getter, setter); 1588} 1589 1590void PandaGen::CreateEmptyArray(const ir::AstNode *node) 1591{ 1592 ra_.Emit<Createemptyarray>(node, 0); 1593} 1594 1595void PandaGen::CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx) 1596{ 1597 ASSERT(util::Helpers::IsInteger<uint32_t>(idx)); 1598 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx); 1599 util::UString litId(idxStr, allocator_); 1600 ra_.Emit<Createarraywithbuffer>(node, 0, litId.View()); 1601} 1602 1603void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector<ir::Expression *> &elements, VReg obj) 1604{ 1605 if (elements.empty()) { 1606 CreateEmptyArray(node); 1607 StoreAccumulator(node, obj); 1608 return; 1609 } 1610 1611 auto *buf = NewLiteralBuffer(); 1612 1613 size_t i = 0; 1614 // This loop handles constant literal data by collecting it into a literal buffer 1615 // until a non-constant element is encountered. 1616 while (i < elements.size() && util::Helpers::IsConstantExpr(elements[i])) { 1617 buf->Add(elements[i]->AsLiteral()); 1618 i++; 1619 } 1620 1621 if (buf->IsEmpty()) { 1622 CreateEmptyArray(node); 1623 } else { 1624 uint32_t bufIdx = static_cast<uint32_t>(AddLiteralBuffer(buf)); 1625 CreateArrayWithBuffer(node, bufIdx); 1626 } 1627 1628 StoreAccumulator(node, obj); 1629 1630 if (i == elements.size()) { 1631 return; 1632 } 1633 1634 bool hasSpread = false; 1635 1636 // This loop handles array elements until a spread element is encountered 1637 for (; i < elements.size(); i++) { 1638 const ir::Expression *elem = elements[i]; 1639 1640 if (elem->IsOmittedExpression()) { 1641 continue; 1642 } 1643 1644 if (elem->IsSpreadElement()) { 1645 // The next loop will handle arrays that have a spread element 1646 hasSpread = true; 1647 break; 1648 } 1649 1650 elem->Compile(this); 1651 StOwnByIndex(elem, obj, i); 1652 } 1653 1654 RegScope rs(this); 1655 VReg idxReg {}; 1656 1657 if (hasSpread) { 1658 idxReg = AllocReg(); 1659 LoadAccumulatorInt(node, i); 1660 StoreAccumulator(node, idxReg); 1661 } 1662 1663 // This loop handles arrays that contain spread elements 1664 for (; i < elements.size(); i++) { 1665 const ir::Expression *elem = elements[i]; 1666 1667 if (elem->IsSpreadElement()) { 1668 elem->AsSpreadElement()->Argument()->Compile(this); 1669 1670 StoreArraySpread(elem, obj, idxReg); 1671 1672 LoadObjByName(node, obj, "length"); 1673 StoreAccumulator(elem, idxReg); 1674 continue; 1675 } 1676 1677 if (!elem->IsOmittedExpression()) { 1678 elem->Compile(this); 1679 StOwnByValue(elem, obj, idxReg); 1680 } 1681 1682 Unary(elem, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, idxReg); 1683 StoreAccumulator(elem, idxReg); 1684 } 1685 1686 // If the last element is omitted, we also have to update the length property 1687 if (elements.back()->IsOmittedExpression()) { 1688 // if there was a spread value then acc already contains the length 1689 if (!hasSpread) { 1690 LoadAccumulatorInt(node, i); 1691 } 1692 1693 StOwnByName(node, obj, "length"); 1694 } 1695 1696 LoadAccumulator(node, obj); 1697} 1698 1699void PandaGen::StoreArraySpread(const ir::AstNode *node, VReg array, VReg index) 1700{ 1701 ra_.Emit<Starrayspread>(node, array, index); 1702} 1703 1704void PandaGen::ThrowIfNotObject(const ir::AstNode *node, VReg obj) 1705{ 1706 ra_.Emit<ThrowIfnotobject>(node, obj); 1707} 1708 1709void PandaGen::ThrowThrowNotExist(const ir::AstNode *node) 1710{ 1711 ra_.Emit<ThrowNotexists>(node); 1712} 1713 1714void PandaGen::GetIterator(const ir::AstNode *node) 1715{ 1716 ra_.Emit<Getiterator>(node, 0); 1717} 1718 1719void PandaGen::GetAsyncIterator(const ir::AstNode *node) 1720{ 1721 ra_.Emit<Getasynciterator>(node, 0); 1722} 1723 1724void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) 1725{ 1726 ASSERT(argStart == obj + 1); 1727 if (argCount == 0) { 1728 LoadConst(node, Constant::JS_UNDEFINED); 1729 StoreAccumulator(node, argStart); 1730 } 1731 1732 size_t argRegCnt = (argCount == 0 ? argCount : argCount - 1); 1733 1734 if (argRegCnt <= util::Helpers::MAX_INT8) { 1735 ra_.EmitRange<Createobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart); 1736 return; 1737 } 1738 1739 ra_.EmitRange<WideCreateobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart); 1740} 1741 1742void PandaGen::ThrowObjectNonCoercible(const ir::AstNode *node) 1743{ 1744 ra_.Emit<ThrowPatternnoncoercible>(node); 1745} 1746 1747void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter) 1748{ 1749 ra_.Emit<Closeiterator>(node, 0, iter); 1750} 1751 1752void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base) 1753{ 1754 auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength(); 1755 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx); 1756 util::UString litId(idxStr, allocator_); 1757 ra_.Emit<Defineclasswithbuffer>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base); 1758 strings_.insert(ctorId); 1759} 1760 1761void PandaGen::DefineSendableClass(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base) 1762{ 1763 auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength(); 1764 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx); 1765 util::UString litId(idxStr, allocator_); 1766 ra_.Emit<CallruntimeDefinesendableclass>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base); 1767 strings_.insert(ctorId); 1768} 1769 1770void PandaGen::LoadSendableClass(const ir::AstNode *node, int32_t level) 1771{ 1772 ra_.Emit<CallruntimeLdsendableclass>(node, level); 1773} 1774 1775void PandaGen::LoadLocalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable) 1776{ 1777 auto index = variable->Index(); 1778 index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldlocalmodulevar>(node, index) : 1779 ra_.Emit<WideLdlocalmodulevar>(node, index); 1780} 1781 1782void PandaGen::LoadExternalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable) 1783{ 1784 auto index = variable->Index(); 1785 1786 auto targetApiVersion = Binder()->Program()->TargetApiVersion(); 1787 bool isLazy = variable->Declaration()->Node()->IsImportSpecifier() ? 1788 variable->Declaration()->Node()->AsImportSpecifier()->IsLazy() : false; 1789 if (isLazy) { 1790 // Change the behavior of using imported object in sendable class since api12 1791 if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) { 1792 index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazysendablemodulevar>(node, index) : 1793 ra_.Emit<CallruntimeWideldlazysendablemodulevar>(node, index); 1794 return; 1795 } 1796 1797 index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazymodulevar>(node, index) : 1798 ra_.Emit<CallruntimeWideldlazymodulevar>(node, index); 1799 return; 1800 } 1801 1802 // Change the behavior of using imported object in sendable class since api12 1803 if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) { 1804 index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdsendableexternalmodulevar>(node, index) : 1805 ra_.Emit<CallruntimeWideldsendableexternalmodulevar>(node, index); 1806 return; 1807 } 1808 1809 index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldexternalmodulevar>(node, index) : 1810 ra_.Emit<WideLdexternalmodulevar>(node, index); 1811} 1812 1813void PandaGen::StoreModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable) 1814{ 1815 auto index = variable->Index(); 1816 index <= util::Helpers::MAX_INT8 ? ra_.Emit<Stmodulevar>(node, index) : 1817 ra_.Emit<WideStmodulevar>(node, index); 1818} 1819 1820void PandaGen::GetModuleNamespace(const ir::AstNode *node, uint32_t index) 1821{ 1822 index <= util::Helpers::MAX_INT8 ? ra_.Emit<Getmodulenamespace>(node, index) : 1823 ra_.Emit<WideGetmodulenamespace>(node, index); 1824} 1825 1826void PandaGen::DynamicImportCall(const ir::AstNode *node) 1827{ 1828 ra_.Emit<Dynamicimport>(node); 1829} 1830 1831void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) 1832{ 1833 ra_.Emit<Stsuperbyname>(node, 0, key, obj); 1834 strings_.insert(key); 1835} 1836 1837void PandaGen::LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) 1838{ 1839 LoadAccumulator(node, obj); // object is load to acc 1840 ra_.Emit<Ldsuperbyname>(node, 0, key); 1841 strings_.insert(key); 1842} 1843 1844void PandaGen::StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop) 1845{ 1846 ra_.Emit<Stsuperbyvalue>(node, 0, obj, prop); 1847} 1848 1849void PandaGen::LdSuperByValue(const ir::AstNode *node, VReg obj) 1850{ 1851 ra_.Emit<Ldsuperbyvalue>(node, 0, obj); // prop is in acc 1852} 1853 1854void PandaGen::StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 1855{ 1856 if (std::holds_alternative<util::StringView>(prop)) { 1857 StSuperByName(node, obj, std::get<util::StringView>(prop)); 1858 return; 1859 } 1860 1861 if (std::holds_alternative<VReg>(prop)) { 1862 StSuperByValue(node, obj, std::get<VReg>(prop)); 1863 return; 1864 } 1865 1866 ASSERT(std::holds_alternative<int64_t>(prop)); 1867 RegScope rs(this); 1868 VReg property = AllocReg(); 1869 VReg value = AllocReg(); 1870 1871 StoreAccumulator(node, value); 1872 LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop))); 1873 StoreAccumulator(node, property); 1874 LoadAccumulator(node, value); 1875 StSuperByValue(node, obj, property); 1876} 1877 1878void PandaGen::LoadSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop) 1879{ 1880 if (std::holds_alternative<util::StringView>(prop)) { 1881 LdSuperByName(node, obj, std::get<util::StringView>(prop)); 1882 return; 1883 } 1884 1885 if (std::holds_alternative<VReg>(prop)) { 1886 LoadAccumulator(node, std::get<VReg>(prop)); 1887 LdSuperByValue(node, obj); 1888 return; 1889 } 1890 1891 ASSERT(std::holds_alternative<int64_t>(prop)); 1892 1893 LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop))); 1894 LdSuperByValue(node, obj); 1895} 1896 1897void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) 1898{ 1899 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1900 ra_.Emit<WideLdlexvar>(node, level, slot); 1901 return; 1902 } 1903 1904 ra_.Emit<Ldlexvar>(node, level, slot); 1905} 1906 1907void PandaGen::LoadSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot) 1908{ 1909 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1910 ra_.Emit<CallruntimeWideldsendablevar>(node, level, slot); 1911 return; 1912 } 1913 1914 ra_.Emit<CallruntimeLdsendablevar>(node, level, slot); 1915} 1916 1917void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, const util::StringView &name) 1918{ 1919 if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) { 1920 uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(name)); 1921 ra_.Emit<WideLdpatchvar>(node, patchSlot); 1922 return; 1923 } 1924 1925 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1926 ra_.Emit<WideLdlexvar>(node, level, slot); 1927 return; 1928 } 1929 1930 ra_.Emit<Ldlexvar>(node, level, slot); 1931} 1932 1933void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) 1934{ 1935 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1936 ra_.Emit<WideStlexvar>(node, level, slot); 1937 return; 1938 } 1939 1940 ra_.Emit<Stlexvar>(node, level, slot); 1941} 1942 1943void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg value) 1944{ 1945 LoadAccumulator(node, value); 1946 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1947 ra_.Emit<WideStlexvar>(node, level, slot); 1948 return; 1949 } 1950 1951 ra_.Emit<Stlexvar>(node, level, slot); 1952} 1953 1954void PandaGen::StoreSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot) 1955{ 1956 if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) { 1957 ra_.Emit<CallruntimeWidestsendablevar>(node, level, slot); 1958 return; 1959 } 1960 1961 ra_.Emit<CallruntimeStsendablevar>(node, level, slot); 1962} 1963 1964void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, 1965 const binder::LocalVariable *local) 1966{ 1967 if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) { 1968 uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(local->Name())); 1969 ra_.Emit<WideStpatchvar>(node, patchSlot); 1970 return; 1971 } 1972 RegScope rs(this); 1973 VReg value = AllocReg(); 1974 StoreAccumulator(node, value); 1975 StoreLexicalVar(node, level, slot, value); 1976} 1977 1978void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num) 1979{ 1980 ra_.Emit<ThrowIfsupernotcorrectcall>(node, num); 1981} 1982 1983void PandaGen::ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name) 1984{ 1985 ra_.Emit<ThrowUndefinedifholewithname>(node, name); 1986 strings_.insert(name); 1987} 1988 1989void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name) 1990{ 1991 RegScope rs(this); 1992 LoadAccumulatorString(node, name); 1993 VReg nameReg = AllocReg(); 1994 StoreAccumulator(node, nameReg); 1995 ra_.Emit<ThrowConstassignment>(node, nameReg); 1996 strings_.insert(name); 1997} 1998 1999void PandaGen::PopLexEnv(const ir::AstNode *node) 2000{ 2001 ra_.Emit<Poplexenv>(node); 2002} 2003 2004void PandaGen::GenDebugger(const ir::AstNode *node) 2005{ 2006 if (IsDebug()) { 2007 ra_.Emit<Debugger>(node); 2008 } 2009} 2010 2011void PandaGen::NewLexicalEnv(const ir::AstNode *node, uint32_t num, binder::VariableScope *scope) 2012{ 2013 if (IsDebug()) { 2014 int32_t scopeInfoIdx = AddLexicalVarNamesForDebugInfo(scope->GetLexicalVarNameAndTypes()); 2015 NewLexEnvWithScopeInfo(node, num, scopeInfoIdx); 2016 return; 2017 } 2018 2019 NewLexEnv(node, num); 2020} 2021 2022void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num) 2023{ 2024 num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenv>(node, num) : ra_.Emit<WideNewlexenv>(node, num); 2025} 2026 2027void PandaGen::NewSendableEnv(const ir::AstNode * node, uint32_t num) 2028{ 2029 num <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeNewsendableenv>(node, num) : 2030 ra_.Emit<CallruntimeWidenewsendableenv>(node, num); 2031} 2032 2033void PandaGen::NewLexEnvWithScopeInfo(const ir::AstNode *node, uint32_t num, int32_t scopeInfoIdx) 2034{ 2035 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(scopeInfoIdx); 2036 util::UString litId(idxStr, allocator_); 2037 num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenvwithname>(node, num, litId.View()) : 2038 ra_.Emit<WideNewlexenvwithname>(node, num, litId.View()); 2039} 2040 2041uint32_t PandaGen::TryDepth() const 2042{ 2043 const auto *iter = dynamicContext_; 2044 uint32_t depth = 0; 2045 2046 while (iter) { 2047 if (iter->HasTryCatch()) { 2048 depth++; 2049 } 2050 2051 iter = iter->Prev(); 2052 } 2053 2054 return depth; 2055} 2056 2057CatchTable *PandaGen::CreateCatchTable() 2058{ 2059 auto *catchTable = allocator_->New<CatchTable>(this, TryDepth()); 2060 CHECK_NOT_NULL(catchTable); 2061 catchList_.push_back(catchTable); 2062 return catchTable; 2063} 2064 2065void PandaGen::SortCatchTables() 2066{ 2067 std::sort(catchList_.begin(), catchList_.end(), 2068 [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); 2069} 2070 2071Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed) 2072{ 2073 VReg res {0}; 2074 2075 if (isComputed) { 2076 return res; 2077 } 2078 2079 if (prop->IsIdentifier()) { 2080 return prop->AsIdentifier()->Name(); 2081 } 2082 2083 if (prop->IsStringLiteral()) { 2084 const util::StringView &str = prop->AsStringLiteral()->Str(); 2085 2086 // remove this when runtime handles __proto__ as property name correctly 2087 if (str.Is("__proto__")) { 2088 return res; 2089 } 2090 2091 int64_t index = util::Helpers::GetIndex(str); 2092 if (index != util::Helpers::INVALID_INDEX) { 2093 return index; 2094 } 2095 2096 return str; 2097 } 2098 2099 if (prop->IsNumberLiteral()) { 2100 auto num = prop->AsNumberLiteral()->Number<double>(); 2101 if (util::Helpers::IsIndex(num)) { 2102 return static_cast<int64_t>(num); 2103 } 2104 2105 return util::Helpers::ToStringView(allocator_, num); 2106 } 2107 2108 return res; 2109} 2110 2111Operand PandaGen::ToPropertyKey(const ir::Expression *prop, bool isComputed) 2112{ 2113 Operand op = ToNamedPropertyKey(prop, isComputed); 2114 if (std::holds_alternative<util::StringView>(op) || (std::holds_alternative<int64_t>(op) && 2115 (std::get<int64_t>(op) <= util::Helpers::MAX_INT32))) { 2116 return op; 2117 } 2118 2119 VReg propReg = AllocReg(); 2120 2121 /** 2122 * Store index to vreg when index > MAX_INT32 to simplify ASM interpreter If byindex-related instructions support 2123 * index > MAX_INT32, ASM interpreter will have to add a judgment whether index needs more than 32 bits which will 2124 * cause inefficiency of it since cases when index > MAX_INT32 can be quite rare 2125 **/ 2126 if (std::holds_alternative<int64_t>(op) && (std::get<int64_t>(op) > util::Helpers::MAX_INT32)) { 2127 LoadAccumulatorFloat(prop, std::get<int64_t>(op)); 2128 StoreAccumulator(prop, propReg); 2129 return propReg; 2130 } 2131 2132 ASSERT(std::holds_alternative<VReg>(op)); 2133 prop->Compile(this); 2134 StoreAccumulator(prop, propReg); 2135 2136 return propReg; 2137} 2138 2139VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed) 2140{ 2141 Operand op = ToNamedPropertyKey(prop, isComputed); 2142 if (std::holds_alternative<util::StringView>(op)) { 2143 LoadAccumulatorString(prop, std::get<util::StringView>(op)); 2144 } else if (std::holds_alternative<int64_t>(op)) { 2145 LoadAccumulatorInt(prop, static_cast<size_t>(std::get<int64_t>(op))); 2146 } else { 2147 prop->Compile(this); 2148 } 2149 2150 VReg propReg = AllocReg(); 2151 StoreAccumulator(prop, propReg); 2152 2153 return propReg; 2154} 2155 2156void PandaGen::ToComputedPropertyKey(const ir::AstNode *node) 2157{ 2158 ra_.Emit<CallruntimeTopropertykey>(node); 2159} 2160 2161void PandaGen::StLetOrClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name) 2162{ 2163 ra_.Emit<Sttoglobalrecord>(node, 0, name); 2164 strings_.insert(name); 2165} 2166 2167void PandaGen::StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name) 2168{ 2169 ra_.Emit<Stconsttoglobalrecord>(node, 0, name); 2170 strings_.insert(name); 2171} 2172 2173bool PandaGen::TryCompileFunctionCallOrNewExpression(const ir::Expression *expr) 2174{ 2175 ASSERT(expr->IsCallExpression() || expr->IsNewExpression()); 2176 const auto *callee = expr->IsCallExpression() ? expr->AsCallExpression()->Callee() : 2177 expr->AsNewExpression()->Callee(); 2178 2179 if (!callee->IsIdentifier()) { 2180 return false; 2181 } 2182 2183 if (callee->AsIdentifier()->Name().Is("Function")) { 2184 auto arguments = expr->IsCallExpression() ? expr->AsCallExpression()->Arguments() : 2185 expr->AsNewExpression()->Arguments(); 2186 if (arguments.empty()) { 2187 return false; 2188 } 2189 2190 auto *arg = arguments[arguments.size() - 1]; 2191 if (!arg->IsStringLiteral()) { 2192 return false; 2193 } 2194 2195 if (std::regex_match(arg->AsStringLiteral()->Str().Mutf8(), std::regex(" *return +this[;]? *$"))) { 2196 LoadConst(arg, Constant::JS_GLOBAL); 2197 return true; 2198 } 2199 } 2200 2201 return false; 2202} 2203 2204void PandaGen::ReArrangeIc() 2205{ 2206 if (!IsIcOverFlow()) { 2207 return; 2208 } 2209 2210 ResetCurrentSlot(0); 2211 2212 for (auto *ins: Insns()) { 2213 if (!ins->InlineCacheEnabled()) { 2214 continue; 2215 } 2216 2217 if (ins->oneByteSlotOnly()) { 2218 auto inc = ins->SetIcSlot(GetCurrentSlot()); 2219 IncreaseCurrentSlot(inc); 2220 } 2221 } 2222 2223 for (auto *ins: Insns()) { 2224 if (!ins->InlineCacheEnabled()) { 2225 continue; 2226 } 2227 2228 if (ins->oneByteSlotOnly()) { 2229 continue; 2230 } 2231 2232 auto inc = ins->SetIcSlot(GetCurrentSlot()); 2233 IncreaseCurrentSlot(inc); 2234 } 2235} 2236 2237void PandaGen::CreatePrivateProperty(const ir::AstNode *node, uint32_t num, int32_t bufIdx) 2238{ 2239 std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(bufIdx); 2240 util::UString litId(idxStr, allocator_); 2241 ra_.Emit<CallruntimeCreateprivateproperty>(node, num, litId.View()); 2242} 2243 2244void PandaGen::TestIn(const ir::AstNode *node, uint32_t level, uint32_t slot) 2245{ 2246 ra_.Emit<Testin>(node, 0, level, slot); 2247} 2248 2249void PandaGen::LoadPrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot) 2250{ 2251 ra_.Emit<Ldprivateproperty>(node, 0, level, slot); 2252} 2253 2254void PandaGen::StorePrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg obj) 2255{ 2256 ra_.Emit<Stprivateproperty>(node, 0, level, slot, obj); 2257} 2258void PandaGen::ThrowTypeErrorIfFalse(const ir::AstNode *node, util::StringView str) 2259{ 2260 auto *trueLabel = AllocLabel(); 2261 BranchIfTrue(node, trueLabel); 2262 ThrowTypeError(node, str); 2263 SetLabel(node, trueLabel); 2264} 2265 2266void PandaGen::ThrowTypeError(const ir::AstNode *node, util::StringView str) 2267{ 2268 LoadAccumulatorString(node, str); 2269 VReg reg = AllocReg(); 2270 StoreAccumulator(node, reg); 2271 TryLoadGlobalByName(node, "TypeError"); 2272 ra_.Emit<Callarg1>(node, 0, reg); 2273 EmitThrow(node); 2274} 2275 2276} // namespace panda::es2panda::compiler 2277