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 "function.h" 17 18#include <binder/binder.h> 19#include <binder/scope.h> 20#include <binder/variable.h> 21#include <compiler/base/lreference.h> 22#include <compiler/core/pandagen.h> 23#include <ir/base/classDefinition.h> 24#include <ir/base/classProperty.h> 25#include <ir/base/classStaticBlock.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#include <ir/ts/tsParameterProperty.h> 31#include <util/helpers.h> 32 33namespace panda::es2panda::compiler { 34 35static void FindLastStatement(const ir::AstNode *&lastNode, const ir::AstNode *currentNode) 36{ 37 if (currentNode->IsStatement()) { 38 if (currentNode->Range().start.index > lastNode->Range().start.index) { 39 lastNode = currentNode; 40 } 41 currentNode->Iterate([&lastNode](auto *childNode) { 42 FindLastStatement(lastNode, childNode); 43 }); 44 } 45} 46 47static void CompileSourceBlock(PandaGen *pg, const ir::BlockStatement *block) 48{ 49 bool endReturn = false; 50 51 const auto &statements = block->Statements(); 52 pg->SetFirstStmt(statements.empty() ? block : statements.front()); 53 54 for (const auto *stmt : statements) { 55 stmt->Compile(pg); 56 57 if (stmt->IsReturnStatement() && (stmt == statements[statements.size() - 1])) { 58 endReturn = true; 59 } 60 } 61 62 if (endReturn) { 63 return; 64 } 65 66 const ir::AstNode *associatedNode = block; 67 if (!statements.empty()) { 68 FindLastStatement(associatedNode, statements.back()); 69 } 70 pg->ImplicitReturn(associatedNode); 71} 72 73static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFunction *func) 74{ 75 ScopeContext scopeCtx(pg, func->Scope()->ParamScope()); 76 77 uint32_t index = 0; 78 79 for (const auto *it : func->Params()) { 80 auto *param = it; 81 if (param->IsTSParameterProperty()) { 82 param = param->AsTSParameterProperty()->Parameter(); 83 } 84 LReference ref = LReference::CreateLRef(pg, param, true); 85 86 [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); 87 88 if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 89 util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index); 90 paramVar = pg->Scope()->FindLocal(name, binder::ResolveBindingOptions::BINDINGS); 91 } 92 93 ASSERT(paramVar && paramVar->IsLocalVariable()); 94 95 VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + index++; 96 ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg); 97 98 // parameter has default value 99 if (param->IsAssignmentPattern()) { 100 RegScope rs(pg); 101 102 ref.Kind() == ReferenceKind::DESTRUCTURING ? 103 pg->LoadAccumulator(func, paramReg) : ref.GetValue(); 104 105 auto *nonDefaultLabel = pg->AllocLabel(); 106 107 if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 108 auto *loadParamLabel = pg->AllocLabel(); 109 110 pg->BranchIfStrictNotUndefined(func, loadParamLabel); 111 param->AsAssignmentPattern()->Right()->Compile(pg); 112 pg->Branch(func, nonDefaultLabel); 113 114 pg->SetLabel(func, loadParamLabel); 115 pg->LoadAccumulator(func, paramReg); 116 117 pg->SetLabel(func, nonDefaultLabel); 118 ref.SetValue(); 119 } else { 120 pg->BranchIfStrictNotUndefined(func, nonDefaultLabel); 121 122 param->AsAssignmentPattern()->Right()->Compile(pg); 123 ref.SetValue(); 124 pg->SetLabel(func, nonDefaultLabel); 125 } 126 127 continue; 128 } 129 // There's extra optimization for super call in default constuctor since api13, 130 // no need to generate copyrestargs in this scene. 131 if (param->IsRestElement() && (!func->HasFlag(ir::ScriptFunctionFlags::GENERATED_CONSTRUCTOR) || 132 pg->Binder()->Program()->TargetApiVersion() < util::Helpers::SUPER_CALL_OPT_MIN_SUPPORTED_API_VERSION)) { 133 pg->CopyRestArgs(param, func->Params().size() - 1); 134 } else if (ref.Kind() == ReferenceKind::DESTRUCTURING) { 135 pg->LoadAccumulator(func, paramReg); 136 } else { 137 continue; 138 } 139 ref.SetValue(); 140 } 141} 142 143static void CompileField(PandaGen *pg, const ir::ClassProperty *prop, VReg thisReg, int32_t level) 144{ 145 RegScope rs(pg); 146 Operand op; 147 binder::PrivateNameFindResult result; 148 if (prop->IsPrivate()) { 149 result = pg->Scope()->FindPrivateName(prop->Key()->AsPrivateIdentifier()->Name()); 150 } else if (prop->IsComputed() && prop->NeedCompileKey()) { 151 auto slot = prop->Parent()->AsClassDefinition()->GetSlot(prop->Key()); 152 pg->LoadLexicalVar(prop->Key(), level, slot); 153 op = pg->AllocReg(); 154 pg->StoreAccumulator(prop->Key(), std::get<VReg>(op)); 155 } else { 156 op = pg->ToPropertyKey(prop->Key(), prop->IsComputed()); 157 } 158 159 if (!prop->Value()) { 160 pg->LoadConst(prop, Constant::JS_UNDEFINED); 161 } else { 162 RegScope rsProp(pg); 163 prop->Value()->Compile(pg); 164 } 165 166 if (prop->IsPrivate()) { 167 pg->DefineClassPrivateField(prop, result.lexLevel, result.result.slot, thisReg); 168 } else { 169 pg->DefineOwnProperty(prop, thisReg, op); 170 } 171} 172 173static void CompileClassInitializer(PandaGen *pg, const ir::ScriptFunction *decl, bool isStatic) 174{ 175 const auto *classDef = decl->Parent()->Parent()->Parent()->AsClassDefinition(); 176 const auto &statements = classDef->Body(); 177 178 RegScope rs(pg); 179 auto thisReg = pg->AllocReg(); 180 pg->GetThis(decl); 181 pg->StoreAccumulator(decl, thisReg); 182 auto [level, slot] = pg->Scope()->Find(nullptr, true); 183 184 if (!isStatic && classDef->HasInstancePrivateMethod()) { 185 binder::PrivateNameFindResult result = pg->Scope()->FindPrivateName("#method"); 186 pg->LoadConst(classDef, Constant::JS_UNDEFINED); 187 pg->DefineClassPrivateField(classDef, result.lexLevel, result.result.slot, thisReg); 188 } 189 for (auto const &stmt : statements) { 190 if (stmt->IsMethodDefinition()) { 191 continue; 192 } 193 194 if (stmt->IsClassProperty()) { 195 const auto *prop = stmt->AsClassProperty(); 196 197 // Do not process non-static public fields when not using define semantic. 198 if (!prop->IsPrivate() && !prop->IsStatic() && !pg->Binder()->Program()->UseDefineSemantic()) { 199 continue; 200 } 201 202 if (prop->IsStatic() == isStatic) { 203 CompileField(pg, prop, thisReg, level); 204 } 205 continue; 206 } 207 208 if (!isStatic) { 209 continue; 210 } 211 212 ASSERT(stmt->IsClassStaticBlock()); 213 const auto *staticBlock = stmt->AsClassStaticBlock(); 214 staticBlock->Compile(pg); 215 } 216} 217 218static void CompileFunction(PandaGen *pg) 219{ 220 const auto *decl = pg->RootNode()->AsScriptFunction(); 221 222 if (decl->IsConstructor()) { 223 const auto *classDef = util::Helpers::GetClassDefiniton(decl); 224 if (classDef->Super() == nullptr && classDef->NeedInstanceInitializer()) { 225 RegScope rs(pg); 226 auto thisReg = pg->AllocReg(); 227 228 pg->GetThis(decl); 229 pg->StoreAccumulator(decl, thisReg); 230 231 auto [level, slot] = pg->Scope()->Find(classDef->InstanceInitializer()->Key()); 232 pg->LoadLexicalVar(decl, level, slot); 233 pg->CallInit(decl, thisReg); 234 } 235 } 236 237 if (decl->IsStaticInitializer() || decl->IsInstanceInitializer()) { 238 CompileClassInitializer(pg, decl, decl->IsStaticInitializer()); 239 pg->ImplicitReturn(decl); 240 return; 241 } 242 243 auto *funcParamScope = pg->TopScope()->ParamScope(); 244 if (funcParamScope->NameVar()) { 245 RegScope rs(pg); 246 pg->GetFunctionObject(pg->RootNode()); 247 pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(funcParamScope->NameVar()->Name()), true); 248 } 249 250 pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION); 251 pg->FunctionEnter(); 252 pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION); 253 254 if (pg->IsAsyncFunction()) { 255 CompileFunctionParameterDeclaration(pg, decl); 256 } 257 258 const ir::AstNode *body = decl->Body(); 259 260 if (body->IsExpression()) { 261 body->Compile(pg); 262 pg->ExplicitReturn(decl); 263 } else { 264 CompileSourceBlock(pg, body->AsBlockStatement()); 265 } 266 267 pg->FunctionExit(); 268} 269 270static void CompileFunctionOrProgram(PandaGen *pg) 271{ 272 FunctionRegScope lrs(pg); 273 const auto *topScope = pg->TopScope(); 274 275 if (pg->FunctionHasFinalizer()) { 276 ASSERT(topScope->IsFunctionScope() || topScope->IsModuleScope()); 277 278 if (!pg->IsAsyncFunction()) { 279 CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction()); 280 } 281 282 TryContext tryCtx(pg); 283 pg->FunctionInit(tryCtx.GetCatchTable()); 284 if (topScope->IsModuleScope()) { 285 pg->FunctionEnter(); 286 CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement()); 287 pg->FunctionExit(); 288 return; 289 } 290 CompileFunction(pg); 291 } else { 292 pg->FunctionInit(nullptr); 293 294 if (topScope->IsFunctionScope() || topScope->IsTSModuleScope() || topScope->IsTSEnumScope()) { 295 CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction()); 296 CompileFunction(pg); 297 } else { 298 ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope()); 299 CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement()); 300 } 301 } 302} 303 304void Function::Compile(PandaGen *pg) 305{ 306 pg->SetFunctionKind(); 307 pg->SetInSendable(); 308 CompileFunctionOrProgram(pg); 309 pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION); 310 pg->CopyFunctionArguments(pg->RootNode()); 311 pg->InitializeLexEnv(pg->RootNode()); 312 pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION); 313 pg->AdjustSpillInsns(); 314 pg->SortCatchTables(); 315 pg->ReArrangeIc(); 316} 317 318} // namespace panda::es2panda::compiler 319