BsMonoManager.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "BsMonoManager.h"
  2. #include "CmException.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. using namespace CamelotFramework;
  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. for(auto& entry : mAssemblies)
  22. {
  23. unloadAssembly(*entry.second);
  24. cm_delete(entry.second);
  25. }
  26. mAssemblies.clear();
  27. if(mDomain != nullptr)
  28. {
  29. mono_jit_cleanup(mDomain);
  30. mDomain = nullptr;
  31. }
  32. }
  33. MonoAssembly& MonoManager::loadAssembly(const String& path, const String& name)
  34. {
  35. MonoAssembly* assembly = nullptr;
  36. if(mDomain == nullptr)
  37. {
  38. mDomain = mono_jit_init (path.c_str());
  39. if(mDomain == nullptr)
  40. {
  41. CM_EXCEPT(InternalErrorException, "Cannot initialize Mono runtime.");
  42. }
  43. }
  44. auto iterFind = mAssemblies.find(name);
  45. if(iterFind != mAssemblies.end())
  46. {
  47. assembly = iterFind->second;
  48. }
  49. else
  50. {
  51. assembly = new (cm_alloc<MonoAssembly>()) MonoAssembly();
  52. mAssemblies[name] = assembly;
  53. }
  54. if(!assembly->mIsLoaded)
  55. {
  56. assembly->load(path, name);
  57. // Fully initialize all types that use this assembly
  58. Vector<ScriptMeta*>::type& mTypeMetas = getTypesToInitialize()[name];
  59. for(auto& meta : mTypeMetas)
  60. {
  61. meta->scriptClass = assembly->getClass(meta->ns, meta->name);
  62. if(meta->scriptClass == nullptr)
  63. CM_EXCEPT(InvalidParametersException, "Unable to find class of type: \"" + meta->ns + "::" + meta->name + "\"");
  64. if(meta->scriptClass->hasField("mCachedPtr"))
  65. meta->thisPtrField = meta->scriptClass->getField("mCachedPtr");
  66. else
  67. meta->thisPtrField = nullptr;
  68. meta->initCallback();
  69. }
  70. }
  71. if(!mIsCoreLoaded)
  72. {
  73. mIsCoreLoaded = true;
  74. MonoImage* existingImage = mono_image_loaded("mscorlib");
  75. if(existingImage != nullptr)
  76. {
  77. MonoAssembly* mscorlib = new (cm_alloc<MonoAssembly>()) MonoAssembly();
  78. mAssemblies["mscorlib"] = mscorlib;
  79. mscorlib->loadAsDependency(existingImage, "mscorlib");
  80. }
  81. else
  82. loadAssembly("mscorlib", "mscorlib");
  83. }
  84. return *assembly;
  85. }
  86. void MonoManager::unloadAssembly(MonoAssembly& assembly)
  87. {
  88. ::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
  89. assembly.unload();
  90. if(monoAssembly)
  91. mono_assembly_close(monoAssembly);
  92. }
  93. MonoAssembly* MonoManager::getAssembly(const CM::String& name) const
  94. {
  95. auto iterFind = mAssemblies.find(name);
  96. if(iterFind != mAssemblies.end())
  97. return iterFind->second;
  98. return nullptr;
  99. }
  100. void MonoManager::registerScriptType(ScriptMeta* metaData)
  101. {
  102. Vector<ScriptMeta*>::type& mMetas = getTypesToInitialize()[metaData->assembly];
  103. mMetas.push_back(metaData);
  104. }
  105. MonoClass* MonoManager::findClass(const CM::String& ns, const CM::String& typeName)
  106. {
  107. MonoClass* monoClass = nullptr;
  108. for(auto& assembly : mAssemblies)
  109. {
  110. monoClass = assembly.second->getClass(ns, typeName);
  111. if(monoClass != nullptr)
  112. return monoClass;
  113. }
  114. return nullptr;
  115. }
  116. MonoClass* MonoManager::findClass(::MonoClass* rawMonoClass)
  117. {
  118. MonoClass* monoClass = nullptr;
  119. for(auto& assembly : mAssemblies)
  120. {
  121. monoClass = assembly.second->getClass(rawMonoClass);
  122. if(monoClass != nullptr)
  123. return monoClass;
  124. }
  125. return nullptr;
  126. }
  127. String MonoManager::getFullTypeName(MonoObject* obj)
  128. {
  129. if(obj == nullptr)
  130. CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
  131. ::MonoClass* monoClass = mono_object_get_class(obj);
  132. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  133. String namespaceStr;
  134. if(nameSpaceChars != nullptr)
  135. namespaceStr = nameSpaceChars;
  136. const char* typeNameChars = mono_class_get_name(monoClass);
  137. String typeNameStr;
  138. if(typeNameChars != nullptr)
  139. typeNameStr = typeNameChars;
  140. return namespaceStr + "." + typeNameStr;
  141. }
  142. String MonoManager::getNamespace(MonoObject* obj)
  143. {
  144. if(obj == nullptr)
  145. CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
  146. ::MonoClass* monoClass = mono_object_get_class(obj);
  147. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  148. String namespaceStr;
  149. if(nameSpaceChars != nullptr)
  150. namespaceStr = nameSpaceChars;
  151. return namespaceStr;
  152. }
  153. String MonoManager::getTypeName(MonoObject* obj)
  154. {
  155. if(obj == nullptr)
  156. CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
  157. ::MonoClass* monoClass = mono_object_get_class(obj);
  158. const char* typeNameChars = mono_class_get_name(monoClass);
  159. String typeNameStr;
  160. if(typeNameChars != nullptr)
  161. typeNameStr = typeNameChars;
  162. return typeNameStr;
  163. }
  164. }