12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124 |
- #include "il2cpp-config.h"
- #include "metadata/GenericMethod.h"
- #include "os/CrashHelpers.h"
- #include "os/Environment.h"
- #include "os/File.h"
- #include "os/Image.h"
- #include "os/Initialize.h"
- #include "os/LibraryLoader.h"
- #include "os/Locale.h"
- #include "os/MemoryMappedFile.h"
- #include "os/Mutex.h"
- #include "os/Path.h"
- #include "os/SynchronizationContext.h"
- #include "os/Thread.h"
- #include "os/Socket.h"
- #include "os/c-api/Allocator.h"
- #include "metadata/GenericMetadata.h"
- #include "vm/Array.h"
- #include "vm/Assembly.h"
- #include "vm/ClassLibraryPAL.h"
- #include "vm/COMEntryPoints.h"
- #include "vm/Class.h"
- #include "vm/Domain.h"
- #include "vm/Exception.h"
- #include "vm/Field.h"
- #include "gc/GCHandle.h"
- #include "vm/Image.h"
- #include "vm/LastError.h"
- #include "vm/MetadataAlloc.h"
- #include "vm/MetadataCache.h"
- #include "vm/MetadataLock.h"
- #include "vm/Method.h"
- #include "vm/Reflection.h"
- #include "vm/Runtime.h"
- #include "vm/Thread.h"
- #include "vm/Type.h"
- #include "vm/StackTrace.h"
- #include "vm/String.h"
- #include "vm/Object.h"
- #include "vm-utils/Debugger.h"
- #include "vm-utils/DebugSymbolReader.h"
- #include "vm/Profiler.h"
- #include "utils/Logging.h"
- #include <string>
- #include <map>
- #include "il2cpp-class-internals.h"
- #include "il2cpp-object-internals.h"
- #include "il2cpp-tabledefs.h"
- #include "gc/GarbageCollector.h"
- #include "gc/WriteBarrier.h"
- #include "vm/InternalCalls.h"
- #include "utils/Collections.h"
- #include "utils/Memory.h"
- #include "utils/StringUtils.h"
- #include "utils/PathUtils.h"
- #include "utils/Runtime.h"
- #include "utils/Environment.h"
- #include "mono/ThreadPool/threadpool-ms.h"
- #include "mono/ThreadPool/threadpool-ms-io.h"
- //#include "icalls/mscorlib/System.Reflection/Assembly.h"
- #include "Baselib.h"
- #include "Cpp/ReentrantLock.h"
- Il2CppDefaults il2cpp_defaults;
- bool g_il2cpp_is_fully_initialized = false;
- static bool shutting_down = false;
- MetadataInitializerCleanupFunc g_ClearMethodMetadataInitializedFlags = NULL;
- static baselib::ReentrantLock s_InitLock;
- static int32_t s_RuntimeInitCount;
- typedef void (*CodegenRegistrationFunction) ();
- extern CodegenRegistrationFunction g_CodegenRegistration;
- namespace il2cpp
- {
- namespace vm
- {
- baselib::ReentrantLock g_MetadataLock;
- static int32_t exitcode = 0;
- static std::string s_ConfigDir;
- static const char *s_FrameworkVersion = 0;
- static const char *s_BundledMachineConfig = 0;
- static Il2CppRuntimeUnhandledExceptionPolicy s_UnhandledExceptionPolicy = IL2CPP_UNHANDLED_POLICY_CURRENT;
- static const void* s_UnitytlsInterface = NULL;
- #define DEFAULTS_INIT(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib, ns, n);\
- IL2CPP_ASSERT(il2cpp_defaults.field); } while (0)
- #define DEFAULTS_INIT_TYPE(field, ns, n, nativetype) do { DEFAULTS_INIT(field, ns, n); \
- IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
- #define DEFAULTS_INIT_OPTIONAL(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib, ns, n); } while (0)
- #define DEFAULTS_INIT_TYPE_OPTIONAL(field, ns, n, nativetype) do { DEFAULTS_INIT_OPTIONAL(field, ns, n); \
- if (il2cpp_defaults.field != NULL) \
- IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
- #define DEFAULTS_GEN_INIT(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib_gen, ns, n);\
- IL2CPP_ASSERT(il2cpp_defaults.field); } while (0)
- #define DEFAULTS_GEN_INIT_TYPE(field, ns, n, nativetype) do { DEFAULTS_GEN_INIT(field, ns, n); \
- IL2CPP_ASSERT(il2cpp_defaults.field->instance_size == sizeof(nativetype) + (il2cpp_defaults.field->byval_arg.valuetype ? sizeof(Il2CppObject) : 0)); } while (0)
- #define DEFAULTS_GEN_INIT_OPTIONAL(field, ns, n) do { il2cpp_defaults.field = Class::FromName (il2cpp_defaults.corlib_gen, ns, n); } while (0)
- char* basepath(const char* path)
- {
- std::string original_path(path);
- size_t position_of_last_separator = original_path.find_last_of(IL2CPP_DIR_SEPARATOR);
- return il2cpp::utils::StringUtils::StringDuplicate(original_path.substr(position_of_last_separator + 1).c_str());
- }
- static const char *framework_version_for(const char *runtime_version)
- {
- IL2CPP_ASSERT(runtime_version && "Invalid runtime version");
- IL2CPP_ASSERT((strstr(runtime_version, "v4.0") == runtime_version) && "Invalid runtime version");
- return "4.0";
- }
- static void SanityChecks()
- {
- #if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
- IL2CPP_ASSERT(ALIGN_OF(int64_t) == 8);
- #endif
- }
- static inline void InitializeStringEmpty()
- {
- Class::Init(il2cpp_defaults.string_class);
- FieldInfo* stringEmptyField = Class::GetFieldFromName(il2cpp_defaults.string_class, "Empty");
- Field::StaticSetValue(stringEmptyField, String::Empty());
- }
- static void SetConfigStr(const std::string& executablePath);
- bool Runtime::Init(const char* domainName)
- {
- os::FastAutoLock lock(&s_InitLock);
- IL2CPP_ASSERT(s_RuntimeInitCount >= 0);
- if (s_RuntimeInitCount++ > 0)
- return true;
- SanityChecks();
- os::Initialize();
- os::Locale::Initialize();
- MetadataAllocInitialize();
- // NOTE(gab): the runtime_version needs to change once we
- // will support multiple runtimes.
- // For now we default to the one used by unity and don't
- // allow the callers to change it.
- s_FrameworkVersion = framework_version_for("v4.0.30319");
- os::Image::Initialize();
- os::Thread::Init();
- #if IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT
- // Has to happen after Thread::Init() due to it needing a COM apartment on Windows
- il2cpp::os::SynchronizationContext::Initialize();
- #endif
- // This should be filled in by generated code.
- IL2CPP_ASSERT(g_CodegenRegistration != NULL);
- g_CodegenRegistration();
- if (!MetadataCache::Initialize())
- {
- s_RuntimeInitCount--;
- return false;
- }
- Assembly::Initialize();
- gc::GarbageCollector::Initialize();
- // Thread needs GC initialized
- Thread::Initialize();
- register_allocator(il2cpp::utils::Memory::Malloc, il2cpp::utils::Memory::Free);
- memset(&il2cpp_defaults, 0, sizeof(Il2CppDefaults));
- const Il2CppAssembly* assembly = Assembly::Load("mscorlib.dll");
- const Il2CppAssembly* assembly2 = Assembly::Load("__Generated");
- // It is not possible to use DEFAULTS_INIT_TYPE for managed types for which we have a native struct, if the
- // native struct does not map the complete managed type.
- // Which is the case for: Il2CppThread, Il2CppAppDomain, Il2CppCultureInfo, Il2CppReflectionProperty,
- // Il2CppDateTimeFormatInfo, Il2CppNumberFormatInfo
- il2cpp_defaults.corlib = Assembly::GetImage(assembly);
- il2cpp_defaults.corlib_gen = Assembly::GetImage(assembly2);
- DEFAULTS_INIT(object_class, "System", "Object");
- DEFAULTS_INIT(void_class, "System", "Void");
- DEFAULTS_INIT_TYPE(boolean_class, "System", "Boolean", bool);
- DEFAULTS_INIT_TYPE(byte_class, "System", "Byte", uint8_t);
- DEFAULTS_INIT_TYPE(sbyte_class, "System", "SByte", int8_t);
- DEFAULTS_INIT_TYPE(int16_class, "System", "Int16", int16_t);
- DEFAULTS_INIT_TYPE(uint16_class, "System", "UInt16", uint16_t);
- DEFAULTS_INIT_TYPE(int32_class, "System", "Int32", int32_t);
- DEFAULTS_INIT_TYPE(uint32_class, "System", "UInt32", uint32_t);
- DEFAULTS_INIT(uint_class, "System", "UIntPtr");
- DEFAULTS_INIT_TYPE(int_class, "System", "IntPtr", intptr_t);
- DEFAULTS_INIT_TYPE(int64_class, "System", "Int64", int64_t);
- DEFAULTS_INIT_TYPE(uint64_class, "System", "UInt64", uint64_t);
- DEFAULTS_INIT_TYPE(single_class, "System", "Single", float);
- DEFAULTS_INIT_TYPE(double_class, "System", "Double", double);
- DEFAULTS_INIT_TYPE(char_class, "System", "Char", Il2CppChar);
- DEFAULTS_INIT(string_class, "System", "String");
- DEFAULTS_INIT(enum_class, "System", "Enum");
- DEFAULTS_INIT(array_class, "System", "Array");
- DEFAULTS_INIT(value_type_class, "System", "ValueType");
- #if !IL2CPP_TINY
- DEFAULTS_INIT_TYPE(delegate_class, "System", "Delegate", Il2CppDelegate);
- DEFAULTS_INIT_TYPE(multicastdelegate_class, "System", "MulticastDelegate", Il2CppMulticastDelegate);
- DEFAULTS_INIT(asyncresult_class, "System.Runtime.Remoting.Messaging", "AsyncResult");
- DEFAULTS_INIT_TYPE(async_call_class, "System", "MonoAsyncCall", Il2CppAsyncCall);
- DEFAULTS_INIT(manualresetevent_class, "System.Threading", "ManualResetEvent");
- #endif // !IL2CPP_TINY
- //DEFAULTS_INIT(typehandle_class, "System", "RuntimeTypeHandle");
- //DEFAULTS_INIT(methodhandle_class, "System", "RuntimeMethodHandle");
- //DEFAULTS_INIT(fieldhandle_class, "System", "RuntimeFieldHandle");
- DEFAULTS_INIT(systemtype_class, "System", "Type");
- #if !IL2CPP_TINY
- DEFAULTS_INIT_TYPE(monotype_class, "System", "MonoType", Il2CppReflectionMonoType);
- #endif
- //DEFAULTS_INIT(exception_class, "System", "Exception");
- //DEFAULTS_INIT(threadabortexcepXtion_class, "System.Threading", "ThreadAbortException");
- DEFAULTS_INIT_TYPE(thread_class, "System.Threading", "Thread", Il2CppThread);
- DEFAULTS_INIT_TYPE(internal_thread_class, "System.Threading", "InternalThread", Il2CppInternalThread);
- DEFAULTS_INIT_TYPE(runtimetype_class, "System", "RuntimeType", Il2CppReflectionRuntimeType);
- #if !IL2CPP_TINY
- DEFAULTS_INIT(appdomain_class, "System", "AppDomain");
- DEFAULTS_INIT(appdomain_setup_class, "System", "AppDomainSetup");
- DEFAULTS_INIT(member_info_class, "System.Reflection", "MemberInfo");
- DEFAULTS_INIT(field_info_class, "System.Reflection", "FieldInfo");
- DEFAULTS_INIT(method_info_class, "System.Reflection", "MethodInfo");
- DEFAULTS_INIT(property_info_class, "System.Reflection", "PropertyInfo");
- DEFAULTS_INIT_TYPE(event_info_class, "System.Reflection", "EventInfo", Il2CppReflectionEvent);
- DEFAULTS_INIT_TYPE(stringbuilder_class, "System.Text", "StringBuilder", Il2CppStringBuilder);
- DEFAULTS_INIT_TYPE(stack_frame_class, "System.Diagnostics", "StackFrame", Il2CppStackFrame);
- DEFAULTS_INIT(stack_trace_class, "System.Diagnostics", "StackTrace");
- DEFAULTS_INIT_TYPE(typed_reference_class, "System", "TypedReference", Il2CppTypedRef);
- #endif
- DEFAULTS_INIT(generic_ilist_class, "System.Collections.Generic", "IList`1");
- DEFAULTS_INIT(generic_icollection_class, "System.Collections.Generic", "ICollection`1");
- DEFAULTS_INIT(generic_ienumerable_class, "System.Collections.Generic", "IEnumerable`1");
- DEFAULTS_INIT(generic_ireadonlylist_class, "System.Collections.Generic", "IReadOnlyList`1");
- DEFAULTS_INIT(generic_ireadonlycollection_class, "System.Collections.Generic", "IReadOnlyCollection`1");
- DEFAULTS_INIT(generic_nullable_class, "System", "Nullable`1");
- #if !IL2CPP_TINY
- DEFAULTS_INIT(version, "System", "Version");
- DEFAULTS_INIT(culture_info, "System.Globalization", "CultureInfo");
- DEFAULTS_INIT_TYPE(assembly_class, "System.Reflection", "RuntimeAssembly", Il2CppReflectionAssembly);
- DEFAULTS_INIT_TYPE_OPTIONAL(assembly_name_class, "System.Reflection", "AssemblyName", Il2CppReflectionAssemblyName);
- DEFAULTS_INIT_TYPE(parameter_info_class, "System.Reflection", "RuntimeParameterInfo", Il2CppReflectionParameter);
- DEFAULTS_INIT_TYPE(module_class, "System.Reflection", "RuntimeModule", Il2CppReflectionModule);
- DEFAULTS_INIT_TYPE(exception_class, "System", "Exception", Il2CppException);
- DEFAULTS_INIT_TYPE(system_exception_class, "System", "SystemException", Il2CppSystemException);
- DEFAULTS_INIT_TYPE(argument_exception_class, "System", "ArgumentException", Il2CppArgumentException);
- DEFAULTS_INIT_TYPE(marshalbyrefobject_class, "System", "MarshalByRefObject", Il2CppMarshalByRefObject);
- DEFAULTS_GEN_INIT_TYPE(il2cpp_com_object_class, "System", "__Il2CppComObject", Il2CppComObject);
- DEFAULTS_INIT_TYPE(safe_handle_class, "System.Runtime.InteropServices", "SafeHandle", Il2CppSafeHandle);
- DEFAULTS_INIT_TYPE(sort_key_class, "System.Globalization", "SortKey", Il2CppSortKey);
- DEFAULTS_INIT(dbnull_class, "System", "DBNull");
- DEFAULTS_INIT_TYPE_OPTIONAL(error_wrapper_class, "System.Runtime.InteropServices", "ErrorWrapper", Il2CppErrorWrapper);
- DEFAULTS_INIT(missing_class, "System.Reflection", "Missing");
- DEFAULTS_INIT(attribute_class, "System", "Attribute");
- DEFAULTS_INIT_OPTIONAL(customattribute_data_class, "System.Reflection", "CustomAttributeData");
- DEFAULTS_INIT_OPTIONAL(customattribute_typed_argument_class, "System.Reflection", "CustomAttributeTypedArgument");
- DEFAULTS_INIT_OPTIONAL(customattribute_named_argument_class, "System.Reflection", "CustomAttributeNamedArgument");
- DEFAULTS_INIT(key_value_pair_class, "System.Collections.Generic", "KeyValuePair`2");
- DEFAULTS_INIT(system_guid_class, "System", "Guid");
- #endif // !IL2CPP_TINY
- #if !IL2CPP_TINY
- DEFAULTS_INIT(threadpool_wait_callback_class, "System.Threading", "_ThreadPoolWaitCallback");
- DEFAULTS_INIT(mono_method_message_class, "System.Runtime.Remoting.Messaging", "MonoMethodMessage");
- il2cpp_defaults.threadpool_perform_wait_callback_method = (MethodInfo*)vm::Class::GetMethodFromName(
- il2cpp_defaults.threadpool_wait_callback_class, "PerformWaitCallback", 0);
- #endif
- DEFAULTS_INIT_OPTIONAL(sbyte_shared_enum, "System", "SByteEnum");
- DEFAULTS_INIT_OPTIONAL(int16_shared_enum, "System", "Int16Enum");
- DEFAULTS_INIT_OPTIONAL(int32_shared_enum, "System", "Int32Enum");
- DEFAULTS_INIT_OPTIONAL(int64_shared_enum, "System", "Int64Enum");
- DEFAULTS_INIT_OPTIONAL(byte_shared_enum, "System", "ByteEnum");
- DEFAULTS_INIT_OPTIONAL(uint16_shared_enum, "System", "UInt16Enum");
- DEFAULTS_INIT_OPTIONAL(uint32_shared_enum, "System", "UInt32Enum");
- DEFAULTS_INIT_OPTIONAL(uint64_shared_enum, "System", "UInt64Enum");
- DEFAULTS_GEN_INIT_OPTIONAL(il2cpp_fully_shared_type, "Unity.IL2CPP.Metadata", "__Il2CppFullySharedGenericType");
- DEFAULTS_GEN_INIT_OPTIONAL(il2cpp_fully_shared_struct_type, "Unity.IL2CPP.Metadata", "__Il2CppFullySharedGenericStructType");
- ClassLibraryPAL::Initialize();
- // Reflection needs GC initialized
- Reflection::Initialize();
- Image::InitNestedTypes(il2cpp_defaults.corlib);
- const Il2CppAssembly* systemDll = Assembly::Load("System");
- if (systemDll != NULL)
- il2cpp_defaults.system_uri_class = Class::FromName(Assembly::GetImage(systemDll), "System", "Uri");
- // This will only exist if there was at least 1 winmd file present during conversion
- const Il2CppAssembly* windowsRuntimeMetadataAssembly = Assembly::Load("WindowsRuntimeMetadata");
- if (windowsRuntimeMetadataAssembly != NULL)
- {
- const Il2CppImage* windowsRuntimeMetadataImage = Assembly::GetImage(windowsRuntimeMetadataAssembly);
- il2cpp_defaults.ireference_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IReference`1");
- il2cpp_defaults.ireferencearray_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IReferenceArray`1");
- il2cpp_defaults.ikey_value_pair_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation.Collections", "IKeyValuePair`2");
- il2cpp_defaults.ikey_value_pair_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation.Collections", "IKeyValuePair`2");
- il2cpp_defaults.windows_foundation_uri_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "Uri");
- il2cpp_defaults.windows_foundation_iuri_runtime_class_class = Class::FromName(windowsRuntimeMetadataImage, "Windows.Foundation", "IUriRuntimeClass");
- }
- Class::Init(il2cpp_defaults.string_class);
- os::Socket::Startup();
- #if IL2CPP_MONO_DEBUGGER
- il2cpp::utils::Debugger::Init();
- #endif
- Il2CppDomain* domain = Domain::GetCurrent();
- Il2CppThread* mainThread = Thread::Attach(domain);
- Thread::SetMain(mainThread);
- #if !IL2CPP_TINY
- Il2CppAppDomainSetup* setup = (Il2CppAppDomainSetup*)Object::NewPinned(il2cpp_defaults.appdomain_setup_class);
- Il2CppAppDomain* ad = (Il2CppAppDomain*)Object::NewPinned(il2cpp_defaults.appdomain_class);
- gc::WriteBarrier::GenericStore(&ad->data, domain);
- gc::WriteBarrier::GenericStore(&domain->domain, ad);
- gc::WriteBarrier::GenericStore(&domain->setup, setup);
- #endif
- domain->domain_id = 1; // Only have a single domain ATM.
- domain->friendly_name = basepath(domainName);
- LastError::InitializeLastErrorThreadStatic();
- gc::GarbageCollector::InitializeFinalizer();
- MetadataCache::InitializeGCSafe();
- String::InitializeEmptyString(il2cpp_defaults.string_class);
- InitializeStringEmpty();
- g_il2cpp_is_fully_initialized = true;
- // Force binary serialization in Mono to use reflection instead of code generation.
- #undef SetEnvironmentVariable // Get rid of windows.h #define.
- os::Environment::SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
- os::Environment::SetEnvironmentVariable("MONO_XMLSERIALIZER_THS", "no");
- #if !IL2CPP_TINY
- Domain::ContextInit(domain);
- Domain::ContextSet(domain->default_context);
- #endif
- VerifyApiVersion();
- #if IL2CPP_MONO_DEBUGGER
- il2cpp::utils::Debugger::Start();
- #endif
- std::string executablePath = os::Path::GetExecutablePath();
- SetConfigStr(executablePath);
- if (utils::Environment::GetNumMainArgs() == 0)
- {
- // If main args were never set, we default to 1 arg that is the executable path
- const char* mainArgs[] = { executablePath.c_str() };
- utils::Environment::SetMainArgs(mainArgs, 1);
- }
- vm::MetadataCache::ExecuteEagerStaticClassConstructors();
- vm::MetadataCache::ExecuteModuleInitializers();
- #if !IL2CPP_TINY && !IL2CPP_MONO_DEBUGGER
- il2cpp::utils::DebugSymbolReader::LoadDebugSymbols();
- #endif
- return true;
- }
- static Il2CppObject* GetEventArgsEmptyField()
- {
- Il2CppClass* eventArgsKlass = Class::FromName(il2cpp_defaults.corlib, "System", "EventArgs");
- if (eventArgsKlass != NULL)
- {
- Class::Init(eventArgsKlass);
- FieldInfo* emptyField = vm::Class::GetFieldFromName(eventArgsKlass, "Empty");
- if (emptyField != NULL)
- {
- Il2CppObject* emptyValue;
- vm::Field::StaticGetValue(emptyField, &emptyValue);
- return emptyValue;
- }
- }
- return NULL;
- }
- static void FireProcessExitEvent()
- {
- FieldInfo* processExitField = vm::Class::GetFieldFromName(il2cpp_defaults.appdomain_class, "ProcessExit");
- if (processExitField != NULL) // The field might have been stripped, just ignore it.
- {
- Il2CppAppDomain* appDomain = vm::Domain::GetCurrent()->domain;
- Il2CppDelegate* processExitDelegate;
- vm::Field::GetValue((Il2CppObject*)appDomain, processExitField, &processExitDelegate);
- if (processExitDelegate == NULL) // Don't call the delegate if no one is listening to it.
- return;
- void* args[2];
- args[0] = appDomain;
- args[1] = GetEventArgsEmptyField();
- Il2CppException* unusedException;
- Runtime::DelegateInvoke(processExitDelegate, args, &unusedException);
- }
- }
- void Runtime::Shutdown()
- {
- os::FastAutoLock lock(&s_InitLock);
- IL2CPP_ASSERT(s_RuntimeInitCount > 0);
- if (--s_RuntimeInitCount > 0)
- return;
- FireProcessExitEvent();
- shutting_down = true;
- #if IL2CPP_ENABLE_PROFILER
- il2cpp::vm::Profiler::Shutdown();
- #endif
- #if IL2CPP_MONO_DEBUGGER
- il2cpp::utils::Debugger::RuntimeShutdownEnd();
- #endif
- #if IL2CPP_SUPPORT_THREADS
- threadpool_ms_cleanup();
- #endif
- // Tries to abort all threads
- // Threads at alertable waits may not have existing when this return
- Thread::AbortAllThreads();
- os::Socket::Cleanup();
- String::CleanupEmptyString();
- il2cpp::gc::GarbageCollector::UninitializeFinalizers();
- // after the gc cleanup so the finalizer thread can unregister itself
- Thread::Uninitialize();
- #if IL2CPP_HAS_OS_SYNCHRONIZATION_CONTEXT
- // Has to happen before os::Thread::Shutdown() due to it needing a COM apartment on Windows
- il2cpp::os::SynchronizationContext::Shutdown();
- #endif
- os::Thread::Shutdown();
- #if IL2CPP_ENABLE_RELOAD
- MetadataCache::Clear();
- #endif
- // We need to do this before UninitializeGC because it uses (fixed) GC memory
- Reflection::ClearStatics();
- // We need to do this after thread shut down because it is freeing GC fixed memory
- il2cpp::gc::GarbageCollector::UninitializeGC();
- // This needs to happen after no managed code can run anymore, including GC finalizers
- os::LibraryLoader::CleanupLoadedLibraries();
- vm::Image::ClearCachedResourceData();
- MetadataAllocCleanup();
- vm::COMEntryPoints::FreeCachedData();
- os::Locale::UnInitialize();
- os::Uninitialize();
- #if IL2CPP_ENABLE_RELOAD
- if (g_ClearMethodMetadataInitializedFlags != NULL)
- g_ClearMethodMetadataInitializedFlags();
- #endif
- }
- bool Runtime::IsShuttingDown()
- {
- return shutting_down;
- }
- void Runtime::SetConfigDir(const char *path)
- {
- s_ConfigDir = path;
- }
- static void SetConfigStr(const std::string& executablePath)
- {
- #if !IL2CPP_TINY
- Il2CppDomain* domain = vm::Domain::GetCurrent();
- std::string configFileName = utils::PathUtils::Basename(executablePath);
- configFileName.append(".config");
- std::string appBase = utils::PathUtils::DirectoryName(executablePath);
- IL2CPP_OBJECT_SETREF(domain->setup, application_base, vm::String::New(appBase.c_str()));
- IL2CPP_OBJECT_SETREF(domain->setup, configuration_file, vm::String::New(configFileName.c_str()));
- #endif
- }
- void Runtime::SetConfigUtf16(const Il2CppChar* executablePath)
- {
- IL2CPP_ASSERT(executablePath);
- std::string exePathUtf8 = il2cpp::utils::StringUtils::Utf16ToUtf8(executablePath);
- SetConfigStr(exePathUtf8);
- }
- void Runtime::SetConfig(const char* executablePath)
- {
- IL2CPP_ASSERT(executablePath);
- std::string executablePathStr(executablePath);
- SetConfigStr(executablePathStr);
- }
- void Runtime::SetUnityTlsInterface(const void* unitytlsInterface)
- {
- s_UnitytlsInterface = unitytlsInterface;
- }
- const char *Runtime::GetFrameworkVersion()
- {
- return s_FrameworkVersion;
- }
- std::string Runtime::GetConfigDir()
- {
- if (s_ConfigDir.size() > 0)
- return s_ConfigDir;
- return utils::PathUtils::Combine(utils::Runtime::GetDataDir(), utils::StringView<char>("etc"));
- }
- const void* Runtime::GetUnityTlsInterface()
- {
- return s_UnitytlsInterface;
- }
- const MethodInfo* Runtime::GetDelegateInvoke(Il2CppClass* klass)
- {
- const MethodInfo* invoke = Class::GetMethodFromName(klass, "Invoke", -1);
- IL2CPP_ASSERT(invoke);
- return invoke;
- }
- Il2CppObject* Runtime::DelegateInvoke(Il2CppDelegate *delegate, void **params, Il2CppException **exc)
- {
- const MethodInfo* invoke = GetDelegateInvoke(delegate->object.klass);
- return Invoke(invoke, delegate, params, exc);
- }
- Il2CppObject* Runtime::Invoke(const MethodInfo *method, void *obj, void **params, Il2CppException **exc)
- {
- if (exc)
- il2cpp::gc::WriteBarrier::GenericStoreNull(exc);
- // we wrap invoker call in try/catch here, rather than emitting a try/catch
- // in every invoke call as that blows up the code size.
- try
- {
- if ((method->flags & METHOD_ATTRIBUTE_STATIC) && method->klass && !method->klass->cctor_finished_or_no_cctor)
- ClassInit(method->klass);
- return InvokeWithThrow(method, obj, params);
- }
- catch (Il2CppExceptionWrapper& ex)
- {
- if (exc)
- il2cpp::gc::WriteBarrier::GenericStore(exc, ex.ex);
- return NULL;
- }
- }
- Il2CppObject* Runtime::InvokeWithThrow(const MethodInfo *method, void *obj, void **params)
- {
- if (method->return_type->type == IL2CPP_TYPE_VOID)
- {
- method->invoker_method(method->methodPointer, method, obj, params, NULL);
- return NULL;
- }
- else
- {
- if (method->return_type->valuetype)
- {
- Il2CppClass* returnType = Class::FromIl2CppType(method->return_type);
- Class::Init(returnType);
- void* returnValue = alloca(returnType->instance_size - sizeof(Il2CppObject));
- method->invoker_method(method->methodPointer, method, obj, params, returnValue);
- return Object::Box(returnType, returnValue);
- }
- else
- {
- // Note that here method->return_type might be a reference type or it might be
- // a value type returned by reference.
- void* returnValue = NULL;
- method->invoker_method(method->methodPointer, method, obj, params, &returnValue);
- if (method->return_type->byref)
- {
- // We cannot use method->return_type->valuetype here, because that will be
- // false for methods that return by reference. Instead, get the class for the
- // type, which discards the byref flag.
- Il2CppClass* returnType = Class::FromIl2CppType(method->return_type);
- if (vm::Class::IsValuetype(returnType))
- return Object::Box(returnType, returnValue);
- return *(Il2CppObject**)returnValue;
- }
- return (Il2CppObject*)returnValue;
- }
- }
- }
- Il2CppObject* Runtime::InvokeArray(const MethodInfo *method, void *obj, Il2CppArray *params, Il2CppException **exc)
- {
- if (params == NULL)
- return InvokeConvertArgs(method, obj, NULL, 0, exc);
- // TO DO: when changing GC to one that moves managed objects around, mark params array local variable as pinned!
- return InvokeConvertArgs(method, obj, reinterpret_cast<Il2CppObject**>(Array::GetFirstElementAddress(params)), Array::GetLength(params), exc);
- }
- void Runtime::ObjectInit(Il2CppObject *object)
- {
- ObjectInitException(object, NULL);
- }
- void Runtime::ObjectInitException(Il2CppObject *object, Il2CppException **exc)
- {
- const MethodInfo *method = NULL;
- Il2CppClass *klass = object->klass;
- method = Class::GetMethodFromName(klass, ".ctor", 0);
- IL2CPP_ASSERT(method != NULL && "ObjectInit; no default constructor for object is found");
- if (method->klass->byval_arg.valuetype)
- object = (Il2CppObject*)Object::Unbox(object);
- Invoke(method, object, NULL, exc);
- }
- void Runtime::SetUnhandledExceptionPolicy(Il2CppRuntimeUnhandledExceptionPolicy value)
- {
- s_UnhandledExceptionPolicy = value;
- }
- Il2CppRuntimeUnhandledExceptionPolicy Runtime::GetUnhandledExceptionPolicy()
- {
- return s_UnhandledExceptionPolicy;
- }
- void Runtime::UnhandledException(Il2CppException* exc)
- {
- Il2CppDomain *currentDomain = Domain::GetCurrent();
- Il2CppDomain *rootDomain = Domain::GetRoot();
- FieldInfo *field;
- Il2CppObject *current_appdomain_delegate = NULL;
- Il2CppObject *root_appdomain_delegate = NULL;
- field = Class::GetFieldFromName(il2cpp_defaults.appdomain_class, "UnhandledException");
- IL2CPP_ASSERT(field);
- Il2CppObject* excObject = (Il2CppObject*)exc;
- if (excObject->klass != il2cpp_defaults.threadabortexception_class)
- {
- //bool abort_process = (Thread::Current () == Thread::Main ()) ||
- // (Runtime::GetUnhandledExceptionPolicy () == IL2CPP_UNHANDLED_POLICY_CURRENT);
- Field::GetValue((Il2CppObject*)rootDomain->domain, field, &root_appdomain_delegate);
- IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Runtime::UnhandledException, "We don't have runtime version info yet");
- //if (currentDomain != rootDomain && (mono_framework_version () >= 2)) {
- // Field::GetValue ((Il2CppObject*)currentDomain->domain, field, ¤t_appdomain_delegate);
- //}
- //else
- //{
- // current_appdomain_delegate = NULL;
- //}
- ///* set exitcode only if we will abort the process */
- //if (abort_process)
- // mono_environment_exitcode_set (1);
- //if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)
- //{
- // mono_print_unhandled_exception (exc);
- //}
- //else
- {
- if (root_appdomain_delegate)
- {
- CallUnhandledExceptionDelegate(rootDomain, (Il2CppDelegate*)root_appdomain_delegate, exc);
- }
- if (current_appdomain_delegate)
- {
- CallUnhandledExceptionDelegate(currentDomain, (Il2CppDelegate*)current_appdomain_delegate, exc);
- }
- }
- }
- }
- static inline Il2CppObject* InvokeConvertThis(const MethodInfo* method, void* thisArg, void** convertedParameters, Il2CppException** exception)
- {
- Il2CppClass* thisType = method->klass;
- // If it's not a constructor, just invoke directly
- if (strcmp(method->name, ".ctor") != 0 || method->klass == il2cpp_defaults.string_class)
- {
- void* obj = thisArg;
- if (Class::IsNullable(method->klass))
- {
- Il2CppObject* nullable;
- /* Convert the unboxed vtype into a Nullable structure */
- nullable = Object::New(method->klass);
- Il2CppObject* boxed = Object::Box(method->klass->castClass, obj);
- Object::NullableInit((uint8_t*)Object::Unbox(nullable), boxed, method->klass);
- obj = Object::Unbox(nullable);
- }
- return Runtime::Invoke(method, obj, convertedParameters, exception);
- }
- // If it is a construction, we need to construct a return value and allocate object if needed
- Il2CppObject* instance;
- if (thisArg == NULL)
- {
- if (Class::IsNullable(thisType))
- {
- // in the case of a Nullable constructor we can just return a boxed value type
- IL2CPP_ASSERT(convertedParameters);
- instance = Object::Box(thisType->castClass, convertedParameters[0]);
- }
- else
- {
- thisArg = instance = Object::New(thisType);
- Runtime::Invoke(method, thisType->byval_arg.valuetype ? Object::Unbox((Il2CppObject*)thisArg) : thisArg, convertedParameters, exception);
- }
- }
- else
- {
- // thisArg is pointer to data in case of a value type
- // We need to invoke the constructor first, passing point to the value
- // Since the constructor may modify the value, we need to box the result
- // AFTER the constructor was invoked
- Runtime::Invoke(method, thisArg, convertedParameters, exception);
- instance = Object::Box(thisType, thisArg);
- }
- return instance;
- }
- Il2CppObject* Runtime::InvokeConvertArgs(const MethodInfo *method, void* thisArg, Il2CppObject** parameters, int paramCount, Il2CppException** exception)
- {
- void** convertedParameters = NULL;
- bool hasByRefNullables = false;
- // Convert parameters if they are not null
- if (parameters != NULL)
- {
- convertedParameters = (void**)alloca(sizeof(void*) * paramCount);
- for (int i = 0; i < paramCount; i++)
- {
- bool passedByReference = method->parameters[i]->byref;
- Il2CppClass* parameterType = Class::FromIl2CppType(method->parameters[i]);
- Class::Init(parameterType);
- if (Class::IsValuetype(parameterType))
- {
- if (Class::IsNullable(parameterType))
- {
- // Since we don't really store boxed nullables, we need to create a new one.
- void* nullableStorage = alloca(parameterType->instance_size - sizeof(Il2CppObject));
- Object::UnboxNullable(parameters[i], parameterType, nullableStorage);
- convertedParameters[i] = nullableStorage;
- hasByRefNullables |= passedByReference;
- }
- else if (passedByReference)
- {
- // If value type is passed by reference, just pass pointer to value directly
- // If null was passed in, create a new boxed value type in its place
- if (parameters[i] == NULL)
- gc::WriteBarrier::GenericStore(parameters + i, Object::New(parameterType));
- convertedParameters[i] = Object::Unbox(parameters[i]);
- }
- else if (parameters[i] == NULL) // If value type is passed by value, we need to pass pointer to its value
- {
- // If null was passed in, allocate a new value with default value
- uint32_t valueSize = parameterType->instance_size - sizeof(Il2CppObject);
- convertedParameters[i] = alloca(valueSize);
- memset(convertedParameters[i], 0, valueSize);
- }
- else
- {
- // Otherwise, pass the original
- convertedParameters[i] = Object::Unbox(parameters[i]);
- }
- }
- else if (passedByReference)
- {
- convertedParameters[i] = ¶meters[i]; // Reference type passed by reference
- }
- else if (parameterType->byval_arg.type == IL2CPP_TYPE_PTR)
- {
- if (parameters[i] != NULL)
- {
- IL2CPP_ASSERT(parameters[i]->klass == il2cpp_defaults.int_class);
- convertedParameters[i] = reinterpret_cast<void*>(*static_cast<intptr_t*>(Object::Unbox(parameters[i])));
- }
- else
- {
- convertedParameters[i] = NULL;
- }
- }
- else
- {
- convertedParameters[i] = parameters[i]; // Reference type passed by value
- }
- }
- }
- Il2CppObject* result = InvokeConvertThis(method, thisArg, convertedParameters, exception);
- if (hasByRefNullables)
- {
- // We need to copy by reference nullables back to original argument array
- for (int i = 0; i < paramCount; i++)
- {
- if (!method->parameters[i]->byref)
- continue;
- Il2CppClass* parameterType = Class::FromIl2CppType(method->parameters[i]);
- if (Class::IsNullable(parameterType))
- gc::WriteBarrier::GenericStore(parameters + i, Object::Box(parameterType, convertedParameters[i]));
- }
- }
- if (method->return_type->type == IL2CPP_TYPE_PTR)
- {
- static Il2CppClass* pointerClass = Class::FromName(il2cpp_defaults.corlib, "System.Reflection", "Pointer");
- Il2CppReflectionPointer* pointer = reinterpret_cast<Il2CppReflectionPointer*>(Object::New(pointerClass));
- pointer->data = result;
- IL2CPP_OBJECT_SETREF(pointer, type, Reflection::GetTypeObject(method->return_type));
- result = reinterpret_cast<Il2CppObject*>(pointer);
- }
- return result;
- }
- void Runtime::CallUnhandledExceptionDelegate(Il2CppDomain* domain, Il2CppDelegate* delegate, Il2CppException* exc)
- {
- Il2CppException *e = NULL;
- void* pa[2];
- pa[0] = domain->domain;
- pa[1] = CreateUnhandledExceptionEventArgs(exc);
- DelegateInvoke(delegate, pa, &e);
- // A managed exception occurred during the unhandled exception handler.
- // We can't do much else here other than try to abort the process.
- if (e != NULL)
- utils::Runtime::Abort();
- }
- static baselib::ReentrantLock s_TypeInitializationLock;
- // We currently call Runtime::ClassInit in 4 places:
- // 1. Just after we allocate storage for a new object (Object::NewAllocSpecific)
- // 2. Just before reading any static field
- // 3. Just before calling any static method
- // 4. Just before calling class instance constructor from a derived class instance constructor
- void Runtime::ClassInit(Il2CppClass *klass)
- {
- // Nothing to do if class has no static constructor or already ran.
- if (klass->cctor_finished_or_no_cctor)
- return;
- s_TypeInitializationLock.Acquire();
- // See if some thread ran it while we acquired the lock.
- if (os::Atomic::CompareExchange(&klass->cctor_finished_or_no_cctor, 1, 1) == 1)
- {
- s_TypeInitializationLock.Release();
- return;
- }
- // See if some other thread got there first and already started running the constructor.
- if (os::Atomic::CompareExchange(&klass->cctor_started, 1, 1) == 1)
- {
- s_TypeInitializationLock.Release();
- // May have been us and we got here through recursion.
- os::Thread::ThreadId currentThread = os::Thread::CurrentThreadId();
- if (os::Atomic::CompareExchangePointer((size_t**)&klass->cctor_thread, (size_t*)currentThread, (size_t*)currentThread) == (size_t*)currentThread)
- return;
- // Wait for other thread to finish executing the constructor.
- while (os::Atomic::CompareExchange(&klass->cctor_finished_or_no_cctor, 1, 1) != 1 && os::Atomic::CompareExchange(&klass->initializationExceptionGCHandle, 0, 0) == 0)
- {
- os::Thread::Sleep(1);
- }
- }
- else
- {
- // Let others know we have started executing the constructor.
- os::Atomic::ExchangePointer((size_t**)&klass->cctor_thread, (size_t*)os::Thread::CurrentThreadId());
- os::Atomic::Exchange(&klass->cctor_started, 1);
- s_TypeInitializationLock.Release();
- // Run it.
- Il2CppException* exception = NULL;
- const MethodInfo* cctor = Class::GetCCtor(klass);
- if (cctor != NULL)
- {
- vm::Runtime::Invoke(cctor, NULL, NULL, &exception);
- }
- os::Atomic::ExchangePointer((size_t**)&klass->cctor_thread, (size_t*)0);
- // Deal with exceptions.
- if (exception == NULL)
- {
- // Let other threads know we finished.
- os::Atomic::Exchange(&klass->cctor_finished_or_no_cctor, 1);
- }
- else
- {
- const Il2CppType *type = Class::GetType(klass);
- 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());
- Class::SetClassInitializationError(klass, Exception::GetTypeInitializationException(n.c_str(), exception));
- }
- }
- if (klass->initializationExceptionGCHandle)
- {
- il2cpp::vm::Exception::Raise((Il2CppException*)gc::GCHandle::GetTarget(klass->initializationExceptionGCHandle));
- }
- }
- struct ConstCharCompare
- {
- bool operator()(char const *a, char const *b) const
- {
- return strcmp(a, b) < 0;
- }
- };
- Il2CppObject* Runtime::CreateUnhandledExceptionEventArgs(Il2CppException *exc)
- {
- Il2CppClass *klass;
- void* args[2];
- const MethodInfo *method = NULL;
- bool is_terminating = true;
- Il2CppObject *obj;
- klass = Class::FromName(il2cpp_defaults.corlib, "System", "UnhandledExceptionEventArgs");
- IL2CPP_ASSERT(klass);
- Class::Init(klass);
- /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
- method = Class::GetMethodFromNameFlags(klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
- IL2CPP_ASSERT(method);
- args[0] = exc;
- args[1] = &is_terminating;
- obj = Object::New(klass);
- Runtime::Invoke(method, obj, args, NULL);
- return obj;
- }
- const char *Runtime::GetBundledMachineConfig()
- {
- return s_BundledMachineConfig;
- }
- void Runtime::RegisterBundledMachineConfig(const char *config_xml)
- {
- s_BundledMachineConfig = config_xml;
- }
- void Runtime::VerifyApiVersion()
- {
- #if !IL2CPP_TINY
- #if IL2CPP_DEBUG
- Il2CppClass *klass = Class::FromName(il2cpp_defaults.corlib, "System", "Environment");
- Class::Init(klass);
- FieldInfo *field = Class::GetFieldFromName(klass, "mono_corlib_version");
- Il2CppString* value;
- Field::StaticGetValue(field, &value);
- std::string version = il2cpp::utils::StringUtils::Utf16ToUtf8(value->chars);
- IL2CPP_ASSERT(version == "1A5E0066-58DC-428A-B21C-0AD6CDAE2789");
- #endif
- #endif
- }
- int32_t Runtime::GetExitCode()
- {
- return exitcode;
- }
- void Runtime::SetExitCode(int32_t value)
- {
- exitcode = value;
- }
- static void MissingMethodInvoker(Il2CppMethodPointer ptr, const MethodInfo* method, void* obj, void** args, void* ret)
- {
- Runtime::RaiseExecutionEngineException(method, false);
- }
- InvokerMethod Runtime::GetMissingMethodInvoker()
- {
- return MissingMethodInvoker;
- }
- void Runtime::AlwaysRaiseExecutionEngineException(const MethodInfo* method)
- {
- RaiseExecutionEngineException(method, false);
- }
- void Runtime::AlwaysRaiseExecutionEngineExceptionOnVirtualCall(const MethodInfo* method)
- {
- RaiseExecutionEngineException(method, true);
- }
- void Runtime::RaiseExecutionEngineException(const MethodInfo* method, bool virtualCall)
- {
- if (Method::GetClass(method))
- RaiseExecutionEngineException(method, Method::GetFullName(method).c_str(), virtualCall);
- else
- RaiseExecutionEngineException(method, Method::GetNameWithGenericTypes(method).c_str(), virtualCall);
- }
- void Runtime::RaiseAmbiguousImplementationException(const MethodInfo* method)
- {
- if (method != NULL && !Method::IsAmbiguousMethodInfo(method))
- 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()));
- else
- Exception::Raise(Exception::GetAmbiguousImplementationException("Attempting to call default interface method with ambiguous implementations"));
- }
- void Runtime::RaiseExecutionEngineException(const MethodInfo* method, const char* methodFullName, bool virtualCall)
- {
- if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
- {
- // Default Interface Method support will throw EntryPointNotFoundExceptions if an abstract interface method is accessed
- Exception::Raise(Exception::GetEntryPointNotFoundException(utils::StringUtils::Printf("Attempting to call abstract method '%s'", methodFullName).c_str()));
- }
- else
- {
- std::string help = "";
- if (virtualCall && (method->flags & METHOD_ATTRIBUTE_VIRTUAL) && method->is_inflated)
- help = utils::StringUtils::Printf(" Consider increasing the --generic-virtual-method-iterations=%d argument", metadata::GenericMetadata::GetGenericVirtualIterations());
- 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()));
- }
- }
- #if IL2CPP_TINY
- void Runtime::FailFast(const std::string& message)
- {
- if (!message.empty())
- {
- il2cpp::utils::Logging::Write(message.c_str());
- }
- else
- {
- il2cpp::utils::Logging::Write("No error message was provided. Hopefully the stack trace can provide some information.");
- }
- const char* managedStackTrace = vm::StackTrace::GetStackTrace();
- if (managedStackTrace != NULL && strlen(managedStackTrace) != 0)
- {
- std::string managedStackTraceMessage = std::string("Managed stack trace:\n") + managedStackTrace;
- il2cpp::utils::Logging::Write(managedStackTraceMessage.c_str());
- }
- else
- {
- il2cpp::utils::Logging::Write("No managed stack trace exists. Make sure this is a development build to enable managed stack traces.");
- }
- il2cpp::os::CrashHelpers::Crash();
- }
- #endif
- } /* namespace vm */
- } /* namespace il2cpp */
|