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
26namespace panda::es2panda::compiler {
27
28FunctionBuilder::FunctionBuilder(PandaGen *pg, CatchTable *catchTable)
29    : pg_(pg), catchTable_(catchTable), funcObj_(pg_->AllocReg())
30{
31}
32
33IteratorType FunctionBuilder::GeneratorKind() const
34{
35    return IteratorType::SYNC;
36}
37
38void FunctionBuilder::DirectReturn(const ir::AstNode *node) const
39{
40    pg_->NotifyConcurrentResult(node);
41    pg_->EmitReturn(node);
42}
43
44void 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
73void FunctionBuilder::ExplicitReturn(const ir::AstNode *node) const
74{
75    DirectReturn(node);
76}
77
78void 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
95void 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
104void 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
115VReg 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
123void 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
141void 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
174void 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