Skip to content

Commit aaa90d0

Browse files
committed
src: optimize byte swaps
1 parent 83b004e commit aaa90d0

File tree

3 files changed

+65
-36
lines changed

3 files changed

+65
-36
lines changed

src/node_buffer.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,7 @@ void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
483483
// Node's "ucs2" encoding expects LE character data inside a Buffer, so we
484484
// need to reorder on BE platforms. See http://nodejs.org/api/buffer.html
485485
// regarding Node's "ucs2" encoding specification.
486-
const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
487-
if (IsLittleEndian() && !aligned) {
486+
if (IsLittleEndian() && !IsAlignedTo<uint16_t>(data)) {
488487
// Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
489488
// This applies ONLY to little endian platforms, as misalignment will be
490489
// handled by a byte-swapping operation in StringBytes::Encode on

src/util-inl.h

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include "util.h"
7+
#include <string.h> // memcpy()
78

89
namespace node {
910

@@ -200,47 +201,69 @@ TypeName* Unwrap(v8::Local<v8::Object> object) {
200201
return static_cast<TypeName*>(pointer);
201202
}
202203

203-
void SwapBytes16(char* dst, const char* src, size_t size) {
204-
for (size_t i = 0; i < size; i += 2) {
205-
char a = src[i + 0];
206-
char b = src[i + 1];
207-
dst[i + 0] = b;
208-
dst[i + 1] = a;
204+
template <typename T, typename U>
205+
bool IsAlignedTo(const U* p) {
206+
return reinterpret_cast<uintptr_t>(p) % sizeof(T) == 0;
207+
}
208+
209+
uint16_t ByteSwap(uint16_t v) {
210+
uint16_t a = (v >> 0) & 255;
211+
uint16_t b = (v >> 8) & 255;
212+
return (a << 8) | b;
213+
}
214+
215+
uint32_t ByteSwap(uint32_t v) {
216+
uint32_t a = (v >> 0) & 255;
217+
uint32_t b = (v >> 8) & 255;
218+
uint32_t c = (v >> 16) & 255;
219+
uint32_t d = (v >> 24) & 255;
220+
return (a << 24) | (b << 16) | (c << 8) | d;
221+
}
222+
223+
uint64_t ByteSwap(uint64_t v) {
224+
uint64_t a = (v >> 0) & 255;
225+
uint64_t b = (v >> 8) & 255;
226+
uint64_t c = (v >> 16) & 255;
227+
uint64_t d = (v >> 24) & 255;
228+
uint64_t e = (v >> 32) & 255;
229+
uint64_t f = (v >> 40) & 255;
230+
uint64_t g = (v >> 48) & 255;
231+
uint64_t h = (v >> 56) & 255;
232+
return (a << 56) | (b << 48) | (c << 40) | (d << 32) |
233+
(e << 24) | (f << 16) | (g << 8) | h;
234+
}
235+
236+
template <typename T>
237+
inline void DoSwapBytes(char* dst, const char* src, size_t size) {
238+
for (size_t i = 0; i < size; i += sizeof(T)) {
239+
T v;
240+
memcpy(&v, &src[i], sizeof(v));
241+
v = ByteSwap(v);
242+
memcpy(&dst[i], &v, sizeof(v));
209243
}
210244
}
211245

212-
void SwapBytes32(char* dst, const char* src, size_t size) {
213-
for (size_t i = 0; i < size; i += 4) {
214-
char a = src[i + 0];
215-
char b = src[i + 1];
216-
char c = src[i + 2];
217-
char d = src[i + 3];
218-
dst[i + 0] = d;
219-
dst[i + 1] = c;
220-
dst[i + 2] = b;
221-
dst[i + 3] = a;
246+
template <typename T>
247+
void SwapBytes(char* dst, const char* src, size_t size) {
248+
if (src == dst && IsAlignedTo<T>(dst)) {
249+
// Hit the compiler over the head with the fact that the source
250+
// and the destination are the same and is properly aligned.
251+
DoSwapBytes<T>(dst, dst, size);
252+
} else {
253+
DoSwapBytes<T>(dst, src, size);
222254
}
223255
}
224256

257+
void SwapBytes16(char* dst, const char* src, size_t size) {
258+
return SwapBytes<uint16_t>(dst, src, size);
259+
}
260+
261+
void SwapBytes32(char* dst, const char* src, size_t size) {
262+
return SwapBytes<uint32_t>(dst, src, size);
263+
}
264+
225265
void SwapBytes64(char* dst, const char* src, size_t size) {
226-
for (size_t i = 0; i < size; i += 8) {
227-
char a = src[i + 0];
228-
char b = src[i + 1];
229-
char c = src[i + 2];
230-
char d = src[i + 3];
231-
char e = src[i + 4];
232-
char f = src[i + 5];
233-
char g = src[i + 6];
234-
char h = src[i + 7];
235-
dst[i + 0] = h;
236-
dst[i + 1] = g;
237-
dst[i + 2] = f;
238-
dst[i + 3] = e;
239-
dst[i + 4] = d;
240-
dst[i + 5] = c;
241-
dst[i + 6] = b;
242-
dst[i + 7] = a;
243-
}
266+
return SwapBytes<uint64_t>(dst, src, size);
244267
}
245268

246269
char ToLower(char c) {

src/util.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,13 @@ inline void ClearWrap(v8::Local<v8::Object> object);
238238
template <typename TypeName>
239239
inline TypeName* Unwrap(v8::Local<v8::Object> object);
240240

241+
template <typename T, typename U>
242+
inline bool IsAlignedTo(const U* p);
243+
244+
inline uint16_t ByteSwap(uint16_t v);
245+
inline uint32_t ByteSwap(uint32_t v);
246+
inline uint64_t ByteSwap(uint64_t v);
247+
241248
// |src| and |dst| are allowed to overlap. |size| is in bytes and must be
242249
// a multiple of the word size.
243250
inline void SwapBytes16(char* dst, const char* src, size_t size);

0 commit comments

Comments
 (0)