Created
September 25, 2020 17:32
-
-
Save xoofx/73d90a9f91d6bc01dff0a41c0c01730f to your computer and use it in GitHub Desktop.
Use calli to delay call to Update methods on a bunch of objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Reflection; | |
using InlineIL; | |
namespace DirectCallApp | |
{ | |
// With the following csproj | |
// <Project Sdk="Microsoft.NET.Sdk"> | |
// | |
// <PropertyGroup> | |
// <OutputType>Exe</OutputType> | |
// <TargetFrameworks>net471;netcoreapp3.1</TargetFrameworks> | |
// <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
// </PropertyGroup> | |
// | |
// <ItemGroup> | |
// <PackageReference Include="Fody" Version="6.2.6"> | |
// <PrivateAssets>all</PrivateAssets> | |
// <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |
// </PackageReference> | |
// <PackageReference Include="InlineIL.Fody" Version="1.5.0"> | |
// <PrivateAssets>all</PrivateAssets> | |
// </PackageReference> | |
// </ItemGroup> | |
// | |
// </Project> | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("Instantiating"); | |
var objects = new ObjectBase[10000]; | |
for (int i = 0; i < objects.Length; i++) | |
{ | |
objects[i] = (i & 1) == 0 ? (ObjectBase) new MyObject1() : new MyObject2(); | |
} | |
Console.WriteLine("Updating"); | |
var clock = Stopwatch.StartNew(); | |
for (int i = 0; i < 10000; i++) | |
{ | |
Updater(objects); | |
} | |
Console.WriteLine($"Elapsed: {clock.Elapsed.TotalMilliseconds} Counter: {ObjectBase.Counter}"); | |
} | |
static void Updater(ObjectBase[] objects) | |
{ | |
foreach (var obj in objects) | |
{ | |
IL.Push(obj); | |
IL.Push(obj.UpdatePointer); | |
IL.Emit.Calli(new StandAloneMethodSig(CallingConventions.HasThis, TypeRef.Type(typeof(void)))); | |
} | |
} | |
} | |
public abstract class ObjectBase | |
{ | |
protected ObjectBase(IntPtr updatePointer) | |
{ | |
UpdatePointer = updatePointer; | |
} | |
public readonly IntPtr UpdatePointer; | |
public static int Counter = 0; | |
} | |
public class MyObject1 : ObjectBase | |
{ | |
void Update() | |
{ | |
Counter++; | |
} | |
private static readonly IntPtr CacheThisUpdatePointer = ThisUpdatePointer(); | |
private static IntPtr ThisUpdatePointer() | |
{ | |
IL.Emit.Ldftn(new MethodRef(new TypeRef(typeof(MyObject1)), "Update")); | |
return IL.Return<IntPtr>(); | |
} | |
public MyObject1() : base(CacheThisUpdatePointer) | |
{ | |
} | |
} | |
public class MyObject2 : ObjectBase | |
{ | |
public MyObject2() : base(CacheThisUpdatePointer) | |
{ | |
} | |
private void Update() | |
{ | |
Counter++; | |
} | |
private static readonly IntPtr CacheThisUpdatePointer = ThisUpdatePointer(); | |
private static IntPtr ThisUpdatePointer() | |
{ | |
IL.Emit.Ldftn(new MethodRef(new TypeRef(typeof(MyObject2)), "Update")); | |
return IL.Return<IntPtr>(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment