• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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