ArrayBuffer neutering

Kenneth Russell kbr at google.com
Wed May 21 10:50:48 PDT 2014


On Tue, May 20, 2014 at 5:10 PM, Allen Wirfs-Brock
<allen at wirfs-brock.com> wrote:
> below
> On May 20, 2014, at 4:28 PM, Kenneth Russell wrote:
>
>> On Tue, May 20, 2014 at 9:40 AM, Allen Wirfs-Brock
>> <allen at wirfs-brock.com> wrote:
>>>
>>> On May 20, 2014, at 8:37 AM, Anne van Kesteren wrote:
>>>
>>>> On Tue, May 20, 2014 at 5:25 PM, Allen Wirfs-Brock
>>>> <allen at wirfs-brock.com> wrote:
>>>>> The ES6 TypedArray/ArrayBuffer spec. was written closely following the
>>>>> Khronos spec. which is pretty vague about what happens when an ArrayBuffer
>>>>> is neutered.
>>>>
>>>> If you go through
>>>> http://www.khronos.org/registry/typedarray/specs/latest/ and search
>>>> for "neutered" it seems relatively clear. byteLength returns 0 and the
>>>> other members follow from there.
>>>
>>> Wow, I'm pretty sure all of those return 0 if neutered's weren't there when I used the Khronos spec. to generate the ES6 spec.
>>>
>>> The change for byteLength of ArrayBuffer is trivial (and already done).
>>>
>>> However, the changes for ArrayBufferView (note this doesn't actually exists in the ES spec.) and in particular the 'length' property of  the various Typed Arrays has a lot of implications to consider.
>>>
>>> In ES6, (almost) all of the Array.prototype methods are available as methods of typed arrays. Do you really want all of these, if applied to an Typed Array with a neutered ArrayBuffer to act as if they were a 0 length array.  That would seem to just be a good way to obscure bugs as many of the array methods turn into no-ops when applied to 0-length arrays. With the current ES6 spec. they would throw as soon as they tried to access the underlying ArrayBuffer using the original length.
>>>
>>> Also note, that ignoring this new requirement, a Typed Array's length, byteLength, and byteOffset are all constants and this fact is used in specifying the behavior of the methods that operate upon them.  If they can change (even to 0) then this can occur on any operation that can trigger side-effects.  (For example, consider calling the callback function on 'map' or similar methods).  Do we really want to dynamically reconsider changes to ;length' as opposed to simply letting throws to occur on access to the neutered ArrayBuffer?
>>
>> First, some background. When typed arrays were designed, they were
>> specified with Web IDL and its ECMAScript binding. There were attempts
>> during typed arrays' development to throw exceptions on some
>> operations -- like out-of-range indexing -- but one by one these were
>> discovered to be incompatible with either Web IDL's or ECMAScript's
>> semantics like property lookup.
>>
>> When neutering was added, there were several discussions regarding how
>> to detect that an object had been neutered. The current behavior of
>> treating the ArrayBuffer and all of its views as though they became
>> zero-length was arrived at after careful consideration of the
>> alternatives. I also recall discussing this behavior in person with
>> ECMAScript committee members.
>>
>> Throwing an exception upon fetching these properties from a neutered
>> ArrayBuffer or view might provide nice fail-fast behavior but it's
>> also incompatible with the current specification. It's likely that web
>> applications using web workers, typed arrays and Transferables will
>> break if this change is made.
>
> We can make those properties all return 0, without too much impact. But that doesn't necessarily mean all the new methods (over 20) that ES6 provides for Typed Arrays can't also fail fast when applied to an TypedArray with a neutered array buffer rather than trying to pretend that it just happens to be zero length.  In particular, I don't want to have to scatter length change checks throughout thee algorithms in case one gets neutered as a side-effect of a callback or a proxy mediated access.
>
> What I propose is that for these new methods we will do a neutered check on entry and immediately throw a TypeError if the this value is a neutered. If not the algorithms proceeds using the current length, etc. values. If the typed array gets neutered while in the middle of one of these algorithms, a TypeError will get thrown at the point where the algorithm next tries to read or write into the ArrayBuffer.

Perhaps that would work, though I agree with Dmitry's comment later in
this thread that consistency is best.


> Oner issue, is that there is currently know way for ES code to test if an Buffer has been neutered.  That means we while I can specify these new built-ins as during the neutered test there is no way to write a ES-hosted implementation of that functionality. Why didn't you provide a isNeutered predicate?

Because when the concept of Transferable was formalized in the HTML5
spec, there was a goal to make the minimal possible changes.
Transferable was basically a generalization of MessagePort, which was
the only type that previously could be "transferred" to a web worker.
Neutering is only a concept in spec text and not in the IDL. The
Transferable typedef doesn't have any associated methods. The only way
to neuter an object is to transfer it to a web worker. There were
requests to provide a "close()" method and make Transferable a
sub-interface of a new Closable interface. We resisted making those
changes because they would have essentially introduced manual memory
management to JavaScript. All of this can be revisited.


>>
>>> Finally, I note that the current Khronos spec. doesn't provide much guidance in this regard.  The thing it has that is most similar to the other array methods is the 'subarray' method and it doesn't explicitly say anything about what happens when it is applied to a TypedArray with an underlying neutered ArrayBuffer.
>>
>> It isn't clear to me that it needs to. Starting from a view which is
>> pointing to a neutered ArrayBuffer, there is no way to create a
>> subarray of any nonzero length.
>
> No, but it seems highly unlikely that anybody doing myTypedArray.subarray(5,10) actually wants to get back a 0-length array is myTypedArray happens to be neutered.

I agree, but the compatibility impact has to be considered if
subarray() is going to start throwing exceptions. It might well be
minimal but it has to be measured.

What about typed arrays' indexed getters and setters? From reading these:

http://people.mozilla.org/~jorendorff/es6-draft.html#sec-getvaluefrombuffer
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-setvalueinbuffer

it looks like in the ES6 spec they throw exceptions if called against
neutered objects. What happens to the length of a neutered typed array
view in the ES6 spec? Does it become 0 as in the Khronos typed array
spec? What happens if an index which would have been out of range
before the object was neutered is passed to the indexed getter or
setter? What happens if the [] operator is used to get or set some
random named property against a neutered typed array view?

-Ken


> Allen


More information about the es-discuss mailing list