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 "dynamicContext.h" 17 18#include "checker/types/ets/etsObjectType.h" 19#include "checker/types/type.h" 20#include "compiler/core/envScope.h" 21#include "compiler/core/ETSGen.h" 22#include "compiler/core/pandagen.h" 23#include "compiler/base/catchTable.h" 24#include "ir/expressions/identifier.h" 25#include "ir/base/catchClause.h" 26#include "ir/statements/blockStatement.h" 27#include "ir/statements/breakStatement.h" 28#include "ir/statements/continueStatement.h" 29#include "ir/statements/returnStatement.h" 30#include "ir/statements/tryStatement.h" 31#include "ir/statements/labelledStatement.h" 32 33namespace ark::es2panda::compiler { 34DynamicContext::DynamicContext(CodeGen *cg, LabelTarget target) : cg_(cg), target_(target), prev_(Cg()->dynamicContext_) 35{ 36 Cg()->dynamicContext_ = this; 37} 38 39DynamicContext::~DynamicContext() 40{ 41 Cg()->dynamicContext_ = prev_; 42} 43 44LabelContext::LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt) 45 : DynamicContext(cg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) 46{ 47 if (!labelledStmt->Body()->IsBlockStatement()) { 48 return; 49 } 50 51 label_ = cg->AllocLabel(); 52 Target().SetBreakTarget(label_); 53} 54 55LabelContext::~LabelContext() 56{ 57 if (label_ == nullptr) { 58 return; 59 } 60 61 Cg()->SetLabel(labelledStmt_, label_); 62} 63 64LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target) 65 : DynamicContext(pg, target), envScope_(envScope) 66{ 67 if (!envScope_->HasEnv()) { 68 return; 69 } 70 71 catchTable_ = Cg()->CreateCatchTable(); 72 const auto &labelSet = catchTable_->LabelSet(); 73 const auto *node = envScope_->Scope()->Node(); 74 75 Cg()->SetLabel(node, labelSet.TryBegin()); 76} 77 78LexEnvContext::~LexEnvContext() 79{ 80 if (!envScope_->HasEnv()) { 81 return; 82 } 83 84 const auto &labelSet = catchTable_->LabelSet(); 85 const auto *node = envScope_->Scope()->Node(); 86 87 Cg()->SetLabel(node, labelSet.TryEnd()); 88 Cg()->Branch(node, labelSet.CatchEnd()); 89 90 Cg()->SetLabel(node, labelSet.CatchBegin()); 91 AsPandaGen()->PopLexEnv(node); 92 AsPandaGen()->EmitThrow(node); 93 Cg()->SetLabel(node, labelSet.CatchEnd()); 94 AsPandaGen()->PopLexEnv(node); 95} 96 97PandaGen *LexEnvContext::AsPandaGen() const 98{ 99 return static_cast<PandaGen *>(Cg()); 100} 101 102bool LexEnvContext::HasTryCatch() const 103{ 104 return envScope_->HasEnv(); 105} 106 107void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, 108 [[maybe_unused]] const util::StringView &targetLabel) 109{ 110 if (cfc == ControlFlowChange::CONTINUE || !envScope_->HasEnv()) { 111 return; 112 } 113 114 const auto *node = envScope_->Scope()->Node(); 115 AsPandaGen()->PopLexEnv(node); 116} 117 118IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target) 119 : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable()) 120{ 121 const auto &labelSet = catchTable_->LabelSet(); 122 pg->SetLabel(iterator_.Node(), labelSet.TryBegin()); 123} 124 125IteratorContext::~IteratorContext() 126{ 127 const auto &labelSet = catchTable_->LabelSet(); 128 const auto *node = iterator_.Node(); 129 130 Cg()->SetLabel(node, labelSet.TryEnd()); 131 Cg()->Branch(node, labelSet.CatchEnd()); 132 133 Cg()->SetLabel(node, labelSet.CatchBegin()); 134 iterator_.Close(true); 135 Cg()->SetLabel(node, labelSet.CatchEnd()); 136} 137 138void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, 139 [[maybe_unused]] const util::StringView &targetLabel) 140{ 141 if (cfc == ControlFlowChange::CONTINUE && Target().ContinueLabel() == targetLabel) { 142 return; 143 } 144 145 iterator_.Close(false); 146} 147 148void TryContext::InitFinalizer() 149{ 150 ASSERT(tryStmt_); 151 152 if (!hasFinalizer_ || (tryStmt_->FinallyBlock() == nullptr)) { 153 return; 154 } 155 156 auto *pg = static_cast<PandaGen *>(Cg()); 157 158 finalizerRun_ = pg->AllocReg(); 159 pg->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); 160} 161 162void CatchContext::InitCatchTable() 163{ 164 auto *pg = static_cast<PandaGen *>(Cg()); 165 catchTable_ = pg->CreateCatchTable(); 166} 167 168const TryLabelSet &CatchContext::LabelSet() const 169{ 170 return catchTable_->LabelSet(); 171} 172 173bool TryContext::HasFinalizer() const 174{ 175 return hasFinalizer_; 176} 177 178void TryContext::EmitFinalizer() 179{ 180 if (!hasFinalizer_ || inFinalizer_ || (tryStmt_->FinallyBlock() == nullptr)) { 181 return; 182 } 183 184 auto *pg = static_cast<PandaGen *>(Cg()); 185 inFinalizer_ = true; 186 tryStmt_->FinallyBlock()->Compile(pg); 187 inFinalizer_ = false; 188} 189 190CatchTable *ETSCatchContext::AddNewCathTable(const util::StringView assemblerType) 191{ 192 auto *cg = Cg(); 193 194 CatchTable *catchTable = cg->CreateCatchTable(assemblerType); 195 catchTables_.push_back(catchTable); 196 197 return catchTable; 198} 199 200CatchTable *ETSCatchContext::AddNewCathTable(const util::StringView assemblerType, const LabelPair tryLabelPair) 201{ 202 auto *cg = Cg(); 203 204 CatchTable *catchTable = cg->CreateCatchTable(tryLabelPair, assemblerType); 205 catchTables_.push_back(catchTable); 206 207 return catchTable; 208} 209 210void ETSTryContext::EmitFinalizer( 211 LabelPair trycatchLabelPair, 212 const ArenaVector<std::pair<compiler::LabelPair, const ir::Statement *>> &finalizerInsertions) 213{ 214 ASSERT(tryStmt_); 215 216 if (!hasFinalizer_ || (tryStmt_->FinallyBlock() == nullptr)) { 217 return; 218 } 219 auto *etsg = static_cast<ETSGen *>(Cg()); 220 221 CatchTable *finalizerTable = AddNewCathTable("", trycatchLabelPair); 222 // First compile of the finaly clause, executed if the statement executed normally 223 tryStmt_->FinallyBlock()->Compile(etsg); 224 225 etsg->Branch(tryStmt_, finalizerTable->LabelSet().CatchEnd()); 226 227 for (std::pair<compiler::LabelPair, const ir::Statement *> insertion : finalizerInsertions) { 228 EmitFinalizerInsertion(etsg, insertion.first, insertion.second); 229 } 230 231 etsg->SetLabel(tryStmt_, finalizerTable->LabelSet().CatchBegin()); 232 233 compiler::VReg exception = etsg->StoreException(tryStmt_); 234 // Third compile of the finaly clause, executed if the statement executed abruptly 235 tryStmt_->FinallyBlock()->Compile(etsg); 236 237 etsg->LoadAccumulator(tryStmt_, exception); 238 etsg->EmitThrow(tryStmt_, exception); 239 240 etsg->SetLabel(tryStmt_, finalizerTable->LabelSet().CatchEnd()); 241} 242 243void ETSTryContext::EmitFinalizerInsertion(ETSGen *etsg, compiler::LabelPair labelPair, const ir::Statement *statement) 244{ 245 etsg->SetLabel(tryStmt_, labelPair.Begin()); 246 247 ASSERT(statement != nullptr); 248 bool isReturn = statement->IsReturnStatement(); 249 250 compiler::RegScope rs(etsg); 251 compiler::VReg res = etsg->AllocReg(); 252 253 if (isReturn) { 254 etsg->SetAccumulatorType(statement->AsReturnStatement()->ReturnType()); 255 etsg->StoreAccumulator(tryStmt_, res); 256 etsg->SetVRegType(res, statement->AsReturnStatement()->ReturnType()); 257 } 258 259 // Second compile of the finaly clause, executed if the statement executed normally, but abrupted by 260 // return, break, or continue statements. 261 tryStmt_->FinallyBlock()->Compile(etsg); 262 263 if (isReturn) { 264 etsg->SetAccumulatorType(statement->AsReturnStatement()->ReturnType()); 265 etsg->LoadAccumulator(tryStmt_, res); 266 } 267 268 if (labelPair.End() != nullptr) { 269 etsg->Branch(tryStmt_, labelPair.End()); 270 } else if (isReturn) { 271 if (etsg->CheckControlFlowChange()) { 272 etsg->StoreAccumulator(tryStmt_, res); 273 etsg->ControlFlowChangeBreak(); 274 etsg->LoadAccumulator(tryStmt_, res); 275 } 276 277 etsg->ReturnAcc(tryStmt_); 278 } else if (statement->IsBreakStatement()) { 279 compiler::Label *target = etsg->ControlFlowChangeBreak(statement->AsBreakStatement()->Ident()); 280 etsg->Branch(tryStmt_, target); 281 } else if (statement->IsContinueStatement()) { 282 compiler::Label *target = etsg->ControlFlowChangeContinue(statement->AsContinueStatement()->Ident()); 283 etsg->Branch(tryStmt_, target); 284 } else { 285 UNREACHABLE(); 286 } 287} 288 289} // namespace ark::es2panda::compiler 290