Bug 123058 - JSC should have an API for typed arrays
Summary: JSC should have an API for typed arrays
Status: RESOLVED DUPLICATE of bug 120112
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-10-19 00:47 PDT by Alexey Proskuryakov
Modified: 2013-11-06 09:42 PST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Proskuryakov 2013-10-19 00:47:18 PDT
It seems that JavaScript API clients can't do anything with typed arrays passed to them as arguments.

I'm facing this in bug 86914, implementing testRunner.setAudioData(ArrayBufferView). In DumpRenderTree, I can grudgingly use private JSC functions just like in WebCore, but API clients can't do that.
Comment 1 Geoffrey Garen 2013-10-19 13:01:31 PDT
What would you like to be able to do with them? Surely you can do some things, like read their lengths and access individual elements.
Comment 2 Alexey Proskuryakov 2013-10-19 13:22:06 PDT
> access individual elements

That's probably not the most reasonable thing to do in cases that warrant TypedArray use :)

Personally, I only needed to get bytes from the buffer efficiently. Not sure if there is anything else that can't be done already, but perhaps some syntactic sugar would help? Also, not sure how efficiently one can create a typed array from C code.
Comment 3 Filip Pizlo 2013-10-19 13:26:53 PDT
(In reply to comment #2)
> > access individual elements
> 
> That's probably not the most reasonable thing to do in cases that warrant TypedArray use :)
> 
> Personally, I only needed to get bytes from the buffer efficiently. Not sure if there is anything else that can't be done already, but perhaps some syntactic sugar would help? Also, not sure how efficiently one can create a typed array from C code.

I agree we should have such an API.  I think we even have some dup's for this bug - you're not the first to ask for this.

Maybe just the following C API function would be enough:

JSGetTypedArrayBase(JSValueRef) -> returns void* of the first element in the view or the base of the buffer
JSGetTypedArrayByteLength(JSValueRef) -> returns size_t of the number of bytes that the view sees or the byteLength of the buffer.

These will work for any view or buffer and return null/0 for things that aren't typed arrays.

Sound sensible?
Comment 4 Geoffrey Garen 2013-10-19 13:35:31 PDT
I think Alexey is also asking for a way to create typed arrays.

> JSGetTypedArrayBase(JSValueRef) -> returns void* of the first element in the view or the base of the buffer
> JSGetTypedArrayByteLength(JSValueRef) -> returns size_t of the number of bytes that the view sees or the byteLength of the buffer.

This would be 

JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)

Maybe "BytesPtr" is a better name than "Base", to match our string and data APIs.

How would I know the data type in the typed array? How long would the returned pointer remain valid? What happens after neutering?
Comment 5 Geoffrey Garen 2013-10-19 13:36:09 PDT
> JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
> JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)

Sorry:

JSObjectGetTypedArrayBase(JSContextRef, JSObjectRef)
JSObjectGetTypedArrayByteLength(JSContextRef, JSObjectRef)
Comment 6 Filip Pizlo 2013-10-19 13:44:50 PDT
(In reply to comment #4)
> I think Alexey is also asking for a way to create typed arrays.
> 
> > JSGetTypedArrayBase(JSValueRef) -> returns void* of the first element in the view or the base of the buffer
> > JSGetTypedArrayByteLength(JSValueRef) -> returns size_t of the number of bytes that the view sees or the byteLength of the buffer.
> 
> This would be 
> 
> JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
> JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)

OK, but out of curiosity, does it have to be?  You can get a JSGenericTypedArrayView's base and length without an ExecState*.

> 
> Maybe "BytesPtr" is a better name than "Base", to match our string and data APIs.

Yeah.

> 
> How would I know the data type in the typed array?

Why would a client care?  If they did, they can already get the element type using JS constructs.

> How long would the returned pointer remain valid?

Only so long as the JSValueRef of the buffer or view was live and so long as it wasn't neutered.

> What happens after neutering?

It's interesting to note that neutering is purely a DOM construct - it will only happen if you use the JS API in conjunction with a WebView.

Neutering will free the buffer so your pointer will become invalid.
Comment 7 Filip Pizlo 2013-10-19 13:51:21 PDT
(In reply to comment #6)
> (In reply to comment #4)
> > I think Alexey is also asking for a way to create typed arrays.
> > 
> > > JSGetTypedArrayBase(JSValueRef) -> returns void* of the first element in the view or the base of the buffer
> > > JSGetTypedArrayByteLength(JSValueRef) -> returns size_t of the number of bytes that the view sees or the byteLength of the buffer.
> > 
> > This would be 
> > 
> > JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
> > JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)
> 
> OK, but out of curiosity, does it have to be?  You can get a JSGenericTypedArrayView's base and length without an ExecState*.
> 
> > 
> > Maybe "BytesPtr" is a better name than "Base", to match our string and data APIs.
> 
> Yeah.
> 
> > 
> > How would I know the data type in the typed array?
> 
> Why would a client care?  If they did, they can already get the element type using JS constructs.
> 
> > How long would the returned pointer remain valid?
> 
> Only so long as the JSValueRef of the buffer or view was live and so long as it wasn't neutered.

And to clarify, we will ensure that the returned buffer pointer was pinned by doing slowDownAndWasteMemory().

> 
> > What happens after neutering?
> 
> It's interesting to note that neutering is purely a DOM construct - it will only happen if you use the JS API in conjunction with a WebView.
> 
> Neutering will free the buffer so your pointer will become invalid.
Comment 8 Geoffrey Garen 2013-10-19 14:40:20 PDT
> > JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
> > JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)

> OK, but out of curiosity, does it have to be?  You can get a JSGenericTypedArrayView's base and length without an ExecState*.

Whenever we’ve made the decision to leave out JSContextRef before, we’ve come to regret it. For example, we made that decision for strings, and now we regret it.

In this case, I could imagine some implementations that might require an ExecState* in order to get a backing pointer. For example, if we did pin the pointer, and pinning required a GC allocation, then we would need an ExecState*. Or, if some typed arrays had a super-slow mode, in which their backing buffer pointers were maintained in an external hash table, that would require an ExecState*. Or if some typed arrays had an "I'm currently in GPU memory" mode, that would require an ExecState*.
Comment 9 Filip Pizlo 2013-10-19 14:43:40 PDT
(In reply to comment #8)
> > > JSObjectGetTypedArrayBase(JSContextRef, JSValueRef)
> > > JSObjectGetTypedArrayByteLength(JSContextRef, JSValueRef)
> 
> > OK, but out of curiosity, does it have to be?  You can get a JSGenericTypedArrayView's base and length without an ExecState*.
> 
> Whenever we’ve made the decision to leave out JSContextRef before, we’ve come to regret it. For example, we made that decision for strings, and now we regret it.
> 
> In this case, I could imagine some implementations that might require an ExecState* in order to get a backing pointer. For example, if we did pin the pointer, and pinning required a GC allocation, then we would need an ExecState*. Or, if some typed arrays had a super-slow mode, in which their backing buffer pointers were maintained in an external hash table, that would require an ExecState*. Or if some typed arrays had an "I'm currently in GPU memory" mode, that would require an ExecState*.

Interestingly, slowDownAndWasteMemory() does require VM& but it doesn't take either VM& or ExecState*.  It just uses heapFor().  That's because there were too many places that expected to be able to get a native buffer from a JS buffer and they didn't have an ExecState* lying around.

But, sure, we don't have to expose such madness to the C API customers.
Comment 10 Alexey Proskuryakov 2013-11-06 09:42:35 PST
Found an older bug, duping to that.

*** This bug has been marked as a duplicate of bug 120112 ***