<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>Note that in practice JNI also doesn't really allow you to pass
      objects to native code, what it actually passes is object handles.
      Semantically this is just a token that can be turned into an
      object again by the JNI runtime later.</p>
    <p>Something similar can be achieved with a simple object store [1]<br>
    </p>
    <p>    static final ObjectStore STORE = new ObjectStore();<br>
      <br>
      ...<br>
      <br>
          Object objectToPass = ...;<br>
          int token = STORE.allocate(objectToPass);<br>
          // pass  'token' to native code<br>
      <br>
      ... later:<br>
      <br>
          int token = ...; // from native code<br>
          Object obj = STORE.resolve(token); // turn back into object<br>
      <br>
      ... when done:<br>
      <br>
          STORE.free(token);<br>
    </p>
    <p>Of course this is a simple example, but this is the basic
      principle: store your object in some store, and have a
      handle/token that you pass to native code instead.<br>
    </p>
    <p>HTH,<br>
      Jorn<br>
      <br>
      [1] :<br>
      <br>
      Simple example of an object store:<br>
    </p>
    <pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:10.5pt;"><span style="color:#0033b3;">public class </span><span style="color:#000000;">ObjectStore </span>{
    
    <span style="color:#0033b3;">private final </span><span style="color:#000000;">Deque</span><<span style="color:#000000;">Node</span>> <span style="color:#871094;">freeList </span>= <span style="color:#0033b3;">new </span>ArrayDeque<>();
    <span style="color:#0033b3;">private final </span><span style="color:#000000;">List</span><<span style="color:#000000;">Node</span>> <span style="color:#871094;">store </span>= <span style="color:#0033b3;">new </span>ArrayList<>();
    
    <span style="color:#0033b3;">public int </span><span style="color:#00627a;">allocate</span>(<span style="color:#000000;">Object </span>obj) {
        <span style="color:#0033b3;">if </span>(!<span style="color:#871094;">freeList</span>.isEmpty()) {
            <span style="color:#000000;">Node n </span>= <span style="color:#871094;">freeList</span>.pop();
            <span style="color:#000000;">n</span>.<span style="color:#871094;">obj </span>= obj;
            <span style="color:#0033b3;">return </span><span style="color:#000000;">n</span>.<span style="color:#871094;">index</span>;
        }
        
        <span style="color:#0033b3;">int </span><span style="color:#000000;">index </span>= <span style="color:#871094;">store</span>.size();
        <span style="color:#871094;">store</span>.add(<span style="color:#0033b3;">new </span>Node(<span style="color:#000000;">index</span>, obj));
        <span style="color:#0033b3;">return </span><span style="color:#000000;">index</span>;
    }
    
    <span style="color:#0033b3;">public </span><span style="color:#000000;">Object </span><span style="color:#00627a;">resolve</span>(<span style="color:#0033b3;">int </span>token) {
        <span style="color:#0033b3;">return </span><span style="color:#871094;">store</span>.get(token).<span style="color:#871094;">obj</span>;
    }
    
    <span style="color:#0033b3;">public void </span><span style="color:#00627a;">free</span>(<span style="color:#0033b3;">int </span>token) {
        <span style="color:#000000;">Node n </span>= <span style="color:#871094;">store</span>.get(token);
        <span style="color:#000000;">n</span>.<span style="color:#871094;">obj </span>= <span style="color:#0033b3;">null</span>;
        <span style="color:#871094;">freeList</span>.push(<span style="color:#000000;">n</span>);
    }
    
    <span style="color:#0033b3;">private static class </span><span style="color:#000000;">Node </span>{
        <span style="color:#0033b3;">final int </span><span style="color:#871094;">index</span>;
        <span style="color:#000000;">Object </span><span style="color:#871094;">obj</span>;

        <span style="color:#0033b3;">public </span><span style="color:#00627a;">Node</span>(<span style="color:#0033b3;">int </span>index, <span style="color:#000000;">Object </span>obj) {
            <span style="color:#0033b3;">this</span>.<span style="color:#871094;">index </span>= index;
            <span style="color:#0033b3;">this</span>.<span style="color:#871094;">obj </span>= obj;
        }
    }
}</pre>
    <div class="moz-cite-prefix">On 02/12/2022 18:02, Maurizio
      Cimadamore wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:bd44b8c8-6106-a0b9-e790-6f4fd0622db6@oracle.com">
      <br>
      On 02/12/2022 16:44, Gregory Klyushnikov wrote:
      <br>
      <blockquote type="cite">But since you say the decision to not
        allow native Java object handles was intentional, I'll try it.
        <br>
      </blockquote>
      <br>
      Some background: if we start allowing Java instances being passed
      to native function, then we have to start worrying about the same
      class "spoofing" issues that JNI suffers from.
      <br>
      <br>
      That is, you can crete an handle for Foo in one class loader, then
      the handle is stored by the native code, and passed again to Java
      code in _another_ class loader, thus violating classloader
      constraints (maybe the class definition for Foo in that second
      class loader is different).
      <br>
      <br>
      For these reasons, JNI restricted library loading to a _single_
      class loader. This restriction solves the spoofing issues, but
      comes at a price: any attempt to load same library from two
      loaders will fail. Frameworks have in the past resorted to various
      "tricks" (such as renaming libraries) to workaround this
      limitation.
      <br>
      <br>
      Since Panama doesn't allow passing Java objects _directly_ to
      native functions (you can pass memory segments, but they are
      either passed by reference - a long - or deconstructed into
      multiple primitive values which are then passed separately), it is
      not subject to same library loading limitations. That is, if you
      load a library with SymbolLookup::libraryLookup you can load it as
      many times as you like, from _any_ classloader you like. Which is
      nice to have.
      <br>
      <br>
      Of course I understand where you are coming from with this use
      case: you want to store an object pointer in the native code. We
      have considered APIs to allow developers to do that (e.g.
      temporarily turn a Java object into a native memory segment,
      controlled by a given memory session). But, as shown above, there
      are some safety consideration when going down that path.
      <br>
      <br>
      Now, in some cases, but not all, you can achieve a similar effect
      with the new scoped value feature:
      <br>
      <br>
      <a class="moz-txt-link-freetext" href="https://openjdk.org/jeps/429">https://openjdk.org/jeps/429</a>
      <br>
      <br>
      E.g. you could "bind" a ScopedValue object before the native call
      takes place, so that the receiver class is set to some known
      instance. The method handle you upcall to would read the
      ScopedValue, fetch the receiver instance, and dispatch to that.
      <br>
      <br>
      This would be more efficient than using a Map (as ScopedValues
      have caches) - but your usage has to be "structured" for
      ScopedValue to be usable.
      <br>
      <br>
      Anyway, I thought I'd mention the connection, in case it's useful
      (if not for this use case, for others).
      <br>
      <br>
      Cheers
      <br>
      Maurizio
      <br>
      <br>
      <br>
      <br>
    </blockquote>
  </body>
</html>