summaryrefslogtreecommitdiff
path: root/Runtime/Mono/MonoManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Mono/MonoManager.cpp')
-rw-r--r--Runtime/Mono/MonoManager.cpp2456
1 files changed, 2456 insertions, 0 deletions
diff --git a/Runtime/Mono/MonoManager.cpp b/Runtime/Mono/MonoManager.cpp
new file mode 100644
index 0000000..871b9d0
--- /dev/null
+++ b/Runtime/Mono/MonoManager.cpp
@@ -0,0 +1,2456 @@
+#include "UnityPrefix.h"
+#include "Configuration/UnityConfigure.h" // include before anything, to get Prof_ENABLED if that is defined
+
+#if ENABLE_MONO
+#include "MonoManager.h"
+#include "MonoScript.h"
+#include "MonoBehaviour.h"
+#include "Runtime/BaseClasses/ManagerContext.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "MonoIncludes.h"
+#include "Runtime/Serialize/PersistentManager.h"
+#include "Runtime/Serialize/TransferUtility.h"
+#include "Runtime/Serialize/TypeTree.h"
+#include "Runtime/BaseClasses/IsPlaying.h"
+#include "Runtime/Utilities/PathNameUtility.h"
+#include "Runtime/Export/MonoICallRegistration.h"
+#include "Runtime/Utilities/Word.h"
+#include <stdlib.h>
+#include "Runtime/Misc/Plugins.h"
+#include "Runtime/Threads/Mutex.h"
+#include "Runtime/Utilities/File.h"
+#include "Runtime/Utilities/FileUtilities.h"
+#include "Runtime/Serialize/FileCache.h"
+#include "Runtime/Profiler/ProfilerImpl.h"
+#include "Runtime/Misc/PreloadManager.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/Utilities/PlayerPrefs.h"
+#include "Runtime/Scripting/CommonScriptingClasses.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "Runtime/Audio/AudioManager.h"
+#include "Runtime/Utilities/Stacktrace.h"
+#include "Runtime/Profiler/TimeHelper.h"
+#include "Runtime/Misc/DeveloperConsole.h"
+#include "Runtime/Scripting/ScriptingExportUtility.h"
+#include "Runtime/Scripting/Backend/ScriptingInvocation.h"
+#include "Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h"
+#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h"
+#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h"
+#include "Runtime/Core/Callbacks/GlobalCallbacks.h"
+#include "Runtime/Scripting/Scripting.h"
+
+#if UNITY_EDITOR
+#include "Editor/Src/EditorModules.h"
+#endif
+
+#ifndef USE_ASSEMBLY_PREPROCESSOR
+#define USE_ASSEMBLY_PREPROCESSOR 0
+#endif
+
+#if WEBPLUG
+#include "PlatformDependent/CommonWebPlugin/CompressedFileStream.h"
+#include "Runtime/Utilities/ErrorExit.h"
+#define PLAYER_DATA_FOLDER ""
+#endif
+#if USE_ASSEMBLY_PREPROCESSOR
+#include "AssemblyModifier.h"
+#include "AssemblyModifierOnDisk.h"
+#endif
+
+#if UNITY_EDITOR
+#include "Editor/Src/EditorSettings.h"
+#include "Editor/Src/EditorHelper.h"
+#include "Editor/Platform/Interface/BugReportingTools.h"
+#include "Runtime/Utilities/Argv.h"
+#include "Editor/Platform/Interface/EditorUtility.h"
+#include "Editor/Src/EditorUserBuildSettings.h"
+#define PLAYER_DATA_FOLDER ""
+#endif
+#if UNITY_OSX || UNITY_LINUX
+#include <dlfcn.h>
+#endif
+#if UNITY_WIN
+#include "Configuration/UnityConfigureOther.h"
+#include "PlatformDependent/Win/PathUnicodeConversion.h"
+#include "PlatformDependent/Win/WinUtils.h"
+#include <signal.h>
+#endif
+#if UNITY_WII
+#include "PlatformDependent/wii/WiiUtility.h"
+#endif
+#if UNITY_OSX
+#include <mach/task.h>
+#include <sys/stat.h>
+#endif
+#ifdef _MSC_VER
+#define va_copy(a,z) ((void)((a)=(z)))
+#endif
+
+#if ENABLE_PLAYERCONNECTION
+#include "Runtime/Network/PlayerCommunicator/PlayerConnection.h"
+#endif
+
+#ifndef PLAYER_DATA_FOLDER
+#include "Runtime/Misc/Player.h"
+#define PLAYER_DATA_FOLDER SelectDataFolder()
+#endif
+
+#define SUPPORT_MDB_FILES (UNITY_EDITOR || WEBPLUG)
+#define USE_MONO_DOMAINS (UNITY_EDITOR || WEBPLUG) && !UNITY_PEPPER
+// Turn off the extra domain for now. It doesn't buy us anything until
+// we get some sharing in the runtime. Right now, it loads the assembly
+// into the extra domain but the code will be jitted again in the child domain.
+#define USE_TWO_MONO_DOMAINS 0
+
+// Editor and development console players always load mdbs
+#define ALWAYS_LOAD_MDBS (UNITY_EDITOR || ((UNITY_XENON || UNITY_WII || UNITY_PS3) && !MASTER_BUILD) || ENABLE_PROFILER)
+
+#if UNITY_EDITOR
+extern "C"
+{
+ void debug_mono_images_leak ();
+}
+
+static const char* kEditorAssembliesPath = "Library/ScriptAssemblies";
+
+#endif // UNITY_EDITOR
+
+#if ENABLE_MONO_MEMORY_PROFILER
+void mono_profiler_startup ();
+#endif
+
+int* s_MonoDomainContainer = NULL;
+
+UNITY_TLS_VALUE(bool) MonoManager::m_IsMonoBehaviourInConstructor;
+
+#if UNITY_WIN && UNITY_WIN_ENABLE_CRASHHANDLER && !UNITY_WINRT
+
+#define USE_WIN_CRASH_HANDLER 1
+// We do cunning things with crash handler and mono - we disable
+// it when mono is initialized (because mono installs its own handler),
+// but setup a callback so that we can still launch bug reporter.
+#include "../../Tools/BugReporterWin/lib/CrashHandler.h"
+extern CrashHandler* gUnityCrashHandler;
+
+#else
+#define USE_WIN_CRASH_HANDLER 0
+#endif
+
+static void UnloadDomain ();
+static MonoDomain* CreateAndSetChildDomain();
+static void UnhandledExceptionHandler (MonoObject* object);
+double GetTimeSinceStartup ();
+
+using namespace std;
+
+static const char* kEngineAssemblyName = "UnityEngine.dll";
+static const char* kEditorInternalNameSpace = "UnityEditorInternal";
+#if MONO_2_12
+const char* kMonoClasslibsProfile = "4.5";
+#else
+const char* kMonoClasslibsProfile = "2.0";
+#endif
+
+#if UNITY_STANDALONE || UNITY_EDITOR
+static const char* gNativeLibsDir = NULL;
+#endif
+
+static MonoVTable** gClassIDToVTable = NULL;
+
+ScriptsDidChangeCallback* gUnloadDomainCallback = NULL;
+
+static bool gDebuggerEnabled = false;
+
+#if UNITY_PEPPER
+void *gCorLibMemory = NULL;
+#endif
+
+struct DomainReloadingData {
+ std::vector<SInt32> m_SavedBehaviours;
+ PPtr<MonoBehaviour> m_SavedScriptReloadProperties;
+ ABSOLUTE_TIME reloadStart;
+};
+
+void RegisterUnloadDomainCallback (ScriptsDidChangeCallback* call)
+{
+ AssertIf(gUnloadDomainCallback != NULL);
+ gUnloadDomainCallback = call;
+}
+
+static void ExtractMonoStacktrace (const std::string& condition, std::string& processedStackTrace, std::string& stackTrace, int errorNum, string& file, int* line, int type, int targetInstanceID);
+
+#if UNITY_OSX
+void HandleSignal (int i, __siginfo* info, void* p);
+#define UNITY_SA_DISABLE 0x0004 // disable taking signals on alternate stack
+#endif
+#if UNITY_WIN
+int HandleSignal( EXCEPTION_POINTERS* ep );
+void HandleAbort (int signal);
+#endif
+
+#if UNITY_EDITOR
+static std::string GetBuildToolsEngineDllPathIfExists (BuildTargetPlatform target)
+{
+ string buildToolsDirectory = GetBuildToolsDirectory(target, false);
+ if ( IsDirectoryCreated(buildToolsDirectory) )
+ {
+ string engineDLLPath = AppendPathName(buildToolsDirectory, kEngineAssemblyName);
+ if (IsFileCreated(engineDLLPath))
+ return engineDLLPath;
+ }
+ return "";
+}
+#endif // UNITY_EDITOR
+
+#if UNITY_STANDALONE || UNITY_EDITOR
+static void * mono_fallback_dlopen (const char* name, int flags, char **err, void *user_data)
+{
+ if (IsAbsoluteFilePath (name))
+ return NULL;
+
+ void* handle = NULL;
+ string fullPath = AppendPathName (gNativeLibsDir, name);
+
+ #if (UNITY_WIN && !UNITY_WINRT)
+ std::wstring widePath;
+ ConvertUnityPathName (fullPath, widePath);
+ handle = (void *) LoadLibraryW (widePath.c_str ());
+
+ #elif UNITY_OSX
+ handle = dlopen (fullPath.c_str (), RTLD_NOW);
+
+ #elif UNITY_XENON
+ handle = cached_module_load (fullPath.c_str (), MONO_DL_LAZY, 0);
+ #endif
+
+ if (!handle && err) {
+ printf_console ("Fallback handler could not load library %s\n", fullPath.c_str());
+ }
+ return handle;
+}
+
+static void* mono_fallback_lookup_symbol (void *handle, const char *name, char **err, void *user_data)
+{
+ void* symbol = NULL;
+ #if (UNITY_WIN && !UNITY_WINRT)
+ symbol = GetProcAddress ((HMODULE)handle, name);
+
+ #elif UNITY_OSX
+ symbol = dlsym (handle, name);
+
+ #elif UNITY_XENON
+ char* ret = mono_dl_symbol ((MonoDl*)handle, name, &symbol);
+ if (!symbol && err)
+ *err = ret;
+ #endif
+
+ #if !UNITY_XENON
+ if (!symbol && err) {
+ printf_console ("Fallback handler could not load symbol %s\n", name);
+ }
+ #endif
+
+ return symbol;
+}
+
+static void* mono_fallback_close (void *handle, void *user_data)
+{
+ #if (UNITY_WIN && !UNITY_METRO)
+ FreeLibrary ((HMODULE) handle);
+
+ #elif UNITY_OSX
+ dlclose (handle);
+
+ #endif
+
+ return NULL;
+}
+#endif
+
+MonoManager::MonoManager (MemLabelId label, ObjectCreationMode mode)
+: ScriptingManager(label, mode, this, UNITY_NEW(ScriptingMethodFactory_Mono(), kMemManager))
+{
+ m_AssemblyReferencingDomain = NULL;
+
+ #if UNITY_PLUGINS_AVAILABLE
+ mono_set_find_plugin_callback ((gconstpointer)FindAndLoadUnityPlugin);
+ #endif
+
+ #if UNITY_EDITOR
+ m_LogAssemblyReload = false;
+ #endif
+
+ #if UNITY_STANDALONE || UNITY_EDITOR
+ gNativeLibsDir = strdup(GetApplicationNativeLibsPath().c_str ());
+ mono_dl_fallback_register (mono_fallback_dlopen, mono_fallback_lookup_symbol, mono_fallback_close, NULL);
+ #endif
+
+ m_HasCompileErrors = false;
+
+ CleanupClassIDMaps();
+}
+
+MonoManager::~MonoManager ()
+{
+ gClassIDToVTable = NULL;
+ gClassIDToClass = NULL;
+ RegisterLogPreprocessor (NULL);
+}
+
+AssemblyMask MonoManager::GetSystemAssemblyMask (bool load)
+{
+ AssemblyMask assemblies(kScriptAssemblies);
+ assemblies[kEngineAssembly] = load;
+ #if UNITY_EDITOR
+ assemblies[kEditorAssembly] = load;
+ assemblies[kLocatorAssembly] = load;
+ #endif
+
+ return assemblies;
+}
+
+
+AssemblyMask MonoManager::GetAvailableDllAssemblyMask ()
+{
+ AssemblyMask assemblies(GetAssemblyCount());
+ assemblies[kEngineAssembly]=true;
+ #if UNITY_EDITOR
+ assemblies[kEditorAssembly]=true;
+ assemblies[kLocatorAssembly]=true;
+ #endif
+
+ for (int i=kScriptAssemblies;i<GetAssemblyCount();i++)
+ {
+ string path = GetAssemblyPath (i);
+ #if UNITY_XENON
+ path += ".mono";
+ #endif
+ #if !UNITY_PEPPER
+ if (IsFileCreated (path))
+ assemblies[i] = true;
+ #endif
+
+ #if WEBPLUG
+ if (CompressedFileStream::Get().Find(GetLastPathNameComponent(path)))
+ assemblies[i] = true;
+ #if UNITY_PEPPER
+ if (CompressedFileStream::GetResources().Find(GetLastPathNameComponent(path)))
+ assemblies[i] = true;
+ #endif
+ #endif
+ }
+
+ return assemblies;
+}
+
+void MonoManager::AwakeFromLoad (AwakeFromLoadMode awakeMode)
+{
+ Super::AwakeFromLoad (awakeMode);
+
+ // Load assemblies in player
+ // In editor MonoImporter Reloads the assemblies
+ #if GAMERELEASE
+ ReloadAssembly (GetAvailableDllAssemblyMask());
+ #endif
+
+#if ENABLE_SERIALIZATION_BY_CODEGENERATION
+ ScriptingInvocation initManagedAnalysis(GetScriptingMethodRegistry().GetMethod("UnityEngine.Serialization","ManagedLivenessAnalysis","Init"));
+ initManagedAnalysis.Invoke();
+
+ ScriptingInvocation initWriter(GetScriptingMethodRegistry().GetMethod("UnityEngine.Serialization","SerializedStateWriter","Init"));
+ initWriter.Invoke();
+
+ ScriptingInvocation initReader(GetScriptingMethodRegistry().GetMethod("UnityEngine.Serialization","SerializedStateReader","Init"));
+ initReader.Invoke();
+
+ ScriptingInvocation initRemapper(GetScriptingMethodRegistry().GetMethod("UnityEngine.Serialization","PPtrRemapper","Init"));
+ initRemapper.Invoke();
+#endif
+
+ // Disable Mono stacktrace in non-development (release) player builds
+ #if UNITY_EDITOR || UNITY_DEVELOPER_BUILD
+ RegisterLogPreprocessor (ExtractMonoStacktrace);
+ #endif
+}
+
+#if !UNITY_RELEASE
+void MonoManager::AssertInvalidAssembly (MonoClass* klass)
+{
+ if (klass == NULL)
+ return;
+
+ MonoImage* image = mono_class_get_image(klass);
+ if (image == mono_get_corlib())
+ return;
+
+ for (int i=0;i<m_ScriptImages.size();i++)
+ {
+// if (m_ScriptImages[i])
+// printf_console("compare against image file %s\n", mono_image_get_filename(m_ScriptImages[i]));
+
+ if (m_ScriptImages[i] == image)
+ return;
+ }
+ printf_console("with error class %p \n", klass);
+ printf_console("with name %s \n", mono_class_get_name(klass));
+ printf_console("with image %p \n", image);
+ printf_console("will image file name %s\n", mono_image_get_filename(image));
+ printf_console("Mono class %s is in an invalid assembly %s ! BUG", mono_class_get_name(klass), mono_image_get_filename(image));
+ #if UNITY_EDITOR
+ ErrorString("Invalid assembly loaded");
+ #endif
+ printf_console("\n\n\n\n");
+}
+#endif
+
+#if UNITY_EDITOR
+
+void MonoManager::ResizeAssemblyNames(int max)
+{
+ m_AssemblyNames.clear();
+ m_AssemblyNames.resize(max);
+}
+
+int MonoManager::InsertAssemblyName(const std::string& assemblyName)
+{
+ int index = GetAssemblyIndexFromAssemblyName(assemblyName);
+ if (index != -1)
+ return index;
+
+ index = GetAssemblyCount();
+ m_AssemblyNames.push_back(assemblyName);
+ return index;
+}
+
+void MonoManager::SetAssemblyName (unsigned assemblyIndex, const string& name)
+{
+ Assert(assemblyIndex <= m_AssemblyNames.size ());
+ m_AssemblyNames[assemblyIndex] = name;
+}
+
+
+void MonoManager::SetCustomDllPathLocation (const std::string& name, const std::string& path)
+{
+ if (m_CustomDllLocation[name] != path)
+ {
+ ////@TODO: Create warnings for duplicate names
+ m_CustomDllLocation[name] = path;
+ }
+}
+
+/*
+std::string MonoManager::AddCustomDll (const std::string& path)
+{
+ if (!DetectDotNetDll(path))
+ return "";
+
+ m_CustomDlls.insert(path);
+
+ set<std::string> names;
+
+ // Warn if a .dll name exists twice
+ for (set<std::string>::iterator i=m_CustomDlls.begin();i != m_CustomDlls.end();i++)
+ {
+ const std::string& dllpath = *i;
+ if (!IsFileCreated (dllpath))
+ continue;
+
+ if(!DetectDotNetDll(dllpath))
+ continue;
+
+ string name = GetLastPathNameComponent(dllpath);
+ if (!names.insert (name).second)
+ return Format("A .dll with name %s exists two times. The dll '%s' will be ignored.", name.c_str(), dllpath.c_str());
+ }
+
+ return "";
+}
+*/
+
+void MonoManager::SetHasCompileErrors (bool compileErrors)
+{
+ m_HasCompileErrors = compileErrors;
+}
+
+#endif
+
+#if UNITY_EDITOR
+static int gMonoPathsIndexOfManagedFolder = 0;
+//#else
+//static int gMonoPathsIndexOfManagedFolder = 1;
+#endif
+
+
+namespace MonoPathContainer
+{
+ std::vector<std::string>* g_MonoPaths = NULL;
+ void StaticInitialize(){ g_MonoPaths = UNITY_NEW(std::vector<std::string>,kMemMono);}
+ void StaticDestroy(){UNITY_DELETE(g_MonoPaths,kMemMono);}
+ std::vector<std::string>& GetMonoPaths() {return *g_MonoPaths;}
+ void SetMonoPaths(const std::vector<std::string>& paths){*g_MonoPaths = paths;}
+ void AppendMonoPath (const string& path)
+ {
+#if UNITY_WIN && !UNITY_WINRT
+ wchar_t widePath[kDefaultPathBufferSize];
+ ConvertUnityPathName(path.c_str(), widePath, kDefaultPathBufferSize);
+
+ wchar_t fullPath[kDefaultPathBufferSize];
+ GetFullPathNameW(widePath, kDefaultPathBufferSize, fullPath, NULL);
+
+ string unityPath;
+ ConvertWindowsPathName(fullPath, unityPath);
+#else
+ string unityPath(path);
+#endif
+ MonoPathContainer::GetMonoPaths().push_back(unityPath);
+ }
+};
+
+string MonoManager::GetAssemblyPath (int index)
+{
+ AssertIf (index < 0);
+
+#if UNITY_EDITOR
+ if (index == kEngineAssembly)
+ {
+ // Check if target specific assembly exists
+ std::string engineDLLPath = GetBuildToolsEngineDllPathIfExists (GetEditorUserBuildSettings().GetActiveBuildTarget());
+ if (!engineDLLPath.empty ())
+ {
+ return engineDLLPath;
+ }
+ else
+ {
+ return AppendPathName(MonoPathContainer::GetMonoPaths()[gMonoPathsIndexOfManagedFolder], m_AssemblyNames[index]);
+ }
+ }
+ else if (index < kScriptAssemblies)
+ {
+ return AppendPathName(MonoPathContainer::GetMonoPaths()[gMonoPathsIndexOfManagedFolder], m_AssemblyNames[index]);
+ }
+ else if (index < m_AssemblyNames.size ())
+ {
+ CustomDllLocation::iterator found = m_CustomDllLocation.find(m_AssemblyNames[index]);
+ if (found != m_CustomDllLocation.end())
+ return found->second;
+ else
+ return AppendPathName (kEditorAssembliesPath, m_AssemblyNames[index]);
+ }
+ else
+ return "";
+#elif WEBPLUG
+#if !UNITY_PEPPER
+ if (index < kScriptAssemblies)
+ return AppendPathName(MonoPathContainer::GetMonoPaths()[0], m_AssemblyNames[index]);
+ else
+#endif
+ if (index < m_AssemblyNames.size ())
+ return m_AssemblyNames[index];
+ else
+ return "";
+#else
+ return AppendPathName("Managed", m_AssemblyNames[index]);
+#endif
+}
+
+MonoAssembly* MonoManager::GetAssembly (int index)
+{
+ AssertIf (index < 0);
+ if (index < m_ScriptImages.size ())
+ {
+ MonoImage* image = m_ScriptImages[index];
+ if (image)
+ return mono_image_get_assembly (image);
+ }
+ return NULL;
+}
+
+BackendNativeType MonoManager::NativeTypeFor(const char* namespaze, const char* className)
+{
+ return GetMonoClass(className,namespaze);
+}
+
+ScriptingTypePtr MonoManager::Provide(BackendNativeType nativePtr)
+{
+ return (ScriptingTypePtr) nativePtr;
+}
+
+ScriptingTypePtr Provide(void* nativeType);
+
+void MonoManager::Release(ScriptingTypePtr klass)
+{
+}
+
+// If namespace is NULL then search is in any namespace
+MonoClass* MonoManager::GetMonoClassCaseInsensitive (const char* className, const char* theNameSpace /*=NULL*/)
+{
+ for (ScriptImages::iterator i=m_ScriptImages.begin ();i != m_ScriptImages.end ();i++)
+ {
+ MonoImage* curImage = *i;
+ if (!curImage)
+ continue;
+
+ MonoClass* klass = mono_class_from_name_case (curImage, theNameSpace, className);
+ if (klass)
+ return klass;
+ }
+
+ return NULL;
+}
+
+// If namespace is NULL then search is in any namespace
+MonoClass* MonoManager::GetMonoClass (const char* className, const char* theNameSpace /*=NULL*/)
+{
+ MonoClass* klass = NULL;
+ MonoImage* curImage;
+
+ klass = mono_class_from_name(mono_get_corlib(), theNameSpace, className);
+
+ ///@todo: give compile error when classes with the same name are defined in different dll's
+ for (ScriptImages::iterator i=m_ScriptImages.begin ();i != m_ScriptImages.end () && klass == NULL;i++)
+ {
+ curImage = *i;
+ if (!curImage)
+ continue;
+
+ klass = mono_class_from_name (curImage, theNameSpace, className);
+ }
+
+ return klass;
+}
+
+int MonoManager::GetAssemblyIndexFromAssemblyName (const string& name)
+{
+ vector<UnityStr>::iterator found = find (m_AssemblyNames.begin (), m_AssemblyNames.end (), name);
+ if (found == m_AssemblyNames.end ())
+ return -1;
+
+ return distance (m_AssemblyNames.begin (), found);
+}
+
+MonoClass* MonoManager::GetMonoClassWithAssemblyName (const std::string& className, const string& nameSpace, const string& assemblyName)
+{
+ int index = GetAssemblyIndexFromAssemblyName (assemblyName);
+ MonoImage* image = 0;
+ if (index == -1)
+ {
+ MonoAssemblyName aname;
+#if !UNITY_PEPPER || UNITY_NACL_WEBPLAYER
+ if (!mono_assembly_name_parse (assemblyName.c_str(),&aname))
+ return NULL;
+#endif
+ MonoAssembly* assembly = mono_assembly_loaded (&aname);
+ if (!assembly) return NULL;
+ image = mono_assembly_get_image(assembly);
+ }
+ else
+ {
+ if (index >= m_ScriptImages.size ()) return NULL;
+ image = m_ScriptImages[index];
+ }
+
+ if (!image) return NULL;
+
+ return mono_class_from_name (image, nameSpace.c_str(), className.c_str ());
+}
+
+string MonoManager::GetAssemblyIdentifierFromImage(MonoImage* image)
+{
+ for (int i=0;i<m_ScriptImages.size ();i++)
+ {
+ if (m_ScriptImages[i] == image)
+ return m_AssemblyNames[i];
+ }
+ return "";
+}
+
+int MonoManager::GetAssemblyIndexFromImage(MonoImage* image)
+{
+ for (int i=0;i<m_ScriptImages.size ();i++)
+ {
+ if (m_ScriptImages[i] == image)
+ return i;
+ }
+ return -1;
+}
+
+#if UNITY_OSX
+bool SameFileSystemEntry(const struct stat& s1, const struct stat& s2)
+{
+ return (s1.st_ino == s2.st_ino) && (s1.st_dev == s2.st_dev);
+}
+#endif
+
+bool IsPlatformPath(const std::string& path)
+{
+ std::vector<string>& monoPaths = MonoPathContainer::GetMonoPaths();
+#if UNITY_OSX
+ // On OSX we want to take symlinks into account
+ struct stat pathStat;
+ if (stat(path.c_str(), &pathStat) != 0)
+ return false;
+
+ for (std::vector<string>::iterator i = monoPaths.begin(); i != monoPaths.end(); ++i)
+ {
+ struct stat platformStat;
+ if (stat((*i).c_str(), &platformStat) == 0 && SameFileSystemEntry(pathStat, platformStat))
+ return true;
+ }
+ return false;
+#elif UNITY_WIN
+ #if !UNITY_WINRT
+ string unityPath = "";
+
+ if (!path.empty())
+ {
+ wchar_t widePath[kDefaultPathBufferSize];
+ ConvertUnityPathName(path.c_str(), widePath, kDefaultPathBufferSize);
+
+ wchar_t fullPath[kDefaultPathBufferSize];
+ if (!GetFullPathNameW(widePath, kDefaultPathBufferSize, fullPath, NULL))
+ fullPath[0] = L'\0';
+
+ ConvertWindowsPathName(fullPath, unityPath);
+ }
+
+ std::vector<string>::iterator pos = std::find(monoPaths.begin(), monoPaths.end(), unityPath);
+ return pos != monoPaths.end();
+ #else
+ #pragma message("todo: implement") // ?!-
+ return false; // ?!-
+ #endif
+#else
+ std::vector<string>::iterator pos = std::find(monoPaths.begin(), monoPaths.end(), path);
+ return pos != monoPaths.end();
+#endif
+}
+
+bool isPlatformCodeCallback(const char* image_name)
+{
+ std::string name(image_name);
+ ConvertSeparatorsToUnity(name);
+
+ bool result = IsPlatformPath(DeleteLastPathNameComponent(name));
+ printf_console(result ? "Platform assembly: %s (this message is harmless)\n" : "Non platform assembly: %s (this message is harmless)\n", image_name);
+ return result;
+}
+
+static MonoAssembly* LoadAssemblyAndSymbolsWrapper(const string& absolutePath)
+{
+ MonoAssembly* assembly = mono_domain_assembly_open (mono_domain_get (), absolutePath.c_str());
+ if (assembly)
+ {
+ #if USE_MONO_DEBUGGER
+ #if !ALWAYS_LOAD_MDBS
+ if (gDebuggerEnabled)
+ #endif
+ {
+ mono_debug_open_image_from_memory(mono_assembly_get_image(assembly), 0, 0);
+ }
+ #endif
+ }
+ return assembly;
+}
+
+static MonoAssembly* LoadAssemblyWrapper (const void* data, size_t size, const char* name)
+{
+ #if (UNITY_PS3 || UNITY_XENON)
+ Assert(data == NULL);
+ string absolutePath = PathToAbsolutePath (name);
+ ConvertSeparatorsToPlatform (absolutePath);
+
+ #if UNITY_XENON
+ // Try loading the .DLL.MONO from UPDATE: drive first.
+ // If it succeeds, mono will also load dependencies from the same path.
+ Assert(absolutePath.substr(0, 5) == "game:");
+ string absoluteUpdatePath = "update" + absolutePath.substr(4);
+ MonoAssembly* updateAssembly = LoadAssemblyAndSymbolsWrapper(absoluteUpdatePath);
+ if (updateAssembly)
+ return updateAssembly;
+ #endif
+
+ MonoAssembly* assembly = LoadAssemblyAndSymbolsWrapper(absolutePath);
+ return assembly;
+
+ #else
+
+
+ // We can't use mono_image_open_file because we continously replace the file when compiling new dll's.
+ // But mono will keep the file locked, so we need to load it into memory.
+ InputString dataString;
+
+ string absolutePath = PathToAbsolutePath(name);
+ ConvertSeparatorsToPlatform(absolutePath);
+
+ if (data == NULL)
+ {
+ #if WEBPLUG
+ return mono_domain_assembly_open (mono_domain_get (), absolutePath.c_str());
+ #endif
+
+ if (!ReadStringFromFile (&dataString, absolutePath))
+ return NULL;
+
+ data = &dataString[0];
+ size = dataString.size ();
+ }
+
+ int status = 0;
+ MonoImage* image = mono_image_open_from_data_with_name ((char*)data, size, /*Copy data*/true, &status, false /* ref only*/, absolutePath.c_str());
+ if (status != 0 || image == NULL)
+ {
+ printf_console("Failed loading assembly %s\n", name);
+ return NULL;
+ }
+
+ #if USE_MONO_DEBUGGER
+ #if !ALWAYS_LOAD_MDBS
+ if (gDebuggerEnabled)
+ #endif
+ {
+ string absolutePathMdb = PathToAbsolutePath(MdbFile(name));
+ ConvertSeparatorsToPlatform(absolutePathMdb);
+
+ #if !UNITY_PEPPER
+ if (ReadStringFromFile(&dataString, absolutePathMdb))
+ {
+ mono_debug_open_image_from_memory(image, &dataString[0], dataString.size ());
+ }
+ #endif
+ }
+ #endif
+
+ /// try out true as last argument (loads reflection only should be faster)
+ printf_console ("Loading %s into Unity Child Domain\n", absolutePath.c_str ());
+ MonoAssembly* assembly = mono_assembly_load_from_full (image, absolutePath.c_str (), &status, false/* ref only*/);
+ if (status != 0 || assembly == NULL)
+ {
+ // clear reference added by mono_image_open_from_data_with_name
+ mono_image_close (image);
+
+ printf_console("Failed loading assembly '%s'\n", name);
+ return NULL;
+ }
+
+ // We are loading a new assembly and it is already loaded????
+ if (mono_assembly_get_image(assembly) != image)
+ {
+ #if !UNITY_RELEASE
+ LogString(Format("Already loaded assembly '%s'", mono_image_get_name(mono_assembly_get_image(assembly))));
+ #endif
+ }
+
+ // clear reference added by mono_image_open_from_data_with_name
+ mono_image_close (image);
+
+ return assembly;
+ #endif
+
+}
+
+void SetSecurityMode()
+{
+ bool enableCoreClr = false;
+ bool enableVerifier = false;
+ bool enableSocketSecurity = false;
+
+#if WEBPLUG && !UNITY_PEPPER
+ enableSocketSecurity = true;
+ enableCoreClr = true;
+ enableVerifier = true;
+#endif
+
+#if UNITY_EDITOR
+ if (DoesBuildTargetUseSecuritySandbox(GetEditorUserBuildSettings().GetActiveBuildTarget ()))
+ {
+ enableSocketSecurity = true;
+ enableVerifier = true;
+ }
+#endif
+
+#if MONO_2_12
+ mono_security_core_clr_set_options ((MonoSecurityCoreCLROptions)(MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION | MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE));
+#endif
+ mono_security_set_core_clr_platform_callback (&isPlatformCodeCallback);
+
+#if !UNITY_PEPPER
+ if (enableCoreClr)
+ {
+ mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
+ } else {
+ mono_security_set_mode (MONO_SECURITY_MODE_NONE);
+ }
+
+ if (enableVerifier)
+ mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
+ else
+ mono_verifier_set_mode (MONO_VERIFIER_MODE_OFF);
+#endif
+
+ #if !UNITY_XENON && !UNITY_PS3 && !UNITY_PEPPER && !UNITY_WII
+ mono_unity_socket_security_enabled_set (enableSocketSecurity);
+ #endif
+}
+
+
+#define LogAssemblyError(x) DebugStringToFile (x, 0, __FILE__, __LINE__, kLog | kAssetImportError, 0, GetInstanceID ());
+#if WEBPLUG
+
+
+
+MonoAssembly *LoadAssemblyWebPlug (string path)
+{
+ MonoAssembly *assembly;
+ CompressedFileStream::Data* data = CompressedFileStream::Get().Find(GetLastPathNameComponent(path));
+#if UNITY_PEPPER
+ if (!data)
+ data = CompressedFileStream::GetResources().Find(GetLastPathNameComponent(path));
+#endif
+ if (data)
+ {
+ MemoryCacherReadBlocks cacher (data->blocks, data->end, kCacheBlockSize);
+ UInt8* dataCpy;
+ ALLOC_TEMP(dataCpy, UInt8, data->GetSize());
+ cacher.DirectRead(dataCpy, data->offset, data->GetSize());
+#if USE_ASSEMBLY_PREPROCESSOR
+ bool modify = true;
+ if (modify)
+ {
+ AssemblyModifier am;
+ InputString output;
+ bool success = am.PreProcessAssembly(dataCpy, data->GetSize(), output);
+ if (success)
+ assembly = LoadAssemblyWrapper (&output[0], output.size(), path.c_str ());
+ }
+ if (assembly==NULL)
+#endif
+ assembly = LoadAssemblyWrapper (dataCpy, data->GetSize(), path.c_str ());
+ if (!assembly) return NULL;
+#if !ALWAYS_LOAD_MDBS
+ if (gDebuggerEnabled)
+#endif
+ {
+ //see if there is an mdb too
+ CompressedFileStream::Data* mdbdata = CompressedFileStream::Get().Find(GetLastPathNameComponent(MdbFile(path)));
+ #if UNITY_PEPPER
+ if (!mdbdata)
+ mdbdata = CompressedFileStream::GetResources().Find(GetLastPathNameComponent(MdbFile(path)));
+ #endif
+ if (mdbdata)
+ {
+ MemoryCacherReadBlocks mdbcacher (mdbdata->blocks, mdbdata->end, kCacheBlockSize);
+ UInt8* mdbdataCpy;
+ ALLOC_TEMP(mdbdataCpy, UInt8, mdbdata->GetSize());
+ mdbcacher.DirectRead(mdbdataCpy, mdbdata->offset, mdbdata->GetSize());
+
+ MonoImage* image = mono_assembly_get_image(assembly);
+ mono_debug_open_image_from_memory(image, (const char*)mdbdataCpy, mdbdata->GetSize());
+ }
+ }
+ }
+ else
+ assembly = LoadAssemblyWrapper (NULL, 0, path.c_str ());
+ return assembly;
+}
+
+MonoAssembly *AssemblyLoadHook (char **name, void* user_data)
+{
+ return LoadAssemblyWebPlug(string(*name)+".dll");
+}
+#endif
+
+bool MonoManager::IsThisFileAnAssemblyThatCouldChange(std::string& path)
+{
+ std::string abspath = PathToAbsolutePath(path);
+ ConvertSeparatorsToUnity(abspath);
+ int startingScriptIndex = kScriptAssemblies;
+
+#if UNITY_EDITOR
+ if (IsDeveloperBuild())
+ startingScriptIndex = kEngineAssembly;
+#endif
+
+ for (int i=startingScriptIndex; i<GetAssemblyCount(); i++)
+ {
+ std::string assemblypath = PathToAbsolutePath(GetAssemblyPath (i));
+ ConvertSeparatorsToUnity(assemblypath);
+
+ if (abspath == assemblypath)
+ return true;
+ }
+ return false;
+}
+
+
+
+bool MonoManager::LoadAssemblies (AssemblyMask allAssembliesMask)
+{
+ bool firstLoad = false;
+ bool failedLoadingSomeAssemblies = false;
+
+ // Load assemblies
+ for (int i = 0; i < GetAssemblyCount() && i < allAssembliesMask.size (); i++)
+ {
+
+ // Does the assembly have to be reloaded?
+ if (allAssembliesMask[i])
+ {
+ if (m_ScriptImages.empty () || m_ScriptImages.size () <= i)
+ m_ScriptImages.resize (max<int> (i + 1, m_ScriptImages.size ()));
+
+ if (i >= kScriptAssemblies || m_ScriptImages[i] == NULL)
+ {
+ if (i < kScriptAssemblies)
+ firstLoad = true;
+
+ string path = GetAssemblyPath (i);
+ m_ScriptImages[i] = NULL;
+
+ // Load the script assembly, the script assembly might not be there
+ // if we dont have scripts this is valid
+ MonoAssembly* assembly = NULL;
+ #if WEBPLUG
+ assembly = LoadAssemblyWebPlug (path);
+ #elif UNITY_EDITOR
+ if ( i < kScriptAssemblies && !IsDeveloperBuild())
+ {
+ string s = PathToAbsolutePath (path);
+ assembly = mono_domain_assembly_open (mono_domain_get (), s.c_str());
+ }
+ else
+ assembly = LoadAssemblyWrapper (NULL, 0, path.c_str ());
+ #else
+ assembly = LoadAssemblyWrapper (NULL, 0, path.c_str ());
+ #endif
+
+ MonoImage* newImage = assembly ? mono_assembly_get_image (assembly) : NULL;
+
+ m_ScriptImages[i] = newImage;
+ if (newImage == NULL)
+ {
+ failedLoadingSomeAssemblies = true;
+ LogAssemblyError ("Loading script assembly \"" + path + "\" failed!");
+ }
+ }
+ }
+ // Should we unload the assembly?
+ else if (i < m_ScriptImages.size ())
+ {
+ m_ScriptImages[i] = NULL;
+ }
+ }
+
+ if (firstLoad)
+ {
+
+#if !UNITY_PS3 && !UNITY_XENON && !UNITY_IPHONE
+ for (int i = 0; i < m_ScriptImages.size (); i++)
+ {
+ if (m_ScriptImages[i])
+ {
+#if USE_ANCIENT_MONO
+ if (!mono_assembly_preload_references (m_ScriptImages[i]))
+ {
+ printf_console ("Failed loading references %s\n", GetAssemblyPath (i).c_str ());
+ m_ScriptImages[i] = NULL;
+ }
+#endif
+ }
+ }
+ ScriptingInvocation ("UnityEngine","ClassLibraryInitializer","Init").Invoke ();
+#endif
+#if UNITY_IOS
+ CallStaticMonoMethod ("UnhandledExceptionHandler", "RegisterUECatcher");
+#endif
+
+ }
+
+ return failedLoadingSomeAssemblies;
+}
+
+#if UNITY_EDITOR
+void MonoManager::SetupLoadedEditorAssemblies ()
+{
+ // Setup editor assemblies
+ MonoClass* editorAssemblies = GetMonoClass("EditorAssemblies", "UnityEditor");
+ if (editorAssemblies)
+ {
+ MonoClass* assemblyClass = mono_class_from_name (mono_get_corlib (), "System.Reflection", "Assembly");
+
+ vector<MonoAssembly*> assemblies;
+ assemblies.reserve(64);
+
+ for (int i=0;i<GetAssemblyCount();i++)
+ {
+ if (GetAssembly(i) && i != kEngineAssembly)
+ assemblies.push_back(GetAssembly(i));
+ }
+
+ MonoArray* array = mono_array_new (mono_domain_get (), assemblyClass, assemblies.size());
+ for (int i=0;i<assemblies.size();i++)
+ {
+ Scripting::SetScriptingArrayElement(array, i, mono_assembly_get_object(mono_domain_get(), assemblies[i]));
+ }
+
+ ScriptingInvocation invocation(editorAssemblies,"SetLoadedEditorAssemblies");
+ invocation.AddArray(array);
+ invocation.Invoke();
+ }
+}
+#endif
+
+
+MonoManager::AssemblyLoadFailure MonoManager::ReloadAssembly (AssemblyMask allAssembliesMask)
+{
+ DomainReloadingData savedData;
+ MonoManager::AssemblyLoadFailure initialLoad = BeginReloadAssembly (savedData);
+ if (initialLoad == kFailedLoadingEngineOrEditorAssemblies)
+ return initialLoad;
+
+#if UNITY_EDITOR
+ GlobalCallbacks::Get().initialDomainReloadingComplete.Invoke();
+ allAssembliesMask = GetAvailableDllAssemblyMask();
+#endif
+
+ return EndReloadAssembly (savedData, allAssembliesMask);
+}
+
+MonoManager::AssemblyLoadFailure MonoManager::BeginReloadAssembly (DomainReloadingData& savedData)
+{
+ printf_console ("Begin MonoManager ReloadAssembly\n");
+
+ // Make sure there are no preload operations queued up before we reload the domain.
+ GetPreloadManager().WaitForAllAsyncOperationsToComplete();
+ StopPreloadManager();
+
+#if UNITY_EDITOR
+ // if there's no script images on the list, no point in trying to stop, nothing has been loaded yet
+ if (!m_ScriptImages.empty())
+ ShutdownManagedModuleManager ();
+#endif
+
+ savedData.reloadStart = START_TIME;
+
+ RemoveErrorWithIdentifierFromConsole (GetInstanceID ());
+
+ #if GAMERELEASE
+ if (!m_ScriptImages.empty())
+ ErrorString("Reload Assembly may not be called multiple times in the player");
+ #endif
+
+ #if DEBUGMODE
+ ///@TODO: Also assert when the preload manager is running, write a test for it
+ if (mono_method_get_last_managed ())
+ {
+ ErrorString("Reload Assembly called from managed code directly. This will cause a crash. You should never refresh assets in synchronous mode or enter playmode synchronously from script code.");
+ return kFailedLoadingEngineOrEditorAssemblies;
+ }
+ #endif
+
+ // Find and backup all Monobehaviours to the EditorExtensionImpl
+ // If we are in play mode we use kForceSerializeAllProperties which will serialize private and public properties.
+ // This makes it possible to reload script while in playmode
+ // Otherwise we use the normal backup mechanism which doesnt persist private properties.
+
+ Object::FindAllDerivedObjects (ClassID(MonoBehaviour), &savedData.m_SavedBehaviours, false);
+ // sort all behaviours by script execution order (if set) and then instance ID, just like the persistent manager does
+ std::sort (savedData.m_SavedBehaviours.begin (), savedData.m_SavedBehaviours.end (), AwakeFromLoadQueue::SortBehaviourByExecutionOrderAndInstanceID);
+ MonoBehaviour* behaviour;
+
+ #if UNITY_EDITOR
+
+ // Allow static editor classes to store their state
+ if (GetAssembly(kEditorAssembly) != NULL)
+ CallStaticMonoMethod ("AssemblyReloadEvents", "OnBeforeAssemblyReload");
+ // Store script reload properties (For example text editing state.)
+ // Only store them if there are any other monobehaviours around, because when loading scripts for the first
+ // time we don't want this because the resource manager has not yet registered the ScriptReloadProperties
+ if (GetAssembly(kEditorAssembly) != NULL && !savedData.m_SavedBehaviours.empty ())
+ {
+ savedData.m_SavedScriptReloadProperties = ScriptingObjectToObject<MonoBehaviour> (CallStaticMonoMethod ("ScriptReloadProperties", "Store"));
+ if (savedData.m_SavedScriptReloadProperties.IsValid ())
+ savedData.m_SavedBehaviours.push_back(savedData.m_SavedScriptReloadProperties.GetInstanceID ());
+ }
+
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour> (savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+
+ // Take backup just so that if we can load after reloading the assembly: Then we load the backup
+ // If we can't load after reloading the assembly, We just keep the backup on the behviour..
+ if (behaviour->GetInstance ())
+ {
+ Assert(behaviour->GetBackup() == NULL);
+
+ int flags = kSerializeDebugProperties | kSerializeMonoReload;
+
+ BackupState* backup = new BackupState();
+ // Due to serialization to YAML not being super-fast, we backup all MonoBehaviours in binary mode
+ // and we convert (when saving) the backup to YAML only when reload of a script fails.
+ MonoBehaviour::ExtractBackupFromInstance (behaviour->GetInstance (), behaviour->GetClass (), *backup, flags);
+ behaviour->SetBackup(backup);
+ }
+
+ // Release and unload.
+ // Calling RemoveFromManager here makes sure
+ if (behaviour->IsAddedToManager ())
+ behaviour->RemoveFromManager ();
+ else
+ behaviour->WillUnloadScriptableObject();
+ }
+
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour> (savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+
+ behaviour->StopAllCoroutines();
+ }
+
+ #endif //#if UNITY_EDITOR
+
+ // Release all mono behaviours
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour> (savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+
+// #if !UNITY_EDITOR
+// ErrorString(Format("MonoBehaviour not unloaded in web player unload %s instance: %d", behaviour->GetName().c_str(), behaviour->GetInstance()));
+// #endif
+
+ // Take backup just so that if we can load after reloading the assembly: Then we load the backup
+ behaviour->ReleaseMonoInstance ();
+ }
+
+ // Release all Monohandles
+ vector<Object*> allObjects;
+ Object::FindObjectsOfType (ClassID(Object), &allObjects);
+ for (int i=0;i<allObjects.size();i++)
+ {
+ if (allObjects[i]->GetCachedScriptingObject() != NULL)
+ allObjects[i]->SetCachedScriptingObject(NULL);
+ }
+
+ // Clear common scripting classes
+ ClearCommonScriptingClasses (m_CommonScriptingClasses);
+ m_ScriptingMethodRegistry->InvalidateCache();
+ m_ScriptingTypeRegistry->InvalidateCache();
+
+ #if ENABLE_PROFILER
+ UnityProfiler::Get().CleanupMonoMethodCaches();
+ #endif
+
+#if !USE_TWO_MONO_DOMAINS
+ AssemblyMask unloadMask = GetSystemAssemblyMask (false);
+ LoadAssemblies (unloadMask);
+#endif
+
+ #if USE_MONO_DOMAINS
+
+ PopulateAssemblyReferencingDomain();
+
+ if (CreateAndSetChildDomain() == NULL)
+ {
+ return kFailedLoadingEngineOrEditorAssemblies;
+ }
+
+#if USE_TWO_MONO_DOMAINS
+ if (m_AssemblyReferencingDomain == NULL)
+ m_AssemblyReferencingDomain = mono_domain_create_appdomain("AssemblyReferencingDomain",NULL);
+#endif
+
+#endif
+
+ SetSecurityMode();
+
+ #if ENABLE_MONO_MEMORY_PROFILER
+ UnityProfiler::Get().SetupProfilerEvents ();
+ #endif
+
+ // debug_mono_images_leak();
+
+ AssemblyMask loadMask = GetSystemAssemblyMask (true);
+ bool failedLoadingSomeAssemblies = LoadAssemblies(loadMask);
+
+ mono_gc_collect (mono_gc_max_generation ());
+
+ if (failedLoadingSomeAssemblies)
+ {
+ for (int i=0;i<m_ScriptImages.size();i++)
+ m_ScriptImages[i] = NULL;
+ CleanupClassIDMaps();
+ }
+
+ return failedLoadingSomeAssemblies ? kFailedLoadingEngineOrEditorAssemblies : kEverythingLoaded;
+}
+
+MonoManager::AssemblyLoadFailure MonoManager::EndReloadAssembly (const DomainReloadingData& savedData, AssemblyMask allAssembliesMask)
+{
+ MonoBehaviour* behaviour;
+
+ bool failedLoadingSomeAssemblies = LoadAssemblies(allAssembliesMask);
+
+ // Rebuild the m_ClassIDToMonoClass lookup table
+ RebuildClassIDToScriptingClass ();
+ RebuildCommonMonoClasses ();
+
+#if UNITY_EDITOR
+
+ // Rebuild all MonoScript classes cached info
+ vector<MonoScript*> scripts;
+ Object::FindObjectsOfType (&scripts);
+ for (int i=0;i<scripts.size ();i++)
+ {
+ MonoScript& script = *scripts[i];
+ MonoClass* klass = GetMonoClassWithAssemblyName (script.GetScriptClassName (), script.GetNameSpace(), script.GetAssemblyName ());
+ #if !UNITY_RELEASE
+ AssertInvalidAssembly(klass);
+ #endif
+
+ script.Rebuild (klass);
+ }
+
+ // Rebuild all mono instances!
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour>(savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+ behaviour->RebuildMonoInstance (SCRIPTING_NULL);
+
+ if (behaviour->GetGameObjectPtr())
+ behaviour->GetGameObjectPtr ()->SetSupportedMessagesDirty ();
+ }
+
+ // Reload all MonoBehaviours from the Backup
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour>(savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+
+ BackupState* backup = behaviour->GetBackup ();
+
+ // We now have an instance
+ // So read the state from the behaviours own backup
+ if (backup != NULL && behaviour->GetInstance ())
+ {
+ int flags = 0;
+ if (!backup->loadedFromDisk)
+ flags = kSerializeDebugProperties | kSerializeMonoReload;
+
+ behaviour->RestoreInstanceStateFromBackup (*backup, flags);
+ behaviour->SetBackup (NULL);
+ }
+
+ AssertIf (behaviour->GetInstance () != NULL && behaviour->GetBackup () != NULL);
+ }
+
+
+ // Add to manager and Awake from load comes last because we want everything to have the correct backup already loaded and ready.
+ for (int i = 0; i < savedData.m_SavedBehaviours.size (); i++)
+ {
+ behaviour = PPtr<MonoBehaviour> (savedData.m_SavedBehaviours[i]);
+ if (behaviour == NULL)
+ continue;
+
+ behaviour->CheckConsistency ();
+ behaviour->AwakeFromLoad (kDefaultAwakeFromLoad);
+
+ behaviour->DidReloadDomain();
+ }
+
+ /////////@TODO: Switch this to didReloadMonoDomain
+ // Notify AudioScriptBufferManager to reload buffers
+ if (GetAudioManager().GetScriptBufferManagerPtr())
+ GetAudioManager().GetScriptBufferManager().DidReloadDomain();
+
+ SetupLoadedEditorAssemblies ();
+
+ GlobalCallbacks::Get().didReloadMonoDomain.Invoke();
+
+ if (m_LogAssemblyReload)
+ {
+ LogString("Mono: successfully reloaded assembly\n");
+ }
+ else
+ {
+ printf_console ("Mono: successfully reloaded assembly\n");
+ }
+ #else
+ ErrorIf(Object::FindAllDerivedObjects (ClassID(MonoBehaviour), NULL) != 0);
+ ErrorIf(Object::FindAllDerivedObjects (ClassID(MonoScript), NULL) != 0);
+ #endif
+
+ #if UNITY_EDITOR
+
+ // Allow static editor classes to reconstruct their state
+ if (GetAssembly(kEditorAssembly) != NULL)
+ CallStaticMonoMethod ("AssemblyReloadEvents", "OnAfterAssemblyReload");
+
+ if (savedData.m_SavedScriptReloadProperties.IsValid ())
+ {
+ void* arg[] = { Scripting::ScriptingWrapperFor(savedData.m_SavedScriptReloadProperties) };
+ CallStaticMonoMethod("ScriptReloadProperties", "Load", arg);
+
+ DestroySingleObject (savedData.m_SavedScriptReloadProperties);
+ }
+ #endif
+
+ printf_console("- Completed reload, in %6.3f seconds\n", GetElapsedTimeInSeconds(savedData.reloadStart));
+
+ return failedLoadingSomeAssemblies ? kFailedLoadingScriptAssemblies : kEverythingLoaded;
+}
+
+void MonoManager::RebuildClassIDToScriptingClass ()
+{
+ ScriptingManager::RebuildClassIDToScriptingClass();
+ int size = m_ClassIDToMonoClass.size();
+ m_ClassIDToVTable.clear();
+ m_ClassIDToVTable.resize (size,NULL);
+ gClassIDToVTable = &m_ClassIDToVTable[0];
+
+ for(int i=0; i!=size; i++)
+ {
+ if (m_ClassIDToMonoClass[i]==NULL) continue;
+ m_ClassIDToVTable[i] = mono_class_vtable(mono_domain_get(), m_ClassIDToMonoClass[i]);
+
+ AssertIf ((m_ClassIDToMonoClass[i] == NULL) != (m_ClassIDToVTable[i] == NULL));
+ }
+}
+
+void MonoManager::CleanupClassIDMaps()
+{
+ m_ClassIDToMonoClass.clear ();
+ m_ClassIDToVTable.clear ();
+ gClassIDToVTable = &m_ClassIDToVTable[0];
+ gClassIDToClass = SCRIPTING_NULL;
+
+ memset(&m_CommonScriptingClasses, 0, sizeof(m_CommonScriptingClasses) );
+}
+
+MonoClass* MonoManager::GetBuiltinMonoClass (const char* name, bool optional)
+{
+ MonoClass* klass = NULL;
+ if (m_ScriptImages[kEngineAssembly])
+ klass = mono_class_from_name (m_ScriptImages[kEngineAssembly], "UnityEngine", name);
+
+ if (klass)
+ return klass;
+ else if (!optional)
+ {
+ ErrorString (Format ("Mono Class %s couldn't be found! This might lead to random crashes later on!", name));
+ return NULL;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+#if UNITY_EDITOR
+MonoClass* MonoManager::GetBuiltinEditorMonoClass (const char* name)
+{
+ MonoClass* klass = NULL;
+ if (m_ScriptImages[kEditorAssembly])
+ klass = mono_class_from_name (m_ScriptImages[kEditorAssembly], "UnityEditor", name);
+
+ if (klass)
+ return klass;
+ else
+ {
+ ErrorString (Format ("Mono Class %s couldn't be found! This might lead to random crashes later on!", name));
+ return NULL;
+ }
+}
+#endif
+
+void MonoManager::RebuildCommonMonoClasses ()
+{
+ FillCommonScriptingClasses(m_CommonScriptingClasses);
+
+ ScriptingMethodPtr setProject = m_CommonScriptingClasses.stackTraceUtilitySetProjectFolder;
+ if (setProject)
+ {
+ MonoException* exception;
+ std::string projectFolder = File::GetCurrentDirectory ();
+ if( !projectFolder.empty() )
+ projectFolder += kPathNameSeparator;
+ ConvertSeparatorsToPlatform( projectFolder );
+
+ void* values[1] = { MonoStringNew (projectFolder) };
+ mono_runtime_invoke_profiled (setProject->monoMethod, NULL, values, &exception);
+ if (exception)
+ Scripting::LogException (exception, 0);
+ }
+}
+
+
+MonoObject* MonoInstantiateScriptingWrapperForClassID(int classID)
+{
+ MonoVTable* vtable = gClassIDToVTable[classID];
+ if (!vtable)
+ return NULL;
+
+ return mono_object_new_alloc_specific (vtable);
+}
+DOES_NOT_RETURN void RaiseDotNetExceptionImpl (const char* ns, const char* type, const char* format, va_list list)
+{
+ va_list ap;
+ va_copy (ap, list);
+
+ char buffer[1024 * 5];
+ vsnprintf (buffer, 1024 * 5, format, ap);
+ va_end (ap);
+
+ MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), ns, type, buffer);
+ mono_raise_exception (exception);
+
+}
+
+DOES_NOT_RETURN void RaiseSystemExceptionImpl (const char* type, const char* format, va_list list)
+{
+ va_list ap;
+ va_copy (ap, list);
+ RaiseDotNetExceptionImpl("System",type,format,ap);
+}
+
+void RaiseManagedException (const char *ns, const char *type, const char *format, ...)
+{
+ va_list va;
+ va_start (va, format);
+ RaiseDotNetExceptionImpl (ns, type, format, va);
+}
+
+void RaiseMonoException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+
+ char buffer[1024 * 5];
+ vsnprintf (buffer, 1024 * 5, format, va);
+
+ MonoException* exception = mono_exception_from_name_msg (GetMonoManager ().GetEngineImage (), kEngineNameSpace, "UnityException", buffer);
+ mono_raise_exception (exception);
+}
+
+void RaiseOutOfRangeException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+ RaiseSystemExceptionImpl("IndexOutOfRangeException", format, va);
+}
+
+void RaiseNullException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+ RaiseSystemExceptionImpl("NullReferenceException", format, va);
+}
+
+void RaiseArgumentException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+ RaiseSystemExceptionImpl("ArgumentException", format, va);
+}
+
+void RaiseInvalidOperationException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+ RaiseSystemExceptionImpl("InvalidOperationException", format, va);
+}
+
+void RaiseSecurityException (const char* format, ...)
+{
+ va_list va;
+ va_start( va, format );
+ RaiseDotNetExceptionImpl("System.Security","SecurityException", format, va);
+}
+
+void RaiseNullExceptionObject (MonoObject* object)
+{
+ #if MONO_QUALITY_ERRORS
+ if (object)
+ {
+ MonoClass* klass = mono_object_get_class(object);
+ if (mono_class_is_subclass_of (mono_object_get_class(object), GetMonoManager().ClassIDToScriptingClass(ClassID(Object)), false))
+ {
+ UnityEngineObjectMemoryLayout& data = ExtractMonoObjectData<UnityEngineObjectMemoryLayout>(object);
+ string error = MonoStringToCpp(data.error);
+
+ // The object was destroyed underneath us - but if we hit a MissingReferenceException then we show that instead!
+ if (data.instanceID != 0 && error.find ("MissingReferenceException:") != 0)
+ {
+ error = Format("The object of type '%s' has been destroyed but you are still trying to access it.\n"
+ "Your script should either check if it is null or you should not destroy the object.", mono_class_get_name(klass));
+
+ MonoException* exception = mono_exception_from_name_msg (GetMonoManager().GetEngineImage(), "UnityEngine", "MissingReferenceException", error.c_str());
+ mono_raise_exception (exception);
+ }
+
+ // We got an error message, parse it and throw it
+ if (data.error)
+ {
+ error = MonoStringToCpp(data.error);
+ string::size_type exceptionTypePos = error.find(':');
+ if (exceptionTypePos != string::npos)
+ {
+ string type = string(error.begin(), error.begin() + exceptionTypePos);
+ error.erase(error.begin(), error.begin()+exceptionTypePos + 1);
+
+ MonoException* exception = mono_exception_from_name_msg (GetMonoManager().GetEngineImage(), "UnityEngine", type.c_str(), error.c_str ());
+ mono_raise_exception (exception);
+ }
+ }
+ }
+ }
+
+ MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "NullReferenceException", "");
+ mono_raise_exception (exception);
+ #else
+ MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "NullReferenceException", "");
+ mono_raise_exception (exception);
+ #endif
+}
+
+MonoObject* InstantiateScriptingWrapperForClassID(int classID)
+{
+ MonoVTable* vtable = gClassIDToVTable[classID];
+ if (!vtable)
+ return NULL;
+
+ return mono_object_new_alloc_specific (vtable);
+}
+
+#if UNITY_EDITOR
+bool AmIBeingDebugged();
+#endif
+
+
+#if UNITY_EDITOR
+extern "C" {
+ void *mono_trace_parse_options (char *options);
+ extern void *mono_jit_trace_calls;
+}
+#endif
+
+#if USE_MONO_DOMAINS
+
+void MonoManager::UnloadAllAssembliesOnNextDomainReload()
+{
+#if USE_TWO_MONO_DOMAINS
+ if (m_AssemblyReferencingDomain != NULL)
+ mono_domain_unload(m_AssemblyReferencingDomain);
+ m_AssemblyReferencingDomain = NULL;
+#endif
+}
+
+void MonoManager::PopulateAssemblyReferencingDomain()
+{
+#if USE_TWO_MONO_DOMAINS
+ //if unityeditor isn't loaded yet (first time), return, since we depend on some managed code to do our work.
+ if (m_ScriptImages.empty())
+ return;
+
+ if (m_AssemblyReferencingDomain == NULL)
+ {
+ printf_console("Not loading any assemblies in assemblyreferencingdomain, since the domain doesn't exist\n");
+ return;
+ }
+
+ MonoException* exc = NULL;
+ printf_console("- GetNamesOfAssembliesLoadedInCurrentDomain\n");
+ ScriptingArrayPtr result = (ScriptingArrayPtr) CallStaticMonoMethod("AssemblyHelper","GetNamesOfAssembliesLoadedInCurrentDomain",NULL,&exc);
+
+ if (exc!=NULL)
+ {
+ ErrorString("Failed calling GetNamesOfAssembliesLoadedInCurrentDomain");
+ return;
+ }
+
+ for (int i=0; i!= GetScriptingArraySize(result); i++)
+ {
+ string filename(ScriptingStringToCpp(Scripting::GetScriptingArrayElement<MonoString*>(result,i)));
+
+ if (IsThisFileAnAssemblyThatCouldChange(filename))
+ continue;
+
+ printf_console("- loading assembly into m_AssemblyReferencingDomain: %s\n",filename.c_str());
+ MonoAssembly* a = mono_domain_assembly_open(m_AssemblyReferencingDomain,filename.c_str());
+ if (a == NULL)
+ ErrorString(Format("Failed to load assembly: %s into temporary domain\n",filename.c_str()));
+ }
+#endif
+}
+
+MonoDomain* CreateAndSetChildDomain()
+{
+ MonoDomain* old_domain = mono_domain_get();
+
+ // Unload the old domain
+ UnloadDomain ();
+
+ //there should only ever be one child domain, so if we're making a new one,
+ //we better be in the rootdomain.
+ AssertIf(mono_get_root_domain() != mono_domain_get());
+
+ MonoDomain* newDomain = mono_domain_create_appdomain("Unity Child Domain", NULL);
+
+ AssertIf(mono_get_root_domain() != mono_domain_get());
+
+ // Activate the domain!
+ if (newDomain)
+ {
+ mono_thread_push_appdomain_ref(newDomain);
+
+ if (!mono_domain_set (newDomain, false))
+ {
+ printf_console("Exception setting domain\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ printf_console("Failed to create domain\n");
+ return NULL;
+ }
+
+
+ AssertIf(mono_domain_get () == mono_get_root_domain());
+ AssertIf(mono_domain_get () == NULL);
+ AssertIf(mono_domain_get () == old_domain);
+ UNUSED(old_domain);
+
+ MonoDomainIncrementUniqueId();
+
+ return mono_domain_get ();
+}
+
+
+static void UnloadDomain ()
+{
+ if (gUnloadDomainCallback)
+ gUnloadDomainCallback();
+
+ ClearLogCallback ();
+
+ //make sure to be in the domain you want to unload.
+ MonoDomain* domainToUnload = mono_domain_get();
+
+ //never unload the rootdomain
+ if (domainToUnload && domainToUnload != mono_get_root_domain())
+ {
+ // you can only unload a domain when it's not the active domain, so we're going to switch to the rootdomain,
+ // so we can kill the childdomain.
+ if (!mono_domain_set(mono_get_root_domain(), false))
+ {
+ printf_console("Exception setting domain\n");
+ }
+ mono_thread_pop_appdomain_ref();
+ mono_domain_unload(domainToUnload);
+ }
+
+ //unloading a domain is also a nice point in time to have the GC run.
+ mono_gc_collect(mono_gc_max_generation());
+
+#if UNITY_PLUGINS_AVAILABLE
+ //@TODO: Have Mono release its DLL handles (see case 373275). Until that is the case,
+ // this is disabled as it results in a change of behavior (plugin functions can get called multiple
+ // times in the editor which as long as we don't actually release the DLLs doesn't really make
+ // sense).
+ //UnloadAllPlugins ();
+#endif
+}
+#endif
+
+#if UNITY_OSX && !UNITY_IPHONE && !UNITY_PEPPER
+void SetupSignalHandler(int signal)
+{
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_sigaction = HandleSignal;
+ action.sa_flags = SA_SIGINFO;
+ if(sigaction(signal, &action, NULL) < 0)
+ printf_console("Error setting signal handler for signal %d\n",signal);
+ }
+#endif
+
+void SetupSignalHandlers()
+{
+
+#if UNITY_OSX
+# if WEBPLUG
+ //Remove possible existing mach exception handlers which interfere with our exception handling (ie Firefox)
+ mach_port_t current_task = mach_task_self();
+ exception_mask_t exceptionMask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
+ task_set_exception_ports(current_task, exceptionMask, 0, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+# endif
+
+# if !UNITY_IPHONE && !UNITY_PEPPER
+ SetupSignalHandler(SIGSEGV);
+ SetupSignalHandler(SIGBUS);
+ SetupSignalHandler(SIGFPE);
+ SetupSignalHandler(SIGILL);
+#endif
+#endif
+
+// Make sure abort() calls get passed to the crash handler
+#if UNITY_WIN
+ _set_abort_behavior (0, _WRITE_ABORT_MSG);
+ signal (SIGABRT, HandleAbort);
+#endif
+
+#if UNITY_WIN || UNITY_OSX || UNITY_ANDROID || UNITY_BB10 || UNITY_TIZEN
+ //this causes mono to forward the signal to us, if the signal is not mono related. (i.e. not a breakpoint, or a managed nullref exception, etc)
+ mono_set_signal_chaining(1);
+#endif
+}
+
+bool ShouldGiveDebuggerChanceToAttach()
+{
+#if SUPPORT_ENVIRONMENT_VARIABLES
+ if (getenv("UNITY_GIVE_CHANCE_TO_ATTACH_DEBUGGER"))
+ return true;
+#endif
+ return false;
+}
+
+void GiveDebuggerChanceToAttachIfRequired()
+{
+ if (ShouldGiveDebuggerChanceToAttach())
+ {
+#if UNITY_WIN && !UNITY_XENON && !UNITY_WINRT
+ MessageBoxW(0,L"You can attach a debugger now if you want",L"Debug",MB_OK);
+#endif
+#if UNITY_OSX
+ CFStringRef msg = CFSTR ("You can attach a debugger now if you want");
+ CFOptionFlags responseFlags;
+ CFUserNotificationDisplayAlert (0.0, kCFUserNotificationPlainAlertLevel, NULL, NULL, NULL, msg, NULL, NULL, NULL, NULL, &responseFlags);
+#endif
+ }
+}
+
+void StoreGlobalMonoPaths (const std::vector<string>& monoPaths)
+{
+#if UNITY_WIN && !UNITY_WINRT
+
+ MonoPathContainer::GetMonoPaths().reserve(monoPaths.size());
+
+ for (vector<string>::const_iterator it = monoPaths.begin(); it != monoPaths.end(); ++it)
+ {
+ wchar_t widePath[kDefaultPathBufferSize];
+ ConvertUnityPathName(it->c_str(), widePath, kDefaultPathBufferSize);
+
+ wchar_t fullPath[kDefaultPathBufferSize];
+ GetFullPathNameW(widePath, kDefaultPathBufferSize, fullPath, NULL);
+
+ string unityPath;
+ ConvertWindowsPathName(fullPath, unityPath);
+
+ MonoPathContainer::GetMonoPaths().push_back(unityPath);
+ }
+
+#else
+ MonoPathContainer::SetMonoPaths(monoPaths);
+#endif
+}
+
+static std::string BuildMonoPath (const std::vector<string>& monoPaths)
+{
+#if UNITY_WIN
+ const char* separator = ";";
+#else
+ const char* separator = ":";
+#endif
+
+ string monoPath;
+ for (int i=0;i!=monoPaths.size();i++)
+ {
+ if (i!=0) monoPath.append(separator);
+ monoPath.append(monoPaths[i]);
+ }
+
+ return monoPath;
+}
+
+static void SetupMonoPaths (const std::vector<string>& monoPaths, const std::string& monoConfigPath)
+{
+ // Mono will not look for the loaded Boo assembly if the version is different.
+ // It will look in the mono path and next to the loading dll.
+ // In web player Boo.Lang.dll is in different location than the rest of mono,
+ // hence we setup multiple assembly paths.
+ for (int i = 0; i < monoPaths.size(); i++)
+ printf_console("Mono path[%d] = '%s'\n", i, monoPaths[i].c_str());
+ printf_console ("Mono config path = '%s'\n", monoConfigPath.c_str ());
+ mono_set_dirs (monoPaths[0].c_str(), monoConfigPath.c_str());
+
+#if !UNITY_PEPPER
+ mono_set_assemblies_path(BuildMonoPath (monoPaths).c_str ());
+#endif
+
+ StoreGlobalMonoPaths (monoPaths);
+}
+
+static void InitializeMonoDebugger (bool forceEnable=false)
+{
+ // Set up debugger
+ string monoOptions;
+
+#if MONO_2_12
+ const string defaultDebuggerOptions = "--debugger-agent=transport=dt_socket,embedding=1,server=y,suspend=n";
+#else
+ const string defaultDebuggerOptions = "--debugger-agent=transport=dt_socket,embedding=1,defer=y";
+#endif
+
+#if UNITY_EDITOR
+ if (EditorPrefs::GetBool ("AllowAttachedDebuggingOfEditor", true))
+ {
+ // Editor always listens on default port
+ monoOptions = defaultDebuggerOptions;
+ }
+#endif
+
+#if SUPPORT_ENVIRONMENT_VARIABLES
+ // MONO_ARGUMENTS overrides everything
+ char* args = getenv("MONO_ARGUMENTS");
+ if (args!=0)
+ {
+ monoOptions = args;
+ }
+#endif
+#if ENABLE_PLAYERCONNECTION && !UNITY_FLASH
+ // Allow attaching using player connection discovery
+ if (monoOptions.empty ())
+ {
+ PlayerConnection::Initialize (PLAYER_DATA_FOLDER, forceEnable);
+ if (PlayerConnection::Get ().AllowDebugging ()) {
+ // Must be synchronized with Unity SDB addin
+ unsigned debuggerPort = 56000 + (PlayerConnection::Get ().GetLocalGuid () % 1000);
+ monoOptions = defaultDebuggerOptions + Format (",address=0.0.0.0:%u", debuggerPort);
+ }
+ }
+#endif
+
+
+ if (!monoOptions.empty ())
+ {
+ char *optionArray[] = { (char*)monoOptions.c_str () };
+ printf_console ("Using monoOptions %s\n", monoOptions.c_str ());
+ mono_jit_parse_options(1, optionArray);
+ gDebuggerEnabled = true;
+ }
+
+#if !ALWAYS_LOAD_MDBS
+ if (gDebuggerEnabled)
+#endif
+ {
+ //this is not so much about debugging (although also required for debugging), but it's about being able to load .mdb files, which you need for nice stacktraces, lineinfo, etc.
+ mono_debug_init (1);
+ }
+}
+
+void MonoPrintfRedirect(const char* msg, va_list list)
+{
+ va_list args;
+ va_copy (args, list);
+ printf_consolev(LogType_Debug,msg,args);
+ va_end (args);
+}
+
+#if UNITY_NACL_WEBPLAYER
+extern "C" {
+ void mono_set_pthread_suspend(int (*_pthread_suspend)(pthread_t thread, int sig));
+ int pthreadsuspend_initialize(void);
+ int pthread_suspend(pthread_t thread, int sig);
+}
+#endif
+
+bool InitializeMonoFromMain (const std::vector<string>& monoPaths, string monoConfigPath, int argc, const char** argv, bool enableDebugger)
+{
+ s_MonoDomainContainer = UNITY_NEW_AS_ROOT(int,kMemMono, "MonoDomain", "");
+ SET_ALLOC_OWNER(s_MonoDomainContainer);
+
+ MonoPathContainer::StaticInitialize();
+
+ const char *emptyarg = "";
+ GiveDebuggerChanceToAttachIfRequired();
+
+
+ #if DEBUGMODE
+ printf_console( "Initialize mono\n" );
+ #endif
+
+// Debug helpers
+#if 0
+ mono_unity_set_vprintf_func(MonoPrintfRedirect);
+
+ //setenvvar ("MONO_DEBUG", "abort-on-sigsegv");
+ //setenvvar ("MONO_LOG_MASK", "all");
+ //setenvvar ("MONO_LOG_LEVEL", "debug");
+ //setenvvar("MONO_TRACE","Console.Out:++++ ");
+
+ // Tracing mask
+ #if UNITY_EDITOR
+ mono_trace_set_mask_string("all"); // "asm", "type", "dll", "gc", "cfg", "aot", "all",
+ mono_trace_set_level_string("debug");// "error", "critical", "warning", "message", "info", "debug"
+ //mono_jit_trace_calls = mono_trace_parse_options ("Console.Out:++++ ");
+ #endif
+#endif
+
+ SetupMonoPaths (monoPaths, monoConfigPath);
+
+ mono_config_parse (NULL);
+
+ SetupSignalHandlers();
+
+ mono_set_defaults (0, mono_parse_default_optimizations (NULL));
+
+#if USE_MONO_DEBUGGER
+ InitializeMonoDebugger (enableDebugger);
+#endif
+
+ if (argv==NULL) argv = &emptyarg;
+#if !UNITY_XENON && ! UNITY_PS3 && !UNITY_IPHONE && !UNITY_PEPPER && !UNITY_WII
+ mono_set_commandline_arguments(argc,argv, NULL);
+#endif
+
+#if UNITY_NACL
+#if UNITY_NACL_WEBPLAYER
+ pthreadsuspend_initialize ();
+
+ mono_set_pthread_suspend (pthread_suspend);
+#endif
+
+ CompressedFileStream::Data* data = CompressedFileStream::GetResources().Find("mscorlib.dll");
+ if (data == NULL)
+ {
+ ErrorString ("Could not find mscorlib in web stream!");
+ return false;
+ }
+
+ MemoryCacherReadBlocks cacher (data->blocks, data->end, kCacheBlockSize);
+ gCorLibMemory = (UInt8*)UNITY_ALLOC(kMemMono, data->GetSize(), 32);
+ cacher.DirectRead(gCorLibMemory, data->offset, data->GetSize());
+ mono_set_corlib_data (gCorLibMemory, data->GetSize());
+
+ mono_install_assembly_postload_search_hook (AssemblyLoadHook, NULL);
+
+ mono_jit_parse_options(argc, (char**)argv);
+#endif
+
+
+// mono_runtime_set_no_exec (true);
+#if MONO_2_12
+ MonoDomain* domain = mono_jit_init_version ("Unity Root Domain", "v4.0.30319");
+#else
+ MonoDomain* domain = mono_jit_init_version ("Unity Root Domain", "v2.0.50727");
+#endif
+ if (domain == NULL)
+ return false;
+
+#if WEBPLUG && (!UNITY_PEPPER || UNITY_NACL_WEBPLAYER)
+ mono_set_ignore_version_and_key_when_finding_assemblies_already_loaded(true);
+#endif
+
+ // The soft debugger needs this
+ mono_thread_set_main (mono_thread_current ());
+
+#if ENABLE_MONO_MEMORY_PROFILER
+ //mono_gc_base_init (); ask joachim why we need this.
+
+ mono_profiler_startup ();
+#endif
+
+#if !UNITY_XENON && !UNITY_PS3 && !UNITY_IPHONE && !UNITY_PEPPER && !UNITY_WII
+ mono_unity_set_embeddinghostname("Unity");
+#endif
+
+#if !UNITY_PEPPER
+ mono_runtime_unhandled_exception_policy_set (MONO_UNHANDLED_POLICY_LEGACY);
+#endif
+
+ RegisterAllInternalCalls();
+
+ return true;
+}
+
+#if !UNITY_WII && !UNITY_PS3 && !UNITY_XENON && !UNITY_IPHONE && !UNITY_ANDROID && !UNITY_PEPPER && !UNITY_LINUX && !UNITY_BB10 && !UNITY_TIZEN
+
+#if UNITY_OSX
+
+#include <dlfcn.h>
+#include <cxxabi.h>
+
+void PrintStackTraceOSX (void* context)
+{
+ void *array[256];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = mono_backtrace_from_context (context, array, 256);
+
+ printf_console ("Obtained %zu stack frames.\n", size);
+
+ for (i = 0; i < size; i++)
+ {
+ const char* symbolName = mono_pmip(array[i]);
+ if (!symbolName)
+ {
+ Dl_info dlinfo;
+ dladdr(array[i], &dlinfo);
+ symbolName = dlinfo.dli_sname;
+ if (symbolName)
+ {
+ int status = 0;
+ char* cname = abi::__cxa_demangle(symbolName, 0, 0, &status);
+ if (status == 0 && cname)
+ symbolName = cname;
+ }
+ }
+
+ printf_console ("#%-3d%016p in %s\n", i, array[i], symbolName);
+ }
+
+ free (strings);
+}
+
+
+void HandleSignal (int i, __siginfo* info, void* p)
+#endif
+#if UNITY_WIN
+int __cdecl HandleSignal( EXCEPTION_POINTERS* ep )
+#endif
+{
+ printf_console("Receiving unhandled NULL exception\n");
+
+ #if UNITY_EDITOR
+
+ // ---- editor
+
+ #if UNITY_OSX
+ printf_console("Launching bug reporter\n");
+ PrintStackTraceOSX(p);
+ LaunchBugReporter (kCrashbug);
+
+ #elif UNITY_WIN
+
+ winutils::ProcessInternalCrash(ep, false);
+
+ if( gUnityCrashHandler )
+ {
+ printf_console( "unity: Launch crash handler\n" );
+ return gUnityCrashHandler->ProcessCrash( ep );
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+
+ #else
+ #error "Unknown platform"
+ #endif
+
+ #else
+ // ---- player
+
+ // We are hitting this from inside a mono method, so lets just keep going!
+ if (mono_thread_current() != NULL && mono_method_get_last_managed() != NULL)
+ {
+ #if WEBPLUG
+ ExitWithErrorCode(kErrorFatalException);
+ #endif
+
+ #if UNITY_OSX
+ abort();
+ #endif
+
+ #if UNITY_WIN
+ return EXCEPTION_EXECUTE_HANDLER;
+ #endif
+
+ }
+ else
+ {
+ // we have a serious exception - launch crash reporter
+ #if UNITY_WIN && USE_WIN_CRASH_HANDLER
+
+ winutils::ProcessInternalCrash(ep, false);
+
+ if( gUnityCrashHandler ) {
+ printf_console( "unity: Launch crash handler\n" );
+ return gUnityCrashHandler->ProcessCrash( ep );
+ }
+ #endif
+
+ #if WEBPLUG
+ ExitWithErrorCode(kErrorFatalException);
+ #endif
+
+ #if UNITY_OSX
+ abort();
+ #endif
+
+ #if UNITY_WIN
+ return EXCEPTION_EXECUTE_HANDLER;
+ #endif
+ }
+ #endif
+}
+
+#endif // !UNITY_WII && !UNITY_PS3 && !UNITY_XENON && !UNITY_IPHONE && !UNITY_ANDROID && !UNITY_PEPPER && !UNITY_LINUX
+
+#if UNITY_WIN
+void __cdecl HandleAbort (int signal)
+{
+ printf_console ("Received abort signal from the operating system\n");
+ #if UNITY_EDITOR
+ LaunchBugReporter (kFatalError);
+ #endif
+}
+#endif
+
+void UnhandledExceptionHandler (MonoObject* object)
+{
+ printf_console("Receiving unhandled exception\n");
+
+ #if UNITY_EDITOR
+ LaunchBugReporter (kFatalError);
+ #elif WEBPLUG
+
+ #else
+ #endif
+}
+
+#if USE_MONO_DOMAINS
+bool CleanupMonoReloadable ()
+{
+
+ UnloadDomain();
+ return true;
+}
+#endif
+
+void CleanupMono ()
+{
+ #if DEBUGMODE
+ printf_console( "Cleanup mono\n" );
+ #endif
+
+ RegisterLogPreprocessor (NULL);
+
+#if USE_MONO_DOMAINS
+ UnloadDomain();
+#endif
+
+ mono_runtime_set_shutting_down ();
+#if !UNITY_PEPPER
+ mono_threads_set_shutting_down ();
+ mono_thread_pool_cleanup ();
+ mono_thread_suspend_all_other_threads ();
+#endif
+ mono_jit_cleanup(mono_get_root_domain());
+
+ #if UNITY_PEPPER
+ UNITY_FREE (kMemMono, gCorLibMemory);
+ #endif
+
+ #if UNITY_OSX
+ struct sigaction sa;
+ sa.sa_sigaction = NULL;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = UNITY_SA_DISABLE;
+ sigaction (SIGSEGV, &sa, NULL);
+
+ sa.sa_sigaction = NULL;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = UNITY_SA_DISABLE;
+ sigaction (SIGABRT, &sa, NULL);
+ #endif
+
+ MonoPathContainer::StaticDestroy();
+
+ UNITY_DELETE(s_MonoDomainContainer,kMemMono);
+}
+
+void PostprocessStacktrace(const char* stackTrace, std::string& processedStackTrace)
+{
+ if (GetMonoManagerPtr () && GetMonoManager ().GetCommonClasses ().postprocessStacktrace)
+ {
+ MonoException* exception = NULL;
+ int stripEngineInternalInformation = UNITY_RELEASE;
+ void* arg[] = { MonoStringNew(stackTrace), &stripEngineInternalInformation };
+
+
+ MonoString* msTrace = (MonoString*)mono_runtime_invoke_profiled (GetMonoManager ().GetCommonClasses ().postprocessStacktrace->monoMethod, NULL, arg, &exception);
+ if (exception)
+ {
+ printf_console ("Failed to postprocess stacktrace\n");
+ return;
+ }
+ processedStackTrace = MonoStringToCpp (msTrace);
+ }
+}
+
+static void ExtractMonoStacktrace (const std::string& condition, std::string& processedStackTrace, std::string& stackTrace, int errorNum, string& file, int* line, int type, int targetInstanceID)
+{
+#if UNITY_WII
+ // When debugger is running on Wii, mono stack extraction fails for unknown reasons
+ // But if running without debugger it works fine
+ if (wii::IsDebuggerPresent()) return;
+#endif
+
+#if SUPPORT_THREADS
+ const bool isMainThread = Thread::EqualsCurrentThreadID(Thread::mainThreadId);
+#else
+ const bool isMainThread = true;
+#endif
+ if (isMainThread && mono_thread_current() != NULL && mono_method_get_last_managed () != NULL && (type & kDontExtractStacktrace) == 0)
+ {
+ MonoClass* stackTraceUtil = GetMonoManager ().GetMonoClass ("StackTraceUtility", kEngineNameSpace);
+ if (stackTraceUtil)
+ {
+ void* iter = NULL;
+ MonoMethod* method;
+ while ((method = mono_class_get_methods (stackTraceUtil, &iter))) {
+ const char* curName = mono_method_get_name (method);
+ if (strcmp ("ExtractStackTrace", curName) == 0)
+ break;
+ }
+
+ if (method)
+ {
+ MonoException* exception = NULL;
+ MonoString* msTrace = (MonoString*)mono_runtime_invoke_profiled (method, NULL, NULL, &exception);
+ if (exception)
+ {
+ printf_console ("Failed to extract mono stacktrace from Log message\n");
+ return;
+ }
+
+ stackTrace = MonoStringToCpp (msTrace);
+ if (!stackTrace.empty ())
+ {
+ int oldLine = *line;
+ string oldFile = file;
+ ExceptionToLineAndPath (stackTrace, *line, file);
+ if (!(type & kMayIgnoreLineNumber))
+ stackTrace = Format ("%s\n[%s line %d]", stackTrace.c_str (), oldFile.c_str(), oldLine);
+
+ PostprocessStacktrace(stackTrace.c_str(), processedStackTrace);
+ }
+ }
+ }
+ }
+}
+
+MonoMethod* FindStaticMonoMethod (MonoImage* image, const char* className, const char* nameSpace, const char* methodName)
+{
+ MonoClass* klass = mono_class_from_name(image,nameSpace,className);
+ if (!klass) return NULL;
+
+ MonoMethod* method = mono_class_get_method_from_name(klass,methodName,-1);
+ if (!method) return NULL;
+
+ return method;
+}
+
+MonoMethod* FindStaticMonoMethod (const char* nameSpace, const char* className, const char* methodName)
+{
+ MonoClass* klass = GetMonoManager ().GetMonoClass (className, nameSpace);
+ if (!klass)
+ return NULL;
+ return mono_class_get_method_from_name (klass, methodName, -1);
+}
+
+MonoMethod* FindStaticMonoMethod (const char* className, const char* methodName)
+{
+ MonoClass* klass = GetMonoManager ().GetMonoClass (className, kEngineNameSpace);
+ if (!klass)
+ klass = GetMonoManager ().GetMonoClass (className, kEditorNameSpace);
+ if (!klass)
+ klass = GetMonoManager ().GetMonoClass (className, kEditorInternalNameSpace);
+ if (!klass)
+ return NULL;
+
+ return mono_class_get_method_from_name (klass, methodName, -1);
+}
+
+std::string MdbFile (const std::string& path)
+{
+ return AppendPathNameExtension (path, "mdb");
+}
+std::string PdbFile (const std::string& path)
+{
+ int f = path.find(".dll");
+ return AppendPathNameExtension (f != -1 ? path.substr(0, f) : path, "pdb");
+}
+
+void ClearLogCallback ()
+{
+#if UNITY_HAS_DEVELOPER_CONSOLE
+ // By default redirect log output to the developer console
+ RegisterLogCallback(DeveloperConsole_HandleLogFunction, true);
+#else
+ RegisterLogCallback(NULL, false);
+#endif // UNITY_HAS_DEVELOPER_CONSOLE
+}
+
+template<class TransferFunction>
+void MonoManager::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.SetVersion(2);
+
+ #if UNITY_EDITOR
+ if (transfer.IsSerializingForGameRelease ())
+ {
+ transfer.Transfer (m_MonoScriptManager.m_RuntimeScripts, "m_Scripts");
+
+ //flash exports monomanager in a special way, it only requires m_Scripts
+ if (transfer.IsWritingGameReleaseData () && transfer.GetBuildingTarget().platform==kBuildFlash)
+ return;
+
+ transfer.Transfer (m_AssemblyNames, "m_AssemblyNames");
+ }
+ else if (transfer.GetFlags() & kPerformUnloadDependencyTracking)
+ {
+ transfer.Transfer (m_MonoScriptManager.m_RuntimeScripts, "m_Scripts");
+ }
+
+ #else
+ transfer.Transfer (m_MonoScriptManager.m_RuntimeScripts, "m_Scripts");
+ transfer.Transfer (m_AssemblyNames, "m_AssemblyNames");
+
+ if (transfer.IsOldVersion (1))
+ {
+ if (m_AssemblyNames.size() >= kScriptAssemblies)
+ {
+ m_AssemblyNames[0] = kEngineAssemblyName;
+ for (int i = 1; i < kScriptAssemblies; i++)
+ m_AssemblyNames[i] = "";
+ }
+
+ set<UnityStr> m_CustomDlls;
+ TRANSFER(m_CustomDlls);
+ for (std::set<UnityStr>::iterator i=m_CustomDlls.begin();i!=m_CustomDlls.end();i++)
+ {
+ if (find(m_AssemblyNames.begin(), m_AssemblyNames.end(), *i) == m_AssemblyNames.end())
+ m_AssemblyNames.push_back(*i);
+ }
+ }
+ #endif
+}
+
+
+IMPLEMENT_OBJECT_SERIALIZE (MonoManager)
+IMPLEMENT_CLASS (MonoManager)
+GET_MANAGER (MonoManager)
+GET_MANAGER_PTR (MonoManager)
+
+#endif //ENABLE_MONO