ArrayMetadata.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  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/MetadataLock.h"
  8. #include "vm/Method.h"
  9. #include "vm/Type.h"
  10. #include "metadata/ArrayMetadata.h"
  11. #include "metadata/GenericMetadata.h"
  12. #include "metadata/GenericMethod.h"
  13. #include "metadata/Il2CppGenericClassHash.h"
  14. #include "metadata/Il2CppGenericClassCompare.h"
  15. #include "metadata/Il2CppGenericInstCompare.h"
  16. #include "metadata/Il2CppGenericInstHash.h"
  17. #include "metadata/Il2CppTypeCompare.h"
  18. #include "metadata/Il2CppTypeHash.h"
  19. #include "vm/MetadataAlloc.h"
  20. #include "vm/MetadataCache.h"
  21. #include "vm/Runtime.h"
  22. #include "utils/Memory.h"
  23. #include "utils/Il2CppHashMap.h"
  24. #include "utils/StringUtils.h"
  25. #include "il2cpp-class-internals.h"
  26. #include "il2cpp-tabledefs.h"
  27. #include <vector>
  28. #include <limits>
  29. using namespace il2cpp::vm;
  30. using il2cpp::os::FastAutoLock;
  31. using il2cpp::utils::StringUtils;
  32. using il2cpp::vm::MetadataCache;
  33. using il2cpp::vm::MetadataCalloc;
  34. using il2cpp::vm::MetadataMalloc;
  35. using std::vector;
  36. using std::pair;
  37. const size_t kImplicitArrayInterfaceCount = 5;
  38. namespace il2cpp
  39. {
  40. namespace metadata
  41. {
  42. static const char* GetArrayName(const char* elementClassName, uint32_t rank, bool bounded)
  43. {
  44. std::string name;
  45. name += elementClassName;
  46. name += "[";
  47. for (uint32_t i = 1; i < rank; i++)
  48. name += ",";
  49. if (bounded)
  50. name += "*";
  51. name += "]";
  52. return StringUtils::StringDuplicate(name.c_str());
  53. }
  54. static MethodInfo* ConstructArrayMethod(Il2CppClass* declaringType, const char* name, const Il2CppType* returnType, uint8_t parameterCount, const Il2CppType** parameterTypes)
  55. {
  56. MethodInfo* method = (MethodInfo*)MetadataCalloc(1, sizeof(MethodInfo), IL2CPP_MSTAT_METHOD);
  57. method->klass = declaringType;
  58. method->flags = METHOD_ATTRIBUTE_PUBLIC;
  59. method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
  60. method->name = name;
  61. method->slot = kInvalidIl2CppMethodSlot;
  62. method->return_type = returnType;
  63. method->parameters_count = parameterCount;
  64. const Il2CppType** parameters = (const Il2CppType**)MetadataCalloc(parameterCount, sizeof(Il2CppType*), IL2CPP_MSTAT_TYPE);
  65. for (uint8_t i = 0; i < parameterCount; i++)
  66. {
  67. parameters[i] = parameterTypes[i];
  68. }
  69. method->parameters = parameters;
  70. if (!strcmp(".ctor", name))
  71. {
  72. method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
  73. }
  74. else
  75. {
  76. method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
  77. }
  78. ++il2cpp_runtime_stats.method_count;
  79. return method;
  80. }
  81. struct GenericArrayMethod
  82. {
  83. const char* name;
  84. const MethodInfo* method;
  85. const MethodInfo* interfaceMethodDefinition;
  86. };
  87. typedef vector<GenericArrayMethod> GenericArrayMethods;
  88. static GenericArrayMethods s_GenericArrayMethods;
  89. static size_t GetArrayGenericMethodsCount();
  90. static void PopulateArrayGenericMethods(Il2CppClass* klass, uint16_t offset);
  91. static void PopulateOneArrayGenericMethod(Il2CppClass* klass, uint16_t offset, uint16_t theMethodIndex);
  92. static void CollectImplicitArrayInterfaces(Il2CppClass* elementClass, ::std::vector<Il2CppClass*>& interfaces);
  93. static void SetupArrayOneMethod(Il2CppClass* arrayClass, MethodIndex theMethodIndex)
  94. {
  95. size_t methodIndex = 0;
  96. uint8_t rank = arrayClass->rank;
  97. ::std::vector<Il2CppClass*> interfaces;
  98. CollectImplicitArrayInterfaces(arrayClass, interfaces);
  99. size_t methodCount = 3 + (rank > 1 ? 2 : 1) + interfaces.size() * GetArrayGenericMethodsCount();
  100. IL2CPP_ASSERT(methodCount <= std::numeric_limits<uint16_t>::max());
  101. arrayClass->method_count = static_cast<uint16_t>(methodCount);
  102. // alloc once
  103. if (arrayClass->methods == NULL) {
  104. arrayClass->methods = (const MethodInfo**)MetadataCalloc(methodCount, sizeof(MethodInfo*), IL2CPP_MSTAT_METHOD);
  105. }
  106. size_t index = methodIndex++;
  107. const Il2CppType** parameters = NULL;
  108. if (arrayClass->methods[index] == NULL && index == theMethodIndex) {
  109. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  110. for (uint8_t i = 0; i < rank; i++)
  111. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  112. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, ".ctor", &il2cpp_defaults.void_class->byval_arg, rank, parameters);
  113. }
  114. if (rank > 1)
  115. {
  116. index = methodIndex++;
  117. if (arrayClass->methods[index] == NULL && index == theMethodIndex) {
  118. parameters = (const Il2CppType**)alloca(2 * rank * sizeof(Il2CppType*));
  119. for (uint8_t i = 0; i < 2 * rank; i++)
  120. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  121. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, ".ctor", &il2cpp_defaults.void_class->byval_arg, 2 * rank, parameters);
  122. }
  123. }
  124. index = methodIndex++;
  125. if (arrayClass->methods[index] == NULL && index == theMethodIndex) {
  126. parameters = (const Il2CppType**)alloca((rank + 1) * sizeof(Il2CppType*));
  127. for (uint8_t i = 0; i < rank; i++)
  128. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  129. parameters[rank] = &arrayClass->element_class->byval_arg;
  130. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Set", &il2cpp_defaults.void_class->byval_arg, rank + 1, parameters);
  131. }
  132. index = methodIndex++;
  133. if (arrayClass->methods[index] == NULL && index == theMethodIndex) {
  134. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  135. for (uint8_t i = 0; i < rank; i++)
  136. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  137. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Address", &arrayClass->element_class->this_arg, rank, parameters);
  138. }
  139. index = methodIndex++;
  140. if (arrayClass->methods[index] == NULL && index == theMethodIndex) {
  141. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  142. for (uint8_t i = 0; i < rank; i++)
  143. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  144. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Get", &arrayClass->element_class->byval_arg, rank, parameters);
  145. }
  146. IL2CPP_ASSERT(methodIndex <= std::numeric_limits<uint16_t>::max());
  147. PopulateOneArrayGenericMethod(arrayClass, static_cast<uint16_t>(methodIndex), static_cast<uint16_t>(theMethodIndex));
  148. }
  149. static void SetupArrayMethods(Il2CppClass* arrayClass)
  150. {
  151. size_t methodIndex = 0;
  152. uint8_t rank = arrayClass->rank;
  153. ::std::vector<Il2CppClass*> interfaces;
  154. CollectImplicitArrayInterfaces(arrayClass, interfaces);
  155. size_t methodCount = 3 + (rank > 1 ? 2 : 1) + interfaces.size() * GetArrayGenericMethodsCount();
  156. IL2CPP_ASSERT(methodCount <= std::numeric_limits<uint16_t>::max());
  157. arrayClass->method_count = static_cast<uint16_t>(methodCount);
  158. // alloc once
  159. if (arrayClass->methods == NULL) {
  160. arrayClass->methods = (const MethodInfo**)MetadataCalloc(methodCount, sizeof(MethodInfo*), IL2CPP_MSTAT_METHOD);
  161. }
  162. size_t index = methodIndex++;
  163. const Il2CppType** parameters = NULL;
  164. if (arrayClass->methods[index] == NULL) {
  165. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  166. for (uint8_t i = 0; i < rank; i++)
  167. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  168. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, ".ctor", &il2cpp_defaults.void_class->byval_arg, rank, parameters);
  169. }
  170. if (rank > 1)
  171. {
  172. index = methodIndex++;
  173. if (arrayClass->methods[index] == NULL) {
  174. parameters = (const Il2CppType**)alloca(2 * rank * sizeof(Il2CppType*));
  175. for (uint8_t i = 0; i < 2 * rank; i++)
  176. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  177. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, ".ctor", &il2cpp_defaults.void_class->byval_arg, 2 * rank, parameters);
  178. }
  179. }
  180. index = methodIndex++;
  181. if (arrayClass->methods[index] == NULL) {
  182. parameters = (const Il2CppType**)alloca((rank + 1) * sizeof(Il2CppType*));
  183. for (uint8_t i = 0; i < rank; i++)
  184. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  185. parameters[rank] = &arrayClass->element_class->byval_arg;
  186. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Set", &il2cpp_defaults.void_class->byval_arg, rank + 1, parameters);
  187. }
  188. index = methodIndex++;
  189. if (arrayClass->methods[index] == NULL) {
  190. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  191. for (uint8_t i = 0; i < rank; i++)
  192. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  193. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Address", &arrayClass->element_class->this_arg, rank, parameters);
  194. }
  195. index = methodIndex++;
  196. if (arrayClass->methods[index] == NULL) {
  197. parameters = (const Il2CppType**)alloca(rank * sizeof(Il2CppType*));
  198. for (uint8_t i = 0; i < rank; i++)
  199. parameters[i] = &il2cpp_defaults.int32_class->byval_arg;
  200. arrayClass->methods[index] = ConstructArrayMethod(arrayClass, "Get", &arrayClass->element_class->byval_arg, rank, parameters);
  201. }
  202. IL2CPP_ASSERT(methodIndex <= std::numeric_limits<uint16_t>::max());
  203. PopulateArrayGenericMethods(arrayClass, static_cast<uint16_t>(methodIndex));
  204. }
  205. static void CollectImplicitArrayInterfacesFromElementClass(Il2CppClass* elementClass, ::std::vector<Il2CppClass*>& interfaces)
  206. {
  207. while (elementClass != NULL)
  208. {
  209. interfaces.push_back(elementClass);
  210. if (!elementClass->byval_arg.valuetype && elementClass != il2cpp_defaults.value_type_class && elementClass != il2cpp_defaults.enum_class)
  211. {
  212. void* iter = NULL;
  213. while (Il2CppClass* itf = Class::GetInterfaces(elementClass, &iter))
  214. interfaces.push_back(itf);
  215. }
  216. if (elementClass->rank == 1)
  217. {
  218. ::std::vector<Il2CppClass*> elementInterfaces;
  219. CollectImplicitArrayInterfacesFromElementClass(elementClass->element_class, elementInterfaces);
  220. for (::std::vector<Il2CppClass*>::iterator iter = elementInterfaces.begin(); iter != elementInterfaces.end(); ++iter)
  221. {
  222. const Il2CppType* genericArgument = &(*iter)->byval_arg;
  223. interfaces.push_back(Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ilist_class, &genericArgument, 1));
  224. interfaces.push_back(Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_icollection_class, &genericArgument, 1));
  225. interfaces.push_back(Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ienumerable_class, &genericArgument, 1));
  226. interfaces.push_back(Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlylist_class, &genericArgument, 1));
  227. interfaces.push_back(Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlycollection_class, &genericArgument, 1));
  228. }
  229. }
  230. elementClass = Class::GetParent(elementClass);
  231. if (elementClass != NULL && (elementClass->byval_arg.valuetype || elementClass == il2cpp_defaults.value_type_class || elementClass == il2cpp_defaults.enum_class))
  232. break;
  233. }
  234. }
  235. static void CollectImplicitArrayInterfaces(Il2CppClass* arrayClass, ::std::vector<Il2CppClass*>& interfaces)
  236. {
  237. if (arrayClass->byval_arg.type != IL2CPP_TYPE_SZARRAY)
  238. return;
  239. CollectImplicitArrayInterfacesFromElementClass(arrayClass->element_class, interfaces);
  240. }
  241. // note assuming list is ordered as IList, ICollection, IEnumerable
  242. static void CollectGenericArrayMethods()
  243. {
  244. const size_t kNumGenericArrayMethods = 13;
  245. s_GenericArrayMethods.reserve(kNumGenericArrayMethods);
  246. void* iter = NULL;
  247. while (const MethodInfo* method = Class::GetMethods(il2cpp_defaults.array_class, &iter))
  248. {
  249. if (strncmp(method->name, "InternalArray__", 15))
  250. continue;
  251. std::string name;
  252. std::string methodName;
  253. Il2CppClass* implementingInterface = NULL;
  254. if (!strncmp(method->name, "InternalArray__ICollection_", 27))
  255. {
  256. implementingInterface = il2cpp_defaults.generic_icollection_class;
  257. methodName = method->name + 27;
  258. name = StringUtils::Printf("System.Collections.Generic.ICollection`1.%s", method->name + 27);
  259. }
  260. else if (!strncmp(method->name, "InternalArray__IEnumerable_", 27))
  261. {
  262. implementingInterface = il2cpp_defaults.generic_ienumerable_class;
  263. methodName = method->name + 27;
  264. name = StringUtils::Printf("System.Collections.Generic.IEnumerable`1.%s", method->name + 27);
  265. }
  266. else if (!strncmp(method->name, "InternalArray__IReadOnlyList_", 29))
  267. {
  268. implementingInterface = il2cpp_defaults.generic_ireadonlylist_class;
  269. methodName = method->name + 29;
  270. name = StringUtils::Printf("System.Collections.Generic.IReadOnlyList`1.%s", method->name + 29);
  271. }
  272. else if (!strncmp(method->name, "InternalArray__IReadOnlyCollection_", 35))
  273. {
  274. implementingInterface = il2cpp_defaults.generic_ireadonlycollection_class;
  275. methodName = method->name + 35;
  276. name = StringUtils::Printf("System.Collections.Generic.IReadOnlyCollection`1.%s", method->name + 35);
  277. }
  278. else
  279. {
  280. implementingInterface = il2cpp_defaults.generic_ilist_class;
  281. methodName = method->name + 15;
  282. name = StringUtils::Printf("System.Collections.Generic.IList`1.%s", method->name + 15);
  283. }
  284. Class::Init(implementingInterface);
  285. //[WL]
  286. Class::SetupMethods(implementingInterface);
  287. const MethodInfo* matchingInterfacesMethod = NULL;
  288. for (int methodIndex = 0; methodIndex < implementingInterface->method_count; methodIndex++)
  289. {
  290. const MethodInfo* interfaceMethod = implementingInterface->methods[methodIndex];
  291. if (methodName == interfaceMethod->name)
  292. matchingInterfacesMethod = interfaceMethod;
  293. }
  294. if (matchingInterfacesMethod != NULL)
  295. {
  296. GenericArrayMethod genericArrayMethod = { StringUtils::StringDuplicate(name.c_str()), method, matchingInterfacesMethod };
  297. s_GenericArrayMethods.push_back(genericArrayMethod);
  298. }
  299. }
  300. }
  301. static size_t GetArrayGenericMethodsCount()
  302. {
  303. if (s_GenericArrayMethods.size() == 0)
  304. CollectGenericArrayMethods();
  305. return s_GenericArrayMethods.size();
  306. }
  307. static MethodInfo* ConstructGenericArrayMethod(const GenericArrayMethod& genericArrayMethod, Il2CppClass* klass, Il2CppGenericContext* context)
  308. {
  309. MethodInfo* inflatedMethod;
  310. if (genericArrayMethod.method->is_generic)
  311. {
  312. inflatedMethod = GenericMethod::AllocateNewMethodInfo(genericArrayMethod.method, context->class_inst, context->method_inst);
  313. }
  314. else
  315. {
  316. inflatedMethod = (MethodInfo*)MetadataCalloc(1, sizeof(MethodInfo), IL2CPP_MSTAT_METHOD);
  317. memcpy(inflatedMethod, genericArrayMethod.method, sizeof(MethodInfo));
  318. }
  319. inflatedMethod->name = genericArrayMethod.name;
  320. // The array methods are owned by the specific array instance, but they do not exist in metadata
  321. // Ensure that the metadata token is zero (and not copied from the method definition) so any
  322. // metadata lookup (e.g. custom attributes) will not find anything
  323. inflatedMethod->klass = klass;
  324. // ==={{ modify by HybridCLR
  325. // 补充元数据需要这个token
  326. // inflatedMethod->token = 0;
  327. inflatedMethod->token = genericArrayMethod.method->token;
  328. // ===}}
  329. return inflatedMethod;
  330. }
  331. void ArrayMetadata::SetupMethodOnVTableIndex(Il2CppClass* klass, VTableIndex theVTableIndex, const il2cpp::os::FastAutoLock& lock)
  332. {
  333. uint8_t rank = klass->rank;
  334. ::std::vector<Il2CppClass*> interfaces;
  335. CollectImplicitArrayInterfaces(klass, interfaces);
  336. size_t methodCount = 3 + (rank > 1 ? 2 : 1) + interfaces.size() * GetArrayGenericMethodsCount();
  337. IL2CPP_ASSERT(methodCount <= std::numeric_limits<uint16_t>::max());
  338. klass->method_count = static_cast<uint16_t>(methodCount);
  339. // alloc once
  340. if (klass->methods == NULL) {
  341. klass->methods = (const MethodInfo**)MetadataCalloc(methodCount, sizeof(MethodInfo*), IL2CPP_MSTAT_METHOD);
  342. }
  343. uint16_t offset = klass->rank > 1 ? 5 : 4;
  344. for (int i = 0; i < klass->interface_offsets_count; i++)
  345. {
  346. Il2CppClass* interfaceType = klass->interfaceOffsets[i].interfaceType;
  347. if (!interfaceType->generic_class)
  348. continue;
  349. Il2CppClass* interfaceDefinition = GenericClass::GetTypeDefinition(interfaceType->generic_class);
  350. Il2CppGenericContext context = { 0 };
  351. context.method_inst = MetadataCache::GetGenericInst(&interfaceType->generic_class->context.class_inst->type_argv[0], 1);
  352. for (GenericArrayMethods::const_iterator iter = s_GenericArrayMethods.begin(); iter != s_GenericArrayMethods.end(); ++iter)
  353. {
  354. if (iter->interfaceMethodDefinition->klass != interfaceDefinition)
  355. continue;
  356. uint16_t index = offset++;
  357. size_t vtableIndex = klass->interfaceOffsets[i].offset + iter->interfaceMethodDefinition->slot;
  358. if (vtableIndex == theVTableIndex)
  359. {
  360. const MethodInfo* arrayMethod = NULL;
  361. if (klass->methods[index] == NULL)
  362. {
  363. arrayMethod = ConstructGenericArrayMethod(*iter, klass, &context);
  364. klass->methods[index] = arrayMethod;
  365. }
  366. else {
  367. arrayMethod = klass->methods[index];
  368. }
  369. klass->vtable[vtableIndex].method = arrayMethod;
  370. klass->vtable[vtableIndex].methodPtr = arrayMethod->virtualMethodPointer;
  371. return;
  372. }
  373. }
  374. }
  375. }
  376. static void PopulateOneArrayGenericMethod(Il2CppClass* klass, uint16_t offset, uint16_t oneIndex)
  377. {
  378. for (int i = 0; i < klass->interface_offsets_count; i++)
  379. {
  380. Il2CppClass* interfaceType = klass->interfaceOffsets[i].interfaceType;
  381. if (!interfaceType->generic_class)
  382. continue;
  383. Il2CppClass* interfaceDefinition = GenericClass::GetTypeDefinition(interfaceType->generic_class);
  384. Il2CppGenericContext context = { 0 };
  385. context.method_inst = MetadataCache::GetGenericInst(&interfaceType->generic_class->context.class_inst->type_argv[0], 1);
  386. for (GenericArrayMethods::const_iterator iter = s_GenericArrayMethods.begin(); iter != s_GenericArrayMethods.end(); ++iter)
  387. {
  388. if (iter->interfaceMethodDefinition->klass != interfaceDefinition)
  389. continue;
  390. uint16_t index = offset++;
  391. if (klass->methods[index] == NULL && index == oneIndex) {
  392. MethodInfo* arrayMethod = ConstructGenericArrayMethod(*iter, klass, &context);
  393. klass->methods[index] = arrayMethod;
  394. size_t vtableIndex = klass->interfaceOffsets[i].offset + iter->interfaceMethodDefinition->slot;
  395. klass->vtable[vtableIndex].method = arrayMethod;
  396. klass->vtable[vtableIndex].methodPtr = arrayMethod->virtualMethodPointer;
  397. return;
  398. }
  399. }
  400. }
  401. }
  402. static void PopulateArrayGenericMethods(Il2CppClass* klass, uint16_t offset)
  403. {
  404. for (int i = 0; i < klass->interface_offsets_count; i++)
  405. {
  406. Il2CppClass* interfaceType = klass->interfaceOffsets[i].interfaceType;
  407. if (!interfaceType->generic_class)
  408. continue;
  409. Il2CppClass* interfaceDefinition = GenericClass::GetTypeDefinition(interfaceType->generic_class);
  410. Il2CppGenericContext context = { 0 };
  411. context.method_inst = MetadataCache::GetGenericInst(&interfaceType->generic_class->context.class_inst->type_argv[0], 1);
  412. for (GenericArrayMethods::const_iterator iter = s_GenericArrayMethods.begin(); iter != s_GenericArrayMethods.end(); ++iter)
  413. {
  414. if (iter->interfaceMethodDefinition->klass != interfaceDefinition)
  415. continue;
  416. uint16_t index = offset++;
  417. if (klass->methods[index] == NULL) {
  418. MethodInfo* arrayMethod = ConstructGenericArrayMethod(*iter, klass, &context);
  419. klass->methods[index] = arrayMethod;
  420. size_t vtableIndex = klass->interfaceOffsets[i].offset + iter->interfaceMethodDefinition->slot;
  421. klass->vtable[vtableIndex].method = arrayMethod;
  422. klass->vtable[vtableIndex].methodPtr = arrayMethod->virtualMethodPointer;
  423. }
  424. }
  425. }
  426. }
  427. void ArrayMetadata::SetupArrayVTableAndInterfaceOffsets(Il2CppClass* klass)
  428. {
  429. // init once
  430. if (klass->interfaceOffsets != NULL)
  431. return;
  432. Il2CppClass* arrayClass = Class::GetParent(klass);
  433. Class::SetupVTable(arrayClass);
  434. size_t arrayInterfacesCount = arrayClass->interface_offsets_count;
  435. ::std::vector<Il2CppClass*> interfaces;
  436. if (klass->byval_arg.type == IL2CPP_TYPE_SZARRAY)
  437. {
  438. CollectImplicitArrayInterfaces(klass, interfaces);
  439. }
  440. Il2CppRuntimeInterfaceOffsetPair* newInterfaceOffsets = (Il2CppRuntimeInterfaceOffsetPair*)MetadataMalloc((arrayInterfacesCount + kImplicitArrayInterfaceCount * interfaces.size()) * sizeof(Il2CppRuntimeInterfaceOffsetPair), IL2CPP_MSTAT_INTERFACE);
  441. memcpy(newInterfaceOffsets, arrayClass->interfaceOffsets, (arrayInterfacesCount) * sizeof(Il2CppRuntimeInterfaceOffsetPair));
  442. int32_t arrayVTableSlot = arrayClass->vtable_count;
  443. size_t slots = arrayVTableSlot + interfaces.size() * (il2cpp_defaults.generic_ilist_class->method_count + il2cpp_defaults.generic_icollection_class->method_count + il2cpp_defaults.generic_ienumerable_class->method_count);
  444. slots += interfaces.size() * (il2cpp_defaults.generic_ireadonlylist_class->method_count + il2cpp_defaults.generic_ireadonlycollection_class->method_count);
  445. memcpy(klass->vtable, arrayClass->vtable, arrayVTableSlot * sizeof(VirtualInvokeData));
  446. size_t index = arrayInterfacesCount;
  447. int32_t vtableSlot = arrayVTableSlot;
  448. for (::std::vector<Il2CppClass*>::iterator iter = interfaces.begin(); iter != interfaces.end(); iter++, index += kImplicitArrayInterfaceCount)
  449. {
  450. const Il2CppType* genericArgument = &(*iter)->byval_arg;
  451. newInterfaceOffsets[index].interfaceType = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ilist_class, &genericArgument, 1);
  452. newInterfaceOffsets[index].offset = vtableSlot;
  453. vtableSlot += newInterfaceOffsets[index].interfaceType->method_count;
  454. newInterfaceOffsets[index + 1].interfaceType = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_icollection_class, &genericArgument, 1);
  455. newInterfaceOffsets[index + 1].offset = vtableSlot;
  456. vtableSlot += newInterfaceOffsets[index + 1].interfaceType->method_count;
  457. newInterfaceOffsets[index + 2].interfaceType = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ienumerable_class, &genericArgument, 1);
  458. newInterfaceOffsets[index + 2].offset = vtableSlot;
  459. vtableSlot += newInterfaceOffsets[index + 2].interfaceType->method_count;
  460. newInterfaceOffsets[index + 3].interfaceType = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlylist_class, &genericArgument, 1);
  461. newInterfaceOffsets[index + 3].offset = vtableSlot;
  462. vtableSlot += newInterfaceOffsets[index + 3].interfaceType->method_count;
  463. newInterfaceOffsets[index + 4].interfaceType = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlycollection_class, &genericArgument, 1);
  464. newInterfaceOffsets[index + 4].offset = vtableSlot;
  465. vtableSlot += newInterfaceOffsets[index + 4].interfaceType->method_count;
  466. }
  467. size_t interfaceOffsetsCount = arrayInterfacesCount + kImplicitArrayInterfaceCount * interfaces.size();
  468. IL2CPP_ASSERT(interfaceOffsetsCount <= std::numeric_limits<uint16_t>::max());
  469. klass->interface_offsets_count = static_cast<uint16_t>(interfaceOffsetsCount);
  470. klass->interfaceOffsets = newInterfaceOffsets;
  471. }
  472. void ArrayMetadata::SetupCastClass(Il2CppClass *arrayType)
  473. {
  474. Il2CppClass *elementType = arrayType->element_class;
  475. arrayType->castClass = ArrayMetadata::GetArrayVarianceReducedType(elementType);
  476. arrayType->has_references = Type::IsReference(&elementType->byval_arg) || elementType->has_references;
  477. }
  478. void ArrayMetadata::SetupArrayInterfaces(Il2CppClass* klass, const FastAutoLock& lock)
  479. {
  480. if (klass->byval_arg.type == IL2CPP_TYPE_SZARRAY)
  481. {
  482. IL2CPP_ASSERT(klass->implementedInterfaces == NULL);
  483. const Il2CppType* genericArguments = &klass->element_class->byval_arg;
  484. IL2CPP_ASSERT(klass->interfaces_count == kImplicitArrayInterfaceCount);
  485. klass->implementedInterfaces = (Il2CppClass**)MetadataMalloc(klass->interfaces_count * sizeof(Il2CppClass*), IL2CPP_MSTAT_INTERFACE);
  486. klass->implementedInterfaces[0] = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ilist_class, &genericArguments, 1);
  487. IL2CPP_ASSERT(klass->implementedInterfaces[0]);
  488. klass->implementedInterfaces[1] = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_icollection_class, &genericArguments, 1);
  489. IL2CPP_ASSERT(klass->implementedInterfaces[1]);
  490. klass->implementedInterfaces[2] = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ienumerable_class, &genericArguments, 1);
  491. IL2CPP_ASSERT(klass->implementedInterfaces[2]);
  492. klass->implementedInterfaces[3] = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlylist_class, &genericArguments, 1);
  493. IL2CPP_ASSERT(klass->implementedInterfaces[3]);
  494. klass->implementedInterfaces[4] = Class::GetInflatedGenericInstanceClass(il2cpp_defaults.generic_ireadonlycollection_class, &genericArguments, 1);
  495. IL2CPP_ASSERT(klass->implementedInterfaces[4]);
  496. }
  497. }
  498. void ArrayMetadata::SetupArrayVTable(Il2CppClass* klass, const FastAutoLock& lock)
  499. {
  500. // we assume we are being called as part of Class::Init and that the element class has already been initialized
  501. IL2CPP_ASSERT(klass->element_class->initialized);
  502. SetupCastClass(klass);
  503. SetupArrayVTableAndInterfaceOffsets(klass);
  504. SetupArrayMethods(klass);
  505. }
  506. void ArrayMetadata::SetupArrayVTableMethodIndex(Il2CppClass* klass, MethodIndex theMethodIndex, const il2cpp::os::FastAutoLock& lock)
  507. {
  508. IL2CPP_ASSERT(klass->element_class->initialized);
  509. SetupCastClass(klass);
  510. SetupArrayVTableAndInterfaceOffsets(klass);
  511. SetupArrayOneMethod(klass, theMethodIndex);
  512. }
  513. struct SZArrayClassHash
  514. {
  515. size_t operator()(const Il2CppClass* arrayClass) const
  516. {
  517. return Il2CppTypeHash::Hash(&arrayClass->byval_arg);
  518. }
  519. };
  520. struct SZArrayClassCompare
  521. {
  522. bool operator()(const Il2CppClass* arrayClass1, const Il2CppClass* arrayClass2) const
  523. {
  524. return Il2CppTypeEqualityComparer::AreEqual(&arrayClass1->byval_arg, &arrayClass2->byval_arg);
  525. }
  526. };
  527. struct ArrayClassHash
  528. {
  529. size_t operator()(const std::pair<Il2CppClass*, uint32_t>& arrayClass) const
  530. {
  531. return Il2CppTypeHash::Hash(&arrayClass.first->byval_arg) * arrayClass.second;
  532. }
  533. };
  534. struct ArrayClassCompare
  535. {
  536. bool operator()(const std::pair<Il2CppClass*, uint32_t>& arrayClass1, const std::pair<Il2CppClass*, uint32_t>& arrayClass2) const
  537. {
  538. return Il2CppTypeEqualityComparer::AreEqual(&arrayClass1.first->byval_arg, &arrayClass2.first->byval_arg) && arrayClass1.second == arrayClass2.second;
  539. }
  540. };
  541. typedef Il2CppReaderWriterLockedHashMap<Il2CppClass*, Il2CppClass*, SZArrayClassHash, SZArrayClassCompare> SZArrayClassMap;
  542. typedef Il2CppReaderWriterLockedHashMap<std::pair<Il2CppClass*, uint32_t>, Il2CppClass*, ArrayClassHash, ArrayClassCompare> ArrayClassMap;
  543. SZArrayClassMap s_SZArrayClassMap;
  544. ArrayClassMap s_ArrayClassMap;
  545. void ArrayMetadata::Clear()
  546. {
  547. s_SZArrayClassMap.Clear();
  548. s_ArrayClassMap.Clear();
  549. for (auto genericArrayMethod : s_GenericArrayMethods)
  550. IL2CPP_FREE((void*)genericArrayMethod.name, IL2CPP_MEM_STRING);
  551. s_GenericArrayMethods.clear();
  552. }
  553. static Il2CppClass* FindBoundedArrayClass(Il2CppClass* elementClass, uint32_t rank, bool bounded)
  554. {
  555. Il2CppClass* arrayClass = NULL;
  556. if (rank > 1 || bounded)
  557. {
  558. if (s_ArrayClassMap.TryGet(std::make_pair(elementClass, rank), &arrayClass))
  559. return arrayClass;
  560. }
  561. else
  562. {
  563. if (s_SZArrayClassMap.TryGet(elementClass, &arrayClass))
  564. return arrayClass;
  565. }
  566. return NULL;
  567. }
  568. Il2CppClass* ArrayMetadata::GetBoundedArrayClass(Il2CppClass* elementClass, uint32_t rank, bool bounded)
  569. {
  570. IL2CPP_ASSERT(rank <= 255);
  571. if (rank > 1)
  572. bounded = false;
  573. // Check for a cached array class using the reader lock only
  574. Il2CppClass* cachedArrayClass = FindBoundedArrayClass(elementClass, rank, bounded);
  575. if (cachedArrayClass != NULL)
  576. return cachedArrayClass;
  577. FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
  578. // Check if the array class was created while we were waiting for the g_MetadataLock
  579. cachedArrayClass = FindBoundedArrayClass(elementClass, rank, bounded);
  580. if (cachedArrayClass != NULL)
  581. return cachedArrayClass;
  582. Il2CppClass* arrayClass = il2cpp_defaults.array_class;
  583. Class::Init(arrayClass);
  584. //count number of virtual call slots for array class
  585. ::std::vector<Il2CppClass*> interfaces;
  586. if (rank <= 1 && !bounded)
  587. CollectImplicitArrayInterfacesFromElementClass(elementClass, interfaces);
  588. size_t slots = arrayClass->vtable_count + interfaces.size() * (il2cpp_defaults.generic_ilist_class->method_count + il2cpp_defaults.generic_icollection_class->method_count + il2cpp_defaults.generic_ienumerable_class->method_count);
  589. slots += interfaces.size() * (il2cpp_defaults.generic_ireadonlylist_class->method_count + il2cpp_defaults.generic_ireadonlycollection_class->method_count);
  590. Il2CppClass* klass = (Il2CppClass*)MetadataCalloc(1, sizeof(Il2CppClass) + (slots * sizeof(VirtualInvokeData)), IL2CPP_MSTAT_CLASS);
  591. #if !IL2CPP_SLIM_CLASS
  592. klass->klass = klass;
  593. #endif
  594. klass->image = elementClass->image;
  595. // can share the const char* since it's immutable
  596. klass->namespaze = elementClass->namespaze;
  597. klass->name = GetArrayName(elementClass->name, rank, bounded);
  598. klass->parent = il2cpp_defaults.array_class;
  599. klass->flags = TYPE_ATTRIBUTE_AUTO_LAYOUT | TYPE_ATTRIBUTE_ANSI_CLASS | TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_PUBLIC | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_SERIALIZABLE;
  600. klass->rank = rank;
  601. klass->instance_size = Class::GetInstanceSize(arrayClass);
  602. klass->stack_slot_size = sizeof(void*);
  603. klass->vtable_count = static_cast<uint16_t>(slots);
  604. // need this before we access the size or has_references
  605. Class::SetupFields(elementClass);
  606. klass->element_size = Class::GetArrayElementSize(elementClass);
  607. klass->native_size = klass->thread_static_fields_offset = -1;
  608. klass->has_references = Type::IsReference(&elementClass->byval_arg) || elementClass->has_references;
  609. klass->size_inited = true; // set only after instance_size and has_references are set
  610. klass->element_class = elementClass;
  611. SetupCastClass(klass);
  612. if (rank > 1 || bounded)
  613. {
  614. Il2CppArrayType *at = (Il2CppArrayType*)MetadataCalloc(1, sizeof(Il2CppArrayType), IL2CPP_MSTAT_TYPE);
  615. klass->byval_arg.type = IL2CPP_TYPE_ARRAY;
  616. klass->byval_arg.data.array = at;
  617. at->etype = &elementClass->byval_arg;
  618. at->rank = rank;
  619. }
  620. else
  621. {
  622. klass->byval_arg.type = IL2CPP_TYPE_SZARRAY;
  623. klass->byval_arg.data.type = &elementClass->byval_arg;
  624. }
  625. klass->this_arg = klass->byval_arg;
  626. klass->this_arg.byref = 1;
  627. if (rank > 1 || bounded)
  628. {
  629. klass->interfaces_count = 0;
  630. }
  631. else
  632. {
  633. klass->interfaces_count = kImplicitArrayInterfaceCount;
  634. }
  635. klass->interopData = MetadataCache::GetInteropDataForType(&klass->byval_arg);
  636. // Insert the new array class while still holding the g_MetadataLock
  637. // This ensures that the class is only added once
  638. // And WalkSZArrays and WalkArrays (see below) only take the g_MetadataLock and assume that the maps won't be changed
  639. // It's not safe to take the reader/writer lock there because those locks aren't re-entrant and those methods take
  640. // call backs that call arbitrary code
  641. if (rank > 1 || bounded)
  642. s_ArrayClassMap.Add(ArrayClassMap::key_type(std::make_pair(klass->element_class, klass->rank)), klass);
  643. else
  644. s_SZArrayClassMap.Add(klass->element_class, klass);
  645. return klass;
  646. }
  647. void ArrayMetadata::WalkSZArrays(ArrayTypeWalkCallback callback, void* context)
  648. {
  649. FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
  650. for (SZArrayClassMap::iterator it = s_SZArrayClassMap.UnlockedBegin(); it != s_SZArrayClassMap.UnlockedEnd(); it++)
  651. {
  652. callback(it->second, context);
  653. }
  654. }
  655. void ArrayMetadata::WalkArrays(ArrayTypeWalkCallback callback, void* context)
  656. {
  657. FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
  658. for (ArrayClassMap::iterator it = s_ArrayClassMap.UnlockedBegin(); it != s_ArrayClassMap.UnlockedEnd(); it++)
  659. {
  660. callback(it->second, context);
  661. }
  662. }
  663. } /* namespace vm */
  664. } /* namespace il2cpp */