1/*
2 * Copyright (c) 2021 - 2024 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
27namespace ark::es2panda::compiler {
28
29ArenaAllocator *CodeGen::Allocator() const noexcept
30{
31    return allocator_;
32}
33
34const ArenaVector<CatchTable *> &CodeGen::CatchList() const noexcept
35{
36    return catchList_;
37}
38
39const varbinder::FunctionScope *CodeGen::TopScope() const noexcept
40{
41    return topScope_;
42}
43
44const varbinder::Scope *CodeGen::Scope() const noexcept
45{
46    return scope_;
47}
48
49const ir::AstNode *CodeGen::RootNode() const noexcept
50{
51    return rootNode_;
52}
53
54ArenaVector<IRNode *> &CodeGen::Insns() noexcept
55{
56    return insns_;
57}
58
59const ArenaVector<IRNode *> &CodeGen::Insns() const noexcept
60{
61    return insns_;
62}
63
64VReg CodeGen::NextReg() const noexcept
65{
66    return VReg {usedRegs_};
67}
68
69std::uint32_t CodeGen::TotalRegsNum() const noexcept
70{
71    return totalRegs_;
72}
73
74std::size_t CodeGen::LabelCount() const noexcept
75{
76    return labelId_;
77}
78
79const DebugInfo &CodeGen::Debuginfo() const noexcept
80{
81    return debugInfo_;
82}
83
84VReg CodeGen::AllocReg()
85{
86    const VReg vreg(usedRegs_--);
87    SetVRegType(vreg, nullptr);
88    return vreg;
89}
90
91VReg CodeGen::AllocRegWithType(const checker::Type *const type)
92{
93    const VReg vreg(usedRegs_--);
94    SetVRegType(vreg, type);
95    return vreg;
96}
97
98void CodeGen::SetVRegType(const VReg vreg, const checker::Type *const type)
99{
100    typeMap_.insert_or_assign(vreg, type);
101}
102
103const 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
109checker::Type const *CodeGen::TypeForVar(varbinder::Variable const *var) const noexcept
110{
111    return var->TsType();
112}
113
114Label *CodeGen::AllocLabel()
115{
116    std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++);
117    return sa_.AllocLabel(std::move(id));
118}
119
120bool CodeGen::IsDebug() const noexcept
121{
122    return context_->config->options->CompilerOptions().isDebug;
123}
124
125std::uint32_t CodeGen::ParamCount() const noexcept
126{
127    if (rootNode_->IsProgram()) {
128        return 0U;
129    }
130
131    return rootNode_->AsScriptFunction()->Params().size();
132}
133
134std::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
145std::uint32_t CodeGen::InternalParamCount() const noexcept
146{
147    static constexpr std::uint32_t HIDDEN_PARAMS = 3U;
148    return ParamCount() + HIDDEN_PARAMS;
149}
150
151const util::StringView &CodeGen::InternalName() const noexcept
152{
153    return topScope_->InternalName();
154}
155
156const util::StringView &CodeGen::FunctionName() const noexcept
157{
158    return topScope_->Name();
159}
160
161varbinder::VarBinder *CodeGen::VarBinder() const noexcept
162{
163    return context_->parserProgram->VarBinder();
164}
165
166std::uint32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf)
167{
168    programElement_->BuffStorage().emplace_back(std::move(buf));
169    return literalBufferIdx_++;
170}
171
172void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str)
173{
174    sa_.Emit<LdaStr>(node, str);
175}
176
177void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label)
178{
179    sa_.AddLabel(label);
180}
181
182void CodeGen::Branch(const ir::AstNode *node, Label *label)
183{
184    sa_.Emit<Jmp>(node, label);
185}
186
187bool 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
202Label *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
229Label *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
255std::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
271CatchTable *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
278CatchTable *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
285void 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
291void CodeGen::SetFirstStmt(const ir::Statement *stmt) noexcept
292{
293    debugInfo_.firstStmt_ = stmt;
294}
295
296void CodeGen::Unimplemented()
297{
298    throw Error(ErrorType::GENERIC, "", "Unimplemented code path");
299}
300
301SimpleAllocator &CodeGen::Sa() noexcept
302{
303    return sa_;
304}
305
306const SimpleAllocator &CodeGen::Sa() const noexcept
307{
308    return sa_;
309}
310
311RegAllocator &CodeGen::Ra() noexcept
312{
313    return ra_;
314}
315
316const RegAllocator &CodeGen::Ra() const noexcept
317{
318    return ra_;
319}
320
321RangeRegAllocator &CodeGen::Rra() noexcept
322{
323    return rra_;
324}
325
326const RangeRegAllocator &CodeGen::Rra() const noexcept
327{
328    return rra_;
329}
330
331public_lib::Context *CodeGen::Context() const noexcept
332{
333    return context_;
334}
335
336ProgramElement *CodeGen::ProgElement() const noexcept
337{
338    return programElement_;
339}
340
341CodeGen::TypeMap &CodeGen::GetTypeMap() noexcept
342{
343    return typeMap_;
344}
345
346const CodeGen::TypeMap &CodeGen::GetTypeMap() const noexcept
347{
348    return typeMap_;
349}
350
351compiler::AstCompiler *CodeGen::GetAstCompiler() const
352{
353    return astCompiler_;
354}
355}  // namespace ark::es2panda::compiler
356