Skip to content

Instantly share code, notes, and snippets.

@xoofx
Created September 25, 2020 17:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xoofx/73d90a9f91d6bc01dff0a41c0c01730f to your computer and use it in GitHub Desktop.
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
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