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