diff options
author | Dean McNamee <dean@gmail.com> | 2013-01-05 22:06:35 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-01-09 17:44:25 +0100 |
commit | 46a489be73fd87fa3e17dd929c53d9e90860f80a (patch) | |
tree | 36b8a4ebcee36d9feef32f650b82600f74c1539e | |
parent | 7d66a9d06048601121220084f7f6d5672866d2ec (diff) | |
download | node-new-46a489be73fd87fa3e17dd929c53d9e90860f80a.tar.gz |
typed arrays: swizzle with compiler intrinsics
Implement swizzling with compiler intrinsics and be aware of the native
endianness to correctly swap on big endian machines.
This introduces a template function to swap the bytes of a value,
and macros for the low level swap (taking advantage of gcc and msvc
intrinsics). This produces code like the following (comments are mine):
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
setValue<double>:
movd %xmm0, %rax ; fp reg -> gen reg
bswapq %rax ; 64-bit byte swap
movd %rax, %xmm0 ; gen reg -> fp reg
movq %xmm0, (%r15,%r12) ; store
-rw-r--r-- | src/v8_typed_array.cc | 38 | ||||
-rw-r--r-- | src/v8_typed_array_bswap.h | 170 |
2 files changed, 188 insertions, 20 deletions
diff --git a/src/v8_typed_array.cc b/src/v8_typed_array.cc index c9cf420221..427615f664 100644 --- a/src/v8_typed_array.cc +++ b/src/v8_typed_array.cc @@ -23,6 +23,7 @@ #include <string.h> // memmove #include "v8_typed_array.h" +#include "v8_typed_array_bswap.h" #include "node_buffer.h" #include "node.h" #include "v8.h" @@ -665,33 +666,20 @@ class DataView { return args.This(); } - // TODO(deanm): This isn't beautiful or optimal. - static void swizzle(char* buf, size_t len) { - for (size_t i = 0; i < len / 2; ++i) { - char t = buf[i]; - buf[i] = buf[len - i - 1]; - buf[len - i - 1] = t; - } - } - template <typename T> static T getValue(void* ptr, unsigned int index, bool swiz) { - char buf[sizeof(T)]; - memcpy(buf, reinterpret_cast<char*>(ptr) + index, sizeof(T)); - if (swiz) - swizzle(buf, sizeof(T)); T val; - memcpy(&val, buf, sizeof(T)); + memcpy(&val, reinterpret_cast<char*>(ptr) + index, sizeof(T)); + if (swiz) + val = v8_typed_array::SwapBytes(val); return val; } template <typename T> static void setValue(void* ptr, unsigned int index, T val, bool swiz) { - char buf[sizeof(T)]; - memcpy(buf, &val, sizeof(T)); if (swiz) - swizzle(buf, sizeof(T)); - memcpy(reinterpret_cast<char*>(ptr) + index, buf, sizeof(T)); + val = v8_typed_array::SwapBytes(val); + memcpy(reinterpret_cast<char*>(ptr) + index, &val, sizeof(T)); } template <typename T> @@ -711,7 +699,12 @@ class DataView { return ThrowError("Index out of range."); void* ptr = args.This()->GetIndexedPropertiesExternalArrayData(); - return cTypeToValue<T>(getValue<T>(ptr, index, !little_endian)); +#if V8_TYPED_ARRAY_LITTLE_ENDIAN + bool swiz = !little_endian; +#else + bool swiz = little_endian; +#endif + return cTypeToValue<T>(getValue<T>(ptr, index, swiz)); } template <typename T> @@ -731,7 +724,12 @@ class DataView { return ThrowError("Index out of range."); void* ptr = args.This()->GetIndexedPropertiesExternalArrayData(); - setValue<T>(ptr, index, valueToCType<T>(args[1]), !little_endian); +#if V8_TYPED_ARRAY_LITTLE_ENDIAN + bool swiz = !little_endian; +#else + bool swiz = little_endian; +#endif + setValue<T>(ptr, index, valueToCType<T>(args[1]), swiz); return v8::Undefined(); } diff --git a/src/v8_typed_array_bswap.h b/src/v8_typed_array_bswap.h new file mode 100644 index 0000000000..4489f06708 --- /dev/null +++ b/src/v8_typed_array_bswap.h @@ -0,0 +1,170 @@ +// V8 Typed Array implementation. +// (c) Dean McNamee <dean@gmail.com>, 2012. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef V8_TYPED_ARRAY_BSWAP_H_ +#define V8_TYPED_ARRAY_BSWAP_H_ + +// Windows will always be little endian (including ARM), so we just need to +// worry about gcc. +#if defined (__ppc__) || defined (__ppc64__) || defined(__ARMEB__) +#define V8_TYPED_ARRAY_BIG_ENDIAN 1 +#else +#define V8_TYPED_ARRAY_LITTLE_ENDIAN 1 +#endif + +#if defined (_MSC_VER) && (_MSC_VER < 1600) + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned __int16 uint16_t; + typedef signed __int16 int16_t; + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + // Definitions to avoid ICU redefinition issue + #define U_HAVE_INT8_T 1 + #define U_HAVE_UINT8_T 1 + #define U_HAVE_INT16_T 1 + #define U_HAVE_UINT16_T 1 + #define U_HAVE_INT32_T 1 + #define U_HAVE_UINT32_T 1 + #define U_HAVE_INT64_T 1 + #define U_HAVE_UINT64_T 1 +#else + #include <stdint.h> +#endif + +#if defined (_MSC_VER) +#define V8_TYPED_ARRAY_BSWAP16 _byteswap_ushort +#define V8_TYPED_ARRAY_BSWAP32 _byteswap_ulong +#define V8_TYPED_ARRAY_BSWAP64 _byteswap_uint64 +#else +// On LLVM based compilers we can feature test, but for GCC we unfortunately +// have to rely on the version. Additionally __builtin_bswap32/64 were added +// in GCC 4.3, but __builtin_bswap16 was not added until GCC 4.8. +// We should be able to assume GCC/LLVM here (and can use ULL constants, etc). +// Fallback swap macros taken from QEMU bswap.h +#ifdef __has_builtin +#define V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN(x) __has_builtin(x) +#define V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN16(x) __has_builtin(x) +#else +#define V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN(x) (defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) +#define V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN16(x) (defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +#endif + +#if V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN(__builtin_bswap64) +#define V8_TYPED_ARRAY_BSWAP64 __builtin_bswap64 +#else +#define V8_TYPED_ARRAY_BSWAP64(x) \ +({ \ + uint64_t __x = (x); \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ +}) +#endif + +#if V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN(__builtin_bswap32) +#define V8_TYPED_ARRAY_BSWAP32 __builtin_bswap32 +#else +#define V8_TYPED_ARRAY_BSWAP32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) +#endif + +#if V8_TYPED_ARRAY_BSWAP_HAS_BUILTIN16(__builtin_bswap16) +#define V8_TYPED_ARRAY_BSWAP16 __builtin_bswap16 +#else +#define V8_TYPED_ARRAY_BSWAP16(x) \ +({ \ + uint16_t __x = (x); \ + ((uint16_t)( \ + (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ +}) +#endif +#endif + + +namespace v8_typed_array { + +template <typename T> +inline T SwapBytes(T x) { + typedef char NoSwapBytesForType[sizeof(T) == 0 ? 1 : -1]; + return 0; +} + +template <> +inline uint8_t SwapBytes(uint8_t x) { return x; } +template <> +inline int8_t SwapBytes(int8_t x) { return x; } +template <> +inline uint16_t SwapBytes(uint16_t x) { return V8_TYPED_ARRAY_BSWAP16(x); } +template <> +inline int16_t SwapBytes(int16_t x) { return V8_TYPED_ARRAY_BSWAP16(x); } +template <> +inline uint32_t SwapBytes(uint32_t x) { return V8_TYPED_ARRAY_BSWAP32(x); } +template <> +inline int32_t SwapBytes(int32_t x) { return V8_TYPED_ARRAY_BSWAP32(x); } +template <> +inline uint64_t SwapBytes(uint64_t x) { return V8_TYPED_ARRAY_BSWAP64(x); } +template <> +inline int64_t SwapBytes(int64_t x) { return V8_TYPED_ARRAY_BSWAP64(x); } + +template <> +inline float SwapBytes(float x) { + typedef char VerifySizesAreEqual[sizeof(uint32_t) == sizeof(float) ? 1 : -1]; + uint32_t swappable; + float result; + memcpy(&swappable, &x, sizeof(x)); + swappable = SwapBytes(swappable); + memcpy(&result, &swappable, sizeof(x)); + return result; +} + +template <> +inline double SwapBytes(double x) { + typedef char VerifySizesAreEqual[sizeof(uint64_t) == sizeof(double) ? 1 : -1]; + uint64_t swappable; + double result; + memcpy(&swappable, &x, sizeof(x)); + swappable = SwapBytes(swappable); + memcpy(&result, &swappable, sizeof(x)); + return result; +} + +} // namespace v8_typed_array + +#endif // V8_TYPED_ARRAY_BSWAP_H_ |