From c207d400f118032a419f978e766acd99af980132 Mon Sep 17 00:00:00 2001 From: Dean McNamee Date: Sun, 6 Jan 2013 18:59:12 +0100 Subject: [PATCH] typed arrays: implement load and store swizzling Implement load and store swizzling operations. This reduces an unneeded back and forth between types and additionally keeps the value in the swappable type until it is swapped. This is important for correctness when dealing with floating point, to avoid the possibility of loading the bits of a signaling NaN (because it isn't yet swapped) into the FPU. This additionally produces better code (comments are mine): gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00) setValue: movd %xmm0, %rax ; fp reg -> gen reg bswapq %rax ; 64-bit byte swap movq %rax, (%r15,%r12) ; store --- src/v8_typed_array.cc | 45 ++++++++++++++--------------- src/v8_typed_array_bswap.h | 59 +++++++++++++++++++++++++++++--------- 2 files changed, 66 insertions(+), 38 deletions(-) diff --git a/src/v8_typed_array.cc b/src/v8_typed_array.cc index 427615f664f..1d2ffc4af75 100644 --- a/src/v8_typed_array.cc +++ b/src/v8_typed_array.cc @@ -666,22 +666,6 @@ class DataView { return args.This(); } - template - static T getValue(void* ptr, unsigned int index, bool swiz) { - T val; - memcpy(&val, reinterpret_cast(ptr) + index, sizeof(T)); - if (swiz) - val = v8_typed_array::SwapBytes(val); - return val; - } - - template - static void setValue(void* ptr, unsigned int index, T val, bool swiz) { - if (swiz) - val = v8_typed_array::SwapBytes(val); - memcpy(reinterpret_cast(ptr) + index, &val, sizeof(T)); - } - template static v8::Handle getGeneric(const v8::Arguments& args) { if (args.Length() < 1) @@ -698,13 +682,20 @@ class DataView { if (index + sizeof(T) > (unsigned)size) // TODO(deanm): integer overflow. return ThrowError("Index out of range."); - void* ptr = args.This()->GetIndexedPropertiesExternalArrayData(); + void* ptr = reinterpret_cast( + args.This()->GetIndexedPropertiesExternalArrayData()) + index; + + T val; #if V8_TYPED_ARRAY_LITTLE_ENDIAN - bool swiz = !little_endian; + if (!little_endian) { #else - bool swiz = little_endian; + if (little_endian) { #endif - return cTypeToValue(getValue(ptr, index, swiz)); + val = v8_typed_array::LoadAndSwapBytes(ptr); + } else { + memcpy(&val, ptr, sizeof(T)); + } + return cTypeToValue(val); } template @@ -723,13 +714,19 @@ class DataView { if (index + sizeof(T) > (unsigned)size) // TODO(deanm): integer overflow. return ThrowError("Index out of range."); - void* ptr = args.This()->GetIndexedPropertiesExternalArrayData(); + void* ptr = reinterpret_cast( + args.This()->GetIndexedPropertiesExternalArrayData()) + index; + + T val = valueToCType(args[1]); #if V8_TYPED_ARRAY_LITTLE_ENDIAN - bool swiz = !little_endian; + if (!little_endian) { #else - bool swiz = little_endian; + if (little_endian) { #endif - setValue(ptr, index, valueToCType(args[1]), swiz); + v8_typed_array::SwapBytesAndStore(ptr, val); + } else { + memcpy(ptr, &val, sizeof(T)); + } return v8::Undefined(); } diff --git a/src/v8_typed_array_bswap.h b/src/v8_typed_array_bswap.h index 4489f067081..c8a24f58405 100644 --- a/src/v8_typed_array_bswap.h +++ b/src/v8_typed_array_bswap.h @@ -143,26 +143,57 @@ 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 // General implementation for all non-FP types. +inline T LoadAndSwapBytes(void* ptr) { + T val; + memcpy(&val, ptr, sizeof(T)); + return SwapBytes(val); } template <> -inline double SwapBytes(double x) { +inline float LoadAndSwapBytes(void* ptr) { + typedef char VerifySizesAreEqual[sizeof(uint32_t) == sizeof(float) ? 1 : -1]; + uint32_t swappable; + float val; + memcpy(&swappable, ptr, sizeof(swappable)); + swappable = SwapBytes(swappable); + memcpy(&val, &swappable, sizeof(swappable)); + return val; +} + +template <> +inline double LoadAndSwapBytes(void* ptr) { typedef char VerifySizesAreEqual[sizeof(uint64_t) == sizeof(double) ? 1 : -1]; uint64_t swappable; - double result; - memcpy(&swappable, &x, sizeof(x)); + double val; + memcpy(&swappable, ptr, sizeof(swappable)); swappable = SwapBytes(swappable); - memcpy(&result, &swappable, sizeof(x)); - return result; + memcpy(&val, &swappable, sizeof(swappable)); + return val; +} + +template // General implementation for all non-FP types. +inline void SwapBytesAndStore(void* ptr, T val) { + val = SwapBytes(val); + memcpy(ptr, &val, sizeof(T)); +} + +template <> +inline void SwapBytesAndStore(void* ptr, float val) { + typedef char VerifySizesAreEqual[sizeof(uint32_t) == sizeof(float) ? 1 : -1]; + uint32_t swappable; + memcpy(&swappable, &val, sizeof(swappable)); + swappable = SwapBytes(swappable); + memcpy(ptr, &swappable, sizeof(swappable)); +} + +template <> +inline void SwapBytesAndStore(void* ptr, double val) { + typedef char VerifySizesAreEqual[sizeof(uint64_t) == sizeof(double) ? 1 : -1]; + uint64_t swappable; + memcpy(&swappable, &val, sizeof(swappable)); + swappable = SwapBytes(swappable); + memcpy(ptr, &swappable, sizeof(swappable)); } } // namespace v8_typed_array