• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_LIBPANDAFILE_BYTECODE_EMITTER_H_
17 #define PANDA_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 public:
42     ~Label() = default;
43     DEFAULT_MOVE_SEMANTIC(Label);
44     DEFAULT_COPY_SEMANTIC(Label);
45 
46 private:
Label(std::list<uint32_t>::iterator pc)47     explicit Label(std::list<uint32_t>::iterator pc) : pc_(pc) {}
48 
GetPc()49     uint32_t GetPc() const
50     {
51         return *pc_;
52     }
53 
54 private:
55     std::list<uint32_t>::iterator pc_;
56 
57     friend class BytecodeEmitter;
58 };
59 
60 class BytecodeEmitter {
61 public:
62     enum class ErrorCode {
63         SUCCESS,
64         /* Opcode is unsupported. It means there is no functionality yet or some bug. */
65         INTERNAL_ERROR,
66         /* There are branches to the labels for which Bind haven't been called. */
67         UNBOUND_LABELS,
68     };
69 
70     enum class BitImmSize {
71         BITSIZE_4,
72         BITSIZE_8,
73         BITSIZE_16,
74         BITSIZE_32,
75     };
76 
77 public:
BytecodeEmitter()78     BytecodeEmitter() : pc_(0) {}
79 
80     ~BytecodeEmitter() = default;
81 
82     NO_COPY_SEMANTIC(BytecodeEmitter);
83     NO_MOVE_SEMANTIC(BytecodeEmitter);
84 
CreateLabel()85     Label CreateLabel()
86     {
87         pc_list_.push_front(0);
88         return Label(pc_list_.begin());
89     }
90 
91     /**
92      * Bind the label with the current place in the final bytecode.
93      */
94     void Bind(const Label &label);
95 
96     /**
97      * Generate mov <reg> <reg> instruction.
98      * The method chooses appropriate instruction encoding.
99      */
100     ErrorCode Build(std::vector<uint8_t> *output);
101 
102 #include <bytecode_emitter_def_gen.h>
103     void Jcmp(BytecodeInstruction::Opcode opcode_short, BytecodeInstruction::Opcode opcode_long, uint8_t reg,
104               const Label &label);
105 
106 private:
107     void Jcmpz(BytecodeInstruction::Opcode opcode, const Label &label);
108     ErrorCode ReserveSpaceForOffsets();
109     ErrorCode DoReserveSpaceForOffset(BytecodeInstruction::Opcode opcode, uint32_t insn_pc,
110                                       BitImmSize expected_imm_size, size_t *extra_bytes_ptr, uint32_t *target_ptr);
111     ErrorCode UpdateBranches();
112     void UpdateLabelTargets(uint32_t pc, size_t bias);
113     int32_t EstimateMaxDistance(uint32_t insn_pc, uint32_t target_pc, uint32_t bias) const;
114     ErrorCode CheckLabels() const;
115 
116     static size_t GetSizeByOpcode(BytecodeInstruction::Opcode opcode);
117     static BytecodeInstruction::Opcode RevertConditionCode(BytecodeInstruction::Opcode opcode);
118     static BitImmSize GetBitImmSizeByOpcode(BytecodeInstruction::Opcode opcode);
119     static BytecodeInstruction::Opcode GetLongestConditionalJump(BytecodeInstruction::Opcode opcode);
120 
121 private:
122     struct LabelCmp {
operatorLabelCmp123         bool operator()(const Label &l1, const Label &l2) const
124         {
125             return *l1.pc_ < *l2.pc_;
126         }
127     };
128 
129 private:
130     uint32_t pc_ {0};
131     std::map<uint32_t, Label> branches_;
132     std::multiset<Label, LabelCmp> targets_;
133     std::list<uint32_t> pc_list_;
134     std::vector<uint8_t> bytecode_;
135 };
136 
137 }  // namespace panda
138 
139 #endif  // PANDA_LIBPANDAFILE_BYTECODE_EMITTER_H_
140