<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Typed Arrays have no public facing API"
   href="https://bugs.webkit.org/show_bug.cgi?id=120112#c25">Comment # 25</a>
              on <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Typed Arrays have no public facing API"
   href="https://bugs.webkit.org/show_bug.cgi?id=120112">bug 120112</a>
              from <span class="vcard"><a class="email" href="mailto:fpizlo&#64;apple.com" title="Filip Pizlo &lt;fpizlo&#64;apple.com&gt;"> <span class="fn">Filip Pizlo</span></a>
</span></b>
        <pre>(In reply to <a href="show_bug.cgi?id=120112#c23">comment #23</a>)
<span class="quote">&gt; (In reply to <a href="show_bug.cgi?id=120112#c22">comment #22</a>)
&gt; 
&gt; &gt; &gt; Can you clarify what the caller must do to ensure that the returned pointer continues to point to valid memory? 
&gt; &gt; My assumption was that a call to JSValueProtect() on the Typed Array would
&gt; &gt; also ensure the pointer remains valid, but I'm not really sure if that's
&gt; &gt; actually the case. Maybe Filip Pizlo can chime in: when/how exactly is the
&gt; &gt; underlying buffer &quot;pinned&quot;?
&gt; &gt; 
&gt; &gt; If JSValueProtect() indeed already ensures the pointer remains valid, I
&gt; &gt; don't think we need another set of functions to retain/release the data
&gt; &gt; pointer. Imho it's obvious that if the JSObject is GC'ed, the pointer will
&gt; &gt; become invalid. If you want to hold on to the pointer, hold on to the
&gt; &gt; JSObject.
&gt; &gt; 
&gt; 
&gt; I'm not sure about this - Fil, do we guarantee we won't move a typed array's
&gt; backing buffer if the referencing object is pinned?</span >

Let's not get confused about the issues here.  Nobody is pinning anything, since we don't have a pinning API.  There is no way to say &quot;please don't move this object or things that this object points to&quot;.  Incidentally it just so happens that the JSCell backing a JSObjectRef will not move, but that's not because it's pinned; it's because we don't move JSCells.

<span class="quote">&gt; 
&gt; &gt; 
&gt; &gt; &gt; Why does getting the data pointer require a byte length?
&gt; &gt; I found that if you want to obtain the data pointer of a Typed Array, you
&gt; &gt; almost always also need to get the byte length of that data. Note that the
&gt; &gt; pointer to the size_t you pass in, is only used for output! Having two
&gt; &gt; separate API calls for this seemed wasteful. If you don't need the byte
&gt; &gt; length, simply pass NULL instead of a pointer to a size_t:
&gt; &gt; void * ptr = JSObjectGetTypedArrayDataPtr(ctx, object, NULL);
&gt; 
&gt; I don't believe we have any other api that behaves in this way.
&gt; API consistency is important.
&gt; 
&gt; &gt; &gt; Why do we use byte length for access but element count for creation?
&gt; &gt; JSObjectGetTypedArrayDataPtr() returns a pointer to raw data. If we were to
&gt; &gt; return the element count instead of the byte length, you would always need
&gt; &gt; to call JSObjectGetTypedArrayType() as well, to figure out how many bytes
&gt; &gt; you could access. Using the byte length here greatly simplifies stuff like
&gt; &gt; memcpy() to/from own buffers for API users.
&gt; 
&gt; r- just based on this API decision.</span >

I think this is a little extreme.  I understand and appreciate the justification for using byte size, and in fact, the JS typed array API emphasizes byte sizes a lot.

<span class="quote">&gt; 
&gt; You're optimizing for a single case (memcpy), over the common case: casting
&gt; the array of X into an X*.
&gt; 
&gt; Mixing and matching what unit the length you're using is a recipe for
&gt; mistakes.</span >

Let's not use this kind of logic.  The typed array API is intended to give expert users who are mixing JS and C to exchange raw memory buffers between the two worlds.  This API must allow the user to shoot himself in the foot; if it doesn't then surely it is a useless API.

<span class="quote">&gt; 
&gt; &gt; Likewise, we use an element count for JSObjectMakeTypedArray() because 
&gt; &gt; 1) you know the type of the Typed Array you want to create anyway
&gt; &gt; 2) usually you know the number of elements you want to store when creating a
&gt; &gt; Typed Array through the API (this is different from being passed a Typed
&gt; &gt; Array from JS Land!)
&gt; &gt; 3) using a byte length here would be error prone: what if I try to create a
&gt; &gt; Uint32Array with a byte length of 5?
&gt; 
&gt; Which is why we should always be using the item count. If absolutely
&gt; necessary you could have a GetByteLength function just as the js api has.</span >

By that logic, the C API should be using a mix of byte sizes and element counts in its functions, just like the JS API already does.

<span class="quote">&gt; 
&gt; &gt; 
&gt; &gt; 
&gt; &gt; &gt; How do you create a typed array with a data pointer? Is the input a void*?
&gt; &gt; I don't think we need an API for this. Just let JSC handle the data
&gt; &gt; allocation and then obtain a pointer to it.
&gt; &gt; 
&gt; &gt; JSObjectRef array = JSObjectMakeTypedArray(ctx, kJSTypedArrayTypeUint8Array,
&gt; &gt; 1024);
&gt; &gt; void *dataPtr = JSObjectGetTypedArrayDataPtr(ctx, array, NULL);
&gt; &gt; memcpy(dataPtr, myOwnData, 1024);
&gt; &gt; 
&gt; &gt; Imho it's not worth to complicate the API to avoid a short memcpy() for
&gt; &gt; handing over data to JS Land.
&gt; Again, optimizing for memcpy is not the right trade off here.
&gt; 
&gt; Also this API fails to allow sharing of data allocated elsewhere, that can
&gt; lead to unnecessary memory copying. Most other data related APIs on OS X
&gt; allow specifying the external buffer to use -- in fact most APIs take the
&gt; buffer pointer, and only allocate if that pointer is null.</span ></pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>