• 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 BYTECODE_EMITTER_H
17 #define 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:
73     BytecodeEmitter() = default;
74 
75     ~BytecodeEmitter() = default;
76 
77     NO_COPY_SEMANTIC(BytecodeEmitter);
78     NO_MOVE_SEMANTIC(BytecodeEmitter);
79 
CreateLabel()80     Label CreateLabel()
81     {
82         pcList_.push_front(0);
83         return Label(pcList_.begin());
84     }
85 
86     /// Bind the label with the current place in the final bytecode.
87     void Bind(const Label &label);
88 
89     /**
90      * Generate mov <reg> <reg> instruction.
91      * The method chooses appropriate instruction encoding.
92      */
93     ErrorCode Build(std::vector<uint8_t> *output);
94 
95 #include <bytecode_emitter_def_gen.h>
96 
97 private:
98     ErrorCode ReserveSpaceForOffsets();
99     ErrorCode DoReserveSpaceForOffset(const BytecodeInstruction &insn, uint32_t insnPc, BitImmSize expectedImmSize,
100                                       size_t *extraBytesPtr, uint32_t *targetPtr);
101     ErrorCode UpdateBranches();
102     void UpdateLabelTargets(uint32_t pc, size_t bias);
103     int32_t EstimateMaxDistance(uint32_t insnPc, uint32_t targetPc, uint32_t bias) const;
104     ErrorCode CheckLabels();
105 
106     static size_t GetSizeByOpcode(BytecodeInstruction::Opcode opcode);
107     static BytecodeInstruction::Opcode RevertConditionCode(BytecodeInstruction::Opcode opcode);
108     static void UpdateBranchOffs(uint8_t *insn, int32_t offs);
109     static BitImmSize GetBitImmSizeByOpcode(BytecodeInstruction::Opcode opcode);
110     static BytecodeInstruction::Opcode GetLongestJump(BytecodeInstruction::Opcode opcode);
111     BytecodeInstruction::Opcode GetSuitableJump(BytecodeInstruction::Opcode opcode, BytecodeEmitter::BitImmSize width);
112 
113 private:
114     struct LabelCmp {
operatorLabelCmp115         bool operator()(const Label &l1, const Label &l2) const
116         {
117             return *l1.pc_ < *l2.pc_;
118         }
119     };
120 
121 private:
122     uint32_t pc_ {0};
123     std::map<uint32_t, Label> branches_;
124     std::multiset<Label, LabelCmp> targets_;
125     std::list<uint32_t> pcList_;
126     std::vector<uint8_t> bytecode_;
127 };
128 }  // namespace panda
129 
130 #endif  // BYTECODE_EMITTER_H
131