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