Permalink
Browse files

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<double>:
  movd  %xmm0, %rax         ; fp reg -> gen reg
  bswapq  %rax              ; 64-bit byte swap
  movq  %rax, (%r15,%r12)   ; store
  • Loading branch information...
1 parent 46a489b commit c207d400f118032a419f978e766acd99af980132 @deanm deanm committed with bnoordhuis Jan 6, 2013
Showing with 62 additions and 34 deletions.
  1. +21 −24 src/v8_typed_array.cc
  2. +41 −10 src/v8_typed_array_bswap.h
View
45 src/v8_typed_array.cc
@@ -667,22 +667,6 @@ class DataView {
}
template <typename T>
- static T getValue(void* ptr, unsigned int index, bool swiz) {
- T val;
- 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) {
- if (swiz)
- val = v8_typed_array::SwapBytes(val);
- memcpy(reinterpret_cast<char*>(ptr) + index, &val, sizeof(T));
- }
-
- template <typename T>
static v8::Handle<v8::Value> getGeneric(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowError("Wrong number of arguments.");
@@ -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<char*>(
+ 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<T>(getValue<T>(ptr, index, swiz));
+ val = v8_typed_array::LoadAndSwapBytes<T>(ptr);
+ } else {
+ memcpy(&val, ptr, sizeof(T));
+ }
+ return cTypeToValue<T>(val);
}
template <typename T>
@@ -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<char*>(
+ args.This()->GetIndexedPropertiesExternalArrayData()) + index;
+
+ T val = valueToCType<T>(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<T>(ptr, index, valueToCType<T>(args[1]), swiz);
+ v8_typed_array::SwapBytesAndStore<T>(ptr, val);
+ } else {
+ memcpy(ptr, &val, sizeof(T));
+ }
return v8::Undefined();
}
View
51 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 <typename T> // General implementation for all non-FP types.
+inline T LoadAndSwapBytes(void* ptr) {
+ T val;
+ memcpy(&val, ptr, sizeof(T));
+ return SwapBytes(val);
+}
+
+template <>
+inline float LoadAndSwapBytes<float>(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<double>(void* ptr) {
+ typedef char VerifySizesAreEqual[sizeof(uint64_t) == sizeof(double) ? 1 : -1];
+ uint64_t swappable;
+ double val;
+ memcpy(&swappable, ptr, sizeof(swappable));
+ swappable = SwapBytes(swappable);
+ memcpy(&val, &swappable, sizeof(swappable));
+ return val;
+}
+
+template <typename T> // General implementation for all non-FP types.
+inline void SwapBytesAndStore(void* ptr, T val) {
+ val = SwapBytes(val);
+ memcpy(ptr, &val, sizeof(T));
+}
+
template <>
-inline float SwapBytes(float x) {
+inline void SwapBytesAndStore(void* ptr, float val) {
typedef char VerifySizesAreEqual[sizeof(uint32_t) == sizeof(float) ? 1 : -1];
uint32_t swappable;
- float result;
- memcpy(&swappable, &x, sizeof(x));
+ memcpy(&swappable, &val, sizeof(swappable));
swappable = SwapBytes(swappable);
- memcpy(&result, &swappable, sizeof(x));
- return result;
+ memcpy(ptr, &swappable, sizeof(swappable));
}
template <>
-inline double SwapBytes(double x) {
+inline void SwapBytesAndStore(void* ptr, double val) {
typedef char VerifySizesAreEqual[sizeof(uint64_t) == sizeof(double) ? 1 : -1];
uint64_t swappable;
- double result;
- memcpy(&swappable, &x, sizeof(x));
+ memcpy(&swappable, &val, sizeof(swappable));
swappable = SwapBytes(swappable);
- memcpy(&result, &swappable, sizeof(x));
- return result;
+ memcpy(ptr, &swappable, sizeof(swappable));
}
} // namespace v8_typed_array

0 comments on commit c207d40

Please sign in to comment.