VTableSetup.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. #include "VTableSetup.h"
  2. #include <algorithm>
  3. #include "vm/GlobalMetadata.h"
  4. #include "metadata/GenericMetadata.h"
  5. #include "MetadataModule.h"
  6. namespace hybridclr
  7. {
  8. namespace metadata
  9. {
  10. const Il2CppType* TryInflateIfNeed(const Il2CppType* containerType, const Il2CppType* genericType, const Il2CppType* selfType)
  11. {
  12. if (selfType->type == IL2CPP_TYPE_CLASS || selfType->type == IL2CPP_TYPE_VALUETYPE)
  13. {
  14. if (genericType->data.typeHandle == selfType->data.typeHandle)
  15. {
  16. return containerType;
  17. }
  18. }
  19. return TryInflateIfNeed(containerType, selfType);
  20. }
  21. VTableSetUp* VTableSetUp::InflateVts(Il2CppType2TypeDeclaringTreeMap& cache, VTableSetUp* genericType, const Il2CppType* type)
  22. {
  23. IL2CPP_ASSERT(genericType->_type->data.typeHandle == type->data.generic_class->type->data.typeHandle);
  24. VTableSetUp* tdt = new (HYBRIDCLR_MALLOC_ZERO(sizeof(VTableSetUp))) VTableSetUp();
  25. tdt->_type = type;
  26. tdt->_typeDef = genericType->_typeDef;
  27. tdt->_parent = genericType->_parent ? BuildByType(cache, TryInflateIfNeed(type, genericType->_parent->_type)) : nullptr;
  28. tdt->_name = genericType->_name;
  29. for (VTableSetUp* gintf : genericType->_interfaces)
  30. {
  31. const Il2CppType* intType = TryInflateIfNeed(type, gintf->_type);
  32. VTableSetUp* intf = BuildByType(cache, intType);
  33. tdt->_interfaces.push_back(intf);
  34. }
  35. for (GenericClassMethod& gcm : genericType->_virtualMethods)
  36. {
  37. tdt->_virtualMethods.push_back({ TryInflateIfNeed(type, genericType->_type, gcm.type), gcm.method, gcm.name });
  38. }
  39. for (RawInterfaceOffsetInfo& roi : genericType->_interfaceOffsetInfos)
  40. {
  41. const Il2CppType* intType = TryInflateIfNeed(type, genericType->_type, roi.type);
  42. VTableSetUp* intf = BuildByType(cache, intType);
  43. tdt->_interfaceOffsetInfos.push_back({ intType, intf, roi.offset });
  44. }
  45. for (VirtualMethodImpl& vmi : genericType->_methodImpls)
  46. {
  47. const Il2CppType* declaringType = vmi.type ? TryInflateIfNeed(type, genericType->_type, vmi.type) : nullptr;
  48. tdt->_methodImpls.push_back({ vmi.method, declaringType, vmi.slot /*, vmi.name*/});
  49. }
  50. return tdt;
  51. }
  52. VTableSetUp* VTableSetUp::BuildByType(Il2CppType2TypeDeclaringTreeMap& cache, const Il2CppType* type)
  53. {
  54. auto it = cache.find(type);
  55. if (it != cache.end())
  56. {
  57. return it->second;
  58. }
  59. if (type->type == IL2CPP_TYPE_GENERICINST)
  60. {
  61. const Il2CppType* genericType = type->data.generic_class->type;
  62. IL2CPP_ASSERT(genericType);
  63. VTableSetUp* gdt = BuildByType(cache, genericType);
  64. VTableSetUp* gidt = InflateVts(cache, gdt, type);
  65. return cache[type] = gidt;
  66. }
  67. VTableSetUp* tdt = new (HYBRIDCLR_MALLOC_ZERO(sizeof(VTableSetUp))) VTableSetUp();
  68. const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
  69. const char* ns = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex);
  70. const char* name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
  71. const Il2CppType* parentType = nullptr;
  72. // FIXME. cache
  73. if (typeDef->parentIndex != kInvalidIndex)
  74. {
  75. parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->parentIndex);
  76. }
  77. tdt->_type = type;
  78. tdt->_typeDef = typeDef;
  79. tdt->_parent = parentType ? BuildByType(cache, parentType) : nullptr;
  80. tdt->_name = name;
  81. for (uint32_t i = 0; i < typeDef->interfaces_count; i++)
  82. {
  83. const Il2CppType* intType = il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(typeDef, i);
  84. VTableSetUp* intf = BuildByType(cache, intType);
  85. tdt->_interfaces.push_back(intf);
  86. }
  87. for (uint32_t i = 0; i < typeDef->method_count; i++)
  88. {
  89. const Il2CppMethodDefinition* methodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromIndex(typeDef->methodStart + i);
  90. const char* methodName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex);
  91. if (hybridclr::metadata::IsVirtualMethod(methodDef->flags))
  92. {
  93. tdt->_virtualMethods.push_back({ type, methodDef, methodName });
  94. }
  95. }
  96. if (hybridclr::metadata::IsInterface(typeDef->flags))
  97. {
  98. tdt->ComputeInterfaceVtables(cache);
  99. }
  100. else
  101. {
  102. tdt->ComputeVtables(cache);
  103. }
  104. cache[type] = tdt;
  105. return tdt;
  106. }
  107. inline bool IsOverrideMethod(const GenericClassMethod& m1, const GenericClassMethod& m2)
  108. {
  109. return hybridclr::metadata::IsOverrideMethod(m1.type, m1.method, m2.type, m2.method);
  110. }
  111. uint16_t FindLastSameMethod(std::vector<GenericClassMethod>& methods, uint32_t maxIdx, const GenericClassMethod& find, bool notSealed)
  112. {
  113. for (uint32_t i = std::min(maxIdx, (uint32_t)methods.size()); i > 0; i--)
  114. {
  115. uint32_t idx = i - 1;
  116. if (methods[idx].method == nullptr)
  117. {
  118. continue;
  119. }
  120. if (IsOverrideMethod(methods[idx], find))
  121. {
  122. return idx;
  123. }
  124. }
  125. return kInvalidIl2CppMethodSlot;
  126. }
  127. bool containeTdt(const std::vector<VTableSetUp*>& trees, VTableSetUp* findTree)
  128. {
  129. for (VTableSetUp* add : trees)
  130. {
  131. if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(add->GetType(), findTree->GetType()))
  132. {
  133. return true;
  134. }
  135. }
  136. return false;
  137. }
  138. bool FindType(const std::vector<RawInterfaceOffsetInfo>& interfaceOffsetInfos, const Il2CppType* type, uint16_t& resultIdx)
  139. {
  140. uint16_t idx = 0;
  141. for (auto& ioi : interfaceOffsetInfos)
  142. {
  143. if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(type, ioi.type))
  144. {
  145. resultIdx = idx;
  146. return true;
  147. }
  148. ++idx;
  149. }
  150. resultIdx = (uint16_t)-1;
  151. return false;
  152. }
  153. void VTableSetUp::ComputeInterfaceVtables(Il2CppType2TypeDeclaringTreeMap& cache)
  154. {
  155. IL2CPP_ASSERT(hybridclr::metadata::IsInterface(_typeDef->flags));
  156. if (IsInterType())
  157. {
  158. uint16_t slotIdx = 0;
  159. for (auto& vm : _virtualMethods)
  160. {
  161. Il2CppMethodDefinition* methodDef = const_cast<Il2CppMethodDefinition*>(vm.method);
  162. IL2CPP_ASSERT(methodDef->slot == slotIdx);
  163. slotIdx++;
  164. }
  165. }
  166. }
  167. void VTableSetUp::ComputeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
  168. {
  169. if (IsInterType())
  170. {
  171. ComputeInterpTypeVtables(cache);
  172. }
  173. else
  174. {
  175. ComputAotTypeVtables(cache);
  176. }
  177. uint16_t idx = 0;
  178. for (auto& vmi : _methodImpls)
  179. {
  180. IL2CPP_ASSERT(vmi.slot == idx);
  181. ++idx;
  182. }
  183. }
  184. const Il2CppType* VTableSetUp::FindImplType(const Il2CppMethodDefinition* methodDef)
  185. {
  186. Il2CppTypeDefinition* declarType = (Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(methodDef->declaringType);
  187. for (VTableSetUp* cur = this; cur; cur = cur->_parent)
  188. {
  189. if (declarType == cur->_typeDef)
  190. {
  191. return cur->_type;
  192. }
  193. for(VTableSetUp* itf : cur->_interfaces)
  194. {
  195. if (declarType == itf->_typeDef)
  196. {
  197. return itf->_type;
  198. }
  199. }
  200. }
  201. TEMP_FORMAT(errMsg, "VTableSetUp::FindImplType can't find impl type for method:%s.%s::%s",
  202. il2cpp::vm::GlobalMetadata::GetStringFromIndex(declarType->namespaceIndex),
  203. il2cpp::vm::GlobalMetadata::GetStringFromIndex(declarType->nameIndex),
  204. il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex)
  205. );
  206. RaiseExecutionEngineException(errMsg);
  207. return nullptr;
  208. }
  209. const VTableSetUp* VTableSetUp::FindAncestorTypeTree(const Il2CppType* implType)
  210. {
  211. for (VTableSetUp* cur = this; cur; cur = cur->_parent)
  212. {
  213. if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(cur->_type, implType))
  214. {
  215. return cur;
  216. }
  217. }
  218. return nullptr;
  219. }
  220. static void RaiseParentOverridedMethodNotFindException(const Il2CppType* type, const char* methodName)
  221. {
  222. if (!type)
  223. {
  224. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException("type not exists"));
  225. }
  226. const Il2CppTypeDefinition* typeDefinition = GetUnderlyingTypeDefinition(type);
  227. TEMP_FORMAT(errMsg, "VTableSetUp fail. virtual method: %s::%s::%s can't be find in declaring type or parent. It may be stripped by il2cpp",
  228. il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->namespaceIndex),
  229. il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->nameIndex),
  230. methodName);
  231. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingMethodException(errMsg));
  232. }
  233. const GenericClassMethod* VTableSetUp::FindImplMethod(const Il2CppType* containerType, const Il2CppMethodDefinition* methodDef, bool throwExceptionIfNotFind)
  234. {
  235. for (VTableSetUp* curTdt = this; curTdt; curTdt = curTdt->_parent)
  236. {
  237. for (int idx = (int)curTdt->_virtualMethods.size() - 1; idx >= 0; idx--)
  238. {
  239. GenericClassMethod& pvm = curTdt->_virtualMethods[idx];
  240. if (hybridclr::metadata::IsOverrideMethod(containerType, methodDef, pvm.type, pvm.method))
  241. {
  242. return &pvm;
  243. }
  244. }
  245. }
  246. if (throwExceptionIfNotFind)
  247. {
  248. RaiseParentOverridedMethodNotFindException(this->_type, il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex));
  249. }
  250. return nullptr;
  251. }
  252. void VTableSetUp::ComputAotTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
  253. {
  254. for (uint16_t i = 0; i < _typeDef->interface_offsets_count; i++)
  255. {
  256. Il2CppInterfaceOffsetInfo ioi = il2cpp::vm::GlobalMetadata::GetInterfaceOffsetInfo(_typeDef, i);
  257. _interfaceOffsetInfos.push_back({ ioi.interfaceType, BuildByType(cache, ioi.interfaceType), (uint16_t)ioi.offset });
  258. }
  259. int nullVtableSlotCount = 0;
  260. for (uint16_t i = 0; i < _typeDef->vtable_count; i++)
  261. {
  262. const Il2CppMethodDefinition* overideMethodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromVTableSlot(_typeDef, i);
  263. if (overideMethodDef == nullptr)
  264. {
  265. if (_parent && i < _parent->_typeDef->vtable_count)
  266. {
  267. IL2CPP_ASSERT(_parent->_methodImpls[i].method);
  268. _methodImpls.push_back(_parent->_methodImpls[i]);
  269. }
  270. else
  271. {
  272. _methodImpls.push_back({ nullptr, nullptr, i /*, nullptr*/});
  273. ++nullVtableSlotCount;
  274. }
  275. continue;
  276. }
  277. const Il2CppType* implType = FindImplType(overideMethodDef);
  278. const char* methodName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(overideMethodDef->nameIndex);
  279. uint16_t slot = i;
  280. _methodImpls.push_back({ overideMethodDef, implType, slot /*, methodName*/});
  281. }
  282. // il2cpp set vtable slot to nullptr if method is abstract, so we fill correct type and method
  283. if (nullVtableSlotCount > 0)
  284. {
  285. for (GenericClassMethod& gcm : _virtualMethods)
  286. {
  287. IL2CPP_ASSERT(gcm.method->slot != kInvalidIl2CppMethodSlot);
  288. VirtualMethodImpl& vmi = _methodImpls[gcm.method->slot];
  289. if (vmi.method == nullptr)
  290. {
  291. vmi.type = _type;
  292. vmi.method = gcm.method;
  293. //vmi.name = gcm.name;
  294. --nullVtableSlotCount;
  295. }
  296. }
  297. for (VTableSetUp* interf : _interfaces)
  298. {
  299. bool findInterf = false;
  300. for (RawInterfaceOffsetInfo& rioi : _interfaceOffsetInfos)
  301. {
  302. if (IsTypeEqual(interf->_type, rioi.type))
  303. {
  304. for (size_t i = 0; i < interf->_virtualMethods.size(); i++)
  305. {
  306. VirtualMethodImpl& vmi = _methodImpls[rioi.offset + i];
  307. if (vmi.method == nullptr)
  308. {
  309. GenericClassMethod& igcm = interf->_virtualMethods[i];
  310. const GenericClassMethod* implVirtualMethod = FindImplMethod(interf->_type, igcm.method);
  311. IL2CPP_ASSERT(implVirtualMethod);
  312. //vmi.name = igcm.name;
  313. vmi.type = implVirtualMethod->type;
  314. vmi.method = implVirtualMethod->method;
  315. --nullVtableSlotCount;
  316. }
  317. }
  318. findInterf = true;
  319. break;
  320. }
  321. }
  322. IL2CPP_ASSERT(findInterf);
  323. }
  324. IL2CPP_ASSERT(nullVtableSlotCount == 0);
  325. }
  326. IL2CPP_ASSERT(_typeDef->vtable_count == (uint16_t)_methodImpls.size());
  327. }
  328. void VTableSetUp::ApplyOverrideMethod(const GenericClassMethod* overrideParentMethod, const Il2CppMethodDefinition* overrideMethodDef, uint16_t checkOverrideMaxIdx)
  329. {
  330. IL2CPP_ASSERT(overrideParentMethod);
  331. if (overrideParentMethod)
  332. {
  333. IL2CPP_ASSERT(overrideParentMethod->method->slot != kInvalidIl2CppMethodSlot);
  334. //const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideParentMethod->method->slot;
  335. uint16_t slotIdx = overrideParentMethod->method->slot;
  336. const Il2CppMethodDefinition* overrideAncestorMethod = _parent->_methodImpls[slotIdx].method;
  337. IL2CPP_ASSERT(overrideAncestorMethod);
  338. VirtualMethodImpl& curImpl = _methodImpls[slotIdx];
  339. curImpl.type = _type;
  340. curImpl.method = overrideMethodDef;
  341. // search hierarchy methods, find match method.
  342. // check override parent virtual methods and
  343. for (uint16_t idx = 0; idx < checkOverrideMaxIdx; idx++)
  344. {
  345. VirtualMethodImpl& vmi = _methodImpls[idx];
  346. if (vmi.method == overrideAncestorMethod)
  347. {
  348. vmi.type = _type;
  349. vmi.method = overrideMethodDef;
  350. }
  351. }
  352. }
  353. }
  354. uint16_t VTableSetUp::FindDefaultOverrideExplicitInterfaceSlot(GenericClassMethod& gcm, const Uin16Set& explicitImplSlots, const std::vector<uint16_t>& implInterfaceOffsetIdxs)
  355. {
  356. uint16_t slot = kInvalidIl2CppMethodSlot;
  357. for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
  358. {
  359. RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
  360. for (uint16_t idx = rioi.offset, end = rioi.offset + (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
  361. {
  362. if (explicitImplSlots.find(idx) != explicitImplSlots.end())
  363. {
  364. continue;
  365. }
  366. VirtualMethodImpl& vmi = _methodImpls[idx];
  367. if (IsOverrideMethod(_type, gcm.method, vmi.type, vmi.method))
  368. {
  369. //IL2CPP_ASSERT(impl.body.methodDef->slot == kInvalidIl2CppMethodSlot);
  370. vmi.type = _type;
  371. vmi.method = gcm.method;
  372. slot = idx;
  373. }
  374. }
  375. }
  376. return slot;
  377. }
  378. uint16_t VTableSetUp::FindExplicitOverrideInterfaceSlot(GenericClassMethod& gcm, const Int32ToUin16Map& explicitImplSlots)
  379. {
  380. auto it = explicitImplSlots.find(gcm.method->token);
  381. return it != explicitImplSlots.end() ? it->second : kInvalidIl2CppMethodSlot;
  382. }
  383. void VTableSetUp::InitInterfaceVTable(uint16_t& curOffset, std::vector<uint16_t>& implInterfaceOffsetIdxs)
  384. {
  385. for (VTableSetUp* intTree : _interfaces)
  386. {
  387. const Il2CppType* intType = intTree->_type;
  388. uint16_t overrideIntIdx;
  389. if (!FindType(_parent->_interfaceOffsetInfos, intType, overrideIntIdx))
  390. {
  391. implInterfaceOffsetIdxs.push_back((uint16_t)_interfaceOffsetInfos.size());
  392. _interfaceOffsetInfos.push_back({ intType, intTree, curOffset });
  393. // curOffset += (uint32_t)intTree->_virtualMethods.size();
  394. for (auto& vm : intTree->_virtualMethods)
  395. {
  396. _methodImpls.push_back({ vm.method, intType, curOffset++ /*, vm.name*/});
  397. }
  398. }
  399. else
  400. {
  401. implInterfaceOffsetIdxs.push_back(overrideIntIdx);
  402. }
  403. }
  404. }
  405. static bool IsExpliciteMethodNameMatch(const char* implMethodName, const Il2CppType* targetDeclaringType, const char* targetMethodName)
  406. {
  407. // end with .<methodName>
  408. std::string fullName;
  409. const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(targetDeclaringType);
  410. if (typeDef->namespaceIndex != kStringLiteralIndexInvalid)
  411. {
  412. fullName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex);
  413. fullName += ".";
  414. }
  415. const char* typeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
  416. const char* genericQualifier = strchr(typeName, '`');
  417. if (genericQualifier)
  418. {
  419. fullName.append(typeName, genericQualifier);
  420. }
  421. else
  422. {
  423. fullName += typeName;
  424. }
  425. if (!std::strstr(implMethodName, fullName.c_str()))
  426. {
  427. return false;
  428. }
  429. size_t len1 = std::strlen(implMethodName);
  430. size_t len2 = std::strlen(targetMethodName);
  431. if (len1 < len2 + 1)
  432. {
  433. return false;
  434. }
  435. if (implMethodName[len1 - len2 - 1] != '.')
  436. {
  437. return false;
  438. }
  439. return strcmp(implMethodName + len1 - len2, targetMethodName) == 0;
  440. }
  441. void VTableSetUp::ApplyAOTInterfaceExplicitOverride(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots,
  442. const Il2CppType* intfType, const Il2CppType* implType, const Il2CppMethodDefinition* implMethod)
  443. {
  444. const char* name1 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
  445. for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
  446. {
  447. RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
  448. if (!il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(rioi.type, intfType))
  449. {
  450. continue;
  451. }
  452. for (uint16_t idx = 0, end = (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
  453. {
  454. GenericClassMethod& rvm = rioi.tree->_virtualMethods[idx];
  455. const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
  456. if (!IsExpliciteMethodNameMatch(name1, intfType, name2))
  457. {
  458. continue;
  459. }
  460. if (IsOverrideMethodIgnoreName(implType, implMethod, rvm.type, rvm.method))
  461. {
  462. uint16_t slot = (uint16_t)(idx + rioi.offset);
  463. VirtualMethodImpl& ivmi = _methodImpls[slot];
  464. _explicitImplSlots.insert(slot);
  465. explicitImplToken2Slots.insert({ implMethod->token, slot });
  466. ivmi.type = implType;
  467. ivmi.method = implMethod;
  468. //ivmi.name = name1;
  469. return;
  470. }
  471. }
  472. }
  473. }
  474. void VTableSetUp::ApplyExplicitOverride(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots,
  475. const Il2CppType* declaringType, const Il2CppMethodDefinition* decalringMethod, const Il2CppType* implType, const Il2CppMethodDefinition* implMethod)
  476. {
  477. const char* name1 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(decalringMethod->nameIndex);
  478. for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
  479. {
  480. RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
  481. if (!il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(rioi.type, declaringType))
  482. {
  483. continue;
  484. }
  485. for (uint16_t idx = 0, end = (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
  486. {
  487. GenericClassMethod& rvm = rioi.tree->_virtualMethods[idx];
  488. const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
  489. if (std::strcmp(name1, name2))
  490. {
  491. continue;
  492. }
  493. if (IsOverrideMethodIgnoreName(declaringType, decalringMethod, rvm.type, rvm.method))
  494. {
  495. uint16_t slot = (uint16_t)(idx + rioi.offset);
  496. VirtualMethodImpl& ivmi = _methodImpls[slot];
  497. _explicitImplSlots.insert(slot);
  498. explicitImplToken2Slots.insert({ implMethod->token, slot});
  499. ivmi.type = implType;
  500. ivmi.method = implMethod;
  501. //ivmi.name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
  502. return;
  503. }
  504. }
  505. }
  506. const VTableSetUp* containerTs = FindAncestorTypeTree(declaringType);
  507. if (containerTs)
  508. {
  509. for (int idx = (int)containerTs->_virtualMethods.size() - 1; idx >= 0; idx--)
  510. {
  511. const GenericClassMethod& rvm = containerTs->_virtualMethods[idx];
  512. const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
  513. if (std::strcmp(name1, name2) != 0)
  514. {
  515. continue;
  516. }
  517. if (IsOverrideMethodIgnoreName(declaringType, decalringMethod, rvm.type, rvm.method))
  518. {
  519. VirtualMethodImpl& ivmi = _methodImpls[rvm.method->slot];
  520. _explicitImplSlots.insert(rvm.method->slot);
  521. explicitImplToken2Slots.insert({ implMethod->token, rvm.method->slot });
  522. ivmi.type = implType;
  523. ivmi.method = implMethod;
  524. //ivmi.name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
  525. return;
  526. }
  527. }
  528. }
  529. const Il2CppTypeDefinition* typeDefinition = GetUnderlyingTypeDefinition(declaringType);
  530. TEMP_FORMAT(errMsg, "VTableSetUp fail. explicit implemented method: %s::%s::%s can't be find in parent or any interface.",
  531. il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->namespaceIndex),
  532. il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->nameIndex),
  533. name1);
  534. il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
  535. }
  536. void VTableSetUp::ApplyTypeExplicitImpls(const Il2CppType* type, const VTableSetUp* tree, const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
  537. {
  538. const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
  539. if (IsInterpreterType(typeDef))
  540. {
  541. const il2cpp::utils::dynamic_array<MethodImpl> explicitImpls = MetadataModule::GetImage(typeDef)->GetTypeMethodImplByTypeDefinition(typeDef);
  542. if (type->type != IL2CPP_TYPE_GENERICINST)
  543. {
  544. for (const MethodImpl& mi : explicitImpls)
  545. {
  546. ApplyExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, mi.declaration.containerType,
  547. mi.declaration.methodDef, mi.body.containerType, mi.body.methodDef);
  548. }
  549. }
  550. else
  551. {
  552. const Il2CppGenericClass* genericClass = type->data.generic_class;
  553. for (const MethodImpl& mi : explicitImpls)
  554. {
  555. const Il2CppType* containerType = il2cpp::metadata::GenericMetadata::InflateIfNeeded(mi.declaration.containerType, &genericClass->context, true);
  556. const Il2CppType* implType = TryInflateIfNeed(type, type->data.generic_class->type, mi.body.containerType);
  557. ApplyExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, containerType,
  558. mi.declaration.methodDef, implType, mi.body.methodDef);
  559. }
  560. }
  561. }
  562. else if (IsInterface(typeDef->flags))
  563. {
  564. // we only need process explicit impls in interface.
  565. // il2cpp doesn't provider any ways to get explicit impls in class.
  566. // so we can only try to find explicit impls by name matching.
  567. for (const GenericClassMethod& gcm : tree->_virtualMethods)
  568. {
  569. // only try to find explicit impls in private methods
  570. uint32_t flags = gcm.method->flags;
  571. if (!IsPrivateMethod(flags) || IsAbstractMethod(flags))
  572. {
  573. continue;
  574. }
  575. for (VTableSetUp* subIntf : tree->_interfaces)
  576. {
  577. ApplyAOTInterfaceExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, subIntf->_type, tree->_type, gcm.method);
  578. }
  579. }
  580. }
  581. }
  582. void VTableSetUp::ComputeExplicitImpls(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
  583. {
  584. ApplyTypeExplicitImpls(_type, this, implInterfaceOffsetIdxs, explicitImplToken2Slots);
  585. for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
  586. {
  587. RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
  588. ApplyTypeExplicitImpls(rioi.type, rioi.tree, implInterfaceOffsetIdxs, explicitImplToken2Slots);
  589. }
  590. }
  591. void VTableSetUp::ComputeOverrideParentVirtualMethod(uint16_t& curOffset, const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
  592. {
  593. const uint16_t startOffset = curOffset;
  594. // override parent virtual methods and interfaces
  595. for (auto& vm : _virtualMethods)
  596. {
  597. IL2CPP_ASSERT(vm.type == _type);
  598. uint16_t mflags = vm.method->flags;
  599. if (hybridclr::metadata::IsNewSlot(mflags))
  600. {
  601. uint16_t overrideSlotIdx = kInvalidIl2CppMethodSlot;
  602. if (IsSealed(mflags))
  603. {
  604. overrideSlotIdx = FindExplicitOverrideInterfaceSlot(vm, explicitImplToken2Slots);
  605. if (overrideSlotIdx == kInvalidIl2CppMethodSlot && IsPublicMethod(mflags))
  606. {
  607. overrideSlotIdx = FindDefaultOverrideExplicitInterfaceSlot(vm, _explicitImplSlots, implInterfaceOffsetIdxs);
  608. }
  609. }
  610. if (overrideSlotIdx != kInvalidIl2CppMethodSlot)
  611. {
  612. const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideSlotIdx;
  613. }
  614. else
  615. {
  616. _methodImpls.push_back({ vm.method, _type, curOffset /*, vm.name*/});
  617. IL2CPP_ASSERT(vm.method->slot == kInvalidIl2CppMethodSlot || vm.method->slot == curOffset);
  618. const_cast<Il2CppMethodDefinition*>(vm.method)->slot = curOffset;
  619. ++curOffset;
  620. }
  621. }
  622. else
  623. {
  624. // It's impossible to define private virtual method in c#,but it's possible in cli.
  625. // so sometime can't find override in parent
  626. const GenericClassMethod* overrideParentMethod = _parent->FindImplMethod(_type, vm.method, false);
  627. if (overrideParentMethod)
  628. {
  629. IL2CPP_ASSERT(overrideParentMethod->method->slot != kInvalidIl2CppMethodSlot);
  630. const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideParentMethod->method->slot;
  631. ApplyOverrideMethod(overrideParentMethod, vm.method, startOffset);
  632. }
  633. else
  634. {
  635. IL2CPP_ASSERT(metadata::IsPrivateMethod(mflags));
  636. _methodImpls.push_back({ vm.method, _type, curOffset /*, vm.name*/});
  637. IL2CPP_ASSERT(vm.method->slot == kInvalidIl2CppMethodSlot || vm.method->slot == curOffset);
  638. const_cast<Il2CppMethodDefinition*>(vm.method)->slot = curOffset;
  639. ++curOffset;
  640. }
  641. }
  642. }
  643. }
  644. void VTableSetUp::ComputeInterfaceOverrideByParentVirtualMethod(const std::vector<uint16_t>& implInterfaceOffsetIdxs)
  645. {
  646. for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
  647. {
  648. RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
  649. for (uint16_t idx = rioi.offset, end = rioi.offset + (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
  650. {
  651. if (isExplicitImplInterfaceSlot(idx))
  652. {
  653. continue;
  654. }
  655. VirtualMethodImpl& vmi = _methodImpls[idx];
  656. // override by virtual method
  657. const GenericClassMethod* implVm = FindImplMethod(vmi.type, vmi.method, false);
  658. if (implVm)
  659. {
  660. vmi.type = implVm->type;
  661. vmi.method = implVm->method;
  662. //vmi.name = implVm->name;
  663. }
  664. }
  665. }
  666. }
  667. void VTableSetUp::ComputeInterpTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
  668. {
  669. uint16_t curOffset = 0;
  670. if (_parent)
  671. {
  672. curOffset = (uint16_t)_parent->_methodImpls.size();
  673. _methodImpls = _parent->_methodImpls;
  674. _interfaceOffsetInfos = _parent->_interfaceOffsetInfos;
  675. }
  676. std::vector<uint16_t> implInterfaceOffsetIdxs;
  677. InitInterfaceVTable(curOffset, implInterfaceOffsetIdxs);
  678. Int32ToUin16Map explicitImplToken2Slots;
  679. ComputeExplicitImpls(implInterfaceOffsetIdxs, explicitImplToken2Slots);
  680. ComputeOverrideParentVirtualMethod(curOffset, implInterfaceOffsetIdxs, explicitImplToken2Slots);
  681. ComputeInterfaceOverrideByParentVirtualMethod(implInterfaceOffsetIdxs);
  682. }
  683. }
  684. }