#include "ClassInlines.h" #include "vm/Class.h" #include "vm/Exception.h" #include "vm/Method.h" #include "vm/RCW.h" #include "gc/GCHandle.h" #include "metadata/GenericMethod.h" namespace il2cpp { namespace vm { Il2CppClass* ClassInlines::InitFromCodegenSlow(Il2CppClass *klass) { IL2CPP_ASSERT(klass != il2cpp_defaults.il2cpp_fully_shared_type); Class::Init(klass); if (klass->initializationExceptionGCHandle) il2cpp::vm::Exception::Raise((Il2CppException*)gc::GCHandle::GetTarget(klass->initializationExceptionGCHandle)); return klass; } Il2CppClass* ClassInlines::InitFromCodegenSlow(Il2CppClass *klass, bool throwOnError) { IL2CPP_ASSERT(klass != il2cpp_defaults.il2cpp_fully_shared_type); if (throwOnError) return InitFromCodegenSlow(klass); Class::Init(klass); if (klass->initializationExceptionGCHandle) return NULL; return klass; } const MethodInfo* ClassInlines::InitRgctxFromCodegenSlow(const MethodInfo* method) { il2cpp::metadata::GenericMethod::InflateRGCTX(method); return method; } NORETURN static void RaiseExceptionForNotFoundInterface(const Il2CppClass* klass, const Il2CppClass* itf, Il2CppMethodSlot slot) { std::string message; message = "Attempt to access method '" + Type::GetName(&itf->byval_arg, IL2CPP_TYPE_NAME_FORMAT_IL) + "." + Method::GetName(itf->methods[slot]) + "' on type '" + Type::GetName(&klass->byval_arg, IL2CPP_TYPE_NAME_FORMAT_IL) + "' failed."; Exception::Raise(il2cpp::vm::Exception::GetMethodAccessException(message.c_str())); } const VirtualInvokeData* ClassInlines::GetInterfaceInvokeDataFromVTableSlowPath(const Il2CppClass* klass, const Il2CppClass* itf, Il2CppMethodSlot slot) { if (itf->generic_class != NULL) { for (uint16_t i = 0; i < klass->interface_offsets_count; ++i) { const Il2CppRuntimeInterfaceOffsetPair* pair = klass->interfaceOffsets + i; if (Class::IsGenericClassAssignableFromVariance(itf, pair->interfaceType, klass)) { IL2CPP_ASSERT(pair->offset + slot < klass->vtable_count); //return &klass->vtable[pair->offset + slot]; return Class::GetOrSetupOneVTableSlot(const_cast(klass), NULL, pair->offset + slot); } } } return NULL; } const VirtualInvokeData& ClassInlines::GetInterfaceInvokeDataFromVTable(Il2CppObject* obj,const Il2CppClass* itf, Il2CppMethodSlot slot) { const VirtualInvokeData* result = GetInterfaceInvokeDataFromVTable(obj->klass,itf,slot); if (result) return *result; return GetInterfaceInvokeDataFromVTableSlowPath(obj,itf,slot); } const VirtualInvokeData& ClassInlines::GetInterfaceInvokeDataFromVTableSlowPath(Il2CppObject* obj, const Il2CppClass* itf, Il2CppMethodSlot slot) { const Il2CppClass* klass = obj->klass; const VirtualInvokeData* data; data = GetInterfaceInvokeDataFromVTableSlowPath(klass, itf, slot); if (data) return *data; #if !IL2CPP_TRIM_COM if (klass->is_import_or_windows_runtime) { Il2CppComObject* rcw = static_cast(obj); // It might be null if it's called on a dead (already released) or fake object if (rcw->identity != NULL) { const VirtualInvokeData* invokeData = RCW::GetComInterfaceInvokeData(rcw, itf, slot); if (invokeData != NULL) { // Nothing will be referencing these types directly, so we need to initialize them here Class::Init(invokeData->method->klass); return *invokeData; } } } #endif RaiseExceptionForNotFoundInterface(klass, itf, slot); IL2CPP_UNREACHABLE; } const VirtualInvokeData& ClassInlines::GetVirtualInvokeData(Il2CppMethodSlot slot, const Il2CppObject* obj) { Assert(slot != kInvalidIl2CppMethodSlot && "MethodSlot is invalid!"); //quick pass Il2CppClass* klass = obj->klass; if(slot < klass->vtable_count && klass->vtable[slot].method != NULL) return klass->vtable[slot]; return *Class::GetOrSetupOneVTableSlot(obj->klass, NULL, slot); } bool ClassInlines::HasParent(const Il2CppClass* klass, const Il2CppClass* parent) { return Class::HasParent(const_cast(klass), const_cast(parent)); } const VirtualInvokeData* ClassInlines::GetInterfaceInvokeDataFromVTable(Il2CppClass* klass, const Il2CppClass* itf, Il2CppMethodSlot slot) { IL2CPP_ASSERT(slot < itf->method_count); //quick pass if (klass->interfaceOffsets != NULL) { for (uint16_t i = 0; i < klass->interface_offsets_count; i++) { if (klass->interfaceOffsets[i].interfaceType == itf) { int32_t offset = klass->interfaceOffsets[i].offset; IL2CPP_ASSERT(offset != -1); IL2CPP_ASSERT(offset + slot < klass->vtable_count); if (klass->vtable[offset + slot].method != NULL) return &(klass->vtable[offset + slot]); } } } const VirtualInvokeData* data = Class::GetOrSetupOneVTableSlot(klass, itf, slot); if (data) return data; return GetInterfaceInvokeDataFromVTableSlowPath(klass, itf, slot); } } }