1/**
2 * Copyright (c) 2021-2022 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#ifndef ASSEMBLER_ASSEMBLY_FUNCTION_H
17#define ASSEMBLER_ASSEMBLY_FUNCTION_H
18
19#include <memory>
20#include <optional>
21#include <string>
22#include <string_view>
23#include <unordered_map>
24#include <vector>
25
26#include "assembly-ins.h"
27#include "assembly-label.h"
28#include "assembly-type.h"
29#include "assembly-debug.h"
30#include "assembly-file-location.h"
31#include "bytecode_emitter.h"
32#include "extensions/extensions.h"
33#include "file_items.h"
34#include "file_item_container.h"
35#include "ide_helpers.h"
36#include "meta.h"
37
38namespace panda::pandasm {
39
40struct Function {
41    struct CatchBlock {
42        std::string whole_line;
43        std::string exception_record;
44        std::string try_begin_label;
45        std::string try_end_label;
46        std::string catch_begin_label;
47        std::string catch_end_label;
48    };
49
50    struct TryCatchInfo {
51        std::unordered_map<std::string_view, size_t> try_catch_labels;
52        std::unordered_map<std::string, std::vector<const CatchBlock *>> try_catch_map;
53        std::vector<std::string> try_catch_order;
54        TryCatchInfo(std::unordered_map<std::string_view, size_t> &labels,
55                     std::unordered_map<std::string, std::vector<const CatchBlock *>> &map,
56                     std::vector<std::string> &param_try_catch_order)
57            : try_catch_labels(labels), try_catch_map(map), try_catch_order(param_try_catch_order)
58        {
59        }
60    };
61
62    struct Parameter {
63        Type type;
64        std::unique_ptr<ParamMetadata> metadata;
65
66        Parameter(Type t, panda::panda_file::SourceLang lang)
67            : type(std::move(t)), metadata(extensions::MetadataExtension::CreateParamMetadata(lang))
68        {
69        }
70    };
71
72    std::string name = "";
73    panda::panda_file::SourceLang language;
74    std::unique_ptr<FunctionMetadata> metadata;
75
76    std::unordered_map<std::string, panda::pandasm::Label> label_table;
77    std::vector<panda::pandasm::Ins> ins; /* function instruction list */
78    std::vector<panda::pandasm::debuginfo::LocalVariable> local_variable_debug;
79    std::string source_file; /* The file in which the function is defined or empty */
80    std::string source_code;
81    std::vector<CatchBlock> catch_blocks;
82    int64_t value_of_first_param = -1;
83    size_t regs_num = 0;
84    std::vector<Parameter> params;
85    bool body_presence = false;
86    Type return_type;
87    SourceLocation body_location;
88    std::optional<FileLocation> file_location;
89    panda::panda_file::FunctionKind function_kind = panda::panda_file::FunctionKind::NONE;
90    size_t slots_num = 0;
91    std::vector<int> concurrent_module_requests;
92
93    void SetSlotsNum(size_t num)
94    {
95        slots_num = num;
96    }
97
98    size_t GetSlotsNum() const
99    {
100        return slots_num;
101    }
102
103    void SetFunctionKind(panda::panda_file::FunctionKind kind)
104    {
105        function_kind = kind;
106    }
107
108    panda::panda_file::FunctionKind GetFunctionKind() const
109    {
110        return function_kind;
111    }
112
113    void SetInsDebug(const std::vector<debuginfo::Ins> &ins_debug)
114    {
115        ASSERT(ins_debug.size() == ins.size());
116        for (std::size_t i = 0; i < ins.size(); i++) {
117            ins[i].ins_debug = ins_debug[i];
118        }
119    }
120
121    void AddInstruction(const panda::pandasm::Ins &instruction)
122    {
123        ins.emplace_back(instruction);
124    }
125
126    Function(std::string s, panda::panda_file::SourceLang lang, size_t b_l, size_t b_r, std::string f_c, bool d,
127             size_t l_n)
128        : name(std::move(s)),
129          language(lang),
130          metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang)),
131          file_location({f_c, b_l, b_r, l_n, d})
132    {
133    }
134
135    Function(std::string s, panda::panda_file::SourceLang lang)
136        : name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang))
137    {
138    }
139
140    std::size_t GetParamsNum() const
141    {
142        return params.size();
143    }
144
145    std::size_t GetTotalRegs() const
146    {
147        return regs_num;
148    }
149
150    bool IsStatic() const
151    {
152        return (metadata->GetAccessFlags() & ACC_STATIC) != 0;
153    }
154
155    bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
156              const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
157              const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
158              const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
159              const std::unordered_map<std::string, panda_file::StringItem *> &strings,
160              const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const;
161
162    size_t GetLineNumber(size_t i) const;
163
164    uint32_t GetColumnNumber(size_t i) const;
165
166    struct LocalVariablePair {
167        size_t insn_order;
168        size_t variable_index;
169        LocalVariablePair(size_t order, size_t index) : insn_order(order), variable_index(index) {}
170    };
171    void CollectLocalVariable(std::vector<LocalVariablePair> &local_variable_info) const;
172    void EmitLocalVariable(panda_file::LineNumberProgramItem *program, panda_file::ItemContainer *container,
173                           std::vector<uint8_t> *constant_pool, uint32_t &pc_inc, size_t instruction_number,
174                           size_t variable_index) const;
175    void EmitNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool, uint32_t pc_inc,
176                    int32_t line_inc) const;
177    void EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
178                        int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const;
179
180    // column number is only for dynamic language now
181    void EmitColumnNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
182                          uint32_t &prev_column_number, uint32_t &pc_inc, size_t instruction_number) const;
183
184    void BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector<uint8_t> &bytecode,
185                                panda_file::ItemContainer *container, std::vector<uint8_t> *constant_pool,
186                                bool emit_debug_info) const;
187
188    Function::TryCatchInfo MakeOrderAndOffsets(const std::vector<uint8_t> &bytecode) const;
189
190    std::vector<panda_file::CodeItem::TryBlock> BuildTryBlocks(
191        panda_file::MethodItem *method, const std::unordered_map<std::string, panda_file::BaseClassItem *> &class_items,
192        const std::vector<uint8_t> &bytecode) const;
193
194    bool HasImplementation() const
195    {
196        return !metadata->IsForeign();
197    }
198
199    bool IsParameter(uint32_t reg_number) const
200    {
201        return reg_number >= regs_num;
202    }
203
204    bool CanThrow() const
205    {
206        return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.CanThrow(); });
207    }
208
209    bool HasDebugInfo() const
210    {
211        return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.HasDebugInfo(); });
212    }
213
214    void DebugDump() const;
215
216    std::set<std::string> CollectStringsFromFunctionInsns() const;
217};
218
219}  // namespace panda::pandasm
220
221#endif  // ASSEMBLER_ASSEMBLY_FUNCTION_H
222