BsMonoManager.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "BsMonoManager.h"
  2. #include "BsException.h"
  3. #include "BsScriptMeta.h"
  4. #include "BsMonoAssembly.h"
  5. #include "BsMonoClass.h"
  6. #include "BsMonoUtil.h"
  7. #include <mono/metadata/assembly.h>
  8. #include <mono/metadata/mono-config.h>
  9. #include <mono/metadata/mono-gc.h>
  10. #include <mono/metadata/mono-debug.h>
  11. namespace BansheeEngine
  12. {
  13. const String MonoManager::MONO_LIB_DIR = "..\\..\\Mono\\lib";
  14. const String MonoManager::MONO_ETC_DIR = "..\\..\\Mono\\etc";
  15. MonoManager::MonoManager()
  16. :mRootDomain(nullptr), mScriptDomain(nullptr), mIsCoreLoaded(false)
  17. {
  18. mono_set_dirs(MONO_LIB_DIR.c_str(), MONO_ETC_DIR.c_str());
  19. #if BS_DEBUG_MODE
  20. mono_set_signal_chaining(true);
  21. mono_debug_init(MONO_DEBUG_FORMAT_MONO);
  22. #endif
  23. mono_config_parse(nullptr);
  24. mRootDomain = mono_jit_init_version("BansheeMono", "v4.0.30319"); // TODO: Allow user-defined version here?
  25. if (mRootDomain == nullptr)
  26. BS_EXCEPT(InternalErrorException, "Cannot initialize Mono runtime.");
  27. }
  28. MonoManager::~MonoManager()
  29. {
  30. for (auto& entry : mAssemblies)
  31. {
  32. bs_delete(entry.second);
  33. }
  34. mAssemblies.clear();
  35. if (mScriptDomain != nullptr)
  36. {
  37. mono_domain_set(mono_get_root_domain(), false);
  38. mono_domain_finalize(mScriptDomain, 2000);
  39. MonoObject* exception = nullptr;
  40. mono_domain_try_unload(mScriptDomain, &exception);
  41. if (exception != nullptr)
  42. MonoUtil::throwIfException(exception);
  43. mScriptDomain = nullptr;
  44. }
  45. if (mRootDomain != nullptr)
  46. {
  47. mono_jit_cleanup(mRootDomain);
  48. mRootDomain = nullptr;
  49. }
  50. }
  51. MonoAssembly& MonoManager::loadAssembly(const String& path, const String& name)
  52. {
  53. MonoAssembly* assembly = nullptr;
  54. if (mScriptDomain == nullptr)
  55. {
  56. mScriptDomain = mono_domain_create_appdomain(const_cast<char *>(path.c_str()), nullptr);
  57. mono_domain_set(mScriptDomain, false);
  58. if (mScriptDomain == nullptr)
  59. {
  60. BS_EXCEPT(InternalErrorException, "Cannot create script app domain.");
  61. }
  62. }
  63. auto iterFind = mAssemblies.find(name);
  64. if(iterFind != mAssemblies.end())
  65. {
  66. assembly = iterFind->second;
  67. }
  68. else
  69. {
  70. assembly = new (bs_alloc<MonoAssembly>()) MonoAssembly();
  71. mAssemblies[name] = assembly;
  72. }
  73. if(!assembly->mIsLoaded)
  74. {
  75. assembly->load(mScriptDomain, path, name);
  76. // Fully initialize all types that use this assembly
  77. Vector<ScriptMeta*>& mTypeMetas = getTypesToInitialize()[name];
  78. for(auto& meta : mTypeMetas)
  79. {
  80. meta->scriptClass = assembly->getClass(meta->ns, meta->name);
  81. if(meta->scriptClass == nullptr)
  82. BS_EXCEPT(InvalidParametersException, "Unable to find class of type: \"" + meta->ns + "::" + meta->name + "\"");
  83. if(meta->scriptClass->hasField("mCachedPtr"))
  84. meta->thisPtrField = meta->scriptClass->getField("mCachedPtr");
  85. else
  86. meta->thisPtrField = nullptr;
  87. meta->initCallback();
  88. }
  89. }
  90. if(!mIsCoreLoaded)
  91. {
  92. mIsCoreLoaded = true;
  93. MonoAssembly* corlib = new (bs_alloc<MonoAssembly>()) MonoAssembly();
  94. mAssemblies["corlib"] = corlib;
  95. corlib->loadFromImage(mono_get_corlib(), "corlib");
  96. }
  97. return *assembly;
  98. }
  99. void MonoManager::unloadAssembly(MonoAssembly& assembly)
  100. {
  101. ::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
  102. assembly.unload();
  103. if(monoAssembly)
  104. mono_assembly_close(monoAssembly);
  105. }
  106. MonoAssembly* MonoManager::getAssembly(const String& name) const
  107. {
  108. auto iterFind = mAssemblies.find(name);
  109. if(iterFind != mAssemblies.end())
  110. return iterFind->second;
  111. return nullptr;
  112. }
  113. void MonoManager::registerScriptType(ScriptMeta* metaData)
  114. {
  115. Vector<ScriptMeta*>& mMetas = getTypesToInitialize()[metaData->assembly];
  116. mMetas.push_back(metaData);
  117. }
  118. MonoClass* MonoManager::findClass(const String& ns, const String& typeName)
  119. {
  120. MonoClass* monoClass = nullptr;
  121. for(auto& assembly : mAssemblies)
  122. {
  123. monoClass = assembly.second->getClass(ns, typeName);
  124. if(monoClass != nullptr)
  125. return monoClass;
  126. }
  127. return nullptr;
  128. }
  129. MonoClass* MonoManager::findClass(::MonoClass* rawMonoClass)
  130. {
  131. MonoClass* monoClass = nullptr;
  132. for(auto& assembly : mAssemblies)
  133. {
  134. monoClass = assembly.second->getClass(rawMonoClass);
  135. if(monoClass != nullptr)
  136. return monoClass;
  137. }
  138. return nullptr;
  139. }
  140. String MonoManager::getFullTypeName(MonoObject* obj)
  141. {
  142. if(obj == nullptr)
  143. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  144. ::MonoClass* monoClass = mono_object_get_class(obj);
  145. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  146. String namespaceStr;
  147. if(nameSpaceChars != nullptr)
  148. namespaceStr = nameSpaceChars;
  149. const char* typeNameChars = mono_class_get_name(monoClass);
  150. String typeNameStr;
  151. if(typeNameChars != nullptr)
  152. typeNameStr = typeNameChars;
  153. return namespaceStr + "." + typeNameStr;
  154. }
  155. String MonoManager::getNamespace(MonoObject* obj)
  156. {
  157. if(obj == nullptr)
  158. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  159. ::MonoClass* monoClass = mono_object_get_class(obj);
  160. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  161. String namespaceStr;
  162. if(nameSpaceChars != nullptr)
  163. namespaceStr = nameSpaceChars;
  164. return namespaceStr;
  165. }
  166. String MonoManager::getTypeName(MonoObject* obj)
  167. {
  168. if(obj == nullptr)
  169. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  170. ::MonoClass* monoClass = mono_object_get_class(obj);
  171. const char* typeNameChars = mono_class_get_name(monoClass);
  172. String typeNameStr;
  173. if(typeNameChars != nullptr)
  174. typeNameStr = typeNameChars;
  175. return typeNameStr;
  176. }
  177. }