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