From 075853ed193e7824475605110c770d01a7f868ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Fri, 17 May 2024 00:47:12 +0200 Subject: [PATCH] buffer: make compare/equals faster 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: https://github.com/nodejs/node/pull/52993 Reviewed-By: Yagiz Nizipli Reviewed-By: Rich Trott Reviewed-By: Mohammed Keyvanzadeh --- src/node_buffer.cc | 22 +++++++++++++++++++++- src/node_external_reference.h | 5 +++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e7e3ead4416a40..dda430d5bb88cb 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -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; @@ -843,6 +844,23 @@ void Compare(const FunctionCallbackInfo &args) { args.GetReturnValue().Set(val); } +int32_t FastCompare(v8::Local, + const FastApiTypedArray& a, + const FastApiTypedArray& 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...], ie inside the Buffer, @@ -1409,7 +1427,7 @@ void Initialize(Local 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); @@ -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); diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 599db7352d2851..be4386dcf71203 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -27,6 +27,10 @@ using CFunctionCallbackWithStrings = bool (*)(v8::Local, const v8::FastOneByteString& input, const v8::FastOneByteString& base); +using CFunctionCallbackWithTwoUint8Arrays = + int32_t (*)(v8::Local, + const v8::FastApiTypedArray&, + const v8::FastApiTypedArray&); using CFunctionCallbackWithTwoUint8ArraysFallback = bool (*)(v8::Local, const v8::FastApiTypedArray&, @@ -56,6 +60,7 @@ class ExternalReferenceRegistry { V(CFunctionCallbackWithBool) \ V(CFunctionCallbackWithString) \ V(CFunctionCallbackWithStrings) \ + V(CFunctionCallbackWithTwoUint8Arrays) \ V(CFunctionCallbackWithTwoUint8ArraysFallback) \ V(CFunctionWithUint32) \ V(CFunctionWithDoubleReturnDouble) \