• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //
18 // Generated machine code.
19 
20 #ifndef BERBERIS_ASSEMBLER_MACHINE_CODE_H_
21 #define BERBERIS_ASSEMBLER_MACHINE_CODE_H_
22 
23 #include <cstdint>
24 #include <string>
25 
26 #include "berberis/base/arena_alloc.h"
27 #include "berberis/base/arena_vector.h"
28 #include "berberis/base/exec_region_anonymous.h"
29 #include "berberis/base/forever_map.h"
30 #include "berberis/base/macros.h"  // DISALLOW_COPY_AND_ASSIGN
31 
32 namespace berberis {
33 
34 enum class RelocationType {
35   // Convert absolute address to PC-relative displacement.
36   // Ensure displacement fits in 32-bit value.
37   RelocAbsToDisp32,
38   // Add recovery point and recovery code to global recovery code map.
39   // TODO(eaeltsin): have recovery map for each region instead!
40   RelocRecoveryPoint,
41 };
42 
43 using RecoveryMap = ForeverMap<uintptr_t, uintptr_t>;
44 
45 // Generated machine code for host architecture. Used by trampolines
46 // and JIT translator.
47 // NOTE: this class is not intended for concurrent usage by multiple threads.
48 class MachineCode {
49  public:
MachineCode()50   MachineCode() : code_(&arena_), relocations_(&arena_) {
51     // The amount is chosen according to the performance of spec2000 benchmarks.
52     code_.reserve(1024);
53   }
54 
arena()55   Arena* arena() { return &arena_; }
56 
57   // TODO(eaeltsin): this will include const pool size when supported.
install_size()58   [[nodiscard]] uint32_t install_size() const { return code_.size(); }
59 
code_offset()60   [[nodiscard]] uint32_t code_offset() const { return code_.size(); }
61 
62   template <typename T>
AddrAs(uint32_t offset)63   T* AddrAs(uint32_t offset) {
64     return reinterpret_cast<T*>(AddrOf(offset));
65   }
66 
67   template <typename T>
AddrAs(uint32_t offset)68   [[nodiscard]] const T* AddrAs(uint32_t offset) const {
69     return reinterpret_cast<const T*>(AddrOf(offset));
70   }
71 
72   template <typename T>
Add(const T & v)73   void Add(const T& v) {
74     memcpy(AddrAs<T>(Grow(sizeof(T))), &v, sizeof(T));
75   }
76 
77   template <typename T>
AddSequence(const T * v,uint32_t count)78   void AddSequence(const T* v, uint32_t count) {
79     memcpy(AddrAs<T>(Grow(sizeof(T) * count)), v, sizeof(T) * count);
80   }
81 
AddU8(uint8_t v)82   void AddU8(uint8_t v) { code_.push_back(v); }
83 
84   void AsString(std::string* result) const;
85 
AddRelocation(uint32_t dst,RelocationType type,uint32_t pc,intptr_t data)86   void AddRelocation(uint32_t dst, RelocationType type, uint32_t pc, intptr_t data) {
87     relocations_.push_back(Relocation{dst, type, pc, data});
88   }
89 
90   // Install to executable memory.
91   template <typename ExecRegionType>
Install(ExecRegionType * exec,const uint8_t * code,RecoveryMap * recovery_map)92   void Install(ExecRegionType* exec, const uint8_t* code, RecoveryMap* recovery_map) {
93     PerformRelocations(code, recovery_map);
94     exec->Write(code, AddrAs<uint8_t>(0), code_.size());
95   }
96 
97   // Install to writable memory.
InstallUnsafe(uint8_t * code,RecoveryMap * recovery_map)98   void InstallUnsafe(uint8_t* code, RecoveryMap* recovery_map) {
99     PerformRelocations(code, recovery_map);
100     memcpy(code, AddrAs<uint8_t>(0), code_.size());
101   }
102 
103   // Print generated code to stderr.
104   void DumpCode() const;
105 
106  private:
107   struct Relocation {
108     uint32_t dst;
109     RelocationType type;
110     uint32_t pc;
111     intptr_t data;
112   };
113   using RelocationList = ArenaVector<Relocation>;
114 
115   [[nodiscard]] uint8_t* AddrOf(uint32_t offset);
116   [[nodiscard]] const uint8_t* AddrOf(uint32_t offset) const;
117   uint32_t Grow(uint32_t count);
118 
119   // Relocate the code, in assumption it is to be installed at address 'code'.
120   void PerformRelocations(const uint8_t* code, RecoveryMap* recovery_map);
121 
122   Arena arena_;
123   ArenaVector<uint8_t> code_;
124   RelocationList relocations_;
125 
126   DISALLOW_COPY_AND_ASSIGN(MachineCode);
127 };
128 
129 }  // namespace berberis
130 
131 #endif  // BERBERIS_ASSEMBLER_MACHINE_CODE_H_
132