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