From 3f3d8fc4942d6625714ce8ad323244342feaed74 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Fri, 19 Nov 2021 16:03:55 +0100 Subject: [PATCH] Add more improvements to Variant and conversions with managed data --- Source/Engine/Core/Types/Variant.cpp | 10 + Source/Engine/Scripting/ManagedCLR/MUtils.cpp | 192 +++++++++--------- 2 files changed, 110 insertions(+), 92 deletions(-) diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 2246a7158..7dacc69f8 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -502,6 +502,16 @@ Variant::Variant(decltype(nullptr)) { } +Variant::Variant(const VariantType& type) + : Type(type) +{ +} + +Variant::Variant(VariantType&& type) + : Type(MoveTemp(type)) +{ +} + Variant::Variant(bool v) : Type(VariantType::Bool) { diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp index 158e20bd1..4b5a3d82d 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp @@ -159,11 +159,9 @@ VariantType MUtils::UnboxVariantType(MonoType* monoType) case MONO_TYPE_BOOLEAN: return VariantType(VariantType::Bool); case MONO_TYPE_I1: - return VariantType(VariantType::Int16); - case MONO_TYPE_U1: - return VariantType(VariantType::Int16); case MONO_TYPE_I2: return VariantType(VariantType::Int16); + case MONO_TYPE_U1: case MONO_TYPE_U2: return VariantType(VariantType::Uint16); case MONO_TYPE_I4: @@ -186,8 +184,6 @@ VariantType MUtils::UnboxVariantType(MonoType* monoType) case MONO_TYPE_VALUETYPE: if (klass == stdTypes.GuidClass->GetNative()) return VariantType(VariantType::Guid); - if (klass == stdTypes.TypeClass->GetNative()) - return VariantType(VariantType::Typename); if (klass == stdTypes.Vector2Class->GetNative()) return VariantType(VariantType::Vector2); if (klass == stdTypes.Vector3Class->GetNative()) @@ -232,6 +228,8 @@ VariantType MUtils::UnboxVariantType(MonoType* monoType) case MONO_TYPE_VALUETYPE: return VariantType(VariantType::Structure, fullname); } + if (klass == stdTypes.TypeClass->GetNative()) + return VariantType(VariantType::Typename); if (mono_class_is_subclass_of(klass, Asset::GetStaticClass()->GetNative(), false) != 0) { if (klass == Asset::GetStaticClass()->GetNative()) @@ -268,101 +266,77 @@ Variant MUtils::UnboxVariant(MonoObject* value) { if (value == nullptr) return Variant::Null; - const auto& stdTypes = *StdTypesContainer::Instance(); const auto klass = mono_object_get_class(value); + void* unboxed = (byte*)value + sizeof(MonoObject); + const MonoType* monoType = mono_class_get_type(klass); - if (klass == mono_get_boolean_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_byte_class()) - return (int16)*static_cast(mono_object_unbox(value)); - if (klass == mono_get_sbyte_class()) - return (int16)*static_cast(mono_object_unbox(value)); - if (klass == mono_get_int16_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_uint16_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_int32_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_uint32_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_int64_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_uint64_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_char_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_single_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_double_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.GuidClass->GetNative()) - return Variant(*static_cast(mono_object_unbox(value))); - if (klass == stdTypes.Vector2Class->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.Vector3Class->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.Vector4Class->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.ColorClass->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_string_class()) + // Fast type detection for in-built types + switch (monoType->type) + { + case MONO_TYPE_VOID: + return Variant(VariantType(VariantType::Void)); + case MONO_TYPE_BOOLEAN: + return *static_cast(unboxed); + case MONO_TYPE_I1: + return *static_cast(unboxed); + case MONO_TYPE_U1: + return *static_cast(unboxed); + case MONO_TYPE_I2: + return *static_cast(unboxed); + case MONO_TYPE_U2: + return *static_cast(unboxed); + case MONO_TYPE_CHAR: + return *static_cast(unboxed); + case MONO_TYPE_I4: + return *static_cast(unboxed); + case MONO_TYPE_U4: + return *static_cast(unboxed); + case MONO_TYPE_I8: + return *static_cast(unboxed); + case MONO_TYPE_U8: + return *static_cast(unboxed); + case MONO_TYPE_R4: + return *static_cast(unboxed); + case MONO_TYPE_R8: + return *static_cast(unboxed); + case MONO_TYPE_STRING: return Variant(MUtils::ToString((MonoString*)value)); - if (klass == stdTypes.BoundingBoxClass->GetNative()) - return Variant(*static_cast(mono_object_unbox(value))); - if (klass == stdTypes.QuaternionClass->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.TransformClass->GetNative()) - return Variant(*static_cast(mono_object_unbox(value))); - if (klass == stdTypes.BoundingSphereClass->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.RectangleClass->GetNative()) - return *static_cast(mono_object_unbox(value)); - if (klass == mono_get_intptr_class() || klass == mono_get_uintptr_class()) - return *static_cast(mono_object_unbox(value)); - if (klass == stdTypes.MatrixClass->GetNative()) - return Variant(*reinterpret_cast(mono_object_unbox(value))); - if (mono_class_is_subclass_of(klass, Asset::GetStaticClass()->GetNative(), false) != 0) - return static_cast(ScriptingObject::ToNative(value)); - if (mono_class_is_subclass_of(klass, ScriptingObject::GetStaticClass()->GetNative(), false) != 0) - return ScriptingObject::ToNative(value); - if (mono_class_is_enum(klass)) + case MONO_TYPE_PTR: + return *static_cast(unboxed); + case MONO_TYPE_VALUETYPE: + if (klass == stdTypes.GuidClass->GetNative()) + return Variant(*static_cast(unboxed)); + if (klass == stdTypes.Vector2Class->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.Vector3Class->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.Vector4Class->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.ColorClass->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.BoundingBoxClass->GetNative()) + return Variant(*static_cast(unboxed)); + if (klass == stdTypes.QuaternionClass->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.TransformClass->GetNative()) + return Variant(*static_cast(unboxed)); + if (klass == stdTypes.BoundingSphereClass->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.RectangleClass->GetNative()) + return *static_cast(unboxed); + if (klass == stdTypes.MatrixClass->GetNative()) + return Variant(*reinterpret_cast(unboxed)); + break; + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: { - MString fullname; - GetClassFullname(klass, fullname); - Variant v; - v.Type = MoveTemp(VariantType(VariantType::Enum, fullname)); - // TODO: what about 64-bit enum? use enum size with memcpy - v.AsUint64 = *static_cast(mono_object_unbox(value)); - return v; - } - if (mono_class_is_valuetype(klass)) - { - MString fullname; - GetClassFullname(klass, fullname); - const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(fullname); - if (typeHandle) + if (klass == mono_array_class_get(mono_get_byte_class(), 1)) { - const ScriptingType& type = typeHandle.GetType(); Variant v; - v.Type = MoveTemp(VariantType(VariantType::Structure, fullname)); - v.AsBlob.Data = Allocator::Allocate(type.Size); - v.AsBlob.Length = type.Size; - type.Struct.Ctor(v.AsBlob.Data); - type.Struct.Unbox(v.AsBlob.Data, value); + v.SetBlob(mono_array_addr((MonoArray*)value, byte, 0), (int32)mono_array_length((MonoArray*)value)); return v; } - return Variant(value); - } - if (klass == mono_array_class_get(mono_get_byte_class(), 1)) - { - Variant v; - v.SetBlob(mono_array_addr((MonoArray*)value, byte, 0), (int32)mono_array_length((MonoArray*)value)); - return v; - } - MonoType* monoType = mono_class_get_type(klass); - if (monoType->type == MONO_TYPE_SZARRAY || monoType->type == MONO_TYPE_ARRAY) - { MString fullname; GetClassFullname(klass, fullname); Variant v; @@ -370,7 +344,7 @@ Variant MUtils::UnboxVariant(MonoObject* value) auto& array = v.AsArray(); array.Resize((int32)mono_array_length((MonoArray*)value)); const StringAnsiView elementTypename(*fullname, fullname.Length() - 2); - MonoClass* elementClass = monoType->data.array->eklass; + MonoClass* elementClass = mono_class_get_element_class(klass); uint32_t elementAlign; const int32 elementSize = mono_class_value_size(elementClass, &elementAlign); if (mono_class_is_enum(elementClass)) @@ -465,6 +439,40 @@ Variant MUtils::UnboxVariant(MonoObject* value) } return v; } + } + + if (mono_class_is_subclass_of(klass, Asset::GetStaticClass()->GetNative(), false) != 0) + return static_cast(ScriptingObject::ToNative(value)); + if (mono_class_is_subclass_of(klass, ScriptingObject::GetStaticClass()->GetNative(), false) != 0) + return ScriptingObject::ToNative(value); + if (mono_class_is_enum(klass)) + { + MString fullname; + GetClassFullname(klass, fullname); + Variant v; + v.Type = MoveTemp(VariantType(VariantType::Enum, fullname)); + // TODO: what about 64-bit enum? use enum size with memcpy + v.AsUint64 = *static_cast(mono_object_unbox(value)); + return v; + } + if (mono_class_is_valuetype(klass)) + { + MString fullname; + GetClassFullname(klass, fullname); + const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(fullname); + if (typeHandle) + { + const ScriptingType& type = typeHandle.GetType(); + Variant v; + v.Type = MoveTemp(VariantType(VariantType::Structure, fullname)); + v.AsBlob.Data = Allocator::Allocate(type.Size); + v.AsBlob.Length = type.Size; + type.Struct.Ctor(v.AsBlob.Data); + type.Struct.Unbox(v.AsBlob.Data, value); + return v; + } + return Variant(value); + } // TODO: support any dictionary unboxing return Variant(value);