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