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 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
HasTryCatch() const90 bool LexEnvContext::HasTryCatch() const
91 {
92 return envScope_->HasEnv();
93 }
94
AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel)95 void 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
IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)110 IteratorContext::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
~IteratorContext()117 IteratorContext::~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
AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel)130 void 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
DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator)140 DestructuringIteratorContext::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
~DestructuringIteratorContext()147 DestructuringIteratorContext::~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
AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel)175 void 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
InitFinalizer()184 void 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
InitCatchTable()196 void TryContext::InitCatchTable()
197 {
198 catchTable_ = pg_->CreateCatchTable();
199 }
200
LabelSet() const201 const TryLabelSet &TryContext::LabelSet() const
202 {
203 return catchTable_->LabelSet();
204 }
205
HasFinalizer() const206 bool TryContext::HasFinalizer() const
207 {
208 return hasFinalizer_;
209 }
210
EmitFinalizer()211 void 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
AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel)222 void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
223 [[maybe_unused]] const util::StringView &targetLabel)
224 {
225 EmitFinalizer();
226 }
227 } // namespace panda::es2panda::compiler
228