Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

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:
    943
    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:
    943
    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:
    943
  7. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    943
    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:
    943
    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:
    263
    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.