BsMonoManager.cpp 5.5 KB

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