mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 871596 - part 3 - replace memcpys of POD datatypes in Pickle with something smarter; r=bent
This commit is contained in:
parent
1a69354879
commit
3d5d16ad9c
@ -4,6 +4,10 @@
|
||||
|
||||
#include "base/pickle.h"
|
||||
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <limits>
|
||||
@ -11,6 +15,9 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
MOZ_STATIC_ASSERT(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
|
||||
"Insufficient alignment");
|
||||
|
||||
// static
|
||||
const int Pickle::kPayloadUnit = 64;
|
||||
|
||||
@ -19,6 +26,74 @@ static const uint32_t kCapacityReadOnly = (uint32_t) -1;
|
||||
|
||||
static const char kBytePaddingMarker = char(0xbf);
|
||||
|
||||
namespace {
|
||||
|
||||
// We want to copy data to our payload as efficiently as possible.
|
||||
// memcpy fits the bill for copying, but not all compilers or
|
||||
// architectures support inlining memcpy from void*, which has unknown
|
||||
// static alignment. However, we know that all the members of our
|
||||
// payload will be aligned on memberAlignmentType boundaries. We
|
||||
// therefore use that knowledge to construct a copier that will copy
|
||||
// efficiently (via standard C++ assignment mechanisms) if the datatype
|
||||
// needs that alignment or less, and memcpy otherwise. (The compiler
|
||||
// may still inline memcpy, of course.)
|
||||
|
||||
template<typename T, size_t size, bool hasSufficientAlignment>
|
||||
struct Copier
|
||||
{
|
||||
static void Copy(T* dest, void** iter) {
|
||||
memcpy(dest, *iter, sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
// Copying 64-bit quantities happens often enough and can easily be made
|
||||
// worthwhile on 32-bit platforms, so handle it specially. Only do it
|
||||
// if 64-bit types aren't sufficiently aligned; the alignment
|
||||
// requirements for them vary between 32-bit platforms.
|
||||
#ifndef HAVE_64BIT_OS
|
||||
template<typename T>
|
||||
struct Copier<T, sizeof(uint64_t), false>
|
||||
{
|
||||
static void Copy(T* dest, void** iter) {
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
static const int loIndex = 0, hiIndex = 1;
|
||||
#else
|
||||
static const int loIndex = 1, hiIndex = 0;
|
||||
#endif
|
||||
MOZ_STATIC_ASSERT(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
|
||||
"Pointers have different alignments");
|
||||
uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
|
||||
uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
|
||||
uint32dest[loIndex] = src[loIndex];
|
||||
uint32dest[hiIndex] = src[hiIndex];
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename T, size_t size>
|
||||
struct Copier<T, size, true>
|
||||
{
|
||||
static void Copy(T* dest, void** iter) {
|
||||
// The reinterpret_cast is only safe if two conditions hold:
|
||||
// (1) If the alignment of T* is the same as void*;
|
||||
// (2) The alignment of the data in *iter is at least as
|
||||
// big as MOZ_ALIGNOF(T).
|
||||
// Check the first condition, as the second condition is already
|
||||
// known to be true, or we wouldn't be here.
|
||||
MOZ_STATIC_ASSERT(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
|
||||
"Pointers have different alignments");
|
||||
*dest = *(*reinterpret_cast<T**>(iter));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void CopyFromIter(T* dest, void** iter) {
|
||||
MOZ_STATIC_ASSERT(mozilla::IsPod<T>::value, "Copied type must be a POD type");
|
||||
Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Payload is sizeof(Pickle::memberAlignmentType) aligned.
|
||||
|
||||
Pickle::Pickle()
|
||||
@ -98,7 +173,7 @@ bool Pickle::ReadInt16(void** iter, int16_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -112,7 +187,7 @@ bool Pickle::ReadUInt16(void** iter, uint16_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -126,10 +201,7 @@ bool Pickle::ReadInt(void** iter, int* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
// TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
|
||||
// alignment.
|
||||
// Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
|
||||
*result = *reinterpret_cast<int*>(*iter);
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -146,9 +218,7 @@ bool Pickle::ReadLong(void** iter, long* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
|
||||
return false;
|
||||
|
||||
// TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
|
||||
// alignment.
|
||||
memcpy(&bigResult, *iter, sizeof(bigResult));
|
||||
CopyFromIter(&bigResult, iter);
|
||||
DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
|
||||
*result = static_cast<long>(bigResult);
|
||||
|
||||
@ -167,9 +237,7 @@ bool Pickle::ReadULong(void** iter, unsigned long* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
|
||||
return false;
|
||||
|
||||
// TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
|
||||
// alignment.
|
||||
memcpy(&bigResult, *iter, sizeof(bigResult));
|
||||
CopyFromIter(&bigResult, iter);
|
||||
DCHECK(bigResult <= ULONG_MAX);
|
||||
*result = static_cast<unsigned long>(bigResult);
|
||||
|
||||
@ -194,9 +262,7 @@ bool Pickle::ReadSize(void** iter, size_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
|
||||
return false;
|
||||
|
||||
// TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
|
||||
// alignment.
|
||||
memcpy(&bigResult, *iter, sizeof(bigResult));
|
||||
CopyFromIter(&bigResult, iter);
|
||||
DCHECK(bigResult <= std::numeric_limits<size_t>::max());
|
||||
*result = static_cast<size_t>(bigResult);
|
||||
|
||||
@ -212,7 +278,7 @@ bool Pickle::ReadInt32(void** iter, int32_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -226,7 +292,7 @@ bool Pickle::ReadUInt32(void** iter, uint32_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -240,7 +306,7 @@ bool Pickle::ReadInt64(void** iter, int64_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -254,7 +320,7 @@ bool Pickle::ReadUInt64(void** iter, uint64_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -268,7 +334,7 @@ bool Pickle::ReadDouble(void** iter, double* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
@ -285,7 +351,7 @@ bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
|
||||
return false;
|
||||
|
||||
memcpy(&bigResult, *iter, sizeof(bigResult));
|
||||
CopyFromIter(&bigResult, iter);
|
||||
DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
|
||||
*result = static_cast<intptr_t>(bigResult);
|
||||
|
||||
@ -301,7 +367,7 @@ bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
|
||||
if (!IteratorHasRoomFor(*iter, sizeof(*result)))
|
||||
return false;
|
||||
|
||||
memcpy(result, *iter, sizeof(*result));
|
||||
CopyFromIter(result, iter);
|
||||
|
||||
UpdateIter(iter, sizeof(*result));
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user