Skip to content

src,buffer: allow heap-allocated typed arrays

I noticed that the reason we’ve been disabling this has not actually been true, so it seems to make sense to let the engine use its default values. /cc @nodejs/buffer @nodejs/v8


build: remove v8_typed_array_max_size_in_heap option

This was added in 16f86d6c, based on the assumption that otherwise, the memory behind ArrayBuffer instances could be moved around on the heap while native code holds references to it.

This does not match what V8 actually does (and also did at the time):

  • The option/build variable was about always only about TypedArrays, not ArrayBuffers. Calls like new ArrayBuffer(4) call into C++ regardless of the option value, but calls like new Uint8Array(4) would not call into C++ under V8 defaults.
  • When first accessing a heap-allocated TypedArray’s ArrayBuffer, whether that is through the JS .buffer getter or the C++ ArrayBufferView::Buffer() function, a copy of the contents is created using the ArrayBuffer allocator and stored as the (permanent, unmovable) backing store.

As a consequence, the memory returned by ArrayBuffer::GetContents() is not moved around, because it is fixed once the ArrayBuffer object itself first comes into explicit existence in any way.

Removing this build option significantly speeds up creation of typed arrays from JS:

$ ./node benchmark/compare.js --new ./node --old ./node-master --runs 10 --filter buffer-creation.js buffers | Rscript benchmark/compare.R
                                                                     confidence improvement accuracy (*)     (**)    (***)
 buffers/buffer-creation.js n=1024 len=10 type='buffer()'                  ***    593.66 %      ±28.64%  ±41.10%  ±60.36%
 buffers/buffer-creation.js n=1024 len=10 type='fast-alloc-fill'           ***    675.42 %      ±90.67% ±130.24% ±191.54%
 buffers/buffer-creation.js n=1024 len=10 type='fast-alloc'                ***    663.55 %      ±58.41%  ±83.87% ±123.29%
 [... see commit log for more, statistically insignificant results ...]

The performance gains effect are undone once native code accesses the underlying ArrayBuffer, but then again that a) does not happen for all TypedArrays, and b) it should also make sense to look into using ArrayBufferView::CopyContents() in some places, which is made specifically to avoid such a performance impact and allows us to use the benefits of heap-allocated typed arrays.

Refs: https://github.com/nodejs/node/commit/16f86d6c578ff7aec708c7d736558a199d290e9c Refs: https://github.com/nodejs/node/pull/2893 Refs: https://github.com/nodejs/node/commit/74178a5682958d499896e0fa1af6bc0321ec1935#commitcomment-13250880 Refs: http://logs.libuv.org/node-dev/2015-09-15

src: allow not materializing ArrayBuffers from C++

Where appropriate, use a helper that wraps around ArrayBufferView::Buffer() or ArrayBufferView::CopyContents() rather than Buffer::Data(), as that may help to avoid materializing the underlying ArrayBuffer when reading small typed arrays from C++. This allows keeping the performance benefits of the faster creation of heap-allocated small typed arrays in many cases.

buffer: avoid materializing ArrayBuffer for creation

Do not create an ArrayBuffer if the engine’s settings avoid it and we don’t need it.

test: verify heap buffer allocations occur

Check that small typed arrays, including Buffers (unless allocated by Buffer.allocUnsafe()), are indeed heap-allocated.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

Merge request reports

Loading