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