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