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