Skip to content

Add ability to Share Native Object Instances between Main and Worker Runtimes #37

Open

Description

@ammarahm-ed

Both Worker and Main JS runtime instances use the same Java environment hence the native objects can be shared between the two.
Main:

const nativeObject = new java.lang.String("string");
const worker = new Worker(...);
worker.postMessage({
  myNativeString: globalThis.createNativeHandle(nativeObject)
});

Worker:

globalThis.onmessage = (message) => {
  const nativeObject = globalThis.resolveNativeHandle(message.myNativeString);
}

Activity

  1. edusperoni commented on Nov 29, 2025

    @edusperoni
    Collaborator

    Probably doesn't even need the global functions. At least on V8 you can just implement the method that deals with serialization/deserialization and check if it's a custom object or not

  2. ammarahm-ed commented on Nov 30, 2025

    @ammarahm-ed
    CollaboratorAuthor

    @edusperoni For napi runtimes we need something that will work across the board on all js engines. Also sharing native objects should be explicit instead of passing an object that may or may not contain a reference to some native object.

  3. edusperoni commented on Nov 30, 2025

    @edusperoni
    Collaborator

    I don't think that's how it works on the web though. Main example being ArrayBuffer vs SharedArrayBuffer. Those can be sent as messages to workers, but one is copied and the other is shared, you don't need to explicitly say which is copied and which isn't.

    See https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer

  4. ammarahm-ed commented on Nov 30, 2025

    @ammarahm-ed
    CollaboratorAuthor

    We cannot use or follow Transferrable Objects API since it's meant to transfer the ownership of the underlying data, in our case we are simply copying reference to a native object.

    This looks good:

    const sab = new SharedArrayBuffer(1024);
    worker.postMessage(sab);

    But it will require doing a deep check on any object passed into postMessage which will slow down sending data to workers even when you are not passing any native object. For example:

    worker.postMessage({
      a: { b: { c: { nativeObject: {...} }} }
    });

    It may also result in accidentally sharing references to the worker that you may not need at all.

    It can work if it's just limited to this:

    worker.postMessage(nativeObject);
  5. ammarahm-ed commented on Nov 30, 2025

    @ammarahm-ed
    CollaboratorAuthor

    I also wanted to ask what happens if someone shares a native class extended on the main runtime to worker runtime or we won't be supporting those?

    const listener =  new android.view.View.OnClickListener("AppClickListener", {
            onClick: function () {
              button.setBackgroundColor(colors[taps % colors.length]);
              taps++;
            },
          });
    
    worker.postMessage(listener);

    What will happen in this case? @edusperoni

  6. edusperoni commented on Nov 30, 2025

    @edusperoni
    Collaborator

    I see this as 2 possible options:

    1. Hard limitation since you can't pass a JS object
    2. You only get implemented native methods (you receive the native class with no access to JS parts). Of course, any calls to JS implemented methods would lock the other isolate

    I'm not sure which would be best, as both seem bad haha

  7. ammarahm-ed commented on Nov 30, 2025

    @ammarahm-ed
    CollaboratorAuthor

    I think once we implement basic object sharing we can figure out rest of the cases and fine tune the API. Currently in NAPI runtime extended classes are bound to invoke callbacks into the runtime. The JS Part can't be transferred obviously. Only the native part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions