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