• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 namespace panda::es2panda::compiler {
DynamicContext(PandaGen * pg,LabelTarget target)26 DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_)
27 {
28     pg_->dynamicContext_ = this;
29 }
30 
~DynamicContext()31 DynamicContext::~DynamicContext()
32 {
33     pg_->dynamicContext_ = prev_;
34 }
35 
LabelContext(PandaGen * pg,const ir::LabelledStatement * labelledStmt)36 LabelContext::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 
~LabelContext()48 LabelContext::~LabelContext()
49 {
50     if (!label_) {
51         return;
52     }
53 
54     pg_->SetLabel(labelledStmt_, label_);
55 }
56 
LexEnvContext(VariableEnvScope * envScope,PandaGen * pg,LabelTarget target)57 LexEnvContext::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 
~LexEnvContext()71 LexEnvContext::~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     if (!GetTryEndFlag()) {
81         pg_->SetLabel(node, labelSet.TryEnd());
82     }
83     SetTryEndFlag(false);
84     pg_->Branch(node, labelSet.CatchEnd());
85 
86     pg_->SetLabel(node, labelSet.CatchBegin());
87     pg_->PopLexEnv(node);
88     pg_->EmitThrow(node);
89     pg_->SetLabel(node, labelSet.CatchEnd());
90     pg_->PopLexEnv(node);
91 }
92 
HasTryCatch() const93 bool LexEnvContext::HasTryCatch() const
94 {
95     return envScope_->HasEnv();
96 }
97 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)98 void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
99                                  const util::StringView &targetLabel)
100 {
101     if (!envScope_->HasEnv()) {
102         return;
103     }
104 
105     const auto *node = envScope_->Scope()->Node();
106     // Process the continue label in the ForUpdate Statement.
107     if (node->IsForUpdateStatement()) {
108         if (targetLabel == LabelTarget::CONTINUE_LABEL || targetLabel == LabelTarget::BREAK_LABEL) {
109             return;
110         }
111 
112         DynamicContext *iter = this->Prev();
113         // Because multiple labels can be set before the loop statement,
114         // iterates forward until the target label is found.
115         while (iter && iter->Type() == DynamicContextType::LABEL) {
116             const auto &labelName = iter->Target().ContinueLabel();
117             if (labelName == targetLabel) {
118                 return;
119             }
120             iter = iter->Prev();
121         }
122         SetTryEndLabel(node);
123         pg_->PopLexEnv(node);
124         return;
125     }
126 
127     SetTryEndLabel(node);
128     pg_->PopLexEnv(node);
129 }
130 
SetTryEndLabel(const ir::AstNode * node)131 void LexEnvContext::SetTryEndLabel(const ir::AstNode *node)
132 {
133     if (!GetTryEndFlag()) {
134         SetTryEndFlag(true);
135         const auto &labelSet = catchTable_->LabelSet();
136         pg_->SetLabel(node, labelSet.TryEnd());
137     }
138 }
139 
IteratorContext(PandaGen * pg,const Iterator & iterator,LabelTarget target)140 IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)
141     : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable())
142 {
143     const auto &labelSet = catchTable_->LabelSet();
144     pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
145 }
146 
~IteratorContext()147 IteratorContext::~IteratorContext()
148 {
149     const auto &labelSet = catchTable_->LabelSet();
150     const auto *node = iterator_.Node();
151 
152     pg_->SetLabel(node, labelSet.TryEnd());
153     pg_->Branch(node, labelSet.CatchEnd());
154 
155     pg_->SetLabel(node, labelSet.CatchBegin());
156     iterator_.Close(true);
157     pg_->SetLabel(node, labelSet.CatchEnd());
158 }
159 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)160 void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
161                                    [[maybe_unused]] const util::StringView &targetLabel)
162 {
163     if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
164         return;
165     }
166 
167     iterator_.Close(false);
168 }
169 
DestructuringIteratorContext(PandaGen * pg,const DestructuringIterator & iterator)170 DestructuringIteratorContext::DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator)
171     : DynamicContext(pg, {}), iterator_(iterator), catchTable_(pg->CreateCatchTable())
172 {
173     const auto &labelSet = catchTable_->LabelSet();
174     pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
175 }
176 
~DestructuringIteratorContext()177 DestructuringIteratorContext::~DestructuringIteratorContext()
178 {
179     const auto &labelSet = catchTable_->LabelSet();
180     const auto *node = iterator_.Node();
181 
182     pg_->SetLabel(node, labelSet.TryEnd());
183 
184     // Normal completion
185     pg_->LoadAccumulator(node, iterator_.Done());
186     pg_->BranchIfTrue(node, labelSet.CatchEnd());
187     iterator_.Close(false);
188 
189     pg_->Branch(node, labelSet.CatchEnd());
190 
191     Label *end = pg_->AllocLabel();
192     pg_->SetLabel(node, labelSet.CatchBegin());
193     pg_->StoreAccumulator(node, iterator_.Result());
194     pg_->LoadAccumulator(node, iterator_.Done());
195 
196     pg_->BranchIfTrue(node, end);
197     pg_->LoadAccumulator(node, iterator_.Result());
198     iterator_.Close(true);
199     pg_->SetLabel(node, end);
200     pg_->LoadAccumulator(node, iterator_.Result());
201     pg_->EmitThrow(node);
202     pg_->SetLabel(node, labelSet.CatchEnd());
203 }
204 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)205 void DestructuringIteratorContext::AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel)
206 {
207     if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
208         return;
209     }
210 
211     iterator_.Close(false);
212 }
213 
InitFinalizer()214 void TryContext::InitFinalizer()
215 {
216     ASSERT(tryStmt_);
217 
218     if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) {
219         return;
220     }
221 
222     finalizerRun_ = pg_->AllocReg();
223     pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED);
224 }
225 
InitCatchTable()226 void TryContext::InitCatchTable()
227 {
228     catchTable_ = pg_->CreateCatchTable();
229 }
230 
LabelSet() const231 const TryLabelSet &TryContext::LabelSet() const
232 {
233     return catchTable_->LabelSet();
234 }
235 
HasFinalizer() const236 bool TryContext::HasFinalizer() const
237 {
238     return hasFinalizer_;
239 }
240 
EmitFinalizer()241 void TryContext::EmitFinalizer()
242 {
243     if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) {
244         return;
245     }
246 
247     inFinalizer_ = true;
248     tryStmt_->FinallyBlock()->Compile(pg_);
249     inFinalizer_ = false;
250 }
251 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)252 void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
253                               [[maybe_unused]] const util::StringView &targetLabel)
254 {
255     EmitFinalizer();
256 }
257 }  // namespace panda::es2panda::compiler
258