GenericMethod.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #include "il2cpp-config.h"
  2. #include "metadata/GenericMetadata.h"
  3. #include "metadata/GenericMethod.h"
  4. #include "metadata/GenericSharing.h"
  5. #include "metadata/Il2CppGenericMethodCompare.h"
  6. #include "metadata/Il2CppGenericMethodHash.h"
  7. #include "os/Atomic.h"
  8. #include "os/Mutex.h"
  9. #include "utils/Memory.h"
  10. #include "vm/Class.h"
  11. #include "vm/Exception.h"
  12. #include "vm/GenericClass.h"
  13. #include "vm/MetadataAlloc.h"
  14. #include "vm/MetadataCache.h"
  15. #include "vm/MetadataLock.h"
  16. #include "vm/Method.h"
  17. #include "vm/Runtime.h"
  18. #include "vm/Type.h"
  19. #include "utils/Il2CppHashMap.h"
  20. #include "utils/InitOnce.h"
  21. #include "il2cpp-class-internals.h"
  22. #include "il2cpp-runtime-metadata.h"
  23. #include "il2cpp-runtime-stats.h"
  24. #include <string>
  25. #include "hybridclr/metadata/MetadataUtil.h"
  26. #include "hybridclr/metadata/MetadataModule.h"
  27. #include "hybridclr/interpreter/InterpreterModule.h"
  28. using il2cpp::metadata::GenericMetadata;
  29. using il2cpp::metadata::GenericSharing;
  30. using il2cpp::os::FastAutoLock;
  31. using il2cpp::vm::Class;
  32. using il2cpp::vm::GenericClass;
  33. using il2cpp::vm::MetadataCalloc;
  34. using il2cpp::vm::MetadataCache;
  35. using il2cpp::vm::Method;
  36. using il2cpp::vm::Runtime;
  37. using il2cpp::vm::Type;
  38. struct FullySharedGenericMethodInfo : public MethodInfo
  39. {
  40. FullySharedGenericMethodInfo() { memset(this, 0, sizeof(*this)); }
  41. Il2CppMethodPointer rawVirtualMethodPointer;
  42. Il2CppMethodPointer rawDirectMethodPointer;
  43. InvokerMethod rawInvokerMethod;
  44. };
  45. static size_t SizeOfGenericMethodInfo(bool hasFullGenericSignature)
  46. {
  47. if (hasFullGenericSignature)
  48. return sizeof(FullySharedGenericMethodInfo);
  49. return sizeof(MethodInfo);
  50. }
  51. static MethodInfo* AllocGenericMethodInfo(bool hasFullGenericSignature)
  52. {
  53. return (MethodInfo*)MetadataCalloc(1, SizeOfGenericMethodInfo(hasFullGenericSignature), IL2CPP_MSTAT_METHOD);
  54. }
  55. static MethodInfo* AllocCopyGenericMethodInfo(const MethodInfo* sourceMethodInfo)
  56. {
  57. MethodInfo* newMethodInfo = AllocGenericMethodInfo(sourceMethodInfo->has_full_generic_sharing_signature);
  58. memcpy(newMethodInfo, sourceMethodInfo, SizeOfGenericMethodInfo(sourceMethodInfo->has_full_generic_sharing_signature));
  59. return newMethodInfo;
  60. }
  61. static void FullySharedGenericInvokeRedirectHasAdjustorThunk(Il2CppMethodPointer methodPointer, const MethodInfo* method, void* obj, void** args, void* retVal)
  62. {
  63. IL2CPP_ASSERT(Method::IsGenericInstance(method));
  64. IL2CPP_ASSERT(il2cpp::vm::Runtime::IsFullGenericSharingEnabled());
  65. IL2CPP_ASSERT(methodPointer == method->virtualMethodPointer || methodPointer == method->methodPointer);
  66. const FullySharedGenericMethodInfo* sharedMethodInfo = reinterpret_cast<const FullySharedGenericMethodInfo*>(method);
  67. IL2CPP_ASSERT(sharedMethodInfo->rawDirectMethodPointer != sharedMethodInfo->rawVirtualMethodPointer);
  68. if (methodPointer == sharedMethodInfo->virtualMethodPointer)
  69. sharedMethodInfo->rawInvokerMethod(sharedMethodInfo->rawVirtualMethodPointer, method, obj, args, retVal);
  70. else
  71. sharedMethodInfo->rawInvokerMethod(sharedMethodInfo->rawDirectMethodPointer, method, obj, args, retVal);
  72. }
  73. static void FullySharedGenericInvokeRedirectNoAdjustorThunk(Il2CppMethodPointer methodPointer, const MethodInfo* method, void* obj, void** args, void* retVal)
  74. {
  75. IL2CPP_ASSERT(Method::IsGenericInstance(method));
  76. IL2CPP_ASSERT(il2cpp::vm::Runtime::IsFullGenericSharingEnabled());
  77. IL2CPP_ASSERT(methodPointer == method->methodPointer || methodPointer == method->virtualMethodPointer);
  78. const FullySharedGenericMethodInfo* sharedMethodInfo = reinterpret_cast<const FullySharedGenericMethodInfo*>(method);
  79. IL2CPP_ASSERT(sharedMethodInfo->rawDirectMethodPointer == sharedMethodInfo->rawVirtualMethodPointer);
  80. sharedMethodInfo->rawInvokerMethod(sharedMethodInfo->rawDirectMethodPointer, method, obj, args, retVal);
  81. }
  82. namespace il2cpp
  83. {
  84. namespace metadata
  85. {
  86. typedef Il2CppReaderWriterLockedHashMap<const Il2CppGenericMethod*, MethodInfo*, Il2CppGenericMethodHash, Il2CppGenericMethodCompare> Il2CppGenericMethodMap;
  87. static Il2CppGenericMethodMap s_GenericMethodMap;
  88. static Il2CppGenericMethodMap s_PendingGenericMethodMap;
  89. static bool HasFullGenericSharedParametersOrReturn(const MethodInfo* methodDefinition, const Il2CppType** inflatedParameterTypes)
  90. {
  91. // If a method has a variable sized return type, the FGS method will always
  92. // expect the return value to be passed as a by ref parameter
  93. if (Type::HasVariableRuntimeSizeWhenFullyShared(methodDefinition->return_type))
  94. return true;
  95. for (int i = 0; i < methodDefinition->parameters_count; i++)
  96. {
  97. // Value types are passed by ref, but reference types are passed normally, so if the inflated parameter is a
  98. // reference type, we don't have a signature difference.
  99. if (Type::IsValueType(inflatedParameterTypes[i]) && Type::HasVariableRuntimeSizeWhenFullyShared(methodDefinition->parameters[i]))
  100. return true;
  101. }
  102. return false;
  103. }
  104. static void AnUnresolvedCallStubWasNotFound()
  105. {
  106. vm::Exception::Raise(vm::Exception::GetExecutionEngineException("An unresolved indirect call lookup failed"));
  107. }
  108. // This method must have a different signature than AnUnresolvedCallStubWasNotFound to prevent identical COMDAT folding
  109. // FullySharedGenericInvokeRedirectHasAdjustorThunk relies on this method having a different address
  110. static void AnUnresolvedCallStubWasNotFoundValueType(void* obj)
  111. {
  112. vm::Exception::Raise(vm::Exception::GetExecutionEngineException("An unresolved indirect call to a value type failed"));
  113. }
  114. static void AGenericMethodWhichIsTooDeeplyNestedWasInvoked()
  115. {
  116. vm::Exception::Raise(vm::Exception::GetMaximumNestedGenericsException());
  117. }
  118. static void AGenericMethodWhichIsTooDeeplyNestedWasInvokedInvoker(Il2CppMethodPointer ptr, const MethodInfo* method, void* obj, void** args, void* ret)
  119. {
  120. AGenericMethodWhichIsTooDeeplyNestedWasInvoked();
  121. }
  122. static FullySharedGenericMethodInfo ambiguousMethodInfo;
  123. bool GenericMethod::IsGenericAmbiguousMethodInfo(const MethodInfo* method)
  124. {
  125. return method == &ambiguousMethodInfo;
  126. }
  127. const MethodInfo* GenericMethod::GetGenericVirtualMethod(const MethodInfo* vtableSlotMethod, const MethodInfo* genericVirtualMethod)
  128. {
  129. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(GetGenericVirtualMethod, "We should only do the following slow method lookup once and then cache on type itself.");
  130. const Il2CppGenericInst* classInst = NULL;
  131. if (vtableSlotMethod->is_inflated)
  132. {
  133. classInst = vtableSlotMethod->genericMethod->context.class_inst;
  134. vtableSlotMethod = vtableSlotMethod->genericMethod->methodDefinition;
  135. }
  136. return metadata::GenericMethod::GetMethod(vtableSlotMethod, classInst, genericVirtualMethod->genericMethod->context.method_inst);
  137. }
  138. const MethodInfo* GenericMethod::GetMethod(const MethodInfo* methodDefinition, const Il2CppGenericInst* classInst, const Il2CppGenericInst* methodInst)
  139. {
  140. Il2CppGenericMethod gmethod = { 0 };
  141. gmethod.methodDefinition = methodDefinition;
  142. gmethod.context.class_inst = classInst;
  143. gmethod.context.method_inst = methodInst;
  144. return GetMethod(&gmethod, true);
  145. }
  146. MethodInfo* GenericMethod::AllocateNewMethodInfo(const MethodInfo* methodDefinition, const Il2CppGenericInst* classInst, const Il2CppGenericInst* methodInst)
  147. {
  148. const MethodInfo* methodInfo = GetMethod(methodDefinition, classInst, methodInst);
  149. return AllocCopyGenericMethodInfo(methodInfo);
  150. }
  151. const MethodInfo* GenericMethod::GetMethod(const Il2CppGenericMethod* gmethod)
  152. {
  153. return GetMethod(gmethod, false);
  154. }
  155. const MethodInfo* GenericMethod::GetMethod(const Il2CppGenericMethod* gmethod, bool copyMethodPtr)
  156. {
  157. // This can be NULL only when we have hit the generic recursion depth limit.
  158. if (gmethod == NULL)
  159. {
  160. MethodInfo* newMethod = AllocGenericMethodInfo(il2cpp::vm::Runtime::IsFullGenericSharingEnabled());
  161. if (il2cpp::vm::Runtime::IsFullGenericSharingEnabled())
  162. {
  163. ((FullySharedGenericMethodInfo*)newMethod)->rawVirtualMethodPointer = AGenericMethodWhichIsTooDeeplyNestedWasInvoked;
  164. ((FullySharedGenericMethodInfo*)newMethod)->rawDirectMethodPointer = AGenericMethodWhichIsTooDeeplyNestedWasInvoked;
  165. ((FullySharedGenericMethodInfo*)newMethod)->rawInvokerMethod = AGenericMethodWhichIsTooDeeplyNestedWasInvokedInvoker;
  166. }
  167. newMethod->methodPointer = AGenericMethodWhichIsTooDeeplyNestedWasInvoked;
  168. newMethod->virtualMethodPointer = AGenericMethodWhichIsTooDeeplyNestedWasInvoked;
  169. newMethod->invoker_method = AGenericMethodWhichIsTooDeeplyNestedWasInvokedInvoker;
  170. return newMethod;
  171. }
  172. // First check for an already constructed generic method using the shared/reader lock
  173. MethodInfo* existingMethod;
  174. if (s_GenericMethodMap.TryGet(gmethod, &existingMethod))
  175. return existingMethod;
  176. if (Method::IsAmbiguousMethodInfo(gmethod->methodDefinition))
  177. {
  178. // is_inflated is used as an initialized check
  179. if (!ambiguousMethodInfo.is_inflated)
  180. {
  181. memcpy(&ambiguousMethodInfo, gmethod->methodDefinition, sizeof(MethodInfo));
  182. ambiguousMethodInfo.is_inflated = true;
  183. ambiguousMethodInfo.rawVirtualMethodPointer = gmethod->methodDefinition->virtualMethodPointer;
  184. ambiguousMethodInfo.rawDirectMethodPointer = gmethod->methodDefinition->methodPointer;
  185. ambiguousMethodInfo.invoker_method = gmethod->methodDefinition->invoker_method;
  186. }
  187. return &ambiguousMethodInfo;
  188. }
  189. return CreateMethodLocked(gmethod, copyMethodPtr);
  190. }
  191. const MethodInfo* GenericMethod::CreateMethodLocked(const Il2CppGenericMethod* gmethod, bool copyMethodPtr)
  192. {
  193. // We need to inflate a new generic method, take the metadata mutex
  194. // All code below this point can and does assume mutual exclusion
  195. FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
  196. // Recheck the s_GenericMethodMap in case there was a race to add this generic method
  197. MethodInfo* existingMethod;
  198. if (s_GenericMethodMap.TryGet(gmethod, &existingMethod))
  199. return existingMethod;
  200. // GetMethodLocked may be called recursively, we keep tracking of pending inflations
  201. if (s_PendingGenericMethodMap.TryGet(gmethod, &existingMethod))
  202. return existingMethod;
  203. if (copyMethodPtr)
  204. gmethod = MetadataCache::GetGenericMethod(gmethod->methodDefinition, gmethod->context.class_inst, gmethod->context.method_inst);
  205. const MethodInfo* methodDefinition = gmethod->methodDefinition;
  206. Il2CppClass* declaringClass = methodDefinition->klass;
  207. if (gmethod->context.class_inst)
  208. {
  209. Il2CppGenericClass* genericClassDeclaringType = GenericMetadata::GetGenericClass(methodDefinition->klass, gmethod->context.class_inst);
  210. declaringClass = GenericClass::GetClass(genericClassDeclaringType);
  211. // we may fail if we cannot construct generic type
  212. if (!declaringClass)
  213. return NULL;
  214. }
  215. const Il2CppType** parameters = GenericMetadata::InflateParameters(methodDefinition->parameters, methodDefinition->parameters_count, &gmethod->context, true);
  216. il2cpp::vm::Il2CppGenericMethodPointers methodPointers = MetadataCache::GetGenericMethodPointers(methodDefinition, &gmethod->context);
  217. bool hasFullGenericSharingSignature = methodPointers.isFullGenericShared && HasFullGenericSharedParametersOrReturn(gmethod->methodDefinition, parameters);
  218. MethodInfo* newMethod = AllocGenericMethodInfo(hasFullGenericSharingSignature);
  219. // we set the pending generic method map here because the initialization may recurse and try to retrieve the same generic method
  220. // this is safe because we *always* take the lock when retrieving the MethodInfo from a generic method.
  221. // if we move lock to only if MethodInfo needs constructed then we need to revisit this since we could return a partially initialized MethodInfo
  222. s_PendingGenericMethodMap.Add(gmethod, newMethod);
  223. newMethod->klass = declaringClass;
  224. newMethod->flags = methodDefinition->flags;
  225. newMethod->iflags = methodDefinition->iflags;
  226. newMethod->slot = methodDefinition->slot;
  227. newMethod->name = methodDefinition->name;
  228. newMethod->is_generic = false;
  229. newMethod->is_inflated = true;
  230. newMethod->token = methodDefinition->token;
  231. newMethod->return_type = GenericMetadata::InflateIfNeeded(methodDefinition->return_type, &gmethod->context, true);
  232. newMethod->parameters_count = methodDefinition->parameters_count;
  233. newMethod->parameters = parameters;
  234. newMethod->genericMethod = gmethod;
  235. if (!gmethod->context.method_inst)
  236. {
  237. if (methodDefinition->is_generic)
  238. newMethod->is_generic = true;
  239. if (!declaringClass->generic_class)
  240. {
  241. newMethod->genericContainerHandle = methodDefinition->genericContainerHandle;
  242. }
  243. newMethod->methodMetadataHandle = methodDefinition->methodMetadataHandle;
  244. }
  245. else if (!il2cpp::vm::Runtime::IsLazyRGCTXInflationEnabled() && !il2cpp::metadata::GenericMetadata::ContainsGenericParameters(newMethod))
  246. {
  247. // we only need RGCTX for generic instance methods
  248. newMethod->rgctx_data = InflateRGCTXLocked(gmethod, lock);
  249. }
  250. newMethod->virtualMethodPointer = methodPointers.virtualMethodPointer;
  251. newMethod->methodPointer = methodPointers.methodPointer;
  252. if (methodPointers.methodPointer)
  253. {
  254. newMethod->invoker_method = methodPointers.invoker_method;
  255. }
  256. else
  257. {
  258. newMethod->invoker_method = Runtime::GetMissingMethodInvoker();
  259. il2cpp::vm::Il2CppUnresolvedCallStubs stubs = MetadataCache::GetUnresovledCallStubs(newMethod);
  260. newMethod->methodPointer = stubs.methodPointer;
  261. newMethod->virtualMethodPointer = stubs.virtualMethodPointer;
  262. }
  263. newMethod->has_full_generic_sharing_signature = hasFullGenericSharingSignature;
  264. bool isInterpMethod = hybridclr::metadata::IsInterpreterMethod(newMethod);
  265. if (!isInterpMethod)
  266. {
  267. newMethod->has_full_generic_sharing_signature = hasFullGenericSharingSignature;
  268. }
  269. ++il2cpp_runtime_stats.inflated_method_count;
  270. bool indirectCallViaInvokers = il2cpp::vm::Method::HasFullGenericSharingSignature(newMethod);
  271. if (indirectCallViaInvokers)
  272. {
  273. // The method has a full generic sharing signature - that is it a fully shared method an has any fully shared parameter types or return type,
  274. // then its signature doesn't match the expected signature
  275. // e.g. If List<T>::Insert(T t) is fully shared then for List<int>::Insert(int), the C++ fully shared instance would be List::Insert(void*) and require an int* to be passed in.
  276. // So in that case we use the unresolved call stubs to find a matching standard signature to wrap any indirect/virtual calls
  277. FullySharedGenericMethodInfo* sharedMethodInfo = reinterpret_cast<FullySharedGenericMethodInfo*>(newMethod);
  278. sharedMethodInfo->rawVirtualMethodPointer = newMethod->virtualMethodPointer;
  279. sharedMethodInfo->rawDirectMethodPointer = newMethod->methodPointer;
  280. sharedMethodInfo->rawInvokerMethod = newMethod->invoker_method;
  281. bool hasAdjustorThunk = newMethod->methodPointer != newMethod->virtualMethodPointer;
  282. if (hasAdjustorThunk)
  283. newMethod->invoker_method = FullySharedGenericInvokeRedirectHasAdjustorThunk;
  284. else
  285. newMethod->invoker_method = FullySharedGenericInvokeRedirectNoAdjustorThunk;
  286. il2cpp::vm::Il2CppUnresolvedCallStubs stubs = MetadataCache::GetUnresovledCallStubs(newMethod);
  287. if (stubs.stubsFound)
  288. {
  289. newMethod->methodPointer = stubs.methodPointer;
  290. newMethod->virtualMethodPointer = stubs.virtualMethodPointer;
  291. }
  292. else
  293. {
  294. newMethod->methodPointer = AnUnresolvedCallStubWasNotFound;
  295. newMethod->virtualMethodPointer = AnUnresolvedCallStubWasNotFound;
  296. if (hasAdjustorThunk)
  297. {
  298. // The FullySharedGenericInvokeRedirectHasAdjustorThunk requires that methodPointer and virtualMethodPointer be different
  299. // so it can tell which raw* method it should call even though it doesn't directly call them
  300. IL2CPP_ASSERT(reinterpret_cast<Il2CppMethodPointer>(AnUnresolvedCallStubWasNotFoundValueType) != AnUnresolvedCallStubWasNotFound);
  301. if (reinterpret_cast<Il2CppMethodPointer>(AnUnresolvedCallStubWasNotFoundValueType) != AnUnresolvedCallStubWasNotFound)
  302. {
  303. newMethod->methodPointer = reinterpret_cast<Il2CppMethodPointer>(AnUnresolvedCallStubWasNotFoundValueType);
  304. }
  305. else
  306. {
  307. // If we got hit by COMDAT folding (but in DEBUG, which is the most likely way it would happen)
  308. // Ensure that are methodPointers are definitely different
  309. // We'll get an less specific error message, but it's better than corruption
  310. // Make the change on methodPointer because we're most likely to be called
  311. newMethod->methodPointer = il2cpp::vm::Method::GetEntryPointNotFoundMethodInfo()->methodPointer;
  312. }
  313. }
  314. }
  315. }
  316. else
  317. {
  318. newMethod->methodPointerCallByInterp = newMethod->methodPointer;
  319. newMethod->virtualMethodPointerCallByInterp = newMethod->virtualMethodPointer;
  320. }
  321. bool isAotImplByInterp = hybridclr::metadata::MetadataModule::IsImplementedByInterpreter(newMethod);
  322. bool isAdjustorThunkMethod = IS_CLASS_VALUE_TYPE(newMethod->klass) && hybridclr::metadata::IsInstanceMethod(newMethod);
  323. if (isInterpMethod || (isAotImplByInterp && (newMethod->methodPointer == nullptr || newMethod->methodPointer == AnUnresolvedCallStubWasNotFound || newMethod->methodPointer == (Il2CppMethodPointer)AnUnresolvedCallStubWasNotFoundValueType)))
  324. {
  325. newMethod->invoker_method = hybridclr::interpreter::InterpreterModule::GetMethodInvoker(newMethod);
  326. newMethod->methodPointer = newMethod->methodPointerCallByInterp = hybridclr::interpreter::InterpreterModule::GetMethodPointer(newMethod);
  327. newMethod->virtualMethodPointer = newMethod->virtualMethodPointerCallByInterp = isAdjustorThunkMethod ?
  328. hybridclr::interpreter::InterpreterModule::GetAdjustThunkMethodPointer(newMethod) :
  329. (newMethod->methodPointerCallByInterp != hybridclr::interpreter::InterpreterModule::NotSupportNative2Managed ?
  330. newMethod->methodPointerCallByInterp : hybridclr::interpreter::InterpreterModule::NotSupportAdjustorThunk);
  331. if (indirectCallViaInvokers)
  332. {
  333. FullySharedGenericMethodInfo* sharedMethodInfo = reinterpret_cast<FullySharedGenericMethodInfo*>(newMethod);
  334. if (!hybridclr::interpreter::InterpreterModule::HasImplementCallNative2Managed(newMethod))
  335. {
  336. newMethod->methodPointer = newMethod->methodPointerCallByInterp = sharedMethodInfo->rawDirectMethodPointer;
  337. }
  338. if (!hybridclr::interpreter::InterpreterModule::HasImplementCallVirtualNative2Managed(newMethod))
  339. {
  340. newMethod->virtualMethodPointer = newMethod->virtualMethodPointerCallByInterp = sharedMethodInfo->rawVirtualMethodPointer;
  341. }
  342. }
  343. newMethod->initInterpCallMethodPointer = true;
  344. newMethod->isInterpterImpl = true;
  345. }
  346. else if (newMethod->methodPointer != AnUnresolvedCallStubWasNotFound && newMethod->methodPointer != (Il2CppMethodPointer)AnUnresolvedCallStubWasNotFoundValueType)
  347. {
  348. newMethod->methodPointerCallByInterp = newMethod->methodPointer;
  349. newMethod->virtualMethodPointerCallByInterp = newMethod->virtualMethodPointer;
  350. }
  351. // IL2CPP_ASSERT(!indirectCallViaInvokers || !isAdjustorThunkMethod || newMethod->methodPointerCallByInterp != newMethod->virtualMethodPointerCallByInterp);
  352. // If we are a default interface method on a generic instance interface we need to ensure that the interfaces rgctx is inflated
  353. if (Method::IsDefaultInterfaceMethodOnGenericInstance(newMethod))
  354. vm::Class::InitLocked(declaringClass, lock);
  355. // The generic method is fully created,
  356. // Update the generic method map, this needs to take an exclusive lock
  357. // **** This must happen with the metadata lock held and be released before the metalock is released ****
  358. // **** This prevents deadlocks and ensures that there is no race condition
  359. // **** creating a new method adding it to s_GenericMethodMap and removing it from s_PendingGenericMethodMap
  360. s_GenericMethodMap.Add(gmethod, newMethod);
  361. // Remove the method from the pending table
  362. s_PendingGenericMethodMap.Remove(gmethod);
  363. return newMethod;
  364. }
  365. const Il2CppRGCTXData* GenericMethod::InflateRGCTX(const MethodInfo* method)
  366. {
  367. IL2CPP_ASSERT(method->is_inflated);
  368. IL2CPP_ASSERT(method->genericMethod);
  369. IL2CPP_ASSERT(method->genericMethod->context.method_inst);
  370. return il2cpp::utils::InitOnce(const_cast<Il2CppRGCTXData**>(&method->rgctx_data), &il2cpp::vm::g_MetadataLock, [method](const il2cpp::os::FastAutoLock& lock) {
  371. return const_cast<Il2CppRGCTXData*>(GenericMethod::InflateRGCTXLocked(method->genericMethod, lock));
  372. });
  373. }
  374. const Il2CppRGCTXData* GenericMethod::InflateRGCTXLocked(const Il2CppGenericMethod* gmethod, const il2cpp::os::FastAutoLock &lock)
  375. {
  376. return GenericMetadata::InflateRGCTXLocked(gmethod->methodDefinition->klass->image, gmethod->methodDefinition->token, &gmethod->context, lock);
  377. }
  378. const Il2CppGenericContext* GenericMethod::GetContext(const Il2CppGenericMethod* gmethod)
  379. {
  380. return &gmethod->context;
  381. }
  382. static std::string FormatGenericArguments(const Il2CppGenericInst* inst)
  383. {
  384. std::string output;
  385. if (inst)
  386. {
  387. output.append("<");
  388. for (size_t i = 0; i < inst->type_argc; ++i)
  389. {
  390. if (i != 0)
  391. output.append(", ");
  392. output.append(Type::GetName(inst->type_argv[i], IL2CPP_TYPE_NAME_FORMAT_FULL_NAME));
  393. }
  394. output.append(">");
  395. }
  396. return output;
  397. }
  398. std::string GenericMethod::GetFullName(const Il2CppGenericMethod* gmethod)
  399. {
  400. const MethodInfo* method = gmethod->methodDefinition;
  401. std::string output;
  402. output.append(Type::GetName(&gmethod->methodDefinition->klass->byval_arg, IL2CPP_TYPE_NAME_FORMAT_FULL_NAME));
  403. output.append(FormatGenericArguments(gmethod->context.class_inst));
  404. output.append("::");
  405. output.append(Method::GetName(method));
  406. output.append(FormatGenericArguments(gmethod->context.method_inst));
  407. return output;
  408. }
  409. void GenericMethod::ClearStatics()
  410. {
  411. s_GenericMethodMap.Clear();
  412. }
  413. } /* namespace vm */
  414. } /* namespace il2cpp */