• 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 
HandleForUpdateDirectReturnContext()98 void LexEnvContext::HandleForUpdateDirectReturnContext()
99 {
100     if (!envScope_->HasEnv()) {
101         return;
102     }
103     const auto *node = envScope_->Scope()->Node();
104     if (node->IsForUpdateStatement()) {
105         pg_->PopLexEnv(node);
106     }
107 }
108 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)109 void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
110                                  const util::StringView &targetLabel)
111 {
112     if (!envScope_->HasEnv()) {
113         return;
114     }
115 
116     const auto *node = envScope_->Scope()->Node();
117     // Process the continue label in the ForUpdate Statement.
118     if (node->IsForUpdateStatement()) {
119         if (targetLabel == LabelTarget::CONTINUE_LABEL || targetLabel == LabelTarget::BREAK_LABEL ||
120             targetLabel == LabelTarget::RETURN_LABEL) {
121             return;
122         }
123 
124         DynamicContext *iter = this->Prev();
125         // Because multiple labels can be set before the loop statement,
126         // iterates forward until the target label is found.
127         while (iter && iter->Type() == DynamicContextType::LABEL) {
128             const auto &labelName = iter->Target().ContinueLabel();
129             if (labelName == targetLabel) {
130                 return;
131             }
132             iter = iter->Prev();
133         }
134         SetTryEndLabel(node);
135         pg_->PopLexEnv(node);
136         return;
137     }
138 
139     SetTryEndLabel(node);
140     pg_->PopLexEnv(node);
141 }
142 
SetTryEndLabel(const ir::AstNode * node)143 void LexEnvContext::SetTryEndLabel(const ir::AstNode *node)
144 {
145     if (!GetTryEndFlag()) {
146         SetTryEndFlag(true);
147         const auto &labelSet = catchTable_->LabelSet();
148         pg_->SetLabel(node, labelSet.TryEnd());
149     }
150 }
151 
IteratorContext(PandaGen * pg,const Iterator & iterator,LabelTarget target)152 IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)
153     : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable())
154 {
155     const auto &labelSet = catchTable_->LabelSet();
156     pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
157 }
158 
~IteratorContext()159 IteratorContext::~IteratorContext()
160 {
161     const auto &labelSet = catchTable_->LabelSet();
162     const auto *node = iterator_.Node();
163 
164     pg_->SetLabel(node, labelSet.TryEnd());
165     pg_->Branch(node, labelSet.CatchEnd());
166 
167     pg_->SetLabel(node, labelSet.CatchBegin());
168     iterator_.Close(true);
169     pg_->SetLabel(node, labelSet.CatchEnd());
170 }
171 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)172 void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
173                                    [[maybe_unused]] const util::StringView &targetLabel)
174 {
175     if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
176         return;
177     }
178 
179     iterator_.Close(false);
180 }
181 
DestructuringIteratorContext(PandaGen * pg,const DestructuringIterator & iterator)182 DestructuringIteratorContext::DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator)
183     : DynamicContext(pg, {}), iterator_(iterator), catchTable_(pg->CreateCatchTable())
184 {
185     const auto &labelSet = catchTable_->LabelSet();
186     pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
187 }
188 
~DestructuringIteratorContext()189 DestructuringIteratorContext::~DestructuringIteratorContext()
190 {
191     const auto &labelSet = catchTable_->LabelSet();
192     const auto *node = iterator_.Node();
193 
194     pg_->SetLabel(node, labelSet.TryEnd());
195 
196     // Normal completion
197     pg_->LoadAccumulator(node, iterator_.Done());
198     pg_->BranchIfTrue(node, labelSet.CatchEnd());
199     iterator_.Close(false);
200 
201     pg_->Branch(node, labelSet.CatchEnd());
202 
203     Label *end = pg_->AllocLabel();
204     pg_->SetLabel(node, labelSet.CatchBegin());
205     pg_->StoreAccumulator(node, iterator_.Result());
206     pg_->LoadAccumulator(node, iterator_.Done());
207 
208     pg_->BranchIfTrue(node, end);
209     pg_->LoadAccumulator(node, iterator_.Result());
210     iterator_.Close(true);
211     pg_->SetLabel(node, end);
212     pg_->LoadAccumulator(node, iterator_.Result());
213     pg_->EmitThrow(node);
214     pg_->SetLabel(node, labelSet.CatchEnd());
215 }
216 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)217 void DestructuringIteratorContext::AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel)
218 {
219     if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
220         return;
221     }
222 
223     iterator_.Close(false);
224 }
225 
InitFinalizer()226 void TryContext::InitFinalizer()
227 {
228     ASSERT(tryStmt_);
229 
230     if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) {
231         return;
232     }
233 
234     finalizerRun_ = pg_->AllocReg();
235     pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED);
236 }
237 
InitCatchTable()238 void TryContext::InitCatchTable()
239 {
240     catchTable_ = pg_->CreateCatchTable();
241 }
242 
LabelSet() const243 const TryLabelSet &TryContext::LabelSet() const
244 {
245     return catchTable_->LabelSet();
246 }
247 
HasFinalizer() const248 bool TryContext::HasFinalizer() const
249 {
250     return hasFinalizer_;
251 }
252 
EmitFinalizer()253 void TryContext::EmitFinalizer()
254 {
255     if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) {
256         return;
257     }
258 
259     inFinalizer_ = true;
260     tryStmt_->FinallyBlock()->Compile(pg_);
261     inFinalizer_ = false;
262 }
263 
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)264 void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
265                               [[maybe_unused]] const util::StringView &targetLabel)
266 {
267     EmitFinalizer();
268 }
269 }  // namespace panda::es2panda::compiler
270