1 /*
2 * Copyright (c) 2021 - 2025 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 "public/public.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 #include "util/options.h"
27
28 namespace ark::es2panda::compiler {
29
Allocator() const30 ArenaAllocator *CodeGen::Allocator() const noexcept
31 {
32 return allocator_;
33 }
34
CatchList() const35 const ArenaVector<CatchTable *> &CodeGen::CatchList() const noexcept
36 {
37 return catchList_;
38 }
39
TopScope() const40 const varbinder::FunctionScope *CodeGen::TopScope() const noexcept
41 {
42 return topScope_;
43 }
44
Scope() const45 const varbinder::Scope *CodeGen::Scope() const noexcept
46 {
47 return scope_;
48 }
49
RootNode() const50 const ir::AstNode *CodeGen::RootNode() const noexcept
51 {
52 return rootNode_;
53 }
54
Insns()55 ArenaVector<IRNode *> &CodeGen::Insns() noexcept
56 {
57 return insns_;
58 }
59
Insns() const60 const ArenaVector<IRNode *> &CodeGen::Insns() const noexcept
61 {
62 return insns_;
63 }
64
NextReg() const65 VReg CodeGen::NextReg() const noexcept
66 {
67 return VReg {usedRegs_};
68 }
69
TotalRegsNum() const70 std::uint32_t CodeGen::TotalRegsNum() const noexcept
71 {
72 return totalRegs_;
73 }
74
LabelCount() const75 std::size_t CodeGen::LabelCount() const noexcept
76 {
77 return labelId_;
78 }
79
Debuginfo() const80 const DebugInfo &CodeGen::Debuginfo() const noexcept
81 {
82 return debugInfo_;
83 }
84
AllocReg()85 VReg CodeGen::AllocReg()
86 {
87 const VReg vreg(usedRegs_--);
88 SetVRegType(vreg, nullptr);
89 return vreg;
90 }
91
AllocRegWithType(const checker::Type * const type)92 VReg CodeGen::AllocRegWithType(const checker::Type *const type)
93 {
94 const VReg vreg(usedRegs_--);
95 SetVRegType(vreg, type);
96 return vreg;
97 }
98
SetVRegType(const VReg vreg,const checker::Type * const type)99 void CodeGen::SetVRegType(const VReg vreg, const checker::Type *const type)
100 {
101 typeMap_.insert_or_assign(vreg, type);
102 }
103
GetVRegType(const VReg vreg) const104 const checker::Type *CodeGen::GetVRegType(const VReg vreg) const
105 {
106 const auto it = typeMap_.find(vreg);
107 return it != typeMap_.end() ? it->second : nullptr;
108 }
109
TypeForVar(varbinder::Variable const * var) const110 checker::Type const *CodeGen::TypeForVar(varbinder::Variable const *var) const noexcept
111 {
112 return var->TsType();
113 }
114
AllocLabel()115 Label *CodeGen::AllocLabel()
116 {
117 std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++);
118 return sa_.AllocLabel(std::move(id));
119 }
120
IsDebug() const121 bool CodeGen::IsDebug() const noexcept
122 {
123 return context_->config->options->IsDebugInfo();
124 }
125
ParamCount() const126 std::uint32_t CodeGen::ParamCount() const noexcept
127 {
128 if (rootNode_->IsProgram()) {
129 return 0U;
130 }
131
132 return rootNode_->AsScriptFunction()->Params().size();
133 }
134
FormalParametersCount() const135 std::uint32_t CodeGen::FormalParametersCount() const noexcept
136 {
137 if (rootNode_->IsProgram()) {
138 return 0U;
139 }
140
141 ES2PANDA_ASSERT(rootNode_->IsScriptFunction());
142
143 return rootNode_->AsScriptFunction()->FormalParamsLength();
144 }
145
InternalParamCount() const146 std::uint32_t CodeGen::InternalParamCount() const noexcept
147 {
148 static constexpr std::uint32_t HIDDEN_PARAMS = 3U;
149 return ParamCount() + HIDDEN_PARAMS;
150 }
151
InternalName() const152 const util::StringView &CodeGen::InternalName() const noexcept
153 {
154 return topScope_->InternalName();
155 }
156
FunctionName() const157 const util::StringView &CodeGen::FunctionName() const noexcept
158 {
159 return topScope_->Name();
160 }
161
VarBinder() const162 varbinder::VarBinder *CodeGen::VarBinder() const noexcept
163 {
164 return context_->parserProgram->VarBinder();
165 }
166
AddLiteralBuffer(LiteralBuffer && buf)167 std::uint32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf)
168 {
169 programElement_->BuffStorage().emplace_back(std::move(buf));
170 return literalBufferIdx_++;
171 }
172
LoadAccumulatorString(const ir::AstNode * node,const util::StringView & str)173 void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str)
174 {
175 sa_.Emit<LdaStr>(node, str);
176 }
177
SetLabel(const ir::AstNode * node,Label * label)178 void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label)
179 {
180 sa_.AddLabel(label);
181 }
182
Branch(const ir::AstNode * node,Label * label)183 void CodeGen::Branch(const ir::AstNode *node, Label *label)
184 {
185 sa_.Emit<Jmp>(node, label);
186 }
187
CheckControlFlowChange() const188 bool CodeGen::CheckControlFlowChange() const
189 {
190 const auto *iter = dynamicContext_;
191
192 while (iter != nullptr) {
193 if (iter->HasFinalizer()) {
194 return true;
195 }
196
197 iter = iter->Prev();
198 }
199
200 return false;
201 }
202
ControlFlowChangeBreak(const ir::Identifier * label)203 Label *CodeGen::ControlFlowChangeBreak(const ir::Identifier *label)
204 {
205 auto *iter = dynamicContext_;
206
207 util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL;
208 Label *breakTarget = nullptr;
209
210 while (iter != nullptr) {
211 iter->AbortContext(ControlFlowChange::BREAK, labelName);
212 const auto *constIter = iter;
213
214 const auto &labelTargetName = constIter->Target().BreakLabel();
215
216 if (constIter->Target().BreakTarget() != nullptr) {
217 breakTarget = constIter->Target().BreakTarget();
218 }
219
220 if (labelTargetName == labelName) {
221 break;
222 }
223
224 iter = iter->Prev();
225 }
226
227 return breakTarget;
228 }
229
ControlFlowChangeContinue(const ir::Identifier * label)230 Label *CodeGen::ControlFlowChangeContinue(const ir::Identifier *label)
231 {
232 auto *iter = dynamicContext_;
233 util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL;
234 Label *continueTarget = nullptr;
235
236 while (iter != nullptr) {
237 iter->AbortContext(ControlFlowChange::CONTINUE, labelName);
238 const auto *constIter = iter;
239
240 const auto &labelTargetName = constIter->Target().ContinueLabel();
241
242 if (constIter->Target().ContinueTarget() != nullptr) {
243 continueTarget = constIter->Target().ContinueTarget();
244 }
245
246 if (labelTargetName == labelName) {
247 break;
248 }
249
250 iter = iter->Prev();
251 }
252
253 return continueTarget;
254 }
255
TryDepth() const256 std::uint32_t CodeGen::TryDepth() const
257 {
258 const auto *iter = dynamicContext_;
259 std::uint32_t depth = 0;
260
261 while (iter != nullptr) {
262 if (iter->HasTryCatch()) {
263 depth++;
264 }
265
266 iter = iter->Prev();
267 }
268
269 return depth;
270 }
271
CreateCatchTable(const util::StringView exceptionType)272 CatchTable *CodeGen::CreateCatchTable(const util::StringView exceptionType)
273 {
274 auto *catchTable = allocator_->New<CatchTable>(this, TryDepth(), exceptionType);
275 catchList_.push_back(catchTable);
276 return catchTable;
277 }
278
CreateCatchTable(const LabelPair tryLabelPair,const util::StringView exceptionType)279 CatchTable *CodeGen::CreateCatchTable(const LabelPair tryLabelPair, const util::StringView exceptionType)
280 {
281 auto *catchTable = allocator_->New<CatchTable>(this, TryDepth(), tryLabelPair, exceptionType);
282 catchList_.push_back(catchTable);
283 return catchTable;
284 }
285
SortCatchTables()286 void CodeGen::SortCatchTables()
287 {
288 std::stable_sort(catchList_.begin(), catchList_.end(),
289 [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); });
290 }
291
SetFirstStmt(const ir::Statement * stmt)292 void CodeGen::SetFirstStmt(const ir::Statement *stmt) noexcept
293 {
294 debugInfo_.firstStmt_ = stmt;
295 }
296
Unimplemented()297 void CodeGen::Unimplemented()
298 {
299 // Unimplemented code path
300 ES2PANDA_UNREACHABLE();
301 }
302
Sa()303 SimpleAllocator &CodeGen::Sa() noexcept
304 {
305 return sa_;
306 }
307
Sa() const308 const SimpleAllocator &CodeGen::Sa() const noexcept
309 {
310 return sa_;
311 }
312
Ra()313 RegAllocator &CodeGen::Ra() noexcept
314 {
315 return ra_;
316 }
317
Ra() const318 const RegAllocator &CodeGen::Ra() const noexcept
319 {
320 return ra_;
321 }
322
Rra()323 RangeRegAllocator &CodeGen::Rra() noexcept
324 {
325 return rra_;
326 }
327
Rra() const328 const RangeRegAllocator &CodeGen::Rra() const noexcept
329 {
330 return rra_;
331 }
332
Context() const333 public_lib::Context *CodeGen::Context() const noexcept
334 {
335 return context_;
336 }
337
ProgElement() const338 ProgramElement *CodeGen::ProgElement() const noexcept
339 {
340 return programElement_;
341 }
342
GetTypeMap()343 CodeGen::TypeMap &CodeGen::GetTypeMap() noexcept
344 {
345 return typeMap_;
346 }
347
GetTypeMap() const348 const CodeGen::TypeMap &CodeGen::GetTypeMap() const noexcept
349 {
350 return typeMap_;
351 }
352
GetAstCompiler() const353 compiler::AstCompiler *CodeGen::GetAstCompiler() const
354 {
355 return astCompiler_;
356 }
357 } // namespace ark::es2panda::compiler
358