add webgl support

This commit is contained in:
minggo 2018-04-04 09:53:11 +08:00
parent 046f573737
commit 281a4c920f
22 changed files with 16554 additions and 0 deletions

6825
sources/firefox/GLConsts.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,387 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGL_FORMATS_H_
#define WEBGL_FORMATS_H_
#include <map>
#include <set>
#include "mozilla/UniquePtr.h"
#include "WebGLTypes.h"
namespace mozilla {
namespace webgl {
typedef uint8_t EffectiveFormatValueT;
enum class EffectiveFormat : EffectiveFormatValueT {
// GLES 3.0.4, p128-129, "Required Texture Formats"
// "Texture and renderbuffer color formats"
RGBA32I,
RGBA32UI,
RGBA16I,
RGBA16UI,
RGBA8,
RGBA8I,
RGBA8UI,
SRGB8_ALPHA8,
RGB10_A2,
RGB10_A2UI,
RGBA4,
RGB5_A1,
RGB8,
RGB565,
RG32I,
RG32UI,
RG16I,
RG16UI,
RG8,
RG8I,
RG8UI,
R32I,
R32UI,
R16I,
R16UI,
R8,
R8I,
R8UI,
// "Texture-only color formats"
RGBA32F,
RGBA16F,
RGBA8_SNORM,
RGB32F,
RGB32I,
RGB32UI,
RGB16F,
RGB16I,
RGB16UI,
RGB8_SNORM,
RGB8I,
RGB8UI,
SRGB8,
R11F_G11F_B10F,
RGB9_E5,
RG32F,
RG16F,
RG8_SNORM,
R32F,
R16F,
R8_SNORM,
// "Depth formats"
DEPTH_COMPONENT32F,
DEPTH_COMPONENT24,
DEPTH_COMPONENT16,
// "Combined depth+stencil formats"
DEPTH32F_STENCIL8,
DEPTH24_STENCIL8,
// GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
STENCIL_INDEX8,
////////////////////////////////////
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
COMPRESSED_R11_EAC,
COMPRESSED_SIGNED_R11_EAC,
COMPRESSED_RG11_EAC,
COMPRESSED_SIGNED_RG11_EAC,
COMPRESSED_RGB8_ETC2,
COMPRESSED_SRGB8_ETC2,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
COMPRESSED_RGBA8_ETC2_EAC,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
// AMD_compressed_ATC_texture
ATC_RGB_AMD,
ATC_RGBA_EXPLICIT_ALPHA_AMD,
ATC_RGBA_INTERPOLATED_ALPHA_AMD,
// EXT_texture_compression_s3tc
COMPRESSED_RGB_S3TC_DXT1_EXT,
COMPRESSED_RGBA_S3TC_DXT1_EXT,
COMPRESSED_RGBA_S3TC_DXT3_EXT,
COMPRESSED_RGBA_S3TC_DXT5_EXT,
// EXT_texture_sRGB
COMPRESSED_SRGB_S3TC_DXT1_EXT,
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
// KHR_texture_compression_astc_ldr
COMPRESSED_RGBA_ASTC_4x4_KHR,
COMPRESSED_RGBA_ASTC_5x4_KHR,
COMPRESSED_RGBA_ASTC_5x5_KHR,
COMPRESSED_RGBA_ASTC_6x5_KHR,
COMPRESSED_RGBA_ASTC_6x6_KHR,
COMPRESSED_RGBA_ASTC_8x5_KHR,
COMPRESSED_RGBA_ASTC_8x6_KHR,
COMPRESSED_RGBA_ASTC_8x8_KHR,
COMPRESSED_RGBA_ASTC_10x5_KHR,
COMPRESSED_RGBA_ASTC_10x6_KHR,
COMPRESSED_RGBA_ASTC_10x8_KHR,
COMPRESSED_RGBA_ASTC_10x10_KHR,
COMPRESSED_RGBA_ASTC_12x10_KHR,
COMPRESSED_RGBA_ASTC_12x12_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
// IMG_texture_compression_pvrtc
COMPRESSED_RGB_PVRTC_4BPPV1,
COMPRESSED_RGBA_PVRTC_4BPPV1,
COMPRESSED_RGB_PVRTC_2BPPV1,
COMPRESSED_RGBA_PVRTC_2BPPV1,
// OES_compressed_ETC1_RGB8_texture
ETC1_RGB8_OES,
////////////////////////////////////
// GLES 3.0.4, p128, table 3.12.
Luminance8Alpha8,
Luminance8,
Alpha8,
// OES_texture_float
Luminance32FAlpha32F,
Luminance32F,
Alpha32F,
// OES_texture_half_float
Luminance16FAlpha16F,
Luminance16F,
Alpha16F,
MAX,
};
enum class UnsizedFormat : uint8_t {
R,
RG,
RGB,
RGBA,
LA,
L,
A,
D,
S,
DEPTH_STENCIL, // `DS` is a macro on Solaris. (regset.h)
};
// GLES 3.0.4 p114 Table 3.4, p240
enum class ComponentType : uint8_t {
None,
Int, // RGBA32I
UInt, // RGBA32UI, STENCIL_INDEX8
NormInt, // RGBA8_SNORM
NormUInt, // RGBA8, DEPTH_COMPONENT16
Float, // RGBA32F
Special, // DEPTH24_STENCIL8
};
enum class CompressionFamily : uint8_t {
ASTC,
ATC,
ES3, // ETC2 or EAC
ETC1,
PVRTC,
S3TC,
};
////////////////////////////////////////////////////////////////////////////////
struct CompressedFormatInfo
{
const EffectiveFormat effectiveFormat;
const uint8_t bytesPerBlock;
const uint8_t blockWidth;
const uint8_t blockHeight;
const CompressionFamily family;
};
struct FormatInfo
{
const EffectiveFormat effectiveFormat;
const char* const name;
const GLenum sizedFormat;
const UnsizedFormat unsizedFormat;
const ComponentType componentType;
const bool isSRGB;
const CompressedFormatInfo* const compression;
const uint8_t estimatedBytesPerPixel; // 0 iff bool(compression).
// In bits. Iff bool(compression), active channels are 1.
const uint8_t r;
const uint8_t g;
const uint8_t b;
const uint8_t a;
const uint8_t d;
const uint8_t s;
//////
std::map<UnsizedFormat, const FormatInfo*> copyDecayFormats;
const FormatInfo* GetCopyDecayFormat(UnsizedFormat) const;
bool IsColorFormat() const {
// Alpha is a 'color format' since it's 'color-attachable'.
return bool(compression) ||
bool(r | g | b | a);
}
};
struct PackingInfo
{
GLenum format;
GLenum type;
bool operator <(const PackingInfo& x) const
{
if (format != x.format)
return format < x.format;
return type < x.type;
}
bool operator ==(const PackingInfo& x) const {
return (format == x.format &&
type == x.type);
}
};
struct DriverUnpackInfo
{
GLenum internalFormat;
GLenum unpackFormat;
GLenum unpackType;
PackingInfo ToPacking() const {
return {unpackFormat, unpackType};
}
};
//////////////////////////////////////////////////////////////////////////////////////////
const FormatInfo* GetFormat(EffectiveFormat format);
uint8_t BytesPerPixel(const PackingInfo& packing);
bool GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes);
/*
GLint ComponentSize(const FormatInfo* format, GLenum component);
GLenum ComponentType(const FormatInfo* format);
*/
////////////////////////////////////////
struct FormatUsageInfo
{
const FormatInfo* const format;
private:
bool isRenderable;
public:
bool isFilterable;
std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
const DriverUnpackInfo* idealUnpack;
const GLint* textureSwizzleRGBA;
bool maxSamplesKnown;
uint32_t maxSamples;
static const GLint kLuminanceSwizzleRGBA[4];
static const GLint kAlphaSwizzleRGBA[4];
static const GLint kLumAlphaSwizzleRGBA[4];
explicit FormatUsageInfo(const FormatInfo* _format)
: format(_format)
, isRenderable(false)
, isFilterable(false)
, idealUnpack(nullptr)
, textureSwizzleRGBA(nullptr)
, maxSamplesKnown(false)
, maxSamples(0)
{ }
bool IsRenderable() const { return isRenderable; }
void SetRenderable();
bool IsUnpackValid(const PackingInfo& key,
const DriverUnpackInfo** const out_value) const;
void ResolveMaxSamples(gl::GLContext* gl);
};
class FormatUsageAuthority
{
std::map<EffectiveFormat, FormatUsageInfo> mUsageMap;
std::map<GLenum, const FormatUsageInfo*> mRBFormatMap;
std::map<GLenum, const FormatUsageInfo*> mSizedTexFormatMap;
std::map<PackingInfo, const FormatUsageInfo*> mUnsizedTexFormatMap;
std::set<GLenum> mValidTexInternalFormats;
std::set<GLenum> mValidTexUnpackFormats;
std::set<GLenum> mValidTexUnpackTypes;
public:
static UniquePtr<FormatUsageAuthority> CreateForWebGL1(gl::GLContext* gl);
static UniquePtr<FormatUsageAuthority> CreateForWebGL2(gl::GLContext* gl);
private:
FormatUsageAuthority() { }
public:
FormatUsageInfo* EditUsage(EffectiveFormat format);
const FormatUsageInfo* GetUsage(EffectiveFormat format) const;
void AddTexUnpack(FormatUsageInfo* usage, const PackingInfo& pi,
const DriverUnpackInfo& dui);
bool IsInternalFormatEnumValid(GLenum internalFormat) const;
bool AreUnpackEnumsValid(GLenum unpackFormat, GLenum unpackType) const;
void AllowRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
void AllowSizedTexFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
void AllowUnsizedTexFormat(const PackingInfo& pi, const FormatUsageInfo* usage);
const FormatUsageInfo* GetRBUsage(GLenum sizedFormat) const;
const FormatUsageInfo* GetSizedTexUsage(GLenum sizedFormat) const;
const FormatUsageInfo* GetUnsizedTexUsage(const PackingInfo& pi) const;
};
} // namespace webgl
} // namespace mozilla
#endif // WEBGL_FORMATS_H_

View File

@ -0,0 +1,435 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
//cjh #include "WebGLContext.h"
#include "WebGLTexelConversions.h"
#include <memory.h>
namespace mozilla {
using namespace WebGLTexelConversions;
namespace {
/** @class WebGLImageConverter
*
* This class is just a helper to implement WebGLContext::ConvertImage below.
*
* Design comments:
*
* WebGLContext::ConvertImage has to handle hundreds of format conversion paths.
* It is important to minimize executable code size here. Instead of passing around
* a large number of function parameters hundreds of times, we create a
* WebGLImageConverter object once, storing these parameters, and then we call
* the run() method on it.
*/
class WebGLImageConverter
{
const size_t mWidth, mHeight;
const void* const mSrcStart;
void* const mDstStart;
const ptrdiff_t mSrcStride, mDstStride;
bool mAlreadyRun;
bool mSuccess;
/*
* Returns sizeof(texel)/sizeof(type). The point is that we will iterate over
* texels with typed pointers and this value will tell us by how much we need
* to increment these pointers to advance to the next texel.
*/
template<WebGLTexelFormat Format>
static size_t NumElementsPerTexelForFormat() {
switch (Format) {
case WebGLTexelFormat::A8:
case WebGLTexelFormat::A16F:
case WebGLTexelFormat::A32F:
case WebGLTexelFormat::R8:
case WebGLTexelFormat::R16F:
case WebGLTexelFormat::R32F:
case WebGLTexelFormat::RGB565:
case WebGLTexelFormat::RGB11F11F10F:
case WebGLTexelFormat::RGBA4444:
case WebGLTexelFormat::RGBA5551:
return 1;
case WebGLTexelFormat::RA8:
case WebGLTexelFormat::RA16F:
case WebGLTexelFormat::RA32F:
case WebGLTexelFormat::RG8:
case WebGLTexelFormat::RG16F:
case WebGLTexelFormat::RG32F:
return 2;
case WebGLTexelFormat::RGB8:
case WebGLTexelFormat::RGB16F:
case WebGLTexelFormat::RGB32F:
return 3;
case WebGLTexelFormat::RGBA8:
case WebGLTexelFormat::RGBA16F:
case WebGLTexelFormat::RGBA32F:
case WebGLTexelFormat::BGRX8:
case WebGLTexelFormat::BGRA8:
return 4;
default:
MOZ_ASSERT(false, "Unknown texel format. Coding mistake?");
return 0;
}
}
/*
* This is the completely format-specific templatized conversion function,
* that will be instantiated hundreds of times for all different combinations.
* It is important to avoid generating useless code here. In particular, many
* instantiations of this function template will never be called, so we try
* to return immediately in these cases to allow the compiler to avoid generating
* useless code.
*/
template<WebGLTexelFormat SrcFormat,
WebGLTexelFormat DstFormat,
WebGLTexelPremultiplicationOp PremultiplicationOp>
void run()
{
// check for never-called cases. We early-return to allow the compiler
// to avoid generating this code. It would be tempting to abort() instead,
// as returning early does leave the destination surface with uninitialized
// data, but that would not allow the compiler to avoid generating this code.
// So instead, we return early, so Success() will return false, and the caller
// must check that and abort in that case. See WebGLContext::ConvertImage.
if (SrcFormat == DstFormat &&
PremultiplicationOp == WebGLTexelPremultiplicationOp::None)
{
// Should have used a fast exit path earlier, rather than entering this function.
// we explicitly return here to allow the compiler to avoid generating this code
return;
}
// Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat.
// DOM elements can only give BGRA8, BGRX8, A8, RGB565 formats. See DOMElementToImageSurface.
// ImageData is always RGBA8. So all other SrcFormat will always satisfy DstFormat==SrcFormat,
// so we can avoid compiling the code for all the unreachable paths.
//cjh const bool CanSrcFormatComeFromDOMElementOrImageData
// = SrcFormat == WebGLTexelFormat::BGRA8 ||
// SrcFormat == WebGLTexelFormat::BGRX8 ||
// SrcFormat == WebGLTexelFormat::A8 ||
// SrcFormat == WebGLTexelFormat::RGB565 ||
// SrcFormat == WebGLTexelFormat::RGBA8;
// if (!CanSrcFormatComeFromDOMElementOrImageData &&
// SrcFormat != DstFormat)
// {
// return;
// }
//
// // Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied.
// if (!CanSrcFormatComeFromDOMElementOrImageData &&
// PremultiplicationOp == WebGLTexelPremultiplicationOp::Unpremultiply)
// {
// return;
// }
// there is no point in premultiplication/unpremultiplication
// in the following cases:
// - the source format has no alpha
// - the source format has no color
// - the destination format has no color
if (!HasAlpha(SrcFormat) ||
!HasColor(SrcFormat) ||
!HasColor(DstFormat))
{
if (PremultiplicationOp != WebGLTexelPremultiplicationOp::None)
{
return;
}
}
// end of early return cases.
MOZ_ASSERT(!mAlreadyRun, "converter should be run only once!");
mAlreadyRun = true;
// gather some compile-time meta-data about the formats at hand.
typedef
typename DataTypeForFormat<SrcFormat>::Type
SrcType;
typedef
typename DataTypeForFormat<DstFormat>::Type
DstType;
const WebGLTexelFormat IntermediateSrcFormat
= IntermediateFormat<SrcFormat>::Value;
const WebGLTexelFormat IntermediateDstFormat
= IntermediateFormat<DstFormat>::Value;
typedef
typename DataTypeForFormat<IntermediateSrcFormat>::Type
IntermediateSrcType;
typedef
typename DataTypeForFormat<IntermediateDstFormat>::Type
IntermediateDstType;
const size_t NumElementsPerSrcTexel = NumElementsPerTexelForFormat<SrcFormat>();
const size_t NumElementsPerDstTexel = NumElementsPerTexelForFormat<DstFormat>();
const size_t MaxElementsPerTexel = 4;
MOZ_ASSERT(NumElementsPerSrcTexel <= MaxElementsPerTexel, "unhandled format");
MOZ_ASSERT(NumElementsPerDstTexel <= MaxElementsPerTexel, "unhandled format");
// we assume that the strides are multiples of the sizeof of respective types.
// this assumption will allow us to iterate over src and dst images using typed
// pointers, e.g. uint8_t* or uint16_t* or float*, instead of untyped pointers.
// So this assumption allows us to write cleaner and safer code, but it might
// not be true forever and if it eventually becomes wrong, we'll have to revert
// to always iterating using uint8_t* pointers regardless of the types at hand.
MOZ_ASSERT(mSrcStride % sizeof(SrcType) == 0 &&
mDstStride % sizeof(DstType) == 0,
"Unsupported: texture stride is not a multiple of sizeof(type)");
const ptrdiff_t srcStrideInElements = mSrcStride / sizeof(SrcType);
const ptrdiff_t dstStrideInElements = mDstStride / sizeof(DstType);
const SrcType* srcRowStart = static_cast<const SrcType*>(mSrcStart);
DstType* dstRowStart = static_cast<DstType*>(mDstStart);
// the loop performing the texture format conversion
for (size_t i = 0; i < mHeight; ++i) {
const SrcType* srcRowEnd = srcRowStart + mWidth * NumElementsPerSrcTexel;
const SrcType* srcPtr = srcRowStart;
DstType* dstPtr = dstRowStart;
while (srcPtr != srcRowEnd) {
// convert a single texel. We proceed in 3 steps: unpack the source texel
// so the corresponding interchange format (e.g. unpack RGB565 to RGBA8),
// convert the resulting data type to the destination type (e.g. convert
// from RGBA8 to RGBA32F), and finally pack the destination texel
// (e.g. pack RGBA32F to RGB32F).
IntermediateSrcType unpackedSrc[MaxElementsPerTexel];
IntermediateDstType unpackedDst[MaxElementsPerTexel];
// unpack a src texel to corresponding intermediate src format.
// for example, unpack RGB565 to RGBA8
unpack<SrcFormat>(srcPtr, unpackedSrc);
// convert the data type to the destination type, if needed.
// for example, convert RGBA8 to RGBA32F
convertType(unpackedSrc, unpackedDst);
// pack the destination texel.
// for example, pack RGBA32F to RGB32F
// pack<DstFormat, PremultiplicationOp>(unpackedDst, dstPtr);
srcPtr += NumElementsPerSrcTexel;
dstPtr += NumElementsPerDstTexel;
}
srcRowStart += srcStrideInElements;
dstRowStart += dstStrideInElements;
}
mSuccess = true;
}
template<WebGLTexelFormat SrcFormat,
WebGLTexelFormat DstFormat>
void run(WebGLTexelPremultiplicationOp premultiplicationOp)
{
#define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \
case PremultiplicationOp: \
return run<SrcFormat, DstFormat, PremultiplicationOp>();
switch (premultiplicationOp) {
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::None)
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Premultiply)
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Unpremultiply)
default:
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
}
#undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP
}
template<WebGLTexelFormat SrcFormat>
void run(WebGLTexelFormat dstFormat,
WebGLTexelPremultiplicationOp premultiplicationOp)
{
#define WEBGLIMAGECONVERTER_CASE_DSTFORMAT(DstFormat) \
case DstFormat: \
return run<SrcFormat, DstFormat>(premultiplicationOp);
switch (dstFormat) {
// 1-channel formats
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A32F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R32F)
// 2-channel formats
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA32F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG32F)
// 3-channel formats
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB565)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB11F11F10F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB32F)
// 4-channel formats
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA4444)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA5551)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA8)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA16F)
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA32F)
default:
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
}
#undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT
}
public:
void run(WebGLTexelFormat srcFormat,
WebGLTexelFormat dstFormat,
WebGLTexelPremultiplicationOp premultiplicationOp)
{
#define WEBGLIMAGECONVERTER_CASE_SRCFORMAT(SrcFormat) \
case SrcFormat: \
return run<SrcFormat>(dstFormat, premultiplicationOp);
switch (srcFormat) {
// 1-channel formats
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A16F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A32F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R16F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R32F)
// 2-channel formats
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA16F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA32F)
// 3-channel formats
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB565)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB16F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB32F)
// 4-channel formats
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA4444)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA5551)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA16F)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA32F)
// DOM element source formats
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRX8)
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRA8)
default:
MOZ_ASSERT(false, "unhandled case. Coding mistake?");
}
#undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT
}
WebGLImageConverter(size_t width, size_t height,
const void* srcStart, void* dstStart,
ptrdiff_t srcStride, ptrdiff_t dstStride)
: mWidth(width), mHeight(height),
mSrcStart(srcStart), mDstStart(dstStart),
mSrcStride(srcStride), mDstStride(dstStride),
mAlreadyRun(false), mSuccess(false)
{}
bool Success() const {
return mSuccess;
}
};
} // end anonymous namespace
bool
ConvertImage(size_t width, size_t height,
const void* srcBegin, size_t srcStride, gl::OriginPos srcOrigin,
WebGLTexelFormat srcFormat, bool srcPremultiplied,
void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
WebGLTexelFormat dstFormat, bool dstPremultiplied,
bool* const out_wasTrivial)
{
*out_wasTrivial = true;
if (srcFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion ||
dstFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion)
{
return false;
}
if (!width || !height)
return true;
const bool shouldYFlip = (srcOrigin != dstOrigin);
const bool canSkipPremult = (!HasAlpha(srcFormat) ||
!HasColor(srcFormat) ||
!HasColor(dstFormat));
WebGLTexelPremultiplicationOp premultOp;
if (canSkipPremult) {
premultOp = WebGLTexelPremultiplicationOp::None;
} else if (!srcPremultiplied && dstPremultiplied) {
premultOp = WebGLTexelPremultiplicationOp::Premultiply;
} else if (srcPremultiplied && !dstPremultiplied) {
premultOp = WebGLTexelPremultiplicationOp::Unpremultiply;
} else {
premultOp = WebGLTexelPremultiplicationOp::None;
}
const uint8_t* srcItr = (const uint8_t*)srcBegin;
const uint8_t* const srcEnd = srcItr + srcStride * height;
uint8_t* dstItr = (uint8_t*)dstBegin;
ptrdiff_t dstItrStride = dstStride;
if (shouldYFlip) {
dstItr = dstItr + dstStride * (height - 1);
dstItrStride = -dstItrStride;
}
if (srcFormat == dstFormat && premultOp == WebGLTexelPremultiplicationOp::None) {
// Fast exit path: we just have to memcpy all the rows.
//
// The case where absolutely nothing needs to be done is supposed to have
// been handled earlier (in TexImage2D_base, etc).
//
// So the case we're handling here is when even though no format conversion is
// needed, we still might have to flip vertically and/or to adjust to a different
// stride.
// We ignore canSkipPremult for this perf trap, since it's an avoidable perf cliff
// under the WebGL API user's control.
MOZ_ASSERT((srcPremultiplied != dstPremultiplied ||
shouldYFlip ||
srcStride != dstStride),
"Performance trap -- should handle this case earlier to avoid memcpy");
const auto bytesPerPixel = TexelBytesForFormat(srcFormat);
const size_t bytesPerRow = bytesPerPixel * width;
while (srcItr != srcEnd) {
memcpy(dstItr, srcItr, bytesPerRow);
srcItr += srcStride;
dstItr += dstItrStride;
}
return true;
}
*out_wasTrivial = false;
WebGLImageConverter converter(width, height, srcItr, dstItr, srcStride, dstItrStride);
converter.run(srcFormat, dstFormat, premultOp);
if (!converter.Success()) {
// the dst image may be left uninitialized, so we better not try to
// continue even in release builds. This should never happen anyway,
// and would be a bug in our code.
MOZ_CRASH("programming mistake in WebGL texture conversions");
}
return true;
}
} // end namespace mozilla

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGLTYPES_H_
#define WEBGLTYPES_H_
// Most WebIDL typedefs are identical to their OpenGL counterparts.
//cjh #include "GLTypes.h"
#include "platform/CCGL.h"
#include "mozilla/Attributes.h"
#include <stdint.h>
#include <stdlib.h>
// Manual reflection of WebIDL typedefs that are different from their
// OpenGL counterparts.
typedef int64_t WebGLsizeiptr;
typedef int64_t WebGLintptr;
typedef bool WebGLboolean;
namespace mozilla {
namespace gl {
class GLContext; // This is going to be needed a lot.
} // namespace gl
/*
* WebGLTextureFakeBlackStatus is an enum to track what needs to use a dummy 1x1 black
* texture, which we refer to as a 'fake black' texture.
*
* There are two things that can cause us to use such 'fake black' textures:
*
* (1) OpenGL ES rules on sampling incomplete textures specify that they
* must be sampled as RGBA(0, 0, 0, 1) (opaque black). We have to implement these rules
* ourselves, if only because we do not always run on OpenGL ES, and also
* because this is dangerously close to the kind of case where we don't
* want to trust the driver with corner cases of texture memory accesses.
*
* (2) OpenGL has cases where a renderbuffer, or a texture image, can contain
* uninitialized image data. See below the comment about WebGLImageDataStatus.
* WebGL must never have access to uninitialized image data. The WebGL 1 spec,
* section 4.1 'Resource Restrictions', specifies that in any such case, the
* uninitialized image data must be exposed to WebGL as if it were filled
* with zero bytes, which means it's either opaque or transparent black
* depending on whether the image format has alpha.
*/
enum class FakeBlackType : uint8_t {
None,
RGBA0001, // Incomplete textures and uninitialized no-alpha color textures.
RGBA0000, // Uninitialized with-alpha color textures.
};
/*
* Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
* emulating the vertex attrib 0 array when it's not enabled. Indeed,
* OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
* desktop OpenGL does not allow that.
*/
enum class WebGLVertexAttrib0Status : uint8_t {
Default, // default status - no emulation needed
EmulatedUninitializedArray, // need an artificial attrib 0 array, but contents may be left uninitialized
EmulatedInitializedArray // need an artificial attrib 0 array, and contents must be initialized
};
/*
* Enum to track the status of image data (renderbuffer or texture image) presence
* and initialization.
*
* - NoImageData is the initial state before any image data is allocated.
* - InitializedImageData is the state after image data is allocated and initialized.
* - UninitializedImageData is an intermediate state where data is allocated but not
* initialized. It is the state that renderbuffers are in after a renderbufferStorage call,
* and it is the state that texture images are in after a texImage2D call with null data.
*/
enum class WebGLImageDataStatus : uint8_t {
NoImageData,
UninitializedImageData,
InitializedImageData
};
/*
* The formats that may participate, either as source or destination formats,
* in WebGL texture conversions. This includes:
* - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
* - additional formats provided by extensions, e.g. RGB32F
* - additional source formats, depending on browser details, used when uploading
* textures from DOM elements. See gfxImageSurface::Format().
*/
enum class WebGLTexelFormat : uint8_t {
// returned by SurfaceFromElementResultToImageSurface to indicate absence of image data
None,
// common value for formats for which format conversions are not supported
FormatNotSupportingAnyConversion,
// dummy pseudo-format meaning "use the other format".
// For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
// is implicitly treated as being RGB8 itself.
Auto,
// 1-channel formats
A8,
A16F, // OES_texture_half_float
A32F, // OES_texture_float
R8,
R16F, // OES_texture_half_float
R32F, // OES_texture_float
// 2-channel formats
RA8,
RA16F, // OES_texture_half_float
RA32F, // OES_texture_float
RG8,
RG16F,
RG32F,
// 3-channel formats
RGB8,
RGB565,
RGB11F11F10F,
RGB16F, // OES_texture_half_float
RGB32F, // OES_texture_float
// 4-channel formats
RGBA8,
RGBA5551,
RGBA4444,
RGBA16F, // OES_texture_half_float
RGBA32F, // OES_texture_float
// DOM element source only formats.
RGBX8,
BGRX8,
BGRA8
};
enum class WebGLTexImageFunc : uint8_t {
TexImage,
TexSubImage,
CopyTexImage,
CopyTexSubImage,
CompTexImage,
CompTexSubImage,
};
enum class WebGLTexDimensions : uint8_t {
Tex2D,
Tex3D
};
// Please keep extensions in alphabetic order.
enum class WebGLExtensionID : uint8_t {
ANGLE_instanced_arrays,
EXT_blend_minmax,
EXT_color_buffer_float,
EXT_color_buffer_half_float,
EXT_frag_depth,
EXT_sRGB,
EXT_shader_texture_lod,
EXT_texture_filter_anisotropic,
EXT_disjoint_timer_query,
MOZ_debug,
OES_element_index_uint,
OES_standard_derivatives,
OES_texture_float,
OES_texture_float_linear,
OES_texture_half_float,
OES_texture_half_float_linear,
OES_vertex_array_object,
WEBGL_color_buffer_float,
WEBGL_compressed_texture_astc,
WEBGL_compressed_texture_atc,
WEBGL_compressed_texture_etc,
WEBGL_compressed_texture_etc1,
WEBGL_compressed_texture_pvrtc,
WEBGL_compressed_texture_s3tc,
WEBGL_compressed_texture_s3tc_srgb,
WEBGL_debug_renderer_info,
WEBGL_debug_shaders,
WEBGL_depth_texture,
WEBGL_draw_buffers,
WEBGL_lose_context,
Max,
Unknown
};
class UniqueBuffer
{
// Like UniquePtr<>, but for void* and malloc/calloc/free.
void* mBuffer;
public:
UniqueBuffer()
: mBuffer(nullptr)
{ }
MOZ_IMPLICIT UniqueBuffer(void* buffer)
: mBuffer(buffer)
{ }
~UniqueBuffer() {
free(mBuffer);
}
UniqueBuffer(UniqueBuffer&& other) {
this->mBuffer = other.mBuffer;
other.mBuffer = nullptr;
}
UniqueBuffer& operator =(UniqueBuffer&& other) {
free(this->mBuffer);
this->mBuffer = other.mBuffer;
other.mBuffer = nullptr;
return *this;
}
UniqueBuffer& operator =(void* newBuffer) {
free(this->mBuffer);
this->mBuffer = newBuffer;
return *this;
}
explicit operator bool() const { return bool(mBuffer); }
void* get() const { return mBuffer; }
UniqueBuffer(const UniqueBuffer& other) = delete; // construct using Move()!
void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include <stdarg.h>
MOZ_BEGIN_EXTERN_C
/*
* The crash reason is defined as a global variable here rather than in the
* crash reporter itself to make it available to all code, even libraries like
* JS that don't link with the crash reporter directly. This value will only
* be consumed if the crash reporter is used by the target application.
*/
MFBT_DATA const char* gMozCrashReason = nullptr;
#ifndef DEBUG
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
MOZ_CrashOOL(int aLine, const char* aReason)
#else
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason)
#endif
{
#ifdef DEBUG
MOZ_ReportCrash(aReason, aFilename, aLine);
#endif
gMozCrashReason = aReason;
MOZ_REALLY_CRASH(aLine);
}
static char sPrintfCrashReason[sPrintfCrashReasonSize] = {};
static mozilla::Atomic<bool> sCrashing(false);
#ifndef DEBUG
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void
MOZ_CrashPrintf(int aLine, const char* aFormat, ...)
#else
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void
MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...)
#endif
{
if (!sCrashing.compareExchange(false, true)) {
// In the unlikely event of a race condition, skip
// setting the crash reason and just crash safely.
MOZ_REALLY_CRASH(aLine);
}
va_list aArgs;
va_start(aArgs, aFormat);
int ret = vsnprintf(sPrintfCrashReason, sPrintfCrashReasonSize,
aFormat, aArgs);
va_end(aArgs);
MOZ_RELEASE_ASSERT(ret >= 0 && size_t(ret) < sPrintfCrashReasonSize,
"Could not write the explanation string to the supplied buffer!");
#ifdef DEBUG
MOZ_ReportCrash(sPrintfCrashReason, aFilename, aLine);
#endif
gMozCrashReason = sPrintfCrashReason;
MOZ_REALLY_CRASH(aLine);
}
MOZ_END_EXTERN_C

View File

@ -0,0 +1,659 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementations of runtime and static assertion macros for C and C++. */
#ifndef mozilla_Assertions_h
#define mozilla_Assertions_h
#if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus)
#define MOZ_DUMP_ASSERTION_STACK
#endif
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/Types.h"
#ifdef MOZ_DUMP_ASSERTION_STACK
#include "nsTraceRefcnt.h"
#endif
/*
* The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter
* if present. It is declared here (and defined in Assertions.cpp) to make it
* available to all code, even libraries that don't link with the crash reporter
* directly.
*/
MOZ_BEGIN_EXTERN_C
extern MFBT_DATA const char* gMozCrashReason;
MOZ_END_EXTERN_C
#if !defined(DEBUG) && (defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API))
static inline void
AnnotateMozCrashReason(const char* reason)
{
gMozCrashReason = reason;
}
# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__)
#else
# define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0)
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
/*
* TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
* further depends on <windef.h>. We hardcode these few definitions manually
* because those headers clutter the global namespace with a significant
* number of undesired macros and symbols.
*/
MOZ_BEGIN_EXTERN_C
__declspec(dllimport) int __stdcall
TerminateProcess(void* hProcess, unsigned int uExitCode);
__declspec(dllimport) void* __stdcall GetCurrentProcess(void);
MOZ_END_EXTERN_C
#else
# include <signal.h>
#endif
#ifdef ANDROID
# include <android/log.h>
#endif
#if defined(__GNUC__)
# define MOZ_UNUSED_ATTRIBUTE __attribute__((unused))
#else
# define MOZ_UNUSED_ATTRIBUTE /* nothing */
#endif
/*
* MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C.
* In C++11, static_assert is provided by the compiler to the same effect.
* This can be useful when you make certain assumptions about what must hold for
* optimal, or even correct, behavior. For example, you might assert that the
* size of a struct is a multiple of the target architecture's word size:
*
* struct S { ... };
* // C
* MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
* "S should be a multiple of word size for efficiency");
* // C++11
* static_assert(sizeof(S) % sizeof(size_t) == 0,
* "S should be a multiple of word size for efficiency");
*
* This macro can be used in any location where both an extern declaration and a
* typedef could be used.
*/
#ifndef __cplusplus
/*
* Some of the definitions below create an otherwise-unused typedef. This
* triggers compiler warnings with some versions of gcc, so mark the typedefs
* as permissibly-unused to disable the warnings.
*/
# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y
# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y)
# if defined(__SUNPRO_CC)
/*
* The Sun Studio C++ compiler is buggy when declaring, inside a function,
* another extern'd function with an array argument whose length contains a
* sizeof, triggering the error message "sizeof expression not accepted as
* size of array parameter". This bug (6688515, not public yet) would hit
* defining moz_static_assert as a function, so we always define an extern
* array for Sun Studio.
*
* We include the line number in the symbol name in a best-effort attempt
* to avoid conflicts (see below).
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1]
# elif defined(__COUNTER__)
/*
* If there was no preferred alternative, use a compiler-agnostic version.
*
* Note that the non-__COUNTER__ version has a bug in C++: it can't be used
* in both |extern "C"| and normal C++ in the same translation unit. (Alas
* |extern "C"| isn't allowed in a function.) The only affected compiler
* we really care about is gcc 4.2. For that compiler and others like it,
* we include the line number in the function name to do the best we can to
* avoid conflicts. These should be rare: a conflict would require use of
* MOZ_STATIC_ASSERT on the same line in separate files in the same
* translation unit, *and* the uses would have to be in code with
* different linkage, *and* the first observed use must be in C++-linkage
* code.
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_UNUSED_ATTRIBUTE
# else
# define MOZ_STATIC_ASSERT(cond, reason) \
extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_UNUSED_ATTRIBUTE
# endif
#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
#else
#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason)
#endif
MOZ_BEGIN_EXTERN_C
/*
* Prints |aStr| as an assertion failure (using aFilename and aLine as the
* location of the assertion) to the standard debug-output channel.
*
* Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
* method is primarily for internal use in this header, and only secondarily
* for use in implementing release-build assertions.
*/
MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void
MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
#ifdef ANDROID
__android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
"Assertion failure: %s, at %s:%d\n",
aStr, aFilename, aLine);
#else
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
#if defined (MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
#endif
}
MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void
MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
#ifdef ANDROID
__android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
"Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#else
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#if defined(MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
#endif
}
/**
* MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should
* call MOZ_CRASH instead.
*/
#if defined(_MSC_VER)
/*
* On MSVC use the __debugbreak compiler intrinsic, which produces an inline
* (not nested in a system function) breakpoint. This distinctively invokes
* Breakpad without requiring system library symbols on all stack-processing
* machines, as a nested breakpoint would require.
*
* We use __LINE__ to prevent the compiler from folding multiple crash sites
* together, which would make crash reports hard to understand.
*
* We use TerminateProcess with the exit code aborting would generate
* because we don't want to invoke atexit handlers, destructors, library
* unload handlers, and so on when our process might be in a compromised
* state.
*
* We don't use abort() because it'd cause Windows to annoyingly pop up the
* process error dialog multiple times. See bug 345118 and bug 426163.
*
* (Technically these are Windows requirements, not MSVC requirements. But
* practically you need MSVC for debugging, and we only ship builds created
* by MSVC, so doing it this way reduces complexity.)
*/
static MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void MOZ_NoReturn(int aLine)
{
*((volatile int*) NULL) = aLine;
TerminateProcess(GetCurrentProcess(), 3);
}
# define MOZ_REALLY_CRASH(line) \
do { \
__debugbreak(); \
MOZ_NoReturn(line); \
} while (0)
#else
# ifdef __cplusplus
# define MOZ_REALLY_CRASH(line) \
do { \
*((volatile int*) NULL) = line; \
::abort(); \
} while (0)
# else
# define MOZ_REALLY_CRASH(line) \
do { \
*((volatile int*) NULL) = line; \
abort(); \
} while (0)
# endif
#endif
/*
* MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a
* Breakpad-compatible way, in both debug and release builds.
*
* MOZ_CRASH is a good solution for "handling" failure cases when you're
* unwilling or unable to handle them more cleanly -- for OOM, for likely memory
* corruption, and so on. It's also a good solution if you need safe behavior
* in release builds as well as debug builds. But if the failure is one that
* should be debugged and fixed, MOZ_ASSERT is generally preferable.
*
* The optional explanation-string, if provided, must be a string literal
* explaining why we're crashing. This argument is intended for use with
* MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's
* obvious why we're crashing.
*
* If we're a DEBUG build and we crash at a MOZ_CRASH which provides an
* explanation-string, we print the string to stderr. Otherwise, we don't
* print anything; this is because we want MOZ_CRASH to be 100% safe in release
* builds, and it's hard to print to stderr safely when memory might have been
* corrupted.
*/
#ifndef DEBUG
# define MOZ_CRASH(...) \
do { \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(__LINE__); \
} while (0)
#else
# define MOZ_CRASH(...) \
do { \
MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(__LINE__); \
} while (0)
#endif
/*
* MOZ_CRASH_UNSAFE_OOL(explanation-string) can be used if the explanation
* string cannot be a string literal (but no other processing needs to be done
* on it). A regular MOZ_CRASH() is preferred wherever possible, as passing
* arbitrary strings from a potentially compromised process is not without risk.
* If the string being passed is the result of a printf-style function,
* consider using MOZ_CRASH_UNSAFE_PRINTF instead.
*
* @note This macro causes data collection because crash strings are annotated
* to crash-stats and are publicly visible. Firefox data stewards must do data
* review on usages of this macro.
*/
#ifndef DEBUG
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
MOZ_CrashOOL(int aLine, const char* aReason);
# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__LINE__, reason)
#else
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason);
# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__FILE__, __LINE__, reason)
#endif
static const size_t sPrintfMaxArgs = 4;
static const size_t sPrintfCrashReasonSize = 1024;
#ifndef DEBUG
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void
MOZ_CrashPrintf(int aLine, const char* aFormat, ...);
# define MOZ_CALL_CRASH_PRINTF(format, ...) \
MOZ_CrashPrintf(__LINE__, format, __VA_ARGS__)
#else
MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void
MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...);
# define MOZ_CALL_CRASH_PRINTF(format, ...) \
MOZ_CrashPrintf(__FILE__, __LINE__, format, __VA_ARGS__)
#endif
/*
* MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more
* information is desired than a string literal can supply. The caller provides
* a printf-style format string, which must be a string literal and between
* 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever
* possible, as passing arbitrary strings to printf from a potentially
* compromised process is not without risk.
*
* @note This macro causes data collection because crash strings are annotated
* to crash-stats and are publicly visible. Firefox data stewards must do data
* review on usages of this macro.
*/
#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
do { \
static_assert( \
MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
"Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \
"Or maybe you want MOZ_CRASH instead?"); \
static_assert( \
MOZ_ARG_COUNT(__VA_ARGS__) <= sPrintfMaxArgs, \
"Only up to 4 additional arguments are allowed!"); \
static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
"The supplied format string is too long!"); \
MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \
} while (0)
MOZ_END_EXTERN_C
/*
* MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
* debug builds. If it is, execution continues. Otherwise, an error message
* including the expression and the explanation-string (if provided) is printed,
* an attempt is made to invoke any existing debugger, and execution halts.
* MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition
* which can correctly be falsy.
*
* The optional explanation-string, if provided, must be a string literal
* explaining the assertion. It is intended for use with assertions whose
* correctness or rationale is non-obvious, and for assertions where the "real"
* condition being tested is best described prosaically. Don't provide an
* explanation if it's not actually helpful.
*
* // No explanation needed: pointer arguments often must not be NULL.
* MOZ_ASSERT(arg);
*
* // An explanation can be helpful to explain exactly how we know an
* // assertion is valid.
* MOZ_ASSERT(state == WAITING_FOR_RESPONSE,
* "given that <thingA> and <thingB>, we must have...");
*
* // Or it might disambiguate multiple identical (save for their location)
* // assertions of the same expression.
* MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
* "we already set [[PrimitiveThis]] for this Boolean object");
* MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
* "we already set [[PrimitiveThis]] for this String object");
*
* MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs
* *only* during debugging, not "in the field". If you want the latter, use
* MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
*
* MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and
* MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare
* enough to require real user testing to hit, but is not security-sensitive.
* This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT
* is firing, it should promptly be converted to a MOZ_ASSERT while the failure
* is being investigated, rather than letting users suffer.
*
* MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined when MOZ_DIAGNOSTIC_ASSERT is like
* MOZ_RELEASE_ASSERT rather than MOZ_ASSERT.
*/
/*
* Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against
* accidentally passing something unintended in lieu of an assertion condition.
*/
#ifdef __cplusplus
# include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
template<typename T>
struct AssertionConditionType
{
typedef typename RemoveReference<T>::Type ValueT;
static_assert(!IsArray<ValueT>::value,
"Expected boolean assertion condition, got an array or a "
"string!");
static_assert(!IsFunction<ValueT>::value,
"Expected boolean assertion condition, got a function! Did "
"you intend to call that function?");
static_assert(!IsFloatingPoint<ValueT>::value,
"It's often a bad idea to assert that a floating-point number "
"is nonzero, because such assertions tend to intermittently "
"fail. Shouldn't your code gracefully handle this case instead "
"of asserting? Anyway, if you really want to do that, write an "
"explicit boolean condition, like !!x or x!=0.");
static const bool isValid = true;
};
} // namespace detail
} // namespace mozilla
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \
"invalid assertion condition")
#else
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
#endif
#if defined(DEBUG) || defined(MOZ_ASAN)
# define MOZ_REPORT_ASSERTION_FAILURE(...) MOZ_ReportAssertionFailure(__VA_ARGS__)
#else
# define MOZ_REPORT_ASSERTION_FAILURE(...) do { /* nothing */ } while (0)
#endif
/* First the single-argument form. */
#define MOZ_ASSERT_HELPER1(expr) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_REPORT_ASSERTION_FAILURE(#expr, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \
MOZ_REALLY_CRASH(__LINE__); \
} \
} while (0)
/* Now the two-argument form. */
#define MOZ_ASSERT_HELPER2(expr, explain) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_REPORT_ASSERTION_FAILURE(#expr " (" explain ")", __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \
MOZ_REALLY_CRASH(__LINE__); \
} \
} while (0)
#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
#define MOZ_RELEASE_ASSERT(...) \
MOZ_RELEASE_ASSERT_GLUE( \
MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
(__VA_ARGS__))
#ifdef DEBUG
# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
#else
# define MOZ_ASSERT(...) do { } while (0)
#endif /* DEBUG */
#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION)
# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
# define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
#else
# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
# ifdef DEBUG
# define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
# endif
#endif
/*
* MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
* true.
*
* MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
*
* As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is
* designed to catch bugs during debugging, not "in the field".
*/
#ifdef DEBUG
# define MOZ_ASSERT_IF(cond, expr) \
do { \
if (cond) { \
MOZ_ASSERT(expr); \
} \
} while (0)
#else
# define MOZ_ASSERT_IF(cond, expr) do { } while (0)
#endif
/*
* MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
* it is undefined behavior for execution to reach this point. No guarantees
* are made about what will happen if this is reached at runtime. Most code
* should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
* asserts.
*/
#if defined(__clang__) || defined(__GNUC__)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
#elif defined(_MSC_VER)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
#else
# ifdef __cplusplus
# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
# else
# define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
# endif
#endif
/*
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it
* can assume that the macro call cannot be reached during execution. This lets
* the compiler generate better-optimized code under some circumstances, at the
* expense of the program's behavior being undefined if control reaches the
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE.
*
* In Gecko, you probably should not use this macro outside of performance- or
* size-critical code, because it's unsafe. If you don't care about code size
* or performance, you should probably use MOZ_ASSERT or MOZ_CRASH.
*
* SpiderMonkey is a different beast, and there it's acceptable to use
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely.
*
* Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid
* not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
* call.
*
* Example usage:
*
* enum ValueType {
* VALUE_STRING,
* VALUE_INT,
* VALUE_FLOAT
* };
*
* int ptrToInt(ValueType type, void* value) {
* {
* // We know for sure that type is either INT or FLOAT, and we want this
* // code to run as quickly as possible.
* switch (type) {
* case VALUE_INT:
* return *(int*) value;
* case VALUE_FLOAT:
* return (int) *(float*) value;
* default:
* MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType");
* }
* }
*/
/*
* Unconditional assert in debug builds for (assumed) unreachable code paths
* that have a safe return without crashing in release builds.
*/
#define MOZ_ASSERT_UNREACHABLE(reason) \
MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
#define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
do { \
MOZ_ASSERT_UNREACHABLE(reason); \
MOZ_ASSUME_UNREACHABLE_MARKER(); \
} while (0)
/**
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds to handle
* unexpected values.
*
* Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
* release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
* requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
* warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
* `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
* a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
* warning stalemate.
*
* // Example before MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case wants to assert in debug builds, fall through in release.
* MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
* MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds!
* case 5:
* return 5;
* }
*
* // Example with MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#ifdef DEBUG
# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
#else
# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
#endif
/*
* MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
* expression, in debug builds and in release builds both. Then, in debug
* builds only, the value of the expression is asserted either true or false
* using MOZ_ASSERT.
*/
#ifdef DEBUG
# define MOZ_ALWAYS_TRUE(expr) \
do { \
if ((expr)) { \
/* Do nothing. */ \
} else { \
MOZ_ASSERT(false, #expr); \
} \
} while (0)
# define MOZ_ALWAYS_FALSE(expr) \
do { \
if ((expr)) { \
MOZ_ASSERT(false, #expr); \
} else { \
/* Do nothing. */ \
} \
} while (0)
# define MOZ_ALWAYS_OK(expr) MOZ_ASSERT((expr).isOk())
# define MOZ_ALWAYS_ERR(expr) MOZ_ASSERT((expr).isErr())
#else
# define MOZ_ALWAYS_TRUE(expr) \
do { \
if ((expr)) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
# define MOZ_ALWAYS_FALSE(expr) \
do { \
if ((expr)) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
# define MOZ_ALWAYS_OK(expr) \
do { \
if ((expr).isOk()) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
# define MOZ_ALWAYS_ERR(expr) \
do { \
if ((expr).isErr()) { \
/* Silence MOZ_MUST_USE. */ \
} \
} while (0)
#endif
#undef MOZ_DUMP_ASSERTION_STACK
#undef MOZ_CRASH_CRASHREPORT
#endif /* mozilla_Assertions_h */

View File

@ -0,0 +1,563 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements (almost always) lock-free atomic operations. The operations here
* are a subset of that which can be found in C++11's <atomic> header, with a
* different API to enforce consistent memory ordering constraints.
*
* Anyone caught using |volatile| for inter-thread memory safety needs to be
* sent a copy of this header and the C++11 standard.
*/
#ifndef mozilla_Atomics_h
#define mozilla_Atomics_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/TypeTraits.h"
#include <atomic>
#include <stdint.h>
namespace mozilla {
/**
* An enum of memory ordering possibilities for atomics.
*
* Memory ordering is the observable state of distinct values in memory.
* (It's a separate concept from atomicity, which concerns whether an
* operation can ever be observed in an intermediate state. Don't
* conflate the two!) Given a sequence of operations in source code on
* memory, it is *not* always the case that, at all times and on all
* cores, those operations will appear to have occurred in that exact
* sequence. First, the compiler might reorder that sequence, if it
* thinks another ordering will be more efficient. Second, the CPU may
* not expose so consistent a view of memory. CPUs will often perform
* their own instruction reordering, above and beyond that performed by
* the compiler. And each core has its own memory caches, and accesses
* (reads and writes both) to "memory" may only resolve to out-of-date
* cache entries -- not to the "most recently" performed operation in
* some global sense. Any access to a value that may be used by
* multiple threads, potentially across multiple cores, must therefore
* have a memory ordering imposed on it, for all code on all
* threads/cores to have a sufficiently coherent worldview.
*
* http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and
* http://en.cppreference.com/w/cpp/atomic/memory_order go into more
* detail on all this, including examples of how each mode works.
*
* Note that for simplicity and practicality, not all of the modes in
* C++11 are supported. The missing C++11 modes are either subsumed by
* the modes we provide below, or not relevant for the CPUs we support
* in Gecko. These three modes are confusing enough as it is!
*/
enum MemoryOrdering {
/*
* Relaxed ordering is the simplest memory ordering: none at all.
* When the result of a write is observed, nothing may be inferred
* about other memory. Writes ostensibly performed "before" on the
* writing thread may not yet be visible. Writes performed "after" on
* the writing thread may already be visible, if the compiler or CPU
* reordered them. (The latter can happen if reads and/or writes get
* held up in per-processor caches.) Relaxed ordering means
* operations can always use cached values (as long as the actual
* updates to atomic values actually occur, correctly, eventually), so
* it's usually the fastest sort of atomic access. For this reason,
* *it's also the most dangerous kind of access*.
*
* Relaxed ordering is good for things like process-wide statistics
* counters that don't need to be consistent with anything else, so
* long as updates themselves are atomic. (And so long as any
* observations of that value can tolerate being out-of-date -- if you
* need some sort of up-to-date value, you need some sort of other
* synchronizing operation.) It's *not* good for locks, mutexes,
* reference counts, etc. that mediate access to other memory, or must
* be observably consistent with other memory.
*
* x86 architectures don't take advantage of the optimization
* opportunities that relaxed ordering permits. Thus it's possible
* that using relaxed ordering will "work" on x86 but fail elsewhere
* (ARM, say, which *does* implement non-sequentially-consistent
* relaxed ordering semantics). Be extra-careful using relaxed
* ordering if you can't easily test non-x86 architectures!
*/
Relaxed,
/*
* When an atomic value is updated with ReleaseAcquire ordering, and
* that new value is observed with ReleaseAcquire ordering, prior
* writes (atomic or not) are also observable. What ReleaseAcquire
* *doesn't* give you is any observable ordering guarantees for
* ReleaseAcquire-ordered operations on different objects. For
* example, if there are two cores that each perform ReleaseAcquire
* operations on separate objects, each core may or may not observe
* the operations made by the other core. The only way the cores can
* be synchronized with ReleaseAcquire is if they both
* ReleaseAcquire-access the same object. This implies that you can't
* necessarily describe some global total ordering of ReleaseAcquire
* operations.
*
* ReleaseAcquire ordering is good for (as the name implies) atomic
* operations on values controlling ownership of things: reference
* counts, mutexes, and the like. However, if you are thinking about
* using these to implement your own locks or mutexes, you should take
* a good, hard look at actual lock or mutex primitives first.
*/
ReleaseAcquire,
/*
* When an atomic value is updated with SequentiallyConsistent
* ordering, all writes observable when the update is observed, just
* as with ReleaseAcquire ordering. But, furthermore, a global total
* ordering of SequentiallyConsistent operations *can* be described.
* For example, if two cores perform SequentiallyConsistent operations
* on separate objects, one core will observably perform its update
* (and all previous operations will have completed), then the other
* core will observably perform its update (and all previous
* operations will have completed). (Although those previous
* operations aren't themselves ordered -- they could be intermixed,
* or ordered if they occur on atomic values with ordering
* requirements.) SequentiallyConsistent is the *simplest and safest*
* ordering of atomic operations -- it's always as if one operation
* happens, then another, then another, in some order -- and every
* core observes updates to happen in that single order. Because it
* has the most synchronization requirements, operations ordered this
* way also tend to be slowest.
*
* SequentiallyConsistent ordering can be desirable when multiple
* threads observe objects, and they all have to agree on the
* observable order of changes to them. People expect
* SequentiallyConsistent ordering, even if they shouldn't, when
* writing code, atomic or otherwise. SequentiallyConsistent is also
* the ordering of choice when designing lockless data structures. If
* you don't know what order to use, use this one.
*/
SequentiallyConsistent,
};
namespace detail {
/*
* We provide CompareExchangeFailureOrder to work around a bug in some
* versions of GCC's <atomic> header. See bug 898491.
*/
template<MemoryOrdering Order> struct AtomicOrderConstraints;
template<>
struct AtomicOrderConstraints<Relaxed>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed;
static const std::memory_order LoadOrder = std::memory_order_relaxed;
static const std::memory_order StoreOrder = std::memory_order_relaxed;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_relaxed;
};
template<>
struct AtomicOrderConstraints<ReleaseAcquire>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel;
static const std::memory_order LoadOrder = std::memory_order_acquire;
static const std::memory_order StoreOrder = std::memory_order_release;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_acquire;
};
template<>
struct AtomicOrderConstraints<SequentiallyConsistent>
{
static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst;
static const std::memory_order LoadOrder = std::memory_order_seq_cst;
static const std::memory_order StoreOrder = std::memory_order_seq_cst;
static const std::memory_order CompareExchangeFailureOrder =
std::memory_order_seq_cst;
};
template<typename T, MemoryOrdering Order>
struct IntrinsicBase
{
typedef std::atomic<T> ValueType;
typedef AtomicOrderConstraints<Order> OrderedOp;
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps : public IntrinsicBase<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T load(const typename Base::ValueType& aPtr)
{
return aPtr.load(Base::OrderedOp::LoadOrder);
}
static void store(typename Base::ValueType& aPtr, T aVal)
{
aPtr.store(aVal, Base::OrderedOp::StoreOrder);
}
static T exchange(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static bool compareExchange(typename Base::ValueType& aPtr,
T aOldVal, T aNewVal)
{
return aPtr.compare_exchange_strong(aOldVal, aNewVal,
Base::OrderedOp::AtomicRMWOrder,
Base::OrderedOp::CompareExchangeFailureOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub : public IntrinsicBase<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T add(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T sub(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
{
typedef IntrinsicBase<T*, Order> Base;
static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T inc(typename Base::ValueType& aPtr)
{
return IntrinsicAddSub<T, Order>::add(aPtr, 1);
}
static T dec(typename Base::ValueType& aPtr)
{
return IntrinsicAddSub<T, Order>::sub(aPtr, 1);
}
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
public IntrinsicIncDec<T, Order>
{
typedef IntrinsicBase<T, Order> Base;
static T or_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T xor_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T and_(typename Base::ValueType& aPtr, T aVal)
{
return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order>
: public IntrinsicMemoryOps<T*, Order>, public IntrinsicIncDec<T*, Order>
{
};
template<typename T>
struct ToStorageTypeArgument
{
static constexpr T convert (T aT) { return aT; }
};
template<typename T, MemoryOrdering Order>
class AtomicBase
{
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"mozilla/Atomics.h only supports 32-bit and 64-bit types");
protected:
typedef typename detail::AtomicIntrinsics<T, Order> Intrinsics;
typedef typename Intrinsics::ValueType ValueType;
ValueType mValue;
public:
constexpr AtomicBase() : mValue() {}
explicit constexpr AtomicBase(T aInit)
: mValue(ToStorageTypeArgument<T>::convert(aInit))
{}
// Note: we can't provide operator T() here because Atomic<bool> inherits
// from AtomcBase with T=uint32_t and not T=bool. If we implemented
// operator T() here, it would cause errors when comparing Atomic<bool> with
// a regular bool.
T operator=(T aVal)
{
Intrinsics::store(mValue, aVal);
return aVal;
}
/**
* Performs an atomic swap operation. aVal is stored and the previous
* value of this variable is returned.
*/
T exchange(T aVal)
{
return Intrinsics::exchange(mValue, aVal);
}
/**
* Performs an atomic compare-and-swap operation and returns true if it
* succeeded. This is equivalent to atomically doing
*
* if (mValue == aOldValue) {
* mValue = aNewValue;
* return true;
* } else {
* return false;
* }
*/
bool compareExchange(T aOldValue, T aNewValue)
{
return Intrinsics::compareExchange(mValue, aOldValue, aNewValue);
}
private:
template<MemoryOrdering AnyOrder>
AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) = delete;
};
template<typename T, MemoryOrdering Order>
class AtomicBaseIncDec : public AtomicBase<T, Order>
{
typedef typename detail::AtomicBase<T, Order> Base;
public:
constexpr AtomicBaseIncDec() : Base() {}
explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {}
using Base::operator=;
operator T() const { return Base::Intrinsics::load(Base::mValue); }
T operator++(int) { return Base::Intrinsics::inc(Base::mValue); }
T operator--(int) { return Base::Intrinsics::dec(Base::mValue); }
T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; }
T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; }
private:
template<MemoryOrdering AnyOrder>
AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) = delete;
};
} // namespace detail
/**
* A wrapper for a type that enforces that all memory accesses are atomic.
*
* In general, where a variable |T foo| exists, |Atomic<T> foo| can be used in
* its place. Implementations for integral and pointer types are provided
* below.
*
* Atomic accesses are sequentially consistent by default. You should
* use the default unless you are tall enough to ride the
* memory-ordering roller coaster (if you're not sure, you aren't) and
* you have a compelling reason to do otherwise.
*
* There is one exception to the case of atomic memory accesses: providing an
* initial value of the atomic value is not guaranteed to be atomic. This is a
* deliberate design choice that enables static atomic variables to be declared
* without introducing extra static constructors.
*/
template<typename T,
MemoryOrdering Order = SequentiallyConsistent,
typename Enable = void>
class Atomic;
/**
* Atomic<T> implementation for integral types.
*
* In addition to atomic store and load operations, compound assignment and
* increment/decrement operators are implemented which perform the
* corresponding read-modify-write operation atomically. Finally, an atomic
* swap method is provided.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value &&
!IsSame<T, bool>::value>::Type>
: public detail::AtomicBaseIncDec<T, Order>
{
typedef typename detail::AtomicBaseIncDec<T, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
using Base::operator=;
T operator+=(T aDelta)
{
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
}
T operator-=(T aDelta)
{
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
}
T operator|=(T aVal)
{
return Base::Intrinsics::or_(Base::mValue, aVal) | aVal;
}
T operator^=(T aVal)
{
return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal;
}
T operator&=(T aVal)
{
return Base::Intrinsics::and_(Base::mValue, aVal) & aVal;
}
private:
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for pointer types.
*
* An atomic compare-and-swap primitive for pointer variables is provided, as
* are atomic increment and decement operators. Also provided are the compound
* assignment operators for addition and subtraction. Atomic swap (via
* exchange()) is included as well.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
{
typedef typename detail::AtomicBaseIncDec<T*, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T* aInit) : Base(aInit) {}
using Base::operator=;
T* operator+=(ptrdiff_t aDelta)
{
return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
}
T* operator-=(ptrdiff_t aDelta)
{
return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
}
private:
Atomic(Atomic<T*, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for enum types.
*
* The atomic store and load operations and the atomic swap method is provided.
*/
template<typename T, MemoryOrdering Order>
class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type>
: public detail::AtomicBase<T, Order>
{
typedef typename detail::AtomicBase<T, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
operator T() const { return T(Base::Intrinsics::load(Base::mValue)); }
using Base::operator=;
private:
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
* Atomic<T> implementation for boolean types.
*
* The atomic store and load operations and the atomic swap method is provided.
*
* Note:
*
* - sizeof(Atomic<bool>) != sizeof(bool) for some implementations of
* bool and/or some implementations of std::atomic. This is allowed in
* [atomic.types.generic]p9.
*
* - It's not obvious whether the 8-bit atomic functions on Windows are always
* inlined or not. If they are not inlined, the corresponding functions in the
* runtime library are not available on Windows XP. This is why we implement
* Atomic<bool> with an underlying type of uint32_t.
*/
template<MemoryOrdering Order>
class Atomic<bool, Order>
: protected detail::AtomicBase<uint32_t, Order>
{
typedef typename detail::AtomicBase<uint32_t, Order> Base;
public:
constexpr Atomic() : Base() {}
explicit constexpr Atomic(bool aInit) : Base(aInit) {}
// We provide boolean wrappers for the underlying AtomicBase methods.
MOZ_IMPLICIT operator bool() const
{
return Base::Intrinsics::load(Base::mValue);
}
bool operator=(bool aVal)
{
return Base::operator=(aVal);
}
bool exchange(bool aVal)
{
return Base::exchange(aVal);
}
bool compareExchange(bool aOldValue, bool aNewValue)
{
return Base::compareExchange(aOldValue, aNewValue);
}
private:
Atomic(Atomic<bool, Order>& aOther) = delete;
};
} // namespace mozilla
#endif /* mozilla_Atomics_h */

View File

@ -0,0 +1,747 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementations of various class and method modifier attributes. */
#ifndef mozilla_Attributes_h
#define mozilla_Attributes_h
#include "mozilla/Compiler.h"
/*
* MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must be inlined, even if the compiler thinks
* otherwise. This is only a (much) stronger version of the inline hint:
* compilers are not guaranteed to respect it (although they're much more likely
* to do so).
*
* The MOZ_ALWAYS_INLINE_EVEN_DEBUG macro is yet stronger. It tells the
* compiler to inline even in DEBUG builds. It should be used very rarely.
*/
#if defined(_MSC_VER)
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline
#elif defined(__GNUC__)
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline
#else
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline
#endif
#if !defined(DEBUG)
# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
#elif defined(_MSC_VER) && !defined(__cplusplus)
# define MOZ_ALWAYS_INLINE __inline
#else
# define MOZ_ALWAYS_INLINE inline
#endif
#if defined(_MSC_VER)
/*
* g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
* without warnings (functionality used by the macros below). These modes are
* detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more
* standardly, by checking whether __cplusplus has a C++11 or greater value.
* Current versions of g++ do not correctly set __cplusplus, so we check both
* for forward compatibility.
*/
# define MOZ_HAVE_NEVER_INLINE __declspec(noinline)
# define MOZ_HAVE_NORETURN __declspec(noreturn)
#elif defined(__clang__)
/*
* Per Clang documentation, "Note that marketing version numbers should not
* be used to check for language features, as different vendors use different
* numbering schemes. Instead, use the feature checking macros."
*/
# ifndef __has_extension
# define __has_extension __has_feature /* compatibility, for older versions of clang */
# endif
# if __has_attribute(noinline)
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# endif
# if __has_attribute(noreturn)
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
# endif
#elif defined(__GNUC__)
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
# define MOZ_HAVE_NORETURN_PTR __attribute__((noreturn))
#endif
/*
* When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN
* to mark some false positives
*/
#ifdef __clang_analyzer__
# if __has_extension(attribute_analyzer_noreturn)
# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
# endif
#endif
/*
* MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must never be inlined, even if the compiler would
* otherwise choose to inline the method. Compilers aren't absolutely
* guaranteed to support this, but most do.
*/
#if defined(MOZ_HAVE_NEVER_INLINE)
# define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE
#else
# define MOZ_NEVER_INLINE /* no support */
#endif
/*
* MOZ_NORETURN, specified at the start of a function declaration, indicates
* that the given function does not return. (The function definition does not
* need to be annotated.)
*
* MOZ_NORETURN void abort(const char* msg);
*
* This modifier permits the compiler to optimize code assuming a call to such a
* function will never return. It also enables the compiler to avoid spurious
* warnings about not initializing variables, or about any other seemingly-dodgy
* operations performed after the function returns.
*
* There are two variants. The GCC version of NORETURN may be applied to a
* function pointer, while for MSVC it may not.
*
* This modifier does not affect the corresponding function's linking behavior.
*/
#if defined(MOZ_HAVE_NORETURN)
# define MOZ_NORETURN MOZ_HAVE_NORETURN
#else
# define MOZ_NORETURN /* no support */
#endif
#if defined(MOZ_HAVE_NORETURN_PTR)
# define MOZ_NORETURN_PTR MOZ_HAVE_NORETURN_PTR
#else
# define MOZ_NORETURN_PTR /* no support */
#endif
/**
* MOZ_COLD tells the compiler that a function is "cold", meaning infrequently
* executed. This may lead it to optimize for size more aggressively than speed,
* or to allocate the body of the function in a distant part of the text segment
* to help keep it from taking up unnecessary icache when it isn't in use.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_COLD int foo();
*
* or
*
* MOZ_COLD int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_COLD __attribute__ ((cold))
#else
# define MOZ_COLD
#endif
/**
* MOZ_NONNULL tells the compiler that some of the arguments to a function are
* known to be non-null. The arguments are a list of 1-based argument indexes
* identifying arguments which are known to be non-null.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_NONNULL(1, 2) int foo(char *p, char *q);
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__)))
#else
# define MOZ_NONNULL(...)
#endif
/**
* MOZ_NONNULL_RETURN tells the compiler that the function's return value is
* guaranteed to be a non-null pointer, which may enable the compiler to
* optimize better at call sites.
*
* Place this attribute at the end of a function declaration. For example,
*
* char* foo(char *p, char *q) MOZ_NONNULL_RETURN;
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_NONNULL_RETURN __attribute__ ((returns_nonnull))
#else
# define MOZ_NONNULL_RETURN
#endif
/*
* MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function
* declaration, indicates that for the purposes of static analysis, this
* function does not return. (The function definition does not need to be
* annotated.)
*
* MOZ_ReportCrash(const char* s, const char* file, int ln)
* MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
*
* Some static analyzers, like scan-build from clang, can use this information
* to eliminate false positives. From the upstream documentation of scan-build:
* "This attribute is useful for annotating assertion handlers that actually
* can return, but for the purpose of using the analyzer we want to pretend
* that such functions do not return."
*
*/
#if defined(MOZ_HAVE_ANALYZER_NORETURN)
# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN
#else
# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */
#endif
/*
* MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time
* instrumentation shipped with Clang and GCC) to not instrument the annotated
* function. Furthermore, it will prevent the compiler from inlining the
* function because inlining currently breaks the blacklisting mechanism of
* AddressSanitizer.
*/
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define MOZ_HAVE_ASAN_BLACKLIST
# endif
#elif defined(__GNUC__)
# if defined(__SANITIZE_ADDRESS__)
# define MOZ_HAVE_ASAN_BLACKLIST
# endif
#endif
#if defined(MOZ_HAVE_ASAN_BLACKLIST)
# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address))
#else
# define MOZ_ASAN_BLACKLIST /* nothing */
#endif
/*
* MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time
* instrumentation shipped with Clang) to not instrument the annotated function.
* Furthermore, it will prevent the compiler from inlining the function because
* inlining currently breaks the blacklisting mechanism of ThreadSanitizer.
*/
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread))
# else
# define MOZ_TSAN_BLACKLIST /* nothing */
# endif
#else
# define MOZ_TSAN_BLACKLIST /* nothing */
#endif
/*
* The MOZ_NO_SANITIZE_* family of macros is an annotation based on a more recently
* introduced Clang feature that allows disabling various sanitizer features for
* the particular function, including those from UndefinedBehaviorSanitizer.
*/
#if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define MOZ_HAVE_NO_SANITIZE_ATTR
# endif
#endif
#if defined(MOZ_HAVE_NO_SANITIZE_ATTR)
# define MOZ_NO_SANITIZE_UINT_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
# define MOZ_NO_SANITIZE_INT_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
#else
# define MOZ_NO_SANITIZE_UINT_OVERFLOW /* nothing */
# define MOZ_NO_SANITIZE_INT_OVERFLOW /* nothing */
#endif
#undef MOZ_HAVE_NO_SANITIZE_ATTR
/**
* MOZ_ALLOCATOR tells the compiler that the function it marks returns either a
* "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the
* block is not pointed to by any other reachable pointer in the program.
* "Pointer-free" means that the block contains no pointers to any valid object
* in the program. It may be initialized with other (non-pointer) values.
*
* Placing this attribute on appropriate functions helps GCC analyze pointer
* aliasing more accurately in their callers.
*
* GCC warns if a caller ignores the value returned by a function marked with
* MOZ_ALLOCATOR: it is hard to imagine cases where dropping the value returned
* by a function that meets the criteria above would be intentional.
*
* Place this attribute after the argument list and 'this' qualifiers of a
* function definition. For example, write
*
* void *my_allocator(size_t) MOZ_ALLOCATOR;
*
* or
*
* void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result))
#else
# define MOZ_ALLOCATOR
#endif
/**
* MOZ_MUST_USE tells the compiler to emit a warning if a function's
* return value is not used by the caller.
*
* Place this attribute at the very beginning of a function declaration. For
* example, write
*
* MOZ_MUST_USE int foo();
* or
* MOZ_MUST_USE int foo() { return 42; }
*
* MOZ_MUST_USE is most appropriate for functions where the return value is
* some kind of success/failure indicator -- often |nsresult|, |bool| or |int|
* -- because these functions are most commonly the ones that have missing
* checks. There are three cases of note.
*
* - Fallible functions whose return values should always be checked. For
* example, a function that opens a file should always be checked because any
* subsequent operations on the file will fail if opening it fails. Such
* functions should be given a MOZ_MUST_USE annotation.
*
* - Fallible functions whose return value need not always be checked. For
* example, a function that closes a file might not be checked because it's
* common that no further operations would be performed on the file. Such
* functions do not need a MOZ_MUST_USE annotation.
*
* - Infallible functions, i.e. ones that always return a value indicating
* success. These do not need a MOZ_MUST_USE annotation. Ideally, they would
* be converted to not return a success/failure indicator, though sometimes
* interface constraints prevent this.
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_MUST_USE __attribute__ ((warn_unused_result))
#else
# define MOZ_MUST_USE
#endif
/**
* MOZ_MAYBE_UNUSED suppresses compiler warnings about functions that are
* never called (in this build configuration, at least).
*
* Place this attribute at the very beginning of a function declaration. For
* example, write
*
* MOZ_MAYBE_UNUSED int foo();
*
* or
*
* MOZ_MAYBE_UNUSED int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_MAYBE_UNUSED __attribute__ ((__unused__))
#elif defined(_MSC_VER)
# define MOZ_MAYBE_UNUSED __pragma(warning(suppress:4505))
#else
# define MOZ_MAYBE_UNUSED
#endif
#ifdef __cplusplus
/**
* MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch
* cases that fall through without a break or return statement. MOZ_FALLTHROUGH
* is only needed on cases that have code.
*
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds. See comment
* in Assertions.h for more details.
*
* switch (foo) {
* case 1: // These cases have no code. No fallthrough annotations are needed.
* case 2:
* case 3: // This case has code, so a fallthrough annotation is needed!
* foo++;
* MOZ_FALLTHROUGH;
* case 4:
* return foo;
*
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(clang::fallthrough)
# define MOZ_FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
# define MOZ_FALLTHROUGH [[gnu::fallthrough]]
#elif defined(_MSC_VER)
/*
* MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
* https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
*/
# include <sal.h>
# define MOZ_FALLTHROUGH __fallthrough
#else
# define MOZ_FALLTHROUGH /* FALLTHROUGH */
#endif
/*
* The following macros are attributes that support the static analysis plugin
* included with Mozilla, and will be implemented (when such support is enabled)
* as C++11 attributes. Since such attributes are legal pretty much everywhere
* and have subtly different semantics depending on their placement, the
* following is a guide on where to place the attributes.
*
* Attributes that apply to a struct or class precede the name of the class:
* (Note that this is different from the placement of final for classes!)
*
* class MOZ_CLASS_ATTRIBUTE SomeClass {};
*
* Attributes that apply to functions follow the parentheses and const
* qualifiers but precede final, override and the function body:
*
* void DeclaredFunction() MOZ_FUNCTION_ATTRIBUTE;
* void SomeFunction() MOZ_FUNCTION_ATTRIBUTE {}
* void PureFunction() const MOZ_FUNCTION_ATTRIBUTE = 0;
* void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE override;
*
* Attributes that apply to variables or parameters follow the variable's name:
*
* int variable MOZ_VARIABLE_ATTRIBUTE;
*
* Attributes that apply to types follow the type name:
*
* typedef int MOZ_TYPE_ATTRIBUTE MagicInt;
* int MOZ_TYPE_ATTRIBUTE someVariable;
* int* MOZ_TYPE_ATTRIBUTE magicPtrInt;
* int MOZ_TYPE_ATTRIBUTE* ptrToMagicInt;
*
* Attributes that apply to statements precede the statement:
*
* MOZ_IF_ATTRIBUTE if (x == 0)
* MOZ_DO_ATTRIBUTE do { } while (0);
*
* Attributes that apply to labels precede the label:
*
* MOZ_LABEL_ATTRIBUTE target:
* goto target;
* MOZ_CASE_ATTRIBUTE case 5:
* MOZ_DEFAULT_ATTRIBUTE default:
*
* The static analyses that are performed by the plugin are as follows:
*
* MOZ_CAN_RUN_SCRIPT: Applies to functions which can run script. Callers of
* this function must also be marked as MOZ_CAN_RUN_SCRIPT, and all refcounted
* arguments must be strongly held in the caller.
* MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate
* subclasses must provide an exact override of this method; if a subclass
* does not override this method, the compiler will emit an error. This
* attribute is not limited to virtual methods, so if it is applied to a
* nonvirtual method and the subclass does not provide an equivalent
* definition, the compiler will emit an error.
* MOZ_STACK_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the stack, so it is a compile-time error to use it, or
* an array of such objects, as a global or static variable, or as the type of
* a new expression (unless placement new is being used). If a member of
* another class uses this class, or if another class inherits from this
* class, then it is considered to be a stack class as well, although this
* attribute need not be provided in such cases.
* MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the stack or in static storage, so it is a compile-time
* error to use it, or an array of such objects, as the type of a new
* expression. If a member of another class uses this class, or if another
* class inherits from this class, then it is considered to be a non-heap class
* as well, although this attribute need not be provided in such cases.
* MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is
* expected to live on the heap, so it is a compile-time error to use it, or
* an array of such objects, as the type of a variable declaration, or as a
* temporary object. If a member of another class uses this class, or if
* another class inherits from this class, then it is considered to be a heap
* class as well, although this attribute need not be provided in such cases.
* MOZ_NON_TEMPORARY_CLASS: Applies to all classes. Any class with this
* annotation is expected not to live in a temporary. If a member of another
* class uses this class or if another class inherits from this class, then it
* is considered to be a non-temporary class as well, although this attribute
* need not be provided in such cases.
* MOZ_RAII: Applies to all classes. Any class with this annotation is assumed
* to be a RAII guard, which is expected to live on the stack in an automatic
* allocation. It is prohibited from being allocated in a temporary, static
* storage, or on the heap. This is a combination of MOZ_STACK_CLASS and
* MOZ_NON_TEMPORARY_CLASS.
* MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are
* intended to prevent introducing static initializers. This attribute
* currently makes it a compile-time error to instantiate these classes
* anywhere other than at the global scope, or as a static member of a class.
* In non-debug mode, it also prohibits non-trivial constructors and
* destructors.
* MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial
* or constexpr constructor and a trivial destructor. Setting this attribute
* on a class makes it a compile-time error for that class to get a
* non-trivial constructor or destructor for any reason.
* MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
* value is allocated on the heap, and will as a result check such allocations
* during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
* MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors
* are disallowed by default unless they are marked as MOZ_IMPLICIT. This
* attribute must be used for constructors which intend to provide implicit
* conversions.
* MOZ_IS_REFPTR: Applies to class declarations of ref pointer to mark them as
* such for use with static-analysis.
* A ref pointer is an object wrapping a pointer and automatically taking care
* of its refcounting upon construction/destruction/transfer of ownership.
* This annotation implies MOZ_IS_SMARTPTR_TO_REFCOUNTED.
* MOZ_IS_SMARTPTR_TO_REFCOUNTED: Applies to class declarations of smart
* pointers to ref counted classes to mark them as such for use with
* static-analysis.
* MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile
* time error to pass arithmetic expressions on variables to the function.
* MOZ_OWNING_REF: Applies to declarations of pointers to reference counted
* types. This attribute tells the compiler that the raw pointer is a strong
* reference, where ownership through methods such as AddRef and Release is
* managed manually. This can make the compiler ignore these pointers when
* validating the usage of pointers otherwise.
*
* Example uses include owned pointers inside of unions, and pointers stored
* in POD types where a using a smart pointer class would make the object
* non-POD.
* MOZ_NON_OWNING_REF: Applies to declarations of pointers to reference counted
* types. This attribute tells the compiler that the raw pointer is a weak
* reference, which is ensured to be valid by a guarantee that the reference
* will be nulled before the pointer becomes invalid. This can make the compiler
* ignore these pointers when validating the usage of pointers otherwise.
*
* Examples include an mOwner pointer, which is nulled by the owning class's
* destructor, and is null-checked before dereferencing.
* MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted types.
* Occasionally there are non-owning references which are valid, but do not take
* the form of a MOZ_NON_OWNING_REF. Their safety may be dependent on the behaviour
* of API consumers. The string argument passed to this macro documents the safety
* conditions. This can make the compiler ignore these pointers when validating
* the usage of pointers elsewhere.
*
* Examples include an nsIAtom* member which is known at compile time to point to a
* static atom which is valid throughout the lifetime of the program, or an API which
* stores a pointer, but doesn't take ownership over it, instead requiring the API
* consumer to correctly null the value before it becomes invalid.
*
* Use of this annotation is discouraged when a strong reference or one of the above
* two annotations can be used instead.
* MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it
* a compile time error to call AddRef or Release on the return value of a
* function. This is intended to be used with operator->() of our smart
* pointer classes to ensure that the refcount of an object wrapped in a
* smart pointer is not manipulated directly.
* MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time
* error to not use the return value of a function which has this type. This
* is intended to be used with types which it is an error to not use.
* MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it
* a compile time error to instantiate this template with a type parameter which
* has a VTable.
* MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe
* to be moved in memory using memmove().
* MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the
* template arguments are required to be safe to move in memory using
* memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a
* compile time error.
* MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member
* must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types
* used in members of these classes are compile time errors.
* MOZ_NO_DANGLING_ON_TEMPORARIES: Applies to method declarations which return
* a pointer that is freed when the destructor of the class is called. This
* prevents these methods from being called on temporaries of the class,
* reducing risks of use-after-free.
* This attribute cannot be applied to && methods.
* In some cases, adding a deleted &&-qualified overload is too restrictive as
* this method should still be callable as a non-escaping argument to another
* function. This annotation can be used in those cases.
* MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class
* declarations where an instance of the template should be considered, for
* static analysis purposes, to inherit any type annotations (such as
* MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments.
* MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally
* there are class members that are not initialized in the constructor,
* but logic elsewhere in the class ensures they are initialized prior to use.
* Using this attribute on a member disables the check that this member must be
* initialized in constructors via list-initialization, in the constructor body,
* or via functions called from the constructor body.
* MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the
* constructor doesn't initialize all of the member variables and another function
* is used to initialize the rest. This marker is used to make the static analysis
* tool aware that the marked function is part of the initialization process
* and to include the marked function in the scan mechanism that determines witch
* member variables still remain uninitialized.
* MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type
* in parameter without pointer or reference.
* MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to
* use `auto` in place of this type in variable declarations. This is intended to
* be used with types which are intended to be implicitly constructed into other
* other types before being assigned to variables.
* MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations.
* Sometimes derived classes override methods that need to be called by their
* overridden counterparts. This marker indicates that the marked method must
* be called by the method that it overrides.
* MOZ_MUST_RETURN_FROM_CALLER: Applies to function or method declarations.
* Callers of the annotated function/method must return from that function
* within the calling block using an explicit `return` statement.
* Only calls to Constructors, references to local and member variables,
* and calls to functions or methods marked as MOZ_MAY_CALL_AFTER_MUST_RETURN
* may be made after the MUST_RETURN_FROM_CALLER call.
* MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations.
* Calls to these methods may be made in functions after calls a
* MOZ_MUST_RETURN_FROM_CALLER function or method.
*/
#ifdef MOZ_CLANG_PLUGIN
# define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script")))
# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
# define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
# define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class")))
# define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
# ifdef DEBUG
/* in debug builds, these classes do have non-trivial constructors. */
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
# else
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
MOZ_TRIVIAL_CTOR_DTOR
# endif
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
# define MOZ_IS_SMARTPTR_TO_REFCOUNTED __attribute__((annotate("moz_is_smartptr_to_refcounted")))
# define MOZ_IS_REFPTR __attribute__((annotate("moz_is_refptr"))) \
MOZ_IS_SMARTPTR_TO_REFCOUNTED
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
# define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
# define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
# define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
# define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
# define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
# define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
# define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
# define MOZ_NO_DANGLING_ON_TEMPORARIES __attribute__((annotate("moz_no_dangling_on_temporaries")))
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
__attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
# define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
# define MOZ_INIT_OUTSIDE_CTOR \
__attribute__((annotate("moz_ignore_ctor_initialization")))
# define MOZ_IS_CLASS_INIT \
__attribute__((annotate("moz_is_class_init")))
# define MOZ_NON_PARAM \
__attribute__((annotate("moz_non_param")))
# define MOZ_REQUIRED_BASE_METHOD \
__attribute__((annotate("moz_required_base_method")))
# define MOZ_MUST_RETURN_FROM_CALLER \
__attribute__((annotate("moz_must_return_from_caller")))
# define MOZ_MAY_CALL_AFTER_MUST_RETURN \
__attribute__((annotate("moz_may_call_after_must_return")))
/*
* It turns out that clang doesn't like void func() __attribute__ {} without a
* warning, so use pragmas to disable the warning. This code won't work on GCC
* anyways, so the warning is safe to ignore.
*/
# define MOZ_HEAP_ALLOCATOR \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
__attribute__((annotate("moz_heap_allocator"))) \
_Pragma("clang diagnostic pop")
#else
# define MOZ_CAN_RUN_SCRIPT /* nothing */
# define MOZ_MUST_OVERRIDE /* nothing */
# define MOZ_STACK_CLASS /* nothing */
# define MOZ_NONHEAP_CLASS /* nothing */
# define MOZ_HEAP_CLASS /* nothing */
# define MOZ_NON_TEMPORARY_CLASS /* nothing */
# define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
# define MOZ_IMPLICIT /* nothing */
# define MOZ_IS_SMARTPTR_TO_REFCOUNTED /* nothing */
# define MOZ_IS_REFPTR /* nothing */
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
# define MOZ_HEAP_ALLOCATOR /* nothing */
# define MOZ_OWNING_REF /* nothing */
# define MOZ_NON_OWNING_REF /* nothing */
# define MOZ_UNSAFE_REF(reason) /* nothing */
# define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */
# define MOZ_MUST_USE_TYPE /* nothing */
# define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */
# define MOZ_NON_MEMMOVABLE /* nothing */
# define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
# define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
# define MOZ_NO_DANGLING_ON_TEMPORARIES /* nothing */
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
# define MOZ_INIT_OUTSIDE_CTOR /* nothing */
# define MOZ_IS_CLASS_INIT /* nothing */
# define MOZ_NON_PARAM /* nothing */
# define MOZ_NON_AUTOABLE /* nothing */
# define MOZ_REQUIRED_BASE_METHOD /* nothing */
# define MOZ_MUST_RETURN_FROM_CALLER /* nothing */
# define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */
#endif /* MOZ_CLANG_PLUGIN */
#define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
#endif /* __cplusplus */
/**
* Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a
* function or method that is "printf-like"; this will let (some)
* compilers check that the arguments match the template string.
*
* This macro takes two arguments. The first argument is the argument
* number of the template string. The second argument is the argument
* number of the '...' argument holding the arguments.
*
* Argument numbers start at 1. Note that the implicit "this"
* argument of a non-static member function counts as an argument.
*
* So, for a simple case like:
* void print_something (int whatever, const char *fmt, ...);
* The corresponding annotation would be
* MOZ_FORMAT_PRINTF(2, 3)
* However, if "print_something" were a non-static member function,
* then the annotation would be:
* MOZ_FORMAT_PRINTF(3, 4)
*
* The second argument should be 0 for vprintf-like functions; that
* is, those taking a va_list argument.
*
* Note that the checking is limited to standards-conforming
* printf-likes, and in particular this should not be used for
* PR_snprintf and friends, which are "printf-like" but which assign
* different meanings to the various formats.
*
* MinGW requires special handling due to different format specifiers
* on different platforms. The macro __MINGW_PRINTF_FORMAT maps to
* either gnu_printf or ms_printf depending on where we are compiling
* to avoid warnings on format specifiers that are legal.
*/
#ifdef __MINGW32__
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \
__attribute__ ((format (__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck)))
#elif __GNUC__
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \
__attribute__ ((format (printf, stringIndex, firstToCheck)))
#else
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck)
#endif
/**
* To manually declare an XPCOM ABI-compatible virtual function, the following
* macros can be used to handle the non-standard ABI used on Windows for COM
* compatibility. E.g.:
*
* virtual ReturnType MOZ_XPCOM_ABI foo();
*/
#if defined(XP_WIN)
# define MOZ_XPCOM_ABI __stdcall
#else
# define MOZ_XPCOM_ABI
#endif
#endif /* mozilla_Attributes_h */

View File

@ -0,0 +1,256 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Cast operations to supplement the built-in casting operations. */
#ifndef mozilla_Casting_h
#define mozilla_Casting_h
#include "mozilla/Assertions.h"
#include "mozilla/TypeTraits.h"
#include <limits.h>
namespace mozilla {
/**
* Sets the outparam value of type |To| with the same underlying bit pattern of
* |aFrom|.
*
* |To| and |From| must be types of the same size; be careful of cross-platform
* size differences, or this might fail to compile on some but not all
* platforms.
*
* There is also a variant that returns the value directly. In most cases, the
* two variants should be identical. However, in the specific case of x86
* chips, the behavior differs: returning floating-point values directly is done
* through the x87 stack, and x87 loads and stores turn signaling NaNs into
* quiet NaNs... silently. Returning floating-point values via outparam,
* however, is done entirely within the SSE registers when SSE2 floating-point
* is enabled in the compiler, which has semantics-preserving behavior you would
* expect.
*
* If preserving the distinction between signaling NaNs and quiet NaNs is
* important to you, you should use the outparam version. In all other cases,
* you should use the direct return version.
*/
template<typename To, typename From>
inline void
BitwiseCast(const From aFrom, To* aResult)
{
static_assert(sizeof(From) == sizeof(To),
"To and From must have the same size");
union
{
From mFrom;
To mTo;
} u;
u.mFrom = aFrom;
*aResult = u.mTo;
}
template<typename To, typename From>
inline To
BitwiseCast(const From aFrom)
{
To temp;
BitwiseCast<To, From>(aFrom, &temp);
return temp;
}
namespace detail {
enum ToSignedness { ToIsSigned, ToIsUnsigned };
enum FromSignedness { FromIsSigned, FromIsUnsigned };
template<typename From,
typename To,
FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned,
ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned>
struct BoundsCheckImpl;
// Implicit conversions on operands to binary operations make this all a bit
// hard to verify. Attempt to ease the pain below by *only* comparing values
// that are obviously the same type (and will undergo no further conversions),
// even when it's not strictly necessary, for explicitness.
enum UUComparison { FromIsBigger, FromIsNotBigger };
// Unsigned-to-unsigned range check
template<typename From, typename To,
UUComparison = (sizeof(From) > sizeof(To))
? FromIsBigger
: FromIsNotBigger>
struct UnsignedUnsignedCheck;
template<typename From, typename To>
struct UnsignedUnsignedCheck<From, To, FromIsBigger>
{
public:
static bool checkBounds(const From aFrom)
{
return aFrom <= From(To(-1));
}
};
template<typename From, typename To>
struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
{
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From aFrom)
{
return UnsignedUnsignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-unsigned range check
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
{
public:
static bool checkBounds(const From aFrom)
{
if (aFrom < 0) {
return false;
}
if (sizeof(To) >= sizeof(From)) {
return true;
}
return aFrom <= From(To(-1));
}
};
// Unsigned-to-signed range check
enum USComparison { FromIsSmaller, FromIsNotSmaller };
template<typename From, typename To,
USComparison = (sizeof(From) < sizeof(To))
? FromIsSmaller
: FromIsNotSmaller>
struct UnsignedSignedCheck;
template<typename From, typename To>
struct UnsignedSignedCheck<From, To, FromIsSmaller>
{
public:
static bool checkBounds(const From aFrom)
{
return true;
}
};
template<typename From, typename To>
struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
{
public:
static bool checkBounds(const From aFrom)
{
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
return aFrom <= From(MaxValue);
}
};
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
{
public:
static bool checkBounds(const From aFrom)
{
return UnsignedSignedCheck<From, To>::checkBounds(aFrom);
}
};
// Signed-to-signed range check
template<typename From, typename To>
struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
{
public:
static bool checkBounds(const From aFrom)
{
if (sizeof(From) <= sizeof(To)) {
return true;
}
const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
const To MinValue = -MaxValue - To(1);
return From(MinValue) <= aFrom &&
From(aFrom) <= From(MaxValue);
}
};
template<typename From, typename To,
bool TypesAreIntegral = IsIntegral<From>::value &&
IsIntegral<To>::value>
class BoundsChecker;
template<typename From>
class BoundsChecker<From, From, true>
{
public:
static bool checkBounds(const From aFrom) { return true; }
};
template<typename From, typename To>
class BoundsChecker<From, To, true>
{
public:
static bool checkBounds(const From aFrom)
{
return BoundsCheckImpl<From, To>::checkBounds(aFrom);
}
};
template<typename From, typename To>
inline bool
IsInBounds(const From aFrom)
{
return BoundsChecker<From, To>::checkBounds(aFrom);
}
} // namespace detail
/**
* Cast a value of integral type |From| to a value of integral type |To|,
* asserting that the cast will be a safe cast per C++ (that is, that |to| is in
* the range of values permitted for the type |From|).
*/
template<typename To, typename From>
inline To
AssertedCast(const From aFrom)
{
MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
return static_cast<To>(aFrom);
}
/**
* Cast a value of integral type |From| to a value of integral type |To|,
* release asserting that the cast will be a safe cast per C++ (that is, that
* |to| is in the range of values permitted for the type |From|).
*/
template<typename To, typename From>
inline To
ReleaseAssertedCast(const From aFrom)
{
MOZ_RELEASE_ASSERT((detail::IsInBounds<From, To>(aFrom)));
return static_cast<To>(aFrom);
}
} // namespace mozilla
#endif /* mozilla_Casting_h */

View File

@ -0,0 +1,791 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Provides checked integers, detecting integer overflow and divide-by-0. */
#ifndef mozilla_CheckedInt_h
#define mozilla_CheckedInt_h
#include <stdint.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/IntegerTypeTraits.h"
namespace mozilla {
template<typename T> class CheckedInt;
namespace detail {
/*
* Step 1: manually record supported types
*
* What's nontrivial here is that there are different families of integer
* types: basic integer types and stdint types. It is merrily undefined which
* types from one family may be just typedefs for a type from another family.
*
* For example, on GCC 4.6, aside from the basic integer types, the only other
* type that isn't just a typedef for some of them, is int8_t.
*/
struct UnsupportedType {};
template<typename IntegerType>
struct IsSupportedPass2
{
static const bool value = false;
};
template<typename IntegerType>
struct IsSupported
{
static const bool value = IsSupportedPass2<IntegerType>::value;
};
template<>
struct IsSupported<int8_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint8_t>
{ static const bool value = true; };
template<>
struct IsSupported<int16_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint16_t>
{ static const bool value = true; };
template<>
struct IsSupported<int32_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint32_t>
{ static const bool value = true; };
template<>
struct IsSupported<int64_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint64_t>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<signed char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<long long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned long long>
{ static const bool value = true; };
/*
* Step 2: Implement the actual validity checks.
*
* Ideas taken from IntegerLib, code different.
*/
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
struct TwiceBiggerType
{
typedef typename detail::StdintTypeForSizeAndSignedness<
sizeof(IntegerType) * 2,
IsSigned<IntegerType>::value
>::Type Type;
};
template<typename IntegerType>
struct TwiceBiggerType<IntegerType, 8>
{
typedef UnsupportedType Type;
};
template<typename T>
inline bool
HasSignBit(T aX)
{
// In C++, right bit shifts on negative values is undefined by the standard.
// Notice that signed-to-unsigned conversions are always well-defined in the
// standard, as the value congruent modulo 2**n as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
return bool(typename MakeUnsigned<T>::Type(aX) >>
PositionOfSignBit<T>::value);
}
// Bitwise ops may return a larger type, so it's good to use this inline
// helper guaranteeing that the result is really of type T.
template<typename T>
inline T
BinaryComplement(T aX)
{
return ~aX;
}
template<typename T,
typename U,
bool IsTSigned = IsSigned<T>::value,
bool IsUSigned = IsSigned<U>::value>
struct DoesRangeContainRange
{
};
template<typename T, typename U, bool Signedness>
struct DoesRangeContainRange<T, U, Signedness, Signedness>
{
static const bool value = sizeof(T) >= sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, true, false>
{
static const bool value = sizeof(T) > sizeof(U);
};
template<typename T, typename U>
struct DoesRangeContainRange<T, U, false, true>
{
static const bool value = false;
};
template<typename T,
typename U,
bool IsTSigned = IsSigned<T>::value,
bool IsUSigned = IsSigned<U>::value,
bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
struct IsInRangeImpl {};
template<typename T, typename U, bool IsTSigned, bool IsUSigned>
struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
{
static bool constexpr run(U)
{
return true;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, true, false>
{
static bool constexpr run(U aX)
{
return aX <= MaxValue<T>::value && aX >= MinValue<T>::value;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, false, false>
{
static bool constexpr run(U aX)
{
return aX <= MaxValue<T>::value;
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, false, false>
{
static bool constexpr run(U aX)
{
return sizeof(T) > sizeof(U) || aX <= U(MaxValue<T>::value);
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, true, false>
{
static bool constexpr run(U aX)
{
return sizeof(T) >= sizeof(U)
? aX >= 0
: aX >= 0 && aX <= U(MaxValue<T>::value);
}
};
template<typename T, typename U>
inline constexpr bool
IsInRange(U aX)
{
return IsInRangeImpl<T, U>::run(aX);
}
template<typename T>
inline bool
IsAddValid(T aX, T aY)
{
// Addition is valid if the sign of aX+aY is equal to either that of aX or
// that of aY. Since the value of aX+aY is undefined if we have a signed
// type, we compute it using the unsigned type of the same size. Beware!
// These bitwise operations can return a larger integer type, if T was a
// small type like int8_t, so we explicitly cast to T.
typename MakeUnsigned<T>::Type ux = aX;
typename MakeUnsigned<T>::Type uy = aY;
typename MakeUnsigned<T>::Type result = ux + uy;
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
: BinaryComplement(aX) >= aY;
}
template<typename T>
inline bool
IsSubValid(T aX, T aY)
{
// Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
// have same sign. Since the value of aX-aY is undefined if we have a signed
// type, we compute it using the unsigned type of the same size.
typename MakeUnsigned<T>::Type ux = aX;
typename MakeUnsigned<T>::Type uy = aY;
typename MakeUnsigned<T>::Type result = ux - uy;
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
: aX >= aY;
}
template<typename T,
bool IsTSigned = IsSigned<T>::value,
bool TwiceBiggerTypeIsSupported =
IsSupported<typename TwiceBiggerType<T>::Type>::value>
struct IsMulValidImpl {};
template<typename T, bool IsTSigned>
struct IsMulValidImpl<T, IsTSigned, true>
{
static bool run(T aX, T aY)
{
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
return IsInRange<T>(product);
}
};
template<typename T>
struct IsMulValidImpl<T, true, false>
{
static bool run(T aX, T aY)
{
const T max = MaxValue<T>::value;
const T min = MinValue<T>::value;
if (aX == 0 || aY == 0) {
return true;
}
if (aX > 0) {
return aY > 0
? aX <= max / aY
: aY >= min / aX;
}
// If we reach this point, we know that aX < 0.
return aY > 0
? aX >= min / aY
: aY >= max / aX;
}
};
template<typename T>
struct IsMulValidImpl<T, false, false>
{
static bool run(T aX, T aY)
{
return aY == 0 || aX <= MaxValue<T>::value / aY;
}
};
template<typename T>
inline bool
IsMulValid(T aX, T aY)
{
return IsMulValidImpl<T>::run(aX, aY);
}
template<typename T>
inline bool
IsDivValid(T aX, T aY)
{
// Keep in mind that in the signed case, min/-1 is invalid because
// abs(min)>max.
return aY != 0 &&
!(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
}
template<typename T, bool IsTSigned = IsSigned<T>::value>
struct IsModValidImpl;
template<typename T>
inline bool
IsModValid(T aX, T aY)
{
return IsModValidImpl<T>::run(aX, aY);
}
/*
* Mod is pretty simple.
* For now, let's just use the ANSI C definition:
* If aX or aY are negative, the results are implementation defined.
* Consider these invalid.
* Undefined for aY=0.
* The result will never exceed either aX or aY.
*
* Checking that aX>=0 is a warning when T is unsigned.
*/
template<typename T>
struct IsModValidImpl<T, false>
{
static inline bool run(T aX, T aY)
{
return aY >= 1;
}
};
template<typename T>
struct IsModValidImpl<T, true>
{
static inline bool run(T aX, T aY)
{
if (aX < 0) {
return false;
}
return aY >= 1;
}
};
template<typename T, bool IsSigned = IsSigned<T>::value>
struct NegateImpl;
template<typename T>
struct NegateImpl<T, false>
{
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
{
// Handle negation separately for signed/unsigned, for simpler code and to
// avoid an MSVC warning negating an unsigned value.
return CheckedInt<T>(0, aVal.isValid() && aVal.mValue == 0);
}
};
template<typename T>
struct NegateImpl<T, true>
{
static CheckedInt<T> negate(const CheckedInt<T>& aVal)
{
// Watch out for the min-value, which (with twos-complement) can't be
// negated as -min-value is then (max-value + 1).
if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
return CheckedInt<T>(aVal.mValue, false);
}
return CheckedInt<T>(-aVal.mValue, true);
}
};
} // namespace detail
/*
* Step 3: Now define the CheckedInt class.
*/
/**
* @class CheckedInt
* @brief Integer wrapper class checking for integer overflow and other errors
* @param T the integer type to wrap. Can be any type among the following:
* - any basic integer type such as |int|
* - any stdint type such as |int8_t|
*
* This class implements guarded integer arithmetic. Do a computation, check
* that isValid() returns true, you then have a guarantee that no problem, such
* as integer overflow, happened during this computation, and you can call
* value() to get the plain integer value.
*
* The arithmetic operators in this class are guaranteed not to raise a signal
* (e.g. in case of a division by zero).
*
* For example, suppose that you want to implement a function that computes
* (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
* zero or integer overflow). You could code it as follows:
@code
bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult)
{
CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
if (checkedResult.isValid()) {
*aResult = checkedResult.value();
return true;
} else {
return false;
}
}
@endcode
*
* Implicit conversion from plain integers to checked integers is allowed. The
* plain integer is checked to be in range before being casted to the
* destination type. This means that the following lines all compile, and the
* resulting CheckedInts are correctly detected as valid or invalid:
* @code
// 1 is of type int, is found to be in range for uint8_t, x is valid
CheckedInt<uint8_t> x(1);
// -1 is of type int, is found not to be in range for uint8_t, x is invalid
CheckedInt<uint8_t> x(-1);
// -1 is of type int, is found to be in range for int8_t, x is valid
CheckedInt<int8_t> x(-1);
// 1000 is of type int16_t, is found not to be in range for int8_t,
// x is invalid
CheckedInt<int8_t> x(int16_t(1000));
// 3123456789 is of type uint32_t, is found not to be in range for int32_t,
// x is invalid
CheckedInt<int32_t> x(uint32_t(3123456789));
* @endcode
* Implicit conversion from
* checked integers to plain integers is not allowed. As shown in the
* above example, to get the value of a checked integer as a normal integer,
* call value().
*
* Arithmetic operations between checked and plain integers is allowed; the
* result type is the type of the checked integer.
*
* Checked integers of different types cannot be used in the same arithmetic
* expression.
*
* There are convenience typedefs for all stdint types, of the following form
* (these are just 2 examples):
@code
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint16_t> CheckedUint16;
@endcode
*/
template<typename T>
class CheckedInt
{
protected:
T mValue;
bool mIsValid;
template<typename U>
CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
friend struct detail::NegateImpl<T>;
public:
/**
* Constructs a checked integer with given @a value. The checked integer is
* initialized as valid or invalid depending on whether the @a value
* is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a
* separate template parameter, ensuring that no conversion is performed
* before this constructor is actually called. As explained in the above
* documentation for class CheckedInt, this constructor checks that its
* argument is valid.
*/
template<typename U>
MOZ_IMPLICIT constexpr CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
: mValue(T(aValue)),
mIsValid(detail::IsInRange<T>(aValue))
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
}
template<typename U>
friend class CheckedInt;
template<typename U>
CheckedInt<U> toChecked() const
{
CheckedInt<U> ret(mValue);
ret.mIsValid = ret.mIsValid && mIsValid;
return ret;
}
/** Constructs a valid checked integer with initial value 0 */
constexpr CheckedInt() : mValue(0), mIsValid(true)
{
static_assert(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** @returns the actual value */
T value() const
{
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
return mValue;
}
/**
* @returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked
* integer
*/
bool isValid() const
{
return mIsValid;
}
template<typename U>
friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator +=(U aRhs);
CheckedInt& operator +=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator -=(U aRhs);
CheckedInt& operator -=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator *=(U aRhs);
CheckedInt& operator *=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator /=(U aRhs);
CheckedInt& operator /=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator %=(U aRhs);
CheckedInt& operator %=(const CheckedInt<T>& aRhs);
CheckedInt operator -() const
{
return detail::NegateImpl<T>::negate(*this);
}
/**
* @returns true if the left and right hand sides are valid
* and have the same value.
*
* Note that these semantics are the reason why we don't offer
* a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
* but that would mean that whenever a or b is invalid, a!=b
* is always true, which would be very confusing.
*
* For similar reasons, operators <, >, <=, >= would be very tricky to
* specify, so we just avoid offering them.
*
* Notice that these == semantics are made more reasonable by these facts:
* 1. a==b implies equality at the raw data level
* (the converse is false, as a==b is never true among invalids)
* 2. This is similar to the behavior of IEEE floats, where a==b
* means that a and b have the same value *and* neither is NaN.
*/
bool operator ==(const CheckedInt& aOther) const
{
return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
}
/** prefix ++ */
CheckedInt& operator++()
{
*this += 1;
return *this;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this += 1;
return tmp;
}
/** prefix -- */
CheckedInt& operator--()
{
*this -= 1;
return *this;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this -= 1;
return tmp;
}
private:
/**
* The !=, <, <=, >, >= operators are disabled:
* see the comment on operator==.
*/
template<typename U> bool operator !=(U aOther) const = delete;
template<typename U> bool operator < (U aOther) const = delete;
template<typename U> bool operator <=(U aOther) const = delete;
template<typename U> bool operator > (U aOther) const = delete;
template<typename U> bool operator >=(U aOther) const = delete;
};
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> \
operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
{ \
if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
return CheckedInt<T>(0, false); \
} \
return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
aLhs.mIsValid && aRhs.mIsValid); \
}
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
// Implement castToCheckedInt<T>(x), making sure that
// - it allows x to be either a CheckedInt<T> or any integer type
// that can be casted to T
// - if x is already a CheckedInt<T>, we just return a reference to it,
// instead of copying it (optimization)
namespace detail {
template<typename T, typename U>
struct CastToCheckedIntImpl
{
typedef CheckedInt<T> ReturnType;
static CheckedInt<T> run(U aU) { return aU; }
};
template<typename T>
struct CastToCheckedIntImpl<T, CheckedInt<T> >
{
typedef const CheckedInt<T>& ReturnType;
static const CheckedInt<T>& run(const CheckedInt<T>& aU) { return aU; }
};
} // namespace detail
template<typename T, typename U>
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
castToCheckedInt(U aU)
{
static_assert(detail::IsSupported<T>::value &&
detail::IsSupported<U>::value,
"This type is not supported by CheckedInt");
return detail::CastToCheckedIntImpl<T, U>::run(aU);
}
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
{ \
*this = *this OP castToCheckedInt<T>(aRhs); \
return *this; \
} \
template<typename T> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const CheckedInt<T>& aRhs) \
{ \
*this = *this OP aRhs; \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) \
{ \
return aLhs OP castToCheckedInt<T>(aRhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) \
{ \
return castToCheckedInt<T>(aLhs) OP aRhs; \
}
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
template<typename T, typename U>
inline bool
operator ==(const CheckedInt<T>& aLhs, U aRhs)
{
return aLhs == castToCheckedInt<T>(aRhs);
}
template<typename T, typename U>
inline bool
operator ==(U aLhs, const CheckedInt<T>& aRhs)
{
return castToCheckedInt<T>(aLhs) == aRhs;
}
// Convenience typedefs.
typedef CheckedInt<int8_t> CheckedInt8;
typedef CheckedInt<uint8_t> CheckedUint8;
typedef CheckedInt<int16_t> CheckedInt16;
typedef CheckedInt<uint16_t> CheckedUint16;
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint32_t> CheckedUint32;
typedef CheckedInt<int64_t> CheckedInt64;
typedef CheckedInt<uint64_t> CheckedUint64;
} // namespace mozilla
#endif /* mozilla_CheckedInt_h */

View File

@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Various compiler checks. */
#ifndef mozilla_Compiler_h
#define mozilla_Compiler_h
#define MOZ_IS_GCC 0
#define MOZ_IS_MSVC 0
#if !defined(__clang__) && defined(__GNUC__)
# undef MOZ_IS_GCC
# define MOZ_IS_GCC 1
/*
* These macros should simplify gcc version checking. For example, to check
* for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`.
*/
# define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
>= ((major) * 10000 + (minor) * 100 + (patchlevel)))
# define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
<= ((major) * 10000 + (minor) * 100 + (patchlevel)))
# if !MOZ_GCC_VERSION_AT_LEAST(4, 9, 0)
# error "mfbt (and Gecko) require at least gcc 4.9 to build."
# endif
#elif defined(_MSC_VER)
# undef MOZ_IS_MSVC
# define MOZ_IS_MSVC 1
#endif
/*
* The situation with standard libraries is a lot worse than with compilers,
* particularly as clang and gcc could end up using one of three or so standard
* libraries, and they may not be up-to-snuff with newer C++11 versions. To
* detect the library, we're going to include cstddef (which is a small header
* which will be transitively included by everybody else at some point) to grab
* the version macros and deduce macros from there.
*/
#ifdef __cplusplus
# include <cstddef>
# ifdef _STLPORT_MAJOR
# define MOZ_USING_STLPORT 1
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \
(_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch)))
# elif defined(_LIBCPP_VERSION)
/*
* libc++, unfortunately, doesn't appear to have useful versioning macros.
* Hopefully, the recommendations of N3694 with respect to standard libraries
* will get applied instead and we won't need to worry about version numbers
* here.
*/
# define MOZ_USING_LIBCXX 1
# elif defined(__GLIBCXX__)
# define MOZ_USING_LIBSTDCXX 1
/*
* libstdc++ is also annoying and doesn't give us useful versioning macros
* for the library. If we're using gcc, then assume that libstdc++ matches
* the compiler version. If we're using clang, we're going to have to fake
* major/minor combinations by looking for newly-defined config macros.
*/
# if MOZ_IS_GCC
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
MOZ_GCC_VERSION_AT_LEAST(major, minor, patch)
# elif defined(_GLIBCXX_THROW_OR_ABORT)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 8))
# elif defined(_GLIBCXX_NOEXCEPT)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 7))
# elif defined(_GLIBCXX_USE_DEPRECATED)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 6))
# elif defined(_GLIBCXX_PSEUDO_VISIBILITY)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 5))
# elif defined(_GLIBCXX_BEGIN_EXTERN_C)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 4))
# elif defined(_GLIBCXX_VISIBILITY_ATTR)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 3))
# elif defined(_GLIBCXX_VISIBILITY)
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
((major) < 4 || ((major) == 4 && (minor) <= 2))
# else
# error "Your version of libstdc++ is unknown to us and is likely too old."
# endif
# endif
// Flesh out the defines for everyone else
# ifndef MOZ_USING_STLPORT
# define MOZ_USING_STLPORT 0
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0
# endif
# ifndef MOZ_USING_LIBCXX
# define MOZ_USING_LIBCXX 0
# endif
# ifndef MOZ_USING_LIBSTDCXX
# define MOZ_USING_LIBSTDCXX 0
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0
# endif
#endif /* __cplusplus */
#endif /* mozilla_Compiler_h */

View File

@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Helpers to manipulate integer types that don't fit in TypeTraits.h */
#ifndef mozilla_IntegerTypeTraits_h
#define mozilla_IntegerTypeTraits_h
#include "mozilla/TypeTraits.h"
#include <stdint.h>
namespace mozilla {
namespace detail {
/**
* StdintTypeForSizeAndSignedness returns the stdint integer type
* of given size (can be 1, 2, 4 or 8) and given signedness
* (false means unsigned, true means signed).
*/
template<size_t Size, bool Signedness>
struct StdintTypeForSizeAndSignedness;
template<>
struct StdintTypeForSizeAndSignedness<1, true>
{
typedef int8_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<1, false>
{
typedef uint8_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<2, true>
{
typedef int16_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<2, false>
{
typedef uint16_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<4, true>
{
typedef int32_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<4, false>
{
typedef uint32_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<8, true>
{
typedef int64_t Type;
};
template<>
struct StdintTypeForSizeAndSignedness<8, false>
{
typedef uint64_t Type;
};
} // namespace detail
template<size_t Size>
struct UnsignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, false>
{};
template<size_t Size>
struct SignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, true>
{};
template<typename IntegerType>
struct PositionOfSignBit
{
static_assert(IsIntegral<IntegerType>::value,
"PositionOfSignBit is only for integral types");
// 8 here should be CHAR_BIT from limits.h, but the world has moved on.
static const size_t value = 8 * sizeof(IntegerType) - 1;
};
/**
* MinValue returns the minimum value of the given integer type as a
* compile-time constant, which std::numeric_limits<IntegerType>::min()
* cannot do in c++98.
*/
template<typename IntegerType>
struct MinValue
{
private:
static_assert(IsIntegral<IntegerType>::value,
"MinValue is only for integral types");
typedef typename MakeUnsigned<IntegerType>::Type UnsignedIntegerType;
static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
public:
// Bitwise ops may return a larger type, that's why we cast explicitly.
// In C++, left bit shifts on signed values is undefined by the standard
// unless the shifted value is representable.
// Notice that signed-to-unsigned conversions are always well-defined in
// the standard as the value congruent to 2**n, as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
static const IntegerType value =
IsSigned<IntegerType>::value
? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
: IntegerType(0);
};
/**
* MaxValue returns the maximum value of the given integer type as a
* compile-time constant, which std::numeric_limits<IntegerType>::max()
* cannot do in c++98.
*/
template<typename IntegerType>
struct MaxValue
{
static_assert(IsIntegral<IntegerType>::value,
"MaxValue is only for integral types");
// Tricksy, but covered by the CheckedInt unit test.
// Relies on the type of MinValue<IntegerType>::value
// being IntegerType.
static const IntegerType value = ~MinValue<IntegerType>::value;
};
} // namespace mozilla
#endif // mozilla_IntegerTypeTraits_h

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* MOZ_LIKELY and MOZ_UNLIKELY macros to hint to the compiler how a
* boolean predicate should be branch-predicted.
*/
#ifndef mozilla_Likely_h
#define mozilla_Likely_h
#if defined(__clang__) || defined(__GNUC__)
# define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1))
# define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#else
# define MOZ_LIKELY(x) (!!(x))
# define MOZ_UNLIKELY(x) (!!(x))
#endif
#endif /* mozilla_Likely_h */

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements various macros meant to ease the use of variadic macros.
*/
#ifndef mozilla_MacroArgs_h
#define mozilla_MacroArgs_h
// Concatenates pre-processor tokens in a way that can be used with __LINE__.
#define MOZ_CONCAT2(x, y) x ## y
#define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y)
/*
* MOZ_ARG_COUNT(...) counts the number of variadic arguments.
* You must pass in between 0 and 50 (inclusive) variadic arguments.
* For example:
*
* MOZ_ARG_COUNT() expands to 0
* MOZ_ARG_COUNT(a) expands to 1
* MOZ_ARG_COUNT(a, b) expands to 2
*
* Implementation notes:
* The `##__VA_ARGS__` form is a GCC extension that removes the comma if
* __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##,
* and its default behavior is already to strip the comma when __VA_ARGS__
* is empty.
*
* So MOZ_MACROARGS_ARG_COUNT_HELPER() expands to
* (_, 50, 49, ...)
* MOZ_MACROARGS_ARG_COUNT_HELPER(a) expands to
* (_, a, 50, 49, ...)
* etc.
*/
#define MOZ_ARG_COUNT(...) \
MOZ_MACROARGS_ARG_COUNT_HELPER2(MOZ_MACROARGS_ARG_COUNT_HELPER(__VA_ARGS__))
#define MOZ_MACROARGS_ARG_COUNT_HELPER(...) (_, ##__VA_ARGS__, \
50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \
MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs
#define MOZ_MACROARGS_ARG_COUNT_HELPER3(a0, \
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \
a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \
a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
a51, ...) a51
/*
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
* arguments and prefixes it with |aPrefix|. For example:
*
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
* MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0
* MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there
* aren't enough arguments given.
*
* You must pass in between 0 and 50 (inclusive) variadic arguments, past
* |aPrefix|.
*/
#define MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(a, b) a b
#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE( \
MOZ_CONCAT, (aPrefix, MOZ_ARG_COUNT(__VA_ARGS__)))
/*
* MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
* arguments. For example:
*
* MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d
*/
#define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__
#define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__
/*
* MOZ_ARG_N expands to its |N|th argument.
*/
#define MOZ_ARG_1(a1, ...) a1
#define MOZ_ARG_2(a1, a2, ...) a2
#endif /* mozilla_MacroArgs_h */

View File

@ -0,0 +1,238 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* C++11-style, but C++98-usable, "move references" implementation. */
#ifndef mozilla_Move_h
#define mozilla_Move_h
#include "mozilla/TypeTraits.h"
namespace mozilla {
/*
* "Move" References
*
* Some types can be copied much more efficiently if we know the original's
* value need not be preserved --- that is, if we are doing a "move", not a
* "copy". For example, if we have:
*
* Vector<T> u;
* Vector<T> v(u);
*
* the constructor for v must apply a copy constructor to each element of u ---
* taking time linear in the length of u. However, if we know we will not need u
* any more once v has been initialized, then we could initialize v very
* efficiently simply by stealing u's dynamically allocated buffer and giving it
* to v --- a constant-time operation, regardless of the size of u.
*
* Moves often appear in container implementations. For example, when we append
* to a vector, we may need to resize its buffer. This entails moving each of
* its extant elements from the old, smaller buffer to the new, larger buffer.
* But once the elements have been migrated, we're just going to throw away the
* old buffer; we don't care if they still have their values. So if the vector's
* element type can implement "move" more efficiently than "copy", the vector
* resizing should by all means use a "move" operation. Hash tables should also
* use moves when resizing their internal array as entries are added and
* removed.
*
* The details of the optimization, and whether it's worth applying, vary
* from one type to the next: copying an 'int' is as cheap as moving it, so
* there's no benefit in distinguishing 'int' moves from copies. And while
* some constructor calls for complex types are moves, many really have to
* be copies, and can't be optimized this way. So we need:
*
* 1) a way for a type (like Vector) to announce that it can be moved more
* efficiently than it can be copied, and provide an implementation of that
* move operation; and
*
* 2) a way for a particular invocation of a copy constructor to say that it's
* really a move, not a copy, and that the value of the original isn't
* important afterwards (although it must still be safe to destroy).
*
* If a constructor has a single argument of type 'T&&' (an 'rvalue reference
* to T'), that indicates that it is a 'move constructor'. That's 1). It should
* move, not copy, its argument into the object being constructed. It may leave
* the original in any safely-destructible state.
*
* If a constructor's argument is an rvalue, as in 'C(f(x))' or 'C(x + y)', as
* opposed to an lvalue, as in 'C(x)', then overload resolution will prefer the
* move constructor, if there is one. The 'mozilla::Move' function, defined in
* this file, is an identity function you can use in a constructor invocation to
* make any argument into an rvalue, like this: C(Move(x)). That's 2). (You
* could use any function that works, but 'Move' indicates your intention
* clearly.)
*
* Where we might define a copy constructor for a class C like this:
*
* C(const C& rhs) { ... copy rhs to this ... }
*
* we would declare a move constructor like this:
*
* C(C&& rhs) { .. move rhs to this ... }
*
* And where we might perform a copy like this:
*
* C c2(c1);
*
* we would perform a move like this:
*
* C c2(Move(c1));
*
* Note that 'T&&' implicitly converts to 'T&'. So you can pass a 'T&&' to an
* ordinary copy constructor for a type that doesn't support a special move
* constructor, and you'll just get a copy. This means that templates can use
* Move whenever they know they won't use the original value any more, even if
* they're not sure whether the type at hand has a specialized move constructor.
* If it doesn't, the 'T&&' will just convert to a 'T&', and the ordinary copy
* constructor will apply.
*
* A class with a move constructor can also provide a move assignment operator.
* A generic definition would run this's destructor, and then apply the move
* constructor to *this's memory. A typical definition:
*
* C& operator=(C&& rhs) {
* MOZ_ASSERT(&rhs != this, "self-moves are prohibited");
* this->~C();
* new(this) C(Move(rhs));
* return *this;
* }
*
* With that in place, one can write move assignments like this:
*
* c2 = Move(c1);
*
* This destroys c2, moves c1's value to c2, and leaves c1 in an undefined but
* destructible state.
*
* As we say, a move must leave the original in a "destructible" state. The
* original's destructor will still be called, so if a move doesn't
* actually steal all its resources, that's fine. We require only that the
* move destination must take on the original's value; and that destructing
* the original must not break the move destination.
*
* (Opinions differ on whether move assignment operators should deal with move
* assignment of an object onto itself. It seems wise to either handle that
* case, or assert that it does not occur.)
*
* Forwarding:
*
* Sometimes we want copy construction or assignment if we're passed an ordinary
* value, but move construction if passed an rvalue reference. For example, if
* our constructor takes two arguments and either could usefully be a move, it
* seems silly to write out all four combinations:
*
* C::C(X& x, Y& y) : x(x), y(y) { }
* C::C(X& x, Y&& y) : x(x), y(Move(y)) { }
* C::C(X&& x, Y& y) : x(Move(x)), y(y) { }
* C::C(X&& x, Y&& y) : x(Move(x)), y(Move(y)) { }
*
* To avoid this, C++11 has tweaks to make it possible to write what you mean.
* The four constructor overloads above can be written as one constructor
* template like so[0]:
*
* template <typename XArg, typename YArg>
* C::C(XArg&& x, YArg&& y) : x(Forward<XArg>(x)), y(Forward<YArg>(y)) { }
*
* ("'Don't Repeat Yourself'? What's that?")
*
* This takes advantage of two new rules in C++11:
*
* - First, when a function template takes an argument that is an rvalue
* reference to a template argument (like 'XArg&& x' and 'YArg&& y' above),
* then when the argument is applied to an lvalue, the template argument
* resolves to 'T&'; and when it is applied to an rvalue, the template
* argument resolves to 'T'. Thus, in a call to C::C like:
*
* X foo(int);
* Y yy;
*
* C(foo(5), yy)
*
* XArg would resolve to 'X', and YArg would resolve to 'Y&'.
*
* - Second, Whereas C++ used to forbid references to references, C++11 defines
* 'collapsing rules': 'T& &', 'T&& &', and 'T& &&' (that is, any combination
* involving an lvalue reference) now collapse to simply 'T&'; and 'T&& &&'
* collapses to 'T&&'.
*
* Thus, in the call above, 'XArg&&' is 'X&&'; and 'YArg&&' is 'Y& &&', which
* collapses to 'Y&'. Because the arguments are declared as rvalue references
* to template arguments, the lvalue-ness "shines through" where present.
*
* Then, the 'Forward<T>' function --- you must invoke 'Forward' with its type
* argument --- returns an lvalue reference or an rvalue reference to its
* argument, depending on what T is. In our unified constructor definition, that
* means that we'll invoke either the copy or move constructors for x and y,
* depending on what we gave C's constructor. In our call, we'll move 'foo()'
* into 'x', but copy 'yy' into 'y'.
*
* This header file defines Move and Forward in the mozilla namespace. It's up
* to individual containers to annotate moves as such, by calling Move; and it's
* up to individual types to define move constructors and assignment operators
* when valuable.
*
* (C++11 says that the <utility> header file should define 'std::move' and
* 'std::forward', which are just like our 'Move' and 'Forward'; but those
* definitions aren't available in that header on all our platforms, so we
* define them ourselves here.)
*
* 0. This pattern is known as "perfect forwarding". Interestingly, it is not
* actually perfect, and it can't forward all possible argument expressions!
* There is a C++11 issue: you can't form a reference to a bit-field. As a
* workaround, assign the bit-field to a local variable and use that:
*
* // C is as above
* struct S { int x : 1; } s;
* C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those
* int tmp = s.x;
* C(tmp, 0); // OK: tmp not a bit-field
*/
/**
* Identical to std::Move(); this is necessary until our stlport supports
* std::move().
*/
template<typename T>
inline typename RemoveReference<T>::Type&&
Move(T&& aX)
{
return static_cast<typename RemoveReference<T>::Type&&>(aX);
}
/**
* These two overloads are identical to std::forward(); they are necessary until
* our stlport supports std::forward().
*/
template<typename T>
inline T&&
Forward(typename RemoveReference<T>::Type& aX)
{
return static_cast<T&&>(aX);
}
template<typename T>
inline T&&
Forward(typename RemoveReference<T>::Type&& aX)
{
static_assert(!IsLvalueReference<T>::value,
"misuse of Forward detected! try the other overload");
return static_cast<T&&>(aX);
}
/** Swap |aX| and |aY| using move-construction if possible. */
template<typename T>
inline void
Swap(T& aX, T& aY)
{
T tmp(Move(aX));
aX = Move(aY);
aY = Move(tmp);
}
} // namespace mozilla
#endif /* mozilla_Move_h */

View File

@ -0,0 +1,219 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A class holding a pair of objects that tries to conserve storage space. */
#ifndef mozilla_Pair_h
#define mozilla_Pair_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
enum StorageType { AsBase, AsMember };
// Optimize storage using the Empty Base Optimization -- that empty base classes
// don't take up space -- to optimize size when one or the other class is
// stateless and can be used as a base class.
//
// The extra conditions on storage for B are necessary so that PairHelper won't
// ambiguously inherit from either A or B, such that one or the other base class
// would be inaccessible.
template<typename A, typename B,
detail::StorageType =
IsEmpty<A>::value ? detail::AsBase : detail::AsMember,
detail::StorageType =
IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value
? detail::AsBase
: detail::AsMember>
struct PairHelper;
template<typename A, typename B>
struct PairHelper<A, B, AsMember, AsMember>
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: mFirstA(Forward<AArg>(aA)),
mSecondB(Forward<BArg>(aB))
{}
A& first() { return mFirstA; }
const A& first() const { return mFirstA; }
B& second() { return mSecondB; }
const B& second() const { return mSecondB; }
void swap(PairHelper& aOther)
{
Swap(mFirstA, aOther.mFirstA);
Swap(mSecondB, aOther.mSecondB);
}
private:
A mFirstA;
B mSecondB;
};
template<typename A, typename B>
struct PairHelper<A, B, AsMember, AsBase> : private B
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: B(Forward<BArg>(aB)),
mFirstA(Forward<AArg>(aA))
{}
A& first() { return mFirstA; }
const A& first() const { return mFirstA; }
B& second() { return *this; }
const B& second() const { return *this; }
void swap(PairHelper& aOther)
{
Swap(mFirstA, aOther.mFirstA);
Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
}
private:
A mFirstA;
};
template<typename A, typename B>
struct PairHelper<A, B, AsBase, AsMember> : private A
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: A(Forward<AArg>(aA)),
mSecondB(Forward<BArg>(aB))
{}
A& first() { return *this; }
const A& first() const { return *this; }
B& second() { return mSecondB; }
const B& second() const { return mSecondB; }
void swap(PairHelper& aOther)
{
Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
Swap(mSecondB, aOther.mSecondB);
}
private:
B mSecondB;
};
template<typename A, typename B>
struct PairHelper<A, B, AsBase, AsBase> : private A, private B
{
protected:
template<typename AArg, typename BArg>
PairHelper(AArg&& aA, BArg&& aB)
: A(Forward<AArg>(aA)),
B(Forward<BArg>(aB))
{}
A& first() { return static_cast<A&>(*this); }
const A& first() const { return static_cast<A&>(*this); }
B& second() { return static_cast<B&>(*this); }
const B& second() const { return static_cast<B&>(*this); }
void swap(PairHelper& aOther)
{
Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
}
};
} // namespace detail
/**
* Pair is the logical concatenation of an instance of A with an instance B.
* Space is conserved when possible. Neither A nor B may be a final class.
*
* It's typically clearer to have individual A and B member fields. Except if
* you want the space-conserving qualities of Pair, you're probably better off
* not using this!
*
* No guarantees are provided about the memory layout of A and B, the order of
* initialization or destruction of A and B, and so on. (This is approximately
* required to optimize space usage.) The first/second names are merely
* conceptual!
*/
template<typename A, typename B>
struct Pair
: private detail::PairHelper<A, B>
{
typedef typename detail::PairHelper<A, B> Base;
public:
template<typename AArg, typename BArg>
Pair(AArg&& aA, BArg&& aB)
: Base(Forward<AArg>(aA), Forward<BArg>(aB))
{}
Pair(Pair&& aOther)
: Base(Move(aOther.first()), Move(aOther.second()))
{ }
Pair(const Pair& aOther) = default;
Pair& operator=(Pair&& aOther)
{
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
first() = Move(aOther.first());
second() = Move(aOther.second());
return *this;
}
Pair& operator=(const Pair& aOther) = default;
/** The A instance. */
using Base::first;
/** The B instance. */
using Base::second;
/** Swap this pair with another pair. */
void swap(Pair& aOther) { Base::swap(aOther); }
};
template<typename A, class B>
void
Swap(Pair<A, B>& aX, Pair<A, B>& aY)
{
aX.swap(aY);
}
/**
* MakePair allows you to construct a Pair instance using type inference. A call
* like this:
*
* MakePair(Foo(), Bar())
*
* will return a Pair<Foo, Bar>.
*/
template<typename A, typename B>
Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
typename RemoveCV<typename RemoveReference<B>::Type>::Type>
MakePair(A&& aA, B&& aB)
{
return
Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
typename RemoveCV<typename RemoveReference<B>::Type>::Type>(
Forward<A>(aA),
Forward<B>(aB));
}
} // namespace mozilla
#endif /* mozilla_Pair_h */

View File

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_StaticAnalysisFunctions_h
#define mozilla_StaticAnalysisFunctions_h
#ifndef __cplusplus
#ifndef bool
#include <stdbool.h>
#endif
#endif
/*
* Functions that are used as markers in Gecko code for static analysis. Their
* purpose is to have different AST nodes generated during compile time and to
* match them based on different checkers implemented in build/clang-plugin
*/
#ifdef MOZ_CLANG_PLUGIN
#ifdef __cplusplus
/**
* MOZ_KnownLive - used to opt an argument out of the CanRunScript checker so
* that we don't check it if is a strong ref.
*
* Example:
* canRunScript(MOZ_KnownLive(rawPointer));
*/
template <typename T>
static MOZ_ALWAYS_INLINE T* MOZ_KnownLive(T* ptr) { return ptr; }
extern "C" {
#endif
/**
* MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible
* presence of assignment instead of logical comparisons.
*
* Example:
* MOZ_ASSERT(retVal = true);
*/
static MOZ_ALWAYS_INLINE bool MOZ_AssertAssignmentTest(bool exprResult) {
return exprResult;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr))
#else
#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr))
#endif /* MOZ_CLANG_PLUGIN */
#endif /* StaticAnalysisFunctions_h */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* mfbt foundational types and macros. */
#ifndef mozilla_Types_h
#define mozilla_Types_h
/*
* This header must be valid C and C++, includable by code embedding either
* SpiderMonkey or Gecko.
*/
/* Expose all <stdint.h> types and size_t. */
#include <stddef.h>
#include <stdint.h>
/* Implement compiler and linker macros needed for APIs. */
/*
* MOZ_EXPORT is used to declare and define a symbol or type which is externally
* visible to users of the current library. It encapsulates various decorations
* needed to properly export the method's symbol.
*
* api.h:
* extern MOZ_EXPORT int MeaningOfLife(void);
* extern MOZ_EXPORT int LuggageCombination;
*
* api.c:
* int MeaningOfLife(void) { return 42; }
* int LuggageCombination = 12345;
*
* If you are merely sharing a method across files, just use plain |extern|.
* These macros are designed for use by library interfaces -- not for normal
* methods or data used cross-file.
*/
#if defined(WIN32)
# define MOZ_EXPORT __declspec(dllexport)
#else /* Unix */
# ifdef HAVE_VISIBILITY_ATTRIBUTE
# define MOZ_EXPORT __attribute__((visibility("default")))
# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
# define MOZ_EXPORT __global
# else
# define MOZ_EXPORT /* nothing */
# endif
#endif
/*
* Whereas implementers use MOZ_EXPORT to declare and define library symbols,
* users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to access them. Most often the
* implementer of the library will expose an API macro which expands to either
* the export or import version of the macro, depending upon the compilation
* mode.
*/
#ifdef _WIN32
# if defined(__MWERKS__)
# define MOZ_IMPORT_API /* nothing */
# else
# define MOZ_IMPORT_API __declspec(dllimport)
# endif
#else
# define MOZ_IMPORT_API MOZ_EXPORT
#endif
#if defined(_WIN32) && !defined(__MWERKS__)
# define MOZ_IMPORT_DATA __declspec(dllimport)
#else
# define MOZ_IMPORT_DATA MOZ_EXPORT
#endif
/*
* Consistent with the above comment, the MFBT_API and MFBT_DATA macros expose
* export mfbt declarations when building mfbt, and they expose import mfbt
* declarations when using mfbt.
*/
#if defined(IMPL_MFBT) || (defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && (defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API)))
# define MFBT_API MOZ_EXPORT
# define MFBT_DATA MOZ_EXPORT
#else
# if defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && defined(STATIC_JS_API)
# define MFBT_API
# define MFBT_DATA
# else
/*
* On linux mozglue is linked in the program and we link libxul.so with
* -z,defs. Normally that causes the linker to reject undefined references in
* libxul.so, but as a loophole it allows undefined references to weak
* symbols. We add the weak attribute to the import version of the MFBT API
* macros to exploit this.
*/
# if defined(MOZ_GLUE_IN_PROGRAM)
# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API
# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA
# else
# define MFBT_API MOZ_IMPORT_API
# define MFBT_DATA MOZ_IMPORT_DATA
# endif
# endif
#endif
/*
* C symbols in C++ code must be declared immediately within |extern "C"|
* blocks. However, in C code, they need not be declared specially. This
* difference is abstracted behind the MOZ_BEGIN_EXTERN_C and MOZ_END_EXTERN_C
* macros, so that the user need not know whether he is being used in C or C++
* code.
*
* MOZ_BEGIN_EXTERN_C
*
* extern MOZ_EXPORT int MostRandomNumber(void);
* ...other declarations...
*
* MOZ_END_EXTERN_C
*
* This said, it is preferable to just use |extern "C"| in C++ header files for
* its greater clarity.
*/
#ifdef __cplusplus
# define MOZ_BEGIN_EXTERN_C extern "C" {
# define MOZ_END_EXTERN_C }
#else
# define MOZ_BEGIN_EXTERN_C
# define MOZ_END_EXTERN_C
#endif
/*
* GCC's typeof is available when decltype is not.
*/
#if defined(__GNUC__) && defined(__cplusplus) && \
!defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
# define decltype __typeof__
#endif
#endif /* mozilla_Types_h */

View File

@ -0,0 +1,697 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Smart pointer managing sole ownership of a resource. */
#ifndef mozilla_UniquePtr_h
#define mozilla_UniquePtr_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/Move.h"
#include "mozilla/Pair.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
template<typename T> class DefaultDelete;
template<typename T, class D = DefaultDelete<T>> class UniquePtr;
} // namespace mozilla
namespace mozilla {
namespace detail {
struct HasPointerTypeHelper
{
template <class U> static double Test(...);
template <class U> static char Test(typename U::pointer* = 0);
};
template <class T>
class HasPointerType : public IntegralConstant<bool, sizeof(HasPointerTypeHelper::Test<T>(0)) == 1>
{
};
template <class T, class D, bool = HasPointerType<D>::value>
struct PointerTypeImpl
{
typedef typename D::pointer Type;
};
template <class T, class D>
struct PointerTypeImpl<T, D, false>
{
typedef T* Type;
};
template <class T, class D>
struct PointerType
{
typedef typename PointerTypeImpl<T, typename RemoveReference<D>::Type>::Type Type;
};
} // namespace detail
/**
* UniquePtr is a smart pointer that wholly owns a resource. Ownership may be
* transferred out of a UniquePtr through explicit action, but otherwise the
* resource is destroyed when the UniquePtr is destroyed.
*
* UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr
* in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr
* obviously *can't* copy ownership of its singly-owned resource. So what
* happens if you try to copy one? Bizarrely, ownership is implicitly
* *transferred*, preserving single ownership but breaking code that assumes a
* copy of an object is identical to the original. (This is why auto_ptr is
* prohibited in STL containers.)
*
* UniquePtr solves this problem by being *movable* rather than copyable.
* Instead of passing a |UniquePtr u| directly to the constructor or assignment
* operator, you pass |Move(u)|. In doing so you indicate that you're *moving*
* ownership out of |u|, into the target of the construction/assignment. After
* the transfer completes, |u| contains |nullptr| and may be safely destroyed.
* This preserves single ownership but also allows UniquePtr to be moved by
* algorithms that have been made move-safe. (Note: if |u| is instead a
* temporary expression, don't use |Move()|: just pass the expression, because
* it's already move-ready. For more information see Move.h.)
*
* UniquePtr is also better than std::auto_ptr in that the deletion operation is
* customizable. An optional second template parameter specifies a class that
* (through its operator()(T*)) implements the desired deletion policy. If no
* policy is specified, mozilla::DefaultDelete<T> is used -- which will either
* |delete| or |delete[]| the resource, depending whether the resource is an
* array. Custom deletion policies ideally should be empty classes (no member
* fields, no member fields in base classes, no virtual methods/inheritance),
* because then UniquePtr can be just as efficient as a raw pointer.
*
* Use of UniquePtr proceeds like so:
*
* UniquePtr<int> g1; // initializes to nullptr
* g1.reset(new int); // switch resources using reset()
* g1 = nullptr; // clears g1, deletes the int
*
* UniquePtr<int> g2(new int); // owns that int
* int* p = g2.release(); // g2 leaks its int -- still requires deletion
* delete p; // now freed
*
* struct S { int x; S(int x) : x(x) {} };
* UniquePtr<S> g3, g4(new S(5));
* g3 = Move(g4); // g3 owns the S, g4 cleared
* S* p = g3.get(); // g3 still owns |p|
* assert(g3->x == 5); // operator-> works (if .get() != nullptr)
* assert((*g3).x == 5); // also operator* (again, if not cleared)
* Swap(g3, g4); // g4 now owns the S, g3 cleared
* g3.swap(g4); // g3 now owns the S, g4 cleared
* UniquePtr<S> g5(Move(g3)); // g5 owns the S, g3 cleared
* g5.reset(); // deletes the S, g5 cleared
*
* struct FreePolicy { void operator()(void* p) { free(p); } };
* UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int))));
* int* ptr = g6.get();
* g6 = nullptr; // calls free(ptr)
*
* Now, carefully note a few things you *can't* do:
*
* UniquePtr<int> b1;
* b1 = new int; // BAD: can only assign another UniquePtr
* int* ptr = b1; // BAD: no auto-conversion to pointer, use get()
*
* UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr
* UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr
*
* (Note that changing a UniquePtr to store a direct |new| expression is
* permitted, but usually you should use MakeUnique, defined at the end of this
* header.)
*
* A few miscellaneous notes:
*
* UniquePtr, when not instantiated for an array type, can be move-constructed
* and move-assigned, not only from itself but from "derived" UniquePtr<U, E>
* instantiations where U converts to T and E converts to D. If you want to use
* this, you're going to have to specify a deletion policy for both UniquePtr
* instantations, and T pretty much has to have a virtual destructor. In other
* words, this doesn't work:
*
* struct Base { virtual ~Base() {} };
* struct Derived : Base {};
*
* UniquePtr<Base> b1;
* // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert
* UniquePtr<Derived> d1(Move(b));
*
* UniquePtr<Base> b2;
* UniquePtr<Derived, DefaultDelete<Base>> d2(Move(b2)); // okay
*
* UniquePtr is specialized for array types. Specializing with an array type
* creates a smart-pointer version of that array -- not a pointer to such an
* array.
*
* UniquePtr<int[]> arr(new int[5]);
* arr[0] = 4;
*
* What else is different? Deletion of course uses |delete[]|. An operator[]
* is provided. Functionality that doesn't make sense for arrays is removed.
* The constructors and mutating methods only accept array pointers (not T*, U*
* that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|.
*
* It's perfectly okay for a function to return a UniquePtr. This transfers
* the UniquePtr's sole ownership of the data, to the fresh UniquePtr created
* in the calling function, that will then solely own that data. Such functions
* can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where
* |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere.
*
* UniquePtr will commonly be a member of a class, with lifetime equivalent to
* that of that class. If you want to expose the related resource, you could
* expose a raw pointer via |get()|, but ownership of a raw pointer is
* inherently unclear. So it's better to expose a |const UniquePtr&| instead.
* This prohibits mutation but still allows use of |get()| when needed (but
* operator-> is preferred). Of course, you can only use this smart pointer as
* long as the enclosing class instance remains live -- no different than if you
* exposed the |get()| raw pointer.
*
* To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&|
* argument. To specify an inout parameter (where the method may or may not
* take ownership of the resource, or reset it), or to specify an out parameter
* (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&|
* argument. To unconditionally transfer ownership of a UniquePtr
* into a method, use a |UniquePtr| argument. To conditionally transfer
* ownership of a resource into a method, should the method want it, use a
* |UniquePtr&&| argument.
*/
template<typename T, class D>
class UniquePtr
{
public:
typedef T ElementType;
typedef D DeleterType;
typedef typename detail::PointerType<T, DeleterType>::Type Pointer;
private:
Pair<Pointer, DeleterType> mTuple;
Pointer& ptr() { return mTuple.first(); }
const Pointer& ptr() const { return mTuple.first(); }
DeleterType& del() { return mTuple.second(); }
const DeleterType& del() const { return mTuple.second(); }
public:
/**
* Construct a UniquePtr containing |nullptr|.
*/
constexpr UniquePtr()
: mTuple(static_cast<Pointer>(nullptr), DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
/**
* Construct a UniquePtr containing |aPtr|.
*/
explicit UniquePtr(Pointer aPtr)
: mTuple(aPtr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
UniquePtr(Pointer aPtr,
typename Conditional<IsReference<D>::value,
D,
const D&>::Type aD1)
: mTuple(aPtr, aD1)
{}
// If you encounter an error with MSVC10 about RemoveReference below, along
// the lines that "more than one partial specialization matches the template
// argument list": don't use UniquePtr<T, reference to function>! Ideally
// you should make deletion use the same function every time, using a
// deleter policy:
//
// // BAD, won't compile with MSVC10, deleter doesn't need to be a
// // variable at all
// typedef void (&FreeSignature)(void*);
// UniquePtr<int, FreeSignature> ptr((int*) malloc(sizeof(int)), free);
//
// // GOOD, compiles with MSVC10, deletion behavior statically known and
// // optimizable
// struct DeleteByFreeing
// {
// void operator()(void* aPtr) { free(aPtr); }
// };
//
// If deletion really, truly, must be a variable: you might be able to work
// around this with a deleter class that contains the function reference.
// But this workaround is untried and untested, because variable deletion
// behavior really isn't something you should use.
UniquePtr(Pointer aPtr,
typename RemoveReference<D>::Type&& aD2)
: mTuple(aPtr, Move(aD2))
{
static_assert(!IsReference<D>::value,
"rvalue deleter can't be stored by reference");
}
UniquePtr(UniquePtr&& aOther)
: mTuple(aOther.release(), Forward<DeleterType>(aOther.get_deleter()))
{}
MOZ_IMPLICIT
UniquePtr(decltype(nullptr))
: mTuple(nullptr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
template<typename U, class E>
MOZ_IMPLICIT
UniquePtr(UniquePtr<U, E>&& aOther,
typename EnableIf<IsConvertible<typename UniquePtr<U, E>::Pointer,
Pointer>::value &&
!IsArray<U>::value &&
(IsReference<D>::value
? IsSame<D, E>::value
: IsConvertible<E, D>::value),
int>::Type aDummy = 0)
: mTuple(aOther.release(), Forward<E>(aOther.get_deleter()))
{
}
~UniquePtr() { reset(nullptr); }
UniquePtr& operator=(UniquePtr&& aOther)
{
reset(aOther.release());
get_deleter() = Forward<DeleterType>(aOther.get_deleter());
return *this;
}
template<typename U, typename E>
UniquePtr& operator=(UniquePtr<U, E>&& aOther)
{
static_assert(IsConvertible<typename UniquePtr<U, E>::Pointer,
Pointer>::value,
"incompatible UniquePtr pointees");
static_assert(!IsArray<U>::value,
"can't assign from UniquePtr holding an array");
reset(aOther.release());
get_deleter() = Forward<E>(aOther.get_deleter());
return *this;
}
UniquePtr& operator=(decltype(nullptr))
{
reset(nullptr);
return *this;
}
T& operator*() const { return *get(); }
Pointer operator->() const
{
MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
return get();
}
explicit operator bool() const { return get() != nullptr; }
Pointer get() const { return ptr(); }
DeleterType& get_deleter() { return del(); }
const DeleterType& get_deleter() const { return del(); }
MOZ_MUST_USE Pointer release()
{
Pointer p = ptr();
ptr() = nullptr;
return p;
}
void reset(Pointer aPtr = Pointer())
{
Pointer old = ptr();
ptr() = aPtr;
if (old != nullptr) {
get_deleter()(old);
}
}
void swap(UniquePtr& aOther)
{
mTuple.swap(aOther.mTuple);
}
UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()!
void operator=(const UniquePtr& aOther) = delete; // assign using Move()!
};
// In case you didn't read the comment by the main definition (you should!): the
// UniquePtr<T[]> specialization exists to manage array pointers. It deletes
// such pointers using delete[], it will reject construction and modification
// attempts using U* or U[]. Otherwise it works like the normal UniquePtr.
template<typename T, class D>
class UniquePtr<T[], D>
{
public:
typedef T* Pointer;
typedef T ElementType;
typedef D DeleterType;
private:
Pair<Pointer, DeleterType> mTuple;
public:
/**
* Construct a UniquePtr containing nullptr.
*/
constexpr UniquePtr()
: mTuple(static_cast<Pointer>(nullptr), DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
/**
* Construct a UniquePtr containing |aPtr|.
*/
explicit UniquePtr(Pointer aPtr)
: mTuple(aPtr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
// delete[] knows how to handle *only* an array of a single class type. For
// delete[] to work correctly, it must know the size of each element, the
// fields and base classes of each element requiring destruction, and so on.
// So forbid all overloads which would end up invoking delete[] on a pointer
// of the wrong type.
template<typename U>
UniquePtr(U&& aU,
typename EnableIf<IsPointer<U>::value &&
IsConvertible<U, Pointer>::value,
int>::Type aDummy = 0)
= delete;
UniquePtr(Pointer aPtr,
typename Conditional<IsReference<D>::value,
D,
const D&>::Type aD1)
: mTuple(aPtr, aD1)
{}
// If you encounter an error with MSVC10 about RemoveReference below, along
// the lines that "more than one partial specialization matches the template
// argument list": don't use UniquePtr<T[], reference to function>! See the
// comment by this constructor in the non-T[] specialization above.
UniquePtr(Pointer aPtr,
typename RemoveReference<D>::Type&& aD2)
: mTuple(aPtr, Move(aD2))
{
static_assert(!IsReference<D>::value,
"rvalue deleter can't be stored by reference");
}
// Forbidden for the same reasons as stated above.
template<typename U, typename V>
UniquePtr(U&& aU, V&& aV,
typename EnableIf<IsPointer<U>::value &&
IsConvertible<U, Pointer>::value,
int>::Type aDummy = 0)
= delete;
UniquePtr(UniquePtr&& aOther)
: mTuple(aOther.release(), Forward<DeleterType>(aOther.get_deleter()))
{}
MOZ_IMPLICIT
UniquePtr(decltype(nullptr))
: mTuple(nullptr, DeleterType())
{
static_assert(!IsPointer<D>::value, "must provide a deleter instance");
static_assert(!IsReference<D>::value, "must provide a deleter instance");
}
~UniquePtr() { reset(nullptr); }
UniquePtr& operator=(UniquePtr&& aOther)
{
reset(aOther.release());
get_deleter() = Forward<DeleterType>(aOther.get_deleter());
return *this;
}
UniquePtr& operator=(decltype(nullptr))
{
reset();
return *this;
}
explicit operator bool() const { return get() != nullptr; }
T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; }
Pointer get() const { return mTuple.first(); }
DeleterType& get_deleter() { return mTuple.second(); }
const DeleterType& get_deleter() const { return mTuple.second(); }
MOZ_MUST_USE Pointer release()
{
Pointer p = mTuple.first();
mTuple.first() = nullptr;
return p;
}
void reset(Pointer aPtr = Pointer())
{
Pointer old = mTuple.first();
mTuple.first() = aPtr;
if (old != nullptr) {
mTuple.second()(old);
}
}
void reset(decltype(nullptr))
{
Pointer old = mTuple.first();
mTuple.first() = nullptr;
if (old != nullptr) {
mTuple.second()(old);
}
}
template<typename U>
void reset(U) = delete;
void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); }
UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()!
void operator=(const UniquePtr& aOther) = delete; // assign using Move()!
};
/**
* A default deletion policy using plain old operator delete.
*
* Note that this type can be specialized, but authors should beware of the risk
* that the specialization may at some point cease to match (either because it
* gets moved to a different compilation unit or the signature changes). If the
* non-specialized (|delete|-based) version compiles for that type but does the
* wrong thing, bad things could happen.
*
* This is a non-issue for types which are always incomplete (i.e. opaque handle
* types), since |delete|-ing such a type will always trigger a compilation
* error.
*/
template<typename T>
class DefaultDelete
{
public:
constexpr DefaultDelete() {}
template<typename U>
MOZ_IMPLICIT DefaultDelete(const DefaultDelete<U>& aOther,
typename EnableIf<mozilla::IsConvertible<U*, T*>::value,
int>::Type aDummy = 0)
{}
void operator()(T* aPtr) const
{
static_assert(sizeof(T) > 0, "T must be complete");
delete aPtr;
}
};
/** A default deletion policy using operator delete[]. */
template<typename T>
class DefaultDelete<T[]>
{
public:
constexpr DefaultDelete() {}
void operator()(T* aPtr) const
{
static_assert(sizeof(T) > 0, "T must be complete");
delete[] aPtr;
}
template<typename U>
void operator()(U* aPtr) const = delete;
};
template<typename T, class D>
void
Swap(UniquePtr<T, D>& aX, UniquePtr<T, D>& aY)
{
aX.swap(aY);
}
template<typename T, class D, typename U, class E>
bool
operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY)
{
return aX.get() == aY.get();
}
template<typename T, class D, typename U, class E>
bool
operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY)
{
return aX.get() != aY.get();
}
template<typename T, class D>
bool
operator==(const UniquePtr<T, D>& aX, decltype(nullptr))
{
return !aX;
}
template<typename T, class D>
bool
operator==(decltype(nullptr), const UniquePtr<T, D>& aX)
{
return !aX;
}
template<typename T, class D>
bool
operator!=(const UniquePtr<T, D>& aX, decltype(nullptr))
{
return bool(aX);
}
template<typename T, class D>
bool
operator!=(decltype(nullptr), const UniquePtr<T, D>& aX)
{
return bool(aX);
}
// No operator<, operator>, operator<=, operator>= for now because simplicity.
namespace detail {
template<typename T>
struct UniqueSelector
{
typedef UniquePtr<T> SingleObject;
};
template<typename T>
struct UniqueSelector<T[]>
{
typedef UniquePtr<T[]> UnknownBound;
};
template<typename T, decltype(sizeof(int)) N>
struct UniqueSelector<T[N]>
{
typedef UniquePtr<T[N]> KnownBound;
};
} // namespace detail
/**
* MakeUnique is a helper function for allocating new'd objects and arrays,
* returning a UniquePtr containing the resulting pointer. The semantics of
* MakeUnique<Type>(...) are as follows.
*
* If Type is an array T[n]:
* Disallowed, deleted, no overload for you!
* If Type is an array T[]:
* MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned
* is as if by |new T[n]()|, which value-initializes each element. (If T
* isn't a class type, this will zero each element. If T is a class type,
* then roughly speaking, each element will be constructed using its default
* constructor. See C++11 [dcl.init]p7 for the full gory details.)
* If Type is non-array T:
* The arguments passed to MakeUnique<T>(...) are forwarded into a
* |new T(...)| call, initializing the T as would happen if executing
* |T(...)|.
*
* There are various benefits to using MakeUnique instead of |new| expressions.
*
* First, MakeUnique eliminates use of |new| from code entirely. If objects are
* only created through UniquePtr, then (assuming all explicit release() calls
* are safe, including transitively, and no type-safety casting funniness)
* correctly maintained ownership of the UniquePtr guarantees no leaks are
* possible. (This pays off best if a class is only ever created through a
* factory method on the class, using a private constructor.)
*
* Second, initializing a UniquePtr using a |new| expression requires repeating
* the name of the new'd type, whereas MakeUnique in concert with the |auto|
* keyword names it only once:
*
* UniquePtr<char> ptr1(new char()); // repetitive
* auto ptr2 = MakeUnique<char>(); // shorter
*
* Of course this assumes the reader understands the operation MakeUnique
* performs. In the long run this is probably a reasonable assumption. In the
* short run you'll have to use your judgment about what readers can be expected
* to know, or to quickly look up.
*
* Third, a call to MakeUnique can be assigned directly to a UniquePtr. In
* contrast you can't assign a pointer into a UniquePtr without using the
* cumbersome reset().
*
* UniquePtr<char> p;
* p = new char; // ERROR
* p.reset(new char); // works, but fugly
* p = MakeUnique<char>(); // preferred
*
* (And third, although not relevant to Mozilla: MakeUnique is exception-safe.
* An exception thrown after |new T| succeeds will leak that memory, unless the
* pointer is assigned to an object that will manage its ownership. UniquePtr
* ably serves this function.)
*/
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::SingleObject
MakeUnique(Args&&... aArgs)
{
return UniquePtr<T>(new T(Forward<Args>(aArgs)...));
}
template<typename T>
typename detail::UniqueSelector<T>::UnknownBound
MakeUnique(decltype(sizeof(int)) aN)
{
typedef typename RemoveExtent<T>::Type ArrayType;
return UniquePtr<T>(new ArrayType[aN]());
}
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::KnownBound
MakeUnique(Args&&... aArgs) = delete;
} // namespace mozilla
#endif /* mozilla_UniquePtr_h */