• 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 "iterators.h"
17 
18 #include <compiler/core/pandagen.h>
19 #include <compiler/base/catchTable.h>
20 #include <compiler/function/functionBuilder.h>
21 
22 namespace panda::es2panda::compiler {
23 
24 // Iterator
25 
Iterator(PandaGen * pg,const ir::AstNode * node,IteratorType type)26 Iterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type)
27     : pg_(pg), node_(node), closed_(pg->AllocReg()), method_(pg->AllocReg()), iterator_(pg->AllocReg()),
28       nextResult_(pg->AllocReg()), type_(type)
29 {
30     if (type_ == IteratorType::ASYNC) {
31         pg_->GetAsyncIterator(node);
32     } else {
33         pg_->GetIterator(node);
34     }
35 
36     pg_->StoreAccumulator(node, iterator_);
37     pg_->LoadObjByName(node_, iterator_, "next");
38     pg_->StoreAccumulator(node_, method_);
39     pg_->StoreConst(node_, closed_, Constant::JS_FALSE);
40 }
41 
GetMethod(util::StringView name) const42 void Iterator::GetMethod(util::StringView name) const
43 {
44     pg_->LoadObjByName(node_, iterator_, name);
45     pg_->StoreAccumulator(node_, method_);
46 }
47 
CallMethodWithValue() const48 void Iterator::CallMethodWithValue() const
49 {
50     pg_->CallThis(node_, method_, 2);
51 }
52 
CallMethod() const53 void Iterator::CallMethod() const
54 {
55     pg_->CallThis(node_, method_, 1);
56 }
57 
Next() const58 void Iterator::Next() const
59 {
60     CallMethod();
61 
62     if (type_ == IteratorType::ASYNC) {
63         pg_->FuncBuilder()->Await(node_);
64     }
65 
66     pg_->StoreAccumulator(node_, nextResult_);
67     pg_->ThrowIfNotObject(node_, nextResult_);
68 }
69 
Complete() const70 void Iterator::Complete() const
71 {
72     pg_->LoadObjByName(node_, nextResult_, "done");
73 }
74 
Value() const75 void Iterator::Value() const
76 {
77     pg_->LoadObjByName(node_, nextResult_, "value");
78 }
79 
Close(bool abruptCompletion) const80 void Iterator::Close(bool abruptCompletion) const
81 {
82     RegScope rs(pg_);
83     VReg completion = pg_->AllocReg();
84     VReg innerResult = pg_->AllocReg();
85     VReg innerException = pg_->AllocReg();
86     Label *noReturn = pg_->AllocLabel();
87 
88     pg_->StoreAccumulator(node_, completion);
89     pg_->LoadAccumulator(node_, closed_);
90     pg_->BranchIfTrue(node_, noReturn);
91 
92     pg_->StoreConst(node_, closed_, Constant::JS_TRUE);
93     pg_->StoreConst(node_, innerResult, Constant::JS_UNDEFINED);
94     pg_->StoreConst(node_, innerException, Constant::JS_HOLE);
95 
96     TryContext tryCtx(pg_);
97     const auto &labelSet = tryCtx.LabelSet();
98 
99     pg_->SetLabel(node_, labelSet.TryBegin());
100 
101     // 4. Let innerResult be GetMethod(iterator, "return").
102     GetMethod("return");
103 
104     // 5. If innerResult.[[Type]] is normal, then
105     {
106         // a. Let return be innerResult.[[Value]].
107         // b. If return is undefined, return Completion(completion).
108         pg_->BranchIfUndefined(node_, noReturn);
109         // c. Set innerResult to Call(return, iterator).
110         CallMethod();
111         if (type_ == IteratorType::ASYNC) {
112             // d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]).
113             pg_->FuncBuilder()->Await(node_);
114         }
115         pg_->StoreAccumulator(node_, innerResult);
116     }
117 
118     pg_->SetLabel(node_, labelSet.TryEnd());
119     pg_->Branch(node_, labelSet.CatchEnd());
120 
121     pg_->SetLabel(node_, labelSet.CatchBegin());
122     pg_->StoreAccumulator(node_, innerException);
123     pg_->SetLabel(node_, labelSet.CatchEnd());
124 
125     // 6. If completion.[[Type]] is throw, return Completion(completion).
126     if (abruptCompletion) {
127         pg_->LoadAccumulator(node_, completion);
128         pg_->EmitThrow(node_);
129     } else {
130         // 7. If innerResult.[[Type]] is throw, return Completion(innerResult).
131         pg_->LoadAccumulator(node_, innerException);
132         pg_->EmitRethrow(node_);
133     }
134 
135     // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception.
136     pg_->LoadAccumulator(node_, innerResult);
137     pg_->ThrowIfNotObject(node_, innerResult);
138 
139     pg_->SetLabel(node_, noReturn);
140     pg_->LoadAccumulator(node_, completion);
141     if (abruptCompletion) {
142         pg_->EmitThrow(node_);
143     }
144 }
145 
DestructuringIterator(PandaGen * pg,const ir::AstNode * node)146 DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node)
147     : Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg())
148 {
149     pg_->StoreConst(node, done_, Constant::JS_FALSE);
150     pg_->StoreConst(node, result_, Constant::JS_UNDEFINED);
151 }
152 
Step(Label * doneTarget) const153 void DestructuringIterator::Step(Label *doneTarget) const
154 {
155     TryContext tryCtx(pg_);
156     const auto &labelSet = tryCtx.LabelSet();
157     Label *normalClose = pg_->AllocLabel();
158     Label *noClose = pg_->AllocLabel();
159 
160     pg_->SetLabel(node_, labelSet.TryBegin());
161     Next();
162     Complete();
163     pg_->StoreAccumulator(node_, done_);
164     pg_->BranchIfFalse(node_, normalClose);
165     pg_->StoreConst(node_, done_, Constant::JS_TRUE);
166     pg_->LoadConst(node_, Constant::JS_UNDEFINED);
167     OnIterDone(doneTarget);
168     pg_->Branch(node_, noClose);
169 
170     pg_->SetLabel(node_, normalClose);
171     Value();
172     pg_->StoreAccumulator(node_, result_);
173     pg_->SetLabel(node_, noClose);
174 
175     pg_->SetLabel(node_, labelSet.TryEnd());
176     pg_->Branch(node_, labelSet.CatchEnd());
177 
178     pg_->SetLabel(node_, labelSet.CatchBegin());
179     pg_->StoreAccumulator(node_, result_);
180     pg_->StoreConst(node_, done_, Constant::JS_TRUE);
181     pg_->LoadAccumulator(node_, result_);
182     pg_->EmitThrow(node_);
183     pg_->SetLabel(node_, labelSet.CatchEnd());
184 }
185 
OnIterDone(Label * doneTarget) const186 void DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
187 {
188     pg_->LoadConst(node_, Constant::JS_UNDEFINED);
189 }
190 
OnIterDone(Label * doneTarget) const191 void DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
192 {
193     pg_->Branch(node_, doneTarget);
194 }
195 
196 }  // namespace panda::es2panda::compiler
197