Skip to content

Commit

Permalink
buffer: make compare/equals faster
Browse files Browse the repository at this point in the history
This patch adds a V8 fast API implementation for the buffer.compare
binding, which is used both by Buffer.prototype.equals and
Buffer.prototype.compare. In particular, it significantly improves the
performance of comparing buffers for equality.

PR-URL: nodejs#52993
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
  • Loading branch information
tniessen authored May 16, 2024
1 parent 3f3226c commit 075853e
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ using v8::ArrayBufferView;
using v8::BackingStore;
using v8::Context;
using v8::EscapableHandleScope;
using v8::FastApiTypedArray;
using v8::FunctionCallbackInfo;
using v8::Global;
using v8::HandleScope;
Expand Down Expand Up @@ -843,6 +844,23 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
args.GetReturnValue().Set(val);
}

int32_t FastCompare(v8::Local<v8::Value>,
const FastApiTypedArray<uint8_t>& a,
const FastApiTypedArray<uint8_t>& b) {
uint8_t* data_a;
uint8_t* data_b;
CHECK(a.getStorageIfAligned(&data_a));
CHECK(b.getStorageIfAligned(&data_b));

size_t cmp_length = std::min(a.length(), b.length());

return normalizeCompareVal(
cmp_length > 0 ? memcmp(data_a, data_b, cmp_length) : 0,
a.length(),
b.length());
}

static v8::CFunction fast_compare(v8::CFunction::Make(FastCompare));

// Computes the offset for starting an indexOf or lastIndexOf search.
// Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
Expand Down Expand Up @@ -1409,7 +1427,7 @@ void Initialize(Local<Object> target,
SlowByteLengthUtf8,
&fast_byte_length_utf8);
SetMethod(context, target, "copy", Copy);
SetMethodNoSideEffect(context, target, "compare", Compare);
SetFastMethodNoSideEffect(context, target, "compare", Compare, &fast_compare);
SetMethodNoSideEffect(context, target, "compareOffset", CompareOffset);
SetMethod(context, target, "fill", Fill);
SetMethodNoSideEffect(context, target, "indexOfBuffer", IndexOfBuffer);
Expand Down Expand Up @@ -1469,6 +1487,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(FastByteLengthUtf8);
registry->Register(Copy);
registry->Register(Compare);
registry->Register(FastCompare);
registry->Register(fast_compare.GetTypeInfo());
registry->Register(CompareOffset);
registry->Register(Fill);
registry->Register(IndexOfBuffer);
Expand Down
5 changes: 5 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ using CFunctionCallbackWithStrings =
bool (*)(v8::Local<v8::Value>,
const v8::FastOneByteString& input,
const v8::FastOneByteString& base);
using CFunctionCallbackWithTwoUint8Arrays =
int32_t (*)(v8::Local<v8::Value>,
const v8::FastApiTypedArray<uint8_t>&,
const v8::FastApiTypedArray<uint8_t>&);
using CFunctionCallbackWithTwoUint8ArraysFallback =
bool (*)(v8::Local<v8::Value>,
const v8::FastApiTypedArray<uint8_t>&,
Expand Down Expand Up @@ -56,6 +60,7 @@ class ExternalReferenceRegistry {
V(CFunctionCallbackWithBool) \
V(CFunctionCallbackWithString) \
V(CFunctionCallbackWithStrings) \
V(CFunctionCallbackWithTwoUint8Arrays) \
V(CFunctionCallbackWithTwoUint8ArraysFallback) \
V(CFunctionWithUint32) \
V(CFunctionWithDoubleReturnDouble) \
Expand Down

0 comments on commit 075853e

Please sign in to comment.