• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 LIBPANDAFILE_BYTECODE_EMITTER_H
17 #define LIBPANDAFILE_BYTECODE_EMITTER_H
18 
19 #include <bytecode_instruction.h>
20 #include <cstdint>
21 #include <map>
22 #include <memory>
23 #include <set>
24 #include <string>
25 #include <vector>
26 #include <list>
27 
28 namespace panda {
29 
30 class BytecodeEmitter;
31 
32 /**
33  * Label represents a branch target.
34  * User can associate a labe with the special place by calling
35  * BytecodeEmitter.Bind(const Label& label) method.
36  * It is not allowed to share labels between different instancies
37  * of BytecodeEmitter.
38  * Lifetime of a label must match lifetime of the emitter.
39  **/
40 class Label {
41 private:
Label(std::list<uint32_t>::iterator pc)42     explicit Label(std::list<uint32_t>::iterator pc) : pc_(pc) {}
43 
GetPc()44     uint32_t GetPc() const
45     {
46         return *pc_;
47     }
48 
49 private:
50     std::list<uint32_t>::iterator pc_;
51 
52     friend class BytecodeEmitter;
53 };
54 
55 class BytecodeEmitter {
56 public:
57     enum class ErrorCode {
58         SUCCESS,
59         /* Opcode is unsupported. It means there is no functionality yet or some bug. */
60         INTERNAL_ERROR,
61         /* There are branches to the labels for which Bind haven't been called. */
62         UNBOUND_LABELS,
63     };
64 
65     enum class BitImmSize {
66         BITSIZE_4,
67         BITSIZE_8,
68         BITSIZE_16,
69         BITSIZE_32,
70     };
71 
72 public:
BytecodeEmitter()73     BytecodeEmitter() : pc_(0) {}
74 
75     ~BytecodeEmitter() = default;
76 
77     NO_COPY_SEMANTIC(BytecodeEmitter);
78     NO_MOVE_SEMANTIC(BytecodeEmitter);
79 
CreateLabel()80     Label CreateLabel()
81     {
82         pc_list_.push_front(0);
83         return Label(pc_list_.begin());
84     }
85 
86     /**
87      * Bind the label with the current place in the final bytecode.
88      */
89     void Bind(const Label &label);
90 
91     /**
92      * Generate mov <reg> <reg> instruction.
93      * The method chooses appropriate instruction encoding.
94      */
95     ErrorCode Build(std::vector<uint8_t> *output);
96 
97 #include <bytecode_emitter_def_gen.h>
98 
99 private:
100     ErrorCode ReserveSpaceForOffsets();
101     ErrorCode DoReserveSpaceForOffset(const BytecodeInstruction &insn, uint32_t insn_pc, BitImmSize expected_imm_size,
102                                       size_t *extra_bytes_ptr, uint32_t *target_ptr);
103     ErrorCode UpdateBranches();
104     void UpdateLabelTargets(uint32_t pc, size_t bias);
105     int32_t EstimateMaxDistance(uint32_t insn_pc, uint32_t target_pc, uint32_t bias) const;
106     ErrorCode CheckLabels();
107 
108     static size_t GetSizeByOpcode(BytecodeInstruction::Opcode opcode);
109     static BytecodeInstruction::Opcode RevertConditionCode(BytecodeInstruction::Opcode opcode);
110     static void UpdateBranchOffs(uint8_t *insn, int32_t offs);
111     static BitImmSize GetBitImmSizeByOpcode(BytecodeInstruction::Opcode opcode);
112     static BytecodeInstruction::Opcode GetLongestJump(BytecodeInstruction::Opcode opcode);
113     BytecodeInstruction::Opcode GetSuitableJump(BytecodeInstruction::Opcode opcode, BytecodeEmitter::BitImmSize width);
114 
115 private:
116     struct LabelCmp {
operatorLabelCmp117         bool operator()(const Label &l1, const Label &l2) const
118         {
119             return *l1.pc_ < *l2.pc_;
120         }
121     };
122 
123 private:
124     uint32_t pc_ {0};
125     std::map<uint32_t, Label> branches_;
126     std::multiset<Label, LabelCmp> targets_;
127     std::list<uint32_t> pc_list_;
128     std::vector<uint8_t> bytecode_;
129 };
130 }  // namespace panda
131 
132 #endif  // LIBPANDAFILE_BYTECODE_EMITTER_H
133