13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "dynamicContext.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h>
193af6ab5fSopenharmony_ci#include <compiler/base/catchTable.h>
203af6ab5fSopenharmony_ci#include <ir/expressions/identifier.h>
213af6ab5fSopenharmony_ci#include <ir/statements/tryStatement.h>
223af6ab5fSopenharmony_ci#include <ir/statements/blockStatement.h>
233af6ab5fSopenharmony_ci#include <ir/statements/labelledStatement.h>
243af6ab5fSopenharmony_ci
253af6ab5fSopenharmony_cinamespace panda::es2panda::compiler {
263af6ab5fSopenharmony_ciDynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_)
273af6ab5fSopenharmony_ci{
283af6ab5fSopenharmony_ci    pg_->dynamicContext_ = this;
293af6ab5fSopenharmony_ci}
303af6ab5fSopenharmony_ci
313af6ab5fSopenharmony_ciDynamicContext::~DynamicContext()
323af6ab5fSopenharmony_ci{
333af6ab5fSopenharmony_ci    pg_->dynamicContext_ = prev_;
343af6ab5fSopenharmony_ci}
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ciLabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt)
373af6ab5fSopenharmony_ci    : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt)
383af6ab5fSopenharmony_ci{
393af6ab5fSopenharmony_ci    if (!labelledStmt->Body()->IsBlockStatement() && !labelledStmt->Body()->IsIfStatement() &&
403af6ab5fSopenharmony_ci        !labelledStmt->Body()->IsBreakStatement()) {
413af6ab5fSopenharmony_ci        return;
423af6ab5fSopenharmony_ci    }
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci    label_ = pg->AllocLabel();
453af6ab5fSopenharmony_ci    target_.SetBreakTarget(label_);
463af6ab5fSopenharmony_ci}
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_ciLabelContext::~LabelContext()
493af6ab5fSopenharmony_ci{
503af6ab5fSopenharmony_ci    if (!label_) {
513af6ab5fSopenharmony_ci        return;
523af6ab5fSopenharmony_ci    }
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_ci    pg_->SetLabel(labelledStmt_, label_);
553af6ab5fSopenharmony_ci}
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_ciLexEnvContext::LexEnvContext(VariableEnvScope *envScope, PandaGen *pg, LabelTarget target)
583af6ab5fSopenharmony_ci    : DynamicContext(pg, target), envScope_(envScope)
593af6ab5fSopenharmony_ci{
603af6ab5fSopenharmony_ci    if (!envScope_->HasEnv()) {
613af6ab5fSopenharmony_ci        return;
623af6ab5fSopenharmony_ci    }
633af6ab5fSopenharmony_ci
643af6ab5fSopenharmony_ci    catchTable_ = pg_->CreateCatchTable();
653af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
663af6ab5fSopenharmony_ci    const auto *node = envScope_->Scope()->Node();
673af6ab5fSopenharmony_ci
683af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.TryBegin());
693af6ab5fSopenharmony_ci}
703af6ab5fSopenharmony_ci
713af6ab5fSopenharmony_ciLexEnvContext::~LexEnvContext()
723af6ab5fSopenharmony_ci{
733af6ab5fSopenharmony_ci    if (!envScope_->HasEnv()) {
743af6ab5fSopenharmony_ci        return;
753af6ab5fSopenharmony_ci    }
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
783af6ab5fSopenharmony_ci    const auto *node = envScope_->Scope()->Node();
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.TryEnd());
813af6ab5fSopenharmony_ci    pg_->Branch(node, labelSet.CatchEnd());
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchBegin());
843af6ab5fSopenharmony_ci    pg_->PopLexEnv(node);
853af6ab5fSopenharmony_ci    pg_->EmitThrow(node);
863af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchEnd());
873af6ab5fSopenharmony_ci    pg_->PopLexEnv(node);
883af6ab5fSopenharmony_ci}
893af6ab5fSopenharmony_ci
903af6ab5fSopenharmony_cibool LexEnvContext::HasTryCatch() const
913af6ab5fSopenharmony_ci{
923af6ab5fSopenharmony_ci    return envScope_->HasEnv();
933af6ab5fSopenharmony_ci}
943af6ab5fSopenharmony_ci
953af6ab5fSopenharmony_civoid LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
963af6ab5fSopenharmony_ci                                 [[maybe_unused]] const util::StringView &targetLabel)
973af6ab5fSopenharmony_ci{
983af6ab5fSopenharmony_ci    if (!envScope_->HasEnv()) {
993af6ab5fSopenharmony_ci        return;
1003af6ab5fSopenharmony_ci    }
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci    const auto *node = envScope_->Scope()->Node();
1033af6ab5fSopenharmony_ci    if (node->IsForUpdateStatement()) {
1043af6ab5fSopenharmony_ci        return;
1053af6ab5fSopenharmony_ci    }
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ci    pg_->PopLexEnv(node);
1083af6ab5fSopenharmony_ci}
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ciIteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)
1113af6ab5fSopenharmony_ci    : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable())
1123af6ab5fSopenharmony_ci{
1133af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
1143af6ab5fSopenharmony_ci    pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
1153af6ab5fSopenharmony_ci}
1163af6ab5fSopenharmony_ci
1173af6ab5fSopenharmony_ciIteratorContext::~IteratorContext()
1183af6ab5fSopenharmony_ci{
1193af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
1203af6ab5fSopenharmony_ci    const auto *node = iterator_.Node();
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.TryEnd());
1233af6ab5fSopenharmony_ci    pg_->Branch(node, labelSet.CatchEnd());
1243af6ab5fSopenharmony_ci
1253af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchBegin());
1263af6ab5fSopenharmony_ci    iterator_.Close(true);
1273af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchEnd());
1283af6ab5fSopenharmony_ci}
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_civoid IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
1313af6ab5fSopenharmony_ci                                   [[maybe_unused]] const util::StringView &targetLabel)
1323af6ab5fSopenharmony_ci{
1333af6ab5fSopenharmony_ci    if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
1343af6ab5fSopenharmony_ci        return;
1353af6ab5fSopenharmony_ci    }
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    iterator_.Close(false);
1383af6ab5fSopenharmony_ci}
1393af6ab5fSopenharmony_ci
1403af6ab5fSopenharmony_ciDestructuringIteratorContext::DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator)
1413af6ab5fSopenharmony_ci    : DynamicContext(pg, {}), iterator_(iterator), catchTable_(pg->CreateCatchTable())
1423af6ab5fSopenharmony_ci{
1433af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
1443af6ab5fSopenharmony_ci    pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
1453af6ab5fSopenharmony_ci}
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ciDestructuringIteratorContext::~DestructuringIteratorContext()
1483af6ab5fSopenharmony_ci{
1493af6ab5fSopenharmony_ci    const auto &labelSet = catchTable_->LabelSet();
1503af6ab5fSopenharmony_ci    const auto *node = iterator_.Node();
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.TryEnd());
1533af6ab5fSopenharmony_ci
1543af6ab5fSopenharmony_ci    // Normal completion
1553af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node, iterator_.Done());
1563af6ab5fSopenharmony_ci    pg_->BranchIfTrue(node, labelSet.CatchEnd());
1573af6ab5fSopenharmony_ci    iterator_.Close(false);
1583af6ab5fSopenharmony_ci
1593af6ab5fSopenharmony_ci    pg_->Branch(node, labelSet.CatchEnd());
1603af6ab5fSopenharmony_ci
1613af6ab5fSopenharmony_ci    Label *end = pg_->AllocLabel();
1623af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchBegin());
1633af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node, iterator_.Result());
1643af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node, iterator_.Done());
1653af6ab5fSopenharmony_ci
1663af6ab5fSopenharmony_ci    pg_->BranchIfTrue(node, end);
1673af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node, iterator_.Result());
1683af6ab5fSopenharmony_ci    iterator_.Close(true);
1693af6ab5fSopenharmony_ci    pg_->SetLabel(node, end);
1703af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node, iterator_.Result());
1713af6ab5fSopenharmony_ci    pg_->EmitThrow(node);
1723af6ab5fSopenharmony_ci    pg_->SetLabel(node, labelSet.CatchEnd());
1733af6ab5fSopenharmony_ci}
1743af6ab5fSopenharmony_ci
1753af6ab5fSopenharmony_civoid DestructuringIteratorContext::AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel)
1763af6ab5fSopenharmony_ci{
1773af6ab5fSopenharmony_ci    if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
1783af6ab5fSopenharmony_ci        return;
1793af6ab5fSopenharmony_ci    }
1803af6ab5fSopenharmony_ci
1813af6ab5fSopenharmony_ci    iterator_.Close(false);
1823af6ab5fSopenharmony_ci}
1833af6ab5fSopenharmony_ci
1843af6ab5fSopenharmony_civoid TryContext::InitFinalizer()
1853af6ab5fSopenharmony_ci{
1863af6ab5fSopenharmony_ci    ASSERT(tryStmt_);
1873af6ab5fSopenharmony_ci
1883af6ab5fSopenharmony_ci    if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) {
1893af6ab5fSopenharmony_ci        return;
1903af6ab5fSopenharmony_ci    }
1913af6ab5fSopenharmony_ci
1923af6ab5fSopenharmony_ci    finalizerRun_ = pg_->AllocReg();
1933af6ab5fSopenharmony_ci    pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED);
1943af6ab5fSopenharmony_ci}
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_civoid TryContext::InitCatchTable()
1973af6ab5fSopenharmony_ci{
1983af6ab5fSopenharmony_ci    catchTable_ = pg_->CreateCatchTable();
1993af6ab5fSopenharmony_ci}
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ciconst TryLabelSet &TryContext::LabelSet() const
2023af6ab5fSopenharmony_ci{
2033af6ab5fSopenharmony_ci    return catchTable_->LabelSet();
2043af6ab5fSopenharmony_ci}
2053af6ab5fSopenharmony_ci
2063af6ab5fSopenharmony_cibool TryContext::HasFinalizer() const
2073af6ab5fSopenharmony_ci{
2083af6ab5fSopenharmony_ci    return hasFinalizer_;
2093af6ab5fSopenharmony_ci}
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_civoid TryContext::EmitFinalizer()
2123af6ab5fSopenharmony_ci{
2133af6ab5fSopenharmony_ci    if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) {
2143af6ab5fSopenharmony_ci        return;
2153af6ab5fSopenharmony_ci    }
2163af6ab5fSopenharmony_ci
2173af6ab5fSopenharmony_ci    inFinalizer_ = true;
2183af6ab5fSopenharmony_ci    tryStmt_->FinallyBlock()->Compile(pg_);
2193af6ab5fSopenharmony_ci    inFinalizer_ = false;
2203af6ab5fSopenharmony_ci}
2213af6ab5fSopenharmony_ci
2223af6ab5fSopenharmony_civoid TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
2233af6ab5fSopenharmony_ci                              [[maybe_unused]] const util::StringView &targetLabel)
2243af6ab5fSopenharmony_ci{
2253af6ab5fSopenharmony_ci    EmitFinalizer();
2263af6ab5fSopenharmony_ci}
2273af6ab5fSopenharmony_ci}  // namespace panda::es2panda::compiler
228