1 /**
2 * Copyright (c) 2021-2024 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 "varbinder/varbinder.h"
19 #include "util/helpers.h"
20 #include "varbinder/scope.h"
21 #include "varbinder/variable.h"
22 #include "compiler/base/lreference.h"
23 #include "compiler/core/pandagen.h"
24 #include "ir/base/classDefinition.h"
25 #include "ir/base/classProperty.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
31 namespace ark::es2panda::compiler {
CompileSourceBlock(PandaGen * pg,const ir::BlockStatement * block)32 static void CompileSourceBlock(PandaGen *pg, const ir::BlockStatement *block)
33 {
34 const auto &statements = block->Statements();
35 if (statements.empty()) {
36 pg->SetFirstStmt(block);
37 pg->ImplicitReturn(block);
38 return;
39 }
40
41 pg->SetFirstStmt(statements.front());
42
43 for (const auto *stmt : statements) {
44 stmt->Compile(pg);
45 }
46
47 switch (statements.back()->Type()) {
48 case ir::AstNodeType::RETURN_STATEMENT: {
49 return;
50 }
51 case ir::AstNodeType::VARIABLE_DECLARATION:
52 case ir::AstNodeType::FUNCTION_DECLARATION:
53 case ir::AstNodeType::STRUCT_DECLARATION:
54 case ir::AstNodeType::CLASS_DECLARATION: {
55 pg->ImplicitReturn(statements.back());
56 break;
57 }
58 default: {
59 if (pg->IsEval()) {
60 pg->DirectReturn(statements.back());
61 } else {
62 pg->ImplicitReturn(statements.back());
63 }
64 }
65 }
66 }
67
CompileFunctionParameterDeclaration(PandaGen * pg,const ir::ScriptFunction * func)68 static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFunction *func)
69 {
70 ScopeContext scopeCtx(pg, func->Scope()->ParamScope());
71
72 uint32_t index = 0;
73
74 for (const auto *param : func->Params()) {
75 auto ref = JSLReference::Create(pg, param, true);
76
77 [[maybe_unused]] varbinder::Variable *paramVar = ref.Variable();
78
79 if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
80 util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index);
81 paramVar = pg->Scope()->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
82 }
83
84 ASSERT(paramVar && paramVar->IsLocalVariable());
85
86 VReg paramReg = VReg(varbinder::VarBinder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++);
87 ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg);
88
89 if (param->IsAssignmentPattern()) {
90 RegScope rs(pg);
91 pg->LoadAccumulator(func, paramReg);
92 auto *nonDefaultLabel = pg->AllocLabel();
93
94 if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
95 auto *loadParamLabel = pg->AllocLabel();
96
97 pg->BranchIfNotUndefined(func, loadParamLabel);
98 param->AsAssignmentPattern()->Right()->Compile(pg);
99 pg->Branch(func, nonDefaultLabel);
100
101 pg->SetLabel(func, loadParamLabel);
102 pg->LoadAccumulator(func, paramReg);
103
104 pg->SetLabel(func, nonDefaultLabel);
105 ref.SetValue();
106 } else {
107 pg->BranchIfNotUndefined(func, nonDefaultLabel);
108
109 param->AsAssignmentPattern()->Right()->Compile(pg);
110 ref.SetValue();
111 pg->SetLabel(func, nonDefaultLabel);
112 }
113
114 continue;
115 }
116
117 if (param->IsRestElement()) {
118 pg->CopyRestArgs(param, func->Params().size() - 1);
119 } else if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
120 pg->LoadAccumulator(func, paramReg);
121 } else {
122 continue;
123 }
124 ref.SetValue();
125 }
126 }
127
LoadClassContexts(const ir::AstNode * node,PandaGen * pg,VReg ctor,const util::StringView & name)128 void Function::LoadClassContexts(const ir::AstNode *node, PandaGen *pg, VReg ctor, const util::StringView &name)
129 {
130 auto *classDef = util::Helpers::GetContainingClassDefinition(node);
131
132 do {
133 auto res = pg->Scope()->Find(classDef->PrivateId());
134 ASSERT(res.variable);
135
136 if (classDef->HasMatchingPrivateKey(name)) {
137 pg->LoadLexicalVar(node, res.lexLevel, res.variable->AsLocalVariable()->LexIdx());
138 pg->StoreAccumulator(node, ctor);
139 break;
140 }
141
142 classDef = util::Helpers::GetContainingClassDefinition(classDef->Parent());
143 } while (classDef != nullptr);
144 }
145
IterateOverElements(const ArenaVector<ir::AstNode * > & elements,PandaGen * pg,VReg & ctor,VReg & thisReg,VReg & computedInstanceFieldsArray)146 void Function::IterateOverElements(const ArenaVector<ir::AstNode *> &elements, PandaGen *pg, VReg &ctor, VReg &thisReg,
147 VReg &computedInstanceFieldsArray)
148 {
149 uint32_t computedInstanceFieldsIndex = 0;
150 for (auto const &element : elements) {
151 if (!element->IsClassProperty()) {
152 continue;
153 }
154
155 const auto *prop = element->AsClassProperty();
156
157 if ((prop->IsStatic())) {
158 continue;
159 }
160
161 if (prop->IsPrivateElement()) {
162 if (prop->Value() == nullptr) {
163 pg->LoadConst(element, Constant::JS_UNDEFINED);
164 } else {
165 RegScope scopeProp(pg);
166 prop->Value()->Compile(pg);
167 }
168
169 pg->ClassPrivateFieldAdd(prop, ctor, thisReg, prop->Key()->AsIdentifier()->Name());
170 continue;
171 }
172
173 RegScope keyScope(pg);
174
175 Operand key;
176 if (prop->IsComputed()) {
177 VReg keyReg = pg->AllocReg();
178 pg->LoadAccumulator(prop, computedInstanceFieldsArray);
179 pg->LoadObjByIndex(prop, computedInstanceFieldsIndex++);
180 pg->StoreAccumulator(prop, keyReg);
181 key = keyReg;
182 } else {
183 key = pg->ToOwnPropertyKey(prop->Key(), false);
184 }
185
186 if (prop->Value() == nullptr) {
187 pg->LoadConst(element, Constant::JS_UNDEFINED);
188 } else {
189 RegScope scopeProp(pg);
190 prop->Value()->Compile(pg);
191 }
192
193 pg->StoreOwnProperty(prop, thisReg, key);
194 }
195 }
196
CompileInstanceFields(PandaGen * pg,const ir::ScriptFunction * decl)197 void Function::CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *decl)
198 {
199 const auto klass = util::Helpers::GetClassDefiniton(decl);
200 const auto &elements = klass->Body();
201
202 RegScope rs(pg);
203 auto thisReg = pg->AllocReg();
204 auto ctor = pg->AllocReg();
205 pg->GetThis(decl);
206 pg->StoreAccumulator(decl, thisReg);
207 pg->GetFunctionObject(decl);
208 pg->StoreAccumulator(decl, ctor);
209
210 VReg computedInstanceFieldsArray {};
211
212 if (klass->HasPrivateMethod()) {
213 pg->ClassPrivateMethodOrAccessorAdd(decl, ctor, thisReg);
214 }
215
216 if (klass->HasComputedInstanceField()) {
217 computedInstanceFieldsArray = pg->AllocReg();
218 pg->LoadClassComputedInstanceFields(klass, ctor);
219 pg->StoreAccumulator(klass, computedInstanceFieldsArray);
220 }
221
222 IterateOverElements(elements, pg, ctor, thisReg, computedInstanceFieldsArray);
223 }
224
CompileFunction(PandaGen * pg)225 static void CompileFunction(PandaGen *pg)
226 {
227 const auto *decl = pg->RootNode()->AsScriptFunction();
228
229 if (decl->IsConstructor() && (util::Helpers::GetClassDefiniton(decl)->Super() == nullptr)) {
230 Function::CompileInstanceFields(pg, decl);
231 }
232
233 auto *funcParamScope = pg->TopScope()->ParamScope();
234 auto *nameVar = funcParamScope->NameVar();
235
236 if (nameVar != nullptr) {
237 RegScope rs(pg);
238 pg->GetFunctionObject(pg->RootNode());
239 pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(nameVar->Name()), true);
240 }
241
242 CompileFunctionParameterDeclaration(pg, decl);
243
244 pg->FunctionEnter();
245 const ir::AstNode *body = decl->Body();
246
247 if (body->IsExpression()) {
248 body->Compile(pg);
249 pg->DirectReturn(decl);
250 } else {
251 CompileSourceBlock(pg, body->AsBlockStatement());
252 }
253
254 pg->FunctionExit();
255 }
256
Compile(PandaGen * pg)257 void Function::Compile(PandaGen *pg)
258 {
259 FunctionRegScope lrs(pg);
260 auto *topScope = pg->TopScope();
261
262 if (pg->FunctionHasFinalizer()) {
263 ASSERT(topScope->IsFunctionScope());
264
265 TryContext tryCtx(pg);
266 pg->FunctionInit(tryCtx.GetCatchTable());
267
268 CompileFunction(pg);
269 } else {
270 pg->FunctionInit(nullptr);
271
272 if (topScope->IsFunctionScope()) {
273 CompileFunction(pg);
274 } else {
275 ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope());
276 CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement());
277 }
278 }
279
280 pg->SortCatchTables();
281 }
282 } // namespace ark::es2panda::compiler
283