summaryrefslogtreecommitdiff
path: root/Runtime/Mono/MonoAttributeHelpers.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Mono/MonoAttributeHelpers.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Mono/MonoAttributeHelpers.cpp')
-rw-r--r--Runtime/Mono/MonoAttributeHelpers.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/Runtime/Mono/MonoAttributeHelpers.cpp b/Runtime/Mono/MonoAttributeHelpers.cpp
new file mode 100644
index 0000000..cde1054
--- /dev/null
+++ b/Runtime/Mono/MonoAttributeHelpers.cpp
@@ -0,0 +1,191 @@
+#include "UnityPrefix.h"
+#include "Configuration/UnityConfigure.h" // include before anything, to get Prof_ENABLED if that is defined
+#if UNITY_EDITOR && ENABLE_MONO
+#include "MonoManager.h"
+#include "MonoAttributeHelpers.h"
+#include <stdlib.h>
+
+using namespace std;
+
+
+static string RemoveStringFromString (string str, string remove)
+{
+ while (true)
+ {
+ int pos = str.find (remove);
+ if (pos == string::npos)
+ break;
+ str.erase (pos, remove.size());
+ }
+ return str;
+}
+
+static std::string SignatureToString (MonoMethodSignature* signature)
+{
+ MonoType* methodType;
+ void* iter = NULL;
+ std::string parameters;
+ while ((methodType = mono_signature_get_params (signature, &iter)))
+ {
+ if (!parameters.empty())
+ parameters += ", ";
+ parameters += mono_type_get_name(methodType);
+ }
+
+ string returnType = mono_type_get_name( mono_signature_get_return_type (signature) );
+ string result = Format ("%s Func(%s)", returnType.c_str(), parameters.c_str());
+ return RemoveStringFromString (result, "System.");
+}
+
+
+
+void GetMethodsWithAttribute (ScriptingClass* attributeClass, MonoMethod* comparedParams, std::vector<MonoMethod*>& resultList)
+{
+ MonoMethodSignature* pCompareSig = NULL;
+ if (comparedParams)
+ pCompareSig = mono_method_signature( comparedParams );
+
+ for (int i = MonoManager::kEngineAssembly; i < GetMonoManager().GetAssemblyCount(); i++)
+ {
+ MonoAssembly* assembly = GetMonoManager().GetAssembly(i);
+ if (!assembly)
+ continue;
+
+ MonoImage* pMonoImage = mono_assembly_get_image( assembly );
+ if (!pMonoImage)
+ continue;
+
+ // stolen from #include...
+ const int MONO_TABLE_TYPEDEF = 2; // mono/metadata/blob.h
+ const int MONO_TOKEN_TYPE_DEF = 0x02000000; // mono/metadata/tokentype.h
+
+ int numFields = mono_image_get_table_rows( pMonoImage, MONO_TABLE_TYPEDEF );
+ for (int typeIdx = 1; typeIdx < numFields; ++typeIdx)
+ {
+ guint32 token = MONO_TOKEN_TYPE_DEF | (typeIdx + 1);
+ MonoClass* klass = mono_class_get (pMonoImage, token);
+ gpointer iter = NULL;
+ MonoMethod* method;
+
+ if (klass == NULL) {
+ // We need to call these two methods to clear the thread local
+ // loader error status in mono. If not we'll randomly process the error
+ // the next time it's checked.
+ void* last_error = mono_loader_get_last_error ();
+ mono_loader_error_prepare_exception (last_error);
+ continue;
+ }
+
+ while ((method = mono_class_get_methods(klass, &iter)))
+ {
+ MonoMethodSignature* sig = mono_method_signature (method);
+
+ if (!sig)
+ continue;
+
+ MonoCustomAttrInfo* attribInfo = mono_custom_attrs_from_method(method);
+ if (!attribInfo)
+ continue;
+
+ if (!mono_custom_attrs_has_attr (attribInfo, attributeClass))
+ {
+ mono_custom_attrs_free(attribInfo);
+ continue;
+ }
+
+ // Get static methods only
+ bool isInstanceMethod = mono_signature_is_instance (sig);
+ if (isInstanceMethod)
+ {
+ mono_custom_attrs_free(attribInfo);
+ ErrorString (Format("UnityException: An [%s] attributed method is not static", mono_class_get_name(attributeClass)));
+ continue;
+ }
+
+ if (pCompareSig)
+ {
+ if (!mono_metadata_signature_equal(sig, pCompareSig))
+ {
+ mono_custom_attrs_free(attribInfo);
+ ErrorString (Format("UnityException: An [%s] attributed method has incorrect signature: %s. Correct signature: %s", mono_class_get_name(attributeClass), SignatureToString(sig).c_str(), SignatureToString(pCompareSig).c_str()));
+ continue;
+ }
+ }
+ else
+ {
+ if (mono_signature_get_param_count (sig) > 0)
+ {
+ mono_custom_attrs_free(attribInfo);
+ ErrorString (Format("UnityException: An [%s] attributed method parameter count should be 0 but signature is: %s", mono_class_get_name(attributeClass), SignatureToString(sig).c_str()));
+ continue;
+ }
+ }
+
+ resultList.push_back(method);
+ mono_custom_attrs_free(attribInfo);
+ }
+ }
+ }
+}
+
+bool AttributeSorter( MonoMethod* methodA, MonoMethod* methodB )
+{
+#if UNITY_EDITOR
+ MonoCustomAttrInfo* attribAInfo = mono_custom_attrs_from_method(methodA);
+ MonoCustomAttrInfo* attribBInfo = mono_custom_attrs_from_method(methodB);
+ MonoObject* objA = mono_custom_attrs_get_attr( attribAInfo, MONO_COMMON.callbackOrderAttribute );
+ MonoObject* objB = mono_custom_attrs_get_attr( attribBInfo, MONO_COMMON.callbackOrderAttribute );
+ MonoClass* klassA = mono_object_get_class(objA);
+ MonoClass* klassB = mono_object_get_class(objB);
+ MonoProperty* propertyA = mono_class_get_property_from_name(klassA, "callbackOrder");
+ MonoProperty* propertyB = mono_class_get_property_from_name(klassB, "callbackOrder");
+ MonoMethod* getterA = mono_property_get_get_method(propertyA);
+ MonoMethod* getterB = mono_property_get_get_method(propertyB);
+ MonoException* monoException = NULL;
+ MonoObject* resA = mono_runtime_invoke(getterA, objA, NULL, &monoException);
+ MonoObject* resB = mono_runtime_invoke(getterB, objB, NULL, &monoException);
+ int x = ExtractMonoObjectData<signed int>(resA);
+ int y = ExtractMonoObjectData<signed int>(resB);
+
+ return x < y;
+#else
+ return false;
+#endif
+}
+
+void CallMethodsWithAttribute (ScriptingClass* attributeClass, ScriptingArguments& arguments, MonoMethod* comparedParams)
+{
+ vector<MonoMethod*> resultList;
+
+ GetMethodsWithAttribute(attributeClass, comparedParams, resultList);
+ sort (resultList.begin(), resultList.end(), AttributeSorter);
+
+ for (vector<MonoMethod*>::iterator iter = resultList.begin(); iter != resultList.end(); ++iter)
+ {
+ ScriptingInvocation invocation(*iter);
+ invocation.Arguments() = arguments;
+ invocation.Invoke();
+ }
+}
+
+bool CallMethodsWithAttributeAndReturnTrueIfUsed (ScriptingClass* attributeClass, ScriptingArguments& arguments, MonoMethod* comparedParams)
+{
+ vector<MonoMethod*> resultList;
+
+ GetMethodsWithAttribute(attributeClass, comparedParams, resultList);
+ sort (resultList.begin(), resultList.end(), AttributeSorter);
+
+ for (vector<MonoMethod*>::iterator iter = resultList.begin(); iter != resultList.end(); ++iter)
+ {
+ ScriptingInvocation invocation(*iter);
+ invocation.Arguments() = arguments;
+ ScriptingObjectPtr returnValueObj = invocation.Invoke();
+ if (ExtractMonoObjectData<bool>(returnValueObj))
+ return true;
+ }
+
+ return false;
+}
+
+
+#endif //UNITY_EDITOR && ENABLE_MONO