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 return;
41 }
42
43 label_ = pg->AllocLabel();
44 target_.SetBreakTarget(label_);
45 }
46
~LabelContext()47 LabelContext::~LabelContext()
48 {
49 if (!label_) {
50 return;
51 }
52
53 pg_->SetLabel(labelledStmt_, label_);
54 }
55
LexEnvContext(LoopEnvScope * envScope,PandaGen * pg,LabelTarget target)56 LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target)
57 : DynamicContext(pg, target), envScope_(envScope)
58 {
59 if (!envScope_->HasEnv()) {
60 return;
61 }
62
63 catchTable_ = pg_->CreateCatchTable();
64 const auto &labelSet = catchTable_->LabelSet();
65 const auto *node = envScope_->Scope()->Node();
66
67 pg_->SetLabel(node, labelSet.TryBegin());
68 }
69
~LexEnvContext()70 LexEnvContext::~LexEnvContext()
71 {
72 if (!envScope_->HasEnv()) {
73 return;
74 }
75
76 const auto &labelSet = catchTable_->LabelSet();
77 const auto *node = envScope_->Scope()->Node();
78
79 pg_->SetLabel(node, labelSet.TryEnd());
80 pg_->Branch(node, labelSet.CatchEnd());
81
82 pg_->SetLabel(node, labelSet.CatchBegin());
83 pg_->PopLexEnv(node);
84 pg_->EmitThrow(node);
85 pg_->SetLabel(node, labelSet.CatchEnd());
86 pg_->PopLexEnv(node);
87 }
88
HasTryCatch() const89 bool LexEnvContext::HasTryCatch() const
90 {
91 return envScope_->HasEnv();
92 }
93
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)94 void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
95 [[maybe_unused]] const util::StringView &targetLabel)
96 {
97 if (!envScope_->HasEnv()) {
98 return;
99 }
100
101 const auto *node = envScope_->Scope()->Node();
102 if (node->IsForUpdateStatement() || node->IsDoWhileStatement()) {
103 return;
104 }
105
106 pg_->PopLexEnv(node);
107 }
108
IteratorContext(PandaGen * pg,const Iterator & iterator,LabelTarget target)109 IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)
110 : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable())
111 {
112 const auto &labelSet = catchTable_->LabelSet();
113 pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
114 }
115
~IteratorContext()116 IteratorContext::~IteratorContext()
117 {
118 const auto &labelSet = catchTable_->LabelSet();
119 const auto *node = iterator_.Node();
120
121 pg_->SetLabel(node, labelSet.TryEnd());
122 pg_->Branch(node, labelSet.CatchEnd());
123
124 pg_->SetLabel(node, labelSet.CatchBegin());
125 iterator_.Close(true);
126 pg_->SetLabel(node, labelSet.CatchEnd());
127 }
128
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)129 void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
130 [[maybe_unused]] const util::StringView &targetLabel)
131 {
132 if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
133 return;
134 }
135
136 iterator_.Close(false);
137 }
138
DestructuringIteratorContext(PandaGen * pg,const DestructuringIterator & iterator)139 DestructuringIteratorContext::DestructuringIteratorContext(PandaGen *pg, const DestructuringIterator &iterator)
140 : DynamicContext(pg, {}), iterator_(iterator), catchTable_(pg->CreateCatchTable())
141 {
142 const auto &labelSet = catchTable_->LabelSet();
143 pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
144 }
145
~DestructuringIteratorContext()146 DestructuringIteratorContext::~DestructuringIteratorContext()
147 {
148 const auto &labelSet = catchTable_->LabelSet();
149 const auto *node = iterator_.Node();
150
151 pg_->SetLabel(node, labelSet.TryEnd());
152
153 // Normal completion
154 pg_->LoadAccumulator(node, iterator_.Done());
155 pg_->BranchIfTrue(node, labelSet.CatchEnd());
156 iterator_.Close(false);
157
158 pg_->Branch(node, labelSet.CatchEnd());
159
160 Label *end = pg_->AllocLabel();
161 pg_->SetLabel(node, labelSet.CatchBegin());
162 pg_->StoreAccumulator(node, iterator_.Result());
163 pg_->LoadAccumulator(node, iterator_.Done());
164
165 pg_->BranchIfTrue(node, end);
166 pg_->LoadAccumulator(node, iterator_.Result());
167 iterator_.Close(true);
168 pg_->SetLabel(node, end);
169 pg_->LoadAccumulator(node, iterator_.Result());
170 pg_->EmitThrow(node);
171 pg_->SetLabel(node, labelSet.CatchEnd());
172 }
173
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)174 void DestructuringIteratorContext::AbortContext(ControlFlowChange cfc, const util::StringView &targetLabel)
175 {
176 if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
177 return;
178 }
179
180 iterator_.Close(false);
181 }
182
InitFinalizer()183 void TryContext::InitFinalizer()
184 {
185 ASSERT(tryStmt_);
186
187 if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) {
188 return;
189 }
190
191 finalizerRun_ = pg_->AllocReg();
192 pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED);
193 }
194
InitCatchTable()195 void TryContext::InitCatchTable()
196 {
197 catchTable_ = pg_->CreateCatchTable();
198 }
199
LabelSet() const200 const TryLabelSet &TryContext::LabelSet() const
201 {
202 return catchTable_->LabelSet();
203 }
204
HasFinalizer() const205 bool TryContext::HasFinalizer() const
206 {
207 return hasFinalizer_;
208 }
209
EmitFinalizer()210 void TryContext::EmitFinalizer()
211 {
212 if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) {
213 return;
214 }
215
216 inFinalizer_ = true;
217 tryStmt_->FinallyBlock()->Compile(pg_);
218 inFinalizer_ = false;
219 }
220
AbortContext(ControlFlowChange cfc,const util::StringView & targetLabel)221 void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
222 [[maybe_unused]] const util::StringView &targetLabel)
223 {
224 EmitFinalizer();
225 }
226 } // namespace panda::es2panda::compiler
227