1/** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "function.h" 17 18#include "varbinder/varbinder.h" 19#include "util/helpers.h" 20#include "varbinder/scope.h" 21#include "varbinder/variable.h" 22#include "compiler/base/lreference.h" 23#include "compiler/core/pandagen.h" 24#include "ir/base/classDefinition.h" 25#include "ir/base/classProperty.h" 26#include "ir/base/scriptFunction.h" 27#include "ir/expressions/assignmentExpression.h" 28#include "ir/expressions/identifier.h" 29#include "ir/statements/blockStatement.h" 30 31namespace ark::es2panda::compiler { 32static void CompileSourceBlock(PandaGen *pg, const ir::BlockStatement *block) 33{ 34 const auto &statements = block->Statements(); 35 if (statements.empty()) { 36 pg->SetFirstStmt(block); 37 pg->ImplicitReturn(block); 38 return; 39 } 40 41 pg->SetFirstStmt(statements.front()); 42 43 for (const auto *stmt : statements) { 44 stmt->Compile(pg); 45 } 46 47 switch (statements.back()->Type()) { 48 case ir::AstNodeType::RETURN_STATEMENT: { 49 return; 50 } 51 case ir::AstNodeType::VARIABLE_DECLARATION: 52 case ir::AstNodeType::FUNCTION_DECLARATION: 53 case ir::AstNodeType::STRUCT_DECLARATION: 54 case ir::AstNodeType::CLASS_DECLARATION: { 55 pg->ImplicitReturn(statements.back()); 56 break; 57 } 58 default: { 59 if (pg->IsEval()) { 60 pg->DirectReturn(statements.back()); 61 } else { 62 pg->ImplicitReturn(statements.back()); 63 } 64 } 65 } 66} 67 68static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFunction *func) 69{ 70 ScopeContext scopeCtx(pg, func->Scope()->ParamScope()); 71 72 uint32_t index = 0; 73 74 for (const auto *param : func->Params()) { 75 auto ref = JSLReference::Create(pg, param, true); 76 77 [[maybe_unused]] varbinder::Variable *paramVar = ref.Variable(); 78 79 if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 80 util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index); 81 paramVar = pg->Scope()->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS); 82 } 83 84 ASSERT(paramVar && paramVar->IsLocalVariable()); 85 86 VReg paramReg = VReg(varbinder::VarBinder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); 87 ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg); 88 89 if (param->IsAssignmentPattern()) { 90 RegScope rs(pg); 91 pg->LoadAccumulator(func, paramReg); 92 auto *nonDefaultLabel = pg->AllocLabel(); 93 94 if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 95 auto *loadParamLabel = pg->AllocLabel(); 96 97 pg->BranchIfNotUndefined(func, loadParamLabel); 98 param->AsAssignmentPattern()->Right()->Compile(pg); 99 pg->Branch(func, nonDefaultLabel); 100 101 pg->SetLabel(func, loadParamLabel); 102 pg->LoadAccumulator(func, paramReg); 103 104 pg->SetLabel(func, nonDefaultLabel); 105 ref.SetValue(); 106 } else { 107 pg->BranchIfNotUndefined(func, nonDefaultLabel); 108 109 param->AsAssignmentPattern()->Right()->Compile(pg); 110 ref.SetValue(); 111 pg->SetLabel(func, nonDefaultLabel); 112 } 113 114 continue; 115 } 116 117 if (param->IsRestElement()) { 118 pg->CopyRestArgs(param, func->Params().size() - 1); 119 } else if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 120 pg->LoadAccumulator(func, paramReg); 121 } else { 122 continue; 123 } 124 ref.SetValue(); 125 } 126} 127 128void Function::LoadClassContexts(const ir::AstNode *node, PandaGen *pg, VReg ctor, const util::StringView &name) 129{ 130 auto *classDef = util::Helpers::GetContainingClassDefinition(node); 131 132 do { 133 auto res = pg->Scope()->Find(classDef->PrivateId()); 134 ASSERT(res.variable); 135 136 if (classDef->HasMatchingPrivateKey(name)) { 137 pg->LoadLexicalVar(node, res.lexLevel, res.variable->AsLocalVariable()->LexIdx()); 138 pg->StoreAccumulator(node, ctor); 139 break; 140 } 141 142 classDef = util::Helpers::GetContainingClassDefinition(classDef->Parent()); 143 } while (classDef != nullptr); 144} 145 146void Function::IterateOverElements(const ArenaVector<ir::AstNode *> &elements, PandaGen *pg, VReg &ctor, VReg &thisReg, 147 VReg &computedInstanceFieldsArray) 148{ 149 uint32_t computedInstanceFieldsIndex = 0; 150 for (auto const &element : elements) { 151 if (!element->IsClassProperty()) { 152 continue; 153 } 154 155 const auto *prop = element->AsClassProperty(); 156 157 if ((prop->IsStatic())) { 158 continue; 159 } 160 161 if (prop->IsPrivateElement()) { 162 if (prop->Value() == nullptr) { 163 pg->LoadConst(element, Constant::JS_UNDEFINED); 164 } else { 165 RegScope scopeProp(pg); 166 prop->Value()->Compile(pg); 167 } 168 169 pg->ClassPrivateFieldAdd(prop, ctor, thisReg, prop->Key()->AsIdentifier()->Name()); 170 continue; 171 } 172 173 RegScope keyScope(pg); 174 175 Operand key; 176 if (prop->IsComputed()) { 177 VReg keyReg = pg->AllocReg(); 178 pg->LoadAccumulator(prop, computedInstanceFieldsArray); 179 pg->LoadObjByIndex(prop, computedInstanceFieldsIndex++); 180 pg->StoreAccumulator(prop, keyReg); 181 key = keyReg; 182 } else { 183 key = pg->ToOwnPropertyKey(prop->Key(), false); 184 } 185 186 if (prop->Value() == nullptr) { 187 pg->LoadConst(element, Constant::JS_UNDEFINED); 188 } else { 189 RegScope scopeProp(pg); 190 prop->Value()->Compile(pg); 191 } 192 193 pg->StoreOwnProperty(prop, thisReg, key); 194 } 195} 196 197void Function::CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *decl) 198{ 199 const auto klass = util::Helpers::GetClassDefiniton(decl); 200 const auto &elements = klass->Body(); 201 202 RegScope rs(pg); 203 auto thisReg = pg->AllocReg(); 204 auto ctor = pg->AllocReg(); 205 pg->GetThis(decl); 206 pg->StoreAccumulator(decl, thisReg); 207 pg->GetFunctionObject(decl); 208 pg->StoreAccumulator(decl, ctor); 209 210 VReg computedInstanceFieldsArray {}; 211 212 if (klass->HasPrivateMethod()) { 213 pg->ClassPrivateMethodOrAccessorAdd(decl, ctor, thisReg); 214 } 215 216 if (klass->HasComputedInstanceField()) { 217 computedInstanceFieldsArray = pg->AllocReg(); 218 pg->LoadClassComputedInstanceFields(klass, ctor); 219 pg->StoreAccumulator(klass, computedInstanceFieldsArray); 220 } 221 222 IterateOverElements(elements, pg, ctor, thisReg, computedInstanceFieldsArray); 223} 224 225static void CompileFunction(PandaGen *pg) 226{ 227 const auto *decl = pg->RootNode()->AsScriptFunction(); 228 229 if (decl->IsConstructor() && (util::Helpers::GetClassDefiniton(decl)->Super() == nullptr)) { 230 Function::CompileInstanceFields(pg, decl); 231 } 232 233 auto *funcParamScope = pg->TopScope()->ParamScope(); 234 auto *nameVar = funcParamScope->NameVar(); 235 236 if (nameVar != nullptr) { 237 RegScope rs(pg); 238 pg->GetFunctionObject(pg->RootNode()); 239 pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(nameVar->Name()), true); 240 } 241 242 CompileFunctionParameterDeclaration(pg, decl); 243 244 pg->FunctionEnter(); 245 const ir::AstNode *body = decl->Body(); 246 247 if (body->IsExpression()) { 248 body->Compile(pg); 249 pg->DirectReturn(decl); 250 } else { 251 CompileSourceBlock(pg, body->AsBlockStatement()); 252 } 253 254 pg->FunctionExit(); 255} 256 257void Function::Compile(PandaGen *pg) 258{ 259 FunctionRegScope lrs(pg); 260 auto *topScope = pg->TopScope(); 261 262 if (pg->FunctionHasFinalizer()) { 263 ASSERT(topScope->IsFunctionScope()); 264 265 TryContext tryCtx(pg); 266 pg->FunctionInit(tryCtx.GetCatchTable()); 267 268 CompileFunction(pg); 269 } else { 270 pg->FunctionInit(nullptr); 271 272 if (topScope->IsFunctionScope()) { 273 CompileFunction(pg); 274 } else { 275 ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope()); 276 CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement()); 277 } 278 } 279 280 pg->SortCatchTables(); 281} 282} // namespace ark::es2panda::compiler 283