• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/scriptFunction.h>
26 #include <ir/expressions/assignmentExpression.h>
27 #include <ir/expressions/identifier.h>
28 #include <ir/statements/blockStatement.h>
29 #include <ir/ts/tsParameterProperty.h>
30 #include <util/helpers.h>
31 
32 namespace panda::es2panda::compiler {
33 
FindLastStatement(const ir::AstNode * & lastNode,const ir::AstNode * currentNode)34 static void FindLastStatement(const ir::AstNode *&lastNode, const ir::AstNode *currentNode)
35 {
36     if (currentNode->IsStatement()) {
37         if (currentNode->Range().start.index > lastNode->Range().start.index) {
38             lastNode = currentNode;
39         }
40         currentNode->Iterate([&lastNode](auto *childNode) {
41             FindLastStatement(lastNode, childNode);
42         });
43     }
44 }
45 
CompileSourceBlock(PandaGen * pg,const ir::BlockStatement * block)46 static void CompileSourceBlock(PandaGen *pg, const ir::BlockStatement *block)
47 {
48     bool endReturn = false;
49 
50     const auto &statements = block->Statements();
51     pg->SetFirstStmt(statements.empty() ? block : statements.front());
52 
53     for (const auto *stmt : statements) {
54         stmt->Compile(pg);
55 
56         if (stmt->IsReturnStatement() && (stmt == statements[statements.size() - 1])) {
57             endReturn = true;
58         }
59     }
60 
61     if (endReturn) {
62         return;
63     }
64 
65     const ir::AstNode *associatedNode = block;
66     if (!statements.empty()) {
67         FindLastStatement(associatedNode, statements.back());
68     }
69     pg->ImplicitReturn(associatedNode);
70 }
71 
CompileFunctionParameterDeclaration(PandaGen * pg,const ir::ScriptFunction * func)72 static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFunction *func)
73 {
74     ScopeContext scopeCtx(pg, func->Scope()->ParamScope());
75 
76     uint32_t index = 0;
77 
78     for (const auto *it : func->Params()) {
79         auto *param = it;
80         if (param->IsTSParameterProperty()) {
81             param = param->AsTSParameterProperty()->Parameter();
82         }
83         LReference ref = LReference::CreateLRef(pg, param, true);
84 
85         [[maybe_unused]] binder::Variable *paramVar = ref.Variable();
86 
87         if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
88             util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index);
89             paramVar = pg->Scope()->FindLocal(name, binder::ResolveBindingOptions::BINDINGS);
90         }
91 
92         ASSERT(paramVar && paramVar->IsLocalVariable());
93 
94         VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + index++;
95         ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg);
96 
97         // parameter has default value
98         if (param->IsAssignmentPattern()) {
99             RegScope rs(pg);
100 
101             ref.Kind() == ReferenceKind::DESTRUCTURING ?
102                 pg->LoadAccumulator(func, paramReg) : ref.GetValue();
103 
104             auto *nonDefaultLabel = pg->AllocLabel();
105 
106             if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
107                 auto *loadParamLabel = pg->AllocLabel();
108 
109                 pg->BranchIfStrictNotUndefined(func, loadParamLabel);
110                 param->AsAssignmentPattern()->Right()->Compile(pg);
111                 pg->Branch(func, nonDefaultLabel);
112 
113                 pg->SetLabel(func, loadParamLabel);
114                 pg->LoadAccumulator(func, paramReg);
115 
116                 pg->SetLabel(func, nonDefaultLabel);
117                 ref.SetValue();
118             } else {
119                 pg->BranchIfStrictNotUndefined(func, nonDefaultLabel);
120 
121                 param->AsAssignmentPattern()->Right()->Compile(pg);
122                 ref.SetValue();
123                 pg->SetLabel(func, nonDefaultLabel);
124             }
125 
126             continue;
127         }
128 
129         if (param->IsRestElement()) {
130             pg->CopyRestArgs(param, func->Params().size() - 1);
131         } else if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
132             pg->LoadAccumulator(func, paramReg);
133         } else {
134             continue;
135         }
136         ref.SetValue();
137     }
138 }
139 
CompileInstanceFields(PandaGen * pg,const ir::ScriptFunction * decl)140 static void CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *decl)
141 {
142     const auto &statements = decl->Parent()->Parent()->Parent()->AsClassDefinition()->Body();
143 
144     RegScope rs(pg);
145     auto thisReg = pg->AllocReg();
146     pg->GetThis(decl);
147     pg->StoreAccumulator(decl, thisReg);
148 
149     for (auto const &stmt : statements) {
150         if (stmt->IsClassProperty()) {
151             const auto *prop = stmt->AsClassProperty();
152             if (prop->IsStatic()) {
153                 continue;
154             }
155             if (!prop->Value()) {
156                 pg->LoadConst(stmt, Constant::JS_UNDEFINED);
157             } else {
158                 RegScope rsProp(pg);
159                 prop->Value()->Compile(pg);
160             }
161 
162             if (!prop->Key()->IsIdentifier()) {
163                 PandaGen::Unimplemented();
164             }
165 
166             pg->StoreObjByName(stmt, thisReg, prop->Key()->AsIdentifier()->Name());
167         }
168     }
169 }
170 
CompileFunction(PandaGen * pg)171 static void CompileFunction(PandaGen *pg)
172 {
173     const auto *decl = pg->RootNode()->AsScriptFunction();
174 
175     // TODO(szilagyia): move after super call
176     if (decl->IsConstructor() && pg->Binder()->Program()->Extension() != ScriptExtension::TS) {
177         CompileInstanceFields(pg, decl);
178     }
179 
180     auto *funcParamScope = pg->TopScope()->ParamScope();
181     if (funcParamScope->NameVar()) {
182         RegScope rs(pg);
183         pg->GetFunctionObject(pg->RootNode());
184         pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(funcParamScope->NameVar()->Name()), true);
185     }
186 
187     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
188     pg->FunctionEnter();
189     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
190 
191     if (pg->IsAsyncFunction()) {
192         CompileFunctionParameterDeclaration(pg, decl);
193     }
194 
195     const ir::AstNode *body = decl->Body();
196 
197     if (body->IsExpression()) {
198         body->Compile(pg);
199         pg->ExplicitReturn(decl);
200     } else {
201         CompileSourceBlock(pg, body->AsBlockStatement());
202     }
203 
204     pg->FunctionExit();
205 }
206 
CompileFunctionOrProgram(PandaGen * pg)207 static void CompileFunctionOrProgram(PandaGen *pg)
208 {
209     FunctionRegScope lrs(pg);
210     const auto *topScope = pg->TopScope();
211 
212     if (pg->FunctionHasFinalizer()) {
213         ASSERT(topScope->IsFunctionScope());
214 
215         if (!pg->IsAsyncFunction()) {
216             CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction());
217         }
218 
219         TryContext tryCtx(pg);
220         pg->FunctionInit(tryCtx.GetCatchTable());
221 
222         CompileFunction(pg);
223     } else {
224         pg->FunctionInit(nullptr);
225 
226         if (topScope->IsFunctionScope() || topScope->IsTSModuleScope() || topScope->IsTSEnumScope()) {
227             CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction());
228             CompileFunction(pg);
229         } else {
230             ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope());
231             CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement());
232         }
233     }
234 }
235 
Compile(PandaGen * pg)236 void Function::Compile(PandaGen *pg)
237 {
238     pg->SetFunctionKind();
239     CompileFunctionOrProgram(pg);
240     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
241     pg->CopyFunctionArguments(pg->RootNode());
242     pg->InitializeLexEnv(pg->RootNode());
243     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
244     pg->AdjustSpillInsns();
245     pg->SortCatchTables();
246 }
247 
248 }  // namespace panda::es2panda::compiler
249