Skip to content

Commit

Permalink
buffer: optimize createFromString
Browse files Browse the repository at this point in the history
PR-URL: #54324
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
ronag authored and targos committed Sep 26, 2024
1 parent c5180e9 commit b80da2f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 31 deletions.
47 changes: 29 additions & 18 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const {
byteLengthUtf8,
compare: _compare,
compareOffset,
createFromString,
fill: bindingFill,
isAscii: bindingIsAscii,
isUtf8: bindingIsUtf8,
Expand Down Expand Up @@ -148,11 +147,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;
}
Expand Down Expand Up @@ -440,38 +440,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) {
Expand Down
13 changes: 0 additions & 13 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -529,17 +529,6 @@ MaybeLocal<Object> New(Environment* env,

namespace {

void CreateFromString(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
CHECK(args[1]->IsInt32());

enum encoding enc = static_cast<enum encoding>(args[1].As<Int32>()->Value());
Local<Object> buf;
if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
args.GetReturnValue().Set(buf);
}


template <encoding encoding>
void StringSlice(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Expand Down Expand Up @@ -1422,7 +1411,6 @@ void Initialize(Local<Object> target,
SetMethodNoSideEffect(context, target, "btoa", Btoa);

SetMethod(context, target, "setBufferPrototype", SetBufferPrototype);
SetMethodNoSideEffect(context, target, "createFromString", CreateFromString);

SetFastMethodNoSideEffect(context,
target,
Expand Down Expand Up @@ -1487,7 +1475,6 @@ void Initialize(Local<Object> target,

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(SetBufferPrototype);
registry->Register(CreateFromString);

registry->Register(SlowByteLengthUtf8);
registry->Register(fast_byte_length_utf8.GetTypeInfo());
Expand Down

0 comments on commit b80da2f

Please sign in to comment.