WindowsRuntime.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. #include "il2cpp-config.h"
  2. #include "metadata/GenericMetadata.h"
  3. #include "os/LibraryLoader.h"
  4. #include "os/WindowsRuntime.h"
  5. #include "utils/StringUtils.h"
  6. #include "utils/StringViewUtils.h"
  7. #include "vm/AssemblyName.h"
  8. #include "vm/Class.h"
  9. #include "vm/Exception.h"
  10. #include "vm/GenericClass.h"
  11. #include "vm/Il2CppHStringReference.h"
  12. #include "vm/Image.h"
  13. #include "vm/MetadataCache.h"
  14. #include "vm/Type.h"
  15. #include "vm/WindowsRuntime.h"
  16. namespace il2cpp
  17. {
  18. namespace vm
  19. {
  20. const char kArrayTypePrefixUtf8[] = "Windows.Foundation.IReferenceArray`1<";
  21. const Il2CppNativeChar kArrayTypePrefix[] = IL2CPP_NATIVE_STRING("Windows.Foundation.IReferenceArray`1<");
  22. const Il2CppNativeChar kIReferencePrefix[] = IL2CPP_NATIVE_STRING("Windows.Foundation.IReference`1<");
  23. const Il2CppNativeChar kArrayTypeOrIReferencePrefix[] = IL2CPP_NATIVE_STRING("Windows.Foundation.IReference");
  24. const Il2CppNativeChar kArrayTypePostprefix[] = IL2CPP_NATIVE_STRING("Array`1<");
  25. const Il2CppNativeChar kIReferencePostprefix[] = IL2CPP_NATIVE_STRING("`1<");
  26. Il2CppIActivationFactory* WindowsRuntime::GetActivationFactory(const utils::StringView<Il2CppNativeChar>& runtimeClassName)
  27. {
  28. Il2CppHStringReference className(runtimeClassName);
  29. Il2CppIActivationFactory* factory = NULL;
  30. il2cpp_hresult_t hr = os::WindowsRuntime::GetActivationFactory(className, &factory);
  31. if (IL2CPP_HR_SUCCEEDED(hr))
  32. return factory;
  33. if (hr != IL2CPP_REGDB_E_CLASSNOTREG)
  34. Exception::Raise(hr, false);
  35. // If GetActivationFactory doesn't find the class, we can still try to find it manually
  36. // All Windows runtime classes must be in namespaces, and that class has to be in a DLL
  37. // that is named after the namespace of a part of it.
  38. // For example, MyNamespace.MySubNamespace.MyClass can be in either
  39. // MyNamespace.MySubNamespace.dll or MyNamespace.dll
  40. IL2CPP_ASSERT(runtimeClassName.Length() > 1);
  41. size_t namespaceEnd = runtimeClassName.Length() - 1;
  42. do
  43. {
  44. namespaceEnd--;
  45. }
  46. while (namespaceEnd > 0 && runtimeClassName[namespaceEnd] != '.');
  47. Il2CppNativeChar* nativeDll = static_cast<Il2CppNativeChar*>(alloca((namespaceEnd + 5) * sizeof(Il2CppNativeChar)));
  48. memcpy(nativeDll, runtimeClassName.Str(), namespaceEnd * sizeof(Il2CppNativeChar));
  49. std::string detailedError;
  50. while (namespaceEnd > 0)
  51. {
  52. memcpy(nativeDll + namespaceEnd, IL2CPP_NATIVE_STRING(".dll"), 4 * sizeof(Il2CppNativeChar));
  53. nativeDll[namespaceEnd + 4] = 0;
  54. Baselib_DynamicLibrary_Handle dynamicLibrary = os::LibraryLoader::LoadDynamicLibrary(utils::StringView<Il2CppNativeChar>(nativeDll, namespaceEnd + 4), detailedError);
  55. if (dynamicLibrary != Baselib_DynamicLibrary_Handle_Invalid)
  56. {
  57. typedef il2cpp_hresult_t(STDCALL * DllGetActivationFactory)(Il2CppHString activatableClassId, Il2CppIActivationFactory** factory);
  58. DllGetActivationFactory dllGetActivationFactory = reinterpret_cast<DllGetActivationFactory>(os::LibraryLoader::GetFunctionPointer(dynamicLibrary, "DllGetActivationFactory", detailedError));
  59. if (dllGetActivationFactory != NULL)
  60. {
  61. hr = dllGetActivationFactory(className, &factory);
  62. if (IL2CPP_HR_SUCCEEDED(hr))
  63. return factory;
  64. if (hr != IL2CPP_REGDB_E_CLASSNOTREG)
  65. Exception::Raise(hr, false);
  66. }
  67. }
  68. do
  69. {
  70. namespaceEnd--;
  71. }
  72. while (namespaceEnd > 0 && runtimeClassName[namespaceEnd] != '.');
  73. }
  74. Exception::Raise(IL2CPP_REGDB_E_CLASSNOTREG, false);
  75. return NULL;
  76. }
  77. static bool IsWindowsRuntimePrimitiveType(const Il2CppType* type, Il2CppClass*& outCachedNonPrimitiveClass)
  78. {
  79. if (type == NULL)
  80. return false;
  81. switch (type->type)
  82. {
  83. case IL2CPP_TYPE_BOOLEAN:
  84. case IL2CPP_TYPE_CHAR:
  85. case IL2CPP_TYPE_U1:
  86. case IL2CPP_TYPE_I2:
  87. case IL2CPP_TYPE_U2:
  88. case IL2CPP_TYPE_I4:
  89. case IL2CPP_TYPE_U4:
  90. case IL2CPP_TYPE_I8:
  91. case IL2CPP_TYPE_U8:
  92. case IL2CPP_TYPE_R4:
  93. case IL2CPP_TYPE_R8:
  94. case IL2CPP_TYPE_OBJECT:
  95. case IL2CPP_TYPE_STRING:
  96. return true;
  97. default:
  98. break;
  99. }
  100. Il2CppClass* klass = Class::FromIl2CppType(type);
  101. if (klass == il2cpp_defaults.system_guid_class)
  102. return true;
  103. outCachedNonPrimitiveClass = klass;
  104. return false;
  105. }
  106. static Il2CppWindowsRuntimeTypeKind GetWindowsRuntimeTypeKind(const Il2CppType* type, Il2CppClass*& outCachedNonPrimitiveClass)
  107. {
  108. if (type == NULL)
  109. return kTypeKindCustom;
  110. switch (type->type)
  111. {
  112. case IL2CPP_TYPE_BOOLEAN:
  113. case IL2CPP_TYPE_CHAR:
  114. case IL2CPP_TYPE_U1:
  115. case IL2CPP_TYPE_I2:
  116. case IL2CPP_TYPE_U2:
  117. case IL2CPP_TYPE_I4:
  118. case IL2CPP_TYPE_U4:
  119. case IL2CPP_TYPE_I8:
  120. case IL2CPP_TYPE_U8:
  121. case IL2CPP_TYPE_R4:
  122. case IL2CPP_TYPE_R8:
  123. case IL2CPP_TYPE_OBJECT:
  124. case IL2CPP_TYPE_STRING:
  125. return kTypeKindPrimitive;
  126. default:
  127. break;
  128. }
  129. Il2CppClass* klass = Class::FromIl2CppType(type);
  130. if (klass == il2cpp_defaults.system_guid_class)
  131. return kTypeKindPrimitive;
  132. outCachedNonPrimitiveClass = klass;
  133. if (klass->rank > 0)
  134. {
  135. Il2CppClass* cachedElementClass;
  136. if (GetWindowsRuntimeTypeKind(&klass->element_class->byval_arg, cachedElementClass) != kTypeKindCustom)
  137. return kTypeKindMetadata;
  138. }
  139. else
  140. {
  141. const char* windowsRuntimeTypeName = MetadataCache::GetWindowsRuntimeClassName(klass);
  142. if (windowsRuntimeTypeName != NULL)
  143. return kTypeKindMetadata;
  144. if (strcmp(klass->image->name, "WindowsRuntimeMetadata") == 0)
  145. {
  146. Il2CppGenericClass* genericClass = klass->generic_class;
  147. if (genericClass == NULL)
  148. return kTypeKindMetadata;
  149. const Il2CppGenericInst* classInst = genericClass->context.class_inst;
  150. IL2CPP_ASSERT(classInst != NULL);
  151. uint32_t genericArgumentCount = classInst->type_argc;
  152. for (uint32_t i = 0; i < genericArgumentCount; i++)
  153. {
  154. Il2CppClass* cachedGenericArgumentClass;
  155. if (GetWindowsRuntimeTypeKind(classInst->type_argv[i], cachedGenericArgumentClass) == kTypeKindCustom)
  156. return kTypeKindCustom;
  157. }
  158. return kTypeKindMetadata;
  159. }
  160. }
  161. return kTypeKindCustom;
  162. }
  163. static utils::StringView<Il2CppNativeChar> GetWindowsRuntimePrimitiveTypeName(const Il2CppType* type)
  164. {
  165. switch (type->type)
  166. {
  167. case IL2CPP_TYPE_BOOLEAN:
  168. return IL2CPP_NATIVE_STRING("Boolean");
  169. case IL2CPP_TYPE_CHAR:
  170. return IL2CPP_NATIVE_STRING("Char16");
  171. case IL2CPP_TYPE_U1:
  172. return IL2CPP_NATIVE_STRING("UInt8");
  173. case IL2CPP_TYPE_I2:
  174. return IL2CPP_NATIVE_STRING("Int16");
  175. case IL2CPP_TYPE_U2:
  176. return IL2CPP_NATIVE_STRING("UInt16");
  177. case IL2CPP_TYPE_I4:
  178. return IL2CPP_NATIVE_STRING("Int32");
  179. case IL2CPP_TYPE_U4:
  180. return IL2CPP_NATIVE_STRING("UInt32");
  181. case IL2CPP_TYPE_I8:
  182. return IL2CPP_NATIVE_STRING("Int64");
  183. case IL2CPP_TYPE_U8:
  184. return IL2CPP_NATIVE_STRING("UInt64");
  185. case IL2CPP_TYPE_R4:
  186. return IL2CPP_NATIVE_STRING("Single");
  187. case IL2CPP_TYPE_R8:
  188. return IL2CPP_NATIVE_STRING("Double");
  189. case IL2CPP_TYPE_OBJECT:
  190. return IL2CPP_NATIVE_STRING("Object");
  191. case IL2CPP_TYPE_STRING:
  192. return IL2CPP_NATIVE_STRING("String");
  193. case IL2CPP_TYPE_VALUETYPE:
  194. return IL2CPP_NATIVE_STRING("Guid");
  195. default:
  196. IL2CPP_UNREACHABLE;
  197. return IL2CPP_NATIVE_STRING("");
  198. }
  199. }
  200. // This is code duplication... but there isn't a better name to achieve good performance for both primitive and metadata types otherwise
  201. static utils::StringView<char> GetWindowsRuntimePrimitiveTypeNameUtf8(const Il2CppType* type)
  202. {
  203. switch (type->type)
  204. {
  205. case IL2CPP_TYPE_BOOLEAN:
  206. return "Boolean";
  207. case IL2CPP_TYPE_CHAR:
  208. return "Char16";
  209. case IL2CPP_TYPE_U1:
  210. return "UInt8";
  211. case IL2CPP_TYPE_I2:
  212. return "Int16";
  213. case IL2CPP_TYPE_U2:
  214. return "UInt16";
  215. case IL2CPP_TYPE_I4:
  216. return "Int32";
  217. case IL2CPP_TYPE_U4:
  218. return "UInt32";
  219. case IL2CPP_TYPE_I8:
  220. return "Int64";
  221. case IL2CPP_TYPE_U8:
  222. return "UInt64";
  223. case IL2CPP_TYPE_R4:
  224. return "Single";
  225. case IL2CPP_TYPE_R8:
  226. return "Double";
  227. case IL2CPP_TYPE_OBJECT:
  228. return "Object";
  229. case IL2CPP_TYPE_STRING:
  230. return "String";
  231. case IL2CPP_TYPE_VALUETYPE:
  232. return "Guid";
  233. default:
  234. IL2CPP_UNREACHABLE;
  235. return "";
  236. }
  237. }
  238. static std::string GetWindowsRuntimeTypeNameFromWinmdReference(Il2CppClass* klass);
  239. static std::string GetWindowsRuntimeMetadataTypeNameUtf8(Il2CppClass* klass)
  240. {
  241. if (klass->rank > 0)
  242. {
  243. std::string typeName, elementMetadataTypeName;
  244. const Il2CppType* elementType = &klass->element_class->byval_arg;
  245. Il2CppClass* elementClass = NULL;
  246. bool elementIsPrimitive = IsWindowsRuntimePrimitiveType(elementType, elementClass);
  247. utils::StringView<char> elementTypeName(utils::StringView<char>::Empty());
  248. // Optimization: time spent in GetWindowsRuntimeMetadataTypeName is dominated by string allocations,
  249. // so try to reserve needed space on a string in advance.
  250. if (elementIsPrimitive)
  251. {
  252. elementTypeName = GetWindowsRuntimePrimitiveTypeNameUtf8(elementType);
  253. }
  254. else
  255. {
  256. elementMetadataTypeName = GetWindowsRuntimeMetadataTypeNameUtf8(elementClass);
  257. elementTypeName = STRING_TO_STRINGVIEW(elementMetadataTypeName);
  258. }
  259. size_t spaceRequired = IL2CPP_ARRAY_SIZE(kArrayTypePrefixUtf8) + elementTypeName.Length() + 1 /* '>' */ - 1 /* minus null terminator from IL2CPP_ARRAY_SIZE */;
  260. typeName.reserve(spaceRequired);
  261. typeName.append(kArrayTypePrefixUtf8);
  262. typeName.append(elementTypeName.Str(), elementTypeName.Length());
  263. typeName.push_back('>');
  264. return typeName;
  265. }
  266. const char* windowsRuntimeTypeName = MetadataCache::GetWindowsRuntimeClassName(klass);
  267. if (windowsRuntimeTypeName != NULL)
  268. return windowsRuntimeTypeName;
  269. return GetWindowsRuntimeTypeNameFromWinmdReference(klass);
  270. }
  271. static std::string GetWindowsRuntimeTypeNameFromWinmdReference(Il2CppClass* klass)
  272. {
  273. IL2CPP_ASSERT(strcmp(klass->image->name, "WindowsRuntimeMetadata") == 0 && "Windows Runtime type kind was Metadata but it did not come from a Windows Runtime component.");
  274. std::string typeName;
  275. size_t namespaceLength = strlen(klass->namespaze);
  276. size_t nameLength = strlen(klass->name);
  277. typeName.reserve(namespaceLength + 1 + nameLength);
  278. typeName.append(klass->namespaze, namespaceLength);
  279. typeName.push_back('.');
  280. typeName.append(klass->name, nameLength);
  281. Il2CppGenericClass* genericClass = klass->generic_class;
  282. if (genericClass == NULL)
  283. return typeName;
  284. const Il2CppGenericInst* classInst = genericClass->context.class_inst;
  285. IL2CPP_ASSERT(classInst != NULL);
  286. typeName += '<';
  287. uint32_t genericArgumentCount = classInst->type_argc;
  288. for (uint32_t i = 0; i < genericArgumentCount; i++)
  289. {
  290. if (i != 0)
  291. typeName += ',';
  292. const Il2CppType* genericArgumentType = classInst->type_argv[i];
  293. Il2CppClass* genericArgumentClass = NULL;
  294. if (IsWindowsRuntimePrimitiveType(genericArgumentType, genericArgumentClass))
  295. {
  296. utils::StringView<char> primitiveTypeName = GetWindowsRuntimePrimitiveTypeNameUtf8(genericArgumentType);
  297. typeName.append(primitiveTypeName.Str(), primitiveTypeName.Length());
  298. }
  299. else
  300. {
  301. // Windows Runtime metadata types can't have generic arguments of Custom type, thus the argument is metadata type too
  302. typeName += GetWindowsRuntimeMetadataTypeNameUtf8(genericArgumentClass);
  303. }
  304. }
  305. typeName += '>';
  306. return typeName;
  307. }
  308. static Il2CppHString GetWindowsRuntimeMetadataTypeName(Il2CppClass* klass)
  309. {
  310. // Optimization: for type arrays we can construct native string in place and avoid extra UTF8 -> UTF16 conversion
  311. // This makes type name retrieval 4 times faster!
  312. if (klass->rank > 0)
  313. {
  314. const Il2CppType* elementType = &klass->element_class->byval_arg;
  315. Il2CppClass* elementClass = NULL;
  316. utils::StringView<Il2CppNativeChar> elementTypeName(utils::StringView<Il2CppNativeChar>::Empty());
  317. Il2CppHString elementMetadataTypeName = NULL;
  318. bool isElementTypePrimitive = IsWindowsRuntimePrimitiveType(elementType, elementClass);
  319. if (isElementTypePrimitive)
  320. {
  321. elementTypeName = GetWindowsRuntimePrimitiveTypeName(elementType);
  322. }
  323. else
  324. {
  325. elementMetadataTypeName = GetWindowsRuntimeMetadataTypeName(elementClass);
  326. uint32_t elementTypeNameLength;
  327. auto elementMetadataTypeNamePtr = os::WindowsRuntime::GetNativeHStringBuffer(elementMetadataTypeName, &elementTypeNameLength);
  328. vm::Exception::RaiseIfError(elementMetadataTypeNamePtr.GetError());
  329. elementTypeName = utils::StringView<Il2CppNativeChar>(elementMetadataTypeNamePtr.Get(), elementTypeNameLength);
  330. }
  331. size_t offsetInChars = 0;
  332. size_t spaceRequired = IL2CPP_ARRAY_SIZE(kArrayTypePrefix) + elementTypeName.Length() + 1 /* '>' */ - 1 /* minus null terminator from IL2CPP_ARRAY_SIZE */;
  333. Il2CppNativeChar* buffer;
  334. void* hstringBufferHandle = WindowsRuntime::PreallocateHStringBuffer(static_cast<uint32_t>(spaceRequired), &buffer);
  335. memcpy(buffer, kArrayTypePrefix, sizeof(kArrayTypePrefix) - sizeof(Il2CppNativeChar));
  336. offsetInChars += IL2CPP_ARRAY_SIZE(kArrayTypePrefix) - 1;
  337. memcpy(buffer + offsetInChars, elementTypeName.Str(), elementTypeName.Length() * sizeof(Il2CppNativeChar));
  338. offsetInChars += elementTypeName.Length();
  339. buffer[offsetInChars] = static_cast<Il2CppNativeChar>('>');
  340. if (!isElementTypePrimitive)
  341. WindowsRuntime::DeleteHString(elementMetadataTypeName);
  342. return WindowsRuntime::PromoteHStringBuffer(hstringBufferHandle);
  343. }
  344. // Note: don't put 'windowsRuntimeTypeName' into an std::string to save an allocation
  345. const char* windowsRuntimeTypeName = MetadataCache::GetWindowsRuntimeClassName(klass);
  346. if (windowsRuntimeTypeName != NULL)
  347. {
  348. Il2CppNativeString typeName = utils::StringUtils::Utf8ToNativeString(windowsRuntimeTypeName);
  349. return WindowsRuntime::CreateHString(STRING_TO_STRINGVIEW(typeName));
  350. }
  351. std::string typeNameUtf8 = GetWindowsRuntimeTypeNameFromWinmdReference(klass);
  352. Il2CppNativeString typeName = utils::StringUtils::Utf8ToNativeString(typeNameUtf8);
  353. return WindowsRuntime::CreateHString(STRING_TO_STRINGVIEW(typeName));
  354. }
  355. static Il2CppHString GetWindowsRuntimeCustomTypeName(const Il2CppType* type)
  356. {
  357. std::string typeNameUtf8 = Type::GetName(type, IL2CPP_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
  358. Il2CppNativeString typeName = utils::StringUtils::Utf8ToNativeString(typeNameUtf8);
  359. return WindowsRuntime::CreateHString(STRING_TO_STRINGVIEW(typeName));
  360. }
  361. void WindowsRuntime::MarshalTypeToNative(const Il2CppType* type, Il2CppWindowsRuntimeTypeName& nativeType)
  362. {
  363. if (type == NULL)
  364. {
  365. nativeType.typeKind = kTypeKindCustom;
  366. nativeType.typeName = NULL;
  367. return;
  368. }
  369. Il2CppClass* cachedClass = NULL;
  370. nativeType.typeKind = GetWindowsRuntimeTypeKind(type, cachedClass);
  371. switch (nativeType.typeKind)
  372. {
  373. case kTypeKindPrimitive:
  374. nativeType.typeName = CreateHString(GetWindowsRuntimePrimitiveTypeName(type));
  375. break;
  376. case kTypeKindMetadata:
  377. nativeType.typeName = GetWindowsRuntimeMetadataTypeName(cachedClass);
  378. break;
  379. case kTypeKindCustom:
  380. nativeType.typeName = GetWindowsRuntimeCustomTypeName(type);
  381. break;
  382. default:
  383. IL2CPP_UNREACHABLE;
  384. }
  385. }
  386. static REAL_NORETURN IL2CPP_NO_INLINE void ThrowUnexpectedTypeKindException()
  387. {
  388. const char kMessage[] = "Unexpected TypeKind when marshaling Windows.Foundation.TypeName. ";
  389. Il2CppException* exception = Exception::GetArgumentException("", kMessage);
  390. Exception::Raise(exception);
  391. IL2CPP_UNREACHABLE;
  392. }
  393. static REAL_NORETURN IL2CPP_NO_INLINE void ThrowWindowsRuntimeTypeNotFoundException(utils::StringView<Il2CppNativeChar> typeName)
  394. {
  395. std::string typeNameUtf8 = utils::StringUtils::NativeStringToUtf8(typeName.Str(), static_cast<uint32_t>(typeName.Length()));
  396. Il2CppException* typeLoadException = Exception::GetTypeLoadExceptionForWindowsRuntimeType(utils::StringView<char>::Empty(), STRING_TO_STRINGVIEW(typeNameUtf8));
  397. Exception::Raise(typeLoadException);
  398. IL2CPP_UNREACHABLE;
  399. }
  400. static Il2CppClass* GetClassFromPrimitiveTypeName(utils::StringView<Il2CppNativeChar> typeName, bool throwOnFailure);
  401. static Il2CppClass* GetClassFromMetadataTypeName(utils::StringView<Il2CppNativeChar> typeName, bool throwOnFailure);
  402. static inline Il2CppClass* GetClassFromPrimitiveOrMetadataTypeName(utils::StringView<Il2CppNativeChar> typeName, bool throwOnFailure)
  403. {
  404. // Try finding type as primitive type first
  405. // If that fails, try finding it as metadata type
  406. Il2CppClass* klass = GetClassFromPrimitiveTypeName(typeName, throwOnFailure);
  407. if (klass != NULL)
  408. return klass;
  409. return GetClassFromMetadataTypeName(typeName, throwOnFailure);
  410. }
  411. static Il2CppClass* GetClassFromPrimitiveTypeName(utils::StringView<Il2CppNativeChar> typeName, bool throwOnFailure)
  412. {
  413. uint32_t characterSum = 0;
  414. for (uint32_t i = 0; i < typeName.Length(); i++)
  415. characterSum += typeName[i];
  416. // Nothing like an (almost) perfect hash function. Thanks for the idea, @andrei!
  417. switch (characterSum)
  418. {
  419. case 393:
  420. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Guid")))
  421. return il2cpp_defaults.system_guid_class;
  422. break;
  423. case 400:
  424. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Int32")))
  425. return il2cpp_defaults.int32_class;
  426. break;
  427. case 402:
  428. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Int16")))
  429. return il2cpp_defaults.int16_class;
  430. break;
  431. case 405:
  432. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Int64")))
  433. return il2cpp_defaults.int64_class;
  434. break;
  435. case 440:
  436. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("UInt8")))
  437. return il2cpp_defaults.byte_class;
  438. break;
  439. case 485:
  440. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Char16")))
  441. return il2cpp_defaults.char_class;
  442. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("UInt32")))
  443. return il2cpp_defaults.uint32_class;
  444. break;
  445. case 487:
  446. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("UInt16")))
  447. return il2cpp_defaults.uint16_class;
  448. break;
  449. case 490:
  450. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("UInt64")))
  451. return il2cpp_defaults.uint64_class;
  452. break;
  453. case 599:
  454. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Object")))
  455. return il2cpp_defaults.object_class;
  456. break;
  457. case 603:
  458. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Double")))
  459. return il2cpp_defaults.double_class;
  460. break;
  461. case 610:
  462. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Single")))
  463. return il2cpp_defaults.single_class;
  464. break;
  465. case 631:
  466. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("String")))
  467. return il2cpp_defaults.string_class;
  468. break;
  469. case 704:
  470. if (utils::StringUtils::Equals(typeName, IL2CPP_NATIVE_STRING("Boolean")))
  471. return il2cpp_defaults.boolean_class;
  472. break;
  473. }
  474. if (throwOnFailure)
  475. {
  476. // Is this actually a metadata type? If so, throw unexpected type kind exception
  477. if (GetClassFromMetadataTypeName(typeName, false) != NULL)
  478. ThrowUnexpectedTypeKindException();
  479. ThrowWindowsRuntimeTypeNotFoundException(typeName);
  480. }
  481. return NULL;
  482. }
  483. static Il2CppClass* GetGenericInstanceClassFromMetadataTypeName(utils::StringView<Il2CppNativeChar> typeName)
  484. {
  485. IL2CPP_ASSERT(typeName[typeName.Length() - 1] == '>');
  486. size_t backtickIndex = typeName.Find('`');
  487. if (backtickIndex == utils::StringView<Il2CppNativeChar>::NPos())
  488. return NULL;
  489. size_t genericArgumentStartIndex = typeName.Find('<', backtickIndex + 1);
  490. if (genericArgumentStartIndex == utils::StringView<Il2CppNativeChar>::NPos())
  491. return NULL;
  492. int genericArgumentCount;
  493. utils::StringView<Il2CppNativeChar> genericArgumentCountStr = typeName.SubStr(backtickIndex + 1, genericArgumentStartIndex - backtickIndex - 1);
  494. if (!genericArgumentCountStr.TryParseAsInt(genericArgumentCount) || genericArgumentCount < 1)
  495. return NULL;
  496. utils::StringView<Il2CppNativeChar> typeDefinitionName = typeName.SubStr(0, genericArgumentStartIndex);
  497. Il2CppClass* classDefinition = GetClassFromMetadataTypeName(typeDefinitionName, false);
  498. if (classDefinition == NULL || !classDefinition->is_generic)
  499. return NULL;
  500. const Il2CppType** genericArguments = (const Il2CppType**)alloca(genericArgumentCount * sizeof(const Il2CppType*));
  501. int genericDepth = 0;
  502. int genericArgumentsAdded = 0;
  503. const Il2CppNativeChar* genericArgumentsPtr = typeName.Str() + genericArgumentStartIndex + 1;
  504. const Il2CppNativeChar* currentGenericArgumentStart = genericArgumentsPtr;
  505. const Il2CppNativeChar* genericArgumentsEnd = typeName.Str() + typeName.Length() - 1;
  506. for (; genericArgumentsPtr <= genericArgumentsEnd; genericArgumentsPtr++)
  507. {
  508. Il2CppNativeChar currentChar = *genericArgumentsPtr;
  509. switch (currentChar)
  510. {
  511. case '<':
  512. genericDepth++;
  513. break;
  514. case '>':
  515. if (genericArgumentsPtr < genericArgumentsEnd)
  516. {
  517. genericDepth--;
  518. break;
  519. }
  520. // fallthrough
  521. case ',':
  522. {
  523. if (genericDepth == 0)
  524. {
  525. il2cpp::utils::StringView<Il2CppNativeChar> genericArgumentTypeName(currentGenericArgumentStart, genericArgumentsPtr - currentGenericArgumentStart);
  526. Il2CppClass* genericArgumentClass = GetClassFromPrimitiveOrMetadataTypeName(genericArgumentTypeName, false);
  527. if (genericArgumentClass == NULL)
  528. return NULL;
  529. genericArguments[genericArgumentsAdded] = &genericArgumentClass->byval_arg;
  530. currentGenericArgumentStart = genericArgumentsPtr + 1;
  531. genericArgumentsAdded++;
  532. }
  533. }
  534. }
  535. }
  536. if (genericArgumentsAdded != genericArgumentCount)
  537. return NULL;
  538. const Il2CppGenericInst* genericInst = MetadataCache::GetGenericInst(genericArguments, genericArgumentCount);
  539. Il2CppGenericClass* genericClass = metadata::GenericMetadata::GetGenericClass(classDefinition, genericInst);
  540. return GenericClass::GetClass(genericClass);
  541. }
  542. static Il2CppClass* GetClassFromMetadataTypeName(utils::StringView<Il2CppNativeChar> typeName, bool throwOnFailure)
  543. {
  544. // Does this type involve generics?
  545. if (typeName[typeName.Length() - 1] == '>')
  546. {
  547. // Is it an array/boxed value?
  548. if (utils::StringUtils::StartsWith(typeName, kArrayTypeOrIReferencePrefix))
  549. {
  550. if (utils::StringUtils::StartsWith(typeName.SubStr(IL2CPP_ARRAY_SIZE(kArrayTypeOrIReferencePrefix) - 1), kArrayTypePostprefix))
  551. {
  552. // We have an array
  553. utils::StringView<Il2CppNativeChar> elementTypeName = typeName.SubStr(IL2CPP_ARRAY_SIZE(kArrayTypePrefix) - 1, typeName.Length() - IL2CPP_ARRAY_SIZE(kArrayTypePrefix));
  554. Il2CppClass* elementClass = GetClassFromPrimitiveOrMetadataTypeName(elementTypeName, false);
  555. if (elementClass != NULL)
  556. return Class::GetArrayClass(elementClass, 1);
  557. }
  558. else if (utils::StringUtils::StartsWith(typeName.SubStr(IL2CPP_ARRAY_SIZE(kArrayTypeOrIReferencePrefix) - 1), kIReferencePostprefix))
  559. {
  560. // We have a boxed value
  561. utils::StringView<Il2CppNativeChar> boxedTypeName = typeName.SubStr(IL2CPP_ARRAY_SIZE(kIReferencePrefix) - 1, typeName.Length() - IL2CPP_ARRAY_SIZE(kIReferencePrefix));
  562. Il2CppClass* boxedClass = GetClassFromPrimitiveOrMetadataTypeName(boxedTypeName, false);
  563. if (boxedClass != NULL)
  564. {
  565. const Il2CppType* boxedType = &boxedClass->byval_arg;
  566. const Il2CppGenericInst* genericInst = MetadataCache::GetGenericInst(&boxedType, 1);
  567. Il2CppGenericClass* genericClass = metadata::GenericMetadata::GetGenericClass(il2cpp_defaults.generic_nullable_class, genericInst);
  568. return GenericClass::GetClass(genericClass);
  569. }
  570. }
  571. }
  572. // This could be a generic type
  573. Il2CppClass* klass = GetGenericInstanceClassFromMetadataTypeName(typeName);
  574. if (klass != NULL)
  575. return klass;
  576. }
  577. // It's not an generic array, or boxed type. Look in Windows Runtime class type map
  578. const std::string typeNameUtf8 = utils::StringUtils::NativeStringToUtf8(typeName.Str(), static_cast<uint32_t>(typeName.Length()));
  579. Il2CppClass* windowsRuntimeClass = MetadataCache::GetWindowsRuntimeClass(typeNameUtf8.c_str());
  580. if (windowsRuntimeClass != NULL)
  581. return windowsRuntimeClass;
  582. // We don't have it in Windows Runtime class type map. Look in WindowsRuntimeMetadata assembly
  583. size_t lastDotIndex = typeNameUtf8.rfind('.');
  584. if (lastDotIndex != std::string::npos)
  585. {
  586. const std::string namespaze = typeNameUtf8.substr(0, lastDotIndex);
  587. const char* name = typeNameUtf8.c_str() + lastDotIndex + 1;
  588. const Il2CppAssembly* windowsRuntimeMetadataAssembly = Assembly::Load("WindowsRuntimeMetadata");
  589. if (windowsRuntimeMetadataAssembly != NULL)
  590. {
  591. Il2CppClass* windowsRuntimeClass = Image::ClassFromName(windowsRuntimeMetadataAssembly->image, namespaze.c_str(), name);
  592. if (windowsRuntimeClass != NULL)
  593. return windowsRuntimeClass;
  594. }
  595. }
  596. if (throwOnFailure)
  597. {
  598. // We couldn't find metadata type with given name, so we must now throw an exception.
  599. // Here's the catch: if a type name is actually a primitive type name, we need to
  600. // throw a special saying that the type kind was unexpected. Otherwise, we need to
  601. // throw the same exception as when we cannot find a primitive type.
  602. if (GetClassFromPrimitiveTypeName(typeName, false) != NULL)
  603. ThrowUnexpectedTypeKindException();
  604. // We want to start the generic part of the name from the exception message
  605. if (typeName[typeName.Length() - 1] == '>')
  606. {
  607. size_t genericArgumentStart = typeName.Find('<');
  608. if (genericArgumentStart != utils::StringView<Il2CppNativeChar>::NPos())
  609. typeName = typeName.SubStr(0, genericArgumentStart);
  610. }
  611. ThrowWindowsRuntimeTypeNotFoundException(typeName);
  612. }
  613. return NULL;
  614. }
  615. static const Il2CppType* GetTypeFromCustomTypeName(utils::StringView<Il2CppNativeChar> typeName)
  616. {
  617. const std::string str = utils::StringUtils::NativeStringToUtf8(typeName.Str(), static_cast<uint32_t>(typeName.Length()));
  618. TypeNameParseInfo info;
  619. TypeNameParser parser(str, info, false);
  620. if (!parser.Parse())
  621. {
  622. utils::StringView<char>
  623. name(utils::StringView<char>::Empty()),
  624. assemblyName(utils::StringView<char>::Empty());
  625. size_t commaIndex = str.find_last_of(',');
  626. if (commaIndex != std::string::npos)
  627. {
  628. name = utils::StringView<char>(str.c_str(), commaIndex);
  629. while (commaIndex < str.length() && (str[commaIndex] == ' ' || str[commaIndex] == '\t'))
  630. commaIndex++;
  631. if (commaIndex < str.length())
  632. assemblyName = utils::StringView<char>(str.c_str() + commaIndex + 1, str.length() - commaIndex - 1);
  633. }
  634. else
  635. {
  636. name = STRING_TO_STRINGVIEW(str);
  637. }
  638. // Splitting name and namespace is pretty complicated, and they're going to be mashed up together in
  639. // the type load exception message anyway. Let's not bother.
  640. Exception::Raise(Exception::GetTypeLoadException(utils::StringView<char>::Empty(), name, assemblyName));
  641. }
  642. return Class::il2cpp_type_from_type_info(info, static_cast<TypeSearchFlags>(kTypeSearchFlagThrowOnError | kTypeSearchFlagDontUseExecutingImage));
  643. }
  644. const Il2CppType* WindowsRuntime::MarshalTypeFromNative(Il2CppWindowsRuntimeTypeName& nativeType)
  645. {
  646. if (nativeType.typeName == NULL)
  647. return NULL;
  648. uint32_t typeNameLength;
  649. auto typeNamePtr = os::WindowsRuntime::GetNativeHStringBuffer(nativeType.typeName, &typeNameLength);
  650. vm::Exception::RaiseIfError(typeNamePtr.GetError());
  651. utils::StringView<Il2CppNativeChar> typeNameView(typeNamePtr.Get(), typeNameLength);
  652. switch (nativeType.typeKind)
  653. {
  654. case kTypeKindPrimitive:
  655. return &GetClassFromPrimitiveTypeName(typeNameView, true)->byval_arg;
  656. case kTypeKindMetadata:
  657. return &GetClassFromMetadataTypeName(typeNameView, true)->byval_arg;
  658. case kTypeKindCustom:
  659. return GetTypeFromCustomTypeName(typeNameView);
  660. default:
  661. ThrowUnexpectedTypeKindException();
  662. }
  663. }
  664. }
  665. }