From 6b81c57d46bd41d4cc40c443527c73645a5244da Mon Sep 17 00:00:00 2001 From: sebas77 Date: Wed, 27 Dec 2017 12:13:19 +0000 Subject: [PATCH] DynamicInvokes are super slow, so I luckily found an alternative. --- ECS/EntityDescriptor.cs | 11 ++++++----- ECS/EntityView.cs | 8 ++++---- Utilities/FastInvoke.cs | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 880c2c2..9b2de27 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -1,5 +1,6 @@ using Svelto.DataStructures; using Svelto.ECS.Internal; +using Svelto.Utilities; using System; using System.Collections.Generic; @@ -160,8 +161,8 @@ namespace Svelto.ECS.Internal int count; //Very efficent way to collect the fields of every EntityViewType - KeyValuePair>[] setters = - FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); + KeyValuePair>[] setters = + FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); var removeEntityComponentType = typeof(IRemoveEntityComponent); @@ -193,14 +194,14 @@ namespace Svelto.ECS.Internal entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); #endif #if DEBUG && !PROFILER - keyValuePair.Value(entityView, component.item1); + keyValuePair.Value.Call(entityView, component.item1); #else - keyValuePair.Value(entityView, component); + keyValuePair.Value.Call(entityView, component); #endif } else { - keyValuePair.Value(entityView, removeEntity); + keyValuePair.Value.Call(entityView, removeEntity); } } diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs index 8add72c..4846935 100644 --- a/ECS/EntityView.cs +++ b/ECS/EntityView.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS { public int ID { get { return _ID; } } - internal FasterList>> entityViewBlazingFastReflection; + internal FasterList>> entityViewBlazingFastReflection; internal int _ID; } @@ -39,9 +39,9 @@ namespace Svelto.ECS { var field = fields[i]; - Action setter = FastInvoke.MakeSetter(field); + CastedAction setter = FastInvoke.MakeSetter(field); - FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); } } @@ -50,7 +50,7 @@ namespace Svelto.ECS static class FieldCache where W:T { - internal static readonly FasterList>> list = new FasterList>>(); + internal static readonly FasterList>> list = new FasterList>>(); } } } diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs index b9a1aab..8cd208c 100644 --- a/Utilities/FastInvoke.cs +++ b/Utilities/FastInvoke.cs @@ -10,7 +10,7 @@ namespace Svelto.Utilities public static class FastInvoke where T : class { #if ENABLE_IL2CPP - public static Action MakeSetter(FieldInfo field) + public static Action MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) { @@ -20,7 +20,7 @@ namespace Svelto.Utilities throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #elif !NETFX_CORE - public static Action MakeSetter(FieldInfo field) + public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { @@ -33,29 +33,54 @@ namespace Svelto.Utilities cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); - return new Action((target, value) => m.CreateDelegate(typeof(Action)).DynamicInvoke(target, value)); + var del = m.CreateDelegate(typeof(Action)); + + return new CastedAction(del); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #else - public static Action MakeSetter(FieldInfo field) + public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); - ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value"); + ParameterExpression valueExp = Expression.Parameter(typeof(object), "value"); MemberExpression fieldExp = Expression.Field(targetExp, field); - BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp); + UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType); + BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp); + + Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) }); - var setter = Expression.Lambda(assignExp, targetExp, valueExp).Compile(); + var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile(); - return new Action((target, value) => setter.DynamicInvoke(target, value)); + return new CastedAction(setter); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #endif } + + public abstract class CastedAction + { + abstract public void Call(W target, object value); + } + + public class CastedAction : CastedAction where W : class where T:class + { + Action setter; + + public CastedAction(Delegate setter) + { + this.setter = (Action)setter; + } + + override public void Call(W target, object value) + { + setter(target as T, value); + } + } } \ No newline at end of file