• 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/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 
33 namespace panda::es2panda::compiler {
34 
FindLastStatement(const ir::AstNode * & lastNode,const ir::AstNode * currentNode)35 static 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 
CompileSourceBlock(PandaGen * pg,const ir::BlockStatement * block)47 static 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 
CompileFunctionParameterDeclaration(PandaGen * pg,const ir::ScriptFunction * func)73 static 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 
130         if (param->IsRestElement()) {
131             pg->CopyRestArgs(param, func->Params().size() - 1);
132         } else if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
133             pg->LoadAccumulator(func, paramReg);
134         } else {
135             continue;
136         }
137         ref.SetValue();
138     }
139 }
140 
CompileField(PandaGen * pg,const ir::ClassProperty * prop,VReg thisReg,int32_t level)141 static void CompileField(PandaGen *pg, const ir::ClassProperty *prop, VReg thisReg, int32_t level)
142 {
143     RegScope rs(pg);
144     Operand op;
145     binder::PrivateNameFindResult result;
146     if (prop->IsPrivate()) {
147         result = pg->Scope()->FindPrivateName(prop->Key()->AsPrivateIdentifier()->Name());
148     } else if (prop->IsComputed() && prop->NeedCompileKey()) {
149         auto slot = prop->Parent()->AsClassDefinition()->GetSlot(prop->Key());
150         pg->LoadLexicalVar(prop->Key(), level, slot);
151         op = pg->AllocReg();
152         pg->StoreAccumulator(prop->Key(), std::get<VReg>(op));
153     } else {
154         op = pg->ToPropertyKey(prop->Key(), prop->IsComputed());
155     }
156 
157     if (!prop->Value()) {
158         pg->LoadConst(prop, Constant::JS_UNDEFINED);
159     } else {
160         RegScope rsProp(pg);
161         prop->Value()->Compile(pg);
162     }
163 
164     if (prop->IsPrivate()) {
165         pg->DefineClassPrivateField(prop, result.lexLevel, result.result.slot, thisReg);
166     } else {
167         pg->DefineClassField(prop, thisReg, op);
168     }
169 }
170 
CompileClassInitializer(PandaGen * pg,const ir::ScriptFunction * decl,bool isStatic)171 static void CompileClassInitializer(PandaGen *pg, const ir::ScriptFunction *decl, bool isStatic)
172 {
173     const auto *classDef = decl->Parent()->Parent()->Parent()->AsClassDefinition();
174     const auto &statements = classDef->Body();
175 
176     RegScope rs(pg);
177     auto thisReg = pg->AllocReg();
178     pg->GetThis(decl);
179     pg->StoreAccumulator(decl, thisReg);
180     auto [level, slot] = pg->Scope()->Find(nullptr, true);
181 
182     if (!isStatic && classDef->HasInstancePrivateMethod()) {
183         binder::PrivateNameFindResult result = pg->Scope()->FindPrivateName("#method");
184         pg->LoadConst(classDef, Constant::JS_UNDEFINED);
185         pg->DefineClassPrivateField(classDef, result.lexLevel, result.result.slot, thisReg);
186     }
187     for (auto const &stmt : statements) {
188         if (stmt->IsMethodDefinition()) {
189             continue;
190         }
191 
192         if (stmt->IsClassProperty()) {
193             const auto *prop = stmt->AsClassProperty();
194 
195             // Do not process non-static public fields when not using define semantic.
196             if (!prop->IsPrivate() && !prop->IsStatic() && !pg->Binder()->Program()->UseDefineSemantic()) {
197                 continue;
198             }
199 
200             if (prop->IsStatic() == isStatic) {
201                 CompileField(pg, prop, thisReg, level);
202             }
203             continue;
204         }
205 
206         if (!isStatic) {
207             continue;
208         }
209 
210         ASSERT(stmt->IsClassStaticBlock());
211         const auto *staticBlock = stmt->AsClassStaticBlock();
212         staticBlock->Compile(pg);
213     }
214 }
215 
CompileFunction(PandaGen * pg)216 static void CompileFunction(PandaGen *pg)
217 {
218     const auto *decl = pg->RootNode()->AsScriptFunction();
219 
220     if (decl->IsConstructor()) {
221         const auto *classDef = util::Helpers::GetClassDefiniton(decl);
222         if (classDef->Super() == nullptr && classDef->NeedInstanceInitializer()) {
223             RegScope rs(pg);
224             auto thisReg = pg->AllocReg();
225 
226             pg->GetThis(decl);
227             pg->StoreAccumulator(decl, thisReg);
228 
229             auto [level, slot] = pg->Scope()->Find(classDef->InstanceInitializer()->Key());
230             pg->LoadLexicalVar(decl, level, slot);
231             pg->CallInit(decl, thisReg);
232         }
233     }
234 
235     if (decl->IsStaticInitializer() || decl->IsInstanceInitializer()) {
236         CompileClassInitializer(pg, decl, decl->IsStaticInitializer());
237         pg->ImplicitReturn(decl);
238         return;
239     }
240 
241     auto *funcParamScope = pg->TopScope()->ParamScope();
242     if (funcParamScope->NameVar()) {
243         RegScope rs(pg);
244         pg->GetFunctionObject(pg->RootNode());
245         pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(funcParamScope->NameVar()->Name()), true);
246     }
247 
248     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
249     pg->FunctionEnter();
250     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
251 
252     if (pg->IsAsyncFunction()) {
253         CompileFunctionParameterDeclaration(pg, decl);
254     }
255 
256     const ir::AstNode *body = decl->Body();
257 
258     if (body->IsExpression()) {
259         body->Compile(pg);
260         pg->ExplicitReturn(decl);
261     } else {
262         CompileSourceBlock(pg, body->AsBlockStatement());
263     }
264 
265     pg->FunctionExit();
266 }
267 
CompileFunctionOrProgram(PandaGen * pg)268 static void CompileFunctionOrProgram(PandaGen *pg)
269 {
270     FunctionRegScope lrs(pg);
271     const auto *topScope = pg->TopScope();
272 
273     if (pg->FunctionHasFinalizer()) {
274         ASSERT(topScope->IsFunctionScope() || topScope->IsModuleScope());
275 
276         if (!pg->IsAsyncFunction()) {
277             CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction());
278         }
279 
280         TryContext tryCtx(pg);
281         pg->FunctionInit(tryCtx.GetCatchTable());
282         if (topScope->IsModuleScope()) {
283             pg->FunctionEnter();
284             CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement());
285             pg->FunctionExit();
286             return;
287         }
288         CompileFunction(pg);
289     } else {
290         pg->FunctionInit(nullptr);
291 
292         if (topScope->IsFunctionScope() || topScope->IsTSModuleScope() || topScope->IsTSEnumScope()) {
293             CompileFunctionParameterDeclaration(pg, pg->RootNode()->AsScriptFunction());
294             CompileFunction(pg);
295         } else {
296             ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope());
297             CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement());
298         }
299     }
300 }
301 
Compile(PandaGen * pg)302 void Function::Compile(PandaGen *pg)
303 {
304     pg->SetFunctionKind();
305     CompileFunctionOrProgram(pg);
306     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
307     pg->CopyFunctionArguments(pg->RootNode());
308     pg->InitializeLexEnv(pg->RootNode());
309     pg->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
310     pg->AdjustSpillInsns();
311     pg->SortCatchTables();
312     pg->ReArrangeIc();
313 }
314 
315 }  // namespace panda::es2panda::compiler
316