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