From 9f083203b0b496171cc7085227dcc5619700a915 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Wed, 14 Aug 2024 15:34:07 +0200 Subject: [PATCH] buffer: optimize createFromString PR-URL: https://github.com/nodejs/node/pull/54324 Reviewed-By: Yagiz Nizipli Reviewed-By: Matteo Collina --- lib/buffer.js | 47 ++++++++++++++++++++++++++++------------------ src/node_buffer.cc | 13 ------------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index ac562b6865dea9..a68718848c1a49 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -59,7 +59,6 @@ const { compare: _compare, compareOffset, copy: _copy, - createFromString, fill: bindingFill, isAscii: bindingIsAscii, isUtf8: bindingIsUtf8, @@ -150,11 +149,12 @@ const constants = ObjectDefineProperties({}, { }); Buffer.poolSize = 8 * 1024; -let poolSize, poolOffset, allocPool; +let poolSize, poolOffset, allocPool, allocBuffer; function createPool() { poolSize = Buffer.poolSize; - allocPool = createUnsafeBuffer(poolSize).buffer; + allocBuffer = createUnsafeBuffer(poolSize); + allocPool = allocBuffer.buffer; markAsUntransferable(allocPool); poolOffset = 0; } @@ -442,38 +442,49 @@ function allocate(size) { } function fromStringFast(string, ops) { - const length = ops.byteLength(string); + const maxLength = Buffer.poolSize >>> 1; - if (length >= (Buffer.poolSize >>> 1)) - return createFromString(string, ops.encodingVal); + let length = string.length; // Min length + + if (length >= maxLength) + return createFromString(string, ops); + + length *= 4; // Max length (4 bytes per character) + + if (length >= maxLength) + length = ops.byteLength(string); // Actual length + + if (length >= maxLength) + return createFromString(string, ops, length); if (length > (poolSize - poolOffset)) createPool(); - let b = new FastBuffer(allocPool, poolOffset, length); - const actual = ops.write(b, string, 0, length); - if (actual !== length) { - // byteLength() may overestimate. That's a rare case, though. - b = new FastBuffer(allocPool, poolOffset, actual); - } + + const actual = ops.write(allocBuffer, string, poolOffset, length); + const b = new FastBuffer(allocPool, poolOffset, actual); + poolOffset += actual; alignPool(); return b; } +function createFromString(string, ops, length = ops.byteLength(string)) { + const buf = Buffer.allocUnsafeSlow(length); + const actual = ops.write(buf, string, 0, length); + return actual < length ? new FastBuffer(buf.buffer, 0, actual) : buf; +} + function fromString(string, encoding) { let ops; - if (typeof encoding !== 'string' || encoding.length === 0) { - if (string.length === 0) - return new FastBuffer(); + if (!encoding || encoding === 'utf8') { ops = encodingOps.utf8; } else { ops = getEncodingOps(encoding); if (ops === undefined) throw new ERR_UNKNOWN_ENCODING(encoding); - if (string.length === 0) - return new FastBuffer(); } - return fromStringFast(string, ops); + + return string.length === 0 ? new FastBuffer() : fromStringFast(string, ops); } function fromArrayBuffer(obj, byteOffset, length) { diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 6e141b974131cc..d8fce1a8e8106a 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -530,17 +530,6 @@ MaybeLocal New(Environment* env, namespace { -void CreateFromString(const FunctionCallbackInfo& args) { - CHECK(args[0]->IsString()); - CHECK(args[1]->IsInt32()); - - enum encoding enc = static_cast(args[1].As()->Value()); - Local buf; - if (New(args.GetIsolate(), args[0].As(), enc).ToLocal(&buf)) - args.GetReturnValue().Set(buf); -} - - template void StringSlice(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1436,7 +1425,6 @@ void Initialize(Local target, SetMethodNoSideEffect(context, target, "btoa", Btoa); SetMethod(context, target, "setBufferPrototype", SetBufferPrototype); - SetMethodNoSideEffect(context, target, "createFromString", CreateFromString); SetFastMethodNoSideEffect(context, target, @@ -1501,7 +1489,6 @@ void Initialize(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(SetBufferPrototype); - registry->Register(CreateFromString); registry->Register(SlowByteLengthUtf8); registry->Register(fast_byte_length_utf8.GetTypeInfo());