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 "tryStatement.h"
17
18 #include <compiler/core/pandagen.h>
19 #include <compiler/base/catchTable.h>
20 #include <ir/astDump.h>
21 #include <ir/base/catchClause.h>
22 #include <ir/statements/blockStatement.h>
23
24 namespace panda::es2panda::ir {
25
Iterate(const NodeTraverser & cb) const26 void TryStatement::Iterate(const NodeTraverser &cb) const
27 {
28 cb(block_);
29
30 if (catchClause_) {
31 cb(catchClause_);
32 }
33
34 if (finalizer_) {
35 cb(finalizer_);
36 }
37 }
38
Dump(ir::AstDumper * dumper) const39 void TryStatement::Dump(ir::AstDumper *dumper) const
40 {
41 dumper->Add({{"type", "TryStatement"},
42 {"block", block_},
43 {"handler", AstDumper::Nullable(catchClause_)},
44 {"finalizer", AstDumper::Nullable(finalizer_)}});
45 }
46
CompileFinally(compiler::PandaGen * pg,compiler::TryContext * tryCtx,const compiler::TryLabelSet & labelSet) const47 void TryStatement::CompileFinally(compiler::PandaGen *pg, compiler::TryContext *tryCtx,
48 const compiler::TryLabelSet &labelSet) const
49 {
50 compiler::RegScope rs(pg);
51 compiler::VReg exception = pg->AllocReg();
52 pg->StoreConst(this, exception, compiler::Constant::JS_HOLE);
53 pg->Branch(this, labelSet.CatchEnd());
54
55 pg->SetLabel(this, labelSet.CatchBegin());
56 pg->StoreAccumulator(this, exception);
57
58 pg->SetLabel(this, labelSet.CatchEnd());
59
60 compiler::Label *label = pg->AllocLabel();
61 pg->LoadAccumulator(this, tryCtx->FinalizerRun());
62
63 pg->BranchIfNotUndefined(this, label);
64 pg->StoreAccumulator(this, tryCtx->FinalizerRun());
65 tryCtx->EmitFinalizer();
66 pg->SetLabel(this, label);
67
68 pg->LoadAccumulator(this, exception);
69 pg->EmitRethrow(this);
70 }
71
CompileTryCatchFinally(compiler::PandaGen * pg) const72 void TryStatement::CompileTryCatchFinally(compiler::PandaGen *pg) const
73 {
74 ASSERT(catchClause_ && finalizer_);
75
76 compiler::TryContext tryCtx(pg, this);
77 const auto &labelSet = tryCtx.LabelSet();
78
79 pg->SetLabel(this, labelSet.TryBegin());
80 {
81 compiler::TryContext innerTryCtx(pg, this, false);
82 const auto &innerLabelSet = innerTryCtx.LabelSet();
83
84 pg->SetLabel(this, innerLabelSet.TryBegin());
85 block_->Compile(pg);
86 pg->SetLabel(this, innerLabelSet.TryEnd());
87
88 pg->Branch(this, innerLabelSet.CatchEnd());
89
90 pg->SetLabel(this, innerLabelSet.CatchBegin());
91 catchClause_->Compile(pg);
92 pg->SetLabel(this, innerLabelSet.CatchEnd());
93 }
94 pg->SetLabel(this, labelSet.TryEnd());
95
96 CompileFinally(pg, &tryCtx, labelSet);
97 }
98
CompileTryFinally(compiler::PandaGen * pg) const99 void TryStatement::CompileTryFinally(compiler::PandaGen *pg) const
100 {
101 ASSERT(!catchClause_ && finalizer_);
102
103 compiler::TryContext tryCtx(pg, this);
104 const auto &labelSet = tryCtx.LabelSet();
105
106 pg->SetLabel(this, labelSet.TryBegin());
107 {
108 compiler::TryContext innerTryCtx(pg, this, false);
109 const auto &innerLabelSet = innerTryCtx.LabelSet();
110
111 pg->SetLabel(this, innerLabelSet.TryBegin());
112 block_->Compile(pg);
113 pg->SetLabel(this, innerLabelSet.TryEnd());
114
115 pg->Branch(this, innerLabelSet.CatchEnd());
116
117 pg->SetLabel(this, innerLabelSet.CatchBegin());
118 pg->EmitThrow(this);
119 pg->SetLabel(this, innerLabelSet.CatchEnd());
120 }
121 pg->SetLabel(this, labelSet.TryEnd());
122
123 CompileFinally(pg, &tryCtx, labelSet);
124 }
125
CompileTryCatch(compiler::PandaGen * pg) const126 void TryStatement::CompileTryCatch(compiler::PandaGen *pg) const
127 {
128 ASSERT(catchClause_ && !finalizer_);
129
130 compiler::TryContext tryCtx(pg, this);
131 const auto &labelSet = tryCtx.LabelSet();
132
133 pg->SetLabel(this, labelSet.TryBegin());
134 block_->Compile(pg);
135 pg->SetLabel(this, labelSet.TryEnd());
136
137 pg->Branch(this, labelSet.CatchEnd());
138
139 pg->SetLabel(this, labelSet.CatchBegin());
140 catchClause_->Compile(pg);
141 pg->SetLabel(this, labelSet.CatchEnd());
142 }
143
Compile(compiler::PandaGen * pg) const144 void TryStatement::Compile(compiler::PandaGen *pg) const
145 {
146 if (finalizer_) {
147 if (catchClause_) {
148 CompileTryCatchFinally(pg);
149 } else {
150 CompileTryFinally(pg);
151 }
152 } else {
153 CompileTryCatch(pg);
154 }
155 }
156
Check(checker::Checker * checker) const157 checker::Type *TryStatement::Check(checker::Checker *checker) const
158 {
159 block_->Check(checker);
160
161 if (catchClause_) {
162 catchClause_->Check(checker);
163 }
164
165 if (finalizer_) {
166 finalizer_->Check(checker);
167 }
168
169 return nullptr;
170 }
171
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)172 void TryStatement::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
173 {
174 block_ = std::get<ir::AstNode *>(cb(block_))->AsBlockStatement();
175
176 if (catchClause_) {
177 catchClause_ = std::get<ir::AstNode *>(cb(catchClause_))->AsCatchClause();
178 }
179
180 if (finalizer_) {
181 finalizer_ = std::get<ir::AstNode *>(cb(finalizer_))->AsBlockStatement();
182 }
183 }
184
185 } // namespace panda::es2panda::ir
186