Skip to content

Instantly share code, notes, and snippets.

@kornman00
Created April 14, 2016 21:14

Revisions

  1. kornman00 created this gist Apr 14, 2016.
    11 changes: 11 additions & 0 deletions After.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    // #NOTE: be mindful of how large T actually is and whether or not your runtime does or doesn't
    // optimize passing large structs by reference instead of copying bits to other parts of the stack
    public static T Read<T>(this BinaryReader reader, T item = default(T))
    where T : IStreamSerializable, new()
    {
    if (item == null) // value types are never null, so this helps us avoid heap allocations
    item = new T();

    item.Load(reader);
    return item;
    }
    42 changes: 42 additions & 0 deletions After.il
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    .method public hidebysig static
    !!T Read<.ctor (IStreamSerializable) T> (
    class [mscorlib]System.IO.BinaryReader reader,
    [opt] !!T item
    ) cil managed
    {
    .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
    01 00 00 00
    )
    // Method begins at RVA 0x1d9f0
    // Code size 64 (0x40)
    .maxstack 5
    .locals init (
    [0] !!T
    )

    IL_0000: ldarg.1
    IL_0001: box !!T
    IL_0006: brtrue IL_0030

    IL_000b: ldloca.s 0
    IL_000d: initobj !!T
    IL_0013: ldloc.0
    IL_0014: box !!T
    IL_0019: brfalse IL_0029

    IL_001e: ldloca.s 0
    IL_0020: initobj !!T
    IL_0026: ldloc.0
    IL_0027: br.s IL_002e

    IL_0029: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()

    IL_002e: starg.s item

    IL_0030: ldarga.s item
    IL_0032: ldarg.0
    IL_0033: constrained. !!T
    IL_0039: callvirt instance void IStreamSerializable::Load(class [mscorlib]System.IO.BinaryReader)
    IL_003e: ldarg.1
    IL_003f: ret
    } // end of method SerializationExtensions::Read
    9 changes: 9 additions & 0 deletions After.il.decompiled.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    public static T Read<T>(this BinaryReader reader, T item = null) where T : IStreamSerializable, new()
    {
    if (item == null)
    {
    item = ((default(T) == null) ? Activator.CreateInstance<T>() : default(T));
    }
    item.Load(reader);
    return item;
    }
    7 changes: 7 additions & 0 deletions Before.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    public static T Read<T>(this BinaryReader reader)
    where T : IStreamSerializable, new()
    {
    T item = new T(); // when T is a value type, this causes a heap allocation in Unity!
    item.Load(reader);
    return item;
    }
    17 changes: 17 additions & 0 deletions BeforeExcerptFromProfilerReport.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    **** Type: MY_STRUCT // names have been changed to protect the innocent
    Unique backtraces 22
    Avg Alloc 238.500000
    Avg Free 2.000000
    Avg Garbage 0.838574
    Frame Count 2
    Allocs 477
    Frees 4
    Skipped Alloc 0
    Skipped Free 0
    91 (%19.077568) // number of allocations from this specific backtrace
    Sample address 000000002620D0F0
    (wrapper managed-to-native) object:__icall_wrapper_mono_object_new_specific
    (wrapper managed-to-native) object:__icall_wrapper_mono_object_new_specific
    SerializationExtensions:Read<MY_STRUCT> C:\[REDACTED]\Serialization.cs(330)
    [REDACTED...]
    (wrapper runtime-invoke) object:runtime_invoke_void__this__