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 "functionBuilder.h"
17
18 #include <binder/binder.h>
19 #include <compiler/base/iterators.h>
20 #include <compiler/core/pandagen.h>
21 #include <ir/base/classDefinition.h>
22 #include <ir/base/scriptFunction.h>
23 #include <ir/statement.h>
24 #include <util/helpers.h>
25
26 namespace panda::es2panda::compiler {
27
FunctionBuilder(PandaGen * pg,CatchTable * catchTable)28 FunctionBuilder::FunctionBuilder(PandaGen *pg, CatchTable *catchTable)
29 : pg_(pg), catchTable_(catchTable), funcObj_(pg_->AllocReg())
30 {
31 }
32
GeneratorKind() const33 IteratorType FunctionBuilder::GeneratorKind() const
34 {
35 return IteratorType::SYNC;
36 }
37
DirectReturn(const ir::AstNode * node) const38 void FunctionBuilder::DirectReturn(const ir::AstNode *node) const
39 {
40 pg_->NotifyConcurrentResult(node);
41 pg_->EmitReturn(node);
42 }
43
ImplicitReturn(const ir::AstNode * node) const44 void FunctionBuilder::ImplicitReturn(const ir::AstNode *node) const
45 {
46 const auto *rootNode = pg_->RootNode();
47 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
48 if (!rootNode->IsScriptFunction() || !rootNode->AsScriptFunction()->IsConstructor()) {
49 if (pg_->isDebuggerEvaluateExpressionMode() && rootNode->IsProgram()) {
50 pg_->NotifyConcurrentResult(node);
51 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
52 pg_->EmitReturn(node);
53 return;
54 }
55 pg_->LoadConst(node, Constant::JS_UNDEFINED);
56 pg_->NotifyConcurrentResult(node);
57 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
58 pg_->EmitReturnUndefined(node);
59 return;
60 }
61
62 pg_->GetThis(node);
63 if (rootNode->AsScriptFunction()->IsConstructor() &&
64 util::Helpers::GetClassDefiniton(rootNode->AsScriptFunction())->Super()) {
65 pg_->ThrowIfSuperNotCorrectCall(node, 0);
66 }
67
68 pg_->NotifyConcurrentResult(node);
69 pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
70 pg_->EmitReturn(node);
71 }
72
ExplicitReturn(const ir::AstNode * node) const73 void FunctionBuilder::ExplicitReturn(const ir::AstNode *node) const
74 {
75 DirectReturn(node);
76 }
77
AsyncYield(const ir::AstNode * node,VReg value,VReg completionType,VReg completionValue) const78 void FunctionBuilder::AsyncYield(const ir::AstNode *node, VReg value, VReg completionType, VReg completionValue) const
79 {
80 ASSERT(BuilderKind() == BuilderType::ASYNC_GENERATOR);
81 RegScope rs(pg_);
82 VReg done = pg_->AllocReg();
83 // 27.6.3.8.6 Set generator.[[AsyncGeneratorState]] to suspendedYield.
84 pg_->GeneratorYield(node, funcObj_);
85 /** 27.6.3.8.7 Remove genContext from the execution context stack and restore the execution context that
86 * is at the top of the execution context stack as the running execution context.
87 * 27.6.3.8.9 Return ! AsyncGeneratorResolve(generator, value, false).
88 */
89 pg_->StoreConst(node, done, Constant::JS_FALSE);
90 pg_->AsyncGeneratorResolve(node, funcObj_, value, done);
91
92 resumeGenerator(node, completionType, completionValue);
93 }
94
SuspendResumeExecution(const ir::AstNode * node,VReg completionType,VReg completionValue) const95 void FunctionBuilder::SuspendResumeExecution(const ir::AstNode *node, VReg completionType, VReg completionValue) const
96 {
97 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR ||
98 BuilderKind() == BuilderType::GENERATOR);
99
100 pg_->SuspendGenerator(node, funcObj_); // iterResult is in acc
101 resumeGenerator(node, completionType, completionValue);
102 }
103
resumeGenerator(const ir::AstNode * node,VReg completionType,VReg completionValue) const104 void FunctionBuilder::resumeGenerator(const ir::AstNode *node, VReg completionType, VReg completionValue) const
105 {
106 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR ||
107 BuilderKind() == BuilderType::GENERATOR);
108
109 pg_->ResumeGenerator(node, funcObj_);
110 pg_->StoreAccumulator(node, completionValue);
111 pg_->GetResumeMode(node, funcObj_);
112 pg_->StoreAccumulator(node, completionType);
113 }
114
FunctionReg(const ir::ScriptFunction * node) const115 VReg FunctionBuilder::FunctionReg(const ir::ScriptFunction *node) const
116 {
117 binder::FunctionScope *scope = node->Scope();
118 auto res = scope->Find(binder::Binder::MANDATORY_PARAM_FUNC);
119 ASSERT(res.level == 0 && res.variable->IsLocalVariable());
120 return res.variable->AsLocalVariable()->Vreg();
121 }
122
Await(const ir::AstNode * node)123 void FunctionBuilder::Await(const ir::AstNode *node)
124 {
125 if (BuilderKind() == BuilderType::NORMAL) {
126 PandaGen::Unimplemented();
127 }
128
129 ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR);
130
131 RegScope rs(pg_);
132 VReg completionType = pg_->AllocReg();
133 VReg completionValue = pg_->AllocReg();
134
135 pg_->AsyncFunctionAwait(node, funcObj_);
136 SuspendResumeExecution(node, completionType, completionValue);
137
138 HandleCompletion(node, completionType, completionValue);
139 }
140
HandleCompletion(const ir::AstNode * node,VReg completionType,VReg completionValue)141 void FunctionBuilder::HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue)
142 {
143 if (BuilderKind() == BuilderType::GENERATOR) {
144 // .return(value)
145 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
146
147 auto *notRetLabel = pg_->AllocLabel();
148 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notRetLabel);
149 if (!handleReturn_) {
150 handleReturn_ = true;
151 pg_->ControlFlowChangeReturn();
152 handleReturn_ = false;
153 }
154
155 pg_->LoadAccumulator(node, completionValue);
156 pg_->DirectReturn(node);
157
158 // .throw(value)
159 pg_->SetLabel(node, notRetLabel);
160 }
161
162 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
163
164 auto *not_throw_label = pg_->AllocLabel();
165 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, not_throw_label);
166 pg_->LoadAccumulator(node, completionValue);
167 pg_->EmitThrow(node);
168
169 // .next(value)
170 pg_->SetLabel(node, not_throw_label);
171 pg_->LoadAccumulator(node, completionValue);
172 }
173
YieldStar(const ir::AstNode * node)174 void FunctionBuilder::YieldStar(const ir::AstNode *node)
175 {
176 ASSERT(BuilderKind() == BuilderType::GENERATOR || BuilderKind() == BuilderType::ASYNC_GENERATOR);
177
178 RegScope rs(pg_);
179
180 auto *loopStart = pg_->AllocLabel();
181 auto *returnCompletion = pg_->AllocLabel();
182 auto *throwCompletion = pg_->AllocLabel();
183 auto *callMethod = pg_->AllocLabel();
184 auto *normalOrThrowCompletion = pg_->AllocLabel();
185 auto *iteratorComplete = pg_->AllocLabel();
186
187 // 4. Let iteratorRecord be ? GetIterator(value, generatorKind).
188 Iterator iterator(pg_, node, GeneratorKind());
189
190 // 6. Let received be NormalCompletion(undefined).
191 VReg receivedValue = iterator.NextResult();
192 VReg receivedType = pg_->AllocReg();
193 VReg nextMethod = pg_->AllocReg();
194 VReg exitReturn = pg_->AllocReg();
195 VReg iterValue = pg_->AllocReg();
196
197 pg_->StoreConst(node, receivedValue, Constant::JS_UNDEFINED);
198 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT));
199 pg_->StoreAccumulator(node, receivedType);
200 pg_->MoveVreg(node, nextMethod, iterator.Method());
201
202 // 7. Repeat
203 pg_->SetLabel(node, loopStart);
204 pg_->StoreConst(node, exitReturn, Constant::JS_FALSE);
205
206 // a. If received.[[Type]] is normal, then
207 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT));
208 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, throwCompletion);
209 pg_->MoveVreg(node, iterator.Method(), nextMethod);
210 pg_->Branch(node, callMethod);
211
212 // b. Else if received.[[Type]] is throw, then
213 pg_->SetLabel(node, throwCompletion);
214 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
215 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, returnCompletion);
216
217 // i. Let throw be ? GetMethod(iterator, "throw").
218 iterator.GetMethod("throw");
219
220 // ii. If throw is not undefined, then
221 pg_->BranchIfNotUndefined(node, callMethod);
222
223 // iii. Else,
224 // 1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we
225 // need to give iterator a chance to clean up.
226 // 2. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
227 // 3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion).
228 // 4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion).
229 iterator.Close(false);
230 // 5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does
231 // not have a throw method.
232 // 6. Throw a TypeError exception.
233 pg_->ThrowThrowNotExist(node);
234
235 // c. Else,
236 // i. Assert: received.[[Type]] is return.
237 pg_->SetLabel(node, returnCompletion);
238 pg_->StoreConst(node, exitReturn, Constant::JS_TRUE);
239 // ii. Let return be ? GetMethod(iterator, "return").
240 iterator.GetMethod("return");
241
242 // iii. If return is undefined, then
243 pg_->BranchIfNotUndefined(node, callMethod);
244
245 // 1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]).
246 pg_->ControlFlowChangeReturn();
247 pg_->LoadAccumulator(node, receivedValue);
248
249 if (GeneratorKind() == IteratorType::ASYNC) {
250 Await(node);
251 }
252
253 // 2. Return Completion(received).
254 pg_->DirectReturn(node);
255
256 pg_->SetLabel(node, callMethod);
257 // i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
258 // 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
259 // iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
260 iterator.CallMethodWithValue();
261
262 // ii. ii. If generatorKind is async, set innerResult to ? Await(innerResult).
263 // 2. If generatorKind is async, set innerResult to ? Await(innerResult).
264 // v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
265 if (GeneratorKind() == IteratorType::ASYNC) {
266 Await(node);
267 }
268
269 pg_->StoreAccumulator(node, receivedValue);
270
271 // ii. If Type(innerResult) is not Object, throw a TypeError exception.
272 // 4. If Type(innerResult) is not Object, throw a TypeError exception.
273 // vi. If Type(innerReturnResult) is not Object, throw a TypeError exception.
274 pg_->ThrowIfNotObject(node, receivedValue);
275
276 // iv. Let done be ? IteratorComplete(innerResult).
277 // v. Let done be ? IteratorComplete(innerResult).
278 // vii. Let done be ? IteratorComplete(innerReturnResult).
279 iterator.Complete();
280 pg_->BranchIfTrue(node, iteratorComplete);
281
282 pg_->LoadAccumulator(node, receivedValue);
283 // vi. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
284 // 7. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
285 // ix. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerReturnResult)).
286 if (GeneratorKind() == IteratorType::ASYNC) {
287 iterator.Value();
288 // 27.6.3.8 AsyncGeneratorYield
289 // 5. Set value to ? Await(value).
290 Await(node);
291 // 6. Set generator.[[AsyncGeneratorState]] to suspendedYield.
292 pg_->StoreAccumulator(node, iterValue);
293 AsyncYield(node, iterValue, receivedType, receivedValue);
294
295 // a. If resumptionValue.[[Type]] is not return
296 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
297 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, receivedType, loopStart);
298
299 // b. Let awaited be Await(resumptionValue.[[Value]]).
300 pg_->LoadAccumulator(node, receivedValue);
301 pg_->AsyncFunctionAwait(node, funcObj_);
302 SuspendResumeExecution(node, receivedType, receivedValue);
303
304 // c. If awaited.[[Type]] is throw, return Completion(awaited).
305 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
306 // d. Assert: awaited.[[Type]] is normal.
307 // e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
308 pg_->Condition(node, lexer::TokenType::PUNCTUATOR_NOT_EQUAL, receivedType, loopStart);
309 pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
310 pg_->StoreAccumulator(node, receivedType);
311 } else {
312 // vii. Else, set received to GeneratorYield(innerResult).
313 // 8. Else, set received to GeneratorYield(innerResult).
314 // x. Else, set received to GeneratorYield(innerReturnResult).
315 SuspendResumeExecution(node, receivedType, receivedValue);
316 }
317
318 pg_->Branch(node, loopStart);
319
320 // v. If done is true, then
321 // 6. If done is true, then
322 // viii. If done is true, then
323 pg_->SetLabel(node, iteratorComplete);
324
325 pg_->LoadAccumulator(node, exitReturn);
326 pg_->BranchIfFalse(node, normalOrThrowCompletion);
327
328 // 1. Let value be ? IteratorValue(innerReturnResult).
329 iterator.Value();
330
331 if (pg_->CheckControlFlowChange()) {
332 pg_->StoreAccumulator(node, receivedValue);
333 pg_->ControlFlowChangeReturn();
334 pg_->LoadAccumulator(node, receivedValue);
335 }
336
337 // 2. Return Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
338 pg_->DirectReturn(node);
339
340 pg_->SetLabel(node, normalOrThrowCompletion);
341 // 1. Return ? IteratorValue(innerResult).
342 // a. Return ? IteratorValue(innerResult).
343 iterator.Value();
344 }
345
346 } // namespace panda::es2panda::compiler
347