Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / third_party / rlbox / include / rlbox_conversion.hpp
blobe82d0d5da004b34c65a1dbd029952a7f60458188
1 #pragma once
2 // IWYU pragma: private, include "rlbox.hpp"
3 // IWYU pragma: friend "rlbox_.*\.hpp"
5 #include <array>
6 #include <cstring>
7 #include <limits>
8 #include <type_traits>
10 #include "rlbox_helpers.hpp"
11 #include "rlbox_type_traits.hpp"
12 #include "rlbox_types.hpp"
14 namespace rlbox::detail {
16 template<typename T_To, typename T_From>
17 inline constexpr void convert_type_fundamental(T_To& to,
18 const volatile T_From& from)
20 using namespace std;
22 if_constexpr_named(cond1, !is_fundamental_or_enum_v<T_To>)
24 rlbox_detail_static_fail_because(
25 cond1, "Conversion target should be fundamental or enum type");
27 else if_constexpr_named(cond2, !is_fundamental_or_enum_v<T_From>)
29 rlbox_detail_static_fail_because(
30 cond2, "Conversion source should be fundamental or enum type");
32 else if_constexpr_named(cond3, is_enum_v<T_To> || is_enum_v<T_From>)
34 static_assert(std::is_same_v<detail::remove_cv_ref_t<T_To>,
35 detail::remove_cv_ref_t<T_From>>);
36 to = from;
38 else if_constexpr_named(
39 cond4, is_floating_point_v<T_To> || is_floating_point_v<T_From>)
41 static_assert(is_floating_point_v<T_To> && is_floating_point_v<T_From>);
42 // language coerces different float types
43 to = from;
45 else if_constexpr_named(cond5, is_integral_v<T_To> || is_integral_v<T_From>)
47 static_assert(is_integral_v<T_To> && is_integral_v<T_From>);
49 const char* err_msg =
50 "Over/Underflow when converting between integer types";
52 // Some branches don't use the param
53 RLBOX_UNUSED(err_msg);
55 if constexpr (is_signed_v<T_To> == is_signed_v<T_From> &&
56 sizeof(T_To) >= sizeof(T_From)) {
57 // Eg: int64_t from int32_t, uint64_t from uint32_t
58 } else if constexpr (is_unsigned_v<T_To> && is_unsigned_v<T_From>) {
59 // Eg: uint32_t from uint64_t
60 dynamic_check(from <= numeric_limits<T_To>::max(), err_msg);
61 } else if constexpr (is_signed_v<T_To> && is_signed_v<T_From>) {
62 // Eg: int32_t from int64_t
63 dynamic_check(from >= numeric_limits<T_To>::min(), err_msg);
64 dynamic_check(from <= numeric_limits<T_To>::max(), err_msg);
65 } else if constexpr (is_unsigned_v<T_To> && is_signed_v<T_From>) {
66 if constexpr (sizeof(T_To) < sizeof(T_From)) {
67 // Eg: uint32_t from int64_t
68 dynamic_check(from >= 0, err_msg);
69 auto to_max = numeric_limits<T_To>::max();
70 dynamic_check(from <= static_cast<T_From>(to_max), err_msg);
71 } else {
72 // Eg: uint32_t from int32_t, uint64_t from int32_t
73 dynamic_check(from >= 0, err_msg);
75 } else if constexpr (is_signed_v<T_To> && is_unsigned_v<T_From>) {
76 if constexpr (sizeof(T_To) <= sizeof(T_From)) {
77 // Eg: int32_t from uint32_t, int32_t from uint64_t
78 auto to_max = numeric_limits<T_To>::max();
79 dynamic_check(from <= static_cast<T_From>(to_max), err_msg);
80 } else {
81 // Eg: int64_t from uint32_t
84 to = static_cast<T_To>(from);
86 else
88 constexpr auto unknownCase = !(cond1 || cond2 || cond3 || cond4 || cond5);
89 rlbox_detail_static_fail_because(
90 unknownCase, "Unexpected case for convert_type_fundamental");
94 template<typename T_To, typename T_From>
95 inline constexpr void convert_type_fundamental_or_array(T_To& to,
96 const T_From& from)
98 using namespace std;
100 using T_To_C = std_array_to_c_arr_t<T_To>;
101 using T_From_C = std_array_to_c_arr_t<T_From>;
102 using T_To_El = remove_all_extents_t<T_To_C>;
103 using T_From_El = remove_all_extents_t<T_From_C>;
105 if_constexpr_named(cond1, is_array_v<T_To_C> != is_array_v<T_From_C>)
107 rlbox_detail_static_fail_because(
108 cond1, "Conversion should not go between array and non array types");
110 else if constexpr (!is_array_v<T_To_C>)
112 convert_type_fundamental(to, from);
114 else if_constexpr_named(cond2, !all_extents_same<T_To_C, T_From_C>)
116 rlbox_detail_static_fail_because(
117 cond2, "Conversion between arrays should have same dimensions");
119 else if_constexpr_named(cond3,
120 is_pointer_v<T_To_El> || is_pointer_v<T_From_El>)
122 rlbox_detail_static_fail_because(cond3,
123 "convert_type_fundamental_or_array "
124 "does not allow arrays of pointers");
126 else
128 // Explicitly using size to check for element type as we may be going across
129 // different types of the same width such as void* and uintptr_t
130 if constexpr (sizeof(T_To_El) == sizeof(T_From_El) &&
131 is_signed_v<T_To_El> == is_signed_v<T_From_El>) {
132 // Sanity check - this should definitely be true
133 static_assert(sizeof(T_From_C) == sizeof(T_To_C));
134 std::memcpy(&to, &from, sizeof(T_To_C));
135 } else {
136 for (size_t i = 0; i < std::extent_v<T_To_C>; i++) {
137 convert_type_fundamental_or_array(to[i], from[i]);
143 enum class adjust_type_direction
145 TO_SANDBOX,
146 TO_APPLICATION,
147 NO_CHANGE
150 enum class adjust_type_context
152 EXAMPLE,
153 SANDBOX
156 template<typename T_Sbx,
157 adjust_type_direction Direction,
158 adjust_type_context Context,
159 typename T_To,
160 typename T_From>
161 inline constexpr void convert_type_non_class(
162 T_To& to,
163 const T_From& from,
164 const void* example_unsandboxed_ptr,
165 rlbox_sandbox<T_Sbx>* sandbox_ptr)
167 using namespace std;
169 // Some branches don't use the param
170 RLBOX_UNUSED(example_unsandboxed_ptr);
171 RLBOX_UNUSED(sandbox_ptr);
173 using T_To_C = std_array_to_c_arr_t<T_To>;
174 using T_From_C = std_array_to_c_arr_t<T_From>;
175 using T_To_El = remove_all_extents_t<T_To_C>;
176 using T_From_El = remove_all_extents_t<T_From_C>;
178 if constexpr (is_pointer_v<T_To_C> || is_pointer_v<T_From_C>) {
180 if constexpr (Direction == adjust_type_direction::NO_CHANGE) {
182 static_assert(is_pointer_v<T_To_C> && is_pointer_v<T_From_C> &&
183 sizeof(T_To_C) == sizeof(T_From_C));
184 to = from;
186 } else if constexpr (Direction == adjust_type_direction::TO_SANDBOX) {
188 static_assert(is_pointer_v<T_From_C>);
189 // Maybe a function pointer, so convert
190 auto from_c = reinterpret_cast<const void*>(from);
191 if constexpr (Context == adjust_type_context::SANDBOX) {
192 RLBOX_DEBUG_ASSERT(sandbox_ptr != nullptr);
193 to = sandbox_ptr->template get_sandboxed_pointer<T_From_C>(from_c);
194 } else {
195 RLBOX_DEBUG_ASSERT(from_c == nullptr ||
196 example_unsandboxed_ptr != nullptr);
197 to =
198 rlbox_sandbox<T_Sbx>::template get_sandboxed_pointer_no_ctx<T_From_C>(
199 from_c, example_unsandboxed_ptr);
202 } else if constexpr (Direction == adjust_type_direction::TO_APPLICATION) {
204 static_assert(is_pointer_v<T_To_C>);
205 if constexpr (Context == adjust_type_context::SANDBOX) {
206 RLBOX_DEBUG_ASSERT(sandbox_ptr != nullptr);
207 to = sandbox_ptr->template get_unsandboxed_pointer<T_To_C>(from);
208 } else {
209 RLBOX_DEBUG_ASSERT(from == 0 || example_unsandboxed_ptr != nullptr);
210 to =
211 rlbox_sandbox<T_Sbx>::template get_unsandboxed_pointer_no_ctx<T_To_C>(
212 from, example_unsandboxed_ptr);
216 } else if constexpr (is_pointer_v<T_To_El> || is_pointer_v<T_From_El>) {
218 if constexpr (Direction == adjust_type_direction::NO_CHANGE) {
219 // Sanity check - this should definitely be true
220 static_assert(sizeof(T_To_El) == sizeof(T_From_El) &&
221 sizeof(T_From_C) == sizeof(T_To_C));
222 memcpy(&to, &from, sizeof(T_To_C));
223 } else {
224 for (size_t i = 0; i < std::extent_v<T_To_C>; i++) {
225 convert_type_non_class<T_Sbx, Direction, Context>(
226 to[i], from[i], example_unsandboxed_ptr, sandbox_ptr);
230 } else {
231 convert_type_fundamental_or_array(to, from);
235 // Structs implement their own convert_type by specializing this class
236 // Have to do this via a class, as functions can't be partially specialized
237 template<typename T_Sbx,
238 adjust_type_direction Direction,
239 adjust_type_context Context,
240 typename T_To,
241 typename T_From>
242 class convert_type_class;
243 // The specialization implements the following
244 // {
245 // static inline void run(T_To& to,
246 // const T_From& from,
247 // const void* example_unsandboxed_ptr);
248 // }
250 template<typename T_Sbx,
251 adjust_type_direction Direction,
252 adjust_type_context Context,
253 typename T_To,
254 typename T_From>
255 inline void convert_type(T_To& to,
256 const T_From& from,
257 const void* example_unsandboxed_ptr,
258 rlbox_sandbox<T_Sbx>* sandbox_ptr)
260 if constexpr ((std::is_class_v<T_To> ||
261 std::is_class_v<T_From>)&&!detail::is_std_array_v<T_To> &&
262 !detail::is_std_array_v<T_From>) {
263 // Sanity check
264 static_assert(std::is_class_v<T_From> && std::is_class_v<T_To>);
265 convert_type_class<T_Sbx, Direction, Context, T_To, T_From>::run(
266 to, from, example_unsandboxed_ptr, sandbox_ptr);
267 } else {
268 convert_type_non_class<T_Sbx, Direction, Context>(
269 to, from, example_unsandboxed_ptr, sandbox_ptr);