| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
I agree with @addaleax about the possible ambiguity with how to retrieve the byte values (by index or by byte of the underlying storage). That makes me lean towards -1 on this change. Do we know if there are other libraries (node or browser) who allow these other non-8-bit typed arrays to be used as 8-bit arrays? It might be good to see if there is a precedent for how we might handle it in node? |
Sorry, something went wrong.
|
Web standards usually use Web IDL as an abstraction for type conversions and other common tasks potentially used by many standards. In addition to ArrayBuffer, all TypedArray types, and DataView, Web IDL specifies two additional types for abstraction of buffer sources:
Additionally, Web IDL defines the abstract operations getting a reference to the bytes held by a buffer source and getting a copy of the bytes held by a buffer source, which are what the Web Standards actually call upon to perform the task of getting the bytes. They both retrieve the byte values by underlying storage, not by index. This effectively means that all Web APIs using ArrayBufferView or BufferSource Web IDL type, i.e. almost all Web APIs that take a generic byte buffer, support all TypedArray types. Examples include:
At the same time, not all Web APIs accept all TypedArray types, but this always happens for a good reason. Two notable exceptions I found:
On the other hand, I'm not familiar with any examples in the Node.js ecosystem, considering Buffer has been the standard for byte buffers since Node.js' inception. /cc @domenic |
Sorry, something went wrong.
Another exception is in readable byte streams (e.g. fetch body streams). This is because we need not only bytes, but also an offset and a length (for reasons I'll leave out here but can explain if desired). And look, we already have a type for that: Uint8Array = { buffer: ArrayBuffer, byteOffset, byteLength }. So we are using Uint8Array for streams. But this is basically a supporting argument: we only restrict to Uint8Array when we also find the byteOffset and byteLength into the larger ArrayBuffer to be meaningful. Otherwise, any form of binary data is acceptable. And indeed, as @TimothyGu pointed out, when accepting data in stream's BYOB-read() method, we accept any type.
Well, jsdom's upcoming v10 will accept any of the BufferSource types, or Buffer. |
Sorry, something went wrong.
|
@TimothyGu Have you compared at least the Buffer benchmarks to see what (if any) performance difference there is before and after these changes? |
Sorry, something went wrong.
|
@mscdex there are no differences in zlib. I did not test crypto, but I don't expect there to be any performance differences since the code is practically identical (except for changing Uint8Array to ArrayBufferView), both in JS and in C++. |
Sorry, something went wrong.
| const stream = require('stream'); | ||
| const util = require('util'); | ||
| const { isUint8Array } = process.binding('util'); | ||
| const { isArrayBufferView } = process.binding('util'); |
There was a problem hiding this comment.
Isn't this equivalent to ArrayBuffer.isView()?
Sorry, something went wrong.
There was a problem hiding this comment.
Isn't this equivalent to ArrayBuffer.isView()?
@lpinca yep, those do the same thing.
Sorry, something went wrong.
There was a problem hiding this comment.
Yes, I think the standard version should be better in this case.
Sorry, something went wrong.
There was a problem hiding this comment.
Is this WIP? There are a few more places in the API where currently only Uint8Arrays are supported (or at least it’s documented that way).
Anyway, I think I’m +1 on this change… @nodejs/collaborators Thoughts?
Sorry, something went wrong.
| const stream = require('stream'); | ||
| const util = require('util'); | ||
| const { isUint8Array } = process.binding('util'); | ||
| const { isArrayBufferView } = process.binding('util'); |
There was a problem hiding this comment.
Isn't this equivalent to ArrayBuffer.isView()?
@lpinca yep, those do the same thing.
Sorry, something went wrong.
| while (null !== (chunk = engine.read())) { | ||
| buffers.push(chunk); | ||
| nread += chunk.length; | ||
| nread += chunk.byteLength; |
There was a problem hiding this comment.
chunk is engine output, so it’s always a Buffer, right?
Sorry, something went wrong.
There was a problem hiding this comment.
I think so, but I'd rather err on the side of replacing too many Buffer.lengths rather than missing an ArrayBufferView.byteLength, since Buffer.length === Buffer.byteLength.
Sorry, something went wrong.
| const out = []; | ||
| for (const type of arrayBufferViews) { | ||
| const { BYTES_PER_ELEMENT = 1 } = type; | ||
| if (Number.isInteger(byteLength % BYTES_PER_ELEMENT)) { |
There was a problem hiding this comment.
Did you mean byteLength % BYTES_PER_ELEMENT === 0, or Number.isInteger(byteLength / BYTES_PER_ELEMENT)?
Sorry, something went wrong.
There was a problem hiding this comment.
Uhh… that's embarrassing. Good catch.
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM as it is. I think it make sense to support JS types for binary data wherever possible.
Sorry, something went wrong.
Somewhat. My intention was to incrementally update individual modules, instead of changing all the modules at the same time – sort of like how the support for Uint8Arrays was incrementally added. The crypto and zlib modules in this PR serve as examples for how it's done. |
Sorry, something went wrong.
|
It looks to me like this PR does not take into account byteOffset. Is that correct? If so that seems pretty bad. I think you need adapter code like https://github.com/tmpvar/jsdom/blob/28d08f58b82cc2100ad36b99cf5e8b4bbb3fc291/lib/api.js#L329-L333 |
Sorry, something went wrong.
@domenic Can you point to the code that you think doesn’t account for the offset? It does look like that’s handled correctly everywhere. |
Sorry, something went wrong.
|
Well, for example, https://github.com/TimothyGu/node/blob/13152405dd8f248192fea558a9bc206201f884f1/lib/crypto.js does not contain the string "byteOffset" anywhere. |
Sorry, something went wrong.
|
@domenic For most of the APIs that use C++, including the crypto ones, the ABV is unwrapped in https://github.com/nodejs/node/pull/12223/files#diff-772f489c7d0a32de3badbfbcb5fd200dR441. That does add the byteOffset to the pointer that actually ends up used (both with and without this PR), so I see no reason for concern here. |
Sorry, something went wrong.
|
Great, that is what I was missing. Thank you! |
Sorry, something went wrong.
PR-URL: #12223 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: #12223 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: #12223 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: #12223 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
PR-URL: nodejs#18651 Refs: nodejs#12223 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
| Back | FazBrowse Home | New Git URL |
Right now, many modules allow the use of plain Uint8Arrays in addition to Buffers. This PR begins the work to expand such support to all ArrayBufferView types (including all TypedArray types and DataView).
This work was inspired by #1826, which requests support for ArrayBuffer as well. But ArrayBuffer is treated separately from its views in V8's API and it is easier to get started with the work here.
The first two commits add the necessary infrastructure for consuming and testing all ArrayBufferView types. The last two demonstrate how to update the JS layer for it. (Specifically, using the new isArrayBufferView utility function and update usage of buf.length to buf.byteLength).
I don't intend this PR to make its way into 8.0.0.
Relevant discussions on IRC with @addaleax2017-03-23 20:20:54 TimothyGu So I was looking at https://github.com/nodejs/node/issues/1826 2017-03-23 20:21:23 TimothyGu As we are trying to support Uint8Array in C++ binding it doesn't look much more work to support all the other ArrayBufferView types 2017-03-23 20:21:40 TimothyGu including all TypedArray and DataView 2017-03-23 20:21:54 addaleax right … that was also pointed out to me in the last streams wg meeting 2017-03-23 20:22:32 addaleax I understand where it’s coming from, but so far I have wanted to keep the changes pretty minimal 2017-03-23 20:23:06 addaleax bc going from Buffer support to Uint8Array support is, for the most part, a tiny change 2017-03-23 20:23:27 addaleax if somebody (you?) wants to work on this, yay 2017-03-23 20:23:40 TimothyGu TBH it doesn't take much of a change on the C++ side to get it working 2017-03-23 20:23:46 TimothyGu http://sprunge.us/SgET 2017-03-23 20:23:54 TimothyGu or http://sprunge.us/SgET?diff 2017-03-23 20:25:12 TimothyGu so I thought maybe we could just support all of them at the same time 2017-03-23 20:25:25 addaleax that’s nice, yes ... 2017-03-23 20:28:20 addaleax re: generic ArrayBufferView support … the one reason I’ve not been doing that is that my personal goal is to give users a more standard way of passing in binary data, and Uint8Arrays work just fine for that purpose. the other reason is that there is at least a small bit of ambiguity, because interpreting e.g. a Uint16Array as a Uint8Array can be done in two ways (entry-for-entry or via the... 2017-03-23 20:28:21 addaleax ...underlying storage)Checklist
Affected core subsystem(s)