1 /*
2  * Copyright (C) 2023 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 #ifndef BERBERIS_RUNTIME_PRIMITIVES_HOST_CODE_H_
17 #define BERBERIS_RUNTIME_PRIMITIVES_HOST_CODE_H_
18 
19 #include <cstdint>
20 
21 #include "berberis/base/bit_util.h"
22 #include "berberis/base/checks.h"
23 
24 namespace berberis {
25 
26 // Pointer to host executable machine code.
27 using HostCode = const void*;
28 
29 // Type used in translation cache and for host_entries
30 #if defined(__x86_64__)
31 using HostCodeAddr = uint32_t;
32 
AsHostCodeAddr(HostCode host_code)33 inline HostCodeAddr AsHostCodeAddr(HostCode host_code) {
34   CHECK(IsInRange<HostCodeAddr>(bit_cast<uintptr_t>(host_code)));
35   return static_cast<HostCodeAddr>(bit_cast<uintptr_t>(host_code));
36 }
37 
AsHostCode(HostCodeAddr host_code_addr)38 inline HostCode AsHostCode(HostCodeAddr host_code_addr) {
39   return bit_cast<HostCode>(uintptr_t{host_code_addr});
40 }
41 #else
42 // TODO(b/363611588): use uint32_t for other 64bit backends (arm64/riscv64)
43 using HostCodeAddr = uintptr_t;
44 
AsHostCodeAddr(HostCode host_code)45 inline HostCodeAddr AsHostCodeAddr(HostCode host_code) {
46   return bit_cast<HostCodeAddr>(host_code);
47 }
48 
AsHostCode(HostCodeAddr host_code_addr)49 inline HostCode AsHostCode(HostCodeAddr host_code_addr) {
50   return bit_cast<HostCode>(host_code_addr);
51 }
52 #endif  // defined(__x86_64__)
53 
54 constexpr HostCodeAddr kNullHostCodeAddr = 0;
55 
56 template <typename T>
AsHostCode(T ptr)57 inline HostCode AsHostCode(T ptr) {
58   return reinterpret_cast<HostCode>(ptr);
59 }
60 
61 template <typename T>
AsFuncPtr(HostCode ptr)62 inline T AsFuncPtr(HostCode ptr) {
63   return reinterpret_cast<T>(const_cast<void*>(ptr));
64 }
65 
66 // Note: ideally we would like the class to be a local class in the AsFuncPtr function below, but
67 // C++ doesn't allow that: local classes are not supposed to have template members.
68 class AsFuncPtrAdaptor;
69 AsFuncPtrAdaptor AsFuncPtr(HostCode ptr);
70 class [[nodiscard]] AsFuncPtrAdaptor {
71   // Note: we need this helper to describe the operator on the next line. Otherwise the C++ syntax
72   // parser becomes very confused. It has to come before the operator to help the parser, though.
73   template <typename Result, typename... Args>
74   using MakeFunctionType = Result (*)(Args...);
75 
76  public:
77   template <typename Result, typename... Args>
78   operator MakeFunctionType<Result, Args...>() {
79     return reinterpret_cast<MakeFunctionType<Result, Args...>>(ptr_);
80   }
81 
82  private:
83   AsFuncPtrAdaptor() = delete;
84   AsFuncPtrAdaptor(const AsFuncPtrAdaptor&) = delete;
85   AsFuncPtrAdaptor(AsFuncPtrAdaptor&&) = delete;
86   AsFuncPtrAdaptor& operator=(const AsFuncPtrAdaptor&) = delete;
87   AsFuncPtrAdaptor& operator=(AsFuncPtrAdaptor&&) = delete;
AsFuncPtrAdaptor(HostCode ptr)88   constexpr explicit AsFuncPtrAdaptor(HostCode ptr) noexcept : ptr_(const_cast<void*>(ptr)) {}
89   friend AsFuncPtrAdaptor AsFuncPtr(HostCode);
90   void* ptr_;
91 };
92 
93 // The result of this function is assumed to be assigned to a non-auto variable type, which will
94 // involve the conversion operator of AsFuncPtrAdaptor.
AsFuncPtr(HostCode ptr)95 inline AsFuncPtrAdaptor AsFuncPtr(HostCode ptr) {
96   return AsFuncPtrAdaptor{ptr};
97 }
98 
99 struct HostCodePiece {
100   HostCodeAddr code;
101   uint32_t size;
102 };
103 
104 }  // namespace berberis
105 
106 #endif  // BERBERIS_RUNTIME_PRIMITIVES_HOST_CODE_H_
107