1 /*
2 * Copyright (c) 2021 - 2023 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 "codeGen.h"
17
18 #include "compiler/core/emitter.h"
19 #include "compiler/core/regAllocator.h"
20 #include "compiler/core/regScope.h"
21 #include "compiler/core/compilerContext.h"
22 #include "compiler/core/dynamicContext.h"
23 #include "compiler/base/catchTable.h"
24 #include "ir/base/scriptFunction.h"
25 #include "ir/expressions/identifier.h"
26
27 namespace panda::es2panda::compiler {
28
Allocator() const29 ArenaAllocator *CodeGen::Allocator() const noexcept
30 {
31 return allocator_;
32 }
33
CatchList() const34 const ArenaVector<CatchTable *> &CodeGen::CatchList() const noexcept
35 {
36 return catchList_;
37 }
38
TopScope() const39 const varbinder::FunctionScope *CodeGen::TopScope() const noexcept
40 {
41 return topScope_;
42 }
43
Scope() const44 const varbinder::Scope *CodeGen::Scope() const noexcept
45 {
46 return scope_;
47 }
48
RootNode() const49 const ir::AstNode *CodeGen::RootNode() const noexcept
50 {
51 return rootNode_;
52 }
53
Insns()54 ArenaVector<IRNode *> &CodeGen::Insns() noexcept
55 {
56 return insns_;
57 }
58
Insns() const59 const ArenaVector<IRNode *> &CodeGen::Insns() const noexcept
60 {
61 return insns_;
62 }
63
NextReg() const64 VReg CodeGen::NextReg() const noexcept
65 {
66 return VReg {usedRegs_};
67 }
68
TotalRegsNum() const69 std::uint32_t CodeGen::TotalRegsNum() const noexcept
70 {
71 return totalRegs_;
72 }
73
LabelCount() const74 std::size_t CodeGen::LabelCount() const noexcept
75 {
76 return labelId_;
77 }
78
Debuginfo() const79 const DebugInfo &CodeGen::Debuginfo() const noexcept
80 {
81 return debugInfo_;
82 }
83
AllocReg()84 VReg CodeGen::AllocReg()
85 {
86 const VReg vreg(usedRegs_--);
87 SetVRegType(vreg, nullptr);
88 return vreg;
89 }
90
AllocRegWithType(const checker::Type * const type)91 VReg CodeGen::AllocRegWithType(const checker::Type *const type)
92 {
93 const VReg vreg(usedRegs_--);
94 SetVRegType(vreg, type);
95 return vreg;
96 }
97
SetVRegType(const VReg vreg,const checker::Type * const type)98 void CodeGen::SetVRegType(const VReg vreg, const checker::Type *const type)
99 {
100 typeMap_.insert_or_assign(vreg, type);
101 }
102
GetVRegType(const VReg vreg) const103 const checker::Type *CodeGen::GetVRegType(const VReg vreg) const
104 {
105 const auto it = typeMap_.find(vreg);
106 return it != typeMap_.end() ? it->second : nullptr;
107 }
108
TypeForVar(varbinder::Variable const * var) const109 checker::Type const *CodeGen::TypeForVar(varbinder::Variable const *var) const noexcept
110 {
111 return var->TsType();
112 }
113
AllocLabel()114 Label *CodeGen::AllocLabel()
115 {
116 std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++);
117 return sa_.AllocLabel(std::move(id));
118 }
119
IsDebug() const120 bool CodeGen::IsDebug() const noexcept
121 {
122 return context_->IsDebug();
123 }
124
ParamCount() const125 std::uint32_t CodeGen::ParamCount() const noexcept
126 {
127 if (rootNode_->IsProgram()) {
128 return 0U;
129 }
130
131 return rootNode_->AsScriptFunction()->Params().size();
132 }
133
FormalParametersCount() const134 std::uint32_t CodeGen::FormalParametersCount() const noexcept
135 {
136 if (rootNode_->IsProgram()) {
137 return 0U;
138 }
139
140 ASSERT(rootNode_->IsScriptFunction());
141
142 return rootNode_->AsScriptFunction()->FormalParamsLength();
143 }
144
InternalParamCount() const145 std::uint32_t CodeGen::InternalParamCount() const noexcept
146 {
147 static constexpr std::uint32_t HIDDEN_PARAMS = 3U;
148 return ParamCount() + HIDDEN_PARAMS;
149 }
150
InternalName() const151 const util::StringView &CodeGen::InternalName() const noexcept
152 {
153 return topScope_->InternalName();
154 }
155
FunctionName() const156 const util::StringView &CodeGen::FunctionName() const noexcept
157 {
158 return topScope_->Name();
159 }
160
VarBinder() const161 varbinder::VarBinder *CodeGen::VarBinder() const noexcept
162 {
163 return context_->VarBinder();
164 }
165
AddLiteralBuffer(LiteralBuffer && buf)166 std::int32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf)
167 {
168 programElement_->BuffStorage().emplace_back(std::move(buf));
169 return literalBufferIdx_++;
170 }
171
LoadAccumulatorString(const ir::AstNode * node,const util::StringView & str)172 void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str)
173 {
174 sa_.Emit<LdaStr>(node, str);
175 }
176
SetLabel(const ir::AstNode * node,Label * label)177 void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label)
178 {
179 sa_.AddLabel(label);
180 }
181
Branch(const ir::AstNode * node,Label * label)182 void CodeGen::Branch(const ir::AstNode *node, Label *label)
183 {
184 sa_.Emit<Jmp>(node, label);
185 }
186
CheckControlFlowChange() const187 bool CodeGen::CheckControlFlowChange() const
188 {
189 const auto *iter = dynamicContext_;
190
191 while (iter != nullptr) {
192 if (iter->HasFinalizer()) {
193 return true;
194 }
195
196 iter = iter->Prev();
197 }
198
199 return false;
200 }
201
ControlFlowChangeBreak(const ir::Identifier * label)202 Label *CodeGen::ControlFlowChangeBreak(const ir::Identifier *label)
203 {
204 auto *iter = dynamicContext_;
205
206 util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL;
207 Label *breakTarget = nullptr;
208
209 while (iter != nullptr) {
210 iter->AbortContext(ControlFlowChange::BREAK, labelName);
211 const auto *constIter = iter;
212
213 const auto &labelTargetName = constIter->Target().BreakLabel();
214
215 if (constIter->Target().BreakTarget() != nullptr) {
216 breakTarget = constIter->Target().BreakTarget();
217 }
218
219 if (labelTargetName == labelName) {
220 break;
221 }
222
223 iter = iter->Prev();
224 }
225
226 return breakTarget;
227 }
228
ControlFlowChangeContinue(const ir::Identifier * label)229 Label *CodeGen::ControlFlowChangeContinue(const ir::Identifier *label)
230 {
231 auto *iter = dynamicContext_;
232 util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL;
233 Label *continueTarget = nullptr;
234
235 while (iter != nullptr) {
236 iter->AbortContext(ControlFlowChange::CONTINUE, labelName);
237 const auto *constIter = iter;
238
239 const auto &labelTargetName = constIter->Target().ContinueLabel();
240
241 if (constIter->Target().ContinueTarget() != nullptr) {
242 continueTarget = constIter->Target().ContinueTarget();
243 }
244
245 if (labelTargetName == labelName) {
246 break;
247 }
248
249 iter = iter->Prev();
250 }
251
252 return continueTarget;
253 }
254
TryDepth() const255 std::uint32_t CodeGen::TryDepth() const
256 {
257 const auto *iter = dynamicContext_;
258 std::uint32_t depth = 0;
259
260 while (iter != nullptr) {
261 if (iter->HasTryCatch()) {
262 depth++;
263 }
264
265 iter = iter->Prev();
266 }
267
268 return depth;
269 }
270
CreateCatchTable(const util::StringView exceptionType)271 CatchTable *CodeGen::CreateCatchTable(const util::StringView exceptionType)
272 {
273 auto *catchTable = allocator_->New<CatchTable>(this, TryDepth(), exceptionType);
274 catchList_.push_back(catchTable);
275 return catchTable;
276 }
277
CreateCatchTable(const LabelPair tryLabelPair,const util::StringView exceptionType)278 CatchTable *CodeGen::CreateCatchTable(const LabelPair tryLabelPair, const util::StringView exceptionType)
279 {
280 auto *catchTable = allocator_->New<CatchTable>(this, TryDepth(), tryLabelPair, exceptionType);
281 catchList_.push_back(catchTable);
282 return catchTable;
283 }
284
SortCatchTables()285 void CodeGen::SortCatchTables()
286 {
287 std::stable_sort(catchList_.begin(), catchList_.end(),
288 [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); });
289 }
290
SetFirstStmt(const ir::Statement * stmt)291 void CodeGen::SetFirstStmt(const ir::Statement *stmt) noexcept
292 {
293 debugInfo_.firstStmt_ = stmt;
294 }
295
Unimplemented()296 void CodeGen::Unimplemented()
297 {
298 throw Error(ErrorType::GENERIC, "", "Unimplemented code path");
299 }
300
Sa()301 SimpleAllocator &CodeGen::Sa() noexcept
302 {
303 return sa_;
304 }
305
Sa() const306 const SimpleAllocator &CodeGen::Sa() const noexcept
307 {
308 return sa_;
309 }
310
Ra()311 RegAllocator &CodeGen::Ra() noexcept
312 {
313 return ra_;
314 }
315
Ra() const316 const RegAllocator &CodeGen::Ra() const noexcept
317 {
318 return ra_;
319 }
320
Rra()321 RangeRegAllocator &CodeGen::Rra() noexcept
322 {
323 return rra_;
324 }
325
Rra() const326 const RangeRegAllocator &CodeGen::Rra() const noexcept
327 {
328 return rra_;
329 }
330
Context() const331 CompilerContext *CodeGen::Context() const noexcept
332 {
333 return context_;
334 }
335
ProgElement() const336 ProgramElement *CodeGen::ProgElement() const noexcept
337 {
338 return programElement_;
339 }
340
GetTypeMap()341 CodeGen::TypeMap &CodeGen::GetTypeMap() noexcept
342 {
343 return typeMap_;
344 }
345
GetTypeMap() const346 const CodeGen::TypeMap &CodeGen::GetTypeMap() const noexcept
347 {
348 return typeMap_;
349 }
350
GetAstCompiler() const351 compiler::AstCompiler *CodeGen::GetAstCompiler() const
352 {
353 return astCompiler_;
354 }
355 } // namespace panda::es2panda::compiler
356