• 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 <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