No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Runtime.cpp 49KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. #include "il2cpp-config.h"
  2. #include "metadata/GenericMethod.h"
  3. #include "os/CrashHelpers.h"
  4. #include "os/Environment.h"
  5. #include "os/File.h"
  6. #include "os/Image.h"
  7. #include "os/Initialize.h"
  8. #include "os/LibraryLoader.h"
  9. #include "os/Locale.h"
  10. #include "os/MemoryMappedFile.h"
  11. #include "os/Mutex.h"
  12. #include "os/Path.h"
  13. #include "os/SynchronizationContext.h"
  14. #include "os/Thread.h"
  15. #include "os/Socket.h"
  16. #include "os/c-api/Allocator.h"
  17. #include "metadata/GenericMetadata.h"
  18. #include "vm/Array.h"
  19. #include "vm/Assembly.h"
  20. #include "vm/ClassLibraryPAL.h"
  21. #include "vm/COMEntryPoints.h"
  22. #include "vm/Class.h"
  23. #include "vm/Domain.h"
  24. #include "vm/Exception.h"
  25. #include "vm/Field.h"
  26. #include "gc/GCHandle.h"
  27. #include "vm/Image.h"
  28. #include "vm/LastError.h"
  29. #include "vm/MetadataAlloc.h"
  30. #include "vm/MetadataCache.h"
  31. #include "vm/MetadataLock.h"
  32. #include "vm/Method.h"
  33. #include "vm/Reflection.h"
  34. #include "vm/Runtime.h"
  35. #include "vm/Thread.h"
  36. #include "vm/Type.h"
  37. #include "vm/StackTrace.h"
  38. #include "vm/String.h"
  39. #include "vm/Object.h"
  40. #include "vm-utils/Debugger.h"
  41. #include "vm-utils/DebugSymbolReader.h"
  42. #include "vm/Profiler.h"
  43. #include "utils/Logging.h"
  44. #include <string>
  45. #include <map>
  46. #include "il2cpp-class-internals.h"
  47. #include "il2cpp-object-internals.h"
  48. #include "il2cpp-tabledefs.h"
  49. #include "gc/GarbageCollector.h"
  50. #include "gc/WriteBarrier.h"
  51. #include "vm/InternalCalls.h"
  52. #include "utils/Collections.h"
  53. #include "utils/Memory.h"
  54. #include "utils/StringUtils.h"
  55. #include "utils/PathUtils.h"
  56. #include "utils/Runtime.h"
  57. #include "utils/Environment.h"
  58. #include "mono/ThreadPool/threadpool-ms.h"
  59. #include "mono/ThreadPool/threadpool-ms-io.h"
  60. #include "icalls/mscorlib/System.Reflection/RuntimeAssembly.h"
  61. #include "icalls/mscorlib/System.IO/MonoIO.h"
  62. #include "vm/Monitor.h"
  63. #include "vm-utils/Debugger.h"
  64. #include "Baselib.h"
  65. #include "Cpp/ReentrantLock.h"
  66. Il2CppDefaults il2cpp_defaults;
  67. bool g_il2cpp_is_fully_initialized = false;
  68. static bool shutting_down = false;
  69. MetadataInitializerCleanupFunc g_ClearMethodMetadataInitializedFlags = NULL;
  70. static baselib::ReentrantLock s_InitLock;
  71. static int32_t s_RuntimeInitCount;
  72. typedef void (*CodegenRegistrationFunction) ();
  73. extern CodegenRegistrationFunction g_CodegenRegistration;
  74. namespace il2cpp
  75. {
  76. namespace vm
  77. {
  78. baselib::ReentrantLock g_MetadataLock;
  79. static int32_t exitcode = 0;
  80. static std::string s_ConfigDir;
  81. static const char *s_FrameworkVersion = 0;
  82. static const char *s_BundledMachineConfig = 0;
  83. static Il2CppRuntimeUnhandledExceptionPolicy s_UnhandledExceptionPolicy = IL2CPP_UNHANDLED_POLICY_CURRENT;
  84. static const void* s_UnitytlsInterface = NULL;
  85. #define DEFAULTS_INIT(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib, ns, n);\
  86. IL2CPP_ASSERT(il2cpp_defaults.field); } while (0)
  87. #define DEFAULTS_INIT_TYPE(field, ns, n, nativetype) do { DEFAULTS_INIT(field, ns, n); \
  88. IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
  89. #define DEFAULTS_INIT_OPTIONAL(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib, ns, n); } while (0)
  90. #define DEFAULTS_INIT_TYPE_OPTIONAL(field, ns, n, nativetype) do { DEFAULTS_INIT_OPTIONAL(field, ns, n); \
  91. if (il2cpp_defaults.field != NULL) \
  92. IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
  93. #define DEFAULTS_GEN_INIT(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib_gen, ns, n);\
  94. IL2CPP_ASSERT(il2cpp_defaults.field); } while (0)
  95. #define DEFAULTS_GEN_INIT_TYPE(field, ns, n, nativetype) do { DEFAULTS_GEN_INIT(field, ns, n); \
  96. IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
  97. #define DEFAULTS_GEN_INIT_OPTIONAL(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib_gen, ns, n); } while (0)
  98. char* basepath(const char* path)
  99. {
  100. std::string original_path(path);
  101. size_t position_of_last_separator = original_path.find_last_of(IL2CPP_DIR_SEPARATOR);
  102. return il2cpp::utils::StringUtils::StringDuplicate(original_path.substr(position_of_last_separator + 1).c_str());
  103. }
  104. static const char *framework_version_for(const char *runtime_version)
  105. {
  106. IL2CPP_ASSERT(runtime_version && "Invalid runtime version");
  107. IL2CPP_ASSERT((strstr(runtime_version, "v4.0") == runtime_version) && "Invalid runtime version");
  108. return "4.0";
  109. }
  110. static void SanityChecks()
  111. {
  112. #if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
  113. IL2CPP_ASSERT(ALIGN_OF(int64_t) == 8);
  114. #endif
  115. }
  116. static inline void InitializeStringEmpty()
  117. {
  118. Class::Init(il2cpp_defaults.string_class);
  119. FieldInfo* stringEmptyField = Class::GetFieldFromName(il2cpp_defaults.string_class, "Empty");
  120. Field::StaticSetValue(stringEmptyField, String::Empty());
  121. }
  122. static void SetConfigStr(const std::string& executablePath);
  123. bool Runtime::Init(const char* domainName)
  124. {
  125. os::FastAutoLock lock(&s_InitLock);
  126. IL2CPP_ASSERT(s_RuntimeInitCount >= 0);
  127. if (s_RuntimeInitCount++ > 0)
  128. return true;
  129. SanityChecks();
  130. #if IL2CPP_MONO_DEBUGGER
  131. il2cpp::utils::Debugger::AllocateStaticData();
  132. #endif
  133. il2cpp::vm::Monitor::AllocateStaticData();
  134. il2cpp::os::MemoryMappedFile::AllocateStaticData();
  135. il2cpp::icalls::mscorlib::System::IO::MonoIO::AllocateStaticData();
  136. il2cpp::vm::Class::AllocateStaticData();
  137. #if IL2CPP_ENABLE_PROFILER
  138. // Static data for profiler is initialised here and also when profiler is installed (Profiler::Install()) since il2cpp test setup differs from Unity
  139. il2cpp::vm::Profiler::AllocateStaticData();
  140. #endif
  141. il2cpp::icalls::mscorlib::System::Reflection::RuntimeAssembly::AllocateStaticData();
  142. os::Initialize();
  143. os::Locale::Initialize();
  144. MetadataAllocInitialize();
  145. // NOTE(gab): the runtime_version needs to change once we
  146. // will support multiple runtimes.
  147. // For now we default to the one used by unity and don't
  148. // allow the callers to change it.
  149. s_FrameworkVersion = framework_version_for("v4.0.30319");
  150. os::Image::Initialize();
  151. os::Thread::Init();
  152. #if IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT
  153. // Has to happen after Thread::Init() due to it needing a COM apartment on Windows
  154. il2cpp::os::SynchronizationContext::Initialize();
  155. #endif
  156. // This should be filled in by generated code.
  157. IL2CPP_ASSERT(g_CodegenRegistration != NULL);
  158. g_CodegenRegistration();
  159. if (!MetadataCache::Initialize())
  160. {
  161. s_RuntimeInitCount--;
  162. return false;
  163. }
  164. Assembly::Initialize();
  165. gc::GarbageCollector::Initialize();
  166. // Thread needs GC initialized
  167. Thread::Initialize();
  168. register_allocator(il2cpp::utils::Memory::Malloc, il2cpp::utils::Memory::Free);
  169. memset(&il2cpp_defaults, 0, sizeof(Il2CppDefaults));
  170. const Il2CppAssembly* assembly = Assembly::Load("mscorlib.dll");
  171. const Il2CppAssembly* assembly2 = Assembly::Load("__Generated");
  172. // It is not possible to use DEFAULTS_INIT_TYPE for managed types for which we have a native struct, if the
  173. // native struct does not map the complete managed type.
  174. // Which is the case for: Il2CppThread, Il2CppAppDomain, Il2CppCultureInfo, Il2CppReflectionProperty,
  175. // Il2CppDateTimeFormatInfo, Il2CppNumberFormatInfo
  176. il2cpp_defaults.corlib = Assembly::GetImage(assembly);
  177. il2cpp_defaults.corlib_gen = Assembly::GetImage(assembly2);
  178. DEFAULTS_INIT(object_class, "System", "Object");
  179. DEFAULTS_INIT(void_class, "System", "Void");
  180. DEFAULTS_INIT_TYPE(boolean_class, "System", "Boolean", bool);
  181. DEFAULTS_INIT_TYPE(byte_class, "System", "Byte", uint8_t);
  182. DEFAULTS_INIT_TYPE(sbyte_class, "System", "SByte", int8_t);
  183. DEFAULTS_INIT_TYPE(int16_class, "System", "Int16", int16_t);
  184. DEFAULTS_INIT_TYPE(uint16_class, "System", "UInt16", uint16_t);
  185. DEFAULTS_INIT_TYPE(int32_class, "System", "Int32", int32_t);
  186. DEFAULTS_INIT_TYPE(uint32_class, "System", "UInt32", uint32_t);
  187. DEFAULTS_INIT(uint_class, "System", "UIntPtr");
  188. DEFAULTS_INIT_TYPE(int_class, "System", "IntPtr", intptr_t);
  189. DEFAULTS_INIT_TYPE(int64_class, "System", "Int64", int64_t);
  190. DEFAULTS_INIT_TYPE(uint64_class, "System", "UInt64", uint64_t);
  191. DEFAULTS_INIT_TYPE(single_class, "System", "Single", float);
  192. DEFAULTS_INIT_TYPE(double_class, "System", "Double", double);
  193. DEFAULTS_INIT_TYPE(char_class, "System", "Char", Il2CppChar);
  194. DEFAULTS_INIT(string_class, "System", "String");
  195. DEFAULTS_INIT(enum_class, "System", "Enum");
  196. DEFAULTS_INIT(array_class, "System", "Array");
  197. DEFAULTS_INIT(value_type_class, "System", "ValueType");
  198. DEFAULTS_INIT_TYPE(delegate_class, "System", "Delegate", Il2CppDelegate);
  199. DEFAULTS_INIT_TYPE(multicastdelegate_class, "System", "MulticastDelegate", Il2CppMulticastDelegate);
  200. DEFAULTS_INIT(asyncresult_class, "System.Runtime.Remoting.Messaging", "AsyncResult");
  201. DEFAULTS_INIT_TYPE(async_call_class, "System", "MonoAsyncCall", Il2CppAsyncCall);
  202. DEFAULTS_INIT(manualresetevent_class, "System.Threading", "ManualResetEvent");
  203. //DEFAULTS_INIT(typehandle_class, "System", "RuntimeTypeHandle");
  204. //DEFAULTS_INIT(methodhandle_class, "System", "RuntimeMethodHandle");
  205. //DEFAULTS_INIT(fieldhandle_class, "System", "RuntimeFieldHandle");
  206. DEFAULTS_INIT(systemtype_class, "System", "Type");
  207. DEFAULTS_INIT_TYPE(monotype_class, "System", "MonoType", Il2CppReflectionMonoType);
  208. //DEFAULTS_INIT(exception_class, "System", "Exception");
  209. //DEFAULTS_INIT(threadabortexcepXtion_class, "System.Threading", "ThreadAbortException");
  210. DEFAULTS_INIT_TYPE(thread_class, "System.Threading", "Thread", Il2CppThread);
  211. DEFAULTS_INIT_TYPE(internal_thread_class, "System.Threading", "InternalThread", Il2CppInternalThread);
  212. DEFAULTS_INIT_TYPE(runtimetype_class, "System", "RuntimeType", Il2CppReflectionRuntimeType);
  213. DEFAULTS_INIT(appdomain_class, "System", "AppDomain");
  214. DEFAULTS_INIT(appdomain_setup_class, "System", "AppDomainSetup");
  215. DEFAULTS_INIT(member_info_class, "System.Reflection", "MemberInfo");
  216. DEFAULTS_INIT(field_info_class, "System.Reflection", "FieldInfo");
  217. DEFAULTS_INIT(method_info_class, "System.Reflection", "MethodInfo");
  218. DEFAULTS_INIT(property_info_class, "System.Reflection", "PropertyInfo");
  219. DEFAULTS_INIT_TYPE(event_info_class, "System.Reflection", "EventInfo", Il2CppReflectionEvent);
  220. DEFAULTS_INIT_TYPE(stringbuilder_class, "System.Text", "StringBuilder", Il2CppStringBuilder);
  221. DEFAULTS_INIT_TYPE(stack_frame_class, "System.Diagnostics", "StackFrame", Il2CppStackFrame);
  222. DEFAULTS_INIT(stack_trace_class, "System.Diagnostics", "StackTrace");
  223. DEFAULTS_INIT_TYPE(typed_reference_class, "System", "TypedReference", Il2CppTypedRef);
  224. DEFAULTS_INIT(generic_ilist_class, "System.Collections.Generic", "IList`1");
  225. DEFAULTS_INIT(generic_icollection_class, "System.Collections.Generic", "ICollection`1");
  226. DEFAULTS_INIT(generic_ienumerable_class, "System.Collections.Generic", "IEnumerable`1");
  227. DEFAULTS_INIT(generic_ireadonlylist_class, "System.Collections.Generic", "IReadOnlyList`1");
  228. DEFAULTS_INIT(generic_ireadonlycollection_class, "System.Collections.Generic", "IReadOnlyCollection`1");
  229. DEFAULTS_INIT(generic_nullable_class, "System", "Nullable`1");
  230. DEFAULTS_INIT(version, "System", "Version");
  231. DEFAULTS_INIT(culture_info, "System.Globalization", "CultureInfo");
  232. DEFAULTS_INIT_TYPE(assembly_class, "System.Reflection", "RuntimeAssembly", Il2CppReflectionAssembly);
  233. DEFAULTS_INIT_TYPE_OPTIONAL(assembly_name_class, "System.Reflection", "AssemblyName", Il2CppReflectionAssemblyName);
  234. DEFAULTS_INIT_TYPE(parameter_info_class, "System.Reflection", "RuntimeParameterInfo", Il2CppReflectionParameter);
  235. DEFAULTS_INIT_TYPE(module_class, "System.Reflection", "RuntimeModule", Il2CppReflectionModule);
  236. DEFAULTS_INIT_TYPE(exception_class, "System", "Exception", Il2CppException);
  237. DEFAULTS_INIT_TYPE(system_exception_class, "System", "SystemException", Il2CppSystemException);
  238. DEFAULTS_INIT_TYPE(argument_exception_class, "System", "ArgumentException", Il2CppArgumentException);
  239. DEFAULTS_INIT_TYPE(marshalbyrefobject_class, "System", "MarshalByRefObject", Il2CppMarshalByRefObject);
  240. DEFAULTS_GEN_INIT_TYPE(il2cpp_com_object_class, "System", "__Il2CppComObject", Il2CppComObject);
  241. DEFAULTS_INIT_TYPE(safe_handle_class, "System.Runtime.InteropServices", "SafeHandle", Il2CppSafeHandle);
  242. DEFAULTS_INIT_TYPE(sort_key_class, "System.Globalization", "SortKey", Il2CppSortKey);
  243. DEFAULTS_INIT(dbnull_class, "System", "DBNull");
  244. DEFAULTS_INIT_TYPE_OPTIONAL(error_wrapper_class, "System.Runtime.InteropServices", "ErrorWrapper", Il2CppErrorWrapper);
  245. DEFAULTS_INIT(missing_class, "System.Reflection", "Missing");
  246. DEFAULTS_INIT(attribute_class, "System", "Attribute");
  247. DEFAULTS_INIT_OPTIONAL(customattribute_data_class, "System.Reflection", "CustomAttributeData");
  248. DEFAULTS_INIT_OPTIONAL(customattribute_typed_argument_class, "System.Reflection", "CustomAttributeTypedArgument");
  249. DEFAULTS_INIT_OPTIONAL(customattribute_named_argument_class, "System.Reflection", "CustomAttributeNamedArgument");
  250. DEFAULTS_INIT(key_value_pair_class, "System.Collections.Generic", "KeyValuePair`2");
  251. DEFAULTS_INIT(system_guid_class, "System", "Guid");
  252. DEFAULTS_INIT(threadpool_wait_callback_class, "System.Threading", "_ThreadPoolWaitCallback");
  253. DEFAULTS_INIT(mono_method_message_class, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
  254. il2cpp_defaults.threadpool_perform_wait_callback_method = (MethodInfo*)vm::Class::GetMethodFromName(
  255. il2cpp_defaults.threadpool_wait_callback_class, "PerformWaitCallback", 0);
  256. DEFAULTS_INIT_OPTIONAL(sbyte_shared_enum, "System", "SByteEnum");
  257. DEFAULTS_INIT_OPTIONAL(int16_shared_enum, "System", "Int16Enum");
  258. DEFAULTS_INIT_OPTIONAL(int32_shared_enum, "System", "Int32Enum");
  259. DEFAULTS_INIT_OPTIONAL(int64_shared_enum, "System", "Int64Enum");
  260. DEFAULTS_INIT_OPTIONAL(byte_shared_enum, "System", "ByteEnum");
  261. DEFAULTS_INIT_OPTIONAL(uint16_shared_enum, "System", "UInt16Enum");
  262. DEFAULTS_INIT_OPTIONAL(uint32_shared_enum, "System", "UInt32Enum");
  263. DEFAULTS_INIT_OPTIONAL(uint64_shared_enum, "System", "UInt64Enum");
  264. DEFAULTS_GEN_INIT_OPTIONAL(il2cpp_fully_shared_type, "Unity.IL2CPP.Metadata", "__Il2CppFullySharedGenericType");
  265. DEFAULTS_GEN_INIT_OPTIONAL(il2cpp_fully_shared_struct_type, "Unity.IL2CPP.Metadata", "__Il2CppFullySharedGenericStructType");
  266. ClassLibraryPAL::Initialize();
  267. // Reflection needs GC initialized
  268. Reflection::Initialize();
  269. Image::InitNestedTypes(il2cpp_defaults.corlib);
  270. const Il2CppAssembly* systemDll = Assembly::Load("System");
  271. if (systemDll != NULL)
  272. il2cpp_defaults.system_uri_class = Class::FromName(Assembly::GetImage(systemDll), "System", "Uri");
  273. // This will only exist if there was at least 1 winmd file present during conversion
  274. const Il2CppAssembly* windowsRuntimeMetadataAssembly = Assembly::Load("WindowsRuntimeMetadata");
  275. if (windowsRuntimeMetadataAssembly != NULL)
  276. {
  277. const Il2CppImage* windowsRuntimeMetadataImage = Assembly::GetImage(windowsRuntimeMetadataAssembly);
  278. il2cpp_defaults.ireference_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IReference`1");
  279. il2cpp_defaults.ireferencearray_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IReferenceArray`1");
  280. il2cpp_defaults.ikey_value_pair_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation.Collections", "IKeyValuePair`2");
  281. il2cpp_defaults.ikey_value_pair_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation.Collections", "IKeyValuePair`2");
  282. il2cpp_defaults.windows_foundation_uri_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "Uri");
  283. il2cpp_defaults.windows_foundation_iuri_runtime_class_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IUriRuntimeClass");
  284. }
  285. Class::Init(il2cpp_defaults.string_class);
  286. os::Socket::Startup();
  287. #if IL2CPP_MONO_DEBUGGER
  288. il2cpp::utils::Debugger::Init();
  289. #endif
  290. Il2CppDomain* domain = Domain::GetCurrent();
  291. Il2CppThread* mainThread = Thread::Attach(domain);
  292. Thread::SetMain(mainThread);
  293. Il2CppAppDomainSetup* setup = (Il2CppAppDomainSetup*)Object::NewPinned(il2cpp_defaults.appdomain_setup_class);
  294. Il2CppAppDomain* ad = (Il2CppAppDomain*)Object::NewPinned(il2cpp_defaults.appdomain_class);
  295. gc::WriteBarrier::GenericStore(&ad->data, domain);
  296. gc::WriteBarrier::GenericStore(&domain->domain, ad);
  297. gc::WriteBarrier::GenericStore(&domain->setup, setup);
  298. domain->domain_id = 1; // Only have a single domain ATM.
  299. domain->friendly_name = basepath(domainName);
  300. LastError::InitializeLastErrorThreadStatic();
  301. gc::GarbageCollector::InitializeFinalizer();
  302. MetadataCache::InitializeGCSafe();
  303. String::InitializeEmptyString(il2cpp_defaults.string_class);
  304. InitializeStringEmpty();
  305. g_il2cpp_is_fully_initialized = true;
  306. // Force binary serialization in Mono to use reflection instead of code generation.
  307. #undef SetEnvironmentVariable // Get rid of windows.h #define.
  308. os::Environment::SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
  309. os::Environment::SetEnvironmentVariable("MONO_XMLSERIALIZER_THS", "no");
  310. Domain::ContextInit(domain);
  311. Domain::ContextSet(domain->default_context);
  312. VerifyApiVersion();
  313. #if IL2CPP_MONO_DEBUGGER
  314. il2cpp::utils::Debugger::Start();
  315. #endif
  316. std::string executablePath = os::Path::GetExecutablePath();
  317. SetConfigStr(executablePath);
  318. if (utils::Environment::GetNumMainArgs() == 0)
  319. {
  320. // If main args were never set, we default to 1 arg that is the executable path
  321. const char* mainArgs[] = { executablePath.c_str() };
  322. utils::Environment::SetMainArgs(mainArgs, 1);
  323. }
  324. vm::MetadataCache::ExecuteEagerStaticClassConstructors();
  325. vm::MetadataCache::ExecuteModuleInitializers();
  326. #if !IL2CPP_MONO_DEBUGGER
  327. il2cpp::utils::DebugSymbolReader::LoadDebugSymbols();
  328. #endif
  329. return true;
  330. }
  331. static Il2CppObject* GetEventArgsEmptyField()
  332. {
  333. Il2CppClass* eventArgsKlass = Class::FromName(il2cpp_defaults.corlib, "System", "EventArgs");
  334. if (eventArgsKlass != NULL)
  335. {
  336. Class::Init(eventArgsKlass);
  337. FieldInfo* emptyField = vm::Class::GetFieldFromName(eventArgsKlass, "Empty");
  338. if (emptyField != NULL)
  339. {
  340. Il2CppObject* emptyValue;
  341. vm::Field::StaticGetValue(emptyField, &emptyValue);
  342. return emptyValue;
  343. }
  344. }
  345. return NULL;
  346. }
  347. static void FireProcessExitEvent()
  348. {
  349. FieldInfo* processExitField = vm::Class::GetFieldFromName(il2cpp_defaults.appdomain_class, "ProcessExit");
  350. if (processExitField != NULL) // The field might have been stripped, just ignore it.
  351. {
  352. Il2CppAppDomain* appDomain = vm::Domain::GetCurrent()->domain;
  353. Il2CppDelegate* processExitDelegate;
  354. vm::Field::GetValue((Il2CppObject*)appDomain, processExitField, &processExitDelegate);
  355. if (processExitDelegate == NULL) // Don't call the delegate if no one is listening to it.
  356. return;
  357. void* args[2];
  358. args[0] = appDomain;
  359. args[1] = GetEventArgsEmptyField();
  360. Il2CppException* unusedException;
  361. Runtime::DelegateInvoke(processExitDelegate, args, &unusedException);
  362. }
  363. }
  364. void Runtime::Shutdown()
  365. {
  366. os::FastAutoLock lock(&s_InitLock);
  367. IL2CPP_ASSERT(s_RuntimeInitCount > 0);
  368. if (--s_RuntimeInitCount > 0)
  369. return;
  370. FireProcessExitEvent();
  371. shutting_down = true;
  372. #if IL2CPP_MONO_DEBUGGER
  373. il2cpp::utils::Debugger::RuntimeShutdownEnd();
  374. #endif
  375. il2cpp::icalls::mscorlib::System::Reflection::RuntimeAssembly::FreeStaticData();
  376. #if IL2CPP_SUPPORT_THREADS
  377. threadpool_ms_cleanup();
  378. #endif
  379. // Tries to abort all threads
  380. // Threads at alertable waits may not have existing when this return
  381. Thread::AbortAllThreads();
  382. #if IL2CPP_ENABLE_PROFILER
  383. il2cpp::vm::Profiler::Shutdown();
  384. #endif
  385. os::Socket::Cleanup();
  386. String::CleanupEmptyString();
  387. il2cpp::gc::GarbageCollector::UninitializeFinalizers();
  388. // after the gc cleanup so the finalizer thread can unregister itself
  389. Thread::Uninitialize();
  390. #if IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT
  391. // Has to happen before os::Thread::Shutdown() due to it needing a COM apartment on Windows
  392. il2cpp::os::SynchronizationContext::Shutdown();
  393. #endif
  394. os::Thread::Shutdown();
  395. #if IL2CPP_ENABLE_RELOAD
  396. MetadataCache::Clear();
  397. #endif
  398. // We need to do this before UninitializeGC because it uses (fixed) GC memory
  399. Reflection::ClearStatics();
  400. // We need to do this after thread shut down because it is freeing GC fixed memory
  401. il2cpp::gc::GarbageCollector::UninitializeGC();
  402. // This needs to happen after no managed code can run anymore, including GC finalizers
  403. os::LibraryLoader::CleanupLoadedLibraries();
  404. vm::Image::ClearCachedResourceData();
  405. MetadataAllocCleanup();
  406. vm::COMEntryPoints::FreeCachedData();
  407. os::Locale::UnInitialize();
  408. os::Uninitialize();
  409. #if IL2CPP_ENABLE_PROFILER
  410. il2cpp::vm::Profiler::FreeStaticData();
  411. #endif
  412. il2cpp::vm::Monitor::FreeStaticData();
  413. il2cpp::os::MemoryMappedFile::FreeStaticData();
  414. il2cpp::icalls::mscorlib::System::IO::MonoIO::FreeStaticData();
  415. il2cpp::vm::Class::FreeStaticData();
  416. #if IL2CPP_MONO_DEBUGGER
  417. il2cpp::utils::Debugger::FreeStaticData();
  418. #endif
  419. #if IL2CPP_ENABLE_RELOAD
  420. if (g_ClearMethodMetadataInitializedFlags != NULL)
  421. g_ClearMethodMetadataInitializedFlags();
  422. #endif
  423. }
  424. bool Runtime::IsShuttingDown()
  425. {
  426. return shutting_down;
  427. }
  428. void Runtime::SetConfigDir(const char *path)
  429. {
  430. s_ConfigDir = path;
  431. }
  432. static void SetConfigStr(const std::string& executablePath)
  433. {
  434. Il2CppDomain* domain = vm::Domain::GetCurrent();
  435. std::string configFileName = utils::PathUtils::Basename(executablePath);
  436. configFileName.append(".config");
  437. std::string appBase = utils::PathUtils::DirectoryName(executablePath);
  438. IL2CPP_OBJECT_SETREF(domain->setup, application_base, vm::String::New(appBase.c_str()));
  439. IL2CPP_OBJECT_SETREF(domain->setup, configuration_file, vm::String::New(configFileName.c_str()));
  440. }
  441. void Runtime::SetConfigUtf16(const Il2CppChar* executablePath)
  442. {
  443. IL2CPP_ASSERT(executablePath);
  444. std::string exePathUtf8 = il2cpp::utils::StringUtils::Utf16ToUtf8(executablePath);
  445. SetConfigStr(exePathUtf8);
  446. }
  447. void Runtime::SetConfig(const char* executablePath)
  448. {
  449. IL2CPP_ASSERT(executablePath);
  450. std::string executablePathStr(executablePath);
  451. SetConfigStr(executablePathStr);
  452. }
  453. void Runtime::SetUnityTlsInterface(const void* unitytlsInterface)
  454. {
  455. s_UnitytlsInterface = unitytlsInterface;
  456. }
  457. const char *Runtime::GetFrameworkVersion()
  458. {
  459. return s_FrameworkVersion;
  460. }
  461. std::string Runtime::GetConfigDir()
  462. {
  463. if (s_ConfigDir.size() > 0)
  464. return s_ConfigDir;
  465. return utils::PathUtils::Combine(utils::Runtime::GetDataDir(), utils::StringView<char>("etc"));
  466. }
  467. const void* Runtime::GetUnityTlsInterface()
  468. {
  469. return s_UnitytlsInterface;
  470. }
  471. const MethodInfo* Runtime::GetDelegateInvoke(Il2CppClass* klass)
  472. {
  473. const MethodInfo* invoke = Class::GetMethodFromName(klass, "Invoke", -1);
  474. IL2CPP_ASSERT(invoke);
  475. return invoke;
  476. }
  477. Il2CppObject* Runtime::DelegateInvoke(Il2CppDelegate *delegate, void **params, Il2CppException **exc)
  478. {
  479. const MethodInfo* invoke = GetDelegateInvoke(delegate->object.klass);
  480. return Invoke(invoke, delegate, params, exc);
  481. }
  482. Il2CppObject* Runtime::Invoke(const MethodInfo *method, void *obj, void **params, Il2CppException **exc)
  483. {
  484. if (exc)
  485. il2cpp::gc::WriteBarrier::GenericStoreNull(exc);
  486. // we wrap invoker call in try/catch here, rather than emitting a try/catch
  487. // in every invoke call as that blows up the code size.
  488. try
  489. {
  490. if ((method->flags & METHOD_ATTRIBUTE_STATIC) && method->klass && !method->klass->cctor_finished_or_no_cctor)
  491. ClassInit(method->klass);
  492. return InvokeWithThrow(method, obj, params);
  493. }
  494. catch (Il2CppExceptionWrapper& ex)
  495. {
  496. if (exc)
  497. il2cpp::gc::WriteBarrier::GenericStore(exc, ex.ex);
  498. return NULL;
  499. }
  500. }
  501. Il2CppObject* Runtime::InvokeWithThrow(const MethodInfo *method, void *obj, void **params)
  502. {
  503. if (method->return_type->type == IL2CPP_TYPE_VOID)
  504. {
  505. method->invoker_method(method->methodPointer, method, obj, params, NULL);
  506. return NULL;
  507. }
  508. else
  509. {
  510. if (method->return_type->valuetype)
  511. {
  512. Il2CppClass* returnType = Class::FromIl2CppType(method->return_type);
  513. Class::Init(returnType);
  514. void* returnValue = alloca(returnType->instance_size - sizeof(Il2CppObject));
  515. method->invoker_method(method->methodPointer, method, obj, params, returnValue);
  516. return Object::Box(returnType, returnValue);
  517. }
  518. else
  519. {
  520. // Note that here method->return_type might be a reference type or it might be
  521. // a value type returned by reference.
  522. void* returnValue = NULL;
  523. method->invoker_method(method->methodPointer, method, obj, params, &returnValue);
  524. if (method->return_type->byref)
  525. {
  526. // We cannot use method->return_type->valuetype here, because that will be
  527. // false for methods that return by reference. Instead, get the class for the
  528. // type, which discards the byref flag.
  529. Il2CppClass* returnType = Class::FromIl2CppType(method->return_type);
  530. if (vm::Class::IsValuetype(returnType))
  531. return Object::Box(returnType, returnValue);
  532. return *(Il2CppObject**)returnValue;
  533. }
  534. return (Il2CppObject*)returnValue;
  535. }
  536. }
  537. }
  538. Il2CppObject* Runtime::InvokeArray(const MethodInfo *method, void *obj, Il2CppArray *params, Il2CppException **exc)
  539. {
  540. if (params == NULL)
  541. return InvokeConvertArgs(method, obj, NULL, 0, exc);
  542. // TO DO: when changing GC to one that moves managed objects around, mark params array local variable as pinned!
  543. return InvokeConvertArgs(method, obj, reinterpret_cast<Il2CppObject**>(Array::GetFirstElementAddress(params)), Array::GetLength(params), exc);
  544. }
  545. void Runtime::ObjectInit(Il2CppObject *object)
  546. {
  547. ObjectInitException(object, NULL);
  548. }
  549. void Runtime::ObjectInitException(Il2CppObject *object, Il2CppException **exc)
  550. {
  551. const MethodInfo *method = NULL;
  552. Il2CppClass *klass = object->klass;
  553. method = Class::GetMethodFromName(klass, ".ctor", 0);
  554. IL2CPP_ASSERT(method != NULL && "ObjectInit; no default constructor for object is found");
  555. if (method->klass->byval_arg.valuetype)
  556. object = (Il2CppObject*)Object::Unbox(object);
  557. Invoke(method, object, NULL, exc);
  558. }
  559. void Runtime::SetUnhandledExceptionPolicy(Il2CppRuntimeUnhandledExceptionPolicy value)
  560. {
  561. s_UnhandledExceptionPolicy = value;
  562. }
  563. Il2CppRuntimeUnhandledExceptionPolicy Runtime::GetUnhandledExceptionPolicy()
  564. {
  565. return s_UnhandledExceptionPolicy;
  566. }
  567. void Runtime::UnhandledException(Il2CppException* exc)
  568. {
  569. Il2CppDomain *currentDomain = Domain::GetCurrent();
  570. Il2CppDomain *rootDomain = Domain::GetRoot();
  571. FieldInfo *field;
  572. Il2CppObject *current_appdomain_delegate = NULL;
  573. Il2CppObject *root_appdomain_delegate = NULL;
  574. field = Class::GetFieldFromName(il2cpp_defaults.appdomain_class, "UnhandledException");
  575. IL2CPP_ASSERT(field);
  576. Il2CppObject* excObject = (Il2CppObject*)exc;
  577. if (excObject->klass != il2cpp_defaults.threadabortexception_class)
  578. {
  579. //bool abort_process = (Thread::Current () == Thread::Main ()) ||
  580. // (Runtime::GetUnhandledExceptionPolicy () == IL2CPP_UNHANDLED_POLICY_CURRENT);
  581. Field::GetValue((Il2CppObject*)rootDomain->domain, field, &root_appdomain_delegate);
  582. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Runtime::UnhandledException, "We don't have runtime version info yet");
  583. //if (currentDomain != rootDomain && (mono_framework_version () >= 2)) {
  584. // Field::GetValue ((Il2CppObject*)currentDomain->domain, field, &current_appdomain_delegate);
  585. //}
  586. //else
  587. //{
  588. // current_appdomain_delegate = NULL;
  589. //}
  590. ///* set exitcode only if we will abort the process */
  591. //if (abort_process)
  592. // mono_environment_exitcode_set (1);
  593. //if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)
  594. //{
  595. // mono_print_unhandled_exception (exc);
  596. //}
  597. //else
  598. {
  599. if (root_appdomain_delegate)
  600. {
  601. CallUnhandledExceptionDelegate(rootDomain, (Il2CppDelegate*)root_appdomain_delegate, exc);
  602. }
  603. if (current_appdomain_delegate)
  604. {
  605. CallUnhandledExceptionDelegate(currentDomain, (Il2CppDelegate*)current_appdomain_delegate, exc);
  606. }
  607. }
  608. }
  609. }
  610. static inline Il2CppObject* InvokeConvertThis(const MethodInfo* method, void* thisArg, void** convertedParameters, Il2CppException** exception)
  611. {
  612. Il2CppClass* thisType = method->klass;
  613. // If it's not a constructor, just invoke directly
  614. if (strcmp(method->name, ".ctor") != 0 || method->klass == il2cpp_defaults.string_class)
  615. {
  616. void* obj = thisArg;
  617. if (Class::IsNullable(method->klass))
  618. {
  619. Il2CppObject* nullable;
  620. /* Convert the unboxed vtype into a Nullable structure */
  621. nullable = Object::New(method->klass);
  622. Il2CppObject* boxed = Object::Box(method->klass->castClass, obj);
  623. Object::NullableInit((uint8_t*)Object::Unbox(nullable), boxed, method->klass);
  624. obj = Object::Unbox(nullable);
  625. }
  626. return Runtime::Invoke(method, obj, convertedParameters, exception);
  627. }
  628. // If it is a construction, we need to construct a return value and allocate object if needed
  629. Il2CppObject* instance;
  630. if (thisArg == NULL)
  631. {
  632. if (Class::IsNullable(thisType))
  633. {
  634. // in the case of a Nullable constructor we can just return a boxed value type
  635. IL2CPP_ASSERT(convertedParameters);
  636. instance = Object::Box(thisType->castClass, convertedParameters[0]);
  637. }
  638. else
  639. {
  640. thisArg = instance = Object::New(thisType);
  641. Runtime::Invoke(method, thisType->byval_arg.valuetype ? Object::Unbox((Il2CppObject*)thisArg) : thisArg, convertedParameters, exception);
  642. }
  643. }
  644. else
  645. {
  646. // thisArg is pointer to data in case of a value type
  647. // We need to invoke the constructor first, passing point to the value
  648. // Since the constructor may modify the value, we need to box the result
  649. // AFTER the constructor was invoked
  650. Runtime::Invoke(method, thisArg, convertedParameters, exception);
  651. instance = Object::Box(thisType, thisArg);
  652. }
  653. return instance;
  654. }
  655. Il2CppObject* Runtime::InvokeConvertArgs(const MethodInfo *method, void* thisArg, Il2CppObject** parameters, int paramCount, Il2CppException** exception)
  656. {
  657. void** convertedParameters = NULL;
  658. bool hasByRefNullables = false;
  659. // Convert parameters if they are not null
  660. if (parameters != NULL)
  661. {
  662. convertedParameters = (void**)alloca(sizeof(void*) * paramCount);
  663. for (int i = 0; i < paramCount; i++)
  664. {
  665. bool passedByReference = method->parameters[i]->byref;
  666. Il2CppClass* parameterType = Class::FromIl2CppType(method->parameters[i]);
  667. Class::Init(parameterType);
  668. if (Class::IsValuetype(parameterType))
  669. {
  670. if (Class::IsNullable(parameterType))
  671. {
  672. // Since we don't really store boxed nullables, we need to create a new one.
  673. void* nullableStorage = alloca(parameterType->instance_size - sizeof(Il2CppObject));
  674. Object::UnboxNullable(parameters[i], parameterType, nullableStorage);
  675. convertedParameters[i] = nullableStorage;
  676. hasByRefNullables |= passedByReference;
  677. }
  678. else if (passedByReference)
  679. {
  680. // If value type is passed by reference, just pass pointer to value directly
  681. // If null was passed in, create a new boxed value type in its place
  682. if (parameters[i] == NULL)
  683. gc::WriteBarrier::GenericStore(parameters + i, Object::New(parameterType));
  684. convertedParameters[i] = Object::Unbox(parameters[i]);
  685. }
  686. else if (parameters[i] == NULL) // If value type is passed by value, we need to pass pointer to its value
  687. {
  688. // If null was passed in, allocate a new value with default value
  689. uint32_t valueSize = parameterType->instance_size - sizeof(Il2CppObject);
  690. convertedParameters[i] = alloca(valueSize);
  691. memset(convertedParameters[i], 0, valueSize);
  692. }
  693. else
  694. {
  695. // Otherwise, pass the original
  696. convertedParameters[i] = Object::Unbox(parameters[i]);
  697. }
  698. }
  699. else if (passedByReference)
  700. {
  701. convertedParameters[i] = &parameters[i]; // Reference type passed by reference
  702. }
  703. else if (parameterType->byval_arg.type == IL2CPP_TYPE_PTR)
  704. {
  705. if (parameters[i] != NULL)
  706. {
  707. IL2CPP_ASSERT(parameters[i]->klass == il2cpp_defaults.int_class);
  708. convertedParameters[i] = reinterpret_cast<void*>(*static_cast<intptr_t*>(Object::Unbox(parameters[i])));
  709. }
  710. else
  711. {
  712. convertedParameters[i] = NULL;
  713. }
  714. }
  715. else
  716. {
  717. convertedParameters[i] = parameters[i]; // Reference type passed by value
  718. }
  719. }
  720. }
  721. Il2CppObject* result = InvokeConvertThis(method, thisArg, convertedParameters, exception);
  722. if (hasByRefNullables)
  723. {
  724. // We need to copy by reference nullables back to original argument array
  725. for (int i = 0; i < paramCount; i++)
  726. {
  727. if (!method->parameters[i]->byref)
  728. continue;
  729. Il2CppClass* parameterType = Class::FromIl2CppType(method->parameters[i]);
  730. if (Class::IsNullable(parameterType))
  731. gc::WriteBarrier::GenericStore(parameters + i, Object::Box(parameterType, convertedParameters[i]));
  732. }
  733. }
  734. if (method->return_type->type == IL2CPP_TYPE_PTR)
  735. {
  736. static Il2CppClass* pointerClass = Class::FromName(il2cpp_defaults.corlib, "System.Reflection", "Pointer");
  737. Il2CppReflectionPointer* pointer = reinterpret_cast<Il2CppReflectionPointer*>(Object::New(pointerClass));
  738. pointer->data = result;
  739. IL2CPP_OBJECT_SETREF(pointer, type, Reflection::GetTypeObject(method->return_type));
  740. result = reinterpret_cast<Il2CppObject*>(pointer);
  741. }
  742. return result;
  743. }
  744. void Runtime::CallUnhandledExceptionDelegate(Il2CppDomain* domain, Il2CppDelegate* delegate, Il2CppException* exc)
  745. {
  746. Il2CppException *e = NULL;
  747. void* pa[2];
  748. pa[0] = domain->domain;
  749. pa[1] = CreateUnhandledExceptionEventArgs(exc);
  750. DelegateInvoke(delegate, pa, &e);
  751. // A managed exception occurred during the unhandled exception handler.
  752. // We can't do much else here other than try to abort the process.
  753. if (e != NULL)
  754. utils::Runtime::Abort();
  755. }
  756. static baselib::ReentrantLock s_TypeInitializationLock;
  757. // We currently call Runtime::ClassInit in 4 places:
  758. // 1. Just after we allocate storage for a new object (Object::NewAllocSpecific)
  759. // 2. Just before reading any static field
  760. // 3. Just before calling any static method
  761. // 4. Just before calling class instance constructor from a derived class instance constructor
  762. void Runtime::ClassInit(Il2CppClass *klass)
  763. {
  764. // Nothing to do if class has no static constructor or already ran.
  765. if (klass->cctor_finished_or_no_cctor)
  766. return;
  767. s_TypeInitializationLock.Acquire();
  768. // See if some thread ran it while we acquired the lock.
  769. if (os::Atomic::CompareExchange(&klass->cctor_finished_or_no_cctor, 1, 1) == 1)
  770. {
  771. s_TypeInitializationLock.Release();
  772. return;
  773. }
  774. // See if some other thread got there first and already started running the constructor.
  775. if (os::Atomic::CompareExchange(&klass->cctor_started, 1, 1) == 1)
  776. {
  777. s_TypeInitializationLock.Release();
  778. // May have been us and we got here through recursion.
  779. os::Thread::ThreadId currentThread = os::Thread::CurrentThreadId();
  780. if (os::Atomic::CompareExchangePointer((size_t**)&klass->cctor_thread, (size_t*)currentThread, (size_t*)currentThread) == (size_t*)currentThread)
  781. return;
  782. // Wait for other thread to finish executing the constructor.
  783. while (os::Atomic::CompareExchange(&klass->cctor_finished_or_no_cctor, 1, 1) != 1 && os::Atomic::CompareExchangePointer((void**)&klass->initializationExceptionGCHandle, (void*)0, (void*)0) == 0)
  784. {
  785. os::Thread::Sleep(1);
  786. }
  787. }
  788. else
  789. {
  790. // Let others know we have started executing the constructor.
  791. os::Atomic::ExchangePointer((size_t**)&klass->cctor_thread, (size_t*)os::Thread::CurrentThreadId());
  792. os::Atomic::Exchange(&klass->cctor_started, 1);
  793. s_TypeInitializationLock.Release();
  794. // Run it.
  795. Il2CppException* exception = NULL;
  796. const MethodInfo* cctor = Class::GetCCtor(klass);
  797. if (cctor != NULL)
  798. {
  799. vm::Runtime::Invoke(cctor, NULL, NULL, &exception);
  800. }
  801. os::Atomic::ExchangePointer((size_t**)&klass->cctor_thread, (size_t*)0);
  802. // Deal with exceptions.
  803. if (exception == NULL)
  804. {
  805. // Let other threads know we finished.
  806. os::Atomic::Exchange(&klass->cctor_finished_or_no_cctor, 1);
  807. }
  808. else
  809. {
  810. const Il2CppType *type = Class::GetType(klass);
  811. std::string n = il2cpp::utils::StringUtils::Printf("The type initializer for '%s' threw an exception.", Type::GetName(type, IL2CPP_TYPE_NAME_FORMAT_IL).c_str());
  812. Class::SetClassInitializationError(klass, Exception::GetTypeInitializationException(n.c_str(), exception));
  813. }
  814. }
  815. if (klass->initializationExceptionGCHandle)
  816. {
  817. il2cpp::vm::Exception::Raise((Il2CppException*)gc::GCHandle::GetTarget(klass->initializationExceptionGCHandle));
  818. }
  819. }
  820. struct ConstCharCompare
  821. {
  822. bool operator()(char const *a, char const *b) const
  823. {
  824. return strcmp(a, b) < 0;
  825. }
  826. };
  827. Il2CppObject* Runtime::CreateUnhandledExceptionEventArgs(Il2CppException *exc)
  828. {
  829. Il2CppClass *klass;
  830. void* args[2];
  831. const MethodInfo *method = NULL;
  832. bool is_terminating = true;
  833. Il2CppObject *obj;
  834. klass = Class::FromName(il2cpp_defaults.corlib, "System", "UnhandledExceptionEventArgs");
  835. IL2CPP_ASSERT(klass);
  836. Class::Init(klass);
  837. /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
  838. method = Class::GetMethodFromNameFlags(klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
  839. IL2CPP_ASSERT(method);
  840. args[0] = exc;
  841. args[1] = &is_terminating;
  842. obj = Object::New(klass);
  843. Runtime::Invoke(method, obj, args, NULL);
  844. return obj;
  845. }
  846. const char *Runtime::GetBundledMachineConfig()
  847. {
  848. return s_BundledMachineConfig;
  849. }
  850. void Runtime::RegisterBundledMachineConfig(const char *config_xml)
  851. {
  852. s_BundledMachineConfig = config_xml;
  853. }
  854. void Runtime::VerifyApiVersion()
  855. {
  856. #if IL2CPP_DEBUG
  857. Il2CppClass *klass = Class::FromName(il2cpp_defaults.corlib, "System", "Environment");
  858. Class::Init(klass);
  859. FieldInfo *field = Class::GetFieldFromName(klass, "mono_corlib_version");
  860. Il2CppString* value;
  861. Field::StaticGetValue(field, &value);
  862. std::string version = il2cpp::utils::StringUtils::Utf16ToUtf8(value->chars);
  863. IL2CPP_ASSERT(version == "1A5E0066-58DC-428A-B21C-0AD6CDAE2789");
  864. #endif
  865. }
  866. int32_t Runtime::GetExitCode()
  867. {
  868. return exitcode;
  869. }
  870. void Runtime::SetExitCode(int32_t value)
  871. {
  872. exitcode = value;
  873. }
  874. static void MissingMethodInvoker(Il2CppMethodPointer ptr, const MethodInfo* method, void* obj, void** args, void* ret)
  875. {
  876. Runtime::RaiseExecutionEngineException(method, false);
  877. }
  878. InvokerMethod Runtime::GetMissingMethodInvoker()
  879. {
  880. return MissingMethodInvoker;
  881. }
  882. static int32_t IndexFromIndicesArgs(Il2CppArray* array, void** args)
  883. {
  884. int32_t rank = array->klass->rank;
  885. int32_t* indices = (int32_t*)alloca(sizeof(int32_t) * rank);
  886. for (auto i = 0; i < rank; ++i)
  887. indices[i] = *(int32_t*)args[i];
  888. return ARRAY_LENGTH_AS_INT32(vm::Array::IndexFromIndices(array, indices));
  889. }
  890. static void SetInvokerMethod(Il2CppMethodPointer methodPtr, const MethodInfo* method, void* obj, void** args, void* returnAddress)
  891. {
  892. int32_t rank = method->klass->rank;
  893. // Arrays are limited to 32 dimensions. Given this limit, we can use a stack allocated array to store the indices.
  894. // https://learn.microsoft.com/en-us/dotnet/api/system.array
  895. IL2CPP_ASSERT(rank <= 32);
  896. IL2CPP_ASSERT(method->parameters_count == (rank + 1));
  897. int32_t index = IndexFromIndicesArgs((Il2CppArray*)obj, args);
  898. Il2CppClass* elementClass = method->klass->element_class;
  899. void* value = args[rank];
  900. if (Class::IsValuetype(elementClass))
  901. {
  902. // In the case of Nullable<T>, the 'value' is the Nullable<T> instance not T.
  903. // This allows us to treat Nullable<T> as a normal value type for the purposes
  904. // of array element setting.
  905. int elementSize = vm::Class::GetArrayElementSize(elementClass);
  906. il2cpp_array_setrefwithsize((Il2CppArray*)obj, elementSize, index, value);
  907. }
  908. else
  909. {
  910. il2cpp_array_setref((Il2CppArray*)obj, index, value);
  911. }
  912. }
  913. InvokerMethod Runtime::GetArraySetInvoker()
  914. {
  915. return &SetInvokerMethod;
  916. }
  917. static void ArrayGetInvoker(Il2CppMethodPointer methodPtr, const MethodInfo* method, void* obj, void** args, void* returnAddress)
  918. {
  919. int32_t rank = method->klass->rank;
  920. // Arrays are limited to 32 dimensions. Given this limit, we can use a stack allocated array to store the indices.
  921. // https://learn.microsoft.com/en-us/dotnet/api/system.array
  922. IL2CPP_ASSERT(rank <= 32);
  923. IL2CPP_ASSERT(method->parameters_count == rank);
  924. int32_t index = IndexFromIndicesArgs((Il2CppArray*)obj, args);
  925. Il2CppClass* elementClass = method->klass->element_class;
  926. void* addr = il2cpp_array_addr_with_size((Il2CppArray*)obj, vm::Class::GetArrayElementSize(elementClass), index);
  927. if (Class::IsValuetype(elementClass))
  928. {
  929. // In the case of Nullable<T>, the 'value' is the Nullable<T> instance not T.
  930. // This allows us to treat Nullable<T> as a normal value type for the purposes
  931. // of array element setting.
  932. int elementSize = vm::Class::GetArrayElementSize(elementClass);
  933. memcpy(returnAddress, addr, elementSize);
  934. gc::GarbageCollector::SetWriteBarrier((void**)returnAddress, elementSize);
  935. }
  936. else
  937. {
  938. gc::WriteBarrier::GenericStore((void**)returnAddress, *(void**)addr);
  939. }
  940. }
  941. InvokerMethod Runtime::GetArrayGetInvoker()
  942. {
  943. return &ArrayGetInvoker;
  944. }
  945. void Runtime::AlwaysRaiseExecutionEngineException(const MethodInfo* method)
  946. {
  947. RaiseExecutionEngineException(method, false);
  948. }
  949. void Runtime::AlwaysRaiseExecutionEngineExceptionOnVirtualCall(const MethodInfo* method)
  950. {
  951. RaiseExecutionEngineException(method, true);
  952. }
  953. void Runtime::RaiseExecutionEngineException(const MethodInfo* method, bool virtualCall)
  954. {
  955. if (Method::GetClass(method))
  956. RaiseExecutionEngineException(method, Method::GetFullName(method).c_str(), virtualCall);
  957. else
  958. RaiseExecutionEngineException(method, Method::GetNameWithGenericTypes(method).c_str(), virtualCall);
  959. }
  960. void Runtime::RaiseAmbiguousImplementationException(const MethodInfo* method)
  961. {
  962. if (method != NULL && !Method::IsAmbiguousMethodInfo(method))
  963. Exception::Raise(Exception::GetAmbiguousImplementationException(utils::StringUtils::Printf("Attempting to call default interface method for '%s' with ambiguous implementations", Method::GetFullName(method).c_str()).c_str()));
  964. else
  965. Exception::Raise(Exception::GetAmbiguousImplementationException("Attempting to call default interface method with ambiguous implementations"));
  966. }
  967. void Runtime::RaiseExecutionEngineException(const MethodInfo* method, const char* methodFullName, bool virtualCall)
  968. {
  969. if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
  970. {
  971. // Default Interface Method support will throw EntryPointNotFoundExceptions if an abstract interface method is accessed
  972. Exception::Raise(Exception::GetEntryPointNotFoundException(utils::StringUtils::Printf("Attempting to call abstract method '%s'", methodFullName).c_str()));
  973. }
  974. else if (method->methodPointer)
  975. {
  976. if (method->is_unmanaged_callers_only)
  977. Exception::Raise(Exception::GetExecutionEngineException(utils::StringUtils::Printf("Cannot call a method marked with [UnmangedCallersOnly] from managed code: '%s'", methodFullName).c_str()));
  978. else
  979. Exception::Raise(Exception::GetExecutionEngineException(utils::StringUtils::Printf("Invalid call to method '%s'", methodFullName).c_str()));
  980. }
  981. else
  982. {
  983. std::string help = "";
  984. if (virtualCall && (method->flags & METHOD_ATTRIBUTE_VIRTUAL) && method->is_inflated)
  985. help = utils::StringUtils::Printf(" Consider increasing the --generic-virtual-method-iterations=%d argument", metadata::GenericMetadata::GetGenericVirtualIterations());
  986. Exception::Raise(Exception::GetExecutionEngineException(utils::StringUtils::Printf("Attempting to call method '%s' for which no ahead of time (AOT) code was generated.%s", methodFullName, help.c_str()).c_str()));
  987. }
  988. }
  989. } /* namespace vm */
  990. } /* namespace il2cpp */