/* * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pandagen.h" #include "varbinder/varbinder.h" #include "checker/checker.h" #include "checker/types/globalTypesHolder.h" #include "util/helpers.h" #include "util/options.h" #include "varbinder/scope.h" #include "varbinder/variable.h" #include "compiler/base/catchTable.h" #include "compiler/base/lexenv.h" #include "compiler/base/literals.h" #include "public/public.h" #include "compiler/core/labelTarget.h" #include "compiler/core/regAllocator.h" #include "compiler/function/asyncFunctionBuilder.h" #include "compiler/function/asyncGeneratorFunctionBuilder.h" #include "compiler/function/functionBuilder.h" #include "compiler/function/generatorFunctionBuilder.h" #include "es2panda.h" #include "generated/isa.h" #include "ir/base/scriptFunction.h" #include "ir/base/spreadElement.h" #include "ir/statement.h" #include "ir/expressions/identifier.h" #include "ir/expressions/literals/numberLiteral.h" #include "ir/expressions/literals/stringLiteral.h" namespace ark::es2panda::compiler { #ifndef PANDA_WITH_ECMASCRIPT class EcmaDisabled : public IRNode { public: template explicit EcmaDisabled(const ir::AstNode *node, [[maybe_unused]] Args &&...args) : IRNode(node) { ES2PANDA_UNREACHABLE(); } Formats GetFormats() const override { ES2PANDA_UNREACHABLE(); } size_t Registers([[maybe_unused]] std::array *regs) override { ES2PANDA_UNREACHABLE(); } size_t Registers([[maybe_unused]] std::array *regs) const override { ES2PANDA_UNREACHABLE(); } size_t OutRegisters([[maybe_unused]] std::array *regs) const override { ES2PANDA_UNREACHABLE(); } void Transform([[maybe_unused]] pandasm::Ins *ins, [[maybe_unused]] ProgramElement *programElement, [[maybe_unused]] uint32_t totalRegs) const override { ES2PANDA_UNREACHABLE(); } }; using EcmaLdhole = EcmaDisabled; using EcmaLdnan = EcmaDisabled; using EcmaLdinfinity = EcmaDisabled; using EcmaLdglobal = EcmaDisabled; using EcmaLdundefined = EcmaDisabled; using EcmaLdsymbol = EcmaDisabled; using EcmaLdnull = EcmaDisabled; using EcmaLdtrue = EcmaDisabled; using EcmaLdfalse = EcmaDisabled; using EcmaTryldglobalbyname = EcmaDisabled; using EcmaTrystglobalbyname = EcmaDisabled; using EcmaLdobjbyname = EcmaDisabled; using EcmaStobjbyname = EcmaDisabled; using EcmaLdobjbyindex = EcmaDisabled; using EcmaLdobjbyvalue = EcmaDisabled; using EcmaStobjbyvalue = EcmaDisabled; using EcmaStobjbyindex = EcmaDisabled; using EcmaStownbyname = EcmaDisabled; using EcmaStownbyvalue = EcmaDisabled; using EcmaStownbyindex = EcmaDisabled; using EcmaDelobjprop = EcmaDisabled; using EcmaLdglobalvar = EcmaDisabled; using EcmaStglobalvar = EcmaDisabled; using EcmaLdbigint = EcmaDisabled; using EcmaEqdyn = EcmaDisabled; using EcmaNoteqdyn = EcmaDisabled; using EcmaStricteqdyn = EcmaDisabled; using EcmaStrictnoteqdyn = EcmaDisabled; using EcmaLessdyn = EcmaDisabled; using EcmaLesseqdyn = EcmaDisabled; using EcmaGreaterdyn = EcmaDisabled; using EcmaGreatereqdyn = EcmaDisabled; using EcmaTonumber = EcmaDisabled; using EcmaNegdyn = EcmaDisabled; using EcmaNotdyn = EcmaDisabled; using EcmaNegate = EcmaDisabled; using EcmaIncdyn = EcmaDisabled; using EcmaDecdyn = EcmaDisabled; using EcmaEqdyn = EcmaDisabled; using EcmaNoteqdyn = EcmaDisabled; using EcmaStricteqdyn = EcmaDisabled; using EcmaStrictnoteqdyn = EcmaDisabled; using EcmaLessdyn = EcmaDisabled; using EcmaLesseqdyn = EcmaDisabled; using EcmaGreaterdyn = EcmaDisabled; using EcmaGreatereqdyn = EcmaDisabled; using EcmaAdd2dyn = EcmaDisabled; using EcmaSub2dyn = EcmaDisabled; using EcmaMul2dyn = EcmaDisabled; using EcmaDiv2dyn = EcmaDisabled; using EcmaMod2dyn = EcmaDisabled; using EcmaExpdyn = EcmaDisabled; using EcmaShl2dyn = EcmaDisabled; using EcmaShr2dyn = EcmaDisabled; using EcmaAshr2dyn = EcmaDisabled; using EcmaAnd2dyn = EcmaDisabled; using EcmaOr2dyn = EcmaDisabled; using EcmaXor2dyn = EcmaDisabled; using EcmaIsindyn = EcmaDisabled; using EcmaInstanceofdyn = EcmaDisabled; using EcmaIsundefined = EcmaDisabled; using EcmaIsundefined = EcmaDisabled; using EcmaJtrue = EcmaDisabled; using EcmaIstrue = EcmaDisabled; using EcmaJfalse = EcmaDisabled; using EcmaIscoercible = EcmaDisabled; using EcmaThrowdyn = EcmaDisabled; using EcmaRethrowdyn = EcmaDisabled; using EcmaReturnDyn = EcmaDisabled; using EcmaReturnundefined = EcmaDisabled; using EcmaCall0thisdyn = EcmaDisabled; using EcmaCall1thisdyn = EcmaDisabled; using EcmaCall0dyn = EcmaDisabled; using EcmaCall1thisdyn = EcmaDisabled; using EcmaCall1dyn = EcmaDisabled; using EcmaCall2thisdyn = EcmaDisabled; using EcmaCall2dyn = EcmaDisabled; using EcmaCall3thisdyn = EcmaDisabled; using EcmaCall3dyn = EcmaDisabled; using EcmaCallithisrangedyn = EcmaDisabled; using EcmaCallirangedyn = EcmaDisabled; using EcmaCall1thisdyn = EcmaDisabled; using EcmaCall1dyn = EcmaDisabled; using EcmaCall2thisdyn = EcmaDisabled; using EcmaCall2dyn = EcmaDisabled; using EcmaCall3thisdyn = EcmaDisabled; using EcmaCall3dyn = EcmaDisabled; using EcmaCallithisrangedyn = EcmaDisabled; using EcmaCallirangedyn = EcmaDisabled; using EcmaSupercall = EcmaDisabled; using EcmaSupercallspread = EcmaDisabled; using EcmaNewobjdynrange = EcmaDisabled; using EcmaLdhomeobject = EcmaDisabled; using EcmaDefinemethod = EcmaDisabled; using EcmaDefineasyncgeneratorfunc = EcmaDisabled; using EcmaDefineasyncfunc = EcmaDisabled; using EcmaDefinegeneratorfunc = EcmaDisabled; using EcmaDefinencfuncdyn = EcmaDisabled; using EcmaDefinefuncdyn = EcmaDisabled; using EcmaTypeofdyn = EcmaDisabled; using EcmaCallspreaddyn = EcmaDisabled; using EcmaNewobjspreaddyn = EcmaDisabled; using EcmaGetunmappedargs = EcmaDisabled; using EcmaNegate = EcmaDisabled; using EcmaToboolean = EcmaDisabled; using EcmaTonumber = EcmaDisabled; using EcmaGetmethod = EcmaDisabled; using EcmaCreategeneratorobj = EcmaDisabled; using EcmaCreateasyncgeneratorobj = EcmaDisabled; using EcmaCreateiterresultobj = EcmaDisabled; using EcmaSuspendgenerator = EcmaDisabled; using EcmaSuspendasyncgenerator = EcmaDisabled; using EcmaSetgeneratorstate = EcmaDisabled; using EcmaSetgeneratorstate = EcmaDisabled; using EcmaResumegenerator = EcmaDisabled; using EcmaGetresumemode = EcmaDisabled; using EcmaAsyncfunctionenter = EcmaDisabled; using EcmaAsyncfunctionawait = EcmaDisabled; using EcmaAsyncfunctionresolve = EcmaDisabled; using EcmaAsyncfunctionreject = EcmaDisabled; using EcmaAsyncgeneratorresolve = EcmaDisabled; using EcmaAsyncgeneratorreject = EcmaDisabled; using EcmaGettemplateobject = EcmaDisabled; using EcmaCopyrestargs = EcmaDisabled; using EcmaGetpropiterator = EcmaDisabled; using EcmaGetnextpropname = EcmaDisabled; using EcmaCreateemptyobject = EcmaDisabled; using EcmaCreateobjectwithbuffer = EcmaDisabled; using EcmaCreateobjecthavingmethod = EcmaDisabled; using EcmaSetobjectwithproto = EcmaDisabled; using EcmaCopydataproperties = EcmaDisabled; using EcmaDefinegettersetterbyvalue = EcmaDisabled; using EcmaCreateemptyarray = EcmaDisabled; using EcmaCreatearraywithbuffer = EcmaDisabled; using EcmaStarrayspread = EcmaDisabled; using EcmaCreateregexpwithliteral = EcmaDisabled; using EcmaThrowifnotobject = EcmaDisabled; using EcmaThrowthrownotexists = EcmaDisabled; using EcmaGetiterator = EcmaDisabled; using EcmaGetasynciterator = EcmaDisabled; using EcmaCreateobjectwithexcludedkeys = EcmaDisabled; using EcmaThrowpatternnoncoercible = EcmaDisabled; using EcmaCloseiterator = EcmaDisabled; using EcmaImportmodule = EcmaDisabled; using EcmaSetclasscomputedfields = EcmaDisabled; using EcmaDefineclasswithbuffer = EcmaDisabled; using EcmaLoadclasscomputedinstancefields = EcmaDisabled; using EcmaDefineclassprivatefields = EcmaDisabled; using EcmaClassfieldadd = EcmaDisabled; using EcmaClassprivatefieldadd = EcmaDisabled; using EcmaClassprivatemethodoraccessoradd = EcmaDisabled; using EcmaClassprivatefieldget = EcmaDisabled; using EcmaClassprivatefieldset = EcmaDisabled; using EcmaClassprivatefieldin = EcmaDisabled; using EcmaLdmodvarbyname = EcmaDisabled; using EcmaStmodulevar = EcmaDisabled; using EcmaCopymodule = EcmaDisabled; using EcmaStsuperbyname = EcmaDisabled; using EcmaLdsuperbyname = EcmaDisabled; using EcmaStsuperbyvalue = EcmaDisabled; using EcmaLdsuperbyvalue = EcmaDisabled; using EcmaLdlexvardyn = EcmaDisabled; using EcmaLdlexdyn = EcmaDisabled; using EcmaStlexvardyn = EcmaDisabled; using EcmaStlexdyn = EcmaDisabled; using EcmaThrowifsupernotcorrectcall = EcmaDisabled; using EcmaThrowtdz = EcmaDisabled; using EcmaThrowconstassignment = EcmaDisabled; using EcmaPoplexenvdyn = EcmaDisabled; using EcmaCopylexenvdyn = EcmaDisabled; using EcmaNewlexenvdyn = EcmaDisabled; using EcmaLdlexenvdyn = EcmaDisabled; using EcmaLdevalvar = EcmaDisabled; using EcmaStevalvar = EcmaDisabled; using EcmaLdevalbindings = EcmaDisabled; using EcmaDirecteval = EcmaDisabled; #endif PandaGen::PandaGen(ArenaAllocator *const allocator, RegSpiller *const spiller, public_lib::Context *const context, std::tuple toCompile) : CodeGen(allocator, spiller, context, toCompile) { Function::Compile(this); } FunctionBuilder *PandaGen::FuncBuilder() const noexcept { return builder_; } EnvScope *PandaGen::GetEnvScope() const noexcept { return envScope_; } void PandaGen::OptionalChainCheck(const bool optional, const VReg obj) const { if (optional && optionalChain_ != nullptr) { optionalChain_->Check(obj); } } void PandaGen::FunctionInit(CatchTable *catchTable) { if (RootNode()->IsProgram()) { builder_ = Allocator()->New(this, catchTable); return; } const ir::ScriptFunction *func = RootNode()->AsScriptFunction(); if (func->IsAsyncFunc()) { if (func->IsGenerator()) { builder_ = Allocator()->New(this, catchTable); return; } builder_ = Allocator()->New(this, catchTable); return; } if (func->IsGenerator()) { builder_ = Allocator()->New(this, catchTable); return; } builder_ = Allocator()->New(this, catchTable); } bool PandaGen::FunctionHasFinalizer() const { if (RootNode()->IsProgram()) { return false; } const ir::ScriptFunction *func = RootNode()->AsScriptFunction(); return func->IsAsyncFunc() || func->IsGenerator(); } void PandaGen::FunctionEnter() { builder_->Prepare(RootNode()->AsScriptFunction()); } void PandaGen::FunctionExit() { builder_->CleanUp(RootNode()->AsScriptFunction()); } void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) { Ra().Emit(node, vreg); } void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) { Ra().Emit(node, reg); } IRNode *PandaGen::AllocMov(const ir::AstNode *node, const VReg vd, const VReg vs) { return Allocator()->New(node, vd, vs); } IRNode *PandaGen::AllocMov(const ir::AstNode *node, OutVReg vd, const VReg vs) { ES2PANDA_ASSERT(vd.type == OperandType::ANY); return Allocator()->New(node, *vd.reg, vs); } void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) { Ra().Emit(node, vd, vs); } void PandaGen::LoadAccumulatorDouble(const ir::AstNode *node, double num) { Sa().Emit(node, num); } void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) { Sa().Emit(node, static_cast(num)); } void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) { LoadConst(node, id); StoreAccumulator(node, reg); } void PandaGen::LoadConst(const ir::AstNode *node, Constant id) { switch (id) { case Constant::JS_HOLE: { Sa().Emit(node); break; } case Constant::JS_NAN: { Sa().Emit(node); break; } case Constant::JS_INFINITY: { Sa().Emit(node); break; } case Constant::JS_GLOBAL: { Sa().Emit(node); break; } case Constant::JS_UNDEFINED: { Sa().Emit(node); break; } case Constant::JS_SYMBOL: { Sa().Emit(node); break; } case Constant::JS_NULL: { Sa().Emit(node); break; } case Constant::JS_TRUE: { Sa().Emit(node); break; } case Constant::JS_FALSE: { Sa().Emit(node); break; } default: { ES2PANDA_UNREACHABLE(); } } } void PandaGen::GetFunctionObject(const ir::AstNode *node) { LoadAccFromLexEnv(node, Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_FUNC)); } void PandaGen::GetNewTarget(const ir::AstNode *node) { LoadAccFromLexEnv(node, Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_NEW_TARGET)); } void PandaGen::GetThis(const ir::AstNode *node) { LoadAccFromLexEnv(node, Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS)); } void PandaGen::SetThis(const ir::AstNode *node) { StoreAccToLexEnv(node, Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS), true); } void PandaGen::LoadVar(const ir::Identifier *node, const varbinder::ConstScopeFindResult &result) { auto *var = result.variable; if (var == nullptr) { TryLoadGlobalByName(node, result.name); return; } if (var->IsGlobalVariable()) { LoadGlobalVar(node, var->Name()); return; } if (var->IsModuleVariable()) { LoadModuleVariable(node, var->AsModuleVariable()->ModuleReg(), var->AsModuleVariable()->ExoticName()); return; } ES2PANDA_ASSERT(var->IsLocalVariable()); LoadAccFromLexEnv(node, result); } void PandaGen::StoreVar(const ir::AstNode *node, const varbinder::ConstScopeFindResult &result, bool isDeclaration) { varbinder::Variable *var = result.variable; if (var == nullptr) { if (IsDirectEval()) { StoreEvalVariable(node, result.name); } else { TryStoreGlobalByName(node, result.name); } return; } if (var->IsGlobalVariable()) { StoreGlobalVar(node, var->Name()); return; } if (var->IsModuleVariable()) { ThrowConstAssignment(node, var->Name()); return; } ES2PANDA_ASSERT(var->IsLocalVariable()); StoreAccToLexEnv(node, result, isDeclaration); } void PandaGen::LoadAccFromArgs(const ir::AstNode *node) { if (!Scope()->HasFlag(varbinder::ScopeFlags::USE_ARGS)) { return; } auto res = Scope()->Find(varbinder::VarBinder::FUNCTION_ARGUMENTS); ES2PANDA_ASSERT(res.scope); GetUnmappedArgs(node); StoreAccToLexEnv(node, res, true); } void PandaGen::LoadObjProperty(const ir::AstNode *node, const Operand &prop) { if (std::holds_alternative(prop)) { LoadObjByValue(node, std::get(prop)); return; } if (std::holds_alternative(prop)) { LoadObjByIndex(node, std::get(prop)); return; } ES2PANDA_ASSERT(std::holds_alternative(prop)); LoadObjByName(node, std::get(prop)); } void PandaGen::StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop) { if (std::holds_alternative(prop)) { StoreObjByValue(node, obj, std::get(prop)); return; } if (std::holds_alternative(prop)) { StoreObjByIndex(node, obj, std::get(prop)); return; } ES2PANDA_ASSERT(std::holds_alternative(prop)); StoreObjByName(node, obj, std::get(prop)); } void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop) { if (std::holds_alternative(prop)) { StOwnByValue(node, obj, std::get(prop)); return; } if (std::holds_alternative(prop)) { StOwnByIndex(node, obj, std::get(prop)); return; } ES2PANDA_ASSERT(std::holds_alternative(prop)); StOwnByName(node, obj, std::get(prop)); } void PandaGen::TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::TryStoreGlobalByName(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::LoadObjByName(const ir::AstNode *node, const util::StringView &prop) { Ra().Emit(node, prop); } void PandaGen::StoreObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) { Ra().Emit(node, prop, obj); } void PandaGen::LoadObjByIndex(const ir::AstNode *node, int64_t index) { Ra().Emit(node, index); } void PandaGen::LoadObjByValue(const ir::AstNode *node, VReg obj) { Ra().Emit(node, obj); } void PandaGen::StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop) { Ra().Emit(node, obj, prop); } void PandaGen::StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index) { Ra().Emit(node, index, obj); } void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) { Ra().Emit(node, prop, obj); } void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop) { Ra().Emit(node, obj, prop); } void PandaGen::StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index) { Ra().Emit(node, index, obj); } void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop) { Ra().Emit(node, obj, prop); } void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } VReg PandaGen::LexEnv() const noexcept { return envScope_->LexEnv(); } void PandaGen::LoadAccFromLexEnv(const ir::AstNode *node, const varbinder::ConstScopeFindResult &result) { VirtualLoadVar::Expand(this, node, result); } void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const varbinder::ConstScopeFindResult &result, bool isDeclaration) { VirtualStoreVar::Expand(this, node, result, isDeclaration); } void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt) { Sa().Emit(node, bigInt); } void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) { switch (op) { case lexer::TokenType::PUNCTUATOR_EQUAL: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { Ra().Emit(node, lhs); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { Ra().Emit(node, lhs); break; } default: { ES2PANDA_UNREACHABLE(); } } BranchIfFalse(node, ifFalse); } void PandaGen::Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand) { switch (op) { case lexer::TokenType::PUNCTUATOR_PLUS: { Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_MINUS: { Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_TILDE: { Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { Sa().Emit(node); break; } case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { Ra().Emit(node, operand); break; } case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { Ra().Emit(node, operand); break; } case lexer::TokenType::KEYW_VOID: case lexer::TokenType::KEYW_DELETE: { LoadConst(node, Constant::JS_UNDEFINED); break; } default: { ES2PANDA_UNREACHABLE(); } } } // CC-OFFNXT(huge_method,huge_cyclomatic_complexity,G.FUN.01-CPP) big switch-case, solid logic void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) { switch (op) { case lexer::TokenType::PUNCTUATOR_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_LESS_THAN: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_GREATER_THAN: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_PLUS: case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_MULTIPLY: case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_DIVIDE: case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_MOD: case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL: case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_BITWISE_AND: case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_BITWISE_OR: case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: return Ra().Emit(node, lhs); case lexer::TokenType::KEYW_IN: return Ra().Emit(node, lhs); case lexer::TokenType::KEYW_INSTANCEOF: return Ra().Emit(node, lhs); case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: case lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL: return Unimplemented(); default: ES2PANDA_UNREACHABLE(); } } void PandaGen::BranchIfUndefined(const ir::AstNode *node, Label *target) { Sa().Emit(node); BranchIfTrue(node, target); } void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target) { Sa().Emit(node); BranchIfFalse(node, target); } void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target) { Sa().Emit(node, target); } void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) { Sa().Emit(node); BranchIfFalse(node, target); } void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target) { Sa().Emit(node, target); } void PandaGen::BranchIfCoercible(const ir::AstNode *node, Label *target) { Sa().Emit(node); BranchIfTrue(node, target); } void PandaGen::EmitThrow(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::EmitRethrow(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::EmitReturn(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::EmitReturnUndefined(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::ImplicitReturn(const ir::AstNode *node) { builder_->ImplicitReturn(node); } void PandaGen::DirectReturn(const ir::AstNode *node) { builder_->DirectReturn(node); } void PandaGen::ValidateClassDirectReturn(const ir::AstNode *node) { const ir::ScriptFunction *func = util::Helpers::GetContainingFunction(node); if (func == nullptr || !func->IsConstructor()) { return; } RegScope rs(this); VReg value = AllocReg(); StoreAccumulator(node, value); auto *notUndefined = AllocLabel(); auto *condEnd = AllocLabel(); BranchIfNotUndefined(node, notUndefined); GetThis(func); ThrowIfSuperNotCorrectCall(func, 0); Branch(node, condEnd); SetLabel(node, notUndefined); LoadAccumulator(node, value); SetLabel(node, condEnd); } void PandaGen::EmitAwait(const ir::AstNode *node) { builder_->Await(node); } void PandaGen::Call0This(const ir::AstNode *node, VReg callee, VReg thisReg) { LoadAccumulator(node, thisReg); Ra().Emit(node, callee); } void PandaGen::Call1This(const ir::AstNode *node, VReg callee, VReg thisReg, VReg arg0) { LoadAccumulator(node, arg0); Ra().Emit(node, callee, thisReg); } void PandaGen::Call0Args(const ir::AstNode *n, VReg c, VReg thisR, bool hasThis) { if (hasThis) { Call0This(n, c, thisR); } else { Sa().Emit(n); } } void PandaGen::Call1Arg(const ir::AstNode *n, VReg c, VReg thisR, const ArenaVector &args, bool hasThis) { const auto *arg0 = args[0]; arg0->Compile(this); if (hasThis) { Ra().Emit(n, c, thisR); } else { Ra().Emit(n, c); } } void PandaGen::Call2Args(const ir::AstNode *n, VReg c, VReg thisR, const ArenaVector &args, bool hasThis) { const auto *arg0 = args[0]; arg0->Compile(this); compiler::VReg arg0Reg = AllocReg(); StoreAccumulator(arg0, arg0Reg); const auto *arg1 = args[1]; arg1->Compile(this); if (hasThis) { Ra().Emit(n, c, thisR, arg0Reg); } else { Ra().Emit(n, c, arg0Reg); } } void PandaGen::Call3Args(const ir::AstNode *n, VReg c, VReg thisR, const ArenaVector &args, bool hasThis) { const auto *arg0 = args[0]; arg0->Compile(this); compiler::VReg arg0Reg = AllocReg(); StoreAccumulator(arg0, arg0Reg); const auto *arg1 = args[1]; arg1->Compile(this); compiler::VReg arg1Reg = AllocReg(); StoreAccumulator(arg1, arg1Reg); const auto *arg2 = args[2]; arg2->Compile(this); if (hasThis) { Ra().Emit(n, c, thisR, arg0Reg, arg1Reg); } else { Ra().Emit(n, c, arg0Reg, arg1Reg); } } void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { bool hasThis = !thisReg.IsInvalid(); switch (arguments.size()) { case 0: { // 0 args Call0Args(node, callee, thisReg, hasThis); return; } case 1: { // 1 arg Call1Arg(node, callee, thisReg, arguments, hasThis); return; } case 2: { // 2 args Call2Args(node, callee, thisReg, arguments, hasThis); return; } case 3: { // 3 args Call3Args(node, callee, thisReg, arguments, hasThis); return; } default: { break; } } for (const auto *it : arguments) { it->Compile(this); compiler::VReg arg = AllocReg(); StoreAccumulator(it, arg); } if (hasThis) { size_t argCount = arguments.size() + 1; auto constexpr EXTRA_ARGS = 2; Rra().Emit(node, callee, argCount + EXTRA_ARGS, static_cast(argCount), callee); } else { size_t argCount = arguments.size(); Rra().Emit(node, callee, argCount + 1, static_cast(argCount), callee); } } bool PandaGen::CallArgsTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments, bool hasThis) { VReg arg0Reg = AllocReg(); StoreAccumulator(node, arg0Reg); const auto call1 = [this, hasThis, arg0Reg](const ir::AstNode *n, VReg c, VReg thisR, const ArenaVector &args) { const auto *arg = args[0]; arg->Compile(this); if (hasThis) { Ra().Emit(n, c, thisR, arg0Reg); } else { Ra().Emit(n, c, arg0Reg); } }; const auto call2 = [this, hasThis, arg0Reg](const ir::AstNode *n, VReg c, VReg thisR, const ArenaVector &args) { const auto *arg1 = args[0]; arg1->Compile(this); compiler::VReg arg1Reg = AllocReg(); StoreAccumulator(arg1, arg1Reg); const auto *arg2 = args[1]; arg2->Compile(this); if (hasThis) { Ra().Emit(n, c, thisR, arg0Reg, arg1Reg); } else { Ra().Emit(n, c, arg0Reg, arg1Reg); } }; switch (arguments.size()) { case 1: { call1(node, callee, thisReg, arguments); return true; } case 2: { // 2:2 args call2(node, callee, thisReg, arguments); return true; } default: { break; } } return false; } void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { bool hasThis = !thisReg.IsInvalid(); StoreAccumulator(node, callee); Literals::GetTemplateObject(this, node->AsTaggedTemplateExpression()); if (arguments.empty()) { if (hasThis) { Ra().Emit(node, callee, thisReg); } else { Sa().Emit(node, callee); } return; } if (CallArgsTagged(node, callee, thisReg, arguments, hasThis)) { return; } for (const auto *it : arguments) { it->Compile(this); compiler::VReg arg = AllocReg(); StoreAccumulator(it, arg); } if (hasThis) { auto constexpr EXTRA_ARGS = 2; size_t argCount = arguments.size() + EXTRA_ARGS; Rra().Emit(node, callee, argCount + EXTRA_ARGS, static_cast(argCount), callee); } else { size_t argCount = arguments.size() + 1; Rra().Emit(node, callee, argCount + 1, static_cast(argCount), callee); } } void PandaGen::SuperCall(const ir::AstNode *node, VReg startReg, size_t argCount) { Rra().Emit(node, startReg, argCount, static_cast(argCount), startReg); } void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs) { Ra().Emit(node, vs); } void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount) { Rra().Emit(node, startReg, argCount, static_cast(argCount), startReg); } void PandaGen::LoadHomeObject(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::DefineMethod(const ir::AstNode *node, const util::StringView &name) { Ra().Emit(node, name, LexEnv()); } void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) { if (realNode->IsAsyncFunc()) { if (realNode->IsGenerator()) { Ra().Emit(node, name, LexEnv()); } else { Ra().Emit(node, name, LexEnv()); } } else if (realNode->IsGenerator()) { Ra().Emit(node, name, LexEnv()); } else if (realNode->IsArrow()) { LoadHomeObject(node); Ra().Emit(node, name, LexEnv()); } else if (realNode->IsMethod()) { DefineMethod(node, name); } else { Ra().Emit(node, name, LexEnv()); } } void PandaGen::TypeOf(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args) { Ra().Emit(node, func, thisReg, args); } void PandaGen::NewObjSpread(const ir::AstNode *node, VReg obj, VReg target) { Ra().Emit(node, obj, target); } void PandaGen::GetUnmappedArgs(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::Negate(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::ToBoolean(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::ToNumber(const ir::AstNode *node, VReg arg) { Ra().Emit(node, arg); } void PandaGen::GetMethod(const ir::AstNode *node, VReg obj, const util::StringView &name) { Ra().Emit(node, name, obj); } void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj) { Ra().Emit(node, funcObj); } void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj) { Ra().Emit(node, funcObj); } void PandaGen::CreateIterResultObject(const ir::AstNode *node, bool done) { Ra().Emit(node, static_cast(done)); } void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj) { Ra().Emit(node, genObj); } void PandaGen::SuspendAsyncGenerator(const ir::AstNode *node, VReg asyncGenObj) { Ra().Emit(node, asyncGenObj); } void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj) { Ra().Emit(node, genObj, static_cast(GeneratorState::SUSPENDED_YIELD)); } void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj) { Ra().Emit(node, genObj, static_cast(GeneratorState::COMPLETED)); } void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj) { Ra().Emit(node, genObj); } void PandaGen::GetResumeMode(const ir::AstNode *node, VReg genObj) { Ra().Emit(node, genObj); } void PandaGen::AsyncFunctionEnter(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj) { Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj) { Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj) { Ra().Emit(node, asyncFuncObj); } void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj) { Ra().Emit(node, asyncGenObj); } void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj) { Ra().Emit(node, asyncGenObj); } void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value) { Ra().Emit(node, value); } void PandaGen::CopyRestArgs(const ir::AstNode *node, uint32_t index) { Sa().Emit(node, index); } void PandaGen::GetPropIterator(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::GetNextPropName(const ir::AstNode *node, VReg iter) { Ra().Emit(node, iter); } void PandaGen::CreateEmptyObject(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx) { ES2PANDA_ASSERT(util::Helpers::IsInteger(idx)); Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } void PandaGen::CreateObjectHavingMethod(const ir::AstNode *node, uint32_t idx) { ES2PANDA_ASSERT(util::Helpers::IsInteger(idx)); LoadAccumulator(node, LexEnv()); Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } void PandaGen::SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj) { Ra().Emit(node, proto, obj); } void PandaGen::CopyDataProperties(const ir::AstNode *node, VReg dst, VReg src) { Ra().Emit(node, dst, src); } void PandaGen::DefineGetterSetterByValue(const ir::AstNode *node, std::tuple registers, bool setName) { const auto [obj, name, getter, setter] = registers; LoadConst(node, setName ? Constant::JS_TRUE : Constant::JS_FALSE); Ra().Emit(node, obj, name, getter, setter); } void PandaGen::CreateEmptyArray(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx) { ES2PANDA_ASSERT(util::Helpers::IsInteger(idx)); Sa().Emit(node, util::Helpers::ToStringView(Allocator(), idx)); } size_t PandaGen::HandleArrayLiterals(const ir::AstNode *node, const ArenaVector &elements) { LiteralBuffer buf {}; size_t i = 0; // This loop handles constant literal data by collecting it into a literal buffer // until a non-constant element is encountered. while (i < elements.size()) { Literal lit = util::Helpers::ToConstantLiteral(elements[i]); if (lit.IsInvalid()) { break; } buf.emplace_back(std::move(lit)); i++; } if (buf.empty()) { CreateEmptyArray(node); } else { uint32_t bufIdx = AddLiteralBuffer(std::move(buf)); CreateArrayWithBuffer(node, bufIdx); } return i; } void PandaGen::HandleArraySpread(const ir::AstNode *node, const ArenaVector &elements, VReg obj) { size_t i = 0; bool hasSpread = false; // This loop handles array elements until a spread element is encountered for (; i < elements.size(); i++) { const ir::Expression *elem = elements[i]; if (elem->IsOmittedExpression()) { continue; } if (elem->IsSpreadElement()) { // The next loop will handle arrays that have a spread element hasSpread = true; break; } elem->Compile(this); StOwnByIndex(elem, obj, i); } RegScope rs(this); VReg idxReg {}; if (hasSpread) { idxReg = AllocReg(); LoadAccumulatorInt(node, i); StoreAccumulator(node, idxReg); } // This loop handles arrays that contain spread elements for (; i < elements.size(); i++) { const ir::Expression *elem = elements[i]; if (elem->IsSpreadElement()) { elem->AsSpreadElement()->Argument()->Compile(this); StoreArraySpread(elem, obj, idxReg); StoreAccumulator(elem, idxReg); continue; } if (!elem->IsOmittedExpression()) { elem->Compile(this); StOwnByValue(elem, obj, idxReg); } Unary(elem, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, idxReg); StoreAccumulator(elem, idxReg); } // If the last element is omitted, we also have to update the length property if (elements.back()->IsOmittedExpression()) { // if there was a spread value then acc already contains the length if (!hasSpread) { LoadAccumulatorInt(node, i); } StOwnByName(node, obj, "length"); } } void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector &elements, VReg obj) { if (elements.empty()) { CreateEmptyArray(node); StoreAccumulator(node, obj); return; } const auto i = HandleArrayLiterals(node, elements); StoreAccumulator(node, obj); if (i == elements.size()) { return; } HandleArraySpread(node, elements, obj); LoadAccumulator(node, obj); } void PandaGen::StoreArraySpread(const ir::AstNode *node, VReg array, VReg index) { Ra().Emit(node, array, index); } void PandaGen::CreateRegExpWithLiteral(const ir::AstNode *node, const util::StringView &pattern, uint8_t flags) { Sa().Emit(node, pattern, flags); } void PandaGen::ThrowIfNotObject(const ir::AstNode *node) { Ra().Emit(node); } void PandaGen::ThrowThrowNotExist(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::GetIterator(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::GetAsyncIterator(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) { ES2PANDA_ASSERT(argStart.GetIndex() == obj.GetIndex() - 1); if (argCount == 0) { // Do not emit undefined register argStart = obj; } Rra().Emit(node, argStart, argCount, static_cast(argCount), obj, argStart); } void PandaGen::ThrowObjectNonCoercible(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter) { Ra().Emit(node, iter); } void PandaGen::ImportModule(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::SetClassComputedFields(const ir::AstNode *node, VReg classReg, VReg computedInstanceFieldArray) { Ra().Emit(node, classReg, computedInstanceFieldArray); } void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, uint32_t litIdx, VReg lexenv, VReg base) { Ra().Emit(node, ctorId, litIdx, lexenv, base); } void PandaGen::LoadClassComputedInstanceFields(const ir::AstNode *node, VReg ctor) { Sa().Emit(node, ctor); } void PandaGen::DefineClassPrivateFields(const ir::AstNode *node, uint32_t privateBufIdx) { Sa().Emit(node, util::Helpers::ToStringView(Allocator(), privateBufIdx), LexEnv()); } void PandaGen::ClassFieldAdd(const ir::AstNode *node, VReg obj, VReg prop) { Ra().Emit(node, obj, prop); } void PandaGen::ClassPrivateFieldAdd(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateMethodOrAccessorAdd(const ir::AstNode *node, VReg ctor, VReg obj) { Ra().Emit(node, ctor, obj); } void PandaGen::ClassPrivateFieldGet(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateFieldSet(const ir::AstNode *node, VReg ctor, VReg obj, const util::StringView &prop) { Ra().Emit(node, prop, ctor, obj); } void PandaGen::ClassPrivateFieldIn(const ir::AstNode *node, VReg ctor, const util::StringView &prop) { Ra().Emit(node, prop, ctor); } void PandaGen::LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name) { Ra().Emit(node, name, module); } void PandaGen::StoreModuleVar(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::CopyModule(const ir::AstNode *node, VReg module) { Ra().Emit(node, module); } void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) { Ra().Emit(node, key, obj); } void PandaGen::LdSuperByName(const ir::AstNode *node, const util::StringView &key) { Ra().Emit(node, key); } void PandaGen::StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop) { Ra().Emit(node, obj, prop); } void PandaGen::LdSuperByValue(const ir::AstNode *node, VReg obj) { Ra().Emit(node, obj); } void PandaGen::StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop) { if (std::holds_alternative(prop)) { StSuperByName(node, obj, std::get(prop)); return; } ES2PANDA_ASSERT(std::holds_alternative(prop)); StSuperByValue(node, obj, std::get(prop)); } void PandaGen::LoadSuperProperty(const ir::AstNode *node, const Operand &prop) { if (std::holds_alternative(prop)) { LdSuperByName(node, std::get(prop)); return; } ES2PANDA_ASSERT(std::holds_alternative(prop)); LdSuperByValue(node, std::get(prop)); } void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) { Sa().Emit(node, level, slot); } void PandaGen::LoadLexical(const ir::AstNode *node, const util::StringView &name, uint32_t level, uint32_t slot) { Sa().Emit(node, name, level, slot); } void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) { Ra().Emit(node, level, slot); } void PandaGen::StoreLexical(const ir::AstNode *node, const util::StringView &name, uint32_t level, uint32_t slot) { Ra().Emit(node, name, level, slot); } void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num) { Sa().Emit(node, num); } void PandaGen::ThrowTdz(const ir::AstNode *node, const util::StringView &name) { Sa().Emit(node, name); } void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name) { Ra().Emit(node, name); } void PandaGen::PopLexEnv(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::CopyLexEnv(const ir::AstNode *node) { Sa().Emit(node); } void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num) { Sa().Emit(node, num); } void PandaGen::LdLexEnv(const ir::AstNode *node) { Sa().Emit(node); } Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed) { VReg res {VReg::REG_START}; if (!isComputed) { if (prop->IsIdentifier()) { return prop->AsIdentifier()->Name(); } return res; } if (prop->IsStringLiteral()) { const util::StringView &str = prop->AsStringLiteral()->Str(); /* NOTE: dbatyai. remove this when runtime handles __proto__ as property name correctly */ if (str.Is("__proto__")) { return res; } int64_t index = util::Helpers::GetIndex(str); if (index != util::Helpers::INVALID_INDEX) { return index; } return str; } if (prop->IsNumberLiteral()) { auto num = prop->AsNumberLiteral()->Number().GetDouble(); if (util::Helpers::IsIndex(num)) { return static_cast(num); } return prop->AsNumberLiteral()->Str(); } return res; } Operand PandaGen::ToPropertyKey(const ir::Expression *prop, bool isComputed, bool isSuperExpression) { Operand op = ToNamedPropertyKey(prop, isComputed); if (std::holds_alternative(op)) { return op; } if (std::holds_alternative(op) && !isSuperExpression) { return op; } VReg objReg = AllocReg(); StoreAccumulator(prop, objReg); prop->Compile(this); return objReg; } Operand PandaGen::ToOwnPropertyKey(const ir::Expression *prop, bool isComputed) { Operand op = ToNamedPropertyKey(prop, isComputed); if (std::holds_alternative(op)) { ES2PANDA_ASSERT(std::holds_alternative(op) || std::holds_alternative(op)); return op; } if (std::holds_alternative(op)) { return op; } VReg propReg = AllocReg(); prop->Compile(this); StoreAccumulator(prop, propReg); return propReg; } void PandaGen::LoadPropertyKeyAcc(const ir::Expression *prop, bool isComputed) { Operand op = ToNamedPropertyKey(prop, isComputed); if (std::holds_alternative(op)) { LoadAccumulatorString(prop, std::get(op)); } else if (std::holds_alternative(op)) { LoadAccumulatorInt(prop, static_cast(std::get(op))); } else { prop->Compile(this); } } VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed) { LoadPropertyKeyAcc(prop, isComputed); VReg propReg = AllocReg(); StoreAccumulator(prop, propReg); return propReg; } void PandaGen::LoadEvalVariable(const ir::AstNode *node, const util::StringView &name) { RegScope rs(this); LoadLexicalContext(node); Ra().Emit(node, name); } void PandaGen::StoreEvalVariable(const ir::AstNode *node, const util::StringView &name) { RegScope rs(this); VReg value = AllocReg(); StoreAccumulator(node, value); LoadLexicalContext(node); Ra().Emit(node, name, value); } void PandaGen::DirectEval(const ir::AstNode *node, uint32_t parserStatus) { RegScope rs(this); uint32_t index = 0; uint32_t evalBindingsIndex = 0; VReg arg0 = AllocReg(); StoreAccumulator(node, arg0); VReg bindings = AllocReg(); CreateEmptyArray(node); StoreAccumulator(node, bindings); GetFunctionObject(node); StOwnByIndex(node, bindings, index++); GetNewTarget(node); StOwnByIndex(node, bindings, index++); GetThis(node); StOwnByIndex(node, bindings, index++); VReg evalBindings = AllocReg(); CreateEmptyArray(node); StoreAccumulator(node, evalBindings); LoadAccumulator(node, LexEnv()); StOwnByIndex(node, evalBindings, evalBindingsIndex++); const auto *iter = Scope()->EnclosingVariableScope(); while (true) { ES2PANDA_ASSERT(iter != nullptr); uint32_t scopeBindingsBuf = iter->EvalBindings(); if (scopeBindingsBuf != INVALID_LITERAL_BUFFER_ID) { Sa().Emit(node, util::Helpers::ToStringView(Allocator(), scopeBindingsBuf)); StOwnByIndex(node, evalBindings, evalBindingsIndex++); } if (iter->Parent() == nullptr) { break; } iter = iter->Parent()->EnclosingVariableScope(); } LoadAccumulator(node, evalBindings); StOwnByIndex(node, bindings, index++); Sa().Emit(node, static_cast(parserStatus), arg0, bindings); } void PandaGen::LoadLexicalContext(const ir::AstNode *node) { auto result = Scope()->Find(varbinder::VarBinder::LEXICAL_CONTEXT_PARAM); LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx()); } bool PandaGen::IsDirectEval() const { return Context()->config->options->IsDirectEval(); } bool PandaGen::IsEval() const { return Context()->config->options->IsEval(); } const checker::Type *PandaGen::GetVRegType(VReg vreg) const { // We assume that all used regs have any type if (vreg.GetIndex() > NextReg().GetIndex()) { return Context()->checker->GetGlobalTypesHolder()->GlobalAnyType(); } return nullptr; } } // namespace ark::es2panda::compiler