GenericMetadata.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #include "il2cpp-config.h"
  2. #include "il2cpp-runtime-stats.h"
  3. #include "os/Mutex.h"
  4. #include "vm/Class.h"
  5. #include "vm/GenericClass.h"
  6. #include "vm/Image.h"
  7. #include "vm/Runtime.h"
  8. #include "vm/Type.h"
  9. #include "metadata/GenericMetadata.h"
  10. #include "metadata/GenericMethod.h"
  11. #include "metadata/Il2CppGenericClassHash.h"
  12. #include "metadata/Il2CppGenericClassCompare.h"
  13. #include "metadata/Il2CppGenericInstCompare.h"
  14. #include "metadata/Il2CppGenericInstHash.h"
  15. #include "metadata/Il2CppTypeCompare.h"
  16. #include "metadata/Il2CppTypeHash.h"
  17. #include "utils/Memory.h"
  18. #include "utils/Il2CppHashMap.h"
  19. #include "utils/Il2CppHashSet.h"
  20. #include "utils/StringUtils.h"
  21. #include "vm/MetadataAlloc.h"
  22. #include "vm/MetadataCache.h"
  23. #include "il2cpp-class-internals.h"
  24. #include "il2cpp-tabledefs.h"
  25. #include <vector>
  26. #include "Baselib.h"
  27. #include "Cpp/ReentrantLock.h"
  28. #include "hybridclr/metadata/MetadataUtil.h"
  29. using namespace il2cpp::vm;
  30. using il2cpp::metadata::GenericMethod;
  31. using il2cpp::os::FastAutoLock;
  32. using il2cpp::utils::StringUtils;
  33. using std::vector;
  34. using std::pair;
  35. namespace il2cpp
  36. {
  37. namespace metadata
  38. {
  39. const Il2CppType** GenericMetadata::InflateParameters(const Il2CppType** parameters, uint8_t parameterCount, const Il2CppGenericContext* context, bool inflateMethodVars)
  40. {
  41. const Il2CppType** inflatedParameters = (const Il2CppType**)MetadataCalloc(parameterCount, sizeof(Il2CppType*));
  42. for (uint8_t j = 0; j < parameterCount; j++)
  43. {
  44. inflatedParameters[j] = InflateIfNeeded(parameters[j], context, inflateMethodVars);
  45. }
  46. return inflatedParameters;
  47. }
  48. static const Il2CppType* InflateGenericParameterIfNeeded(const Il2CppType* type, const Il2CppGenericInst* inst)
  49. {
  50. IL2CPP_ASSERT(inst);
  51. Il2CppGenericParameterInfo gp = Type::GetGenericParameterInfo(type);
  52. IL2CPP_ASSERT(gp.num < inst->type_argc);
  53. const Il2CppType* genericArgument = inst->type_argv[gp.num];
  54. if (genericArgument->attrs == type->attrs && genericArgument->byref == type->byref)
  55. return genericArgument;
  56. Il2CppType* inflatedType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
  57. memcpy(inflatedType, genericArgument, sizeof(Il2CppType));
  58. inflatedType->byref = type->byref;
  59. inflatedType->attrs = type->attrs;
  60. ++il2cpp_runtime_stats.inflated_type_count;
  61. return inflatedType;
  62. }
  63. const Il2CppType* GenericMetadata::InflateIfNeeded(const Il2CppType* type, const Il2CppGenericContext* context, bool inflateMethodVars)
  64. {
  65. switch (type->type)
  66. {
  67. case IL2CPP_TYPE_VAR:
  68. return InflateGenericParameterIfNeeded(type, context->class_inst);
  69. case IL2CPP_TYPE_MVAR:
  70. {
  71. if (context->method_inst)
  72. return InflateGenericParameterIfNeeded(type, context->method_inst);
  73. return type;
  74. }
  75. case IL2CPP_TYPE_ARRAY:
  76. {
  77. const Il2CppType* inflatedElementType = InflateIfNeeded(type->data.array->etype, context, inflateMethodVars);
  78. if (!Il2CppTypeEqualityComparer::AreEqual(inflatedElementType, type->data.array->etype))
  79. {
  80. Il2CppType* inflatedType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
  81. memcpy(inflatedType, type, sizeof(Il2CppType));
  82. Il2CppArrayType* arrayType = (Il2CppArrayType*)MetadataMalloc(sizeof(Il2CppArrayType));
  83. memcpy(arrayType, type->data.array, sizeof(Il2CppArrayType));
  84. arrayType->etype = inflatedElementType;
  85. inflatedType->data.array = arrayType;
  86. ++il2cpp_runtime_stats.inflated_type_count;
  87. return inflatedType;
  88. }
  89. return type;
  90. }
  91. case IL2CPP_TYPE_PTR:
  92. case IL2CPP_TYPE_SZARRAY:
  93. {
  94. const Il2CppType* inflatedElementType = InflateIfNeeded(type->data.type, context, inflateMethodVars);
  95. if (!Il2CppTypeEqualityComparer::AreEqual(inflatedElementType, type->data.type))
  96. {
  97. Il2CppType* arrayType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
  98. memcpy(arrayType, type, sizeof(Il2CppType));
  99. arrayType->data.type = inflatedElementType;
  100. ++il2cpp_runtime_stats.inflated_type_count;
  101. return arrayType;
  102. }
  103. return type;
  104. }
  105. case IL2CPP_TYPE_GENERICINST:
  106. {
  107. const Il2CppGenericInst* inst = type->data.generic_class->context.class_inst;
  108. if (inst == NULL)
  109. return NULL; // This is a generic type that was too deeply nested to generate
  110. const Il2CppGenericInst* inflatedInst = GetInflatedGenericIntance(inst, context, inflateMethodVars);
  111. Il2CppGenericClass* genericClass = GenericMetadata::GetGenericClass(type->data.generic_class->type, inflatedInst);
  112. if (genericClass != type->data.generic_class)
  113. {
  114. Il2CppType* genericType = (Il2CppType*)MetadataMalloc(sizeof(Il2CppType));
  115. memcpy(genericType, type, sizeof(Il2CppType));
  116. genericType->data.generic_class = genericClass;
  117. ++il2cpp_runtime_stats.inflated_type_count;
  118. return genericType;
  119. }
  120. return type;
  121. }
  122. default:
  123. return type;
  124. }
  125. }
  126. static baselib::ReentrantLock s_GenericClassMutex;
  127. typedef Il2CppHashSet<Il2CppGenericClass*, Il2CppGenericClassHash, Il2CppGenericClassCompare> Il2CppGenericClassSet;
  128. static Il2CppGenericClassSet s_GenericClassSet;
  129. Il2CppGenericClass* GenericMetadata::GetGenericClass(const Il2CppClass* genericTypeDefinition, const Il2CppGenericInst* inst)
  130. {
  131. return GetGenericClass(&genericTypeDefinition->byval_arg, inst);
  132. }
  133. Il2CppGenericClass* GenericMetadata::GetGenericClass(const Il2CppType* genericTypeDefinition, const Il2CppGenericInst* inst)
  134. {
  135. // Assert that the element type is a non-inflated generic type defintion
  136. IL2CPP_ASSERT(genericTypeDefinition->type == IL2CPP_TYPE_CLASS || genericTypeDefinition->type == IL2CPP_TYPE_VALUETYPE);
  137. // temporary inst to lookup a permanent one that may already exist
  138. Il2CppGenericClass genericClass = { 0 };
  139. genericClass.type = genericTypeDefinition;
  140. genericClass.context.class_inst = inst;
  141. FastAutoLock lock(&s_GenericClassMutex);
  142. Il2CppGenericClassSet::const_iterator iter = s_GenericClassSet.find(&genericClass);
  143. if (iter != s_GenericClassSet.end())
  144. return *iter;
  145. Il2CppGenericClass* newClass = MetadataAllocGenericClass();
  146. newClass->type = genericTypeDefinition;
  147. newClass->context.class_inst = inst;
  148. s_GenericClassSet.insert(newClass);
  149. ++il2cpp_runtime_stats.generic_class_count;
  150. return newClass;
  151. }
  152. const MethodInfo* GenericMetadata::Inflate(const MethodInfo* methodDefinition, const Il2CppGenericContext* context)
  153. {
  154. return GenericMethod::GetMethod(methodDefinition, context->class_inst, context->method_inst);
  155. }
  156. static int RecursiveGenericDepthFor(const Il2CppGenericInst* inst);
  157. static int RecursiveGenericDepthFor(Il2CppGenericClass* genericClass)
  158. {
  159. int classInstDepth = RecursiveGenericDepthFor(genericClass->context.class_inst);
  160. int methodInstDepth = RecursiveGenericDepthFor(genericClass->context.method_inst);
  161. return std::max(classInstDepth, methodInstDepth);
  162. }
  163. static int RecursiveGenericDepthFor(const Il2CppGenericInst* inst)
  164. {
  165. if (inst == NULL)
  166. return 0;
  167. int maximumDepth = 0;
  168. for (size_t i = 0; i < inst->type_argc; i++)
  169. {
  170. if (inst->type_argv[i]->type == IL2CPP_TYPE_GENERICINST)
  171. {
  172. maximumDepth = std::max(maximumDepth, RecursiveGenericDepthFor(inst->type_argv[i]->data.generic_class));
  173. }
  174. }
  175. return maximumDepth + 1;
  176. }
  177. const Il2CppGenericMethod* GenericMetadata::Inflate(const Il2CppGenericMethod* genericMethod, const Il2CppGenericContext* context)
  178. {
  179. const Il2CppGenericInst* classInst = GetInflatedGenericIntance(genericMethod->context.class_inst, context, true);
  180. const Il2CppGenericInst* methodInst = GetInflatedGenericIntance(genericMethod->context.method_inst, context, true);
  181. // We have cases where we could infinitely recurse, inflating generics at runtime. This will lead to a stack overflow.
  182. // As we do for code generation, let's cut this off at an arbitrary level. If something tries to execute code at this
  183. // level, a crash will happen. We'll assume that this code won't actually be executed though.
  184. int maximumRuntimeGenericDepth = GetMaximumRuntimeGenericDepth();
  185. if (!il2cpp::vm::Runtime::IsLazyRGCTXInflationEnabled() && (RecursiveGenericDepthFor(classInst) > maximumRuntimeGenericDepth || RecursiveGenericDepthFor(methodInst) > maximumRuntimeGenericDepth))
  186. return NULL;
  187. return MetadataCache::GetGenericMethod(genericMethod->methodDefinition, classInst, methodInst);
  188. }
  189. const Il2CppGenericInst* GenericMetadata::GetInflatedGenericIntance(const Il2CppGenericInst* inst, const Il2CppGenericContext* context, bool inflateMethodVars)
  190. {
  191. if (inst == NULL)
  192. return NULL;
  193. const Il2CppType** inflatedArgs = (const Il2CppType**)alloca(inst->type_argc * sizeof(Il2CppType*));
  194. for (size_t i = 0; i < inst->type_argc; i++)
  195. inflatedArgs[i] = InflateIfNeeded(inst->type_argv[i], context, inflateMethodVars);
  196. return MetadataCache::GetGenericInst(inflatedArgs, inst->type_argc);
  197. }
  198. static void ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupported()
  199. {
  200. vm::Exception::Raise(vm::Exception::GetNotSupportedException("Cannot make a constrained call to a default interface method from a value type"));
  201. }
  202. static void ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupportedInvoker(Il2CppMethodPointer ptr, const MethodInfo* method, void* obj, void** args, void* ret)
  203. {
  204. ConstrainedCallsToGenericInterfaceMethodsOnStructsAreNotSupported();
  205. }
  206. Il2CppRGCTXData* GenericMetadata::InflateRGCTXLocked(const Il2CppImage* image, uint32_t token, const Il2CppGenericContext* context, const FastAutoLock& lock)
  207. {
  208. // This method assumes that it has the g_MetadataLock
  209. if (hybridclr::metadata::IsInterpreterImage(image))
  210. {
  211. return nullptr;
  212. }
  213. RGCTXCollection collection = MetadataCache::GetRGCTXs(image, token);
  214. if (collection.count == 0)
  215. return NULL;
  216. Il2CppRGCTXData* dataValues = (Il2CppRGCTXData*)MetadataCalloc(collection.count, sizeof(Il2CppRGCTXData));
  217. for (RGCTXIndex rgctxIndex = 0; rgctxIndex < collection.count; rgctxIndex++)
  218. {
  219. const Il2CppRGCTXDefinition* definitionData = collection.items + rgctxIndex;
  220. switch (definitionData->type)
  221. {
  222. case IL2CPP_RGCTX_DATA_TYPE:
  223. dataValues[rgctxIndex].type = GenericMetadata::InflateIfNeeded(MetadataCache::GetTypeFromRgctxDefinition(definitionData), context, true);
  224. break;
  225. case IL2CPP_RGCTX_DATA_CLASS:
  226. dataValues[rgctxIndex].klass = Class::FromIl2CppType(GenericMetadata::InflateIfNeeded(MetadataCache::GetTypeFromRgctxDefinition(definitionData), context, true));
  227. break;
  228. case IL2CPP_RGCTX_DATA_METHOD:
  229. dataValues[rgctxIndex].method = GenericMethod::GetMethod(Inflate(MetadataCache::GetGenericMethodFromRgctxDefinition(definitionData), context));
  230. break;
  231. case IL2CPP_RGCTX_DATA_CONSTRAINED:
  232. {
  233. const Il2CppType* type;
  234. const MethodInfo* method;
  235. std::tie(type, method) = MetadataCache::GetConstrainedCallFromRgctxDefinition(definitionData);
  236. const Il2CppType* inflatedType = GenericMetadata::InflateIfNeeded(type, context, true);
  237. if (method->is_inflated)
  238. method = GenericMethod::GetMethod(Inflate(method->genericMethod, context));
  239. if (inflatedType->valuetype)
  240. {
  241. Il2CppClass* inflatedClass = Class::FromIl2CppType(inflatedType);
  242. Class::InitLocked(inflatedClass, lock);
  243. Class::InitLocked(method->klass, lock);
  244. method = Class::GetVirtualMethod(inflatedClass, method);
  245. }
  246. dataValues[rgctxIndex].method = method;
  247. }
  248. break;
  249. default:
  250. IL2CPP_ASSERT(0);
  251. }
  252. }
  253. return dataValues;
  254. }
  255. // temporary while we generate generics
  256. void GenericMetadata::RegisterGenericClasses(Il2CppGenericClass* const * genericClasses, int32_t genericClassesCount)
  257. {
  258. s_GenericClassSet.resize(genericClassesCount / 2 + 1);
  259. // don't lock, this should only be called from startup and temporarily
  260. for (int32_t i = 0; i < genericClassesCount; i++)
  261. {
  262. if (genericClasses[i]->type != NULL)
  263. s_GenericClassSet.insert(genericClasses[i]);
  264. }
  265. }
  266. bool GenericMetadata::ContainsGenericParameters(const Il2CppClass* klass)
  267. {
  268. if (!klass->generic_class)
  269. return false;
  270. return ContainsGenericParameters(klass->generic_class->context.class_inst);
  271. }
  272. bool GenericMetadata::ContainsGenericParameters(const MethodInfo* method)
  273. {
  274. if (!method->is_inflated)
  275. return false;
  276. if (ContainsGenericParameters(method->genericMethod->context.method_inst))
  277. return true;
  278. if (method->genericMethod->context.class_inst == NULL)
  279. return false;
  280. return ContainsGenericParameters(method->genericMethod->context.class_inst);
  281. }
  282. bool GenericMetadata::ContainsGenericParameters(const Il2CppGenericInst* inst)
  283. {
  284. for (uint32_t i = 0; i < inst->type_argc; i++)
  285. {
  286. if (ContainsGenericParameters(inst->type_argv[i]))
  287. return true;
  288. }
  289. return false;
  290. }
  291. bool GenericMetadata::ContainsGenericParameters(const Il2CppType* type)
  292. {
  293. switch (type->type)
  294. {
  295. case IL2CPP_TYPE_VAR:
  296. case IL2CPP_TYPE_MVAR:
  297. return true;
  298. case IL2CPP_TYPE_GENERICINST:
  299. return ContainsGenericParameters(type->data.generic_class->context.class_inst);
  300. case IL2CPP_TYPE_ARRAY:
  301. return ContainsGenericParameters(type->data.array->etype);
  302. case IL2CPP_TYPE_SZARRAY:
  303. case IL2CPP_TYPE_PTR:
  304. case IL2CPP_TYPE_BYREF:
  305. return ContainsGenericParameters(type->data.type);
  306. default:
  307. return false;
  308. }
  309. return false;
  310. }
  311. void GenericMetadata::WalkAllGenericClasses(GenericClassWalkCallback callback, void* context)
  312. {
  313. FastAutoLock lock(&s_GenericClassMutex);
  314. for (Il2CppGenericClassSet::iterator it = s_GenericClassSet.begin(); it != s_GenericClassSet.end(); it++)
  315. {
  316. if ((*it).key->cached_class != NULL)
  317. callback((*it).key->cached_class, context);
  318. }
  319. }
  320. void GenericMetadata::Clear()
  321. {
  322. for (Il2CppGenericClassSet::iterator genericClass = s_GenericClassSet.begin(); genericClass != s_GenericClassSet.end(); genericClass++)
  323. (*genericClass).key->cached_class = NULL;
  324. s_GenericClassSet.clear();
  325. }
  326. static int s_MaximumRuntimeGenericDepth;
  327. static int s_GenericVirtualIterations;
  328. int GenericMetadata::GetMaximumRuntimeGenericDepth()
  329. {
  330. return s_MaximumRuntimeGenericDepth;
  331. }
  332. void GenericMetadata::SetMaximumRuntimeGenericDepth(int depth)
  333. {
  334. s_MaximumRuntimeGenericDepth = depth;
  335. }
  336. int GenericMetadata::GetGenericVirtualIterations()
  337. {
  338. return s_GenericVirtualIterations;
  339. }
  340. void GenericMetadata::SetGenericVirtualIterations(int iterations)
  341. {
  342. s_GenericVirtualIterations = iterations;
  343. }
  344. } /* namespace vm */
  345. } /* namespace il2cpp */