diff options
Diffstat (limited to 'Runtime/Scripting/Backend')
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 |