mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
zlib: add crc32c
Add zlib.crc32c(data[, value]), which computes the CRC-32C checksum (Castagnoli polynomial, RFC 3720 section 12.1). CRC-32C has better error detection properties than the CRC-32 of zlib.crc32() and is the checksum required by many current protocols, formats and services, among them: - iSCSI header and data digests (RFC 7143) - SCTP packet checksums (RFC 9260) - iWARP MPA framing (RFC 5044) - NVMe/TCP header and data digests - ext4, Btrfs and XFS metadata checksums - the Snappy framing format - Apache Kafka record batches - LevelDB and RocksDB block checksums - TensorFlow TFRecord files - Google Cloud Storage and Amazon S3 object checksums Implementing any of these in JavaScript currently needs a userland CRC-32C, which is far slower than native code. The function mirrors zlib.crc32(): it accepts a string (encoded as UTF-8) or an ArrayBufferView, takes an optional 32-bit unsigned starting value so a checksum can be continued across chunks, and has a V8 fast API path. The checksum is computed by absl::ExtendCrc32c() from the bundled Abseil, which is already built and linked into node, so this adds no new dependency and no new checksum implementation. absl_crc32c is added to the libraries linked with --shared-abseil. Abseil selects its hardware-accelerated CRC-32C path (SSE4.2 and PCLMULQDQ on x64, the CRC32 and PMULL extensions on arm64) at compile time, so with node's default compiler flags the portable table-driven implementation is used. It runs at about the same speed as zlib.crc32() (about 6.5 GB/s on a recent x64 machine), while the hardware path reaches about 38 GB/s. Builds whose target CPU baseline already includes those instructions get the hardware path without changes. Enabling it for generic builds is left out on purpose: on x64, Abseil uses the accelerated code for unrecognized CPUs without a runtime feature check, so compiling it in unconditionally would fault on CPUs without SSE4.2. Signed-off-by: Philipp Dunkel <pip@pipobscure.com> PR-URL: https://github.com/nodejs/node/pull/66828 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
1 parent
754325cd2f
commit
df2ea49e00
8 files changed
+258
-1
No files matched your search
@@ -34,6 +34,7 @@
|
||||
#include "threadpoolwork-inl.h"
|
||||
#include "util-inl.h"
|
||||
|
||||
#include "absl/crc/crc32c.h"
|
||||
#include "node_debug.h"
|
||||
#include "v8-fast-api-calls.h"
|
||||
#include "v8.h"
|
||||
@@ -2127,6 +2128,36 @@ static uint32_t FastCRC32(v8::Local<v8::Value> receiver,
|
||||
|
||||
static CFunction fast_crc32_(CFunction::Make(FastCRC32));
|
||||
|
||||
static inline uint32_t CRC32CImpl(Isolate* isolate,
|
||||
Local<Value> data,
|
||||
uint32_t value) {
|
||||
return CallOnSequence<uint32_t>(
|
||||
isolate, data, [&](const char* ptr, size_t size) -> uint32_t {
|
||||
return static_cast<uint32_t>(absl::ExtendCrc32c(
|
||||
absl::crc32c_t{value}, std::string_view(ptr, size)));
|
||||
});
|
||||
}
|
||||
|
||||
static void CRC32C(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[0]->IsArrayBufferView() || args[0]->IsString());
|
||||
CHECK(args[1]->IsUint32());
|
||||
uint32_t value = args[1].As<v8::Uint32>()->Value();
|
||||
args.GetReturnValue().Set(CRC32CImpl(args.GetIsolate(), args[0], value));
|
||||
}
|
||||
|
||||
static uint32_t FastCRC32C(v8::Local<v8::Value> receiver,
|
||||
v8::Local<v8::Value> data,
|
||||
uint32_t value,
|
||||
// NOLINTNEXTLINE(runtime/references)
|
||||
v8::FastApiCallbackOptions& options) {
|
||||
TRACK_V8_FAST_API_CALL("zlib.crc32c");
|
||||
v8::HandleScope handle_scope(options.isolate);
|
||||
CHECK(data->IsArrayBufferView() || data->IsString());
|
||||
return CRC32CImpl(options.isolate, data, value);
|
||||
}
|
||||
|
||||
static CFunction fast_crc32c_(CFunction::Make(FastCRC32C));
|
||||
|
||||
void Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
Local<Context> context,
|
||||
@@ -2140,6 +2171,7 @@ void Initialize(Local<Object> target,
|
||||
MakeClass<ZstdDecompressStream>::Make(env, target, "ZstdDecompress");
|
||||
|
||||
SetFastMethodNoSideEffect(context, target, "crc32", CRC32, &fast_crc32_);
|
||||
SetFastMethodNoSideEffect(context, target, "crc32c", CRC32C, &fast_crc32c_);
|
||||
target->Set(env->context(),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check();
|
||||
@@ -2153,6 +2185,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
MakeClass<ZstdDecompressStream>::Make(registry);
|
||||
registry->Register(CRC32);
|
||||
registry->Register(fast_crc32_);
|
||||
registry->Register(CRC32C);
|
||||
registry->Register(fast_crc32c_);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Reference in new issue
Block a user