From 70bbc02dac6c4588183612db1fba564473e9b828 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 18 Jun 2024 16:46:54 -0700 Subject: [PATCH] src, deps: add nbytes library Projects that seek to implement Node.js compatible APIs end up needed to reproduce various bits of functionality internally in order to faithfully replicate the Node.js behaviors. This is particularly true for things like byte manipulation, base64 and hex encoding, and other low-level operations. This change proposes moving much of this low-level byte manipulation code out of nodejs/src and into a new `nbytes` library. Initially this new library will exist in the `deps` directory but the intent is to spin out a new separate repository to be its home in the future. Doing so will allow other projects to use the nbytes library with exactly the same implementation as Node.js. This commit moves only the byte swapping and legacy base64 handling code. Additional commits will move additional byte manipulation logic into the library. PR-URL: https://github.com/nodejs/node/pull/53507 Reviewed-By: Yagiz Nizipli Reviewed-By: Robert Nagy Reviewed-By: Chengzhong Wu --- Makefile | 2 +- deps/nbytes/README.md | 5 + deps/nbytes/nbytes.cpp | 251 ++++++++++++++++ deps/nbytes/nbytes.gyp | 16 + src/string_search.h => deps/nbytes/nbytes.h | 314 +++++++++++++++++--- node.gyp | 8 +- src/base64-inl.h | 126 -------- src/base64.h | 49 --- src/cares_wrap.cc | 17 +- src/crypto/crypto_common.cc | 9 +- src/inspector_socket.cc | 6 +- src/node_buffer.cc | 91 +++--- src/node_http2.cc | 6 +- src/node_http_common-inl.h | 3 +- src/node_i18n.cc | 7 +- src/node_metadata.cc | 2 + src/node_metadata.h | 1 + src/node_sockaddr.cc | 9 +- src/quic/cid.cc | 10 +- src/quic/tokens.cc | 11 +- src/spawn_sync.cc | 6 +- src/string_bytes.cc | 172 ++--------- src/string_bytes.h | 7 - src/util-inl.h | 104 ------- src/util.h | 21 -- test/cctest/test_base64.cc | 7 +- test/parallel/test-process-versions.js | 2 + 27 files changed, 669 insertions(+), 593 deletions(-) create mode 100644 deps/nbytes/README.md create mode 100644 deps/nbytes/nbytes.cpp create mode 100644 deps/nbytes/nbytes.gyp rename src/string_search.h => deps/nbytes/nbytes.h (68%) delete mode 100644 src/base64-inl.h delete mode 100644 src/base64.h diff --git a/Makefile b/Makefile index aebae059bdfbef..c718da0b9d7ee6 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ with-code-cache test-code-cache: out/Makefile: config.gypi common.gypi common_node.gypi node.gyp \ deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \ - deps/simdutf/simdutf.gyp deps/ada/ada.gyp \ + deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \ tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \ tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp $(PYTHON) tools/gyp_node.py -f make diff --git a/deps/nbytes/README.md b/deps/nbytes/README.md new file mode 100644 index 00000000000000..9ff412adb30560 --- /dev/null +++ b/deps/nbytes/README.md @@ -0,0 +1,5 @@ +# Node.js bytes (nbytes) library + +The `nbytes` library extracts certain Node.js specific byte manipulation +functions from the core of Node.js itself and makes them available for +use in other projects that need to emulate Node.js' behavior. diff --git a/deps/nbytes/nbytes.cpp b/deps/nbytes/nbytes.cpp new file mode 100644 index 00000000000000..4eb4b6e6aa72a8 --- /dev/null +++ b/deps/nbytes/nbytes.cpp @@ -0,0 +1,251 @@ +#include "nbytes.h" +#include +#include +#include + +namespace nbytes { + +// ============================================================================ +// Byte Swapping + +namespace { +// These are defined by or on some systems. +// To avoid warnings, undefine them before redefining them. +#ifdef BSWAP_2 +# undef BSWAP_2 +#endif +#ifdef BSWAP_4 +# undef BSWAP_4 +#endif +#ifdef BSWAP_8 +# undef BSWAP_8 +#endif + +#if defined(_MSC_VER) +#include +#define BSWAP_2(x) _byteswap_ushort(x) +#define BSWAP_4(x) _byteswap_ulong(x) +#define BSWAP_8(x) _byteswap_uint64(x) +#else +#define BSWAP_2(x) ((x) << 8) | ((x) >> 8) +#define BSWAP_4(x) \ + (((x) & 0xFF) << 24) | \ + (((x) & 0xFF00) << 8) | \ + (((x) >> 8) & 0xFF00) | \ + (((x) >> 24) & 0xFF) +#define BSWAP_8(x) \ + (((x) & 0xFF00000000000000ull) >> 56) | \ + (((x) & 0x00FF000000000000ull) >> 40) | \ + (((x) & 0x0000FF0000000000ull) >> 24) | \ + (((x) & 0x000000FF00000000ull) >> 8) | \ + (((x) & 0x00000000FF000000ull) << 8) | \ + (((x) & 0x0000000000FF0000ull) << 24) | \ + (((x) & 0x000000000000FF00ull) << 40) | \ + (((x) & 0x00000000000000FFull) << 56) +#endif +} // namespace + +bool SwapBytes16(void* data, size_t nbytes) { + if (nbytes % sizeof(uint16_t) != 0) return false; + +#if defined(_MSC_VER) + if (AlignUp(data, sizeof(uint16_t)) == data) { + // MSVC has no strict aliasing, and is able to highly optimize this case. + uint16_t* data16 = reinterpret_cast(data); + size_t len16 = nbytes / sizeof(uint16_t); + for (size_t i = 0; i < len16; i++) { + data16[i] = BSWAP_2(data16[i]); + } + return true; + } +#endif + + uint16_t temp; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint16_t)) { + memcpy(&temp, &ptr[i], sizeof(uint16_t)); + temp = BSWAP_2(temp); + memcpy(&ptr[i], &temp, sizeof(uint16_t)); + } + + return true; +} + +bool SwapBytes32(void* data, size_t nbytes) { + if (nbytes % sizeof(uint32_t) != 0) return false; + +#if defined(_MSC_VER) + // MSVC has no strict aliasing, and is able to highly optimize this case. + if (AlignUp(data, sizeof(uint32_t)) == data) { + uint32_t* data32 = reinterpret_cast(data); + size_t len32 = nbytes / sizeof(uint32_t); + for (size_t i = 0; i < len32; i++) { + data32[i] = BSWAP_4(data32[i]); + } + return true; + } +#endif + + uint32_t temp = 0; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint32_t)) { + memcpy(&temp, &ptr[i], sizeof(uint32_t)); + temp = BSWAP_4(temp); + memcpy(&ptr[i], &temp, sizeof(uint32_t)); + } + + return true; +} + +bool SwapBytes64(void* data, size_t nbytes) { + if (nbytes % sizeof(uint64_t) != 0) return false; + +#if defined(_MSC_VER) + if (AlignUp(data, sizeof(uint64_t)) == data) { + // MSVC has no strict aliasing, and is able to highly optimize this case. + uint64_t* data64 = reinterpret_cast(data); + size_t len64 = nbytes / sizeof(uint64_t); + for (size_t i = 0; i < len64; i++) { + data64[i] = BSWAP_8(data64[i]); + } + return true; + } +#endif + + uint64_t temp = 0; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint64_t)) { + memcpy(&temp, &ptr[i], sizeof(uint64_t)); + temp = BSWAP_8(temp); + memcpy(&ptr[i], &temp, sizeof(uint64_t)); + } + + return true; +} + +// ============================================================================ +// Base64 (legacy) + +// supports regular and URL-safe base64 +const int8_t unbase64_table[256] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + +// ============================================================================ +// Hex + +const int8_t unhex_table[256] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + +size_t HexEncode( + const char* src, + size_t slen, + char* dst, + size_t dlen) { + // We know how much we'll write, just make sure that there's space. + NBYTES_ASSERT_TRUE( + dlen >= MultiplyWithOverflowCheck(slen, 2u) && + "not enough space provided for hex encode"); + + dlen = slen * 2; + for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) { + static const char hex[] = "0123456789abcdef"; + uint8_t val = static_cast(src[i]); + dst[k + 0] = hex[val >> 4]; + dst[k + 1] = hex[val & 15]; + } + + return dlen; +} + +std::string HexEncode(const char* src, size_t slen) { + size_t dlen = slen * 2; + std::string dst(dlen, '\0'); + HexEncode(src, slen, dst.data(), dlen); + return dst; +} + +// ============================================================================ + +void ForceAsciiSlow(const char* src, char* dst, size_t len) { + for (size_t i = 0; i < len; ++i) { + dst[i] = src[i] & 0x7f; + } +} + +void ForceAscii(const char* src, char* dst, size_t len) { + if (len < 16) { + ForceAsciiSlow(src, dst, len); + return; + } + + const unsigned bytes_per_word = sizeof(uintptr_t); + const unsigned align_mask = bytes_per_word - 1; + const unsigned src_unalign = reinterpret_cast(src) & align_mask; + const unsigned dst_unalign = reinterpret_cast(dst) & align_mask; + + if (src_unalign > 0) { + if (src_unalign == dst_unalign) { + const unsigned unalign = bytes_per_word - src_unalign; + ForceAsciiSlow(src, dst, unalign); + src += unalign; + dst += unalign; + len -= src_unalign; + } else { + ForceAsciiSlow(src, dst, len); + return; + } + } + +#if defined(_WIN64) || defined(_LP64) + const uintptr_t mask = ~0x8080808080808080ll; +#else + const uintptr_t mask = ~0x80808080l; +#endif + + const uintptr_t* srcw = reinterpret_cast(src); + uintptr_t* dstw = reinterpret_cast(dst); + + for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { + dstw[i] = srcw[i] & mask; + } + + const unsigned remainder = len & align_mask; + if (remainder > 0) { + const size_t offset = len - remainder; + ForceAsciiSlow(src + offset, dst + offset, remainder); + } +} + +} // namespace nbytes diff --git a/deps/nbytes/nbytes.gyp b/deps/nbytes/nbytes.gyp new file mode 100644 index 00000000000000..0c1b76752e98b5 --- /dev/null +++ b/deps/nbytes/nbytes.gyp @@ -0,0 +1,16 @@ +{ + 'variables': { + 'nbytes_sources': [ 'nbytes.cpp' ], + }, + 'targets': [ + { + 'target_name': 'nbytes', + 'type': 'static_library', + 'include_dirs': ['.'], + 'direct_dependent_settings': { + 'include_dirs': ['.'], + }, + 'sources': [ '<@(nbytes_sources)' ] + }, + ] +} diff --git a/src/string_search.h b/deps/nbytes/nbytes.h similarity index 68% rename from src/string_search.h rename to deps/nbytes/nbytes.h index cd9ef320a81112..7af92ddc3d538e 100644 --- a/src/string_search.h +++ b/deps/nbytes/nbytes.h @@ -1,18 +1,260 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +#pragma once -#ifndef SRC_STRING_SEARCH_H_ -#define SRC_STRING_SEARCH_H_ +#include +#include +#include +#include +#include +#include + +namespace nbytes { + +#if NBYTES_DEVELOPMENT_CHECKS +#define NBYTES_STR(x) #x +#define NBYTES_REQUIRE(EXPR) \ + { \ + if (!(EXPR) { abort(); }) } + +#define NBYTES_FAIL(MESSAGE) \ + do { \ + std::cerr << "FAIL: " << (MESSAGE) << std::endl; \ + abort(); \ + } while (0); +#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) \ + do { \ + if (LHS != RHS) { \ + std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \ + NBYTES_FAIL(MESSAGE); \ + } \ + } while (0); +#define NBYTES_ASSERT_TRUE(COND) \ + do { \ + if (!(COND)) { \ + std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \ + << std::endl; \ + NBYTES_FAIL(NBYTES_STR(COND)); \ + } \ + } while (0); +#else +#define NBYTES_FAIL(MESSAGE) +#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) +#define NBYTES_ASSERT_TRUE(COND) +#endif -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +[[noreturn]] inline void unreachable() { +#ifdef __GNUC__ + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(false); +#else +#endif +} -#include "util.h" +// The nbytes (short for "node bytes") is a set of utility helpers for +// working with bytes that are extracted from Node.js' internals. The +// motivation for extracting these into a separate library is to make it +// easier for other projects to implement functionality that is compatible +// with Node.js' implementation of various byte manipulation functions. -#include -#include +// Round up a to the next highest multiple of b. +template +constexpr T RoundUp(T a, T b) { + return a % b != 0 ? a + b - (a % b) : a; +} + +// Align ptr to an `alignment`-bytes boundary. +template +constexpr T* AlignUp(T* ptr, U alignment) { + return reinterpret_cast( + RoundUp(reinterpret_cast(ptr), alignment)); +} + +template +inline T AlignDown(T value, U alignment) { + return reinterpret_cast( + (reinterpret_cast(value) & ~(alignment - 1))); +} + +template +inline T MultiplyWithOverflowCheck(T a, T b) { + auto ret = a * b; + if (a != 0) { + NBYTES_ASSERT_TRUE(b == ret / a); + } + + return ret; +} + +void ForceAsciiSlow(const char* src, char* dst, size_t len); +void ForceAscii(const char* src, char* dst, size_t len); + +// ============================================================================ +// Byte Swapping + +// Swaps bytes in place. nbytes is the number of bytes to swap and must be a +// multiple of the word size (checked by function). +bool SwapBytes16(void* data, size_t nbytes); +bool SwapBytes32(void* data, size_t nbytes); +bool SwapBytes64(void* data, size_t nbytes); + +// ============================================================================ +// Base64 (legacy) + +#ifdef _MSC_VER +#pragma warning(push) +// MSVC C4003: not enough actual parameters for macro 'identifier' +#pragma warning(disable : 4003) +#endif + +extern const int8_t unbase64_table[256]; + +template +bool Base64DecodeGroupSlow(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + size_t* const i, size_t* const k) { + uint8_t hi; + uint8_t lo; +#define V(expr) \ + for (;;) { \ + const uint8_t c = static_cast(src[*i]); \ + lo = unbase64_table[c]; \ + *i += 1; \ + if (lo < 64) break; /* Legal character. */ \ + if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ + } \ + expr; \ + if (*i >= srclen) return false; \ + if (*k >= dstlen) return false; \ + hi = lo; + V(/* Nothing. */); + V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); + V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); + V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); +#undef V + return true; // Continue decoding. +} + +enum class Base64Mode { + NORMAL, + URL +}; + +inline constexpr size_t Base64EncodedSize( + size_t size, + Base64Mode mode = Base64Mode::NORMAL) { + return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4) + : static_cast(std::ceil( + static_cast(size * 4) / 3)); +} + +// Doesn't check for padding at the end. Can be 1-2 bytes over. +inline constexpr size_t Base64DecodedSizeFast(size_t size) { + // 1-byte input cannot be decoded + return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0; +} + +inline uint32_t ReadUint32BE(const unsigned char* p) { + return static_cast(p[0] << 24U) | + static_cast(p[1] << 16U) | + static_cast(p[2] << 8U) | + static_cast(p[3]); +} + +template +size_t Base64DecodedSize(const TypeName* src, size_t size) { + // 1-byte input cannot be decoded + if (size < 2) + return 0; + + if (src[size - 1] == '=') { + size--; + if (src[size - 1] == '=') + size--; + } + return Base64DecodedSizeFast(size); +} + +template +size_t Base64DecodeFast(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + const size_t decoded_size) { + const size_t available = dstlen < decoded_size ? dstlen : decoded_size; + const size_t max_k = available / 3 * 3; + size_t max_i = srclen / 4 * 4; + size_t i = 0; + size_t k = 0; + while (i < max_i && k < max_k) { + const unsigned char txt[] = { + static_cast(unbase64_table[static_cast(src[i + 0])]), + static_cast(unbase64_table[static_cast(src[i + 1])]), + static_cast(unbase64_table[static_cast(src[i + 2])]), + static_cast(unbase64_table[static_cast(src[i + 3])]), + }; + + const uint32_t v = ReadUint32BE(txt); + // If MSB is set, input contains whitespace or is not valid base64. + if (v & 0x80808080) { + if (!Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k)) + return k; + max_i = i + (srclen - i) / 4 * 4; // Align max_i again. + } else { + dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); + dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); + dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); + i += 4; + k += 3; + } + } + if (i < srclen && k < dstlen) { + Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k); + } + return k; +} + +template +size_t Base64Decode(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen) { + const size_t decoded_size = Base64DecodedSize(src, srclen); + return Base64DecodeFast(dst, dstlen, src, srclen, decoded_size); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// ============================================================================ +// Hex (legacy) + +extern const int8_t unhex_table[256]; + +template +static size_t HexDecode(char* buf, + size_t len, + const TypeName* src, + const size_t srcLen) { + size_t i; + for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { + unsigned a = unhex_table[static_cast(src[i * 2 + 0])]; + unsigned b = unhex_table[static_cast(src[i * 2 + 1])]; + if (!~a || !~b) + return i; + buf[i] = (a << 4) | b; + } + + return i; +} + +size_t HexEncode( + const char* src, + size_t slen, + char* dst, + size_t dlen); + +std::string HexEncode(const char* src, size_t slen); + +// ============================================================================ +// StringSearch -namespace node { namespace stringsearch { template @@ -36,7 +278,7 @@ class Vector { // Access individual vector elements - checks bounds in debug mode. T& operator[](size_t index) const { - DCHECK_LT(index, length_); + NBYTES_ASSERT_TRUE(index < length_); return start_[is_forward_ ? index : (length_ - index - 1)]; } @@ -46,7 +288,6 @@ class Vector { bool is_forward_; }; - //--------------------------------------------------------------------- // String Search object. //--------------------------------------------------------------------- @@ -97,7 +338,7 @@ class StringSearch : private StringSearchBase { } size_t pattern_length = pattern_.length(); - CHECK_GT(pattern_length, 0); + NBYTES_ASSERT_TRUE(pattern_length > 0); if (pattern_length < kBMMinPatternLength) { if (pattern_length == 1) { strategy_ = SearchStrategy::kSingleChar; @@ -122,7 +363,7 @@ class StringSearch : private StringSearchBase { case kSingleChar: return SingleCharSearch(subject, index); } - UNREACHABLE(); + unreachable(); } static inline int AlphabetSize() { @@ -176,23 +417,13 @@ class StringSearch : private StringSearchBase { size_t start_; }; - -template -inline T AlignDown(T value, U alignment) { - return reinterpret_cast( - (reinterpret_cast(value) & ~(alignment - 1))); -} - - inline uint8_t GetHighestValueByte(uint16_t character) { return std::max(static_cast(character & 0xFF), static_cast(character >> 8)); } - inline uint8_t GetHighestValueByte(uint8_t character) { return character; } - // Searches for a byte value in a memory buffer, back to front. // Uses memrchr(3) on systems which support it, for speed. // Falls back to a vanilla for loop on non-GNU systems such as Windows. @@ -211,7 +442,6 @@ inline const void* MemrchrFill(const void* haystack, uint8_t needle, #endif } - // Finds the first occurrence of *two-byte* character pattern[0] in the string // `subject`. Does not check that the whole pattern matches. template @@ -229,12 +459,12 @@ inline size_t FindFirstCharacter(Vector pattern, const void* void_pos; if (subject.forward()) { // Assert that bytes_to_search won't overflow - CHECK_LE(pos, max_n); - CHECK_LE(max_n - pos, SIZE_MAX / sizeof(Char)); + NBYTES_ASSERT_TRUE(pos <= max_n); + NBYTES_ASSERT_TRUE(max_n - pos <= SIZE_MAX / sizeof(Char)); void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search); } else { - CHECK_LE(pos, subject.length()); - CHECK_LE(subject.length() - pos, SIZE_MAX / sizeof(Char)); + NBYTES_ASSERT_TRUE(pos <= subject.length()); + NBYTES_ASSERT_TRUE(subject.length() - pos <= SIZE_MAX / sizeof(Char)); void_pos = MemrchrFill(subject.start() + pattern.length() - 1, search_byte, bytes_to_search); @@ -257,7 +487,6 @@ inline size_t FindFirstCharacter(Vector pattern, return subject.length(); } - // Finds the first occurrence of the byte pattern[0] in string `subject`. // Does not verify that the whole pattern matches. template <> @@ -293,7 +522,7 @@ template size_t StringSearch::SingleCharSearch( Vector subject, size_t index) { - CHECK_EQ(1, pattern_.length()); + NBYTES_ASSERT_TRUE(1 == pattern_.length()); return FindFirstCharacter(pattern_, subject, index); } @@ -306,13 +535,13 @@ template size_t StringSearch::LinearSearch( Vector subject, size_t index) { - CHECK_GT(pattern_.length(), 1); + NBYTES_ASSERT_TRUE(pattern_.length() > 1); const size_t n = subject.length() - pattern_.length(); for (size_t i = index; i <= n; i++) { i = FindFirstCharacter(pattern_, subject, i); if (i == subject.length()) return subject.length(); - CHECK_LE(i, n); + NBYTES_ASSERT_TRUE(i <= n); bool matches = true; for (size_t j = 1; j < pattern_.length(); j++) { @@ -553,7 +782,7 @@ size_t StringSearch::InitialSearch( i = FindFirstCharacter(pattern_, subject, i); if (i == subject.length()) return subject.length(); - CHECK_LE(i, n); + NBYTES_ASSERT_TRUE(i <= n); size_t j = 1; do { if (pattern_[j] != subject[i + j]) { @@ -586,9 +815,6 @@ size_t SearchString(Vector subject, return search.Search(subject, start_index); } } // namespace stringsearch -} // namespace node - -namespace node { template size_t SearchString(const Char* haystack, @@ -614,7 +840,7 @@ size_t SearchString(const Char* haystack, } else { relative_start_index = diff - start_index; } - size_t pos = node::stringsearch::SearchString( + size_t pos = stringsearch::SearchString( v_haystack, v_needle, relative_start_index); if (pos == haystack_length) { // not found @@ -631,8 +857,14 @@ size_t SearchString(const char* haystack, size_t haystack_length, reinterpret_cast(needle), N - 1, 0, true); } -} // namespace node +// ============================================================================ +// Version metadata +#define NBYTES_VERSION "0.0.1" -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +enum { + NBYTES_VERSION_MAJOR = 0, + NBYTES_VERSION_MINOR = 0, + NBYTES_VERSION_REVISION = 1, +}; -#endif // SRC_STRING_SEARCH_H_ +} // namespace nbytes diff --git a/node.gyp b/node.gyp index d9706ca3e99909..9e0d48a910fb5a 100644 --- a/node.gyp +++ b/node.gyp @@ -187,8 +187,6 @@ 'src/base_object.h', 'src/base_object-inl.h', 'src/base_object_types.h', - 'src/base64.h', - 'src/base64-inl.h', 'src/blob_serializer_deserializer.h', 'src/blob_serializer_deserializer-inl.h', 'src/callback_queue.h', @@ -293,7 +291,6 @@ 'src/string_bytes.h', 'src/string_decoder.h', 'src/string_decoder-inl.h', - 'src/string_search.h', 'src/tcp_wrap.h', 'src/timers.h', 'src/tracing/agent.h', @@ -854,6 +851,7 @@ 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', 'node_js2c#host', ], @@ -1130,6 +1128,7 @@ 'deps/sqlite/sqlite.gyp:sqlite', 'deps/uvwasi/uvwasi.gyp:uvwasi', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ 'node.gypi' @@ -1180,6 +1179,7 @@ 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ @@ -1256,6 +1256,7 @@ 'deps/histogram/histogram.gyp:histogram', 'deps/sqlite/sqlite.gyp:sqlite', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ @@ -1371,6 +1372,7 @@ 'deps/histogram/histogram.gyp:histogram', 'deps/sqlite/sqlite.gyp:sqlite', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', ], diff --git a/src/base64-inl.h b/src/base64-inl.h deleted file mode 100644 index 20a2f233ae9f35..00000000000000 --- a/src/base64-inl.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef SRC_BASE64_INL_H_ -#define SRC_BASE64_INL_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "base64.h" -#include "util.h" - -namespace node { - -extern const int8_t unbase64_table[256]; - - -inline static int8_t unbase64(uint8_t x) { - return unbase64_table[x]; -} - - -inline uint32_t ReadUint32BE(const unsigned char* p) { - return static_cast(p[0] << 24U) | - static_cast(p[1] << 16U) | - static_cast(p[2] << 8U) | - static_cast(p[3]); -} - -#ifdef _MSC_VER -#pragma warning(push) -// MSVC C4003: not enough actual parameters for macro 'identifier' -#pragma warning(disable : 4003) -#endif - -template -bool base64_decode_group_slow(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - size_t* const i, size_t* const k) { - uint8_t hi; - uint8_t lo; -#define V(expr) \ - for (;;) { \ - const uint8_t c = static_cast(src[*i]); \ - lo = unbase64(c); \ - *i += 1; \ - if (lo < 64) break; /* Legal character. */ \ - if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ - } \ - expr; \ - if (*i >= srclen) return false; \ - if (*k >= dstlen) return false; \ - hi = lo; - V(/* Nothing. */); - V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); - V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); - V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); -#undef V - return true; // Continue decoding. -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -template -size_t base64_decode_fast(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - const size_t decoded_size) { - const size_t available = dstlen < decoded_size ? dstlen : decoded_size; - const size_t max_k = available / 3 * 3; - size_t max_i = srclen / 4 * 4; - size_t i = 0; - size_t k = 0; - while (i < max_i && k < max_k) { - const unsigned char txt[] = { - static_cast(unbase64(static_cast(src[i + 0]))), - static_cast(unbase64(static_cast(src[i + 1]))), - static_cast(unbase64(static_cast(src[i + 2]))), - static_cast(unbase64(static_cast(src[i + 3]))), - }; - - const uint32_t v = ReadUint32BE(txt); - // If MSB is set, input contains whitespace or is not valid base64. - if (v & 0x80808080) { - if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) - return k; - max_i = i + (srclen - i) / 4 * 4; // Align max_i again. - } else { - dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); - dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); - dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); - i += 4; - k += 3; - } - } - if (i < srclen && k < dstlen) { - base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); - } - return k; -} - - -template -size_t base64_decoded_size(const TypeName* src, size_t size) { - // 1-byte input cannot be decoded - if (size < 2) - return 0; - - if (src[size - 1] == '=') { - size--; - if (src[size - 1] == '=') - size--; - } - return base64_decoded_size_fast(size); -} - - -template -size_t base64_decode(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen) { - const size_t decoded_size = base64_decoded_size(src, srclen); - return base64_decode_fast(dst, dstlen, src, srclen, decoded_size); -} - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_BASE64_INL_H_ diff --git a/src/base64.h b/src/base64.h deleted file mode 100644 index c59a8bb50637c8..00000000000000 --- a/src/base64.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SRC_BASE64_H_ -#define SRC_BASE64_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "util.h" - -#include -#include -#include - -namespace node { -//// Base 64 //// - -enum class Base64Mode { - NORMAL, - URL -}; - -static inline constexpr size_t base64_encoded_size( - size_t size, - Base64Mode mode = Base64Mode::NORMAL) { - return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4) - : static_cast(std::ceil( - static_cast(size * 4) / 3)); -} - -// Doesn't check for padding at the end. Can be 1-2 bytes over. -static inline constexpr size_t base64_decoded_size_fast(size_t size) { - // 1-byte input cannot be decoded - return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0; -} - -inline uint32_t ReadUint32BE(const unsigned char* p); - -template -size_t base64_decoded_size(const TypeName* src, size_t size); - -template -size_t base64_decode(char* const dst, - const size_t dstlen, - const TypeName* const src, - const size_t srclen); -} // namespace node - - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_BASE64_H_ diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 299802238732df..26877f3ddd8f69 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -22,10 +22,10 @@ #include "cares_wrap.h" #include "ada.h" #include "async_wrap-inl.h" -#include "base64-inl.h" #include "base_object-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node.h" #include "node_errors.h" #include "node_external_reference.h" @@ -591,11 +591,11 @@ int ParseSoaReply( return ARES_EBADRESP; } - const unsigned int serial = ReadUint32BE(ptr + 0 * 4); - const unsigned int refresh = ReadUint32BE(ptr + 1 * 4); - const unsigned int retry = ReadUint32BE(ptr + 2 * 4); - const unsigned int expire = ReadUint32BE(ptr + 3 * 4); - const unsigned int minttl = ReadUint32BE(ptr + 4 * 4); + const unsigned int serial = nbytes::ReadUint32BE(ptr + 0 * 4); + const unsigned int refresh = nbytes::ReadUint32BE(ptr + 1 * 4); + const unsigned int retry = nbytes::ReadUint32BE(ptr + 2 * 4); + const unsigned int expire = nbytes::ReadUint32BE(ptr + 3 * 4); + const unsigned int minttl = nbytes::ReadUint32BE(ptr + 4 * 4); Local soa_record = Object::New(env->isolate()); soa_record->Set(env->context(), @@ -1801,7 +1801,7 @@ void SetLocalAddress(const FunctionCallbackInfo& args) { // to 0 (any). if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) { - ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr0)); + ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0)); type0 = 4; } else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) { ares_set_local_ip6(channel->cares_channel(), addr0); @@ -1820,7 +1820,8 @@ void SetLocalAddress(const FunctionCallbackInfo& args) { THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses."); return; } else { - ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr1)); + ares_set_local_ip4(channel->cares_channel(), + nbytes::ReadUint32BE(addr1)); } } else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) { if (type0 == 6) { diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc index 962018583360a1..4da42cf4147bf6 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc @@ -2,6 +2,7 @@ #include "base_object-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node.h" #include "node_buffer.h" #include "node_crypto.h" @@ -90,10 +91,10 @@ void LogSecret( } std::string line = name; - line += " " + StringBytes::hex_encode(reinterpret_cast(crandom), - kTlsClientRandomSize); - line += " " + StringBytes::hex_encode( - reinterpret_cast(secret), secretlen); + line += " " + nbytes::HexEncode(reinterpret_cast(crandom), + kTlsClientRandomSize); + line += + " " + nbytes::HexEncode(reinterpret_cast(secret), secretlen); keylog_cb(ssl.get(), line.c_str()); } diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc index b6059b49410868..5246b9170a7a78 100644 --- a/src/inspector_socket.cc +++ b/src/inspector_socket.cc @@ -1,7 +1,7 @@ #include "inspector_socket.h" #include "llhttp.h" -#include "base64.h" +#include "nbytes.h" #include "simdutf.h" #include "util-inl.h" @@ -11,7 +11,7 @@ #include #include -#define ACCEPT_KEY_LENGTH base64_encoded_size(20) +#define ACCEPT_KEY_LENGTH nbytes::Base64EncodedSize(20) #define DUMP_READS 0 #define DUMP_WRITES 0 @@ -149,7 +149,7 @@ static void generate_accept_string(const std::string& client_key, std::string input(client_key + ws_magic); char hash[SHA_DIGEST_LENGTH]; - CHECK(ACCEPT_KEY_LENGTH >= base64_encoded_size(SHA_DIGEST_LENGTH) && + CHECK(ACCEPT_KEY_LENGTH >= nbytes::Base64EncodedSize(SHA_DIGEST_LENGTH) && "not enough space provided for base64 encode"); USE(SHA1(reinterpret_cast(input.data()), input.size(), diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 871324f687617a..02a6a79492cf12 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -30,13 +30,14 @@ #include "env-inl.h" #include "simdutf.h" #include "string_bytes.h" -#include "string_search.h" + #include "util-inl.h" #include "v8-fast-api-calls.h" #include "v8.h" -#include #include +#include +#include "nbytes.h" #define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \ THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument") \ @@ -667,7 +668,7 @@ void Fill(const FunctionCallbackInfo& args) { str_length = str_obj->Length() * sizeof(uint16_t); node::TwoByteValue str(env->isolate(), args[1]); if constexpr (IsBigEndian()) - SwapBytes16(reinterpret_cast(&str[0]), str_length); + CHECK(nbytes::SwapBytes16(reinterpret_cast(&str[0]), str_length)); memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length)); @@ -969,19 +970,20 @@ void IndexOfString(const FunctionCallbackInfo& args) { if (decoded_string == nullptr) return args.GetReturnValue().Set(-1); - result = SearchString(reinterpret_cast(haystack), - haystack_length / 2, - decoded_string, - decoder.size() / 2, - offset / 2, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + decoded_string, + decoder.size() / 2, + offset / 2, + is_forward); } else { - result = SearchString(reinterpret_cast(haystack), - haystack_length / 2, - reinterpret_cast(*needle_value), - needle_value.length(), - offset / 2, - is_forward); + result = + nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + reinterpret_cast(*needle_value), + needle_value.length(), + offset / 2, + is_forward); } result *= 2; } else if (enc == UTF8) { @@ -989,12 +991,13 @@ void IndexOfString(const FunctionCallbackInfo& args) { if (*needle_value == nullptr) return args.GetReturnValue().Set(-1); - result = SearchString(reinterpret_cast(haystack), - haystack_length, - reinterpret_cast(*needle_value), - needle_length, - offset, - is_forward); + result = + nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + reinterpret_cast(*needle_value), + needle_length, + offset, + is_forward); } else if (enc == LATIN1) { uint8_t* needle_data = node::UncheckedMalloc(needle_length); if (needle_data == nullptr) { @@ -1003,12 +1006,12 @@ void IndexOfString(const FunctionCallbackInfo& args) { needle->WriteOneByte( isolate, needle_data, 0, needle_length, String::NO_NULL_TERMINATION); - result = SearchString(reinterpret_cast(haystack), - haystack_length, - needle_data, - needle_length, - offset, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + needle_data, + needle_length, + offset, + is_forward); free(needle_data); } @@ -1067,22 +1070,20 @@ void IndexOfBuffer(const FunctionCallbackInfo& args) { if (haystack_length < 2 || needle_length < 2) { return args.GetReturnValue().Set(-1); } - result = SearchString( - reinterpret_cast(haystack), - haystack_length / 2, - reinterpret_cast(needle), - needle_length / 2, - offset / 2, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + reinterpret_cast(needle), + needle_length / 2, + offset / 2, + is_forward); result *= 2; } else { - result = SearchString( - reinterpret_cast(haystack), - haystack_length, - reinterpret_cast(needle), - needle_length, - offset, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + reinterpret_cast(needle), + needle_length, + offset, + is_forward); } args.GetReturnValue().Set( @@ -1105,7 +1106,7 @@ int32_t IndexOfNumber(const uint8_t* buffer_data, if (is_forward) { ptr = memchr(buffer_data + offset, needle, buffer_length - offset); } else { - ptr = node::stringsearch::MemrchrFill(buffer_data, needle, offset + 1); + ptr = nbytes::stringsearch::MemrchrFill(buffer_data, needle, offset + 1); } const uint8_t* ptr_uint8 = static_cast(ptr); return ptr != nullptr ? static_cast(ptr_uint8 - buffer_data) : -1; @@ -1145,7 +1146,7 @@ void Swap16(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes16(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes16(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } @@ -1154,7 +1155,7 @@ void Swap32(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes32(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes32(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } @@ -1163,7 +1164,7 @@ void Swap64(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes64(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes64(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } diff --git a/src/node_http2.cc b/src/node_http2.cc index 56297ba2a3b909..50636d24763078 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -13,6 +13,8 @@ #include "stream_base-inl.h" #include "util-inl.h" +#include "nbytes.h" + #include #include #include @@ -455,8 +457,8 @@ Origins::Origins( } // Make sure the start address is aligned appropriately for an nghttp2_nv*. - char* start = AlignUp(static_cast(bs_->Data()), - alignof(nghttp2_origin_entry)); + char* start = nbytes::AlignUp(static_cast(bs_->Data()), + alignof(nghttp2_origin_entry)); char* origin_contents = start + (count_ * sizeof(nghttp2_origin_entry)); nghttp2_origin_entry* const nva = reinterpret_cast(start); diff --git a/src/node_http_common-inl.h b/src/node_http_common-inl.h index e78a6fdd2f95bd..dba1a5e051b3e0 100644 --- a/src/node_http_common-inl.h +++ b/src/node_http_common-inl.h @@ -8,6 +8,7 @@ #include "v8.h" #include +#include "nbytes.h" namespace node { @@ -31,7 +32,7 @@ NgHeaders::NgHeaders(Environment* env, v8::Local headers) { count_ * sizeof(nv_t) + header_string_len); - char* start = AlignUp(buf_.out(), alignof(nv_t)); + char* start = nbytes::AlignUp(buf_.out(), alignof(nv_t)); char* header_contents = start + (count_ * sizeof(nv_t)); nv_t* const nva = reinterpret_cast(start); diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 743ea8c872cef4..7a13f35d2f2bcb 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -69,6 +69,7 @@ #include #include #include +#include "nbytes.h" #ifdef NODE_HAVE_SMALL_ICU /* if this is defined, we have a 'secondary' entry point. @@ -113,7 +114,7 @@ MaybeLocal ToBufferEndian(Environment* env, MaybeStackBuffer* buf) { "Currently only one- or two-byte buffers are supported"); if constexpr (sizeof(T) > 1 && IsBigEndian()) { SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf); - SwapBytes16(retbuf_data, retbuf_length); + CHECK(nbytes::SwapBytes16(retbuf_data, retbuf_length)); } return ret; @@ -129,7 +130,7 @@ void CopySourceBuffer(MaybeStackBuffer* dest, char* dst = reinterpret_cast(**dest); memcpy(dst, data, length); if constexpr (IsBigEndian()) { - SwapBytes16(dst, length); + CHECK(nbytes::SwapBytes16(dst, length)); } } @@ -528,7 +529,7 @@ void ConverterObject::Decode(const FunctionCallbackInfo& args) { char* value = reinterpret_cast(output) + beginning; if constexpr (IsBigEndian()) { - SwapBytes16(value, length); + CHECK(nbytes::SwapBytes16(value, length)); } MaybeLocal encoded = diff --git a/src/node_metadata.cc b/src/node_metadata.cc index 98c0443b15b757..56d99f529f7a93 100644 --- a/src/node_metadata.cc +++ b/src/node_metadata.cc @@ -5,6 +5,7 @@ #include "brotli/encode.h" #include "cjs_module_lexer_version.h" #include "llhttp.h" +#include "nbytes.h" #include "nghttp2/nghttp2ver.h" #include "node.h" #include "simdjson.h" @@ -133,6 +134,7 @@ Metadata::Versions::Versions() { simdutf = SIMDUTF_VERSION; sqlite = SQLITE_VERSION; ada = ADA_VERSION; + nbytes = NBYTES_VERSION; } Metadata::Release::Release() : name(NODE_RELEASE) { diff --git a/src/node_metadata.h b/src/node_metadata.h index 5400220424e8d7..90c7dbf22c8e85 100644 --- a/src/node_metadata.h +++ b/src/node_metadata.h @@ -50,6 +50,7 @@ namespace node { V(simdutf) \ V(sqlite) \ V(ada) \ + V(nbytes) \ NODE_VERSIONS_KEY_UNDICI(V) \ V(cjs_module_lexer) diff --git a/src/node_sockaddr.cc b/src/node_sockaddr.cc index 99af64d7259d48..e1572187437f1b 100644 --- a/src/node_sockaddr.cc +++ b/src/node_sockaddr.cc @@ -1,9 +1,10 @@ -#include "node_sockaddr-inl.h" // NOLINT(build/include) -#include "env-inl.h" -#include "base64-inl.h" +#include "node_sockaddr.h" // NOLINT(build/include_inline) #include "base_object-inl.h" +#include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node_errors.h" +#include "node_sockaddr-inl.h" // NOLINT(build/include_inline) #include "uv.h" #include @@ -308,7 +309,7 @@ bool in_network_ipv6_ipv4( return false; ptr += sizeof(mask); - uint32_t check = ReadUint32BE(ptr); + uint32_t check = nbytes::ReadUint32BE(ptr); return (check & m) == (htonl(net_in->sin_addr.s_addr) & m); } diff --git a/src/quic/cid.cc b/src/quic/cid.cc index 7c30d0d542aeaf..404b98c47d6c19 100644 --- a/src/quic/cid.cc +++ b/src/quic/cid.cc @@ -4,6 +4,7 @@ #include #include #include +#include "nbytes.h" #include "quic/defs.h" namespace node { @@ -71,11 +72,10 @@ size_t CID::length() const { std::string CID::ToString() const { char dest[kMaxLength * 2]; - size_t written = - StringBytes::hex_encode(reinterpret_cast(ptr_->data), - ptr_->datalen, - dest, - arraysize(dest)); + size_t written = nbytes::HexEncode(reinterpret_cast(ptr_->data), + ptr_->datalen, + dest, + arraysize(dest)); return std::string(dest, written); } diff --git a/src/quic/tokens.cc b/src/quic/tokens.cc index 9ffdab2575cb42..e2c03d49c1b32f 100644 --- a/src/quic/tokens.cc +++ b/src/quic/tokens.cc @@ -7,6 +7,7 @@ #include #include #include +#include "nbytes.h" namespace node { namespace quic { @@ -49,8 +50,8 @@ TokenSecret::operator const char*() const { std::string TokenSecret::ToString() const { char dest[QUIC_TOKENSECRET_LEN * 2]; - size_t written = StringBytes::hex_encode( - *this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest)); + size_t written = + nbytes::HexEncode(*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest)); DCHECK_EQ(written, arraysize(dest)); return std::string(dest, written); } @@ -117,7 +118,7 @@ std::string StatelessResetToken::ToString() const { if (ptr_ == nullptr) return std::string(); char dest[kStatelessTokenLen * 2]; size_t written = - StringBytes::hex_encode(*this, kStatelessTokenLen, dest, arraysize(dest)); + nbytes::HexEncode(*this, kStatelessTokenLen, dest, arraysize(dest)); DCHECK_EQ(written, arraysize(dest)); return std::string(dest, written); } @@ -230,7 +231,7 @@ std::string RetryToken::ToString() const { if (ptr_.base == nullptr) return std::string(); MaybeStackBuffer dest(ptr_.len * 2); size_t written = - StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length()); + nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length()); DCHECK_EQ(written, dest.length()); return std::string(dest.out(), written); } @@ -289,7 +290,7 @@ std::string RegularToken::ToString() const { if (ptr_.base == nullptr) return std::string(); MaybeStackBuffer dest(ptr_.len * 2); size_t written = - StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length()); + nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length()); DCHECK_EQ(written, dest.length()); return std::string(dest.out(), written); } diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index d03803fe3abc5b..36570d069ad00b 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -28,7 +28,7 @@ #include "util-inl.h" #include - +#include "nbytes.h" namespace node { @@ -1069,7 +1069,7 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, Maybe maybe_size = StringBytes::StorageSize(isolate, value, UTF8); if (maybe_size.IsNothing()) return Nothing(); data_size += maybe_size.FromJust() + 1; - data_size = RoundUp(data_size, sizeof(void*)); + data_size = nbytes::RoundUp(data_size, sizeof(void*)); } buffer = new char[list_size + data_size]; @@ -1086,7 +1086,7 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, value, UTF8); buffer[data_offset++] = '\0'; - data_offset = RoundUp(data_offset, sizeof(void*)); + data_offset = nbytes::RoundUp(data_offset, sizeof(void*)); } list[length] = nullptr; diff --git a/src/string_bytes.cc b/src/string_bytes.cc index 94e6079023284d..3e2b29005a2012 100644 --- a/src/string_bytes.cc +++ b/src/string_bytes.cc @@ -21,8 +21,8 @@ #include "string_bytes.h" -#include "base64-inl.h" #include "env-inl.h" +#include "nbytes.h" #include "node_buffer.h" #include "node_errors.h" #include "simdutf.h" @@ -200,67 +200,6 @@ MaybeLocal ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate, } // anonymous namespace -// supports regular and URL-safe base64 -const int8_t unbase64_table[256] = - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - -static const int8_t unhex_table[256] = - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - -static inline unsigned unhex(uint8_t x) { - return unhex_table[x]; -} - -template -static size_t hex_decode(char* buf, - size_t len, - const TypeName* src, - const size_t srcLen) { - size_t i; - for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { - unsigned a = unhex(static_cast(src[i * 2 + 0])); - unsigned b = unhex(static_cast(src[i * 2 + 1])); - if (!~a || !~b) - return i; - buf[i] = (a << 4) | b; - } - - return i; -} - size_t StringBytes::WriteUCS2( Isolate* isolate, char* buf, size_t buflen, Local str, int flags) { uint16_t* const dst = reinterpret_cast(buf); @@ -270,7 +209,7 @@ size_t StringBytes::WriteUCS2( return 0; } - uint16_t* const aligned_dst = AlignUp(dst, sizeof(*dst)); + uint16_t* const aligned_dst = nbytes::AlignUp(dst, sizeof(*dst)); size_t nchars; if (aligned_dst == dst) { nchars = str->Write(isolate, dst, 0, max_chars, flags); @@ -339,7 +278,7 @@ size_t StringBytes::Write(Isolate* isolate, // the Buffer, so we need to reorder on BE platforms. See // https://nodejs.org/api/buffer.html regarding Node's "ucs2" // encoding specification - if constexpr (IsBigEndian()) SwapBytes16(buf, nbytes); + if constexpr (IsBigEndian()) CHECK(nbytes::SwapBytes16(buf, nbytes)); break; } @@ -356,7 +295,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // adapted for base64url // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, ext->data(), ext->length()); + nbytes = + nbytes::Base64Decode(buf, buflen, ext->data(), ext->length()); } } else if (str->IsOneByte()) { MaybeStackBuffer stack_buf(str->Length()); @@ -378,7 +318,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length()); + nbytes = + nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length()); } } else { String::Value value(isolate, str); @@ -395,7 +336,7 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length()); } } break; @@ -411,7 +352,8 @@ size_t StringBytes::Write(Isolate* isolate, } else { // The input does not follow the WHATWG forgiving-base64 specification // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, ext->data(), ext->length()); + nbytes = + nbytes::Base64Decode(buf, buflen, ext->data(), ext->length()); } } else if (str->IsOneByte()) { MaybeStackBuffer stack_buf(str->Length()); @@ -432,7 +374,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length()); + nbytes = + nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length()); } } else { String::Value value(isolate, str); @@ -447,7 +390,7 @@ size_t StringBytes::Write(Isolate* isolate, } else { // The input does not follow the WHATWG base64 specification // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length()); } } break; @@ -455,10 +398,10 @@ size_t StringBytes::Write(Isolate* isolate, case HEX: if (str->IsExternalOneByte()) { auto ext = str->GetExternalOneByteStringResource(); - nbytes = hex_decode(buf, buflen, ext->data(), ext->length()); + nbytes = nbytes::HexDecode(buf, buflen, ext->data(), ext->length()); } else { String::Value value(isolate, str); - nbytes = hex_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::HexDecode(buf, buflen, *value, value.length()); } break; @@ -568,85 +511,6 @@ Maybe StringBytes::Size(Isolate* isolate, UNREACHABLE(); } -static void force_ascii_slow(const char* src, char* dst, size_t len) { - for (size_t i = 0; i < len; ++i) { - dst[i] = src[i] & 0x7f; - } -} - - -static void force_ascii(const char* src, char* dst, size_t len) { - if (len < 16) { - force_ascii_slow(src, dst, len); - return; - } - - const unsigned bytes_per_word = sizeof(uintptr_t); - const unsigned align_mask = bytes_per_word - 1; - const unsigned src_unalign = reinterpret_cast(src) & align_mask; - const unsigned dst_unalign = reinterpret_cast(dst) & align_mask; - - if (src_unalign > 0) { - if (src_unalign == dst_unalign) { - const unsigned unalign = bytes_per_word - src_unalign; - force_ascii_slow(src, dst, unalign); - src += unalign; - dst += unalign; - len -= src_unalign; - } else { - force_ascii_slow(src, dst, len); - return; - } - } - -#if defined(_WIN64) || defined(_LP64) - const uintptr_t mask = ~0x8080808080808080ll; -#else - const uintptr_t mask = ~0x80808080l; -#endif - - const uintptr_t* srcw = reinterpret_cast(src); - uintptr_t* dstw = reinterpret_cast(dst); - - for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { - dstw[i] = srcw[i] & mask; - } - - const unsigned remainder = len & align_mask; - if (remainder > 0) { - const size_t offset = len - remainder; - force_ascii_slow(src + offset, dst + offset, remainder); - } -} - - -size_t StringBytes::hex_encode( - const char* src, - size_t slen, - char* dst, - size_t dlen) { - // We know how much we'll write, just make sure that there's space. - CHECK(dlen >= MultiplyWithOverflowCheck(slen, 2u) && - "not enough space provided for hex encode"); - - dlen = slen * 2; - for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) { - static const char hex[] = "0123456789abcdef"; - uint8_t val = static_cast(src[i]); - dst[k + 0] = hex[val >> 4]; - dst[k + 1] = hex[val & 15]; - } - - return dlen; -} - -std::string StringBytes::hex_encode(const char* src, size_t slen) { - size_t dlen = slen * 2; - std::string dst(dlen, '\0'); - hex_encode(src, slen, dst.data(), dlen); - return dst; -} - #define CHECK_BUFLEN_IN_RANGE(len) \ do { \ if ((len) > Buffer::kMaxLength) { \ @@ -688,7 +552,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); return MaybeLocal(); } - force_ascii(buf, out, buflen); + nbytes::ForceAscii(buf, out, buflen); return ExternOneByteString::New(isolate, out, buflen, error); } else { return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error); @@ -747,7 +611,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); return MaybeLocal(); } - size_t written = hex_encode(buf, buflen, dst, dlen); + size_t written = nbytes::HexEncode(buf, buflen, dst, dlen); CHECK_EQ(written, dlen); return ExternOneByteString::New(isolate, dst, dlen, error); @@ -810,7 +674,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, } size_t nbytes = buflen * sizeof(uint16_t); memcpy(dst, buf, nbytes); - SwapBytes16(reinterpret_cast(dst), nbytes); + CHECK(nbytes::SwapBytes16(reinterpret_cast(dst), nbytes)); return ExternTwoByteString::New(isolate, dst, buflen, error); } else { return ExternTwoByteString::NewFromCopy(isolate, buf, buflen, error); diff --git a/src/string_bytes.h b/src/string_bytes.h index ad1f15b05704c8..fde5070ffb66a7 100644 --- a/src/string_bytes.h +++ b/src/string_bytes.h @@ -98,13 +98,6 @@ class StringBytes { enum encoding encoding, v8::Local* error); - static size_t hex_encode(const char* src, - size_t slen, - char* dst, - size_t dlen); - - static std::string hex_encode(const char* src, size_t slen); - private: static size_t WriteUCS2(v8::Isolate* isolate, char* buf, diff --git a/src/util-inl.h b/src/util-inl.h index 463f982c91c71b..88d0cfee7f257f 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -30,41 +30,6 @@ #include "node_revert.h" #include "util.h" -// These are defined by or on some systems. -// To avoid warnings, undefine them before redefining them. -#ifdef BSWAP_2 -# undef BSWAP_2 -#endif -#ifdef BSWAP_4 -# undef BSWAP_4 -#endif -#ifdef BSWAP_8 -# undef BSWAP_8 -#endif - -#if defined(_MSC_VER) -#include -#define BSWAP_2(x) _byteswap_ushort(x) -#define BSWAP_4(x) _byteswap_ulong(x) -#define BSWAP_8(x) _byteswap_uint64(x) -#else -#define BSWAP_2(x) ((x) << 8) | ((x) >> 8) -#define BSWAP_4(x) \ - (((x) & 0xFF) << 24) | \ - (((x) & 0xFF00) << 8) | \ - (((x) >> 8) & 0xFF00) | \ - (((x) >> 24) & 0xFF) -#define BSWAP_8(x) \ - (((x) & 0xFF00000000000000ull) >> 56) | \ - (((x) & 0x00FF000000000000ull) >> 40) | \ - (((x) & 0x0000FF0000000000ull) >> 24) | \ - (((x) & 0x000000FF00000000ull) >> 8) | \ - (((x) & 0x00000000FF000000ull) << 8) | \ - (((x) & 0x0000000000FF0000ull) << 24) | \ - (((x) & 0x000000000000FF00ull) << 40) | \ - (((x) & 0x00000000000000FFull) << 56) -#endif - #define CHAR_TEST(bits, name, expr) \ template \ bool name(const T ch) { \ @@ -214,75 +179,6 @@ inline v8::Local OneByteString(v8::Isolate* isolate, .ToLocalChecked(); } -void SwapBytes16(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 2, 0); - -#if defined(_MSC_VER) - if (AlignUp(data, sizeof(uint16_t)) == data) { - // MSVC has no strict aliasing, and is able to highly optimize this case. - uint16_t* data16 = reinterpret_cast(data); - size_t len16 = nbytes / sizeof(*data16); - for (size_t i = 0; i < len16; i++) { - data16[i] = BSWAP_2(data16[i]); - } - return; - } -#endif - - uint16_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_2(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - -void SwapBytes32(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 4, 0); - -#if defined(_MSC_VER) - // MSVC has no strict aliasing, and is able to highly optimize this case. - if (AlignUp(data, sizeof(uint32_t)) == data) { - uint32_t* data32 = reinterpret_cast(data); - size_t len32 = nbytes / sizeof(*data32); - for (size_t i = 0; i < len32; i++) { - data32[i] = BSWAP_4(data32[i]); - } - return; - } -#endif - - uint32_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_4(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - -void SwapBytes64(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 8, 0); - -#if defined(_MSC_VER) - if (AlignUp(data, sizeof(uint64_t)) == data) { - // MSVC has no strict aliasing, and is able to highly optimize this case. - uint64_t* data64 = reinterpret_cast(data); - size_t len64 = nbytes / sizeof(*data64); - for (size_t i = 0; i < len64; i++) { - data64[i] = BSWAP_8(data64[i]); - } - return; - } -#endif - - uint64_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_8(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - char ToLower(char c) { return std::tolower(c, std::locale::classic()); } diff --git a/src/util.h b/src/util.h index a0cee453ee43a7..d3ad830e162a36 100644 --- a/src/util.h +++ b/src/util.h @@ -358,14 +358,6 @@ inline v8::Local FIXED_ONE_BYTE_STRING( return OneByteString(isolate, arr.data(), N - 1); } - - -// Swaps bytes in place. nbytes is the number of bytes to swap and must be a -// multiple of the word size (checked by function). -inline void SwapBytes16(char* data, size_t nbytes); -inline void SwapBytes32(char* data, size_t nbytes); -inline void SwapBytes64(char* data, size_t nbytes); - // tolower() is locale-sensitive. Use ToLower() instead. inline char ToLower(char c); inline std::string ToLower(const std::string& in); @@ -794,19 +786,6 @@ constexpr inline bool IsBigEndian() { static_assert(IsLittleEndian() || IsBigEndian(), "Node.js does not support mixed-endian systems"); -// Round up a to the next highest multiple of b. -template -constexpr T RoundUp(T a, T b) { - return a % b != 0 ? a + b - (a % b) : a; -} - -// Align ptr to an `alignment`-bytes boundary. -template -constexpr T* AlignUp(T* ptr, U alignment) { - return reinterpret_cast( - RoundUp(reinterpret_cast(ptr), alignment)); -} - class SlicedArguments : public MaybeStackBuffer> { public: inline explicit SlicedArguments( diff --git a/test/cctest/test_base64.cc b/test/cctest/test_base64.cc index ce960a6fc8dd56..4f1bc9173b6818 100644 --- a/test/cctest/test_base64.cc +++ b/test/cctest/test_base64.cc @@ -1,13 +1,12 @@ -#include "base64-inl.h" +#include "nbytes.h" #include "simdutf.h" +#include "util-inl.h" #include #include #include "gtest/gtest.h" -using node::base64_decode; - TEST(Base64Test, Encode) { auto test = [](const char* string, const char* base64_string) { const size_t len = strlen(base64_string); @@ -70,7 +69,7 @@ TEST(Base64Test, Decode) { const size_t len = strlen(string); char* const buffer = new char[len + 1]; buffer[len] = 0; - base64_decode(buffer, len, base64_string, strlen(base64_string)); + nbytes::Base64Decode(buffer, len, base64_string, strlen(base64_string)); EXPECT_STREQ(string, buffer); delete[] buffer; }; diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index 374c339cd814f5..bab483a7e2637e 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -23,6 +23,7 @@ const expected_keys = [ 'sqlite', 'ada', 'cjs_module_lexer', + 'nbytes', ]; const hasUndici = process.config.variables.node_builtin_shareable_builtins.includes('deps/undici/undici.js'); @@ -62,6 +63,7 @@ assert.match(process.versions.brotli, commonTemplate); assert.match(process.versions.llhttp, commonTemplate); assert.match(process.versions.node, commonTemplate); assert.match(process.versions.uv, commonTemplate); +assert.match(process.versions.nbytes, commonTemplate); assert.match(process.versions.zlib, /^\d+(?:\.\d+){1,3}(?:-.*)?$/); if (hasUndici) {