Search Unity

Is using __makeref safe if I just plan to build for Windows and Mac?

Discussion in 'Entity Component System' started by davenirline, May 10, 2021.

  1. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    It is undocumented and has portability issues. I got it here. I wanted to use it for serialization using reflection. Didn't think it would be hard when dealing with value types.

    I would just use boxing if __makeref is just trouble. I've read that it's fast.
     
  2. ddalacu

    ddalacu

    Joined:
    May 13, 2014
    Posts:
    31
    If you want speed use UnsafeUtility.GetFieldOffset() and set the field value directly
     
    davenirline likes this.
  3. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    How do you exactly set the value? I assume that you convert the struct into a byte array then write the bytes to the index returned by UnsafeUtility.GetFieldOffset().
     
  4. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    I think you're supposed to use an unsafe context, get a pointer to the struct and then use the offset to get a pointer to your field.
     
  5. ddalacu

    ddalacu

    Joined:
    May 13, 2014
    Posts:
    31
    You you should pin the object, get it's address add the offset and read/write to it. I f you want to see how to pin managed objects/arrays check https://github.com/ddalacu/USerializer

    Code (CSharp):
    1.  var pinnable = Unsafe.As<object, PinnableObject>(ref obj);
    2.          
    3. fixed (byte* objectAddress = &pinnable.Pinnable)
    4. {
    5.  var fieldData = objectAddress+offset;//take offset from unsafeuttility
    6.  *(int*) fieldData = 112;
    7.  }
     
    davenirline likes this.
  6. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
  7. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    Sorry for being dumb. I don't see the implementation of Unsafe in USerializer. Where should I get it?

    Edit: So it's supposed to be in System.Runtime.CompilerServices but Unity is unable to see it.
    upload_2021-5-12_14-28-33.png
     
    Last edited: May 12, 2021
  8. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    I got it now after looking at other methods in UnsafeUtility:
    Code (CSharp):
    1. private struct Data {
    2.     public float floatValue;
    3.     public int intValue;
    4.     public bool boolValue;
    5. }
    6.  
    7. [Test]
    8. public unsafe void SetValueUsingUnsafeUtility() {
    9.     Type type = typeof(Data);
    10.     FieldInfo intField = type.GetField("intValue");
    11.     int fieldOffset = UnsafeUtility.GetFieldOffset(intField);
    12.    
    13.     Data data = new Data();
    14.     void* address = UnsafeUtility.AddressOf(ref data);
    15.     byte* addressAsByte = (byte*) address;
    16.     byte* intFieldAddress = addressAsByte + fieldOffset;
    17.     *(int*) intFieldAddress = 1;
    18.    
    19.     Debug.Log($"intValue: {data.intValue}");
    20.     Assert.IsTrue(data.intValue == 1);
    21. }
     
    ddalacu likes this.
  9. ddalacu

    ddalacu

    Joined:
    May 13, 2014
    Posts:
    31
    If you still want to get System.Runtime.CompilerServices.Unsafe in unity you can add the scoped registry found at https://github.com/xoofx/UnityNuGet and then use package manager to add it.
     
    davenirline likes this.
  10. apkdev

    apkdev

    Joined:
    Dec 12, 2015
    Posts:
    284
    I've always used the UnsafeUtility.PinGCObjectAndGetAddress API to get a pointer to a managed objects. You also get a handle that you then need to release using UnsafeUtility.ReleaseGCObject. Pretty sure that's the easiest way to do it, it's relatively fast* and it seems pretty reliable. It is used by ECS in a couple of places.

    upload_2021-5-12_18-38-58.png

    There's also the analogical PinGCObjectAndGetAddress and PinGCArrayAndGetDataAddress APIs.

    * Unity added a null check there around 2018.3 which probably slows things down. Would a throw helper method be preferable here? @Unity
     
  11. ddalacu

    ddalacu

    Joined:
    May 13, 2014
    Posts:
    31
    I think the fixed way is a bit faster in il2cpp because it only calls "get_address_of_" and with UnsafeUtillity you get the method calls associated with PinGCObjectAndGetAddress/ReleaseGCObject (but be aware that fixed method skipps the object header and UnsafeUtillity does not).
    I also have a question for unity, why do they use "PinGCObjectAndGetAddress/ReleaseGCObject" instead of "
    void* objectAddress;
    UnsafeUtility.CopyObjectAddressToPtr(target, &objectAddress);" if unity's boehm gc does not move objects in memory anyway?
     
    apkdev likes this.