<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    Mark,<br>
    <br>
    yes, I needed that persistence for the HTTP and VFS classes, but I
    also needed to be able to couple a dynamic C++ instance with a JS
    object and have a mechanism to prevent garbage collection while the
    C++ side is still in use. If the C++ side is no longer needed, the
    JS finalizer also needs to imply the C++ instance can be deleted.<br>
    <br>
    That is all implemented by DuktapeObject. DuktapeObject also
    provides JS method invocation on the coupled JS object and a mutex
    for concurrency protection.<br>
    <br>
    We probably need some more framework documentation than the header
    comments (applies to all of our framework classes…):<br>
    <br>
    <tt>/***************************************************************************************************</tt><tt><br>
    </tt><tt> * DuktapeObject: coupled C++ / JS object</tt><tt><br>
    </tt><tt> * </tt><tt><br>
    </tt><tt> *  Intended for API methods to attach internal API state
      to a JS object and provide</tt><tt><br>
    </tt><tt> *    a standard callback invocation interface for JS
      objects in local scopes.</tt><tt><br>
    </tt><tt> *  </tt><tt><br>
    </tt><tt> *  - Override CallMethod() to implement specific method
      calls</tt><tt><br>
    </tt><tt> *  - Override Finalize() for specific destruction in JS
      context (garbage collection)</tt><tt><br>
    </tt><tt> *  - call Register() to prevent normal garbage collection
      (but not heap destruction)</tt><tt><br>
    </tt><tt> *  - call Ref() to protect against deletion (reference
      count)</tt><tt><br>
    </tt><tt> *  - call Lock() to protect concurrent access (recursive
      mutex)</tt><tt><br>
    </tt><tt> *  </tt><tt><br>
    </tt><tt> *  - GetInstance() retrieves the DuktapeObject associated
      with a JS object if any</tt><tt><br>
    </tt><tt> *  - Push() pushes the JS object onto the Duktape stack</tt><tt><br>
    </tt><tt> *  </tt><tt><br>
    </tt><tt> *  Note: the DuktapeObject may persist after the JS object
      has been finalized, e.g.</tt><tt><br>
    </tt><tt> *    if some callbacks are pending after the Duktape heap
      has been destroyed.</tt><tt><br>
    </tt><tt> *    Use IsCoupled() to check if the JS object is still
      available.</tt><tt><br>
    </tt><tt> *  </tt><tt><br>
    </tt><tt> *  Ref/Unref:</tt><tt><br>
    </tt><tt> *    Normal life cycle is from construction to
      finalization. Pending callbacks extend</tt><tt><br>
    </tt><tt> *    the life until the last callback has been processed.
      A subclass may extend the life</tt><tt><br>
    </tt><tt> *    by calling Ref(), which increases the reference
      count. Unref() deletes the instance</tt><tt><br>
    </tt><tt> *    if no references are left.</tt><tt><br>
    </tt><tt> */</tt><tt><br>
    </tt><br>
    You normally just need to use Register/Deregister & Ref/Unref,
    and to implement the constructor and CallMethod. Coupling of the
    instances normally is done on construction, as a JS object is
    normally already needed for the parameters and can simply be
    attached to.<br>
    <br>
    Have a look at DuktapeHTTPRequest, DuktapeVFSLoad and
    DuktapeVFSSave, these are the current subclasses using this.<br>
    <br>
    For the command registration I would probably couple the OvmsCommand
    instance with a JS command object providing an execution method.<br>
    <br>
    Tell me if you need more info.<br>
    <br>
    Regards,<br>
    Michael<br>
    <br>
    <br>
    <div class="moz-cite-prefix">Am 15.07.20 um 08:12 schrieb Mark
      Webb-Johnson:<br>
    </div>
    <blockquote type="cite"
      cite="mid:B291C8AF-8382-4F45-87E3-3DA555E068BE@webb-johnson.net">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <div class=""><br class="">
      </div>
      <div class="">@Michael this is probably for you.</div>
      <div class=""><br class="">
      </div>
      <div class="">I am trying to implement javascript command
        registration. The idea is that a javascript module can call
        something like:</div>
      <div class=""><br class="">
      </div>
      <div class="">
        <blockquote style="caret-color: rgb(0, 0, 0); color: rgb(0, 0,
          0); margin: 0px 0px 0px 40px; border: none; padding: 0px;"
          class="">OvmsCommand.Register(basecommand, name, title,
          callbackfn, usage, min, max)</blockquote>
        <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
          class=""><br class="">
        </div>
      </div>
      <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
        class="">Then we reflect that into MyCommandApp.RegisterCommand,
        and keep a track of which command is for which javascript
        callbackfn. When the command is executed, we pass it into
        duktape.</div>
      <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
        class=""><br class="">
      </div>
      <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
        class="">I also have tracking for javascript module loading and
        unloading, so I can DeregisterCommand() if duktape is reloaded
        (and also protected against commands being registered in
        short-lived scripts run from the command line).</div>
      <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
        class=""><br class="">
      </div>
      <div style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
        class="">To implement this, I need to store the callbackfn as a
        persistent reference to a duktape javascript function.</div>
      <div class=""><br class="">
      </div>
      <div class="">The issue with callback function references in
        duktape is summarised here:</div>
      <div class=""><br class="">
      </div>
      <blockquote style="margin: 0 0 0 40px; border: none; padding:
        0px;" class="">
        <div class=""><a
            href="https://wiki.duktape.org/howtonativepersistentreferences"
            class="" moz-do-not-send="true">https://wiki.duktape.org/howtonativepersistentreferences</a></div>
        <div class=""><br class="">
        </div>
        <div class=""><i class="">When a Duktape/C function is called,
            Duktape places the call arguments on the value stack. While
            the arguments are on the value stack, they're guaranteed to
            be reachable and the Duktape/C function can safely work with
            the arguments.<br class="">
            <br class="">
            However, when the Duktape/C function returns, the value
            stack is unwound and references in the function's value
            stack frame are lost. If the last reference to a particular
            value was in the function's value stack frame, the value
            will be garbage collected when the function return is
            processed.</i></div>
      </blockquote>
      <div class=""><br class="">
      </div>
      <div class="">The standard approach is to store the reference back
        in the duktape duk_push_global_stash so it won’t get
        garbage-collected. But, that seems messy.</div>
      <div class=""><br class="">
      </div>
      <div class="">I see that Michael has already implemented something
        that seems similar in ovms_script.{h, cpp}, for the async http
        callbacks. Presumably to avoid this issue. But, the approach
        seems very different, and I am not sure if it is stopping _all_
        garbage collection for the duration of the async query, or just
        that particular object being garbage collected. The work seems
        extensive (quite a few objects involved).</div>
      <div class=""><br class="">
      </div>
      <div class="">So @Michael, any suggestions for this? I don’t want
        to reinvent the wheel...</div>
      <div class=""><br class="">
      </div>
      <div class="">Regards, Mark.</div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.openvehicles.com">OvmsDev@lists.openvehicles.com</a>
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
    </blockquote>
    <br>
    <pre class="moz-signature" cols="72">-- 
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
</pre>
  </body>
</html>