Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Resolved Arrays shared between C# and jslib in WebGL - buffer undefined in 2023.3.0a6

Discussion in 'Unity 6 Beta' started by adamgolden, Sep 23, 2023.

  1. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    An issue encountered going from 2022->2023 and the solution that worked for me.

    Without doing this, the browser would crash due to buffer being undefined.

    In 2022 LTS and earlier when sharing a float[] between C# and jslib, we'd have a line in a jslib like this:
    Code (CSharp):
    1. .. = new Float32Array(buffer, byteOffset, length);
    Finally did get it working again by changing it like this (..tested in Windows 11 Chrome, Edge, Firefox):
    Code (CSharp):
    1. new Float32Array(myUnityInstanceReference.asm.memory.buffer, byteOffset, length);
    I'm guessing it's not broken due to something specific in my project because the code was working for ages prior to 2023.x. Happy to be proven wrong, but not interested in testing further because it's working now, enough time wasted already trying things until success with the above - but if anyone else runs into this, try same approach and good luck :)
     
  2. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    So it turns out the above workaround only works in Shorter Build Time builds (I also tested Disk Size, Runtime Speed and Runtime Speed with LTO). When I first posted, that was the kind I was testing with.. lucky break I guess (sort of)!

    I've created a repro and submitted a bug report. IN-55971

    Here's what the repro shows in Javascript console in 2022 LTS/earlier (Chrome, Windows 11):
    Result_in_2022.png

    And in 2023, the crash that happens instead:
    Result_in_2023.png

    The repro consists of the 3D URP template, plus a script and jslib, the above images, a text file with some info and a scene which has the following Example.cs on a GameObject:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Runtime.InteropServices;
    3. public class Example : MonoBehaviour
    4. {
    5.   [DllImport("__Internal")]
    6.   public static extern void JS_Example(float[] array, int length);
    7.  
    8.   float[] data = new float[] { 1, 2, 3 };
    9.   void Start()
    10.   {
    11. #if UNITY_EDITOR || !UNITY_WEBGL
    12.     Debug.Log("This example must be built and run in a web browser.");
    13. #else
    14.     Debug.Log("Values before jslib function: " + data[0].ToString() + ", " + data[1].ToString() + ", " + data[2].ToString());
    15.     JS_Example(data, 3);
    16.     Debug.Log("Values after jslib function: " + data[0].ToString() + ", " + data[1].ToString() + ", " + data[2].ToString());
    17. #endif
    18.   }
    19. }
    The Example.jslib:
    Code (JavaScript):
    1. mergeInto(LibraryManager.library, {
    2.  
    3.   JS_Example: function(byteOffset, length) {
    4.  
    5.     // in 2023.3.0a6, crashes due to buffer being undefined:
    6.  
    7.     var test = new Float32Array(buffer, byteOffset, length);
    8.  
    9.     test[0] = 3;
    10.     test[1] = 2;
    11.     test[2] = 1;
    12.  
    13.   }
    14.  
    15. });
    @jukka_j @unityruba

    Edit: Also in 2023.3.0a7
     
    Last edited: Sep 28, 2023
  3. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    Updated by email: "Your bug report ReferenceError is thrown when sharing an array between C# and JavaScript in WebGL has been confirmed and transferred to the appropriate internal development team at Unity."

    Thanks - hopefully it's easy to fix! :)
     
  4. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
  5. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    This breakage was caused by this PR: https://github.com/emscripten-core/emscripten/pull/18454, where Google developers of Emscripten removed the 'buffer' variable as unnecessary.

    Instead of referencing

    new Float32Array(myUnityInstanceReference.asm.memory.buffer, byteOffset, length);

    try referencing

    new Float32Array(wasmMemory.buffer, byteOffset, length);

    or

    new Float32Array(HEAP8.buffer, byteOffset, length);

    We are hesitant to fix this regression, because it would be akin to forking Emscripten for Unity's use (which we have tried not to do). Would the above fix work?
     
    adamgolden likes this.
  6. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    Thanks for looking into this, I'll test your recommendations today and post here again by this evening at the latest.
     
  7. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    Confirmed in 2023.3.0a11:

    WORKS: wasmMemory.buffer, Shorter Build Time
    WORKS: wasmMemory.buffer, Runtime Speed
    WORKS: wasmMemory.buffer, Runtime Speed with LTO
    WORKS: wasmMemory.buffer, Disk Size
    WORKS: wasmMemory.buffer, Disk Size with LTO

    WORKS: HEAP8.buffer, Shorter Build Time
    WORKS: HEAP8.buffer, Runtime Speed
    WORKS: HEAP8.buffer, Runtime Speed with LTO
    WORKS: HEAP8.buffer, Disk Size
    WORKS: HEAP8.buffer, Disk Size with LTO

    Lastly, tested quickly if using "buffer" by itself again still crashed the page (to confirm my jslib changes weren't ignored due to caching somehow throughout the above process), which it did.

    So.. looks like 100% good to go as-is, issue can be closed, I'm changing this to resolved and will post a link to this thread where this technique was mentioned and I learned it from, so anyone else following that will be aware of the change and hopefully won't report it again when they upgrade to 2023 - thanks again! :)
     
  8. Marks4

    Marks4

    Joined:
    Feb 25, 2018
    Posts:
    569
    Thanks for this bug report man!...Now I'm just wondering, is wasmMemory.buffer and HEAP8.buffer both functionality equivalent to the old buffer ? And if they are, more importantly, do they also work on older Unity versions? I guess it's just easier to replace buffer with wasmMemory.buffer or HEAP8.buffer if they work on all Unity versions.

    @jukka_j do these methods work on Unity 2019 and higher, and are they equivalent to just using buffer on Unity < 2023?
     
    adamgolden likes this.
  9. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    Also, @jukka_j based on the link below, I see there are 8 kinds of "views" into memory including HEAP8 - out of curiosity when I did the above tests I also tested a couple of different build types using HEAP32 and those worked as well. I'm just going to use wasmMemory personally, but for some additional clarity, is there any situation where we'd want to use HEAP8 instead, or where we'd want to use another of the types? I currently assume .buffer of wasmMemory and .buffer of all 8 types are effectively the same, but my confidence in that assumption isn't 100%
    https://emscripten.org/docs/api_reference/preamble.js.html#type-accessors-for-the-memory-model
     
    Marks4 likes this.
  10. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    "HEAP8.buffer" will work back to the dawn of time of Emscripten. "wasmMemory.buffer" might not work with older Emscripten/Unity versions, like 2018/2019 or so, but will work in all Unity versions starting from circa 2020.x forwards. (I don't exactly recall what was the version that wasmMemory was introduced)

    All of these "xxx.buffer" are exact aliases to each other, and all reference the same original global `buffer` variable. So whether you use HEAP8.buffer or HEAP32.buffer does not matter.

    (however naturally using the appropriate views is important, so HEAP8 when you have a signed 8-bit access, and HEAPU32 when you have an unsigned 32-bit access, etc)
     
    mariandev, adamgolden and Marks4 like this.
  11. Marks4

    Marks4

    Joined:
    Feb 25, 2018
    Posts:
    569
    @jukka_j @adamgolden It seems that Module._malloc is also now undefined. What's the alternative? This is a huge deal malloc doesn't work anymore T_T.

    EDIT

    @jukka_j Maybe it's a bug and I need to report it? Or is it a part of the Emscripten update?
     
    Last edited: Jan 17, 2024
  12. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,558
    I have several WebGL game builds that use _malloc in jslibs (without the Module. before it). My latest are using 2023.3.0a16, but I haven't experienced any issues with previous versions either.
     
    Marks4 likes this.
  13. Marks4

    Marks4

    Joined:
    Feb 25, 2018
    Posts:
    569
    Try with Unity 2023.2.0f1. It doesn't work. Or maybe it's the Module. that doesn't work anymore and only _malloc without Module. works. I have to try it as well.

    EDIT

    So...the issue was the preceding Module. On Unity 2023 and later, just _malloc can be used. Thanks @adamgolden.

    Also worth noting... if you have the web assembly table enabled



    all the regular dyncalls will stop working with an error saying they are undefined...this means that you can't mix webgl plugins using the old dyncall system with the new system.

    Which is very bad and makes the new system basically useless, because I can't make a plugin that will be incompatible with every other webgl plugin on the store.
     
    Last edited: Jan 17, 2024
    Thaina likes this.