BsMonoManager.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include "BsMonoManager.h"
  2. #include "BsException.h"
  3. #include "BsScriptMeta.h"
  4. #include "BsMonoAssembly.h"
  5. #include "BsMonoClass.h"
  6. #include <mono/metadata/assembly.h>
  7. #include <mono/metadata/mono-config.h>
  8. #include <mono/metadata/mono-gc.h>
  9. namespace BansheeEngine
  10. {
  11. const String MonoManager::MONO_LIB_DIR = "..\\..\\Mono\\lib";
  12. const String MonoManager::MONO_ETC_DIR = "..\\..\\Mono\\etc";
  13. MonoManager::MonoManager()
  14. :mDomain(nullptr), mIsCoreLoaded(false)
  15. {
  16. mono_set_dirs(MONO_LIB_DIR.c_str(), MONO_ETC_DIR.c_str());
  17. mono_config_parse(nullptr);
  18. }
  19. MonoManager::~MonoManager()
  20. {
  21. if (mDomain != nullptr)
  22. {
  23. // TODO - Someone suggested I need to GC collect and wait for finalizers before cleanup
  24. // I don't see how that would help unless I manually release all references before that as well
  25. // BUT that is a good way to debug those errors on exit
  26. // TODO: This might not be necessary
  27. //mono_gc_collect(mono_gc_max_generation());
  28. //mono_domain_finalize(mDomain, -1);
  29. // TODO: Commented out because it crashes for no reason
  30. mono_jit_cleanup(mDomain);
  31. mDomain = nullptr;
  32. }
  33. for (auto& entry : mAssemblies)
  34. {
  35. //unloadAssembly(*entry.second);
  36. //bs_delete(entry.second);
  37. }
  38. mAssemblies.clear();
  39. }
  40. MonoAssembly& MonoManager::loadAssembly(const String& path, const String& name)
  41. {
  42. MonoAssembly* assembly = nullptr;
  43. if(mDomain == nullptr)
  44. {
  45. mDomain = mono_jit_init (path.c_str());
  46. if(mDomain == nullptr)
  47. {
  48. BS_EXCEPT(InternalErrorException, "Cannot initialize Mono runtime.");
  49. }
  50. }
  51. auto iterFind = mAssemblies.find(name);
  52. if(iterFind != mAssemblies.end())
  53. {
  54. assembly = iterFind->second;
  55. }
  56. else
  57. {
  58. assembly = new (bs_alloc<MonoAssembly>()) MonoAssembly();
  59. mAssemblies[name] = assembly;
  60. }
  61. if(!assembly->mIsLoaded)
  62. {
  63. assembly->load(path, name);
  64. // Fully initialize all types that use this assembly
  65. Vector<ScriptMeta*>& mTypeMetas = getTypesToInitialize()[name];
  66. for(auto& meta : mTypeMetas)
  67. {
  68. meta->scriptClass = assembly->getClass(meta->ns, meta->name);
  69. if(meta->scriptClass == nullptr)
  70. BS_EXCEPT(InvalidParametersException, "Unable to find class of type: \"" + meta->ns + "::" + meta->name + "\"");
  71. if(meta->scriptClass->hasField("mCachedPtr"))
  72. meta->thisPtrField = meta->scriptClass->getField("mCachedPtr");
  73. else
  74. meta->thisPtrField = nullptr;
  75. meta->initCallback();
  76. }
  77. }
  78. if(!mIsCoreLoaded)
  79. {
  80. mIsCoreLoaded = true;
  81. MonoImage* existingImage = mono_image_loaded("mscorlib");
  82. if(existingImage != nullptr)
  83. {
  84. MonoAssembly* mscorlib = new (bs_alloc<MonoAssembly>()) MonoAssembly();
  85. mAssemblies["mscorlib"] = mscorlib;
  86. mscorlib->loadAsDependency(existingImage, "mscorlib");
  87. }
  88. else
  89. loadAssembly("mscorlib", "mscorlib");
  90. }
  91. return *assembly;
  92. }
  93. void MonoManager::unloadAssembly(MonoAssembly& assembly)
  94. {
  95. ::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
  96. assembly.unload();
  97. if(monoAssembly)
  98. mono_assembly_close(monoAssembly);
  99. }
  100. MonoAssembly* MonoManager::getAssembly(const String& name) const
  101. {
  102. auto iterFind = mAssemblies.find(name);
  103. if(iterFind != mAssemblies.end())
  104. return iterFind->second;
  105. return nullptr;
  106. }
  107. void MonoManager::registerScriptType(ScriptMeta* metaData)
  108. {
  109. Vector<ScriptMeta*>& mMetas = getTypesToInitialize()[metaData->assembly];
  110. mMetas.push_back(metaData);
  111. }
  112. MonoClass* MonoManager::findClass(const String& ns, const String& typeName)
  113. {
  114. MonoClass* monoClass = nullptr;
  115. for(auto& assembly : mAssemblies)
  116. {
  117. monoClass = assembly.second->getClass(ns, typeName);
  118. if(monoClass != nullptr)
  119. return monoClass;
  120. }
  121. return nullptr;
  122. }
  123. MonoClass* MonoManager::findClass(::MonoClass* rawMonoClass)
  124. {
  125. MonoClass* monoClass = nullptr;
  126. for(auto& assembly : mAssemblies)
  127. {
  128. monoClass = assembly.second->getClass(rawMonoClass);
  129. if(monoClass != nullptr)
  130. return monoClass;
  131. }
  132. return nullptr;
  133. }
  134. String MonoManager::getFullTypeName(MonoObject* obj)
  135. {
  136. if(obj == nullptr)
  137. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  138. ::MonoClass* monoClass = mono_object_get_class(obj);
  139. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  140. String namespaceStr;
  141. if(nameSpaceChars != nullptr)
  142. namespaceStr = nameSpaceChars;
  143. const char* typeNameChars = mono_class_get_name(monoClass);
  144. String typeNameStr;
  145. if(typeNameChars != nullptr)
  146. typeNameStr = typeNameChars;
  147. return namespaceStr + "." + typeNameStr;
  148. }
  149. String MonoManager::getNamespace(MonoObject* obj)
  150. {
  151. if(obj == nullptr)
  152. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  153. ::MonoClass* monoClass = mono_object_get_class(obj);
  154. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  155. String namespaceStr;
  156. if(nameSpaceChars != nullptr)
  157. namespaceStr = nameSpaceChars;
  158. return namespaceStr;
  159. }
  160. String MonoManager::getTypeName(MonoObject* obj)
  161. {
  162. if(obj == nullptr)
  163. BS_EXCEPT(InvalidParametersException, "Object cannot be null.");
  164. ::MonoClass* monoClass = mono_object_get_class(obj);
  165. const char* typeNameChars = mono_class_get_name(monoClass);
  166. String typeNameStr;
  167. if(typeNameChars != nullptr)
  168. typeNameStr = typeNameChars;
  169. return typeNameStr;
  170. }
  171. }