Browse Source

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
v0.9.6-release
Dean McNamee 12 years ago
committed by Ben Noordhuis
parent
commit
c207d400f1
  1. 45
      src/v8_typed_array.cc
  2. 51
      src/v8_typed_array_bswap.h

45
src/v8_typed_array.cc

@ -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();
}

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

Loading…
Cancel
Save