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 "dynamicContext.h" 17 18#include <compiler/core/pandagen.h> 19#include <compiler/base/catchTable.h> 20#include <ir/expressions/identifier.h> 21#include <ir/statements/tryStatement.h> 22#include <ir/statements/blockStatement.h> 23#include <ir/statements/labelledStatement.h> 24 25namespace panda::es2panda::compiler { 26DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_) 27{ 28 pg_->dynamicContext_ = this; 29} 30 31DynamicContext::~DynamicContext() 32{ 33 pg_->dynamicContext_ = prev_; 34} 35 36LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt) 37 : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) 38{ 39 if (!labelledStmt->Body()->IsBlockStatement() && !labelledStmt->Body()->IsIfStatement() && 40 !labelledStmt->Body()->IsBreakStatement()) { 41 return; 42 } 43 44 label_ = pg->AllocLabel(); 45 target_.SetBreakTarget(label_); 46} 47 48LabelContext::~LabelContext() 49{ 50 if (!label_) { 51 return; 52 } 53 54 pg_->SetLabel(labelledStmt_, label_); 55} 56 57LexEnvContext::LexEnvContext(VariableEnvScope *envScope, PandaGen *pg, LabelTarget target) 58 : DynamicContext(pg, target), envScope_(envScope) 59{ 60 if (!envScope_->HasEnv()) { 61 return; 62 } 63 64 catchTable_ = pg_->CreateCatchTable(); 65 const auto &labelSet = catchTable_->LabelSet(); 66 const auto *node = envScope_->Scope()->Node(); 67 68 pg_->SetLabel(node, labelSet.TryBegin()); 69} 70 71LexEnvContext::~LexEnvContext() 72{ 73 if (!envScope_->HasEnv()) { 74 return; 75 } 76 77 const auto &labelSet = catchTable_->LabelSet(); 78 const auto *node = envScope_->Scope()->Node(); 79 80 pg_->SetLabel(node, labelSet.TryEnd()); 81 pg_->Branch(node, labelSet.CatchEnd()); 82 83 pg_->SetLabel(node, labelSet.CatchBegin()); 84 pg_->PopLexEnv(node); 85 pg_->EmitThrow(node); 86 pg_->SetLabel(node, labelSet.CatchEnd()); 87 pg_->PopLexEnv(node); 88} 89 90bool LexEnvContext::HasTryCatch() const 91{ 92 return envScope_->HasEnv(); 93} 94 95void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, 96 [[maybe_unused]] const util::StringView &targetLabel) 97{ 98 if (!envScope_->HasEnv()) { 99 return; 100 } 101 102 const auto *node = envScope_->Scope()->Node(); 103 if (node->IsForUpdateStatement()) { 104 return; 105 } 106 107 pg_->PopLexEnv(node); 108} 109 110IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target) 111 : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable()) 112{ 113 const auto &labelSet = catchTable_->LabelSet(); 114 pg_->SetLabel(iterator_.Node(), labelSet.TryBegin()); 115} 116 117IteratorContext::~IteratorContext() 118{ 119 const auto &labelSet = catchTable_->LabelSet(); 120 const auto *node = iterator_.Node(); 121 122 pg_->SetLabel(node, labelSet.TryEnd()); 123 pg_->Branch(node, labelSet.CatchEnd()); 124 125 pg_->SetLabel(node, labelSet.CatchBegin()); 126 iterator_.Close(true); 127 pg_->SetLabel(node, labelSet.CatchEnd()); 128} 129 130void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, 131 [[maybe_unused]] const util::StringView &targetLabel) 132{ 133 if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) { 134 return; 135 } 136 137 iterator_.Close(false); 138} 139 140DestructuringIteratorContext::DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator) 141 : DynamicContext(pg, {}), iterator_(iterator), catchTable_(pg->CreateCatchTable()) 142{ 143 const auto &labelSet = catchTable_->LabelSet(); 144 pg_->SetLabel(iterator_.Node(), labelSet.TryBegin()); 145} 146 147DestructuringIteratorContext::~DestructuringIteratorContext() 148{ 149 const auto &labelSet = catchTable_->LabelSet(); 150 const auto *node = iterator_.Node(); 151 152 pg_->SetLabel(node, labelSet.TryEnd()); 153 154 // Normal completion 155 pg_->LoadAccumulator(node, iterator_.Done()); 156 pg_->BranchIfTrue(node, labelSet.CatchEnd()); 157 iterator_.Close(false); 158 159 pg_->Branch(node, labelSet.CatchEnd()); 160 161 Label *end = pg_->AllocLabel(); 162 pg_->SetLabel(node, labelSet.CatchBegin()); 163 pg_->StoreAccumulator(node, iterator_.Result()); 164 pg_->LoadAccumulator(node, iterator_.Done()); 165 166 pg_->BranchIfTrue(node, end); 167 pg_->LoadAccumulator(node, iterator_.Result()); 168 iterator_.Close(true); 169 pg_->SetLabel(node, end); 170 pg_->LoadAccumulator(node, iterator_.Result()); 171 pg_->EmitThrow(node); 172 pg_->SetLabel(node, labelSet.CatchEnd()); 173} 174 175void DestructuringIteratorContext::AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel) 176{ 177 if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) { 178 return; 179 } 180 181 iterator_.Close(false); 182} 183 184void TryContext::InitFinalizer() 185{ 186 ASSERT(tryStmt_); 187 188 if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) { 189 return; 190 } 191 192 finalizerRun_ = pg_->AllocReg(); 193 pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); 194} 195 196void TryContext::InitCatchTable() 197{ 198 catchTable_ = pg_->CreateCatchTable(); 199} 200 201const TryLabelSet &TryContext::LabelSet() const 202{ 203 return catchTable_->LabelSet(); 204} 205 206bool TryContext::HasFinalizer() const 207{ 208 return hasFinalizer_; 209} 210 211void TryContext::EmitFinalizer() 212{ 213 if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) { 214 return; 215 } 216 217 inFinalizer_ = true; 218 tryStmt_->FinallyBlock()->Compile(pg_); 219 inFinalizer_ = false; 220} 221 222void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, 223 [[maybe_unused]] const util::StringView &targetLabel) 224{ 225 EmitFinalizer(); 226} 227} // namespace panda::es2panda::compiler 228