summaryrefslogtreecommitdiff
path: root/Runtime/Scripting/Backend
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Scripting/Backend')
-rw-r--r--Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp287
-rw-r--r--Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h45
-rw-r--r--Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h40
-rw-r--r--Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h53
-rw-r--r--Runtime/Scripting/Backend/IScriptingTypeProvider.h16
-rw-r--r--Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp280
-rw-r--r--Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h15
-rw-r--r--Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h83
-rw-r--r--Runtime/Scripting/Backend/ScriptingArguments.cpp218
-rw-r--r--Runtime/Scripting/Backend/ScriptingArguments.h79
-rw-r--r--Runtime/Scripting/Backend/ScriptingBackendApi.h72
-rw-r--r--Runtime/Scripting/Backend/ScriptingInvocation.cpp223
-rw-r--r--Runtime/Scripting/Backend/ScriptingInvocation.h73
-rw-r--r--Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp123
-rw-r--r--Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h31
-rw-r--r--Runtime/Scripting/Backend/ScriptingMethodFactory.h18
-rw-r--r--Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp165
-rw-r--r--Runtime/Scripting/Backend/ScriptingMethodRegistry.h60
-rw-r--r--Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp237
-rw-r--r--Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp214
-rw-r--r--Runtime/Scripting/Backend/ScriptingTypeRegistry.h33
-rw-r--r--Runtime/Scripting/Backend/ScriptingTypes.h202
-rw-r--r--Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp35
-rw-r--r--Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h30
24 files changed, 2632 insertions, 0 deletions
diff --git a/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp
new file mode 100644
index 0000000..8022f96
--- /dev/null
+++ b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp
@@ -0,0 +1,287 @@
+#include "UnityPrefix.h"
+
+#include "../ScriptingTypes.h"
+#include "ScriptingBackendApi_Flash.h"
+#include "../ScriptingTypeRegistry.h"
+#include "../ScriptingMethodRegistry.h"
+#include <string>
+#include "../ScriptingArguments.h"
+#include "PlatformDependent\FlashSupport\cpp\FlashUtils.h"
+
+std::string scripting_cpp_string_for(ScriptingStringPtr str)
+{
+ return std::string((const char*)str);
+}
+
+//implemented in raw actionscript
+extern "C" ScriptingClass* Ext_Flash_GetBaseClassFromScriptingClass(ScriptingClass* klass);
+bool scripting_method_is_instance(ScriptingMethodPtr method)
+{
+ //not implemented on flash yet.
+ return true;
+}
+
+ScriptingStringPtr scripting_string_new(const char* str)
+{
+ __asm __volatile__("returnString = strFromPtr(%0);" : : "r" (str) );
+ return (ScriptingStringPtr)str;
+}
+
+ScriptingStringPtr scripting_string_new(const std::string& str)
+{
+ return scripting_string_new(str.c_str());
+}
+
+extern "C" int Ext_Flash_ScriptingGetMethodParamCount(ScriptingObjectPtr object, AS3String as3String);
+int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry)
+{
+ ScriptingObjectPtr methodInfo = method->GetSystemReflectionMethodInfo();
+ if (methodInfo==NULL)
+ return 0;
+
+ int result;
+ FLASH_ASM_WITH_NEWSP("%0 = ScriptingMethodHelper.NumberOfArgumentsOf(marshallmap.getObjectWithId(%1));" : "=r"(result) : "r"(methodInfo));
+
+ return result;
+}
+
+ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry)
+{
+ ScriptingObjectPtr methodInfo = method->GetSystemReflectionMethodInfo();
+ if (methodInfo==NULL)
+ return NULL;
+
+ ScriptingTypePtr result;
+ FLASH_ASM_WITH_NEWSP("scratch_object = ScriptingMethodHelper.NthArgumentType(marshallmap.getObjectWithId(%0), %1)" : : "r"(methodInfo), "r"(index));
+ FLASH_ASM_WITH_NEWSP("if (scratch_object!=null) %0 = marshallmap.getIdForObject(scratch_object.GetClass()); else %0 = 0;" : "=r"(result));
+ return result;
+}
+
+const char* scripting_method_get_name(ScriptingMethodPtr method)
+{
+ return method->GetName();
+}
+
+bool scripting_method_has_attribute (ScriptingMethodPtr method, ScriptingClassPtr attribute)
+{
+ //not implemented on flash yet
+ return false;
+}
+
+ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr type, ScriptingTypeRegistry& typeRegistry)
+{
+ return Ext_Flash_GetBaseClassFromScriptingClass(type);
+}
+
+bool scripting_class_is_enum(ScriptingTypePtr type)
+{
+ //todo: implement
+ return false;
+}
+
+extern "C" const char* Ext_Flash_GetNameFromClass(ScriptingClassPtr klass);
+const char* scripting_class_get_name(ScriptingClassPtr klass)
+{
+ //Horrible, we can only clean this up once we create a struct ScriptingClass for flash.
+ std::string* s = new std::string(Ext_Flash_GetNameFromClass(klass));
+ return s->c_str();
+}
+
+extern "C" const char* Ext_Flash_GetNameSpaceFromScriptingType(ScriptingType* scriptingType);
+const char* scripting_class_get_namespace(ScriptingClassPtr klass)
+{
+ //Horrible, we can only clean this up once we create a struct ScriptingClass for flash.
+ std::string* s = new std::string(Ext_Flash_GetNameSpaceFromScriptingType(klass));
+ return s->c_str();
+}
+
+extern "C" bool Ext_Flash_ScriptingClassIsSubclassOf(ScriptingTypePtr t1, ScriptingTypePtr t2);
+bool scripting_class_is_subclass_of(ScriptingTypePtr t1, ScriptingTypePtr t2)
+{
+ return Ext_Flash_ScriptingClassIsSubclassOf(t1,t2);
+}
+
+ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry)
+{
+ return method->GetReturnType();
+}
+
+extern "C" ScriptingObjectPtr Ext_Flash_InvokeMethodOnObject(void* object, AS3String as3String, ScriptingException** exception);
+ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception)
+{
+ void* objectToInvokeOn = object;
+ *exception = NULL;
+ if (object==NULL)
+ {
+ objectToInvokeOn = method->m_Class;
+ if (objectToInvokeOn == NULL)
+ ErrorString("flash_invoke_method called with NULL object, and scriptmethod->m_Class is NULL too.");
+ }
+
+ __asm __volatile__("invocation_arguments.length = 0;\n");
+
+ for (int i=0; i!=arguments.GetCount(); i++)
+ {
+ switch (arguments.GetTypeAt(i))
+ {
+ case ScriptingArguments::ARGTYPE_BOOLEAN:
+ __asm __volatile__("invocation_arguments.push(%0 ? true : false);" : : "r"(arguments.GetBooleanAt(i)));
+ break;
+ case ScriptingArguments::ARGTYPE_INT:
+ __asm __volatile__("invocation_arguments.push(%0);" : : "r"(arguments.GetIntAt(i)));
+ break;
+ case ScriptingArguments::ARGTYPE_FLOAT:
+ __asm __volatile__("invocation_arguments.push(%0);" : : "f"(arguments.GetFloatAt(i)));
+ break;
+ case ScriptingArguments::ARGTYPE_STRING:
+ __asm __volatile__("invocation_arguments.push(strFromPtr(%0));" : : "r"(arguments.GetStringAt(i)));
+ break;
+ case ScriptingArguments::ARGTYPE_OBJECT:
+ __asm __volatile__("invocation_arguments.push(marshallmap.getObjectWithId(%0));" : : "r"(arguments.GetObjectAt(i)));
+ break;
+ default:
+ ErrorString(Format("Flash does not support calling managed methods with this type of argument: %d",arguments.GetTypeAt(i)));
+ break;
+ }
+ }
+ return Ext_Flash_InvokeMethodOnObject(objectToInvokeOn, method->m_As3String,exception);
+}
+
+ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry)
+{
+ //todo: think about if this is actually correct.
+ return (ScriptingClassPtr)systemTypeInstance;
+}
+
+extern "C" ScriptingObjectPtr Ext_Flash_CreateInstance(ScriptingClass* klass);
+ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t)
+{
+ return Ext_Flash_CreateInstance(t);
+}
+
+extern "C" ScriptingClassPtr Ext_Flash_GetScriptingTypeOfScriptingObject(ScriptingObjectPtr);
+ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr o, ScriptingTypeRegistry& typeRegistry)
+{
+ return Ext_Flash_GetScriptingTypeOfScriptingObject(o);
+}
+
+ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry)
+{
+ return method;
+}
+
+void scripting_object_invoke_default_constructor(ScriptingObjectPtr o, ScriptingExceptionPtr* exc)
+{
+ *exc = NULL;
+ //todo: properly deal with exception.
+ FLASH_ASM_WITH_NEWSP("marshallmap.getObjectWithId(%0).cil2as_DefaultConstructor()" : : "r"(o));
+}
+
+int scripting_gchandle_new(ScriptingObjectPtr o)
+{
+ __asm __volatile__("marshallmap.gcHandle(%0);" : : "r" (o));
+ return (int)o;
+}
+
+int scripting_gchandle_weak_new(ScriptingObjectPtr o)
+{
+ FatalErrorMsg("ToDo");
+ return 0;
+}
+
+void scripting_gchandle_free(int handle)
+{
+ __asm __volatile__("marshallmap.gcFree(%0);" : : "r" (handle));
+}
+
+ScriptingObjectPtr scripting_gchandle_get_target(int handle)
+{
+ return (ScriptingObjectPtr) handle;
+}
+
+int scripting_gc_maxgeneration()
+{
+ return 0;
+}
+
+void scripting_gc_collect(int maxGeneration)
+{
+ FatalErrorMsg("ToDo");
+}
+
+void ScriptingMethod::Init(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass)
+{
+ m_Name = strcpy(new char[strlen(name) + 1],name);
+ m_Mappedname = strcpy(new char[strlen(mappedName) + 1],mappedName);
+ __asm __volatile__("%0 = getAS3StringForPtr(%1);\n" : "=r" (m_As3String) : "r" (m_Mappedname));
+
+ m_Signature = strcpy(new char[strlen(sig) + 1],sig);
+ m_Class = klass;
+ m_MethodInfo = NULL;
+ FLASH_ASM_WITH_NEWSP("%0 = marshallmap.getIdForObject(System.Type.ForClass(marshallmap.getObjectWithId(%1)));\n" : "=r" (m_SystemType) : "r"(m_Class) );
+ scripting_gchandle_new(m_SystemType);
+}
+
+extern "C" const char* Ext_GetMappedMethodName(const char* name, ScriptingType* klass);
+ScriptingMethod::ScriptingMethod(const char* name, ScriptingClass* klass)
+{
+ const char* mappedName = Ext_GetMappedMethodName(name,klass);
+ Init(name,mappedName,"",klass);
+}
+
+ScriptingMethod::ScriptingMethod(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass)
+{
+ Init(name,mappedName,sig,klass);
+}
+
+extern "C" ScriptingClass* Ext_Flash_GetMethodReturnType(const char* methodname, ScriptingClass* klass);
+ScriptingClass* ScriptingMethod::GetReturnType()
+{
+ return Ext_Flash_GetMethodReturnType(m_Mappedname, m_Class);
+}
+
+ScriptingObjectPtr ScriptingMethod::GetSystemReflectionMethodInfo()
+{
+ if (m_MethodInfo)
+ return m_MethodInfo;
+
+ FLASH_ASM_WITH_NEWSP("%0 = marshallmap.getIdForObject(ScriptingMethodHelper.GetMethodInfo(marshallmap.getObjectWithId(%1), strFromPtr(%2)));" : "=r"(m_MethodInfo) : "r"(m_SystemType),"r"(m_Name) );
+
+ scripting_gchandle_new(m_MethodInfo);
+ return m_MethodInfo;
+}
+
+ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass)
+{
+ FatalErrorMsg("ToDo");
+ return SCRIPTING_NULL;
+}
+
+ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o)
+{
+ FatalErrorMsg("ToDo");
+ return SCRIPTING_NULL;
+}
+
+void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info)
+{
+ AssertIf (exception == NULL);
+
+ __asm __volatile__("var errorStr:String = marshallmap.getObjectWithId(%0) as String;"::"r"(exception));
+ int length;
+ __asm __volatile__("%0=getStringMarshallingLength(errorStr);":"=r"(length));
+ char* errorStrPtr = (char*)alloca(length);
+ __asm __volatile__("var ptr:int = placeStringAtPtr(errorStr,%0);"::"r"(errorStrPtr));
+
+ info.condition = errorStrPtr;
+ info.strippedStacktrace = "";
+ info.stacktrace = "";
+ info.errorNum = 0;
+ info.file = "";
+ info.line = 0;
+}
+
+void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size)
+{
+ return (UInt8*)array + sizeof(int) + i * element_size;
+} \ No newline at end of file
diff --git a/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h
new file mode 100644
index 0000000..c2372a2
--- /dev/null
+++ b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h
@@ -0,0 +1,45 @@
+#ifndef _SCRIPTINGBACKENDAPI_FLASH_H_
+#define _SCRIPTINGBACKENDAPI_FLASH_H_
+
+#include <string>
+
+#include "../ScriptingTypes.h"
+#include "../ScriptingBackendApi.h"
+
+//todo: remove
+typedef ScriptingObject* (*FastMonoMethod) (void* thiz, ScriptingException** ex);
+typedef int AS3String;
+
+struct ScriptingMethod
+{
+ const char* m_Name;
+ const char* m_Mappedname;
+ const char* m_Signature;
+ AS3String m_As3String;
+
+ ScriptingClass* m_Class;
+ ScriptingObject* m_SystemType;
+ ScriptingObject* m_MethodInfo;
+
+ ScriptingMethod(const char* name, ScriptingClass* klass);
+ ScriptingMethod(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass);
+ void Init(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass);
+ ScriptingClass* GetReturnType();
+ const char* GetName() { return m_Name; }
+ ScriptingObjectPtr GetSystemReflectionMethodInfo();
+};
+
+struct ScriptingField
+{
+ ScriptingField(const char* name,const char* type)
+ : m_name(name)
+ , m_type(type)
+ {
+
+ }
+
+ std::string m_name;
+ std::string m_type;
+};
+
+#endif
diff --git a/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h
new file mode 100644
index 0000000..35b7015
--- /dev/null
+++ b/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h
@@ -0,0 +1,40 @@
+#ifndef _SCRIPTINGMETHODFACTORY_FLASH_
+#define _SCRIPTINGMETHODFACTORY_FLASH_
+
+#include "../ScriptingMethodFactory.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "ScriptingBackendApi_Flash.h"
+
+#if UNITY_FLASH
+
+extern "C" const char* Ext_GetMappedMethodName(const char* name, ScriptingType* klass);
+
+class ScriptingMethodFactory_Flash : public IScriptingMethodFactory
+{
+public:
+ virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter)
+ {
+ //todo: respect the searchfilter
+ std::string mappedName(Ext_GetMappedMethodName(name,klass));
+
+ //remove this hack when interfaces contain mapping information
+ if (mappedName.size()==0 && strcmp(name,"MoveNext")==0)
+ mappedName.assign("IEnumerator_MoveNext");
+ return new ScriptingMethod(name, mappedName.c_str(), "",klass);
+ }
+
+ virtual ScriptingMethodPtr Produce(void* nativeMethod)
+ {
+ //not implemented for flash.
+ return NULL;
+ }
+
+ virtual void Release(ScriptingMethodPtr method)
+ {
+ delete method;
+ }
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h
new file mode 100644
index 0000000..eb2142c
--- /dev/null
+++ b/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h
@@ -0,0 +1,53 @@
+#ifndef _SCRIPTINGTYPEPROVIDER_FLASH
+#define _SCRIPTINGTYPEPROVIDER_FLASH
+
+#include "../IScriptingTypeProvider.h"
+//#include "Runtime/Scripting/ScriptingUtility.h"
+
+#if UNITY_FLASH
+
+extern "C" ScriptingTypePtr Ext_Flash_GetScriptingTypeFromName(const char* name);
+
+class ScriptingTypeProvider_Flash : public IScriptingTypeProvider
+{
+public:
+ virtual BackendNativeType NativeTypeFor(const char* namespaze, const char* name)
+ {
+ if (strcmp(name,"Object") == 0)
+ name = "_Object";
+
+ if (strcmp(namespaze,"System")==0)
+ {
+ if (strcmp(name,"String")==0)
+ return Ext_Flash_GetScriptingTypeFromName("String");
+ if (strcmp(name,"Int32")==0)
+ return Ext_Flash_GetScriptingTypeFromName("int");
+ if (strcmp(name,"Single")==0)
+ return Ext_Flash_GetScriptingTypeFromName("Number");
+ if (strcmp(name,"Double")==0)
+ return Ext_Flash_GetScriptingTypeFromName("Number");
+ if (strcmp(name,"Byte")==0)
+ return Ext_Flash_GetScriptingTypeFromName("int");
+ }
+
+ std::string combined(namespaze);
+ if (combined.size() > 0)
+ combined+=".";
+ combined+=name;
+
+ return Ext_Flash_GetScriptingTypeFromName(combined.c_str());
+ }
+
+ virtual ScriptingTypePtr Provide(BackendNativeType nativePtr)
+ {
+ return (ScriptingTypePtr)nativePtr;
+ }
+
+ virtual void Release(ScriptingTypePtr t)
+ {
+ }
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/IScriptingTypeProvider.h b/Runtime/Scripting/Backend/IScriptingTypeProvider.h
new file mode 100644
index 0000000..c8a9fe7
--- /dev/null
+++ b/Runtime/Scripting/Backend/IScriptingTypeProvider.h
@@ -0,0 +1,16 @@
+#ifndef _ISCRIPTINGTYPEPROVIDER_H_
+#define _ISCRIPTINGTYPEPROVIDER_H_
+
+#include "ScriptingTypes.h"
+#include "Runtime/Modules/ExportModules.h"
+
+class EXPORT_COREMODULE IScriptingTypeProvider
+{
+public:
+ virtual ~IScriptingTypeProvider() {}
+ virtual BackendNativeType NativeTypeFor(const char* namespaze, const char* name) = 0;
+ virtual ScriptingTypePtr Provide(BackendNativeType nativeType) = 0;
+ virtual void Release(ScriptingTypePtr t) = 0;
+};
+
+#endif
diff --git a/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp
new file mode 100644
index 0000000..b27269b
--- /dev/null
+++ b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp
@@ -0,0 +1,280 @@
+#include "UnityPrefix.h"
+
+#include "../ScriptingTypes.h"
+#include "Runtime/Mono/MonoIncludes.h"
+#include "ScriptingBackendApi_Mono.h"
+#include "../ScriptingMethodRegistry.h"
+#include "../ScriptingTypeRegistry.h"
+#include "Runtime/Scripting/ScriptingUtility.h" //required for ExtractMonoobjectData, todo: see if we can remove that.
+
+std::string scripting_cpp_string_for(ScriptingStringPtr str)
+{
+ return MonoStringToCpp(str);
+}
+
+bool scripting_method_is_instance(ScriptingMethodPtr method)
+{
+ return method->isInstance;
+}
+
+const char* scripting_method_get_name(ScriptingMethodPtr method)
+{
+ return mono_method_get_name(method->monoMethod);
+}
+
+int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry)
+{
+ MonoMethodSignature* sig = mono_method_signature(method->monoMethod);
+ Assert(sig);
+ return mono_signature_get_param_count(sig);
+}
+
+ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& registry)
+{
+ MonoMethodSignature* sig = mono_method_signature (method->monoMethod);
+ MonoType* returnType = mono_signature_get_return_type (sig);
+ if (returnType == NULL)
+ return NULL;
+
+ return mono_class_from_mono_type (returnType);
+}
+
+ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry)
+{
+ MonoMethodSignature* sig = mono_method_signature (method->monoMethod);
+ void* iterator = NULL;
+ MonoType* type = mono_signature_get_params (sig, &iterator);
+ if (type == NULL)
+ return NULL;
+ MonoClass* methodClass = mono_class_from_mono_type (type);
+ return typeRegistry.GetType(methodClass);
+}
+
+bool scripting_method_has_attribute(ScriptingMethodPtr method, ScriptingClassPtr attribute)
+{
+ bool hasAttribute = false;
+ MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method (method->monoMethod);
+ if (attrInfo != NULL && mono_custom_attrs_has_attr (attrInfo, attribute))
+ hasAttribute = true;
+
+ if (attrInfo)
+ mono_custom_attrs_free(attrInfo);
+
+ return hasAttribute;
+}
+
+ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr t, ScriptingTypeRegistry& registry)
+{
+ return mono_class_get_parent(t);
+}
+
+void scripting_class_get_methods(ScriptingTypePtr t, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result)
+{
+ void* iterator = NULL;
+ ScriptingMethodPtr scriptingMethod = NULL;
+ while (MonoMethod* method = mono_class_get_methods(t, &iterator))
+ if ((scriptingMethod = registry.GetMethod (method)))
+ result.push_back(scriptingMethod);
+}
+
+ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry)
+{
+ if (!systemTypeInstance)
+ return NULL;
+
+ MonoClass* klass = mono_class_from_mono_type(ExtractMonoObjectData<MonoType*>(systemTypeInstance));
+ return typeRegistry.GetType(klass);
+}
+
+const char* scripting_class_get_name(ScriptingClassPtr klass)
+{
+ return mono_class_get_name(klass);
+}
+
+const char* scripting_class_get_namespace(ScriptingClassPtr klass)
+{
+ return mono_class_get_namespace(klass);
+}
+
+bool scripting_class_is_subclass_of(ScriptingClassPtr c1, ScriptingClassPtr c2)
+{
+ return mono_class_is_subclass_of(c1,c2,true);
+}
+
+bool scripting_class_is_enum(ScriptingClassPtr klass)
+{
+ return mono_class_is_enum (klass);
+}
+
+ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr t, ScriptingTypeRegistry& registry)
+{
+ return mono_object_get_class(t);
+}
+
+void scripting_object_invoke_default_constructor(ScriptingObjectPtr t, ScriptingExceptionPtr* exc)
+{
+ mono_runtime_object_init_exception(t,exc);
+}
+
+ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry)
+{
+ return methodRegistry.GetMethod(mono_object_get_virtual_method(o,method->monoMethod));
+}
+
+ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t)
+{
+#if UNITY_EDITOR
+ if (mono_unity_class_is_abstract (t)) {
+ // Cannot instantiate abstract class
+ return SCRIPTING_NULL;
+ }
+#endif
+ return mono_object_new(mono_domain_get(), t);
+}
+
+int scripting_gchandle_new(ScriptingObjectPtr o)
+{
+ return mono_gchandle_new(o,1);
+}
+
+int scripting_gchandle_weak_new(ScriptingObjectPtr o)
+{
+ return mono_gchandle_new_weakref(o, 1);
+}
+
+void scripting_gchandle_free(int handle)
+{
+ mono_gchandle_free(handle);
+}
+
+ScriptingObjectPtr scripting_gchandle_get_target(int handle)
+{
+ return mono_gchandle_get_target(handle);
+}
+
+int scripting_gc_maxgeneration()
+{
+ return mono_gc_max_generation();
+}
+
+void scripting_gc_collect(int maxGeneration)
+{
+ mono_gc_collect(maxGeneration);
+}
+
+ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception)
+{
+#if UNITY_EDITOR
+ bool IsStackLargeEnough ();
+ if (!IsStackLargeEnough ())
+ {
+ *exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "StackOverflowException", "");
+ return NULL;
+ }
+#endif
+
+ if (method->fastMonoMethod)
+ {
+ Assert(arguments.GetCount()==0);
+ Assert(object);
+ return method->fastMonoMethod(object,exception);
+ }
+
+ return mono_runtime_invoke(method->monoMethod, object, arguments.InMonoFormat(), exception);
+}
+
+ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass)
+{
+ return mono_class_get_object(klass);
+}
+
+ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o)
+{
+ return (ScriptingArrayPtr)o;
+}
+
+ScriptingStringPtr scripting_string_new(const std::string& str)
+{
+ return scripting_string_new(str.c_str());
+}
+
+ScriptingStringPtr scripting_string_new(const UnityStr& str)
+{
+ return scripting_string_new(str.c_str());
+}
+
+ScriptingStringPtr scripting_string_new(const char* str)
+{
+ return MonoStringNew(str);
+}
+
+ScriptingStringPtr scripting_string_new(const wchar_t* str)
+{
+ return MonoStringNewUTF16(str);
+}
+
+ScriptingStringPtr scripting_string_new(const char* str, unsigned int length)
+{
+ return MonoStringNewLength(str, length);
+}
+
+void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info)
+{
+ AssertIf (exception == NULL);
+
+ MonoException* tempException = NULL;
+ MonoString* monoStringMessage = NULL;
+ MonoString* monoStringTrace = NULL;
+ void* args[] = { exception, &monoStringMessage, &monoStringTrace };
+
+ if (GetMonoManagerPtr () && GetMonoManager ().GetCommonClasses ().extractStringFromException)
+ {
+ // Call mono_runtime_invoke directly to avoid our stack size check in mono_runtime_invoke_profiled.
+ // We *should* have enough stack here to make this call, and a stack trace would be useful for the user.
+ mono_runtime_invoke (GetMonoManager ().GetCommonClasses ().extractStringFromException->monoMethod, (MonoObject*)exception, args, &tempException);
+ }
+
+ if (tempException)
+ {
+ char const* exceptionClassName = mono_class_get_name(mono_object_get_class((MonoObject*)tempException));
+ ErrorString ("Couldn't extract exception string from exception (another exception of class '"
+ + std::string (exceptionClassName) + "' was thrown while processing the stack trace)");
+ return;
+ }
+
+ // Log returned string
+ string message;
+
+ char* extractedMessage = NULL;
+ if (monoStringMessage)
+ message = extractedMessage = mono_string_to_utf8 (monoStringMessage);
+
+ char* extractedTrace = NULL;
+ if (monoStringTrace)
+ extractedTrace = mono_string_to_utf8 (monoStringTrace);
+
+ string processedStackTrace;
+ int line = -1;
+ string path;
+
+ if (extractedTrace && *extractedTrace != 0)
+ {
+ PostprocessStacktrace(extractedTrace, processedStackTrace);
+ ExceptionToLineAndPath (processedStackTrace, line, path);
+ }
+
+ info.condition = message;
+ info.strippedStacktrace = processedStackTrace;
+ info.stacktrace = extractedTrace;
+ info.errorNum = 0;
+ info.file = path;
+ info.line = line;
+
+ g_free (extractedMessage);
+ g_free (extractedTrace);
+}
+
+void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size)
+{
+ return kMonoArrayOffset + i * element_size + (char*)array;
+} \ No newline at end of file
diff --git a/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h
new file mode 100644
index 0000000..e6ae12a
--- /dev/null
+++ b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h
@@ -0,0 +1,15 @@
+#ifndef _SCRIPTINGBACKENDAPI_MONO_H_
+#define _SCRIPTINGBACKENDAPI_MONO_H_
+
+#include "../ScriptingTypes.h"
+
+typedef MonoObject* (*FastMonoMethod) (void* thiz, MonoException** ex);
+
+struct ScriptingMethod
+{
+ MonoMethod* monoMethod;
+ FastMonoMethod fastMonoMethod;
+ bool isInstance;
+};
+
+#endif
diff --git a/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h b/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h
new file mode 100644
index 0000000..a7519f8
--- /dev/null
+++ b/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h
@@ -0,0 +1,83 @@
+#ifndef _SCRIPTINGMETHODFACTORY_MONO_
+#define _SCRIPTINGMETHODFACTORY_MONO_
+
+#include "../ScriptingMethodFactory.h"
+#include "Runtime/Mono/MonoIncludes.h"
+#include "../ScriptingMethodRegistry.h"
+#if ENABLE_MONO
+
+
+// Flag defined in mono, when AOT libraries are built with -ficall option
+// But that is not available in mono/consoles
+extern "C" int mono_ficall_flag;
+
+FastMonoMethod FastMonoMethodPtrFor(MonoMethod* method)
+{
+#if USE_MONO_AOT && !(UNITY_XENON || UNITY_PS3)
+ return mono_ficall_flag && method ? (FastMonoMethod) mono_aot_get_method(mono_domain_get(), method) : NULL;
+#else
+ return NULL;
+#endif
+}
+
+static bool MethodMatchesSearchFilter(MonoMethod* method, int searchFilter)
+{
+ MonoMethodSignature* sig = mono_method_signature(method);
+ return MethodDescriptionMatchesSearchFilter(searchFilter, mono_signature_is_instance(sig), mono_signature_get_param_count(sig));
+}
+
+class ScriptingMethodFactory_Mono : public IScriptingMethodFactory
+{
+public:
+ virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter)
+ {
+ void* iterator = NULL;
+ while (MonoMethod* method = mono_class_get_methods(klass, &iterator))
+ {
+ if (!method)
+ return NULL;
+
+ if (strcmp(mono_method_get_name(method), name)!=0)
+ continue;
+
+ if (MethodMatchesSearchFilter(method,searchFilter))
+ return Produce(method);
+ }
+ return NULL;
+ }
+
+ virtual ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod)
+ {
+ ScriptingMethodPtr result = new ScriptingMethod();
+ result->monoMethod = nativeMethod;
+ MonoMethodSignature* sig = mono_method_signature(nativeMethod);
+#if UNITY_EDITOR
+ if (!sig) {
+ // Loader error - usually missing reference
+ Scripting::LogException(mono_loader_error_prepare_exception (mono_loader_get_last_error ()), 0);
+ return NULL;
+ }
+#endif
+ result->isInstance = mono_signature_is_instance(sig);
+ result->fastMonoMethod = IsSignatureSupportedForFastAotCalls(sig) ? FastMonoMethodPtrFor(nativeMethod) : NULL;
+ return result;
+ }
+
+ virtual void Release(ScriptingMethodPtr method)
+ {
+ delete method;
+ }
+
+private:
+ bool IsSignatureSupportedForFastAotCalls(MonoMethodSignature* sig)
+ {
+ if (!mono_signature_is_instance(sig))
+ return false;
+
+ return mono_signature_get_param_count(sig) == 0;
+ }
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingArguments.cpp b/Runtime/Scripting/Backend/ScriptingArguments.cpp
new file mode 100644
index 0000000..9fcbaad
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingArguments.cpp
@@ -0,0 +1,218 @@
+#include "UnityPrefix.h"
+#include "ScriptingTypes.h"
+
+#if ENABLE_SCRIPTING
+
+#include "ScriptingArguments.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+
+ScriptingArguments::ScriptingArguments()
+ : m_Count(0)
+{
+#if UNITY_WINRT
+ m_StringArguments = ref new Platform::Array<Platform::String^>(MAXARGS);
+#else
+ memset(m_Arguments, 0, sizeof(m_Arguments));
+#endif
+ memset(&m_PrimitiveStorage, 0, sizeof(m_PrimitiveStorage));
+ memset(m_ArgumentTypes, 0, sizeof(m_ArgumentTypes));
+}
+
+void ScriptingArguments::AddBoolean(bool value)
+{
+ m_PrimitiveStorage.ints[m_Count] = value ? 1 : 0;
+#if UNITY_WINRT
+ m_Arguments[m_Count] = m_PrimitiveStorage.ints[m_Count];
+#else
+ m_Arguments[m_Count] = &m_PrimitiveStorage.ints[m_Count];
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_BOOLEAN;
+ m_Count++;
+}
+
+void ScriptingArguments::AddInt(int value)
+{
+ m_PrimitiveStorage.ints[m_Count] = value;
+#if UNITY_WINRT
+ m_Arguments[m_Count] = *(long long*)&value;
+#else
+ m_Arguments[m_Count] = &m_PrimitiveStorage.ints[m_Count];
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_INT;
+ m_Count++;
+}
+
+void ScriptingArguments::AddFloat(float value)
+{
+ m_PrimitiveStorage.floats[m_Count] = value;
+#if UNITY_WINRT
+ m_Arguments[m_Count] = *(long long*)&value;
+#else
+ m_Arguments[m_Count] = &m_PrimitiveStorage.floats[m_Count];
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_FLOAT;
+ m_Count++;
+}
+
+void ScriptingArguments::AddString(const char* str)
+{
+#if ENABLE_MONO
+ m_Arguments[m_Count] = MonoStringNew(str);
+#elif UNITY_FLASH
+ m_Arguments[m_Count] = str;
+#elif UNITY_WINRT
+ m_StringArguments[m_Count] = ConvertUtf8ToString(str);
+ m_Arguments[m_Count] = (long long)m_StringArguments[m_Count]->Data();
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_STRING;
+ m_Count++;
+}
+
+void ScriptingArguments::AddString(std::string& str)
+{
+ AddString(str.c_str());
+}
+
+void ScriptingArguments::AddObject(ScriptingObjectPtr scriptingObject)
+{
+#if UNITY_WINRT
+ m_Arguments[m_Count] = scriptingObject.GetHandle();
+#else
+ m_Arguments[m_Count] = scriptingObject;
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_OBJECT;
+ m_Count++;
+}
+
+void ScriptingArguments::AddStruct(void* pointerToStruct)
+{
+#if UNITY_WINRT
+ // We need to pass struct size, and ScriptingType here, to set the struct for metro
+ FatalErrorMsg("ToDo");
+#else
+ m_Arguments[m_Count] = pointerToStruct;
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_STRUCT;
+ m_Count++;
+}
+
+void ScriptingArguments::AddArray(ScriptingArrayPtr arr)
+{
+#if UNITY_WINRT
+ m_Arguments[m_Count] = arr.GetHandle();
+#elif UNITY_FLASH
+ FatalErrorMsg("ToDo");
+#else
+ m_Arguments[m_Count] = arr;
+#endif
+ m_ArgumentTypes[m_Count] = ARGTYPE_ARRAY;
+ m_Count++;
+}
+
+void ScriptingArguments::AddEnum(int value)
+{
+ AddInt(value);
+ m_ArgumentTypes[m_Count-1] = ARGTYPE_ENUM;
+}
+
+bool ScriptingArguments::GetBooleanAt(int index)
+{
+ return m_PrimitiveStorage.ints[index] == 1;
+}
+
+int ScriptingArguments::GetIntAt(int index)
+{
+ return m_PrimitiveStorage.ints[index];
+}
+
+float ScriptingArguments::GetFloatAt(int index)
+{
+ return m_PrimitiveStorage.floats[index];
+}
+
+const void* ScriptingArguments::GetStringAt(int index)
+{
+#if UNITY_WINRT
+ return m_StringArguments[index]->Data();
+#else
+ return m_Arguments[index];
+#endif
+}
+
+ScriptingObjectPtr ScriptingArguments::GetObjectAt(int index)
+{
+#if UNITY_WINRT
+ return ScriptingObjectPtr(safe_cast<long long>(m_Arguments[index]));
+#else
+ return (ScriptingObjectPtr) m_Arguments[index];
+#endif
+}
+
+void** ScriptingArguments::InMonoFormat()
+{
+ return (void**) &m_Arguments[0];
+}
+
+int ScriptingArguments::GetTypeAt(int index)
+{
+ return m_ArgumentTypes[index];
+}
+
+int ScriptingArguments::GetCount()
+{
+ return m_Count;
+}
+
+void ScriptingArguments::AdjustArgumentsToMatchMethod(ScriptingMethodPtr method)
+{
+#if ENABLE_MONO
+ MonoMethodSignature* sig = mono_method_signature (method->monoMethod);
+ int methodCount = mono_signature_get_param_count (sig);
+ if (methodCount < m_Count)
+ m_Count = methodCount;
+#endif
+}
+
+bool ScriptingArguments::CheckArgumentsAgainstMethod(ScriptingMethodPtr method)
+{
+#if !ENABLE_MONO
+ return true;
+#else
+
+ MonoMethodSignature* sig = mono_method_signature (method->monoMethod);
+ int argCount = mono_signature_get_param_count (sig);
+ if (argCount != GetCount())
+ return false;
+
+ void* iterator = NULL;
+ int argIndex = -1;
+ while(true)
+ {
+ argIndex++;
+ MonoType* methodType = mono_signature_get_params (sig, &iterator);
+ if (methodType == NULL)
+ return true;
+
+ if (GetTypeAt(argIndex) != ScriptingArguments::ARGTYPE_OBJECT)
+ continue;
+
+ MonoClass* invokingArgument = mono_object_get_class(GetObjectAt(argIndex));
+ MonoClass* receivingArgument = mono_class_from_mono_type (methodType);
+
+ if (!mono_class_is_subclass_of (invokingArgument, receivingArgument, false))
+ return false;
+ }
+ return true;
+#endif
+}
+
+
+#if UNITY_WINRT
+ScriptingParamsPtr ScriptingArguments::InMetroFormat()
+{
+ if (m_Count <= 0) return SCRIPTING_NULL;
+ return &m_Arguments[0];
+}
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingArguments.h b/Runtime/Scripting/Backend/ScriptingArguments.h
new file mode 100644
index 0000000..9ea823f
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingArguments.h
@@ -0,0 +1,79 @@
+#ifndef _SCRIPTINGARGUMENTS_H_
+#define _SCRIPTINGARGUMENTS_H_
+
+#if ENABLE_SCRIPTING
+#include "ScriptingTypes.h"
+#include <string>
+#include "Runtime/Modules/ExportModules.h"
+
+
+struct EXPORT_COREMODULE ScriptingArguments
+{
+ enum Constants
+ {
+ MAXARGS=10
+ };
+
+ enum ArgType
+ {
+ ARGTYPE_BOOLEAN,
+ ARGTYPE_INT,
+ ARGTYPE_FLOAT,
+ ARGTYPE_STRING,
+ ARGTYPE_OBJECT,
+ ARGTYPE_STRUCT,
+ ARGTYPE_ARRAY,
+ ARGTYPE_ENUM
+ };
+
+ //this setup is kind of weird. some types of arguments just need to be stuffed in m_Arguments,
+ //however for ints and floats, instead of stuffing them in, mono actually excepts a pointer to one.
+ //to make it happy, we store the actual int in a field, and store a pointer to it in the ScriptingParam.
+ union
+ {
+ int ints[MAXARGS];
+ float floats[MAXARGS];
+ } m_PrimitiveStorage;
+
+#if UNITY_WINRT
+ Platform::Array<Platform::String^>^ m_StringArguments;
+ ScriptingParams m_Arguments[MAXARGS];
+#else
+ const void* m_Arguments[MAXARGS];
+#endif
+ int m_ArgumentTypes[MAXARGS];
+ int m_Count;
+
+ ScriptingArguments();
+
+ void AddBoolean(bool value);
+ void AddInt(int value);
+ void AddFloat(float value);
+ void AddString(const char* str);
+ void AddString(std::string& str);
+ void AddObject(ScriptingObjectPtr scriptingObject);
+ void AddStruct(void* pointerToStruct);
+ void AddEnum(int value);
+ void AddArray(ScriptingArrayPtr arr);
+
+ bool GetBooleanAt(int index);
+ int GetIntAt(int index);
+ float GetFloatAt(int index);
+ const void* GetStringAt(int index);
+ ScriptingObjectPtr GetObjectAt(int index);
+
+ void** InMonoFormat();
+
+ void AdjustArgumentsToMatchMethod(ScriptingMethodPtr method);
+ bool CheckArgumentsAgainstMethod(ScriptingMethodPtr method);
+#if UNITY_WINRT
+ ScriptingParamsPtr InMetroFormat();
+#endif
+
+ int GetTypeAt(int index);
+ int GetCount();
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingBackendApi.h b/Runtime/Scripting/Backend/ScriptingBackendApi.h
new file mode 100644
index 0000000..1e729b7
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingBackendApi.h
@@ -0,0 +1,72 @@
+#ifndef _SCRIPTINGBACKEND_API_H_
+#define _SCRIPTINGBACKEND_API_H_
+
+#include <string>
+
+#include "ScriptingTypes.h"
+class ScriptingMethodRegistry;
+class ScriptingTypeRegistry;
+struct ScriptingArguments;
+
+struct StackTraceInfo
+{
+ std::string condition;
+ std::string strippedStacktrace;
+ std::string stacktrace;
+ int errorNum;
+ std::string file;
+ int line;
+};
+
+bool scripting_method_is_instance(ScriptingMethodPtr method);
+const char* scripting_method_get_name(ScriptingMethodPtr method);
+int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry);
+ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry);
+bool scripting_method_has_attribute(ScriptingMethodPtr method, ScriptingClassPtr attribute);
+ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry);
+ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception);
+
+ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr t, ScriptingTypeRegistry& typeRegistry);
+void scripting_class_get_methods(ScriptingTypePtr t, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result);
+const char* scripting_class_get_name(ScriptingTypePtr t);
+const char* scripting_class_get_namespace(ScriptingTypePtr t);
+bool scripting_class_is_subclass_of(ScriptingTypePtr t1, ScriptingTypePtr t2);
+bool scripting_class_is_enum(ScriptingTypePtr t);
+ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t);
+void scripting_object_invoke_default_constructor(ScriptingObjectPtr o, ScriptingExceptionPtr* exc);
+ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr t, ScriptingTypeRegistry& typeRegistry);
+ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry);
+
+ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry);
+
+EXPORT_COREMODULE int scripting_gchandle_new(ScriptingObjectPtr o);
+EXPORT_COREMODULE int scripting_gchandle_weak_new(ScriptingObjectPtr o);
+EXPORT_COREMODULE void scripting_gchandle_free(int handle);
+EXPORT_COREMODULE ScriptingObjectPtr scripting_gchandle_get_target(int handle);
+
+int scripting_gc_maxgeneration();
+void scripting_gc_collect(int maxGeneration);
+
+ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass);
+ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o);
+
+ScriptingStringPtr scripting_string_new(const char* str);
+ScriptingStringPtr scripting_string_new(const std::string& str);
+ScriptingStringPtr scripting_string_new(const wchar_t* str);
+ScriptingStringPtr scripting_string_new(const char* str, unsigned int length);
+
+void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info);
+EXPORT_COREMODULE std::string scripting_cpp_string_for(ScriptingStringPtr ptr);
+
+void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size);
+
+// TODO: temporary, these includes are going to disappear very soon
+
+#if UNITY_FLASH
+#include "Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h"
+#elif UNITY_WINRT
+#elif ENABLE_MONO
+#include "Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h"
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingInvocation.cpp b/Runtime/Scripting/Backend/ScriptingInvocation.cpp
new file mode 100644
index 0000000..71ead05
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingInvocation.cpp
@@ -0,0 +1,223 @@
+#include "UnityPrefix.h"
+
+#if ENABLE_SCRIPTING
+
+#include "ScriptingInvocation.h"
+#include "Runtime/Utilities/LogAssert.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "ScriptingArguments.h"
+#include "ScriptingMethodRegistry.h"
+#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Scripting/ScriptingManager.h"
+
+#if ENABLE_MONO
+#include "Runtime/Mono/MonoIncludes.h"
+#include "Runtime/Mono/MonoManager.h"
+#include "Runtime/Mono/MonoUtility.h"
+#include "Runtime/Mono/MonoScript.h"
+#endif
+
+ScriptingInvocation::ScriptingInvocation()
+{
+}
+
+ScriptingInvocation::ScriptingInvocation(ScriptingMethodPtr in_method)
+ : ScriptingInvocationNoArgs(in_method)
+{
+}
+
+#if ENABLE_MONO || UNITY_WINRT
+ScriptingInvocation::ScriptingInvocation(const char* namespaze, const char* klassName, const char* methodName)
+{
+ method = GetScriptingMethodRegistry().GetMethod(namespaze, klassName, methodName);
+}
+
+ScriptingInvocation::ScriptingInvocation(ScriptingClassPtr klass, const char* methodName)
+{
+ method = GetScriptingMethodRegistry().GetMethod(klass, methodName);
+}
+
+ScriptingInvocation::ScriptingInvocation(BackendNativeMethod monoMethod)
+{
+ method = GetScriptingMethodRegistry().GetMethod(monoMethod);
+}
+#endif
+
+bool ScriptingInvocation::Check()
+{
+#if !ENABLE_MONO
+ return true;
+#else
+ return ScriptingInvocationNoArgs::Check() && arguments.CheckArgumentsAgainstMethod(method);
+#endif
+}
+
+template<class T>
+T ScriptingInvocation::Invoke()
+{
+ ScriptingExceptionPtr ex = NULL;
+ return Invoke<T>(&ex);
+}
+
+template<>
+ScriptingObjectPtr ScriptingInvocation::Invoke<ScriptingObjectPtr>()
+{
+ return Invoke();
+}
+
+template<>
+bool ScriptingInvocation::Invoke<bool>(ScriptingExceptionPtr* exception)
+{
+ ScriptingObjectPtr o = Invoke(exception);
+ if (*exception != NULL)
+ return false;
+
+ #if ENABLE_MONO
+ if (method->fastMonoMethod)
+ return (bool)o;
+ else
+ return ExtractMonoObjectData<char>(o);
+ #elif UNITY_FLASH
+ bool boolResult;
+ __asm __volatile__("%0 = marshallmap.getObjectWithId(%1);" : "=r"(boolResult) : "r"(o));
+ return boolResult;
+ #elif UNITY_WINRT
+ return o != SCRIPTING_NULL ? o.ToBool() : false;
+ #endif
+}
+
+ScriptingObjectPtr ScriptingInvocation::Invoke()
+{
+ ScriptingExceptionPtr ex = NULL;
+ return Invoke(&ex);
+}
+
+ScriptingObjectPtr ScriptingInvocation::Invoke(ScriptingExceptionPtr* exception)
+{
+ return Invoke(exception, false);
+}
+
+ScriptingObjectPtr ScriptingInvocation::Invoke(ScriptingExceptionPtr* exception, bool convertArguments)
+{
+ ScriptingObjectPtr returnValue;
+
+ *exception = NULL;
+
+#if ENABLE_MONO || UNITY_FLASH || UNITY_WINRT
+ MONO_PROFILER_BEGIN (method, classContextForProfiler, object)
+#if UNITY_WINRT
+ ScriptingObjectPtr metro_invoke_method(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments* arguments, ScriptingExceptionPtr* exception, bool convertArgs);
+ returnValue = metro_invoke_method(method, object, &arguments, exception, convertArguments);
+#else
+ returnValue = scripting_method_invoke(method, object, arguments, exception);
+#endif
+ MONO_PROFILER_END
+#elif !UNITY_EXTERNAL_TOOL
+ ErrorString("Invoke() not implemented on this platform");
+#else
+ return NULL;
+#endif
+
+ if (! *exception) return returnValue;
+
+ this->exception = *exception;
+#if !UNITY_EXTERNAL_TOOL
+ if (logException)
+ Scripting::LogException(*exception, objectInstanceIDContextForException );
+#endif
+
+ return SCRIPTING_NULL;
+}
+
+void ScriptingInvocation::AdjustArgumentsToMatchMethod()
+{
+ arguments.AdjustArgumentsToMatchMethod(method);
+}
+
+
+#if ENABLE_MONO
+
+MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters)
+{
+ MonoException* exception = NULL;
+ return CallStaticMonoMethod(klass, methodName, parameters, &exception);
+}
+
+
+static MonoObject* CallStaticMonoMethod (MonoMethod* method, void** parameters, MonoException** exception)
+{
+ MonoObject* returnValue = mono_runtime_invoke_profiled (method, NULL, parameters, exception);
+ if (! *exception) return returnValue;
+
+ Scripting::LogException(*exception, 0);
+ return NULL;
+}
+
+
+static MonoObject* CallStaticMonoMethod (MonoMethod* method, void** parameters)
+{
+ MonoException* exception = NULL;
+ return CallStaticMonoMethod(method, parameters, &exception);
+}
+
+MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters)
+{
+ MonoException* exception = NULL;
+ return CallStaticMonoMethod(className, methodName, parameters, &exception);
+}
+
+MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters, MonoException** exception)
+{
+ MonoMethod* method = mono_class_get_method_from_name (klass, methodName, -1);
+
+ if (!method)
+ {
+ ErrorString (Format ("Couldn't call method %s in class %s because it wasn't found.", methodName, mono_class_get_name(klass)));
+ return NULL;
+ }
+
+ return CallStaticMonoMethod(method, parameters, exception);
+}
+
+MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters, MonoException** exception)
+{
+ MonoMethod* m = FindStaticMonoMethod(className, methodName);
+ if (!m)
+ {
+ ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className));
+ return NULL;
+ }
+
+ return CallStaticMonoMethod(m, parameters, exception);
+}
+
+MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** parameters)
+{
+ MonoException* exception = NULL;
+ MonoMethod* m = FindStaticMonoMethod(nameSpace, className, methodName);
+ if (!m)
+ {
+ ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className));
+ return NULL;
+ }
+
+ return CallStaticMonoMethod(m, parameters, &exception);
+}
+
+MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** parameters, MonoException** exception)
+{
+ MonoMethod* m = FindStaticMonoMethod(nameSpace, className, methodName);
+ if (!m)
+ {
+ ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className));
+ return NULL;
+ }
+
+ return CallStaticMonoMethod(m, parameters, exception);
+}
+
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingInvocation.h b/Runtime/Scripting/Backend/ScriptingInvocation.h
new file mode 100644
index 0000000..2bad02c
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingInvocation.h
@@ -0,0 +1,73 @@
+#ifndef _SCRIPTINGINVOCATION_H_
+#define _SCRIPTINGINVOCATION_H_
+
+#if ENABLE_SCRIPTING
+
+#include "ScriptingInvocationNoArgs.h"
+#include "ScriptingArguments.h"
+
+
+/// ScriptingInvocation invocation (scriptingMethod); // Slow alternative (Don't use this in runtime code) ScriptingInvocation invocation ("MyNameSpace", "MyClassName", "MyMethod");
+/// invocation.AddInt(5);
+/// invocation.Invoke (); // < you are certain that the bound method accepts those exact parameters
+/// invocation.InvokeChecked(); // < you cant guarantee that the bound method has the passed parameters
+
+/// By default logs the exception (Can be turned off via invocation.logException = false;)
+/// Parameters are setup AddInt, AddFloat, AddStruct functions below
+class ScriptingInvocation : public ScriptingInvocationNoArgs
+{
+public:
+ ScriptingInvocation();
+ ScriptingInvocation(ScriptingMethodPtr in_method);
+#if ENABLE_MONO || UNITY_WINRT
+ ScriptingInvocation(const char* namespaze, const char* klass, const char* name);
+ ScriptingInvocation(ScriptingClassPtr klass, const char* name);
+ ScriptingInvocation(BackendNativeMethod method);
+#endif
+
+ //convenience forwarders to arguments
+ void AddBoolean(bool value) { arguments.AddBoolean(value); }
+ void AddInt(int value) { arguments.AddInt(value); }
+ void AddFloat(float value) { arguments.AddFloat(value); }
+ void AddString(const char* str) { arguments.AddString(str); }
+ void AddString(std::string& str) { arguments.AddString(str); }
+ void AddObject(ScriptingObjectPtr scriptingObject) { arguments.AddObject(scriptingObject); }
+ void AddStruct(void* pointerToStruct) { arguments.AddStruct(pointerToStruct); }
+ void AddEnum(int value) { arguments.AddEnum(value); }
+ void AddArray(ScriptingArrayPtr arr) { arguments.AddArray(arr); }
+
+ void AdjustArgumentsToMatchMethod();
+
+ template<class T> T Invoke();
+ template<class T> T Invoke(ScriptingException**);
+ ScriptingObjectPtr Invoke();
+ ScriptingObjectPtr Invoke(ScriptingException**);
+ ScriptingObjectPtr Invoke(ScriptingExceptionPtr*, bool);
+
+ ScriptingArguments& Arguments() { return arguments; }
+protected:
+ ScriptingArguments arguments;
+ virtual bool Check();
+};
+
+
+#if ENABLE_MONO
+
+struct MonoObject;
+struct MonoException;
+class Object;
+struct MonoMethod;
+struct MonoClass;
+class MonoScript;
+
+MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters = NULL);
+MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters, MonoException** exception);
+MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** paramenters = NULL);
+MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** paramenters, MonoException** exception);
+MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters = NULL);
+MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters, MonoException** exception);
+#endif
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp
new file mode 100644
index 0000000..19ab0f0
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp
@@ -0,0 +1,123 @@
+#include "UnityPrefix.h"
+
+#if ENABLE_SCRIPTING
+
+#include "ScriptingInvocationNoArgs.h"
+#include "Runtime/Utilities/LogAssert.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "ScriptingMethodRegistry.h"
+#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
+#include "Runtime/Profiler/Profiler.h"
+
+#if ENABLE_MONO
+#include "Runtime/Mono/MonoIncludes.h"
+#include "Runtime/Mono/MonoManager.h"
+#include "Runtime/Mono/MonoUtility.h"
+#include "Runtime/Mono/MonoScript.h"
+#endif
+
+ScriptingInvocationNoArgs::ScriptingInvocationNoArgs()
+{
+ SetDefaults();
+}
+
+ScriptingInvocationNoArgs::ScriptingInvocationNoArgs(ScriptingMethodPtr in_method)
+{
+ SetDefaults();
+ method = in_method;
+}
+
+void ScriptingInvocationNoArgs::SetDefaults()
+{
+ object = SCRIPTING_NULL;
+ method = SCRIPTING_NULL;
+ classContextForProfiler = NULL;
+ logException = true;
+ objectInstanceIDContextForException = 0;
+ exception = SCRIPTING_NULL;
+}
+
+bool ScriptingInvocationNoArgs::Check()
+{
+#if !ENABLE_MONO
+ return true;
+#else
+
+ // Check method
+ if (method == NULL)
+ {
+ ErrorString("Failed to call function because it was null");
+ return false;
+ }
+
+ bool methodIsInstance = mono_signature_is_instance (mono_method_signature(method->monoMethod));
+ bool invokingInstance = object != NULL;
+
+ if (methodIsInstance && !invokingInstance)
+ {
+ DebugStringToFile (Format("Failed to call instance function %s because the no object was provided", mono_method_get_name (method->monoMethod)), 0, __FILE_STRIPPED__, __LINE__,
+ kError, objectInstanceIDContextForException);
+ return false;
+ }
+
+ if (!methodIsInstance && invokingInstance)
+ {
+ DebugStringToFile (Format("Failed to call static function %s because an object was provided", mono_method_get_name (method->monoMethod)), 0, __FILE_STRIPPED__, __LINE__,
+ kError, objectInstanceIDContextForException);
+ return false;
+ }
+
+ return true;
+
+#endif
+}
+
+
+ScriptingObjectPtr ScriptingInvocationNoArgs::Invoke()
+{
+ ScriptingExceptionPtr ex = NULL;
+ return Invoke(&ex);
+}
+
+ScriptingObjectPtr ScriptingInvocationNoArgs::Invoke(ScriptingExceptionPtr* exception)
+{
+ ScriptingObjectPtr returnValue;
+
+ *exception = NULL;
+
+#if ENABLE_MONO || UNITY_FLASH || UNITY_WINRT
+ ScriptingArguments arguments;
+ MONO_PROFILER_BEGIN (method, classContextForProfiler, object)
+#if UNITY_WINRT
+ ScriptingObjectPtr metro_invoke_method(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments* arguments, ScriptingExceptionPtr* exception, bool convertArgs);
+ returnValue = metro_invoke_method(method, object, NULL, exception, false);
+#else
+ returnValue = scripting_method_invoke(method, object, arguments, exception);
+#endif
+ MONO_PROFILER_END
+#elif !UNITY_EXTERNAL_TOOL
+ ErrorString("Invoke() not implemented on this platform");
+#else
+ return NULL;
+#endif
+
+ if (! *exception) return returnValue;
+
+ this->exception = *exception;
+#if !UNITY_EXTERNAL_TOOL
+ if (logException)
+ Scripting::LogException(*exception, objectInstanceIDContextForException);
+#endif
+
+ return SCRIPTING_NULL;
+}
+
+ScriptingObjectPtr ScriptingInvocationNoArgs::InvokeChecked()
+{
+ if (!Check())
+ return SCRIPTING_NULL;
+
+ return Invoke();
+}
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h
new file mode 100644
index 0000000..ece7010
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h
@@ -0,0 +1,31 @@
+#ifndef _SCRIPTINGINVOCATIONNOARGS_H_
+#define _SCRIPTINGINVOCATIONNOARGS_H_
+
+#if ENABLE_SCRIPTING
+
+#include "ScriptingTypes.h"
+
+class ScriptingInvocationNoArgs
+{
+public:
+ ScriptingInvocationNoArgs();
+ ScriptingInvocationNoArgs(ScriptingMethodPtr in_method);
+
+ ScriptingMethodPtr method;
+ ScriptingObjectPtr object;
+ int objectInstanceIDContextForException;
+ ScriptingTypePtr classContextForProfiler;
+ bool logException;
+ ScriptingExceptionPtr exception;
+
+ ScriptingObjectPtr Invoke();
+ virtual ScriptingObjectPtr Invoke(ScriptingException**);
+ ScriptingObjectPtr InvokeChecked();
+protected:
+ void SetDefaults();
+ virtual bool Check();
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingMethodFactory.h b/Runtime/Scripting/Backend/ScriptingMethodFactory.h
new file mode 100644
index 0000000..a497d62
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingMethodFactory.h
@@ -0,0 +1,18 @@
+#ifndef _SCRIPTINGMETHODFACTORY_H_
+#define _SCRIPTINGMETHODFACTORY_H_
+
+#include "ScriptingTypes.h"
+
+
+// !!TODO: ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) & ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod) must return the same
+// method if internally method is the same !!!
+class IScriptingMethodFactory
+{
+public:
+ virtual ~IScriptingMethodFactory() {}
+ virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) = 0;
+ virtual ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod) = 0;
+ virtual void Release(ScriptingMethodPtr) = 0;
+};
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp b/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp
new file mode 100644
index 0000000..e9df7fd
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp
@@ -0,0 +1,165 @@
+#include "UnityPrefix.h"
+#if ENABLE_SCRIPTING
+#include "ScriptingMethodRegistry.h"
+#include "ScriptingMethodFactory.h"
+#include "ScriptingTypeRegistry.h"
+#include "Runtime/Mono/MonoIncludes.h"
+#include "ScriptingBackendApi.h"
+#include "Runtime/Scripting/ScriptingManager.h"
+
+using std::vector;
+
+
+ScriptingMethodRegistry::ScriptingMethodRegistry(IScriptingMethodFactory* scriptingMethodFactory, ScriptingTypeRegistry* scriptingTypeRegistry)
+ : m_ScriptingMethodFactory(scriptingMethodFactory),
+ m_ScriptingTypeRegistry(scriptingTypeRegistry)
+{
+}
+
+ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(const char* namespaze, const char* className, const char* methodName, int searchOptions)
+{
+ ScriptingTypePtr klass = m_ScriptingTypeRegistry->GetType(namespaze,className);
+ if (klass==SCRIPTING_NULL)
+ return SCRIPTING_NULL;
+ return GetMethod(klass,methodName,searchOptions);
+}
+
+ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(BackendNativeMethod nativeMethod)
+{
+ NativeMethodToScriptingMethod::iterator i = m_NativeMethodToScriptingMethod.find(nativeMethod);
+ if (i != m_NativeMethodToScriptingMethod.end())
+ return i->second;
+
+ ScriptingMethodPtr scriptingMethod = m_ScriptingMethodFactory->Produce(nativeMethod);
+ m_NativeMethodToScriptingMethod[nativeMethod] = scriptingMethod;
+ return scriptingMethod;
+}
+
+ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(ScriptingTypePtr klass, const char* methodName, int searchOptions)
+{
+ bool found;
+ ScriptingMethodPtr cached = FindInCache(klass,methodName,searchOptions,&found);
+ if (found)
+ return cached;
+
+ ScriptingMethodPtr scriptingMethod = m_ScriptingMethodFactory->Produce(klass,methodName, searchOptions);
+
+ if (!scriptingMethod && (!(searchOptions & kDontSearchBaseTypes)))
+ {
+ ScriptingTypePtr baseClass = scripting_class_get_parent (klass, *m_ScriptingTypeRegistry);
+ if (baseClass)
+ scriptingMethod = GetMethod(baseClass, methodName, searchOptions);
+ }
+
+ PlaceInCache(klass,methodName,scriptingMethod);
+
+ return scriptingMethod;
+}
+
+bool MethodDescriptionMatchesSearchFilter(int searchFilter, bool isInstance, int argCount)
+{
+ if ((searchFilter & ScriptingMethodRegistry::kStaticOnly) && isInstance)
+ return false;
+
+ if ((searchFilter & ScriptingMethodRegistry::kInstanceOnly) && !isInstance)
+ return false;
+
+ if ((searchFilter & ScriptingMethodRegistry::kWithoutArguments) && argCount>0)
+ return false;
+
+ return true;
+}
+
+static bool MethodMatchesSearchFilter(ScriptingMethodPtr method, int searchFilter)
+{
+ return MethodDescriptionMatchesSearchFilter(searchFilter, scripting_method_is_instance(method), scripting_method_get_argument_count(method, GetScriptingTypeRegistry()));
+}
+
+void ScriptingMethodRegistry::AllMethodsIn(ScriptingTypePtr klass, vector<ScriptingMethodPtr>& result, int searchOptions)
+{
+ vector<ScriptingMethodPtr> methods;
+ scripting_class_get_methods(klass, *this, methods);
+ for (vector<ScriptingMethodPtr>::iterator item = methods.begin();
+ item != methods.end();
+ item++)
+ {
+ if (!MethodMatchesSearchFilter(*item, searchOptions))
+ continue;
+
+ result.push_back(*item);
+ }
+
+ if (searchOptions & kDontSearchBaseTypes)
+ return;
+
+ ScriptingTypePtr baseClass = scripting_class_get_parent(klass, *m_ScriptingTypeRegistry);
+ if (baseClass == SCRIPTING_NULL)
+ return;
+
+ return AllMethodsIn(baseClass, result, searchOptions);
+}
+
+void ScriptingMethodRegistry::InvalidateCache()
+{
+ //make sure to not delete a scriptingmethod twice, as it could be in the cache in multiple places. (in case of classes implementing interfaces & virtual methods)
+ MethodsSet todelete;
+ for (ClassToMethodsByName::iterator cci = m_Cache.begin(); cci != m_Cache.end(); cci++)
+ for (MethodsByName::iterator mbni = cci->second.begin(); mbni != cci->second.end(); mbni++)
+ for (VectorOfMethods::iterator smpi = mbni->second.begin(); smpi != mbni->second.end(); smpi++)
+ todelete.insert(*smpi);
+
+ for (NativeMethodToScriptingMethod::iterator i = m_NativeMethodToScriptingMethod.begin(); i != m_NativeMethodToScriptingMethod.end(); i++)
+ todelete.insert(i->second);
+
+ for (MethodsSet::iterator i = todelete.begin(); i != todelete.end(); i++)
+ m_ScriptingMethodFactory->Release(*i);
+
+ m_Cache.clear();
+ m_NativeMethodToScriptingMethod.clear();
+}
+
+ScriptingMethodPtr ScriptingMethodRegistry::FindInCache(ScriptingTypePtr klass, const char* name, int searchFilter, bool* found)
+{
+ *found = false;
+ MethodsByName* cc = FindMethodsByNameFor(klass);
+ if (cc == NULL)
+ return SCRIPTING_NULL;
+
+ MethodsByName::iterator mbni = cc->find(name);
+ if (mbni == cc->end())
+ return SCRIPTING_NULL;
+
+ for (VectorOfMethods::iterator i = mbni->second.begin(); i != mbni->second.end(); i++)
+ {
+ if (*i == NULL || MethodMatchesSearchFilter(*i, searchFilter))
+ {
+ *found = true;
+ return *i;
+ }
+ }
+ return SCRIPTING_NULL;
+}
+
+void ScriptingMethodRegistry::PlaceInCache(ScriptingTypePtr klass, const char* name, ScriptingMethodPtr method)
+{
+ MethodsByName* mbn = FindMethodsByNameFor(klass);
+ if (mbn == NULL)
+ {
+ m_Cache.insert(std::make_pair(klass, MethodsByName()));
+ mbn = FindMethodsByNameFor(klass);
+ }
+
+ VectorOfMethods vom;
+ vom.push_back(method);
+ mbn->insert(std::make_pair(name,vom));
+}
+
+ScriptingMethodRegistry::MethodsByName* ScriptingMethodRegistry::FindMethodsByNameFor(ScriptingTypePtr klass)
+{
+ ClassToMethodsByName::iterator cc = m_Cache.find(klass);
+ if (cc == m_Cache.end())
+ return NULL;
+ return &cc->second;
+}
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistry.h b/Runtime/Scripting/Backend/ScriptingMethodRegistry.h
new file mode 100644
index 0000000..82d7e40
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingMethodRegistry.h
@@ -0,0 +1,60 @@
+#ifndef _SCRIPTINGMETHODREGISTRY_H_
+#define _SCRIPTINGMETHODREGISTRY_H_
+
+#if ENABLE_SCRIPTING
+#include "ScriptingTypes.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+class IScriptingMethodFactory;
+class ScriptingTypeRegistry;
+
+class ScriptingMethodRegistry
+{
+public:
+ ScriptingMethodRegistry(IScriptingMethodFactory* scriptingMethodFactory, ScriptingTypeRegistry* scriptingTypeRegistry);
+ ~ScriptingMethodRegistry() {InvalidateCache();}
+
+ enum SearchFilter
+ {
+ kNone = 0,
+ kInstanceOnly = 1,
+ kStaticOnly = 2,
+ kWithoutArguments = 4,
+ kDontSearchBaseTypes = 8,
+ };
+
+ ScriptingMethodPtr GetMethod(const char* namespaze, const char* klassName, const char* methodName, int searchOptions=kNone);
+ ScriptingMethodPtr GetMethod(ScriptingTypePtr klass, const char* methodName, int searchOptions=kNone);
+ ScriptingMethodPtr GetMethod(BackendNativeMethod nativeMathod);
+
+ void AllMethodsIn(ScriptingTypePtr klass, std::vector<ScriptingMethodPtr>& result, int searchOptions=kNone);
+
+ void InvalidateCache();
+
+private:
+ typedef std::vector<ScriptingMethodPtr> VectorOfMethods;
+ typedef std::map< std::string,VectorOfMethods > MethodsByName;
+ typedef std::map<ScriptingTypePtr, MethodsByName> ClassToMethodsByName;
+ typedef std::map<BackendNativeMethod, ScriptingMethodPtr> NativeMethodToScriptingMethod;
+ typedef std::set<ScriptingMethodPtr> MethodsSet;
+
+ ClassToMethodsByName m_Cache;
+
+
+ NativeMethodToScriptingMethod m_NativeMethodToScriptingMethod;
+
+ IScriptingMethodFactory* m_ScriptingMethodFactory;
+ ScriptingTypeRegistry* m_ScriptingTypeRegistry;
+
+ ScriptingMethodPtr FindInCache(ScriptingTypePtr klass, const char* name, int searchFilter, bool* out_found);
+ void PlaceInCache(ScriptingTypePtr klass, const char* name, ScriptingMethodPtr method);
+ MethodsByName* FindMethodsByNameFor(ScriptingTypePtr klass);
+};
+
+bool MethodDescriptionMatchesSearchFilter(int searchFilter, bool isInstance, int argCount);
+#endif
+
+#endif \ No newline at end of file
diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp b/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp
new file mode 100644
index 0000000..e3735b0
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp
@@ -0,0 +1,237 @@
+#include "UnityPrefix.h"
+#if DEDICATED_UNIT_TEST_BUILD
+#include "ScriptingMethodRegistry.h"
+#include "External/UnitTest++/src/UnitTest++.h"
+#include "ScriptingMethodFactory.h"
+#include "Tests/ScriptingBackendApi_Tests.h"
+#include <queue>
+#include <set>
+#include <vector>
+using std::queue;
+using std::vector;
+
+class ScriptingMethodFactory_Dummy : public IScriptingMethodFactory
+{
+public:
+ queue<ScriptingMethodPtr> produceThis;
+ ScriptingTypePtr returnNullForRequestson;
+ int produceCallCount;
+
+ ScriptingMethodFactory_Dummy() : produceCallCount(0) {}
+
+ virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter)
+ {
+ produceCallCount++;
+
+ if (returnNullForRequestson == klass)
+ return NULL;
+
+ if (produceThis.size()==0)
+ return NULL;
+
+ ScriptingMethodPtr result = produceThis.front();
+
+ if (result && !MethodDescriptionMatchesSearchFilter(searchFilter, result->instance, result->args))
+ return NULL;
+
+ produceThis.pop();
+ return result;
+ }
+
+ virtual ScriptingMethodPtr Produce(void* nativePtr)
+ {
+ return Produce(NULL,NULL, 0);
+ }
+
+ virtual void Release(ScriptingMethodPtr method)
+ {
+ }
+};
+
+struct Fixture
+{
+ ScriptingMethodFactory_Dummy methodFactory;
+ ScriptingMethodRegistry registry;
+
+ ScriptingType normalType;
+
+ ScriptingMethod method1;
+ ScriptingMethod method2;
+
+ Fixture() : registry(&methodFactory,NULL)
+ {
+ }
+};
+
+TEST_FIXTURE(Fixture,RegistryProducesNullForNonExistingMethod)
+{
+ CHECK_EQUAL((ScriptingMethodPtr)NULL,registry.GetMethod(&normalType,"Method1"));
+}
+
+TEST_FIXTURE(Fixture,RegistryProducesMethod)
+{
+ methodFactory.produceThis.push(&method1);
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+}
+
+TEST_FIXTURE(Fixture,RegistryReturnsSameMethodWhenQueriedTwiceWithSameArguments)
+{
+ methodFactory.produceThis.push(&method1);
+
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+}
+
+TEST_FIXTURE(Fixture,RegistryReturnsDifferentMethodsWhenQueriedForTwoDifferentClasses)
+{
+ methodFactory.produceThis.push(&method1);
+ methodFactory.produceThis.push(&method2);
+
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+ CHECK_EQUAL(&method2,registry.GetMethod((ScriptingTypePtr)124,"Method1"));
+}
+
+TEST_FIXTURE(Fixture,RegistryReturnsDifferentMethodsForDifferentSearchFilters)
+{
+ methodFactory.produceThis.push(&method1);
+ methodFactory.produceThis.push(&method2);
+ method1.instance = false;
+ method2.instance = true;
+
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kStaticOnly));
+ CHECK_EQUAL(&method2,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kInstanceOnly));
+}
+
+TEST_FIXTURE(Fixture,RegistryDoesNotFindMethodsNotMatchingSearchFilter)
+{
+ methodFactory.produceThis.push(&method1);
+ method1.instance = true;
+
+ ScriptingMethodPtr found = registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kStaticOnly);
+ if (found==NULL)
+ CHECK_EQUAL(1,1);
+ else
+ CHECK_EQUAL(1,0);
+}
+
+TEST_FIXTURE(Fixture,RegistryRemembersNonFoundMethods)
+{
+ methodFactory.produceThis.push(NULL);
+ methodFactory.produceThis.push(NULL);
+
+ registry.GetMethod(&normalType,"NonExisting");
+ registry.GetMethod(&normalType,"NonExisting");
+
+ CHECK_EQUAL(1,methodFactory.produceCallCount);
+}
+
+
+
+TEST_FIXTURE(Fixture,InvalidateCacheCausesNewMethodToBeProduced)
+{
+ methodFactory.produceThis.push(&method1);
+ methodFactory.produceThis.push(&method2);
+
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+ registry.InvalidateCache();
+ CHECK_EQUAL(&method2,registry.GetMethod(&normalType,"Method1"));
+}
+
+struct FixtureWithBaseTypeHavingMethod : public Fixture
+{
+ ScriptingType normalType;
+ ScriptingType baseType;
+
+ FixtureWithBaseTypeHavingMethod()
+ {
+ normalType.baseType = &baseType;
+ methodFactory.produceThis.push(&method1);
+ methodFactory.returnNullForRequestson = &normalType;
+ }
+};
+
+TEST_FIXTURE(FixtureWithBaseTypeHavingMethod,RegistryWillSearchBaseTypesIfRequested)
+{
+ CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1"));
+}
+
+TEST_FIXTURE(FixtureWithBaseTypeHavingMethod, RegistryWillNotSearchBaseTypesIfNotRequested)
+{
+ CHECK_EQUAL((ScriptingMethodPtr)NULL,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kDontSearchBaseTypes));
+}
+
+TEST_FIXTURE(Fixture, CanGetMethodFromNativeMethodPointer)
+{
+ int nativeMethod;
+ methodFactory.produceThis.push(&method1);
+ CHECK_EQUAL(&method1,registry.GetMethod( &nativeMethod));
+}
+
+TEST_FIXTURE(Fixture, CanGetSameMethodFromNativeMethodTwice)
+{
+ int nativeMethod;
+ methodFactory.produceThis.push(&method1);
+ CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod));
+ CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod));
+}
+
+TEST_FIXTURE(Fixture, InvalidateCacheClearsNativeMethodWrappers)
+{
+ int nativeMethod;
+ methodFactory.produceThis.push(&method1);
+ methodFactory.produceThis.push(&method2);
+ CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod));
+ registry.InvalidateCache();
+ CHECK_EQUAL(&method2,registry.GetMethod(&nativeMethod));
+}
+
+TEST_FIXTURE(Fixture, AllMethodsInType)
+{
+ normalType.methods.push_back(&method1);
+
+ vector<ScriptingMethodPtr> result;
+ registry.AllMethodsIn(&normalType, result);
+ CHECK_EQUAL(1, result.size());
+ CHECK_EQUAL(&method1, result[0]);
+}
+
+TEST_FIXTURE(Fixture, AllMethodsInTypeWillSearchBaseTypes)
+{
+ ScriptingType baseType;
+ baseType.methods.push_back(&method1);
+ normalType.baseType = &baseType;
+
+ vector<ScriptingMethodPtr> result;
+ registry.AllMethodsIn(&normalType, result);
+ CHECK_EQUAL(1, result.size());
+ CHECK_EQUAL(&method1, result[0]);
+}
+
+TEST_FIXTURE(Fixture, AllMethodsInTypeCanSkipStaticMethods)
+{
+ normalType.methods.push_back(&method1);
+ normalType.methods.push_back(&method2);
+
+ method2.instance = true;
+
+ vector<ScriptingMethodPtr> result;
+ registry.AllMethodsIn(&normalType, result, ScriptingMethodRegistry::kInstanceOnly);
+ CHECK_EQUAL(1, result.size());
+ CHECK_EQUAL(&method2, result[0]);
+}
+
+TEST_FIXTURE(Fixture, SearchFilterCanSkipMethodsWithArguments)
+{
+ normalType.methods.push_back(&method1);
+ normalType.methods.push_back(&method2);
+
+ method1.args=0;
+ method2.args=2;
+
+ vector<ScriptingMethodPtr> result;
+ registry.AllMethodsIn(&normalType, result, ScriptingMethodRegistry::kWithoutArguments );
+ CHECK_EQUAL(1, result.size());
+ CHECK_EQUAL(&method1, result[0]);
+}
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp b/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp
new file mode 100644
index 0000000..0e4fcbd
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp
@@ -0,0 +1,214 @@
+#include "UnityPrefix.h"
+#if ENABLE_SCRIPTING
+#include "ScriptingTypeRegistry.h"
+#include "ScriptingBackendApi.h"
+
+ScriptingTypeRegistry::ScriptingTypeRegistry(IScriptingTypeProvider* scriptingTypeProvider)
+ : m_ScriptingTypeProvider(scriptingTypeProvider)
+{
+}
+
+ScriptingTypePtr ScriptingTypeRegistry::GetType(const char* namespaze, const char* name)
+{
+ NameSpaceAndNamePair key = std::make_pair(namespaze,name);
+
+ Cache::iterator i = m_Cache.find(key);
+ if (i != m_Cache.end())
+ return i->second;
+
+ BackendNativeType nativetype = m_ScriptingTypeProvider->NativeTypeFor(namespaze, name);
+ ScriptingTypePtr type = m_ScriptingTypeProvider->Provide(nativetype);
+
+ m_Cache.insert(std::make_pair(key,type));
+ return type;
+}
+
+ScriptingTypePtr ScriptingTypeRegistry::GetType(BackendNativeType nativeType)
+{
+ NativeTypeCache::iterator i = m_NativeTypeCache.find(ScriptingObjectToComPtr(nativeType));
+ if (i != m_NativeTypeCache.end())
+ return i->second;
+
+ ScriptingTypePtr type = m_ScriptingTypeProvider->Provide(nativeType);
+
+ m_NativeTypeCache.insert(std::make_pair(ScriptingObjectToComPtr(nativeType), type));
+ return type;
+}
+
+ScriptingTypePtr ScriptingTypeRegistry::GetType(ScriptingObjectPtr systemTypeInstance)
+{
+ return scripting_class_from_systemtypeinstance(systemTypeInstance, *this);
+}
+
+void ScriptingTypeRegistry::InvalidateCache()
+{
+ m_Cache.clear();
+ m_NativeTypeCache.clear();
+}
+
+#if DEDICATED_UNIT_TEST_BUILD
+#include "External/UnitTest++/src/UnitTest++.h"
+#include <queue>
+#include "Tests/ScriptingBackendApi_Tests.h"
+using std::queue;
+
+class ScriptingTypeProvider_test : public IScriptingTypeProvider
+{
+public:
+ BackendNativeType NativeTypeFor(const char* namespaze, const char* name)
+ {
+ BackendNativeType ptr = provideThis.front();
+ provideThis.pop();
+ return ptr;
+ }
+
+ ScriptingTypePtr Provide(BackendNativeType nativeType)
+ {
+ return (ScriptingTypePtr)nativeType;
+ }
+
+ void Release(ScriptingTypePtr ptr) {}
+
+ queue<BackendNativeType> provideThis;
+};
+
+struct MyFixture
+{
+ ScriptingTypeProvider_test typeProvider;
+
+ ScriptingType type1;
+ ScriptingType type2;
+ int nativeType1;
+ int nativeType2;
+ FakeSystemTypeInstance systemTypeInstance1;
+ FakeSystemTypeInstance systemTypeInstance2;
+};
+
+TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsSameTypeWhenAskedForSameName)
+{
+ typeProvider.provideThis.push(&type1);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+ ScriptingTypePtr t1 = registry.GetType("mynamespace","mytype");
+ ScriptingTypePtr t2 = registry.GetType("mynamespace","mytype");
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type1,t2);
+}
+
+TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsDifferentTypeWhenAskedForDifferentName)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+ ScriptingTypePtr t1 = registry.GetType("mynamespace", "mytype");
+ ScriptingTypePtr t2 = registry.GetType("mynamespace", "myothertype");
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsDifferentTypeWhenAskedForTypesWithDifferentNamespace)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+ ScriptingTypePtr t1 = registry.GetType("mynamespace", "mytype");
+ ScriptingTypePtr t2 = registry.GetType("myothernamespace", "mytype");
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+TEST_FIXTURE(MyFixture,ScriptingTypeRegistryInvalidateCacheCausesNewTypeBeingProduced)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+ ScriptingTypePtr t1 = registry.GetType("mynamespace","mytype");
+ registry.InvalidateCache();
+ ScriptingTypePtr t2 = registry.GetType("mynamespace", "mytype");
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+TEST_FIXTURE(MyFixture,AskingForTheSameNativeTypeTwiceReturnsSameScriptingTypeTwice)
+{
+ typeProvider.provideThis.push(&type1);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+
+ ScriptingTypePtr t1 = registry.GetType(&nativeType1);
+ ScriptingTypePtr t2 = registry.GetType(&nativeType1);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type1,t2);
+}
+
+TEST_FIXTURE(MyFixture,AskingForTwoDifferentNativeTypesReturnsDifferentScriptingTypes)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+ ScriptingTypePtr t1 = registry.GetType(&nativeType1);
+ ScriptingTypePtr t2 = registry.GetType(&nativeType2);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+TEST_FIXTURE(MyFixture,InvalidateCacheCausesNewTypeToBeReturned)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+
+ ScriptingTypeRegistry registry(&typeProvider);
+
+ ScriptingTypePtr t1 = registry.GetType(&nativeType1);
+ registry.InvalidateCache();
+ ScriptingTypePtr t2 = registry.GetType(&nativeType1);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+TEST_FIXTURE(MyFixture,AskingForTypeOfSystemTypeInstanceTwiceReturnsSameType)
+{
+ typeProvider.provideThis.push(&type1);
+ ScriptingTypeRegistry registry(&typeProvider);
+
+ systemTypeInstance1.nativeType = &nativeType1;
+ ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1);
+ ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type1,t2);
+}
+/*
+TEST_FIXTURE(MyFixture,AskingForDifferentSystemTypeInstancesReturnsDifferentTypes)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+ ScriptingTypeRegistry registry(&typeProvider);
+
+ systemTypeInstance1.nativeType = &nativeType1;
+ systemTypeInstance1.nativeType = &nativeType2;
+ ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1);
+ ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance2);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+*/
+TEST_FIXTURE(MyFixture,InvalidateCacheCausesSystemTypeInstanceQueryToProvideNewType)
+{
+ typeProvider.provideThis.push(&type1);
+ typeProvider.provideThis.push(&type2);
+ ScriptingTypeRegistry registry(&typeProvider);
+
+ systemTypeInstance1.nativeType = &nativeType1;
+ ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1);
+ registry.InvalidateCache();
+ ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1);
+ CHECK_EQUAL(&type1,t1);
+ CHECK_EQUAL(&type2,t2);
+}
+
+#endif
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingTypeRegistry.h b/Runtime/Scripting/Backend/ScriptingTypeRegistry.h
new file mode 100644
index 0000000..be2328f
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingTypeRegistry.h
@@ -0,0 +1,33 @@
+#ifndef _SCRIPTINGTYPEREGISTRY_Y_
+#define _SCRIPTINGTYPEREGISTRY_Y_
+
+#if ENABLE_SCRIPTING
+
+#include <map>
+#include <string>
+#include "ScriptingTypes.h"
+#include "IScriptingTypeProvider.h"
+
+class ScriptingTypeRegistry
+{
+public:
+ ScriptingTypeRegistry(IScriptingTypeProvider* scriptingTypeProvider);
+ ScriptingTypePtr GetType(const char* namespaze, const char* name);
+ ScriptingTypePtr GetType(BackendNativeType nativeType);
+ ScriptingTypePtr GetType(ScriptingObjectPtr systemTypeInstance);
+ void InvalidateCache();
+
+private:
+ typedef std::pair<std::string,std::string> NameSpaceAndNamePair;
+ typedef std::map<NameSpaceAndNamePair, ScriptingTypePtr> Cache;
+ Cache m_Cache;
+
+ typedef std::map<void*, ScriptingTypePtr> NativeTypeCache;
+ NativeTypeCache m_NativeTypeCache;
+
+ IScriptingTypeProvider* m_ScriptingTypeProvider;
+};
+
+#endif
+
+#endif
diff --git a/Runtime/Scripting/Backend/ScriptingTypes.h b/Runtime/Scripting/Backend/ScriptingTypes.h
new file mode 100644
index 0000000..45911b0
--- /dev/null
+++ b/Runtime/Scripting/Backend/ScriptingTypes.h
@@ -0,0 +1,202 @@
+#ifndef _SCRIPTINGTYPES_H_
+#define _SCRIPTINGTYPES_H_
+
+#if ENABLE_MONO
+struct MonoObject;
+struct MonoString;
+struct MonoArray;
+struct MonoType;
+struct MonoClass;
+struct MonoException;
+struct MonoMethod;
+struct MonoClassField;
+typedef MonoObject ScriptingObject;
+typedef MonoString ScriptingString;
+typedef MonoArray ScriptingArray;
+typedef MonoClass ScriptingType;
+typedef MonoClass ScriptingClass;
+typedef MonoException ScriptingException;
+typedef MonoClassField ScriptingField;
+struct ScriptingMethod;
+typedef MonoMethod* BackendNativeMethod;
+typedef MonoClass* BackendNativeType;
+
+#elif UNITY_FLASH
+struct ScriptingObject;
+struct ScriptingString;
+struct ScriptingArray;
+struct ScriptingClass;
+typedef ScriptingClass ScriptingType;
+struct ScriptingException;
+
+struct ScriptingMethod;
+struct ScriptingField;
+struct MonoImage;
+
+//hack to not have to change everything in one go.
+struct MonoMethod;
+struct MonoObject;
+typedef ScriptingType MonoClass;
+typedef void* BackendNativeType;
+typedef void* BackendNativeMethod;
+#elif UNITY_WINRT && ENABLE_SCRIPTING
+struct WinRTNullPtrImplementation
+{
+ inline operator long long()
+ {
+ return -1;
+ }
+ inline operator decltype(__nullptr)()
+ {
+ return nullptr;
+ }
+};
+
+// Implemented in WinRTUtility.cpp
+class WinRTScriptingObjectWrapper
+{
+public:
+ // Must be in sync with WinRTBridge\GCHandledObjects.cs, would be nice to somehow get those values directly...
+ static const int kMaxHandlesShift = 11;
+ static const int kMaxHandlesPerBlock = 1 << kMaxHandlesShift;
+ static const int kHandleMask = kMaxHandlesPerBlock - 1;
+public:
+ WinRTScriptingObjectWrapper();
+ WinRTScriptingObjectWrapper(decltype(__nullptr));
+ WinRTScriptingObjectWrapper(long long handleId);
+ WinRTScriptingObjectWrapper(const WinRTNullPtrImplementation& interopParam);
+ WinRTScriptingObjectWrapper(const WinRTScriptingObjectWrapper& handleId);
+ ~WinRTScriptingObjectWrapper();
+
+ const WinRTScriptingObjectWrapper &operator = (const WinRTScriptingObjectWrapper &ptr);
+ WinRTScriptingObjectWrapper& operator=(decltype(__nullptr));
+ WinRTScriptingObjectWrapper& operator=(const WinRTNullPtrImplementation& nullptrimpl);
+ inline operator bool () const
+ {
+ return m_Handle != -1;
+ }
+ inline operator long long() const
+ {
+ return m_Handle;
+ }
+ int GetReferenceCount() const;
+
+ // Converters
+ bool ToBool();
+
+ inline long long GetHandle() const { return m_Handle;}
+ inline int GetBlockId() const {return m_BlockId; }
+ inline int GetHandleInBlock() const { return m_HandleInBlock; }
+
+ void Validate();
+
+ static void FreeHandles();
+ static void ClearCache();
+ static void ValidateCache();
+private:
+ friend bool operator == (const WinRTScriptingObjectWrapper& a, decltype(__nullptr));
+ friend bool operator != (const WinRTScriptingObjectWrapper& a, decltype(__nullptr));
+ friend bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b);
+ friend bool operator != (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b);
+ static int* GetPtrToReferences(int blockId);
+
+ void Init(long long handleId);
+ void InternalAddRef();
+ void InternalRelease();
+
+ long long m_Handle;
+ int m_BlockId;
+ int m_HandleInBlock;
+ int* m_PtrToReferences;
+
+ static const int kMaxCachedPtrToReferences = 4096;
+ static int* m_CachedPtrToReferences[kMaxCachedPtrToReferences];
+ static int m_CachedBlockCount;
+};
+
+bool operator == (const WinRTScriptingObjectWrapper& a, decltype(__nullptr));
+bool operator != (const WinRTScriptingObjectWrapper& a, decltype(__nullptr));
+bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b);
+bool operator != (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b);
+// Don't implement this, as same objects can have different handle ids, so currently there's no way of effectively comparing them
+//bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTScriptingObjectWrapper& b);
+
+struct ScriptingObject;
+struct ScriptingString;
+typedef Platform::Object ScriptingArray;
+//struct ScriptingArray;
+struct ScriptingType;
+typedef ScriptingType ScriptingClass;
+struct ScriptingException;
+
+typedef int BackendNativeMethod;
+typedef BridgeInterface::IScriptingClassWrapper^ BackendNativeType;
+
+struct ScriptingMethod;
+struct ScriptingField;
+struct MonoImage;
+
+//hack to not have to change everything in one go.
+struct MonoMethod;
+struct MonoObject;
+typedef ScriptingType MonoClass;
+#else
+struct ScriptingObject;
+struct ScriptingString;
+struct ScriptingException;
+struct ScriptingMethod;
+struct ScriptingField;
+struct ScriptingString;
+struct ScriptingClass;
+struct ScriptingType;
+struct ScriptingArray;
+struct ScriptingString;
+struct MonoMethod;
+struct MonoObject;
+struct MonoClass;
+typedef void* BackendNativeType;
+typedef void* BackendNativeMethod;
+#endif
+
+
+#if UNITY_WINRT && ENABLE_SCRIPTING
+typedef WinRTScriptingObjectWrapper ScriptingObjectPtr;
+typedef Platform::Object^ ScriptingStringPtr;
+typedef WinRTScriptingObjectWrapper ScriptingArrayPtr;
+typedef WinRTScriptingObjectWrapper ScriptingPinnedArrayPtr;
+typedef WinRTScriptingObjectWrapper const ScriptingArrayConstPtr;
+typedef WinRTScriptingObjectWrapper ScriptingPinnedArrayConstPtr;
+typedef ScriptingType* ScriptingTypePtr;
+typedef ScriptingClass* ScriptingClassPtr;
+typedef ScriptingException* ScriptingExceptionPtr;
+typedef ScriptingMethod* ScriptingMethodPtr;
+typedef ScriptingField* ScriptingFieldPtr;
+//typedef Platform::Array<Platform::Object^> ScriptingParams;
+//typedef ScriptingParams^ ScriptingParamsPtr;
+typedef long long ScriptingParams;
+typedef long long* ScriptingParamsPtr;
+#define ScriptingBool bool
+#define SCRIPTING_NULL WinRTNullPtrImplementation()
+#define ScriptingObjectComPtr(Type) Microsoft::WRL::ComPtr<IInspectable>
+#define ScriptingObjectToComPtr(Object) reinterpret_cast<IInspectable*>(Object)
+#define ScriptingComPtrToObject(Type, Object) reinterpret_cast<Type>((Object).Get())
+#else
+typedef ScriptingObject* ScriptingObjectPtr;
+typedef ScriptingString* ScriptingStringPtr;
+typedef ScriptingArray* ScriptingArrayPtr;
+typedef ScriptingType* ScriptingTypePtr;
+typedef ScriptingClass* ScriptingClassPtr;
+typedef ScriptingException* ScriptingExceptionPtr;
+typedef ScriptingMethod* ScriptingMethodPtr;
+typedef ScriptingField* ScriptingFieldPtr;
+typedef void* ScriptingParams;
+typedef ScriptingParams* ScriptingParamsPtr;
+#define ScriptingBool short
+#define SCRIPTING_NULL NULL
+#define ScriptingObjectComPtr(Type) Type
+#define ScriptingObjectToComPtr(Object) Object
+#define ScriptingComPtrToObject(Type, Object) Object
+#endif
+
+
+#endif
diff --git a/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp
new file mode 100644
index 0000000..c8c0122
--- /dev/null
+++ b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp
@@ -0,0 +1,35 @@
+#include "UnityPrefix.h"
+
+#if DEDICATED_UNIT_TEST_BUILD
+#include "Runtime/Scripting/Backend/ScriptingTypes.h"
+#include "Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h"
+#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h"
+#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h"
+
+bool scripting_method_is_instance(ScriptingMethodPtr method)
+{
+ return method->instance;
+}
+
+int scripting_method_get_argument_count(ScriptingMethodPtr method)
+{
+ return method->args;
+}
+
+ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr type, ScriptingTypeRegistry& typeRegistry)
+{
+ return type->baseType;
+}
+
+void scripting_class_get_methods(ScriptingTypePtr type, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result)
+{
+ result = type->methods;
+}
+
+ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr type, ScriptingTypeRegistry& typeRegistry)
+{
+ FakeSystemTypeInstance* sti = (FakeSystemTypeInstance*) type;
+ return typeRegistry.GetType(sti->nativeType);
+}
+
+#endif
diff --git a/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h
new file mode 100644
index 0000000..2ab7765
--- /dev/null
+++ b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h
@@ -0,0 +1,30 @@
+#ifndef _SCRIPTINGBACKENDAPI_TESTS_H_
+#define _SCRIPTINGBACKENDAPI_TESTS_H_
+
+#if DEDICATED_UNIT_TEST_BUILD
+#include "Runtime/Scripting/Backend/ScriptingTypes.h"
+#include <vector>
+
+struct ScriptingType
+{
+ ScriptingTypePtr baseType;
+ ScriptingType() : baseType(NULL) {}
+
+ std::vector<ScriptingMethodPtr> methods;
+};
+
+struct ScriptingMethod
+{
+ bool instance;
+ int args;
+
+ ScriptingMethod() : instance(false), args(0) {}
+};
+
+struct FakeSystemTypeInstance
+{
+ void* nativeType;
+};
+
+#endif
+#endif