Browse Source

DynamicInvokes are super slow, so I luckily found an alternative.

tags/Rel2b
sebas77 6 years ago
parent
commit
6b81c57d46
3 changed files with 43 additions and 17 deletions
  1. +6
    -5
      ECS/EntityDescriptor.cs
  2. +4
    -4
      ECS/EntityView.cs
  3. +33
    -8
      Utilities/FastInvoke.cs

+ 6
- 5
ECS/EntityDescriptor.cs View File

@@ -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<Type, Action<EntityView, object>>[] setters =
FasterList<KeyValuePair<Type, Action<EntityView, object>>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count);
KeyValuePair<Type, CastedAction<EntityView>>[] setters =
FasterList<KeyValuePair<Type, CastedAction<EntityView>>>.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);
}
}



+ 4
- 4
ECS/EntityView.cs View File

@@ -20,7 +20,7 @@ namespace Svelto.ECS
{
public int ID { get { return _ID; } }

internal FasterList<KeyValuePair<Type, Action<EntityView, object>>> entityViewBlazingFastReflection;
internal FasterList<KeyValuePair<Type, CastedAction<EntityView>>> entityViewBlazingFastReflection;
internal int _ID;
}

@@ -39,9 +39,9 @@ namespace Svelto.ECS
{
var field = fields[i];

Action<EntityView, object> setter = FastInvoke<T>.MakeSetter<EntityView>(field);
CastedAction<EntityView> setter = FastInvoke<T>.MakeSetter<EntityView>(field);
FieldCache<T>.list.Add(new KeyValuePair<Type, Action<EntityView, object>>(field.FieldType, setter));
FieldCache<T>.list.Add(new KeyValuePair<Type, CastedAction<EntityView>>(field.FieldType, setter));
}
}

@@ -50,7 +50,7 @@ namespace Svelto.ECS

static class FieldCache<W> where W:T
{
internal static readonly FasterList<KeyValuePair<Type, Action<EntityView, object>>> list = new FasterList<KeyValuePair<Type, Action<EntityView, object>>>();
internal static readonly FasterList<KeyValuePair<Type, CastedAction<EntityView>>> list = new FasterList<KeyValuePair<Type, CastedAction<EntityView>>>();
}
}
}


+ 33
- 8
Utilities/FastInvoke.cs View File

@@ -10,7 +10,7 @@ namespace Svelto.Utilities
public static class FastInvoke<T> where T : class
{
#if ENABLE_IL2CPP
public static Action<CastedType, object> MakeSetter<CastedType>(FieldInfo field)
public static Action<CastedType, object> MakeSetter<CastedType>(FieldInfo field) where CastedType:class
{
if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false)
{
@@ -20,7 +20,7 @@ namespace Svelto.Utilities
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
}
#elif !NETFX_CORE
public static Action<CastedType, object> MakeSetter<CastedType>(FieldInfo field)
public static CastedAction<CastedType> MakeSetter<CastedType>(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<CastedType, object>((target, value) => m.CreateDelegate(typeof(Action<T, object>)).DynamicInvoke(target, value));
var del = m.CreateDelegate(typeof(Action<T, object>));

return new CastedAction<CastedType, T>(del);
}

throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
}
#else
public static Action<CastedType, object> MakeSetter<CastedType>(FieldInfo field)
public static CastedAction<CastedType> MakeSetter<CastedType>(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<CastedType, object>((target, value) => setter.DynamicInvoke(target, value));
return new CastedAction<CastedType, T>(setter);
}

throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
}
#endif
}

public abstract class CastedAction<W>
{
abstract public void Call(W target, object value);
}

public class CastedAction<W, T> : CastedAction<W> where W : class where T:class
{
Action<T, object> setter;

public CastedAction(Delegate setter)
{
this.setter = (Action<T, object>)setter;
}

override public void Call(W target, object value)
{
setter(target as T, value);
}
}
}

Loading…
Cancel
Save