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:
parent
46a489be73
commit
c207d400f1
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user