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