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