Runtime.cpp 49 KB

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