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