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 17 #ifndef BERBERIS_GUEST_ABI_GUEST_PARAMS_H_ 18 #define BERBERIS_GUEST_ABI_GUEST_PARAMS_H_ 19 20 #include "berberis/guest_abi/guest_abi.h" 21 #include "berberis/guest_abi/guest_params_arch.h" 22 23 namespace berberis { 24 25 // Structured binding rules are designed for access to the insides of a structured type. 26 // Specifically: 27 // auto [x,y] = structured_var; // Makes copy of structured_var. 28 // auto& [x,y] = structured_var; // Doesn't make copy of a structures var. 29 // Note that x and y themselves are always references -- either to the copy or the original. 30 // Access modifiers are applied to the declaration of hidden, invisible variable. 31 // 32 // This works well when structured_var has some "insides" which may be copied. 33 // 34 // But in our case all these types are "lightweight adapters" used to parse ThreadState. 35 // There are no difference which copy you use -- all of the calls to Params() or Return() would 36 // return references to original ThreadState. 37 // 38 // However, it's allowed to return regular variable, not reference, from "get<>" function. 39 // In that case variables x and y (in the example above) would become rvalue references which 40 // would point to copy of the appropriate value. 41 // 42 // This allows us to make accessors XxxValues and XxxReferences which either allow one to access 43 // copies of Values stored in the ThreadState or access contents of ThreadState directly. 44 45 // GuestParamsValues is a syntax sugar for use with structured binding declaration. 46 // Usage looks like this: 47 // auto [length, angle] = GuestParamsValues<double(int, double)>(state); 48 // if (length > 100) { 49 // length = 100; 50 // } 51 // 52 // Note: variables are copies here not because "auto [x,y,z] =" construct is used but 53 // because GuestParamsValues always returns values. See above. 54 55 template <typename FunctionType, GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 56 class GuestParamsValues : public GuestParamsAndReturn<FunctionType, kCallingConventionsVariant> { 57 public: GuestParamsValues(ThreadState * state)58 GuestParamsValues(ThreadState* state) 59 : GuestParamsAndReturn<FunctionType, kCallingConventionsVariant>(state) {} 60 61 // Adapter for structural bindings. 62 template <std::size_t index> get()63 auto get() const { 64 return *this->template Params<index>(); 65 } 66 }; 67 68 // GuestReturnReference is a syntax sugar for use with structured binding declaration. 69 // Usage looks like this: 70 // auto&& [ret] = GuestReturnReference<double(int, double)>(state); 71 // ret = 5.0; 72 // 73 // Note: variable is a reference here not because "auto&& [x,y,z] =" construct is used but 74 // because GuestReturnReference always returns references. See above. 75 76 template <typename FunctionType, 77 GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> 78 class GuestReturnReference : public GuestParamsAndReturn<FunctionType, kCallingConventionsVariant> { 79 public: GuestReturnReference(ThreadState * state)80 GuestReturnReference(ThreadState* state) 81 : GuestParamsAndReturn<FunctionType, kCallingConventionsVariant>(state) {} 82 83 // Adapter for structural bindings. Note: we return normal references here, not rvalue references 84 // since we are pointing to non-temporary object and don't want to see it moved. 85 template <std::size_t index> get()86 auto& get() const { 87 static_assert(index == 0); 88 return *this->Return(); 89 } 90 }; 91 92 } // namespace berberis 93 94 namespace std { 95 96 // Partial specializations to support structural bindings for templates 97 // GuestParamsValues/GuestReturnReference. 98 99 // tuple_size for GuestParamsValues<Function> 100 template <typename ReturnType, 101 typename... ParamType, 102 bool kNoexcept, 103 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 104 class tuple_size<berberis::GuestParamsValues<ReturnType(ParamType...) noexcept(kNoexcept), 105 kCallingConventionsVariant>> 106 : public std::integral_constant<std::size_t, sizeof...(ParamType)> {}; 107 108 // tuple_size for GuestParamsValues<PointerToFunction> 109 template <typename ReturnType, 110 typename... ParamType, 111 bool kNoexcept, 112 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 113 class tuple_size<berberis::GuestParamsValues<ReturnType (*)(ParamType...) noexcept(kNoexcept), 114 kCallingConventionsVariant>> 115 : public std::integral_constant<std::size_t, sizeof...(ParamType)> {}; 116 117 template <typename ReturnType, 118 typename... ParamType, 119 bool kNoexcept, 120 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 121 class tuple_size<berberis::GuestParamsValues<ReturnType(ParamType..., ...) noexcept(kNoexcept), 122 kCallingConventionsVariant>> 123 : public std::integral_constant<std::size_t, sizeof...(ParamType)> {}; 124 125 template <typename ReturnType, 126 typename... ParamType, 127 bool kNoexcept, 128 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 129 class tuple_size<berberis::GuestParamsValues<ReturnType (*)(ParamType..., ...) noexcept(kNoexcept), 130 kCallingConventionsVariant>> 131 : public std::integral_constant<std::size_t, sizeof...(ParamType)> {}; 132 133 template <std::size_t index, 134 typename FunctionType, 135 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 136 class tuple_element<index, berberis::GuestParamsValues<FunctionType, kCallingConventionsVariant>> { 137 public: 138 using type = std::invoke_result_t< 139 decltype(&berberis::GuestParamsValues<FunctionType, 140 kCallingConventionsVariant>::template get<index>), 141 berberis::GuestParamsValues<FunctionType, kCallingConventionsVariant>>; 142 }; 143 144 // tuple_size for GuestReturnReference<Function> 145 template <typename ReturnType, 146 typename... ParamType, 147 bool kNoexcept, 148 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 149 class tuple_size<berberis::GuestReturnReference<ReturnType(ParamType...) noexcept(kNoexcept), 150 kCallingConventionsVariant>> 151 : public std::integral_constant<std::size_t, std::is_same_v<ReturnType, void> ? 0 : 1> {}; 152 153 // tuple_size for GuestReturnReference<PointerToFunction> 154 template <typename ReturnType, 155 typename... ParamType, 156 bool kNoexcept, 157 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 158 class tuple_size<berberis::GuestReturnReference<ReturnType (*)(ParamType...) noexcept(kNoexcept), 159 kCallingConventionsVariant>> 160 : public std::integral_constant<std::size_t, std::is_same_v<ReturnType, void> ? 0 : 1> {}; 161 162 template <typename ReturnType, 163 typename... ParamType, 164 bool kNoexcept, 165 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 166 class tuple_size<berberis::GuestReturnReference<ReturnType(ParamType..., ...) noexcept(kNoexcept), 167 kCallingConventionsVariant>> 168 : public std::integral_constant<std::size_t, std::is_same_v<ReturnType, void> ? 0 : 1> {}; 169 170 template <typename ReturnType, 171 typename... ParamType, 172 bool kNoexcept, 173 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 174 class tuple_size< 175 berberis::GuestReturnReference<ReturnType (*)(ParamType..., ...) noexcept(kNoexcept), 176 kCallingConventionsVariant>> 177 : public std::integral_constant<std::size_t, std::is_same_v<ReturnType, void> ? 0 : 1> {}; 178 179 template <typename FunctionType, 180 berberis::GuestAbi::CallingConventionsVariant kCallingConventionsVariant> 181 class tuple_element<0, berberis::GuestReturnReference<FunctionType, kCallingConventionsVariant>> { 182 public: 183 using type = std::invoke_result_t< 184 decltype(&berberis::GuestReturnReference<FunctionType, 185 kCallingConventionsVariant>::template get<0>), 186 berberis::GuestReturnReference<FunctionType, kCallingConventionsVariant>>; 187 }; 188 189 } // namespace std 190 191 #endif // BERBERIS_GUEST_ABI_GUEST_PARAMS_H_ 192