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
This commit is contained in:
Dean McNamee 2013-01-06 18:59:12 +01:00 committed by Ben Noordhuis
parent 46a489be73
commit c207d400f1
2 changed files with 66 additions and 38 deletions

View File

@ -666,22 +666,6 @@ class DataView {
return args.This();
}
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)
@ -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 File

@ -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 <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 double SwapBytes(double x) {
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 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 <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 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