Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZach Bjornson <zbbjornson@gmail.com>2016-09-22 04:02:45 +0300
committerGibson Fahnestock <gib@uk.ibm.com>2016-10-04 11:28:18 +0300
commit7420835390bcf44696349fad0498390959816acd (patch)
tree3078395df358abc1cf68151139ed82cc4ff1c61f /src
parentd33c4bf97b68dbae83a1d456f7b34a91b1583666 (diff)
src: fix build for older clang
Removes use of builtins that are unavailable for older clang. Per benchmarks, only uses builtins on Windows, where speedup is significant. Also adds test for unaligned ucs2 buffer write. Between #3410 and #7645, bytes were swapped twice on bigendian platforms if buffer was not two-byte aligned. See comment in #7645. PR-URL: https://github.com/nodejs/node/pull/7645 Fixes: https://github.com/nodejs/node/issues/7618 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node_buffer.cc91
-rw-r--r--src/string_bytes.cc34
-rw-r--r--src/util-inl.h97
-rw-r--r--src/util.h6
4 files changed, 113 insertions, 115 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 467a6e88474..d7c27295e94 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -12,7 +12,6 @@
#include <string.h>
#include <limits.h>
-#include <utility>
#define BUFFER_ID 0xB0E4
@@ -49,38 +48,6 @@
THROW_AND_RETURN_IF_OOB(end <= end_max); \
size_t length = end - start;
-#if defined(__GNUC__) || defined(__clang__)
-#define BSWAP_INTRINSIC_2(x) __builtin_bswap16(x)
-#define BSWAP_INTRINSIC_4(x) __builtin_bswap32(x)
-#define BSWAP_INTRINSIC_8(x) __builtin_bswap64(x)
-#elif defined(__linux__)
-#include <byteswap.h>
-#define BSWAP_INTRINSIC_2(x) bswap_16(x)
-#define BSWAP_INTRINSIC_4(x) bswap_32(x)
-#define BSWAP_INTRINSIC_8(x) bswap_64(x)
-#elif defined(_MSC_VER)
-#include <intrin.h>
-#define BSWAP_INTRINSIC_2(x) _byteswap_ushort(x);
-#define BSWAP_INTRINSIC_4(x) _byteswap_ulong(x);
-#define BSWAP_INTRINSIC_8(x) _byteswap_uint64(x);
-#else
-#define BSWAP_INTRINSIC_2(x) ((x) << 8) | ((x) >> 8)
-#define BSWAP_INTRINSIC_4(x) \
- (((x) & 0xFF) << 24) | \
- (((x) & 0xFF00) << 8) | \
- (((x) >> 8) & 0xFF00) | \
- (((x) >> 24) & 0xFF)
-#define BSWAP_INTRINSIC_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 node {
// if true, all Buffer and SlowBuffer instances will automatically zero-fill
@@ -1204,23 +1171,7 @@ void Swap16(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
SPREAD_ARG(args[0], ts_obj);
-
- CHECK_EQ(ts_obj_length % 2, 0);
-
- int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint16_t);
-
- if (align == 0) {
- uint16_t* data16 = reinterpret_cast<uint16_t*>(ts_obj_data);
- size_t len16 = ts_obj_length / 2;
- for (size_t i = 0; i < len16; i++) {
- data16[i] = BSWAP_INTRINSIC_2(data16[i]);
- }
- } else {
- for (size_t i = 0; i < ts_obj_length; i += 2) {
- std::swap(ts_obj_data[i], ts_obj_data[i + 1]);
- }
- }
-
+ SwapBytes16(ts_obj_data, ts_obj_length);
args.GetReturnValue().Set(args[0]);
}
@@ -1229,24 +1180,7 @@ void Swap32(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
SPREAD_ARG(args[0], ts_obj);
-
- CHECK_EQ(ts_obj_length % 4, 0);
-
- int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint32_t);
-
- if (align == 0) {
- uint32_t* data32 = reinterpret_cast<uint32_t*>(ts_obj_data);
- size_t len32 = ts_obj_length / 4;
- for (size_t i = 0; i < len32; i++) {
- data32[i] = BSWAP_INTRINSIC_4(data32[i]);
- }
- } else {
- for (size_t i = 0; i < ts_obj_length; i += 4) {
- std::swap(ts_obj_data[i], ts_obj_data[i + 3]);
- std::swap(ts_obj_data[i + 1], ts_obj_data[i + 2]);
- }
- }
-
+ SwapBytes32(ts_obj_data, ts_obj_length);
args.GetReturnValue().Set(args[0]);
}
@@ -1255,26 +1189,7 @@ void Swap64(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
SPREAD_ARG(args[0], ts_obj);
-
- CHECK_EQ(ts_obj_length % 8, 0);
-
- int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint64_t);
-
- if (align == 0) {
- uint64_t* data64 = reinterpret_cast<uint64_t*>(ts_obj_data);
- size_t len32 = ts_obj_length / 8;
- for (size_t i = 0; i < len32; i++) {
- data64[i] = BSWAP_INTRINSIC_8(data64[i]);
- }
- } else {
- for (size_t i = 0; i < ts_obj_length; i += 8) {
- std::swap(ts_obj_data[i], ts_obj_data[i + 7]);
- std::swap(ts_obj_data[i + 1], ts_obj_data[i + 6]);
- std::swap(ts_obj_data[i + 2], ts_obj_data[i + 5]);
- std::swap(ts_obj_data[i + 3], ts_obj_data[i + 4]);
- }
- }
-
+ SwapBytes64(ts_obj_data, ts_obj_length);
args.GetReturnValue().Set(args[0]);
}
diff --git a/src/string_bytes.cc b/src/string_bytes.cc
index d9e8b97114e..882ca6e3e89 100644
--- a/src/string_bytes.cc
+++ b/src/string_bytes.cc
@@ -309,27 +309,13 @@ size_t StringBytes::Write(Isolate* isolate,
if (chars_written != nullptr)
*chars_written = nchars;
- if (!IsBigEndian())
- break;
-
// Node's "ucs2" encoding wants LE character data stored in
// the Buffer, so we need to reorder on BE platforms. See
// http://nodejs.org/api/buffer.html regarding Node's "ucs2"
// encoding specification
+ if (IsBigEndian())
+ SwapBytes16(buf, nbytes);
- const bool is_aligned =
- reinterpret_cast<uintptr_t>(buf) % sizeof(uint16_t);
- if (is_aligned) {
- uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
- SwapBytes(dst, dst, nchars);
- }
-
- ASSERT_EQ(sizeof(uint16_t), 2);
- for (size_t i = 0; i < nchars; i++) {
- char tmp = buf[i * 2];
- buf[i * 2] = buf[i * 2 + 1];
- buf[i * 2 + 1] = tmp;
- }
break;
}
@@ -705,17 +691,19 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
Local<Value> StringBytes::Encode(Isolate* isolate,
const uint16_t* buf,
size_t buflen) {
- Local<String> val;
+ // Node's "ucs2" encoding expects LE character data inside a
+ // Buffer, so we need to reorder on BE platforms. See
+ // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
+ // encoding specification
std::vector<uint16_t> dst;
if (IsBigEndian()) {
- // Node's "ucs2" encoding expects LE character data inside a
- // Buffer, so we need to reorder on BE platforms. See
- // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
- // encoding specification
- dst.resize(buflen);
- SwapBytes(&dst[0], buf, buflen);
+ dst.assign(buf, buf + buflen);
+ size_t nbytes = buflen * sizeof(dst[0]);
+ SwapBytes16(reinterpret_cast<char*>(&dst[0]), nbytes);
buf = &dst[0];
}
+
+ Local<String> val;
if (buflen < EXTERN_APEX) {
val = String::NewFromTwoByte(isolate,
buf,
diff --git a/src/util-inl.h b/src/util-inl.h
index 51adb816926..5ffe5b857f5 100644
--- a/src/util-inl.h
+++ b/src/util-inl.h
@@ -4,6 +4,30 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "util.h"
+#include <cstring>
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#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 node {
@@ -200,9 +224,76 @@ TypeName* Unwrap(v8::Local<v8::Object> object) {
return static_cast<TypeName*>(pointer);
}
-void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen) {
- for (size_t i = 0; i < buflen; i += 1)
- dst[i] = (src[i] << 8) | (src[i] >> 8);
+void SwapBytes16(char* data, size_t nbytes) {
+ CHECK_EQ(nbytes % 2, 0);
+
+#if defined(_MSC_VER)
+ int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint16_t);
+ if (align == 0) {
+ // MSVC has no strict aliasing, and is able to highly optimize this case.
+ uint16_t* data16 = reinterpret_cast<uint16_t*>(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)
+ int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint32_t);
+ // MSVC has no strict aliasing, and is able to highly optimize this case.
+ if (align == 0) {
+ uint32_t* data32 = reinterpret_cast<uint32_t*>(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)
+ int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint64_t);
+ if (align == 0) {
+ // MSVC has no strict aliasing, and is able to highly optimize this case.
+ uint64_t* data64 = reinterpret_cast<uint64_t*>(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) {
diff --git a/src/util.h b/src/util.h
index 25f2eb01783..e2f9df02bc4 100644
--- a/src/util.h
+++ b/src/util.h
@@ -254,7 +254,11 @@ inline void ClearWrap(v8::Local<v8::Object> object);
template <typename TypeName>
inline TypeName* Unwrap(v8::Local<v8::Object> object);
-inline void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen);
+// 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);