123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #include "il2cpp-config.h"
- #include "il2cpp-runtime-stats.h"
- #include "os/Mutex.h"
- #include "vm/Class.h"
- #include "vm/GenericClass.h"
- #include "vm/Image.h"
- #include "vm/Runtime.h"
- #include "vm/Type.h"
- #include "metadata/GenericMetadata.h"
- #include "metadata/GenericMethod.h"
- #include "metadata/Il2CppGenericClassHash.h"
- #include "metadata/Il2CppGenericClassCompare.h"
- #include "metadata/Il2CppGenericInstCompare.h"
- #include "metadata/Il2CppGenericInstHash.h"
- #include "metadata/Il2CppTypeCompare.h"
- #include "metadata/Il2CppTypeHash.h"
- #include "utils/Memory.h"
- #include "utils/Il2CppHashMap.h"
- #include "utils/Il2CppHashSet.h"
- #include "utils/StringUtils.h"
- #include "vm/MetadataAlloc.h"
- #include "vm/MetadataCache.h"
- #include "il2cpp-class-internals.h"
- #include "il2cpp-tabledefs.h"
- #include <vector>
- #include "Baselib.h"
- #include "Cpp/ReentrantLock.h"
- using namespace il2cpp::vm;
- using il2cpp::metadata::GenericMethod;
- using il2cpp::os::FastAutoLock;
- using il2cpp::utils::StringUtils;
- using std::vector;
- using std::pair;
- namespace il2cpp
- {
- namespace metadata
- {
- const Il2CppType** GenericMetadata::InflateParameters(const Il2CppType** parameters, uint8_t parameterCount, const Il2CppGenericContext* context, bool inflateMethodVars)
- {
- const Il2CppType** inflatedParameters = (const Il2CppType**)MetadataCalloc(parameterCount, sizeof(Il2CppType*));
- for (uint8_t j = 0; j < parameterCount; j++)
- {
- inflatedParameters[j] = InflateIfNeeded(parameters[j], context, inflateMethodVars);
- }
- return inflatedParameters;
- }
- static const Il2CppType* InflateGenericParameterIfNeeded(const Il2CppType* type, const Il2CppGenericInst* inst)
- {
- IL2CPP_ASSERT(inst);
- Il2CppGenericParameterInfo gp = Type::GetGenericParameterInfo(type);
- IL2CPP_ASSERT(gp.num < inst->type_argc);
- const Il2CppType* genericArgument = inst->type_argv[gp.num];
- if (genericArgument->attrs == type->attrs && genericArgument->byref == type->byref)
- return genericArgument;
- Il2CppType* inflatedType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
- memcpy(inflatedType, genericArgument, sizeof(Il2CppType));
- inflatedType->byref = type->byref;
- inflatedType->attrs = type->attrs;
- ++il2cpp_runtime_stats.inflated_type_count;
- return inflatedType;
- }
- const Il2CppType* GenericMetadata::InflateIfNeeded(const Il2CppType* type, const Il2CppGenericContext* context, bool inflateMethodVars)
- {
- switch (type->type)
- {
- case IL2CPP_TYPE_VAR:
- return InflateGenericParameterIfNeeded(type, context->class_inst);
- case IL2CPP_TYPE_MVAR:
- {
- if (context->method_inst)
- return InflateGenericParameterIfNeeded(type, context->method_inst);
- return type;
- }
- case IL2CPP_TYPE_ARRAY:
- {
- const Il2CppType* inflatedElementType = InflateIfNeeded(type->data.array->etype, context, inflateMethodVars);
- if (!Il2CppTypeEqualityComparer::AreEqual(inflatedElementType, type->data.array->etype))
- {
- Il2CppType* inflatedType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
- memcpy(inflatedType, type, sizeof(Il2CppType));
- Il2CppArrayType* arrayType = (Il2CppArrayType*)MetadataMalloc(sizeof(Il2CppArrayType));
- memcpy(arrayType, type->data.array, sizeof(Il2CppArrayType));
- arrayType->etype = inflatedElementType;
- inflatedType->data.array = arrayType;
- ++il2cpp_runtime_stats.inflated_type_count;
- return inflatedType;
- }
- return type;
- }
- case IL2CPP_TYPE_PTR:
- case IL2CPP_TYPE_SZARRAY:
- {
- const Il2CppType* inflatedElementType = InflateIfNeeded(type->data.type, context, inflateMethodVars);
- if (!Il2CppTypeEqualityComparer::AreEqual(inflatedElementType, type->data.type))
- {
- Il2CppType* arrayType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
- memcpy(arrayType, type, sizeof(Il2CppType));
- arrayType->data.type = inflatedElementType;
- ++il2cpp_runtime_stats.inflated_type_count;
- return arrayType;
- }
- return type;
- }
- case IL2CPP_TYPE_GENERICINST:
- {
- const Il2CppGenericInst* inst = type->data.generic_class->context.class_inst;
- if (inst == NULL)
- return NULL; // This is a generic type that was too deeply nested to generate
- const Il2CppGenericInst* inflatedInst = GetInflatedGenericIntance(inst, context, inflateMethodVars);
- Il2CppGenericClass* genericClass = GenericMetadata::GetGenericClass(GenericClass::GetTypeDefinition(type->data.generic_class), inflatedInst);
- if (genericClass != type->data.generic_class)
- {
- Il2CppType* genericType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
- memcpy(genericType, type, sizeof(Il2CppType));
- genericType->data.generic_class = genericClass;
- ++il2cpp_runtime_stats.inflated_type_count;
- return genericType;
- }
- return type;
- }
- default:
- return type;
- }
- }
- static baselib::ReentrantLock s_GenericClassMutex;
- typedef Il2CppHashSet<Il2CppGenericClass*, Il2CppGenericClassHash, Il2CppGenericClassCompare> Il2CppGenericClassSet;
- static Il2CppGenericClassSet s_GenericClassSet;
- Il2CppGenericClass* GenericMetadata::GetGenericClass(const Il2CppClass* genericTypeDefinition, const Il2CppGenericInst* inst)
- {
- return GetGenericClass(&genericTypeDefinition->byval_arg, inst);
- }
- Il2CppGenericClass* GenericMetadata::GetGenericClass(const Il2CppType* genericTypeDefinition, const Il2CppGenericInst* inst)
- {
- // Assert that the element type is a non-inflated generic type defintion
- IL2CPP_ASSERT(il2cpp::vm::Class::IsGenericTypeDefinition(vm::Class::FromIl2CppType(genericTypeDefinition)));
- // temporary inst to lookup a permanent one that may already exist
- Il2CppGenericClass genericClass = { 0 };
- genericClass.type = genericTypeDefinition;
- genericClass.context.class_inst = inst;
- FastAutoLock lock(&s_GenericClassMutex);
- Il2CppGenericClassSet::const_iterator iter = s_GenericClassSet.find(&genericClass);
- if (iter != s_GenericClassSet.end())
- return *iter;
- Il2CppGenericClass* newClass = MetadataAllocGenericClass();
- newClass->type = genericTypeDefinition;
- newClass->context.class_inst = inst;
- s_GenericClassSet.insert(newClass);
- ++il2cpp_runtime_stats.generic_class_count;
- return newClass;
- }
- const MethodInfo* GenericMetadata::Inflate(const MethodInfo* methodDefinition, const Il2CppGenericContext* context)
- {
- return GenericMethod::GetMethod(methodDefinition, context->class_inst, context->method_inst);
- }
- static int RecursiveGenericDepthFor(const Il2CppGenericInst* inst);
- static int RecursiveGenericDepthFor(Il2CppGenericClass* genericClass)
- {
- int classInstDepth = RecursiveGenericDepthFor(genericClass->context.class_inst);
- int methodInstDepth = RecursiveGenericDepthFor(genericClass->context.method_inst);
- return std::max(classInstDepth, methodInstDepth);
- }
- static int RecursiveGenericDepthFor(const Il2CppGenericInst* inst)
- {
- if (inst == NULL)
- return 0;
- int maximumDepth = 0;
- for (size_t i = 0; i < inst->type_argc; i++)
- {
- if (inst->type_argv[i]->type == IL2CPP_TYPE_GENERICINST)
- {
- maximumDepth = std::max(maximumDepth, RecursiveGenericDepthFor(inst->type_argv[i]->data.generic_class));
- }
- }
- return maximumDepth + 1;
- }
- const Il2CppGenericMethod* GenericMetadata::Inflate(const Il2CppGenericMethod* genericMethod, const Il2CppGenericContext* context)
- {
- const Il2CppGenericInst* classInst = GetInflatedGenericIntance(genericMethod->context.class_inst, context, true);
- const Il2CppGenericInst* methodInst = GetInflatedGenericIntance(genericMethod->context.method_inst, context, true);
- // We have cases where we could infinitely recurse, inflating generics at runtime. This will lead to a stack overflow.
- // As we do for code generation, let's cut this off at an arbitrary level. If something tries to execute code at this
- // level, a crash will happen. We'll assume that this code won't actually be executed though.
- int maximumRuntimeGenericDepth = GetMaximumRuntimeGenericDepth();
- if (!il2cpp::vm::Runtime::IsLazyRGCTXInflationEnabled() && (RecursiveGenericDepthFor(classInst) > maximumRuntimeGenericDepth || RecursiveGenericDepthFor(methodInst) > maximumRuntimeGenericDepth))
- return NULL;
- return MetadataCache::GetGenericMethod(genericMethod->methodDefinition, classInst, methodInst);
- }
- const Il2CppGenericInst* GenericMetadata::GetInflatedGenericIntance(const Il2CppGenericInst* inst, const Il2CppGenericContext* context, bool inflateMethodVars)
- {
- if (inst == NULL)
- return NULL;
- const Il2CppType** inflatedArgs = (const Il2CppType**)alloca(inst->type_argc * sizeof(Il2CppType*));
- for (size_t i = 0; i < inst->type_argc; i++)
- inflatedArgs[i] = InflateIfNeeded(inst->type_argv[i], context, inflateMethodVars);
- return MetadataCache::GetGenericInst(inflatedArgs, inst->type_argc);
- }
- static void ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupported()
- {
- vm::Exception::Raise(vm::Exception::GetNotSupportedException("Cannot make a constrained call to a default interface method from a value type"));
- }
- static void ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupportedInvoker(Il2CppMethodPointer ptr, const MethodInfo* method, void* obj, void** args, void* ret)
- {
- ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupported();
- }
- Il2CppRGCTXData* GenericMetadata::InflateRGCTXLocked(const Il2CppImage* image, uint32_t token, const Il2CppGenericContext* context, const FastAutoLock& lock)
- {
- // This method assumes that it has the g_MetadataLock
- RGCTXCollection collection = MetadataCache::GetRGCTXs(image, token);
- if (collection.count == 0)
- return NULL;
- Il2CppRGCTXData* dataValues = (Il2CppRGCTXData*)MetadataCalloc(collection.count, sizeof(Il2CppRGCTXData));
- for (RGCTXIndex rgctxIndex = 0; rgctxIndex < collection.count; rgctxIndex++)
- {
- const Il2CppRGCTXDefinition* definitionData = collection.items + rgctxIndex;
- switch (definitionData->type)
- {
- case IL2CPP_RGCTX_DATA_TYPE:
- dataValues[rgctxIndex].type = GenericMetadata::InflateIfNeeded(MetadataCache::GetTypeFromRgctxDefinition(definitionData), context, true);
- break;
- case IL2CPP_RGCTX_DATA_CLASS:
- dataValues[rgctxIndex].klass = Class::FromIl2CppType(GenericMetadata::InflateIfNeeded(MetadataCache::GetTypeFromRgctxDefinition(definitionData), context, true));
- Class::InitSizeAndFieldLayoutLocked(dataValues[rgctxIndex].klass, lock);
- break;
- case IL2CPP_RGCTX_DATA_METHOD:
- dataValues[rgctxIndex].method = GenericMethod::GetMethod(Inflate(MetadataCache::GetGenericMethodFromRgctxDefinition(definitionData), context));
- break;
- case IL2CPP_RGCTX_DATA_CONSTRAINED:
- {
- const Il2CppType* type;
- const MethodInfo* method;
- std::tie(type, method) = MetadataCache::GetConstrainedCallFromRgctxDefinition(definitionData);
- const Il2CppType* inflatedType = GenericMetadata::InflateIfNeeded(type, context, true);
- if (method->is_inflated)
- method = GenericMethod::GetMethod(Inflate(method->genericMethod, context));
- if (inflatedType->valuetype)
- {
- Il2CppClass* inflatedClass = Class::FromIl2CppType(inflatedType);
- Class::InitLocked(inflatedClass, lock);
- Class::InitLocked(method->klass, lock);
- method = Class::GetVirtualMethod(inflatedClass, method);
- }
- dataValues[rgctxIndex].method = method;
- }
- break;
- default:
- IL2CPP_ASSERT(0);
- }
- }
- return dataValues;
- }
- // temporary while we generate generics
- void GenericMetadata::RegisterGenericClasses(Il2CppGenericClass* const * genericClasses, int32_t genericClassesCount)
- {
- s_GenericClassSet.resize(genericClassesCount / 2 + 1);
- // don't lock, this should only be called from startup and temporarily
- for (int32_t i = 0; i < genericClassesCount; i++)
- {
- if (genericClasses[i]->type != NULL)
- s_GenericClassSet.insert(genericClasses[i]);
- }
- }
- bool GenericMetadata::ContainsGenericParameters(const Il2CppClass* klass)
- {
- if (!klass->generic_class)
- return false;
- return ContainsGenericParameters(klass->generic_class->context.class_inst);
- }
- bool GenericMetadata::ContainsGenericParameters(const MethodInfo* method)
- {
- if (!method->is_inflated)
- return false;
- if (ContainsGenericParameters(method->genericMethod->context.method_inst))
- return true;
- if (method->genericMethod->context.class_inst == NULL)
- return false;
- return ContainsGenericParameters(method->genericMethod->context.class_inst);
- }
- bool GenericMetadata::ContainsGenericParameters(const Il2CppGenericInst* inst)
- {
- for (uint32_t i = 0; i < inst->type_argc; i++)
- {
- if (ContainsGenericParameters(inst->type_argv[i]))
- return true;
- }
- return false;
- }
- bool GenericMetadata::ContainsGenericParameters(const Il2CppType* type)
- {
- switch (type->type)
- {
- case IL2CPP_TYPE_VAR:
- case IL2CPP_TYPE_MVAR:
- return true;
- case IL2CPP_TYPE_GENERICINST:
- return ContainsGenericParameters(type->data.generic_class->context.class_inst);
- case IL2CPP_TYPE_ARRAY:
- return ContainsGenericParameters(type->data.array->etype);
- case IL2CPP_TYPE_SZARRAY:
- case IL2CPP_TYPE_PTR:
- case IL2CPP_TYPE_BYREF:
- return ContainsGenericParameters(type->data.type);
- default:
- return false;
- }
- return false;
- }
- void GenericMetadata::WalkAllGenericClasses(GenericClassWalkCallback callback, void* context)
- {
- FastAutoLock lock(&s_GenericClassMutex);
- for (Il2CppGenericClassSet::iterator it = s_GenericClassSet.begin(); it != s_GenericClassSet.end(); it++)
- {
- if ((*it).key->cached_class != NULL)
- callback((*it).key->cached_class, context);
- }
- }
- void GenericMetadata::Clear()
- {
- for (Il2CppGenericClassSet::iterator genericClass = s_GenericClassSet.begin(); genericClass != s_GenericClassSet.end(); genericClass++)
- (*genericClass).key->cached_class = NULL;
- s_GenericClassSet.clear();
- }
- static int s_MaximumRuntimeGenericDepth;
- static int s_GenericVirtualIterations;
- int GenericMetadata::GetMaximumRuntimeGenericDepth()
- {
- return s_MaximumRuntimeGenericDepth;
- }
- void GenericMetadata::SetMaximumRuntimeGenericDepth(int depth)
- {
- s_MaximumRuntimeGenericDepth = depth;
- }
- int GenericMetadata::GetGenericVirtualIterations()
- {
- return s_GenericVirtualIterations;
- }
- void GenericMetadata::SetGenericVirtualIterations(int iterations)
- {
- s_GenericVirtualIterations = iterations;
- }
- } /* namespace vm */
- } /* namespace il2cpp */
|