Commit Graph
2 Commits
Author SHA1 Message Date
Chris Tate 0d59abe143 Pool small Buffers as Node does
Buffer.from of strings, arrays and Uint8Arrays, Buffer.allocUnsafe and
Buffer.concat now return views into a per-thread pool slab of
Buffer.poolSize bytes (64 KiB by default) when the size is below
Buffer.poolSize >>> 1, following Node's allocate, fromStringFast and
fromArrayLike: 8-byte aligned offsets, a new slab when a request does not
fit, and the four-bytes-per-unit reservation for strings. Buffer.poolSize
can be read and set, and Buffer.allocUnsafeSlow returns an unpooled Buffer.
A slab lives while any of its views does. Its ArrayBuffer cannot be
transferred, and structuredClone of a typed array view copies the whole
ArrayBuffer and keeps the view's offset. Buffer.alloc, allocUnsafe and
allocUnsafeSlow validate sizes with Node's ERR_OUT_OF_RANGE error.

The first pooled allocation finds the startup slab, which has the
default 64 KiB size. A request it cannot hold gets a slab of the current
Buffer.poolSize, as in Node, and the room is checked after every new
slab, so a Buffer.poolSize raised before the first pooled allocation
cannot place a reservation past the end of a 64 KiB slab. A reservation
larger than a fresh slab traps instead of writing past it.

Corpus 5531 (typed) and 5532 (untyped) raise Buffer.poolSize before the
first pooled allocation and allocate just under the new threshold
through each pooled path, each case in a fresh child process, and also
shrink Buffer.poolSize and change it between allocations. The
node-types fenced fixture no longer lists Buffer.poolSize, which now
compiles.
2026-10-16 01:39:10 -05:00
Chris Tate 07ce602de5 Close Node 24 gaps in util.types keys, HTTP header limits and unread requests
- Object.keys(util.types) lists Node's 43 keys in Node's order, and
  Object.keys over the node:util/types namespace lists them sorted with
  "default". Object.values and Object.entries over util.types are refused,
  because some members do not compile yet.
- The HTTP server answers 431 Request Header Fields Too Large when a head
  or trailer block exceeds 1000 fields or the header byte bound, and the
  trailer block counts its fields on its own, like Node. Parser errors send
  Node's fixed responses without a Content-Length header.
- Server requests start paused like Node's IncomingMessage: body bytes and
  'end' wait for a 'data' listener, pipe() or resume(). When the response
  finishes, an unread request is dumped and emits 'end', before the
  response's 'close' for an empty body and after it otherwise. A body that
  is still arriving when the response finishes keeps reaching its
  listeners. req.complete reads true once the body has arrived.
- Document that small Buffers own exact-size ArrayBuffers instead of
  sharing Node's 64 KiB pool.

Corpus 5405-5409 cover each case.
2026-10-15 02:26:31 -05:00