1/* 2 * Copyright (c) 2021 - 2024 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 22namespace ark::es2panda::compiler { 23// Iterator 24 25Iterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type) 26 : pg_(pg), node_(node), method_(pg->AllocReg()), iterator_(pg->AllocReg()), nextResult_(pg->AllocReg()), type_(type) 27{ 28 if (type_ == IteratorType::ASYNC) { 29 pg_->GetAsyncIterator(node); 30 } else { 31 pg_->GetIterator(node); 32 } 33 34 pg_->StoreAccumulator(node, iterator_); 35 pg_->LoadObjByName(node_, "next"); 36 pg_->StoreAccumulator(node_, method_); 37 38 pg_->ThrowIfNotObject(node_); 39} 40 41void Iterator::GetMethod(util::StringView name) const 42{ 43 pg_->GetMethod(node_, iterator_, name); 44 pg_->StoreAccumulator(node_, method_); 45} 46 47void Iterator::CallMethodWithValue() const 48{ 49 pg_->Call1This(node_, method_, iterator_, nextResult_); 50} 51 52void Iterator::CallMethod() const 53{ 54 pg_->Call0This(node_, method_, iterator_); 55} 56 57void Iterator::Next() const 58{ 59 CallMethod(); 60 61 if (type_ == IteratorType::ASYNC) { 62 pg_->FuncBuilder()->Await(node_); 63 } 64 65 pg_->ThrowIfNotObject(node_); 66 pg_->StoreAccumulator(node_, nextResult_); 67} 68 69void Iterator::Complete() const 70{ 71 pg_->LoadObjByName(node_, "done"); 72 pg_->ToBoolean(node_); 73} 74 75void Iterator::Value() const 76{ 77 pg_->LoadAccumulator(node_, nextResult_); 78 pg_->LoadObjByName(node_, "value"); 79} 80 81void Iterator::CloseInnerResultNormal(bool abruptCompletion, Label *returnExits) const 82{ 83 VReg completion = pg_->AllocReg(); 84 VReg innerResult = pg_->AllocReg(); 85 VReg innerResultType = pg_->AllocReg(); 86 87 // b. If return is undefined, return Completion(completion). 88 pg_->BranchIfNotUndefined(node_, returnExits); 89 // a. Let return be innerResult.[[Value]]. 90 pg_->LoadAccumulator(node_, completion); 91 92 if (abruptCompletion) { 93 pg_->EmitThrow(node_); 94 } else { 95 pg_->DirectReturn(node_); 96 } 97 98 pg_->SetLabel(node_, returnExits); 99 100 { 101 TryContext innerTryCtx(pg_); 102 const auto &innerLabelSet = innerTryCtx.LabelSet(); 103 104 pg_->SetLabel(node_, innerLabelSet.TryBegin()); 105 // c. Set innerResult to Call(return, iterator). 106 CallMethod(); 107 // d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]). 108 pg_->FuncBuilder()->Await(node_); 109 pg_->StoreAccumulator(node_, innerResult); 110 pg_->SetLabel(node_, innerLabelSet.TryEnd()); 111 pg_->Branch(node_, innerLabelSet.CatchEnd()); 112 113 pg_->SetLabel(node_, innerLabelSet.CatchBegin()); 114 pg_->StoreAccumulator(node_, innerResult); 115 pg_->StoreAccumulator(node_, innerResultType); 116 pg_->SetLabel(node_, innerLabelSet.CatchEnd()); 117 } 118} 119 120void Iterator::Close(bool abruptCompletion) const 121{ 122 if (type_ == IteratorType::SYNC) { 123 if (!abruptCompletion) { 124 pg_->LoadConst(node_, Constant::JS_HOLE); 125 } 126 pg_->CloseIterator(node_, iterator_); 127 return; 128 } 129 130 RegScope rs(pg_); 131 VReg completion = pg_->AllocReg(); 132 VReg innerResult = pg_->AllocReg(); 133 VReg innerResultType = pg_->AllocReg(); 134 135 pg_->StoreAccumulator(node_, completion); 136 pg_->StoreConst(node_, innerResultType, Constant::JS_HOLE); 137 138 TryContext tryCtx(pg_); 139 const auto &labelSet = tryCtx.LabelSet(); 140 Label *returnExits = pg_->AllocLabel(); 141 142 pg_->SetLabel(node_, labelSet.TryBegin()); 143 144 // 4. Let innerResult be GetMethod(iterator, "return"). 145 GetMethod("return"); 146 147 // 5. If innerResult.[[Type]] is normal, then 148 { 149 CloseInnerResultNormal(abruptCompletion, returnExits); 150 } 151 152 pg_->SetLabel(node_, labelSet.TryEnd()); 153 pg_->Branch(node_, labelSet.CatchEnd()); 154 155 pg_->SetLabel(node_, labelSet.CatchBegin()); 156 pg_->StoreAccumulator(node_, innerResult); 157 pg_->StoreAccumulator(node_, innerResultType); 158 pg_->SetLabel(node_, labelSet.CatchEnd()); 159 160 // 6. If completion.[[Type]] is throw, return Completion(completion). 161 if (abruptCompletion) { 162 pg_->LoadAccumulator(node_, completion); 163 pg_->EmitThrow(node_); 164 } else { 165 // 7. If innerResult.[[Type]] is throw, return Completion(innerResult). 166 pg_->LoadAccumulator(node_, innerResultType); 167 pg_->EmitRethrow(node_); 168 } 169 170 // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. 171 pg_->LoadAccumulator(node_, innerResult); 172 pg_->ThrowIfNotObject(node_); 173} 174 175DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node) 176 : Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg()) 177{ 178 pg_->StoreConst(node, done_, Constant::JS_FALSE); 179 pg_->StoreConst(node, result_, Constant::JS_UNDEFINED); 180} 181 182void DestructuringIterator::Step(Label *doneTarget) const 183{ 184 TryContext tryCtx(pg_); 185 const auto &labelSet = tryCtx.LabelSet(); 186 Label *normalClose = pg_->AllocLabel(); 187 Label *noClose = pg_->AllocLabel(); 188 189 pg_->SetLabel(node_, labelSet.TryBegin()); 190 Next(); 191 Complete(); 192 pg_->StoreAccumulator(node_, done_); 193 pg_->BranchIfFalse(node_, normalClose); 194 pg_->StoreConst(node_, done_, Constant::JS_TRUE); 195 pg_->LoadConst(node_, Constant::JS_UNDEFINED); 196 OnIterDone(doneTarget); 197 pg_->Branch(node_, noClose); 198 199 pg_->SetLabel(node_, normalClose); 200 Value(); 201 pg_->StoreAccumulator(node_, result_); 202 pg_->SetLabel(node_, noClose); 203 204 pg_->SetLabel(node_, labelSet.TryEnd()); 205 pg_->Branch(node_, labelSet.CatchEnd()); 206 207 pg_->SetLabel(node_, labelSet.CatchBegin()); 208 pg_->StoreAccumulator(node_, result_); 209 pg_->StoreConst(node_, done_, Constant::JS_TRUE); 210 pg_->LoadAccumulator(node_, result_); 211 pg_->EmitThrow(node_); 212 pg_->SetLabel(node_, labelSet.CatchEnd()); 213} 214 215void DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const 216{ 217 pg_->LoadConst(node_, Constant::JS_UNDEFINED); 218} 219 220void DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const 221{ 222 pg_->Branch(node_, doneTarget); 223} 224} // namespace ark::es2panda::compiler 225