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 22namespace panda::es2panda::compiler { 23 24// Iterator 25 26Iterator::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 42void Iterator::GetMethod(util::StringView name) const 43{ 44 pg_->LoadObjByName(node_, iterator_, name); 45 pg_->StoreAccumulator(node_, method_); 46} 47 48void Iterator::CallMethodWithValue() const 49{ 50 pg_->CallThis(node_, method_, 2); 51} 52 53void Iterator::CallMethod() const 54{ 55 pg_->CallThis(node_, method_, 1); 56} 57 58void 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 70void Iterator::Complete() const 71{ 72 pg_->LoadObjByName(node_, nextResult_, "done"); 73} 74 75void Iterator::Value() const 76{ 77 pg_->LoadObjByName(node_, nextResult_, "value"); 78} 79 80void 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 146DestructuringIterator::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 153void 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 JumpIfDone(noClose); 162 Next(); 163 Complete(); 164 pg_->StoreAccumulator(node_, done_); 165 pg_->BranchIfFalse(node_, normalClose); 166 pg_->StoreConst(node_, done_, Constant::JS_TRUE); 167 pg_->LoadConst(node_, Constant::JS_UNDEFINED); 168 pg_->Branch(node_, noClose); 169 170 pg_->SetLabel(node_, normalClose); 171 Value(); 172 pg_->StoreAccumulator(node_, result_); 173 pg_->Branch(node_, labelSet.CatchEnd()); 174 pg_->SetLabel(node_, noClose); 175 OnIterDone(doneTarget); 176 177 pg_->SetLabel(node_, labelSet.TryEnd()); 178 pg_->Branch(node_, labelSet.CatchEnd()); 179 180 pg_->SetLabel(node_, labelSet.CatchBegin()); 181 pg_->StoreAccumulator(node_, result_); 182 pg_->StoreConst(node_, done_, Constant::JS_TRUE); 183 pg_->LoadAccumulator(node_, result_); 184 pg_->EmitThrow(node_); 185 pg_->SetLabel(node_, labelSet.CatchEnd()); 186} 187 188void DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const 189{ 190 pg_->LoadConst(node_, Constant::JS_UNDEFINED); 191} 192 193void DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const 194{ 195 pg_->Branch(node_, doneTarget); 196} 197 198void DestructuringIterator::JumpIfDone(Label *noClose) const 199{ 200 pg_->LoadAccumulator(node_, done_); 201 pg_->BranchIfTrue(node_, noClose); 202} 203 204} // namespace panda::es2panda::compiler 205