ArrayBuffer neutering (original) (raw)
On May 21, 2014, at 10:50 AM, Kenneth Russell wrote:
On Tue, May 20, 2014 at 5:10 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
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.
I think it is better to have one legacy method that behaves differently from all the other (new) methods then to maintain consistency by introducing 20+ new bug farms.
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.
So you would have no objection to adding a isNeutered method to ArrayBuffer.prototype. As I mentioned, I think it is needed for self-hosting the currently specified typed array methods and any new methods that people might want to write the recognize the possibility that an arrays backing store can get neutered.
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.
This sounds like something that can be tried in a pre-beta browser build.
What about typed arrays' indexed getters and setters? From reading these:
people.mozilla.org/~jorendorff/es6-draft.html#sec-getvaluefrombuffer, people.mozilla.org/~jorendorff/es6-draft.html#sec-setvalueinbuffer
it looks like in the ES6 spec they throw exceptions if called against neutered objects.
Yes, as currently spec'ed [[Get]] and [[Set]] operations upon TypedArray instances throw if the backing ArrayBuffer has been neutered. But the reason is inpeople.mozilla.org/~jorendorff/es6-draft.html#sec-integerindexedelementget andpeople.mozilla.org/~jorendorff/es6-draft.html#sec-integerindexedelementset
(IntegerIndexed exotic objects are the ES underlying specification type that is used for all Typed Array instances).
Integer indexed property access (eg, ta[5] ) return undefined (on [[Get]]'s) that are outside of the 0..originalLength-1 range of the array. This test is specified in terms of an internal [[ArrayLength]] property that is immutably set to the original defined size of the array. So the spec. currently say an "in original array range" access on a TypedArray with a neutered ArrayBuffer will be "in range" but the call to GetValueFromBuffer will throw because the ArrayBuffer has been neutered.
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?
The length property of an Typed Array is an accessor property. I just updated my working draft of the specification of that accessor (people.mozilla.org/~jorendorff/es6-draft.html#sec-get-%typedarray%.prototype.length not yet updated) and also the accessors for byteLength and byteOffset so they return 0 when the backing ArrayBuffer is observed to be neutered.
However, that doesn't directly address the indexed access issues. Implementations presumably want indexed access to typed arrays to be has fast as possible, so they are unlikely to want to make a call to a 'length' accessor property on every indexed access. That's why we specify the [[ArrayLength]] as private state of the the typed array instance.
Instead I can either place a IsNeutered guard on the calls to GetValueInBuffer/SetValueInBuffer from the indexed accessors or change GetValueInBuffer/SetValueInBuffer to not throw on neutered buffered accesses. However, this also requires some care to make sure that DataView accesses continue to throw.
The bottom line of all of this is we want the fast path for a non-netured typed array access to be as fast as possible while still behaving safely (if not reasonably) in the presence of neuterable ArrayBuffers.
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?
Currently, in the ES spec. it is range checked against the original array length. All out of range accesses return undefined.
What happens if the [] operator is used to get or set some random named property against a neutered typed array view?
They just work (assuming that the property isn't an integer index). Neutering the backing ArrayBuffer doesn't do anything to the ordinary properties of a typed array instance.
On May 21, 2014, at 10:50 AM, Kenneth Russell wrote:
On Tue, May 20, 2014 at 5:10 PM, Allen Wirfs-Brock wrote:
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.
I think it is better to have one legacy method that behaves differently from all the other (new) methods then to maintain consistency by introducing 20+ new bug farms.
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.
So you would have no objection to adding a isNeutered method to ArrayBuffer.prototype. As I mentioned, I think it is needed for self-hosting the currently specified typed array methods and any new methods that people might want to write the recognize the possibility that an arrays backing store can get neutered.
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.
This sounds like something that can be tried in a pre-beta browser build.
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.
Yes, as currently spec'ed [[Get]] and [[Set]] operations upon TypedArray instances throw if the backing ArrayBuffer has been neutered. But the reason is in http://people.mozilla.org/~jorendorff/es6-draft.html#sec-integerindexedelementget and http://people.mozilla.org/~jorendorff/es6-draft.html#sec-integerindexedelementset
(IntegerIndexed exotic objects are the ES underlying specification type that is used for all Typed Array instances).
Integer indexed property access (eg, ta[5] ) return undefined (on [[Get]]'s) that are outside of the 0..originalLength-1 range of the array. This test is specified in terms of an internal [[ArrayLength]] property that is immutably set to the original defined size of the array. So the spec. currently say an "in original array range" access on a TypedArray with a neutered ArrayBuffer will be "in range" but the call to GetValueFromBuffer will throw because the ArrayBuffer has been neutered.
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?
The length property of an Typed Array is an accessor property. I just updated my working draft of the specification of that accessor (http://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-%typedarray%.prototype.length not yet updated) and also the accessors for byteLength and byteOffset so they return 0 when the backing ArrayBuffer is observed to be neutered.
However, that doesn't directly address the indexed access issues. Implementations presumably want indexed access to typed arrays to be has fast as possible, so they are unlikely to want to make a call to a 'length' accessor property on every indexed access. That's why we specify the [[ArrayLength]] as private state of the the typed array instance.
Instead I can either place a IsNeutered guard on the calls to GetValueInBuffer/SetValueInBuffer from the indexed accessors or change GetValueInBuffer/SetValueInBuffer to not throw on neutered buffered accesses. However, this also requires some care to make sure that DataView accesses continue to throw.
The bottom line of all of this is we want the fast path for a non-netured typed array access to be as fast as possible while still behaving safely (if not reasonably) in the presence of neuterable ArrayBuffers.
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? Currently, in the ES spec. it is range checked against the original array length. All out of range accesses return undefined.
What happens if the [] operator is used to get or set some random named property against a neutered typed array view?
They just work (assuming that the property isn't an integer index). Neutering the backing ArrayBuffer doesn't do anything to the ordinary properties of a typed array instance.
Allen -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20140521/8a4d888b/attachment.html