BsMonoManager.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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, const String& entryPoint)
  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. assembly->initialize(entryPoint); // Perform any initialization after everything is loaded
  71. }
  72. if(!mIsCoreLoaded)
  73. {
  74. mIsCoreLoaded = true;
  75. MonoAssembly* mscorlib = new (cm_alloc<MonoAssembly>()) MonoAssembly();
  76. mAssemblies["mscorlib"] = mscorlib;
  77. mscorlib->loadAsDependency(assembly->mMonoImage, "mscorlib");
  78. mIsCoreLoaded = true;
  79. }
  80. return *assembly;
  81. }
  82. void MonoManager::unloadAssembly(MonoAssembly& assembly)
  83. {
  84. ::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
  85. assembly.unload();
  86. if(monoAssembly)
  87. mono_assembly_close(monoAssembly);
  88. }
  89. MonoAssembly* MonoManager::getAssembly(const CM::String& name) const
  90. {
  91. auto iterFind = mAssemblies.find(name);
  92. if(iterFind != mAssemblies.end())
  93. return iterFind->second;
  94. return nullptr;
  95. }
  96. void MonoManager::registerScriptType(ScriptMeta* metaData)
  97. {
  98. Vector<ScriptMeta*>::type& mMetas = getTypesToInitialize()[metaData->assembly];
  99. mMetas.push_back(metaData);
  100. }
  101. MonoClass* MonoManager::findClass(const CM::String& ns, const CM::String& typeName)
  102. {
  103. MonoClass* monoClass = nullptr;
  104. for(auto& assembly : mAssemblies)
  105. {
  106. monoClass = assembly.second->getClass(ns, typeName);
  107. if(monoClass != nullptr)
  108. return monoClass;
  109. }
  110. return nullptr;
  111. }
  112. String MonoManager::getFullTypeName(MonoObject* obj)
  113. {
  114. if(obj == nullptr)
  115. CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
  116. ::MonoClass* monoClass = mono_object_get_class(obj);
  117. const char* nameSpaceChars = mono_class_get_namespace(monoClass);
  118. String namespaceStr;
  119. if(nameSpaceChars != nullptr)
  120. namespaceStr = nameSpaceChars;
  121. const char* typeNameChars = mono_class_get_name(monoClass);
  122. String typeNameStr;
  123. if(typeNameChars != nullptr)
  124. typeNameStr = typeNameChars;
  125. return namespaceStr + "." + typeNameStr;
  126. }
  127. String MonoManager::getNamespace(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. return namespaceStr;
  137. }
  138. String MonoManager::getTypeName(MonoObject* obj)
  139. {
  140. if(obj == nullptr)
  141. CM_EXCEPT(InvalidParametersException, "Object cannot be null.");
  142. ::MonoClass* monoClass = mono_object_get_class(obj);
  143. const char* typeNameChars = mono_class_get_name(monoClass);
  144. String typeNameStr;
  145. if(typeNameChars != nullptr)
  146. typeNameStr = typeNameChars;
  147. return typeNameStr;
  148. }
  149. }