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