1/** 2 * Copyright (c) 2021 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 "tryStatement.h" 17 18#include <compiler/core/pandagen.h> 19#include <compiler/core/dynamicContext.h> 20#include <compiler/base/catchTable.h> 21#include <ir/astDump.h> 22#include <ir/base/catchClause.h> 23#include <ir/statements/blockStatement.h> 24 25namespace panda::es2panda::ir { 26 27void TryStatement::Iterate(const NodeTraverser &cb) const 28{ 29 cb(block_); 30 31 if (catchClause_) { 32 cb(catchClause_); 33 } 34 35 if (finalizer_) { 36 cb(finalizer_); 37 } 38} 39 40void TryStatement::Dump(ir::AstDumper *dumper) const 41{ 42 dumper->Add({{"type", "TryStatement"}, 43 {"block", block_}, 44 {"handler", AstDumper::Nullable(catchClause_)}, 45 {"finalizer", AstDumper::Nullable(finalizer_)}}); 46} 47 48void TryStatement::CompileFinally(compiler::PandaGen *pg, compiler::TryContext *tryCtx, 49 const compiler::TryLabelSet &labelSet) const 50{ 51 compiler::RegScope rs(pg); 52 compiler::VReg exception = pg->AllocReg(); 53 pg->StoreConst(this, exception, compiler::Constant::JS_HOLE); 54 pg->Branch(this, labelSet.CatchEnd()); 55 56 pg->SetLabel(this, labelSet.CatchBegin()); 57 pg->StoreAccumulator(this, exception); 58 59 pg->SetLabel(this, labelSet.CatchEnd()); 60 61 compiler::Label *label = pg->AllocLabel(); 62 pg->LoadAccumulator(this, tryCtx->FinalizerRun()); 63 64 pg->BranchIfNotUndefined(this, label); 65 pg->StoreAccumulator(this, tryCtx->FinalizerRun()); 66 tryCtx->EmitFinalizer(); 67 pg->SetLabel(this, label); 68 69 pg->LoadAccumulator(this, exception); 70 pg->EmitRethrow(this); 71} 72 73void TryStatement::CompileTryCatchFinally(compiler::PandaGen *pg) const 74{ 75 ASSERT(catchClause_ && finalizer_); 76 77 compiler::TryContext tryCtx(pg, this); 78 const auto &labelSet = tryCtx.LabelSet(); 79 80 pg->SetLabel(this, labelSet.TryBegin()); 81 { 82 compiler::TryContext innerTryCtx(pg, this, false); 83 const auto &innerLabelSet = innerTryCtx.LabelSet(); 84 85 pg->SetLabel(this, innerLabelSet.TryBegin()); 86 block_->Compile(pg); 87 pg->SetLabel(this, innerLabelSet.TryEnd()); 88 89 pg->Branch(this, innerLabelSet.CatchEnd()); 90 91 pg->SetLabel(this, innerLabelSet.CatchBegin()); 92 catchClause_->Compile(pg); 93 pg->SetLabel(this, innerLabelSet.CatchEnd()); 94 } 95 pg->SetLabel(this, labelSet.TryEnd()); 96 97 CompileFinally(pg, &tryCtx, labelSet); 98} 99 100void TryStatement::CompileTryFinally(compiler::PandaGen *pg) const 101{ 102 ASSERT(!catchClause_ && finalizer_); 103 104 compiler::TryContext tryCtx(pg, this); 105 const auto &labelSet = tryCtx.LabelSet(); 106 107 pg->SetLabel(this, labelSet.TryBegin()); 108 { 109 compiler::TryContext innerTryCtx(pg, this, false); 110 const auto &innerLabelSet = innerTryCtx.LabelSet(); 111 112 pg->SetLabel(this, innerLabelSet.TryBegin()); 113 block_->Compile(pg); 114 pg->SetLabel(this, innerLabelSet.TryEnd()); 115 116 pg->Branch(this, innerLabelSet.CatchEnd()); 117 118 pg->SetLabel(this, innerLabelSet.CatchBegin()); 119 pg->EmitThrow(this); 120 pg->SetLabel(this, innerLabelSet.CatchEnd()); 121 } 122 pg->SetLabel(this, labelSet.TryEnd()); 123 124 CompileFinally(pg, &tryCtx, labelSet); 125} 126 127void TryStatement::CompileTryCatch(compiler::PandaGen *pg) const 128{ 129 ASSERT(catchClause_ && !finalizer_); 130 131 compiler::TryContext tryCtx(pg, this); 132 const auto &labelSet = tryCtx.LabelSet(); 133 134 pg->SetLabel(this, labelSet.TryBegin()); 135 block_->Compile(pg); 136 pg->SetLabel(this, labelSet.TryEnd()); 137 138 pg->Branch(this, labelSet.CatchEnd()); 139 140 pg->SetLabel(this, labelSet.CatchBegin()); 141 catchClause_->Compile(pg); 142 pg->SetLabel(this, labelSet.CatchEnd()); 143} 144 145void TryStatement::Compile(compiler::PandaGen *pg) const 146{ 147 if (finalizer_) { 148 if (catchClause_) { 149 CompileTryCatchFinally(pg); 150 } else { 151 CompileTryFinally(pg); 152 } 153 } else { 154 CompileTryCatch(pg); 155 } 156} 157 158checker::Type *TryStatement::Check(checker::Checker *checker) const 159{ 160 block_->Check(checker); 161 162 if (catchClause_) { 163 catchClause_->Check(checker); 164 } 165 166 if (finalizer_) { 167 finalizer_->Check(checker); 168 } 169 170 return nullptr; 171} 172 173void TryStatement::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 174{ 175 block_ = std::get<ir::AstNode *>(cb(block_))->AsBlockStatement(); 176 177 if (catchClause_) { 178 catchClause_ = std::get<ir::AstNode *>(cb(catchClause_))->AsCatchClause(); 179 } 180 181 if (finalizer_) { 182 finalizer_ = std::get<ir::AstNode *>(cb(finalizer_))->AsBlockStatement(); 183 } 184} 185 186} // namespace panda::es2panda::ir 187