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