#include "il2cpp-config.h" #include "il2cpp-object-internals.h" #include "il2cpp-class-internals.h" #include "icalls/mscorlib/System/Enum.h" #include "vm/Class.h" #include "vm/Object.h" #include "vm/Exception.h" #include "vm/Reflection.h" #include "vm/Enum.h" namespace il2cpp { namespace icalls { namespace mscorlib { namespace System { Il2CppObject * Enum::get_value(Il2CppObject *thisPtr) { if (!thisPtr) return NULL; IL2CPP_ASSERT(thisPtr->klass->enumtype); Il2CppClass* enumClass = vm::Class::FromIl2CppType(vm::Class::GetEnumBaseType(thisPtr->klass)); Il2CppObject* res = vm::Object::New(enumClass); void* dst = (char*)res + sizeof(Il2CppObject); void* src = (char*)thisPtr + sizeof(Il2CppObject); int32_t size = vm::Class::GetValueSize(enumClass, NULL); memcpy(dst, src, size); return res; } int Enum::compare_value_to(Il2CppObject * thisPtr, Il2CppObject * other) { void* tdata = (char*)thisPtr + sizeof(Il2CppObject); void* odata = (char*)other + sizeof(Il2CppObject); const Il2CppType *basetype = vm::Class::GetEnumBaseType(vm::Object::GetClass(thisPtr)); IL2CPP_ASSERT(basetype); #define COMPARE_ENUM_VALUES(ENUM_TYPE) do { \ ENUM_TYPE me = *((ENUM_TYPE*)tdata); \ ENUM_TYPE other = *((ENUM_TYPE*)odata); \ if (me == other) \ return 0; \ return me > other ? 1 : -1; \ } while (0) #define COMPARE_ENUM_VALUES_RANGE(ENUM_TYPE) do { \ ENUM_TYPE me = *((ENUM_TYPE*)tdata); \ ENUM_TYPE other = *((ENUM_TYPE*)odata); \ if (me == other) \ return 0; \ return me - other; \ } while (0) switch (basetype->type) { case IL2CPP_TYPE_U1: COMPARE_ENUM_VALUES(uint8_t); case IL2CPP_TYPE_I1: COMPARE_ENUM_VALUES(int8_t); case IL2CPP_TYPE_CHAR: COMPARE_ENUM_VALUES_RANGE(Il2CppChar); case IL2CPP_TYPE_U2: COMPARE_ENUM_VALUES_RANGE(uint16_t); case IL2CPP_TYPE_I2: COMPARE_ENUM_VALUES(int16_t); case IL2CPP_TYPE_U4: COMPARE_ENUM_VALUES(uint32_t); case IL2CPP_TYPE_I4: COMPARE_ENUM_VALUES(int32_t); case IL2CPP_TYPE_U8: COMPARE_ENUM_VALUES(uint64_t); case IL2CPP_TYPE_I8: COMPARE_ENUM_VALUES(int64_t); default: IL2CPP_ASSERT(false && "Implement type 0x%02x in compare_value_to"); } #undef COMPARE_ENUM_VALUES_RANGE #undef COMPARE_ENUM_VALUES return 0; } int32_t Enum::get_hashcode(Il2CppObject * thisPtr) { void* data = (char*)thisPtr + sizeof(Il2CppObject); Il2CppClass *basetype = thisPtr->klass->element_class; IL2CPP_ASSERT(basetype); if (basetype == il2cpp_defaults.sbyte_class) return *((int8_t*)data); if (basetype == il2cpp_defaults.byte_class) return *((uint8_t*)data); if (basetype == il2cpp_defaults.char_class) return *((Il2CppChar*)data); if (basetype == il2cpp_defaults.uint16_class) return *((uint16_t*)data); if (basetype == il2cpp_defaults.int16_class) return *((uint16_t*)data); if (basetype == il2cpp_defaults.uint32_class) return *((uint32_t*)data); if (basetype == il2cpp_defaults.int32_class) return *((int32_t*)data); if (basetype == il2cpp_defaults.uint64_class || basetype == il2cpp_defaults.int64_class) { int64_t value = *((int64_t*)data); return (int32_t)(value & 0xffffffff) ^ (int32_t)(value >> 32); } IL2CPP_ASSERT(0 && "System_Enum_get_hashcode_icall"); return 0; } static uint64_t read_enum_value(char *mem, Il2CppClass* type) { if (type == il2cpp_defaults.byte_class) return *(int8_t*)mem; if (type == il2cpp_defaults.sbyte_class) return *(uint8_t*)mem; if (type == il2cpp_defaults.uint16_class) return *(uint16_t*)mem; if (type == il2cpp_defaults.int16_class) return *(int16_t*)mem; if (type == il2cpp_defaults.uint32_class) return *(uint32_t*)mem; if (type == il2cpp_defaults.int32_class) return *(int32_t*)mem; if (type == il2cpp_defaults.uint64_class) return *(uint64_t*)mem; if (type == il2cpp_defaults.int64_class) return *(int64_t*)mem; IL2CPP_ASSERT(0); return 0; } static void write_enum_value(char *mem, Il2CppClass* type, uint64_t value) { if (type == il2cpp_defaults.byte_class || type == il2cpp_defaults.sbyte_class) { uint8_t *p = (uint8_t*)mem; *p = (uint8_t)value; } else if (type == il2cpp_defaults.uint16_class || type == il2cpp_defaults.int16_class) { uint16_t *p = (uint16_t*)mem; *p = (uint16_t)value; } else if (type == il2cpp_defaults.uint32_class || type == il2cpp_defaults.int32_class) { uint32_t *p = (uint32_t*)mem; *p = (uint32_t)value; } else if (type == il2cpp_defaults.uint64_class || type == il2cpp_defaults.int64_class) { uint64_t *p = (uint64_t*)mem; *p = value; } else { IL2CPP_ASSERT(0); } } Il2CppObject * Enum::ToObject(Il2CppReflectionType * enumType, Il2CppObject * value) { //MonoDomain *domain; Il2CppClass *enumc, *objc; Il2CppObject *res; Il2CppClass *etype; uint64_t val; IL2CPP_CHECK_ARG_NULL(enumType); IL2CPP_CHECK_ARG_NULL(value); //domain = mono_object_domain (enumType); enumc = vm::Class::FromIl2CppType(enumType->type); objc = vm::Object::GetClass(value); //if (!enumc->enumtype) // mono_raise_exception (mono_get_exception_argument ("enumType", "Type provided must be an Enum.")); //if (!((objc->enumtype) || (objc->byval_arg.type >= MONO_TYPE_I1 && objc->byval_arg.type <= MONO_TYPE_U8))) // mono_raise_exception (mono_get_exception_argument ("value", "The value passed in must be an enum base or an underlying type for an enum, such as an Int32.")); etype = vm::Class::GetElementClass(enumc); if (!etype) /* MS throws this for typebuilders */ il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetArgumentException("Type must be a type provided by the runtime.", "enumType")); res = (Il2CppObject*)il2cpp::vm::Object::New(enumc); //val = read_enum_value ((char *)value + sizeof (mscorlib_System_Object), objc->enumtype? mono_class_enum_basetype (objc)->type: objc->byval_arg.type); val = read_enum_value((char*)value + sizeof(Il2CppObject), objc->enumtype ? objc->element_class : objc); write_enum_value((char*)res + sizeof(Il2CppObject), etype, val); return res; } Il2CppReflectionType * Enum::get_underlying_type(Il2CppReflectionType *type) { const Il2CppType *etype; etype = vm::Class::GetEnumBaseType(vm::Class::FromIl2CppType(type->type)); if (!etype) /* MS throws this for typebuilders */ il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetArgumentException("Type must be a type provided by the runtime.", "enumType")); return il2cpp::vm::Reflection::GetTypeObject(etype); } bool Enum::GetEnumValuesAndNames(Il2CppReflectionRuntimeType* enumType, Il2CppArray** values, Il2CppArray** names) { return vm::Enum::GetEnumValuesAndNames(vm::Class::FromIl2CppType(enumType->type.type), values, names); } bool Enum::InternalHasFlag(Il2CppObject* thisPtr, Il2CppObject* flags) { Il2CppClass* enumClass = vm::Class::FromIl2CppType(vm::Class::GetEnumBaseType(thisPtr->klass)); int32_t size = vm::Class::GetValueSize(enumClass, NULL); uint64_t a_val = 0, b_val = 0; memcpy(&a_val, vm::Object::Unbox(thisPtr), size); memcpy(&b_val, vm::Object::Unbox(flags), size); return (a_val & b_val) == b_val; } int32_t Enum::InternalCompareTo(Il2CppObject* o1, Il2CppObject* o2) { return compare_value_to(o1, o2); } Il2CppObject* Enum::InternalBoxEnum(Il2CppReflectionRuntimeType* enumType, int64_t value) { return vm::Object::Box(vm::Class::FromIl2CppType(enumType->type.type), &value); } Il2CppReflectionRuntimeType* Enum::InternalGetUnderlyingType(Il2CppReflectionRuntimeType* enumType) { return reinterpret_cast(get_underlying_type(&enumType->type)); } #if IL2CPP_TINY bool Enum::TinyEnumEquals(Il2CppObject* left, Il2CppObject* right) { if (left->klass != right->klass) return false; return compare_value_to(left, right) == 0; } #endif } /* namespace System */ } /* namespace mscorlib */ } /* namespace icalls */ } /* namespace il2cpp */