buffer: make indexOf(byte) faster

Add a V8 fast API implementation for indexOfNumber, which significantly
improves the performance of finding a single byte within a buffer.

Refs: https://github.com/nodejs/node/pull/52993
PR-URL: https://github.com/nodejs/node/pull/53455
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
This commit is contained in:
Tobias Nießen authored and GitHub committed 2024-06-16 17:44:58 +00:00
1 parent 1aa8a785be
commit 103623b5ae
2 files changed
+54 -21

No files matched your search

+47 -21
View File
@@ -1089,37 +1089,57 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
result == haystack_length ? -1 : static_cast<int>(result));
}
void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
int32_t IndexOfNumber(const uint8_t* buffer_data,
size_t buffer_length,
uint32_t needle,
int64_t offset_i64,
bool is_forward) {
int64_t opt_offset = IndexOfOffset(buffer_length, offset_i64, 1, is_forward);
if (opt_offset <= -1 || buffer_length == 0) {
return -1;
}
size_t offset = static_cast<size_t>(opt_offset);
CHECK_LT(offset, buffer_length);
const void* ptr;
if (is_forward) {
ptr = memchr(buffer_data + offset, needle, buffer_length - offset);
} else {
ptr = node::stringsearch::MemrchrFill(buffer_data, needle, offset + 1);
}
const uint8_t* ptr_uint8 = static_cast<const uint8_t*>(ptr);
return ptr != nullptr ? static_cast<int32_t>(ptr_uint8 - buffer_data) : -1;
}
void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
CHECK(args[1]->IsUint32());
CHECK(args[2]->IsNumber());
CHECK(args[3]->IsBoolean());
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ArrayBufferViewContents<char> buffer(args[0]);
ArrayBufferViewContents<uint8_t> buffer(args[0]);
uint32_t needle = args[1].As<Uint32>()->Value();
int64_t offset_i64 = args[2].As<Integer>()->Value();
bool is_forward = args[3]->IsTrue();
int64_t opt_offset =
IndexOfOffset(buffer.length(), offset_i64, 1, is_forward);
if (opt_offset <= -1 || buffer.length() == 0) {
return args.GetReturnValue().Set(-1);
}
size_t offset = static_cast<size_t>(opt_offset);
CHECK_LT(offset, buffer.length());
const void* ptr;
if (is_forward) {
ptr = memchr(buffer.data() + offset, needle, buffer.length() - offset);
} else {
ptr = node::stringsearch::MemrchrFill(buffer.data(), needle, offset + 1);
}
const char* ptr_char = static_cast<const char*>(ptr);
args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - buffer.data())
: -1);
args.GetReturnValue().Set(IndexOfNumber(
buffer.data(), buffer.length(), needle, offset_i64, is_forward));
}
int32_t FastIndexOfNumber(v8::Local<v8::Value>,
const FastApiTypedArray<uint8_t>& buffer,
uint32_t needle,
int64_t offset_i64,
bool is_forward) {
uint8_t* buffer_data;
CHECK(buffer.getStorageIfAligned(&buffer_data));
return IndexOfNumber(
buffer_data, buffer.length(), needle, offset_i64, is_forward);
}
static v8::CFunction fast_index_of_number(
v8::CFunction::Make(FastIndexOfNumber));
void Swap16(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -1431,7 +1451,11 @@ void Initialize(Local<Object> target,
SetMethodNoSideEffect(context, target, "compareOffset", CompareOffset);
SetMethod(context, target, "fill", Fill);
SetMethodNoSideEffect(context, target, "indexOfBuffer", IndexOfBuffer);
SetMethodNoSideEffect(context, target, "indexOfNumber", IndexOfNumber);
SetFastMethodNoSideEffect(context,
target,
"indexOfNumber",
SlowIndexOfNumber,
&fast_index_of_number);
SetMethodNoSideEffect(context, target, "indexOfString", IndexOfString);
SetMethod(context, target, "detachArrayBuffer", DetachArrayBuffer);
@@ -1492,7 +1516,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(CompareOffset);
registry->Register(Fill);
registry->Register(IndexOfBuffer);
registry->Register(IndexOfNumber);
registry->Register(SlowIndexOfNumber);
registry->Register(FastIndexOfNumber);
registry->Register(fast_index_of_number.GetTypeInfo());
registry->Register(IndexOfString);
registry->Register(Swap16);
+7
View File
@@ -41,6 +41,12 @@ using CFunctionCallbackWithTwoUint8ArraysFallback =
const v8::FastApiTypedArray<uint8_t>&,
const v8::FastApiTypedArray<uint8_t>&,
v8::FastApiCallbackOptions&);
using CFunctionCallbackWithUint8ArrayUint32Int64Bool =
int32_t (*)(v8::Local<v8::Value>,
const v8::FastApiTypedArray<uint8_t>&,
uint32_t,
int64_t,
bool);
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
const uint32_t input);
using CFunctionWithDoubleReturnDouble = double (*)(v8::Local<v8::Value>,
@@ -68,6 +74,7 @@ class ExternalReferenceRegistry {
V(CFunctionCallbackWithStrings) \
V(CFunctionCallbackWithTwoUint8Arrays) \
V(CFunctionCallbackWithTwoUint8ArraysFallback) \
V(CFunctionCallbackWithUint8ArrayUint32Int64Bool) \
V(CFunctionWithUint32) \
V(CFunctionWithDoubleReturnDouble) \
V(CFunctionWithInt64Fallback) \