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