• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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