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