123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- #pragma once
- #include "il2cpp-config.h"
- #include "il2cpp-object-internals.h"
- #include <cmath>
- #include <limits>
- #include <type_traits>
- #ifdef _MSC_VER
- #define IL2CPP_DISABLE_OPTIMIZATIONS __pragma(optimize("", off))
- #define IL2CPP_ENABLE_OPTIMIZATIONS __pragma(optimize("", on))
- #elif IL2CPP_TARGET_LINUX || IL2CPP_TARGET_QNX
- #define IL2CPP_DISABLE_OPTIMIZATIONS
- #define IL2CPP_ENABLE_OPTIMIZATIONS
- #else
- #define IL2CPP_DISABLE_OPTIMIZATIONS __attribute__ ((optnone))
- #define IL2CPP_ENABLE_OPTIMIZATIONS
- #endif
- #if defined(__GNUC__) || defined(__SNC__) || defined(__clang__)
- #define IL2CPP_FORCE_INLINE_FOR_MINIGAME inline __attribute__ ((always_inline))
- #elif defined(_MSC_VER)
- #define IL2CPP_FORCE_INLINE_FOR_MINIGAME __forceinline
- #else
- #define IL2CPP_FORCE_INLINE_FOR_MINIGAME inline
- #endif
- template<typename T>
- using no_infer = typename std::common_type<T>::type;
- #if IL2CPP_ENABLE_WRITE_BARRIERS
- void Il2CppCodeGenWriteBarrier(void** targetAddress, void* object);
- void Il2CppCodeGenWriteBarrierForType(const Il2CppType* type, void** targetAddress, void* object);
- void Il2CppCodeGenWriteBarrierForClass(Il2CppClass* klass, void** targetAddress, void* object);
- #else
- inline void Il2CppCodeGenWriteBarrier(void** targetAddress, void* object) {}
- inline void Il2CppCodeGenWriteBarrierForType(const Il2CppType* type, void** targetAddress, void* object) {}
- inline void Il2CppCodeGenWriteBarrierForClass(Il2CppClass* klass, void** targetAddress, void* object) {}
- #endif
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(void* dest, const void* src, size_t count)
- {
- return memcpy(dest, src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(intptr_t dest, const void* src, size_t count)
- {
- return memcpy((void*)dest, src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(uintptr_t dest, const void* src, size_t count)
- {
- return memcpy((void*)dest, src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(void* dest, intptr_t src, size_t count)
- {
- return memcpy(dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(intptr_t dest, intptr_t src, size_t count)
- {
- return memcpy((void*)dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(uintptr_t dest, intptr_t src, size_t count)
- {
- return memcpy((void*)dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(void* dest, uintptr_t src, size_t count)
- {
- return memcpy(dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(intptr_t dest, uintptr_t src, size_t count)
- {
- return memcpy((void*)dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void* il2cpp_codegen_memcpy(uintptr_t dest, uintptr_t src, size_t count)
- {
- return memcpy((void*)dest, (void*)src, count);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_memset(void* ptr, int value, size_t num)
- {
- memset(ptr, value, num);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_memset(intptr_t ptr, int value, size_t num)
- {
- memset((void*)ptr, value, num);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_memset(uintptr_t ptr, int value, size_t num)
- {
- memset((void*)ptr, value, num);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_initobj(void* value, size_t size)
- {
- memset(value, 0, size);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_initobj(intptr_t value, size_t size)
- {
- memset((void*)value, 0, size);
- }
- IL2CPP_FORCE_INLINE_FOR_MINIGAME void il2cpp_codegen_initobj(uintptr_t value, size_t size)
- {
- memset((void*)value, 0, size);
- }
- template<typename TInput, typename TOutput, typename TFloat>
- inline TOutput il2cpp_codegen_cast_floating_point(TFloat value)
- {
- // In release builds and on ARM, a cast from a floating point to
- // integer value will use the min or max value if the cast is out
- // of range (instead of overflowing like x86/x64 debug builds).
- // So first do a cast to the output type (which is signed in
- // .NET - the value stack does not have unsigned types) to try to
- // get the value into a range that will actually be cast the way .NET does.
- if (value < 0)
- return (TOutput)((TInput)(TOutput)value);
- return (TOutput)((TInput)value);
- }
- // ARM targets handle a cast of floating point positive infinity (0x7F800000)
- // differently from Intel targets. The expected behavior for .NET is from Intel,
- // where the cast to a 32-bit int produces the value 0x80000000. On ARM, the sign
- // is unchanged, producing 0x7FFFFFFF. To work around this change the positive
- // infinity value to negative infinity.
- template<typename T>
- inline T il2cpp_codegen_cast_double_to_int(double value)
- {
- #if IL2CPP_TARGET_ARM64 || IL2CPP_TARGET_ARMV7
- if (value == HUGE_VAL)
- {
- if (std::is_same<T, int64_t>::value)
- return INT64_MIN;
- if (std::is_same<T, int32_t>::value)
- return INT32_MIN;
- return 0;
- }
- #endif
- return (T)value;
- }
- template<bool, class T, class U>
- struct pick_first;
- template<class T, class U>
- struct pick_first<true, T, U>
- {
- typedef T type;
- };
- template<class T, class U>
- struct pick_first<false, T, U>
- {
- typedef U type;
- };
- template<class T, class U>
- struct pick_bigger
- {
- typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type;
- };
- template<typename T, typename U>
- IL2CPP_FORCE_INLINE_FOR_MINIGAME typename pick_bigger<T, U>::type il2cpp_codegen_multiply(T left, U right)
- {
- return left * right;
- }
- template<typename T, typename U>
- IL2CPP_FORCE_INLINE_FOR_MINIGAME typename pick_bigger<T, U>::type il2cpp_codegen_add(T left, U right)
- {
- return left + right;
- }
- template<typename T, typename U>
- IL2CPP_FORCE_INLINE_FOR_MINIGAME typename pick_bigger<T, U>::type il2cpp_codegen_subtract(T left, U right)
- {
- return left - right;
- }
- template<typename T>
- inline bool il2cpp_codegen_enum_has_flag(T enumValue, T flag)
- {
- return (enumValue & flag) == flag;
- }
- NORETURN void il2cpp_codegen_raise_exception(Exception_t* ex, RuntimeMethod* lastManagedFrame = NULL);
- // NativeArray macros
- #define IL2CPP_NATIVEARRAY_GET_ITEM(TElementType, TTField, TIndex) \
- *(reinterpret_cast<TElementType*>(TTField) + TIndex)
- #define IL2CPP_NATIVEARRAY_SET_ITEM(TElementType, TTField, TIndex, TValue) \
- *(reinterpret_cast<TElementType*>(TTField) + TIndex) = TValue;
- #define IL2CPP_NATIVEARRAY_GET_LENGTH(TLengthField) \
- (TLengthField)
- inline bool il2cpp_codegen_is_little_endian()
- {
- #if IL2CPP_BYTE_ORDER == IL2CPP_LITTLE_ENDIAN
- return true;
- #else
- return false;
- #endif
- }
- // This code ids used for Tiny and for libil2cpp with Tiny when the debugger is enabled.
- #if IL2CPP_TINY
- #include "utils/StringUtils.h"
- String_t* il2cpp_codegen_string_new_utf16(const il2cpp::utils::StringView<Il2CppChar>& str);
- inline String_t* il2cpp_codegen_string_new_from_char_array(Il2CppArray* characterArray, size_t startIndex, size_t length)
- {
- il2cpp_array_size_t arraySize = characterArray->max_length;
- if (startIndex + length > arraySize || startIndex < 0)
- il2cpp_codegen_raise_exception(NULL);
- return il2cpp_codegen_string_new_utf16(il2cpp::utils::StringView<Il2CppChar>(reinterpret_cast<Il2CppChar*>(characterArray + 1), startIndex, length));
- }
- inline int il2cpp_codegen_get_offset_to_string_data()
- {
- return offsetof(Il2CppString, chars);
- }
- inline int32_t il2cpp_codegen_get_array_length(Il2CppArray* szArray)
- {
- return static_cast<int32_t>(szArray->max_length);
- }
- int il2cpp_codegen_double_to_string(double value, uint8_t* format, uint8_t* buffer, int bufferLength);
- struct Delegate_t;
- inline intptr_t il2cpp_codegen_marshal_get_function_pointer_for_delegate(const Delegate_t* d)
- {
- return reinterpret_cast<intptr_t>(reinterpret_cast<const Il2CppDelegate*>(d)->m_ReversePInvokeWrapperPtr);
- }
- inline void* il2cpp_codegen_get_reverse_pinvoke_function_ptr(void* d)
- {
- return d;
- }
- #endif // IL2CPP_TINY
- NORETURN void il2cpp_codegen_raise_overflow_exception(const RuntimeMethod* method);
- template<typename T>
- constexpr bool il2cpp_codegen_is_floating_point_type()
- {
- return std::is_same<T, float>::value || std::is_same<T, double>::value;
- }
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned, bool destIsFloatingPoint, bool sourceIsFloatingPoint>
- class ConvImpl
- {
- static TDest Conv(TSource srcValue, const RuntimeMethod* method);
- };
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned>
- struct ConvImpl<TDest, TSource, TILStackType, checkOverflow, treatInputAsUnsigned, false, false>
- {
- // Integer type to integer type
- static TDest Conv(TSource srcValue, const RuntimeMethod* method)
- {
- IL2CPP_ASSERT(!il2cpp_codegen_is_floating_point_type<TDest>() && !il2cpp_codegen_is_floating_point_type<TSource>());
- TILStackType ilStackValue = (TILStackType)srcValue;
- if (checkOverflow)
- {
- typedef typename pick_bigger<TDest, TILStackType>::type CompType;
- if (!treatInputAsUnsigned && !std::is_unsigned<TDest>::value)
- {
- if ((CompType)ilStackValue > (CompType)std::numeric_limits<TDest>::max())
- il2cpp_codegen_raise_overflow_exception(method);
- if ((CompType)ilStackValue < (CompType)std::numeric_limits<TDest>::min())
- il2cpp_codegen_raise_overflow_exception(method);
- }
- if (treatInputAsUnsigned || std::is_unsigned<TDest>::value)
- {
- if ((typename std::make_unsigned<TILStackType>::type)ilStackValue > (typename std::make_unsigned<TDest>::type) std::numeric_limits<TDest>::max())
- il2cpp_codegen_raise_overflow_exception(method);
- if (!treatInputAsUnsigned && ilStackValue < 0)
- il2cpp_codegen_raise_overflow_exception(method);
- }
- }
- if (std::is_unsigned<TDest>::value)
- return (TDest)(typename std::make_unsigned<TILStackType>::type)ilStackValue;
- #if __cplusplus < 202022L
- // Prior to C++ 20 conversion of integer types to smaller types is undefined behavior
- // In most implementations it works as expected, except the optimizer is allowed to optimize it out
- if (sizeof(TDest) >= sizeof(TILStackType))
- return (TDest)ilStackValue;
- constexpr TILStackType mask = (TILStackType)std::numeric_limits<typename std::make_unsigned<TDest>::type>::max();
- return (TDest)(ilStackValue & mask);
- #else
- return (TDest)ilStackValue;
- #endif
- }
- };
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned>
- struct ConvImpl<TDest, TSource, TILStackType, checkOverflow, treatInputAsUnsigned, false, true>
- {
- // Floating point type to integer type
- static TDest Conv(TSource srcValue, const RuntimeMethod* method)
- {
- IL2CPP_ASSERT(!il2cpp_codegen_is_floating_point_type<TDest>() && il2cpp_codegen_is_floating_point_type<TSource>());
- TILStackType ilStackValue = (TILStackType)srcValue;
- if (checkOverflow)
- {
- if (ilStackValue > (TILStackType)std::numeric_limits<TDest>::max())
- il2cpp_codegen_raise_overflow_exception(method);
- if (std::is_signed<TDest>::value && ilStackValue < (TILStackType)std::numeric_limits<TDest>::min())
- il2cpp_codegen_raise_overflow_exception(method);
- if (std::is_unsigned<TDest>::value && ilStackValue < 0)
- il2cpp_codegen_raise_overflow_exception(method);
- }
- if (std::is_same<TDest, typename std::make_unsigned<TDest>::type>::value)
- return il2cpp_codegen_cast_floating_point<typename std::make_signed<TDest>::type, TDest, TSource>(ilStackValue);
- return il2cpp_codegen_cast_double_to_int<TDest>(ilStackValue);
- }
- };
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned>
- struct ConvImpl<TDest, TSource, TILStackType, checkOverflow, treatInputAsUnsigned, true, false>
- {
- // Integer type to floating point type
- static TDest Conv(TSource srcValue, const RuntimeMethod * method)
- {
- IL2CPP_ASSERT(il2cpp_codegen_is_floating_point_type<TDest>() && !il2cpp_codegen_is_floating_point_type<TSource>());
- TILStackType ilStackValue = (TILStackType)srcValue;
- if (treatInputAsUnsigned)
- return (TDest)(typename std::make_unsigned<TILStackType>::type)ilStackValue;
- return (TDest)ilStackValue;
- }
- };
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned>
- struct ConvImpl<TDest, TSource, TILStackType, checkOverflow, treatInputAsUnsigned, true, true>
- {
- // Floating point to floating point type
- static TDest Conv(TSource srcValue, const RuntimeMethod* method)
- {
- IL2CPP_ASSERT(il2cpp_codegen_is_floating_point_type<TDest>() && il2cpp_codegen_is_floating_point_type<TSource>());
- return (TDest)srcValue;
- }
- };
- template<typename TDest, typename TSource, typename TILStackType, bool checkOverflow, bool treatInputAsUnsigned>
- TDest il2cpp_codegen_conv(TSource srcValue, const RuntimeMethod* method)
- {
- return ConvImpl<TDest, TSource, TILStackType, checkOverflow, treatInputAsUnsigned, il2cpp_codegen_is_floating_point_type<TDest>(), il2cpp_codegen_is_floating_point_type<TSource>()>::Conv(srcValue, method);
- }
|