mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1444125 - work harder to generate good code for Maybe poisoning; r=gerald
This commit is contained in:
parent
1a314fba8e
commit
e7e0eac6bc
62
mfbt/Maybe.h
62
mfbt/Maybe.h
@ -28,6 +28,65 @@ struct Nothing { };
|
||||
|
||||
namespace detail {
|
||||
|
||||
// You would think that poisoning Maybe instances could just be a call
|
||||
// to mozWritePoison. Unfortunately, using a simple call to
|
||||
// mozWritePoison generates poor code on MSVC for small structures. The
|
||||
// generated code contains (always not-taken) branches and does a bunch
|
||||
// of setup for `rep stos{l,q}`, even though we know at compile time
|
||||
// exactly how many words we're poisoning. Instead, we're going to
|
||||
// force MSVC to generate the code we want via recursive templates.
|
||||
|
||||
// Write the given poisonValue into p at offset*sizeof(uintptr_t).
|
||||
template<size_t offset>
|
||||
inline void
|
||||
WritePoisonAtOffset(void* p, const uintptr_t poisonValue)
|
||||
{
|
||||
memcpy(static_cast<char*>(p) + offset*sizeof(poisonValue),
|
||||
&poisonValue, sizeof(poisonValue));
|
||||
}
|
||||
|
||||
|
||||
template<size_t Offset, size_t NOffsets>
|
||||
struct InlinePoisoner
|
||||
{
|
||||
static void poison(void* p, const uintptr_t poisonValue)
|
||||
{
|
||||
WritePoisonAtOffset<Offset>(p, poisonValue);
|
||||
InlinePoisoner<Offset+1, NOffsets>::poison(p, poisonValue);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct InlinePoisoner<N, N>
|
||||
{
|
||||
static void poison(void*, const uintptr_t)
|
||||
{
|
||||
// All done!
|
||||
}
|
||||
};
|
||||
|
||||
// We can't generate inline code for large structures, though, because we'll
|
||||
// blow out recursive template instantiation limits, and the code would be
|
||||
// bloated to boot. So provide a fallback to the out-of-line poisoner.
|
||||
template<size_t ObjectSize>
|
||||
struct OutOfLinePoisoner
|
||||
{
|
||||
static void poison(void* p, const uintptr_t)
|
||||
{
|
||||
mozWritePoison(p, ObjectSize);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
PoisonObject(T* p)
|
||||
{
|
||||
const uintptr_t POISON = mozPoisonValue();
|
||||
Conditional<(sizeof(T) <= 8*sizeof(POISON)),
|
||||
InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
|
||||
OutOfLinePoisoner<sizeof(T)>>::Type::poison(p, POISON);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct MaybePoisoner
|
||||
{
|
||||
@ -36,9 +95,8 @@ struct MaybePoisoner
|
||||
static void poison(void* aPtr)
|
||||
{
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
// Avoid MOZ_ASSERT in mozWritePoison.
|
||||
if (N >= sizeof(uintptr_t)) {
|
||||
mozWritePoison(aPtr, N);
|
||||
PoisonObject(static_cast<typename RemoveCV<T>::Type*>(aPtr));
|
||||
}
|
||||
#endif
|
||||
MOZ_MAKE_MEM_UNDEFINED(aPtr, N);
|
||||
|
Loading…
Reference in New Issue
Block a user