* Copyright (c) 2021-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "tryStatement.h"
#include <compiler/core/pandagen.h>
#include <compiler/base/catchTable.h>
#include <ir/astDump.h>
#include <ir/base/catchClause.h>
#include <ir/statements/blockStatement.h>
namespace panda::es2panda::ir {
void TryStatement::Iterate(const NodeTraverser &cb) const
{
cb(block_);
if (catchClause_) {
cb(catchClause_);
}
if (finalizer_) {
cb(finalizer_);
}
}
void TryStatement::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", "TryStatement"},
{"block", block_},
{"handler", AstDumper::Nullable(catchClause_)},
{"finalizer", AstDumper::Nullable(finalizer_)}});
}
void TryStatement::CompileFinally(compiler::PandaGen *pg, compiler::TryContext *tryCtx,
const compiler::TryLabelSet &labelSet) const
{
compiler::RegScope rs(pg);
compiler::VReg exception = pg->AllocReg();
pg->StoreConst(this, exception, compiler::Constant::JS_HOLE);
pg->Branch(this, labelSet.CatchEnd());
pg->SetLabel(this, labelSet.CatchBegin());
pg->StoreAccumulator(this, exception);
pg->SetLabel(this, labelSet.CatchEnd());
compiler::Label *label = pg->AllocLabel();
pg->LoadAccumulator(this, tryCtx->FinalizerRun());
pg->BranchIfNotUndefined(this, label);
pg->StoreAccumulator(this, tryCtx->FinalizerRun());
tryCtx->EmitFinalizer();
pg->SetLabel(this, label);
pg->LoadAccumulator(this, exception);
pg->EmitRethrow(this);
}
void TryStatement::CompileTryCatchFinally(compiler::PandaGen *pg) const
{
ASSERT(catchClause_ && finalizer_);
compiler::TryContext tryCtx(pg, this);
const auto &labelSet = tryCtx.LabelSet();
pg->SetLabel(this, labelSet.TryBegin());
{
compiler::TryContext innerTryCtx(pg, this, false);
const auto &innerLabelSet = innerTryCtx.LabelSet();
pg->SetLabel(this, innerLabelSet.TryBegin());
block_->Compile(pg);
pg->SetLabel(this, innerLabelSet.TryEnd());
pg->Branch(this, innerLabelSet.CatchEnd());
pg->SetLabel(this, innerLabelSet.CatchBegin());
catchClause_->Compile(pg);
pg->SetLabel(this, innerLabelSet.CatchEnd());
}
pg->SetLabel(this, labelSet.TryEnd());
CompileFinally(pg, &tryCtx, labelSet);
}
void TryStatement::CompileTryFinally(compiler::PandaGen *pg) const
{
ASSERT(!catchClause_ && finalizer_);
compiler::TryContext tryCtx(pg, this);
const auto &labelSet = tryCtx.LabelSet();
pg->SetLabel(this, labelSet.TryBegin());
{
compiler::TryContext innerTryCtx(pg, this, false);
const auto &innerLabelSet = innerTryCtx.LabelSet();
pg->SetLabel(this, innerLabelSet.TryBegin());
block_->Compile(pg);
pg->SetLabel(this, innerLabelSet.TryEnd());
pg->Branch(this, innerLabelSet.CatchEnd());
pg->SetLabel(this, innerLabelSet.CatchBegin());
pg->EmitThrow(this);
pg->SetLabel(this, innerLabelSet.CatchEnd());
}
pg->SetLabel(this, labelSet.TryEnd());
CompileFinally(pg, &tryCtx, labelSet);
}
void TryStatement::CompileTryCatch(compiler::PandaGen *pg) const
{
ASSERT(catchClause_ && !finalizer_);
compiler::TryContext tryCtx(pg, this);
const auto &labelSet = tryCtx.LabelSet();
pg->SetLabel(this, labelSet.TryBegin());
block_->Compile(pg);
pg->SetLabel(this, labelSet.TryEnd());
pg->Branch(this, labelSet.CatchEnd());
pg->SetLabel(this, labelSet.CatchBegin());
catchClause_->Compile(pg);
pg->SetLabel(this, labelSet.CatchEnd());
}
void TryStatement::Compile(compiler::PandaGen *pg) const
{
if (finalizer_) {
if (catchClause_) {
CompileTryCatchFinally(pg);
} else {
CompileTryFinally(pg);
}
} else {
CompileTryCatch(pg);
}
}
void TryStatement::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
{
block_ = std::get<ir::AstNode *>(cb(block_))->AsBlockStatement();
if (catchClause_) {
catchClause_ = std::get<ir::AstNode *>(cb(catchClause_))->AsCatchClause();
}
if (finalizer_) {
finalizer_ = std::get<ir::AstNode *>(cb(finalizer_))->AsBlockStatement();
}
}
}