Merge mozilla-central to fx-team
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "e811ee9b89a2a4cbb789fb88e532113dc5105e2a",
|
||||
"revision": "36aa3e5d226a844b07b3e4b2219f54b549456ec1",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -13,10 +13,6 @@ export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
else
|
||||
|
@ -18,10 +18,6 @@ export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
else
|
||||
|
@ -8,10 +8,6 @@ ac_add_options --enable-metro
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
else
|
||||
|
@ -17,9 +17,5 @@ export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
@ -11,10 +11,6 @@ ac_add_options --enable-metro
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
||||
|
@ -1,8 +1,4 @@
|
||||
# Pymake needs Windows-style paths. Use cmd.exe to hack around this.
|
||||
mk_export_correct_style() {
|
||||
if test -n "${_PYMAKE}"; then
|
||||
mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
|
||||
else
|
||||
mk_add_options "export $1=$(eval echo \$$1)"
|
||||
fi
|
||||
mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
|
||||
}
|
||||
|
@ -85,13 +85,6 @@ endif
|
||||
# Windows checks.
|
||||
ifneq (,$(findstring mingw,$(CONFIG_GUESS)))
|
||||
|
||||
# Require pymake (as opposed to GNU make).
|
||||
ifndef .PYMAKE
|
||||
$(error Pymake is required to build on Windows. Run |./mach build| to \
|
||||
automatically use pymake. Or, invoke pymake directly via \
|
||||
|python build/pymake/make.py|.)
|
||||
endif
|
||||
|
||||
# check for CRLF line endings
|
||||
ifneq (0,$(shell $(PERL) -e 'binmode(STDIN); while (<STDIN>) { if (/\r/) { print "1"; exit } } print "0"' < $(TOPSRCDIR)/client.mk))
|
||||
$(error This source tree appears to have Windows-style line endings. To \
|
||||
@ -117,7 +110,7 @@ endef
|
||||
# before evaluation. $(shell) replacing newlines with spaces, || is always
|
||||
# followed by a space (since sed doesn't remove newlines), except on the
|
||||
# last line, so replace both '|| ' and '||'.
|
||||
MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell _PYMAKE=$(.PYMAKE) $(TOPSRCDIR)/$(MOZCONFIG_LOADER) $(TOPSRCDIR) | sed 's/$$/||/')))
|
||||
MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell $(TOPSRCDIR)/$(MOZCONFIG_LOADER) $(TOPSRCDIR) | sed 's/$$/||/')))
|
||||
$(eval $(MOZCONFIG_CONTENT))
|
||||
|
||||
export FOUND_MOZCONFIG
|
||||
|
@ -9,16 +9,15 @@ DIST = $(DEPTH)/dist
|
||||
_OBJ_SUFFIX := $(OBJ_SUFFIX)
|
||||
OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
|
||||
|
||||
# We only want to do the pymake sanity on Windows, other os's can cope
|
||||
ifeq ($(HOST_OS_ARCH),WINNT)
|
||||
# Ensure invariants between GNU Make and pymake
|
||||
# Checked here since we want the sane error in a file that
|
||||
# actually can be found regardless of path-style.
|
||||
ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir)))
|
||||
$(error Windows-style srcdir being used with GNU make. Did you mean to run $(topsrcdir)/build/pymake/make.py instead? [see-also: https://developer.mozilla.org/en/Gmake_vs._Pymake])
|
||||
# We only support building with pymake or a specially built gnu make.
|
||||
ifndef .PYMAKE
|
||||
ifeq (,$(filter mozmake%,$(notdir $(MAKE))))
|
||||
$(error Only building with pymake or mozmake is supported.)
|
||||
endif
|
||||
ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(srcdir))))
|
||||
$(error MSYS-style srcdir being used with Pymake. Did you mean to run GNU Make instead? [see-also: https://developer.mozilla.org/ en/Gmake_vs._Pymake])
|
||||
endif
|
||||
ifeq (a,$(firstword a$(subst /, ,$(srcdir))))
|
||||
$(error MSYS-style srcdir are not supported for Windows builds.)
|
||||
endif
|
||||
endif # WINNT
|
||||
|
||||
|
@ -220,13 +220,13 @@ endif # CPP_UNIT_TESTS
|
||||
|
||||
ifdef PYTHON_UNIT_TESTS
|
||||
|
||||
RUN_PYTHON_UNIT_TESTS := $(addprefix run-,$(PYTHON_UNIT_TESTS))
|
||||
RUN_PYTHON_UNIT_TESTS := $(addsuffix -run,$(PYTHON_UNIT_TESTS))
|
||||
|
||||
.PHONY: $(RUN_PYTHON_UNIT_TESTS)
|
||||
|
||||
check:: $(RUN_PYTHON_UNIT_TESTS)
|
||||
|
||||
$(RUN_PYTHON_UNIT_TESTS): run-%: %
|
||||
$(RUN_PYTHON_UNIT_TESTS): %-run: %
|
||||
@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $<
|
||||
|
||||
endif # PYTHON_UNIT_TESTS
|
||||
|
@ -1191,6 +1191,11 @@ DrawTargetCG::CopySurface(SourceSurface *aSurface,
|
||||
CGRect flippedRect = CGRectMake(aDestination.x, -(aDestination.y + aSourceRect.height),
|
||||
aSourceRect.width, aSourceRect.height);
|
||||
|
||||
// Quartz seems to copy A8 surfaces incorrectly if we don't initialize them
|
||||
// to transparent first.
|
||||
if (mFormat == FORMAT_A8) {
|
||||
CGContextClearRect(mCg, flippedRect);
|
||||
}
|
||||
CGContextDrawImage(mCg, flippedRect, image);
|
||||
|
||||
CGContextRestoreGState(mCg);
|
||||
|
@ -16,6 +16,8 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
// The Data is layed out as follows:
|
||||
//
|
||||
// +-------------------+ -++ --+ <-- ImageDataSerializerBase::mData pointer
|
||||
@ -36,11 +38,11 @@ struct SurfaceBufferInfo
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
gfx::SurfaceFormat format;
|
||||
SurfaceFormat format;
|
||||
|
||||
static uint32_t GetOffset()
|
||||
{
|
||||
return gfx::GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
|
||||
return GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
@ -53,8 +55,8 @@ GetBufferInfo(uint8_t* aBuffer)
|
||||
|
||||
|
||||
void
|
||||
ImageDataSerializer::InitializeBufferInfo(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
ImageDataSerializer::InitializeBufferInfo(IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
info->width = aSize.width;
|
||||
@ -63,18 +65,18 @@ ImageDataSerializer::InitializeBufferInfo(gfx::IntSize aSize,
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
ComputeStride(gfx::SurfaceFormat aFormat, uint32_t aWidth)
|
||||
ComputeStride(SurfaceFormat aFormat, uint32_t aWidth)
|
||||
{
|
||||
return gfx::GetAlignedStride<4>(gfx::BytesPerPixel(aFormat) * aWidth);
|
||||
return GetAlignedStride<4>(BytesPerPixel(aFormat) * aWidth);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ImageDataSerializer::ComputeMinBufferSize(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
ImageDataSerializer::ComputeMinBufferSize(IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
uint32_t bufsize = aSize.height * ComputeStride(aFormat, aSize.width);
|
||||
return SurfaceBufferInfo::GetOffset()
|
||||
+ gfx::GetAlignedStride<16>(bufsize);
|
||||
+ GetAlignedStride<16>(bufsize);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -91,15 +93,23 @@ ImageDataSerializerBase::GetData()
|
||||
return mData + SurfaceBufferInfo::GetOffset();
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
uint32_t
|
||||
ImageDataSerializerBase::GetStride() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
return ComputeStride(GetFormat(), info->width);
|
||||
}
|
||||
|
||||
IntSize
|
||||
ImageDataSerializerBase::GetSize() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
return gfx::IntSize(info->width, info->height);
|
||||
return IntSize(info->width, info->height);
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
SurfaceFormat
|
||||
ImageDataSerializerBase::GetFormat() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
@ -110,25 +120,31 @@ TemporaryRef<gfxImageSurface>
|
||||
ImageDataSerializerBase::GetAsThebesSurface()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
uint32_t stride = ComputeStride(GetFormat(), info->width);
|
||||
gfxIntSize size(info->width, info->height);
|
||||
RefPtr<gfxImageSurface> surf =
|
||||
new gfxImageSurface(GetData(), size, stride,
|
||||
gfx::SurfaceFormatToImageFormat(GetFormat()));
|
||||
return surf.forget();
|
||||
IntSize size = GetSize();
|
||||
return new gfxImageSurface(GetData(),
|
||||
gfxIntSize(size.width, size.height),
|
||||
GetStride(),
|
||||
SurfaceFormatToImageFormat(GetFormat()));
|
||||
}
|
||||
|
||||
TemporaryRef<gfx::DataSourceSurface>
|
||||
TemporaryRef<DrawTarget>
|
||||
ImageDataSerializerBase::GetAsDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return gfxPlatform::GetPlatform()->CreateDrawTargetForData(GetData(),
|
||||
GetSize(),
|
||||
GetStride(),
|
||||
GetFormat());
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
ImageDataSerializerBase::GetAsSurface()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
gfx::IntSize size(info->width, info->height);
|
||||
uint32_t stride = ComputeStride(GetFormat(), info->width);
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(GetData(), stride, size, GetFormat());
|
||||
return surf.forget();
|
||||
return Factory::CreateWrappingDataSourceSurface(GetData(),
|
||||
GetStride(),
|
||||
GetSize(),
|
||||
GetFormat());
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
@ -19,6 +19,7 @@ class gfxImageSurface;
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
@ -35,8 +36,11 @@ public:
|
||||
gfx::SurfaceFormat GetFormat() const;
|
||||
TemporaryRef<gfx::DataSourceSurface> GetAsSurface();
|
||||
TemporaryRef<gfxImageSurface> GetAsThebesSurface();
|
||||
TemporaryRef<gfx::DrawTarget> GetAsDrawTarget();
|
||||
|
||||
protected:
|
||||
uint32_t GetStride() const;
|
||||
|
||||
ImageDataSerializerBase(uint8_t* aData)
|
||||
: mData(aData) {}
|
||||
uint8_t* mData;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "ImageContainer.h" // for PlanarYCbCrImage, etc
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#ifdef MOZ_ANDROID_OMTC
|
||||
# include "gfxReusableImageSurfaceWrapper.h"
|
||||
@ -32,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gl;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -259,15 +261,23 @@ BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
|
||||
if (!surf) {
|
||||
return false;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
RefPtr<DrawTarget> dt = serializer.GetAsDrawTarget();
|
||||
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
|
||||
|
||||
dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
|
||||
} else {
|
||||
RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
|
||||
if (!surf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
|
||||
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
|
||||
serializer.GetSize().height));
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
|
||||
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
|
||||
serializer.GetSize().height));
|
||||
|
||||
if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) {
|
||||
// We don't have support for proper locking yet, so we'll
|
||||
|
@ -11,8 +11,9 @@
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
|
||||
using namespace gfx;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
@ -73,6 +74,31 @@ void AssertSurfacesEqual(gfxImageSurface* surface1,
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above, for YCbCr surfaces
|
||||
void AssertYCbCrSurfacesEqual(PlanarYCbCrData* surface1,
|
||||
PlanarYCbCrData* surface2)
|
||||
{
|
||||
ASSERT_EQ(surface1->mYSize, surface2->mYSize);
|
||||
ASSERT_EQ(surface1->mCbCrSize, surface2->mCbCrSize);
|
||||
ASSERT_EQ(surface1->mStereoMode, surface2->mStereoMode);
|
||||
ASSERT_EQ(surface1->mPicSize, surface2->mPicSize);
|
||||
|
||||
for (int y = 0; y < surface1->mYSize.height; ++y) {
|
||||
for (int x = 0; x < surface1->mYSize.width; ++x) {
|
||||
ASSERT_EQ(surface1->mYChannel[y*surface1->mYStride + x*(1+surface1->mYSkip)],
|
||||
surface2->mYChannel[y*surface2->mYStride + x*(1+surface2->mYSkip)]);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < surface1->mCbCrSize.height; ++y) {
|
||||
for (int x = 0; x < surface1->mCbCrSize.width; ++x) {
|
||||
ASSERT_EQ(surface1->mCbChannel[y*surface1->mCbCrStride + x*(1+surface1->mCbSkip)],
|
||||
surface2->mCbChannel[y*surface2->mCbCrStride + x*(1+surface2->mCbSkip)]);
|
||||
ASSERT_EQ(surface1->mCrChannel[y*surface1->mCbCrStride + x*(1+surface1->mCrSkip)],
|
||||
surface2->mCrChannel[y*surface2->mCbCrStride + x*(1+surface2->mCrSkip)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test for a texture client and a surface
|
||||
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
|
||||
|
||||
@ -119,6 +145,74 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
|
||||
host->DeallocateSharedData();
|
||||
}
|
||||
|
||||
// Same as above, for YCbCr surfaces
|
||||
void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
|
||||
|
||||
// client allocation
|
||||
ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr);
|
||||
TextureClientYCbCr* texture = client->AsTextureClientYCbCr();
|
||||
texture->AllocateForYCbCr(ToIntSize(ycbcrData.mYSize),
|
||||
ToIntSize(ycbcrData.mCbCrSize),
|
||||
ycbcrData.mStereoMode);
|
||||
ASSERT_TRUE(client->IsAllocated());
|
||||
|
||||
// client painting
|
||||
texture->UpdateYCbCr(ycbcrData);
|
||||
|
||||
ASSERT_TRUE(client->Lock(OPEN_READ_ONLY));
|
||||
client->Unlock();
|
||||
|
||||
// client serialization
|
||||
client->SetID(1);
|
||||
SurfaceDescriptor descriptor;
|
||||
ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
|
||||
|
||||
ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
|
||||
|
||||
// host deserialization
|
||||
RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(client->GetID(),
|
||||
descriptor, nullptr,
|
||||
client->GetFlags());
|
||||
|
||||
RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
|
||||
|
||||
ASSERT_TRUE(host.get() != nullptr);
|
||||
ASSERT_EQ(host->GetFlags(), client->GetFlags());
|
||||
ASSERT_EQ(host->GetID(), client->GetID());
|
||||
|
||||
// This will work iff the compositor is not BasicCompositor
|
||||
ASSERT_EQ(host->GetFormat(), mozilla::gfx::FORMAT_YUV);
|
||||
|
||||
// host read
|
||||
ASSERT_TRUE(host->Lock());
|
||||
|
||||
ASSERT_TRUE(host->GetFormat() == mozilla::gfx::FORMAT_YUV);
|
||||
|
||||
YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer());
|
||||
ASSERT_TRUE(yuvDeserializer.IsValid());
|
||||
PlanarYCbCrData data;
|
||||
data.mYChannel = yuvDeserializer.GetYData();
|
||||
data.mCbChannel = yuvDeserializer.GetCbData();
|
||||
data.mCrChannel = yuvDeserializer.GetCrData();
|
||||
data.mYStride = yuvDeserializer.GetYStride();
|
||||
data.mCbCrStride = yuvDeserializer.GetCbCrStride();
|
||||
data.mStereoMode = yuvDeserializer.GetStereoMode();
|
||||
data.mYSize = yuvDeserializer.GetYSize();
|
||||
data.mCbCrSize = yuvDeserializer.GetCbCrSize();
|
||||
data.mYSkip = 0;
|
||||
data.mCbSkip = 0;
|
||||
data.mCrSkip = 0;
|
||||
data.mPicSize = data.mYSize;
|
||||
data.mPicX = 0;
|
||||
data.mPicY = 0;
|
||||
|
||||
AssertYCbCrSurfacesEqual(&ycbcrData, &data);
|
||||
host->Unlock();
|
||||
|
||||
// host deallocation
|
||||
host->DeallocateSharedData();
|
||||
}
|
||||
|
||||
TEST(Layers, TextureSerialization) {
|
||||
// the test is run on all the following image formats
|
||||
gfxImageFormat formats[3] = {
|
||||
@ -142,3 +236,38 @@ TEST(Layers, TextureSerialization) {
|
||||
// XXX - Test more texture client types.
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Layers, TextureYCbCrSerialization) {
|
||||
RefPtr<gfxImageSurface> ySurface = new gfxImageSurface(gfxIntSize(400,300), gfxImageFormatA8);
|
||||
RefPtr<gfxImageSurface> cbSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormatA8);
|
||||
RefPtr<gfxImageSurface> crSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormatA8);
|
||||
SetupSurface(ySurface.get());
|
||||
SetupSurface(cbSurface.get());
|
||||
SetupSurface(crSurface.get());
|
||||
|
||||
PlanarYCbCrData clientData;
|
||||
clientData.mYChannel = ySurface->Data();
|
||||
clientData.mCbChannel = cbSurface->Data();
|
||||
clientData.mCrChannel = crSurface->Data();
|
||||
clientData.mYSize = ySurface->GetSize();
|
||||
clientData.mPicSize = ySurface->GetSize();
|
||||
clientData.mCbCrSize = cbSurface->GetSize();
|
||||
clientData.mYStride = ySurface->Stride();
|
||||
clientData.mCbCrStride = cbSurface->Stride();
|
||||
clientData.mStereoMode = STEREO_MODE_MONO;
|
||||
clientData.mYSkip = 0;
|
||||
clientData.mCbSkip = 0;
|
||||
clientData.mCrSkip = 0;
|
||||
clientData.mCrSkip = 0;
|
||||
clientData.mPicX = 0;
|
||||
clientData.mPicX = 0;
|
||||
|
||||
RefPtr<TextureClient> client
|
||||
= new MemoryTextureClient(nullptr,
|
||||
mozilla::gfx::FORMAT_YUV,
|
||||
TEXTURE_FLAGS_DEFAULT);
|
||||
|
||||
TestTextureClientYCbCr(client, clientData);
|
||||
|
||||
// XXX - Test more texture client types.
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxContext.h"
|
||||
@ -52,6 +53,7 @@
|
||||
#include "nsIClipboardHelper.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
static cairo_user_data_key_t gfxasurface_pointer_key;
|
||||
|
||||
@ -359,10 +361,17 @@ gfxASurface::CopyToARGB32ImageSurface()
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(size, gfxImageFormatARGB32);
|
||||
|
||||
gfxContext ctx(imgSurface);
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx.SetSource(this);
|
||||
ctx.Paint();
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height));
|
||||
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
|
||||
|
||||
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
|
||||
} else {
|
||||
gfxContext ctx(imgSurface);
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx.SetSource(this);
|
||||
ctx.Paint();
|
||||
}
|
||||
|
||||
return imgSurface.forget();
|
||||
}
|
||||
|
@ -188,6 +188,10 @@ gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
|
||||
{
|
||||
}
|
||||
|
||||
gfxPatternDrawable::~gfxPatternDrawable()
|
||||
{
|
||||
}
|
||||
|
||||
class DrawingCallbackFromDrawable : public gfxDrawingCallback {
|
||||
public:
|
||||
DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
|
||||
|
@ -123,7 +123,7 @@ class gfxPatternDrawable : public gfxDrawable {
|
||||
public:
|
||||
gfxPatternDrawable(gfxPattern* aPattern,
|
||||
const gfxIntSize aSize);
|
||||
virtual ~gfxPatternDrawable() {}
|
||||
virtual ~gfxPatternDrawable();
|
||||
|
||||
virtual bool Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
|
@ -6,6 +6,8 @@
|
||||
#ifndef gfxMacPlatformFontList_H_
|
||||
#define gfxMacPlatformFontList_H_
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
@ -14,8 +16,6 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPlatformMac.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@ -101,7 +101,11 @@ private:
|
||||
// special case font faces treated as font families (set via prefs)
|
||||
void InitSingleFaceList();
|
||||
|
||||
static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
|
||||
static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo);
|
||||
|
||||
// search fonts system-wide for a given character, null otherwise
|
||||
virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
|
||||
@ -112,9 +116,6 @@ private:
|
||||
|
||||
virtual bool UsesSystemFallback() { return true; }
|
||||
|
||||
// keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
|
||||
uint32_t mATSGeneration;
|
||||
|
||||
enum {
|
||||
kATSGenerationInitial = -1
|
||||
};
|
||||
|
@ -43,7 +43,6 @@
|
||||
#endif
|
||||
#include "prlog.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <algorithm>
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
@ -646,12 +645,15 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF
|
||||
#pragma mark-
|
||||
|
||||
gfxMacPlatformFontList::gfxMacPlatformFontList() :
|
||||
gfxPlatformFontList(false), mATSGeneration(uint32_t(kATSGenerationInitial)),
|
||||
gfxPlatformFontList(false),
|
||||
mDefaultFont(nullptr)
|
||||
{
|
||||
::ATSFontNotificationSubscribe(ATSNotification,
|
||||
kATSFontNotifyOptionDefault,
|
||||
(void*)this, nullptr);
|
||||
::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(),
|
||||
this,
|
||||
RegisteredFontsChangedNotificationCallback,
|
||||
kCTFontManagerRegisteredFontsChangedNotification,
|
||||
0,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
|
||||
// cache this in a static variable so that MacOSFontFamily objects
|
||||
// don't have to repeatedly look it up
|
||||
@ -670,19 +672,8 @@ gfxMacPlatformFontList::InitFontList()
|
||||
{
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
ATSGeneration currentGeneration = ::ATSGetGeneration();
|
||||
|
||||
// need to ignore notifications after adding each font
|
||||
if (mATSGeneration == currentGeneration)
|
||||
return NS_OK;
|
||||
|
||||
Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
|
||||
|
||||
mATSGeneration = currentGeneration;
|
||||
#ifdef PR_LOGGING
|
||||
LOG_FONTLIST(("(fontlist) updating to generation: %d", mATSGeneration));
|
||||
#endif
|
||||
|
||||
// reset font lists
|
||||
gfxPlatformFontList::InitFontList();
|
||||
|
||||
@ -777,11 +768,18 @@ gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAStr
|
||||
}
|
||||
|
||||
void
|
||||
gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
|
||||
void* aUserArg)
|
||||
gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo)
|
||||
{
|
||||
if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
|
||||
static_cast<gfxMacPlatformFontList*>(aUserArg)->UpdateFontList();
|
||||
static_cast<gfxMacPlatformFontList*>(observer)->UpdateFontList();
|
||||
|
||||
// modify a preference that will trigger reflow everywhere
|
||||
static const char kPrefName[] = "font.internaluseonly.changed";
|
||||
|
@ -235,11 +235,21 @@ ClippedImage::GetFrameInternal(const nsIntSize& aViewportSize,
|
||||
aFlags)) {
|
||||
// Create a surface to draw into.
|
||||
mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
|
||||
target = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
|
||||
gfx::FORMAT_B8G8R8A8);
|
||||
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
|
||||
GetThebesSurfaceForDrawTarget(target);
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
target = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height),
|
||||
gfx::FORMAT_B8G8R8A8);
|
||||
ctx = new gfxContext(target);
|
||||
} else {
|
||||
target = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
|
||||
gfx::FORMAT_B8G8R8A8);
|
||||
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
|
||||
GetThebesSurfaceForDrawTarget(target);
|
||||
ctx = new gfxContext(surface);
|
||||
}
|
||||
|
||||
// Create our callback.
|
||||
nsRefPtr<gfxDrawingCallback> drawTileCallback =
|
||||
@ -248,7 +258,6 @@ ClippedImage::GetFrameInternal(const nsIntSize& aViewportSize,
|
||||
new gfxCallbackDrawable(drawTileCallback, mClip.Size());
|
||||
|
||||
// Actually draw. The callback will end up invoking DrawSingleTile.
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
|
||||
gfxRect imageRect(0, 0, mClip.width, mClip.height);
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, gfxMatrix(),
|
||||
imageRect, imageRect, imageRect, imageRect,
|
||||
|
@ -245,6 +245,28 @@ void imgRequest::CancelAndAbort(nsresult aStatus)
|
||||
}
|
||||
}
|
||||
|
||||
class imgRequestMainThreadCancel : public nsRunnable
|
||||
{
|
||||
public:
|
||||
imgRequestMainThreadCancel(imgRequest *aImgRequest, nsresult aStatus)
|
||||
: mImgRequest(aImgRequest)
|
||||
, mStatus(aStatus)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Create me off main thread only!");
|
||||
MOZ_ASSERT(aImgRequest);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "I should be running on the main thread!");
|
||||
mImgRequest->ContinueCancel(mStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<imgRequest> mImgRequest;
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
void imgRequest::Cancel(nsresult aStatus)
|
||||
{
|
||||
/* The Cancel() method here should only be called by this class. */
|
||||
@ -258,14 +280,22 @@ void imgRequest::Cancel(nsresult aStatus)
|
||||
statusTracker->RecordCancel();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
RemoveFromCache();
|
||||
ContinueCancel(aStatus);
|
||||
} else {
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableMethod(this, &imgRequest::RemoveFromCache));
|
||||
NS_DispatchToMainThread(new imgRequestMainThreadCancel(this, aStatus));
|
||||
}
|
||||
}
|
||||
|
||||
if (mRequest && statusTracker->IsLoading())
|
||||
mRequest->Cancel(aStatus);
|
||||
void imgRequest::ContinueCancel(nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RemoveFromCache();
|
||||
|
||||
nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
|
||||
if (mRequest && statusTracker->IsLoading()) {
|
||||
mRequest->Cancel(aStatus);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult imgRequest::GetURI(ImageURL **aURI)
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
// won't be sufficient.
|
||||
void CancelAndAbort(nsresult aStatus);
|
||||
|
||||
// Called or dispatched by cancel for main thread only execution.
|
||||
void ContinueCancel(nsresult aStatus);
|
||||
|
||||
// Methods that get forwarded to the Image, or deferred until it's
|
||||
// instantiated.
|
||||
nsresult LockImage();
|
||||
|
@ -23,8 +23,11 @@
|
||||
#include "Image.h"
|
||||
#include "ScriptedNotificationObserver.h"
|
||||
#include "imgIScriptedNotificationObserver.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::image;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
/* ========== imgITools implementation ========== */
|
||||
|
||||
@ -144,17 +147,33 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
|
||||
// Create a temporary image surface
|
||||
nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
|
||||
gfxImageFormatARGB32);
|
||||
gfxContext ctx(dest);
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(dest, IntSize(aScaledWidth, aScaledHeight));
|
||||
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, frame);
|
||||
|
||||
// Set scaling
|
||||
gfxFloat sw = (double) aScaledWidth / frameWidth;
|
||||
gfxFloat sh = (double) aScaledHeight / frameHeight;
|
||||
ctx.Scale(sw, sh);
|
||||
dt->DrawSurface(source,
|
||||
Rect(0, 0, aScaledWidth, aScaledHeight),
|
||||
Rect(0, 0, frameWidth, frameHeight),
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, OP_SOURCE));
|
||||
} else {
|
||||
gfxContext ctx(dest);
|
||||
|
||||
// Set scaling
|
||||
gfxFloat sw = (double) aScaledWidth / frameWidth;
|
||||
gfxFloat sh = (double) aScaledHeight / frameHeight;
|
||||
ctx.Scale(sw, sh);
|
||||
|
||||
// Paint a scaled image
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
|
||||
nsRefPtr<gfxPattern> pat = new gfxPattern(frame);
|
||||
pat->SetExtend(gfxPattern::EXTEND_PAD);
|
||||
ctx.SetPattern(pat);
|
||||
ctx.Paint();
|
||||
}
|
||||
|
||||
// Paint a scaled image
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx.SetSource(frame);
|
||||
ctx.Paint();
|
||||
|
||||
return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@ -289,7 +289,7 @@ encodedBytes = streamToArray(istream);
|
||||
refName = "image3ico32x32.png";
|
||||
refFile = do_get_file(refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 2281);
|
||||
do_check_eq(istream.available(), 2285);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
|
@ -16,16 +16,15 @@ endif
|
||||
_OBJ_SUFFIX := $(OBJ_SUFFIX)
|
||||
OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
|
||||
|
||||
# We only want to do the pymake sanity on Windows, other os's can cope
|
||||
ifeq ($(HOST_OS_ARCH),WINNT)
|
||||
# Ensure invariants between GNU Make and pymake
|
||||
# Checked here since we want the sane error in a file that
|
||||
# actually can be found regardless of path-style.
|
||||
ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir)))
|
||||
$(error Windows-style srcdir being used with GNU make. Did you mean to run $(topsrcdir)/build/pymake/make.py instead? [see-also: https://developer.mozilla.org/en/Gmake_vs._Pymake])
|
||||
# We only support building with pymake or a specially built gnu make.
|
||||
ifndef .PYMAKE
|
||||
ifeq (,$(filter mozmake%,$(notdir $(MAKE))))
|
||||
$(error Only building with pymake or mozmake is supported.)
|
||||
endif
|
||||
ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(srcdir))))
|
||||
$(error MSYS-style srcdir being used with Pymake. Did you mean to run GNU Make instead? [see-also: https://developer.mozilla.org/ en/Gmake_vs._Pymake])
|
||||
endif
|
||||
ifeq (a,$(firstword a$(subst /, ,$(srcdir))))
|
||||
$(error MSYS-style srcdir are not supported for Windows builds.)
|
||||
endif
|
||||
endif # WINNT
|
||||
|
||||
|
@ -220,13 +220,13 @@ endif # CPP_UNIT_TESTS
|
||||
|
||||
ifdef PYTHON_UNIT_TESTS
|
||||
|
||||
RUN_PYTHON_UNIT_TESTS := $(addprefix run-,$(PYTHON_UNIT_TESTS))
|
||||
RUN_PYTHON_UNIT_TESTS := $(addsuffix -run,$(PYTHON_UNIT_TESTS))
|
||||
|
||||
.PHONY: $(RUN_PYTHON_UNIT_TESTS)
|
||||
|
||||
check:: $(RUN_PYTHON_UNIT_TESTS)
|
||||
|
||||
$(RUN_PYTHON_UNIT_TESTS): run-%: %
|
||||
$(RUN_PYTHON_UNIT_TESTS): %-run: %
|
||||
@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $<
|
||||
|
||||
endif # PYTHON_UNIT_TESTS
|
||||
|
@ -4197,6 +4197,7 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
|
||||
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS"
|
||||
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION"
|
||||
|
||||
ICU_SRCDIR=""
|
||||
# Set OS dependent options for ICU
|
||||
case "$OS_TARGET" in
|
||||
Darwin)
|
||||
@ -4207,6 +4208,7 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
|
||||
;;
|
||||
WINNT)
|
||||
ICU_TARGET=MSYS/MSVC
|
||||
ICU_SRCDIR="--srcdir=$(cd $srcdir/../../intl/icu/source; pwd -W)"
|
||||
;;
|
||||
DragonFly|FreeBSD|NetBSD|OpenBSD)
|
||||
ICU_TARGET=BSD
|
||||
@ -4240,6 +4242,8 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
|
||||
$ICU_BUILD_OPTS \
|
||||
$ICU_TARGET \
|
||||
$ICU_LINK_OPTS \
|
||||
dnl Shell quoting is fun.
|
||||
${ICU_SRCDIR+"$ICU_SRCDIR"} \
|
||||
--enable-extras=no --enable-icuio=no --enable-layout=no \
|
||||
--enable-tests=no --enable-samples=no || exit 1
|
||||
])
|
||||
|
@ -478,6 +478,10 @@ MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest
|
||||
convertUInt32ToDouble(temp, dest.fpu());
|
||||
} else {
|
||||
load32(src, dest.gpr());
|
||||
|
||||
// Bail out if the value doesn't fit into a signed int32 value. This
|
||||
// is what allows MLoadTypedArrayElement to have a type() of
|
||||
// MIRType_Int32 for UInt32 array loads.
|
||||
test32(dest.gpr(), dest.gpr());
|
||||
j(Assembler::Signed, fail);
|
||||
}
|
||||
|
@ -2027,8 +2027,8 @@ class LBitOpI : public LInstructionHelper<1, 2, 0>
|
||||
{ }
|
||||
|
||||
const char *extraName() const {
|
||||
if (bitop() == JSOP_URSH && mir_->toUrsh()->canOverflow())
|
||||
return "UrshCanOverflow";
|
||||
if (bitop() == JSOP_URSH && mir_->toUrsh()->bailoutsDisabled())
|
||||
return "ursh:BailoutsDisabled";
|
||||
return js_CodeName[op_];
|
||||
}
|
||||
|
||||
|
@ -2706,6 +2706,7 @@ LIRGenerator::visitAssertRange(MAssertRange *ins)
|
||||
LInstruction *lir = nullptr;
|
||||
|
||||
switch (input->type()) {
|
||||
case MIRType_Boolean:
|
||||
case MIRType_Int32:
|
||||
lir = new LAssertRangeI(useRegisterAtStart(input));
|
||||
break;
|
||||
|
@ -1466,9 +1466,9 @@ MMul::canOverflow()
|
||||
}
|
||||
|
||||
bool
|
||||
MUrsh::canOverflow()
|
||||
MUrsh::fallible()
|
||||
{
|
||||
if (!canOverflow_)
|
||||
if (bailoutsDisabled())
|
||||
return false;
|
||||
return !range() || !range()->hasInt32Bounds();
|
||||
}
|
||||
@ -2013,7 +2013,14 @@ MUrsh::NewAsmJS(MDefinition *left, MDefinition *right)
|
||||
{
|
||||
MUrsh *ins = new MUrsh(left, right);
|
||||
ins->specializeForAsmJS();
|
||||
ins->canOverflow_ = false;
|
||||
|
||||
// Since Ion has no UInt32 type, we use Int32 and we have a special
|
||||
// exception to the type rules: we can return values in
|
||||
// (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
|
||||
// without bailing out. This is necessary because Ion has no UInt32
|
||||
// type and we can't have bailouts in asm.js code.
|
||||
ins->bailoutsDisabled_ = true;
|
||||
|
||||
return ins;
|
||||
}
|
||||
|
||||
|
@ -359,6 +359,10 @@ class MDefinition : public MNode
|
||||
return trackedPc_;
|
||||
}
|
||||
|
||||
// Return the range of this value, *before* any bailout checks. Contrast
|
||||
// this with the type() method, and the Range constructor which takes an
|
||||
// MDefinition*, which describe the value *after* any bailout checks.
|
||||
//
|
||||
// Warning: Range analysis is removing the bit-operations such as '| 0' at
|
||||
// the end of the transformations. Using this function to analyse any
|
||||
// operands after the truncate phase of the range analysis will lead to
|
||||
@ -438,6 +442,12 @@ class MDefinition : public MNode
|
||||
MIR_FLAG_LIST(FLAG_ACCESSOR)
|
||||
#undef FLAG_ACCESSOR
|
||||
|
||||
// Return the type of this value. This may be speculative, and enforced
|
||||
// dynamically with the use of bailout checks. If all the bailout checks
|
||||
// pass, the value will have this type.
|
||||
//
|
||||
// Unless this is an MUrsh, which, as a special case, may return a value
|
||||
// in (INT32_MAX,UINT32_MAX] even when its type() is MIRType_Int32.
|
||||
MIRType type() const {
|
||||
return resultType_;
|
||||
}
|
||||
@ -548,7 +558,8 @@ class MDefinition : public MNode
|
||||
bool is##opcode() const { \
|
||||
return op() == Op_##opcode; \
|
||||
} \
|
||||
inline M##opcode *to##opcode();
|
||||
inline M##opcode *to##opcode(); \
|
||||
inline const M##opcode *to##opcode() const;
|
||||
MIR_OPCODE_LIST(OPCODE_CASTS)
|
||||
# undef OPCODE_CASTS
|
||||
|
||||
@ -3232,11 +3243,11 @@ class MRsh : public MShiftInstruction
|
||||
|
||||
class MUrsh : public MShiftInstruction
|
||||
{
|
||||
bool canOverflow_;
|
||||
bool bailoutsDisabled_;
|
||||
|
||||
MUrsh(MDefinition *left, MDefinition *right)
|
||||
: MShiftInstruction(left, right),
|
||||
canOverflow_(true)
|
||||
bailoutsDisabled_(false)
|
||||
{ }
|
||||
|
||||
public:
|
||||
@ -3254,12 +3265,12 @@ class MUrsh : public MShiftInstruction
|
||||
|
||||
void infer(BaselineInspector *inspector, jsbytecode *pc);
|
||||
|
||||
bool canOverflow();
|
||||
|
||||
bool fallible() {
|
||||
return canOverflow();
|
||||
bool bailoutsDisabled() const {
|
||||
return bailoutsDisabled_;
|
||||
}
|
||||
|
||||
bool fallible();
|
||||
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
@ -8936,6 +8947,11 @@ class MAsmJSCheckOverRecursed : public MNullaryInstruction
|
||||
{ \
|
||||
JS_ASSERT(is##opcode()); \
|
||||
return static_cast<M##opcode *>(this); \
|
||||
} \
|
||||
const M##opcode *MDefinition::to##opcode() const \
|
||||
{ \
|
||||
JS_ASSERT(is##opcode()); \
|
||||
return static_cast<const M##opcode *>(this); \
|
||||
}
|
||||
MIR_OPCODE_LIST(OPCODE_CASTS)
|
||||
#undef OPCODE_CASTS
|
||||
|
@ -29,7 +29,10 @@ using mozilla::IsInfinite;
|
||||
using mozilla::IsFinite;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::IsNegative;
|
||||
using mozilla::NegativeInfinity;
|
||||
using mozilla::PositiveInfinity;
|
||||
using mozilla::Swap;
|
||||
using JS::GenericNaN;
|
||||
|
||||
// This algorithm is based on the paper "Eliminating Range Checks Using
|
||||
// Static Single Assignment Form" by Gough and Klaren.
|
||||
@ -142,22 +145,19 @@ RangeAnalysis::addBetaNodes()
|
||||
continue;
|
||||
|
||||
MCompare *compare = test->getOperand(0)->toCompare();
|
||||
|
||||
// TODO: support unsigned comparisons
|
||||
if (compare->compareType() == MCompare::Compare_UInt32)
|
||||
continue;
|
||||
|
||||
MDefinition *left = compare->getOperand(0);
|
||||
MDefinition *right = compare->getOperand(1);
|
||||
double bound;
|
||||
int16_t exponent = Range::IncludesInfinity;
|
||||
double conservativeLower = NegativeInfinity();
|
||||
double conservativeUpper = PositiveInfinity();
|
||||
MDefinition *val = nullptr;
|
||||
|
||||
JSOp jsop = compare->jsop();
|
||||
|
||||
if (branch_dir == FALSE_BRANCH) {
|
||||
jsop = analyze::NegateCompareOp(jsop);
|
||||
exponent = Range::IncludesInfinityAndNaN;
|
||||
conservativeLower = GenericNaN();
|
||||
conservativeUpper = GenericNaN();
|
||||
}
|
||||
|
||||
if (left->isConstant() && left->toConstant()->value().isNumber()) {
|
||||
@ -197,15 +197,10 @@ RangeAnalysis::addBetaNodes()
|
||||
// val is the other operand.
|
||||
JS_ASSERT(val);
|
||||
|
||||
// If we can't convert this bound to an int32_t, it won't be as easy to
|
||||
// create interesting Ranges with.
|
||||
if (!IsFinite(bound) || bound < INT32_MIN || bound > INT32_MAX)
|
||||
continue;
|
||||
|
||||
Range comp;
|
||||
switch (jsop) {
|
||||
case JSOP_LE:
|
||||
comp.set(Range::NoInt32LowerBound, ceil(bound), true, exponent);
|
||||
comp.setDouble(conservativeLower, bound);
|
||||
break;
|
||||
case JSOP_LT:
|
||||
// For integers, if x < c, the upper bound of x is c-1.
|
||||
@ -214,10 +209,10 @@ RangeAnalysis::addBetaNodes()
|
||||
if (DoubleIsInt32(bound, &intbound) && SafeSub(intbound, 1, &intbound))
|
||||
bound = intbound;
|
||||
}
|
||||
comp.set(Range::NoInt32LowerBound, ceil(bound), true, exponent);
|
||||
comp.setDouble(conservativeLower, bound);
|
||||
break;
|
||||
case JSOP_GE:
|
||||
comp.set(floor(bound), Range::NoInt32UpperBound, true, exponent);
|
||||
comp.setDouble(bound, conservativeUpper);
|
||||
break;
|
||||
case JSOP_GT:
|
||||
// For integers, if x > c, the lower bound of x is c+1.
|
||||
@ -226,10 +221,11 @@ RangeAnalysis::addBetaNodes()
|
||||
if (DoubleIsInt32(bound, &intbound) && SafeAdd(intbound, 1, &intbound))
|
||||
bound = intbound;
|
||||
}
|
||||
comp.set(floor(bound), Range::NoInt32UpperBound, true, exponent);
|
||||
comp.setDouble(bound, conservativeUpper);
|
||||
break;
|
||||
case JSOP_EQ:
|
||||
comp.set(floor(bound), ceil(bound), true, exponent);
|
||||
comp.setDouble(bound, bound);
|
||||
break;
|
||||
default:
|
||||
continue; // well, for neq we could have
|
||||
// [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges.
|
||||
@ -376,6 +372,34 @@ Range::intersect(const Range *lhs, const Range *rhs, bool *emptyRange)
|
||||
bool newFractional = lhs->canHaveFractionalPart_ && rhs->canHaveFractionalPart_;
|
||||
uint16_t newExponent = Min(lhs->max_exponent_, rhs->max_exponent_);
|
||||
|
||||
// NaN is a special value which is neither greater than infinity or less than
|
||||
// negative infinity. When we intersect two ranges like [?, 0] and [0, ?], we
|
||||
// can end up thinking we have both a lower and upper bound, even though NaN
|
||||
// is still possible. In this case, just be conservative, since any case where
|
||||
// we can have NaN is not especially interesting.
|
||||
if (newHasInt32LowerBound && newHasInt32UpperBound && newExponent == IncludesInfinityAndNaN)
|
||||
return nullptr;
|
||||
|
||||
// If one of the ranges has a fractional part and the other doesn't, it's
|
||||
// possible that we will have computed a newExponent that's more precise
|
||||
// than our newLower and newUpper. This is unusual, so we handle it here
|
||||
// instead of in optimize().
|
||||
//
|
||||
// For example, when the floating-point range has an actual maximum value
|
||||
// of 1.5, it may have a range like [0,2] and the max_exponent may be zero.
|
||||
// When intersecting such a range with an integer range, the fractional part
|
||||
// of the range is dropped, but the max exponent of 0 remains valid.
|
||||
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_ &&
|
||||
newExponent < MaxInt32Exponent)
|
||||
{
|
||||
// pow(2, newExponent+1)-1 to compute the maximum value for newExponent.
|
||||
int32_t limit = (uint32_t(1) << (newExponent + 1)) - 1;
|
||||
if (limit != INT32_MIN) {
|
||||
newUpper = Min(newUpper, limit);
|
||||
newLower = Max(newLower, -limit);
|
||||
}
|
||||
}
|
||||
|
||||
return new Range(newLower, newHasInt32LowerBound, newUpper, newHasInt32UpperBound,
|
||||
newFractional, newExponent);
|
||||
}
|
||||
@ -399,22 +423,102 @@ Range::Range(const MDefinition *def)
|
||||
: symbolicLower_(nullptr),
|
||||
symbolicUpper_(nullptr)
|
||||
{
|
||||
const Range *other = def->range();
|
||||
if (!other) {
|
||||
if (def->type() == MIRType_Int32)
|
||||
if (const Range *other = def->range()) {
|
||||
// The instruction has range information; use it.
|
||||
*this = *other;
|
||||
|
||||
// Simulate the effect of converting the value to its type.
|
||||
switch (def->type()) {
|
||||
case MIRType_Int32:
|
||||
wrapAroundToInt32();
|
||||
break;
|
||||
case MIRType_Boolean:
|
||||
wrapAroundToBoolean();
|
||||
break;
|
||||
case MIRType_None:
|
||||
MOZ_ASSUME_UNREACHABLE("Asking for the range of an instruction with no value");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Otherwise just use type information. We can trust the type here
|
||||
// because we don't care what value the instruction actually produces,
|
||||
// but what value we might get after we get past the bailouts.
|
||||
switch (def->type()) {
|
||||
case MIRType_Int32:
|
||||
setInt32(JSVAL_INT_MIN, JSVAL_INT_MAX);
|
||||
else if (def->type() == MIRType_Boolean)
|
||||
break;
|
||||
case MIRType_Boolean:
|
||||
setInt32(0, 1);
|
||||
else
|
||||
break;
|
||||
case MIRType_None:
|
||||
MOZ_ASSUME_UNREACHABLE("Asking for the range of an instruction with no value");
|
||||
default:
|
||||
setUnknown();
|
||||
symbolicLower_ = symbolicUpper_ = nullptr;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(def->type() == MIRType_Boolean, other->isBoolean());
|
||||
// As a special case, MUrsh is permitted to claim a result type of
|
||||
// MIRType_Int32 while actually returning values in [0,UINT32_MAX] without
|
||||
// bailouts. If range analysis hasn't ruled out values in
|
||||
// (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for
|
||||
// use as either a uint32 or an int32.
|
||||
if (!hasInt32UpperBound() && def->isUrsh() && def->toUrsh()->bailoutsDisabled())
|
||||
lower_ = INT32_MIN;
|
||||
|
||||
*this = *other;
|
||||
symbolicLower_ = symbolicUpper_ = nullptr;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ExponentImpliedByDouble(double d)
|
||||
{
|
||||
// Handle the special values.
|
||||
if (IsNaN(d))
|
||||
return Range::IncludesInfinityAndNaN;
|
||||
if (IsInfinite(d))
|
||||
return Range::IncludesInfinity;
|
||||
|
||||
// Otherwise take the exponent part and clamp it at zero, since the Range
|
||||
// class doesn't track fractional ranges.
|
||||
return uint16_t(Max(int_fast16_t(0), ExponentComponent(d)));
|
||||
}
|
||||
|
||||
void
|
||||
Range::setDouble(double l, double h)
|
||||
{
|
||||
// Infer lower_, upper_, hasInt32LowerBound_, and hasInt32UpperBound_.
|
||||
if (l >= INT32_MIN && l <= INT32_MAX) {
|
||||
lower_ = int32_t(floor(l));
|
||||
hasInt32LowerBound_ = true;
|
||||
} else {
|
||||
lower_ = INT32_MIN;
|
||||
hasInt32LowerBound_ = false;
|
||||
}
|
||||
if (h >= INT32_MIN && h <= INT32_MAX) {
|
||||
upper_ = int32_t(ceil(h));
|
||||
hasInt32UpperBound_ = true;
|
||||
} else {
|
||||
upper_ = INT32_MAX;
|
||||
hasInt32UpperBound_ = false;
|
||||
}
|
||||
|
||||
// Infer max_exponent_.
|
||||
uint16_t lExp = ExponentImpliedByDouble(l);
|
||||
uint16_t hExp = ExponentImpliedByDouble(h);
|
||||
max_exponent_ = Max(lExp, hExp);
|
||||
|
||||
// Infer the canHaveFractionalPart_ field. We can have a fractional part
|
||||
// if the range crosses through the neighborhood of zero. We won't have a
|
||||
// fractional value if the value is always beyond the point at which
|
||||
// double precision can't represent fractional values.
|
||||
uint16_t minExp = Min(lExp, hExp);
|
||||
bool includesNegative = IsNaN(l) || l < 0;
|
||||
bool includesPositive = IsNaN(h) || h > 0;
|
||||
bool crossesZero = includesNegative && includesPositive;
|
||||
canHaveFractionalPart_ = crossesZero || minExp < MaxTruncatableExponent;
|
||||
|
||||
optimize();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -759,7 +863,7 @@ Range::min(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (lhs->canBeNaN() || rhs->canBeNaN())
|
||||
return new Range();
|
||||
return nullptr;
|
||||
|
||||
return new Range(Min(lhs->lower_, rhs->lower_),
|
||||
lhs->hasInt32LowerBound_ && rhs->hasInt32LowerBound_,
|
||||
@ -774,7 +878,7 @@ Range::max(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (lhs->canBeNaN() || rhs->canBeNaN())
|
||||
return new Range();
|
||||
return nullptr;
|
||||
|
||||
return new Range(Max(lhs->lower_, rhs->lower_),
|
||||
lhs->hasInt32LowerBound_ || rhs->hasInt32LowerBound_,
|
||||
@ -837,17 +941,17 @@ MPhi::computeRange()
|
||||
if (isOSRLikeValue(getOperand(i)))
|
||||
continue;
|
||||
|
||||
Range *input = getOperand(i)->range();
|
||||
// Peek at the pre-bailout range so we can take a short-cut; if any of
|
||||
// the operands has an unknown range, this phi has an unknown range.
|
||||
if (!getOperand(i)->range())
|
||||
return;
|
||||
|
||||
if (!input) {
|
||||
range = nullptr;
|
||||
break;
|
||||
}
|
||||
Range input(getOperand(i));
|
||||
|
||||
if (range)
|
||||
range->unionWith(input);
|
||||
range->unionWith(&input);
|
||||
else
|
||||
range = new Range(*input);
|
||||
range = new Range(input);
|
||||
}
|
||||
|
||||
setRange(range);
|
||||
@ -858,7 +962,8 @@ MBeta::computeRange()
|
||||
{
|
||||
bool emptyRange = false;
|
||||
|
||||
Range *range = Range::intersect(getOperand(0)->range(), comparison_, &emptyRange);
|
||||
Range opRange(getOperand(0));
|
||||
Range *range = Range::intersect(&opRange, comparison_, &emptyRange);
|
||||
if (emptyRange) {
|
||||
IonSpew(IonSpew_Range, "Marking block for inst %d unexitable", id());
|
||||
block()->setEarlyAbort();
|
||||
@ -870,68 +975,9 @@ MBeta::computeRange()
|
||||
void
|
||||
MConstant::computeRange()
|
||||
{
|
||||
if (type() == MIRType_Int32) {
|
||||
setRange(Range::NewSingleValueRange(value().toInt32()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (type() != MIRType_Double)
|
||||
return;
|
||||
|
||||
double d = value().toDouble();
|
||||
|
||||
// NaN is not handled by range analysis.
|
||||
if (IsNaN(d))
|
||||
return;
|
||||
|
||||
// Beyond-int32 values are used to set both lower and upper to the range boundaries.
|
||||
if (IsInfinite(d)) {
|
||||
if (IsNegative(d))
|
||||
setRange(Range::NewDoubleRange(Range::NoInt32LowerBound,
|
||||
Range::NoInt32LowerBound,
|
||||
Range::IncludesInfinity));
|
||||
else
|
||||
setRange(Range::NewDoubleRange(Range::NoInt32UpperBound,
|
||||
Range::NoInt32UpperBound,
|
||||
Range::IncludesInfinity));
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the exponent, to approximate it with the range analysis.
|
||||
int exp = ExponentComponent(d);
|
||||
if (exp < 0) {
|
||||
// This double only has a fractional part.
|
||||
if (IsNegative(d))
|
||||
setRange(Range::NewDoubleRange(-1, 0));
|
||||
else
|
||||
setRange(Range::NewDoubleRange(0, 1));
|
||||
} else if (exp < Range::MaxTruncatableExponent) {
|
||||
// Extract the integral part.
|
||||
int64_t integral = ToInt64(d);
|
||||
// Extract the fractional part.
|
||||
double rest = d - (double) integral;
|
||||
// Estimate the smallest integral boundaries.
|
||||
// Safe double comparisons, because there is no precision loss.
|
||||
int64_t l = integral - ((rest < 0) ? 1 : 0);
|
||||
int64_t h = integral + ((rest > 0) ? 1 : 0);
|
||||
// If we adjusted into a new exponent range, adjust exp accordingly.
|
||||
if ((rest < 0 && (l == INT64_MIN || IsPowerOfTwo(Abs(l)))) ||
|
||||
(rest > 0 && (h == INT64_MIN || IsPowerOfTwo(Abs(h)))))
|
||||
{
|
||||
++exp;
|
||||
}
|
||||
setRange(new Range(l, h, (rest != 0), exp));
|
||||
} else {
|
||||
// This double has a precision loss. This also mean that it cannot
|
||||
// encode any values with fractional parts.
|
||||
if (IsNegative(d))
|
||||
setRange(Range::NewDoubleRange(Range::NoInt32LowerBound,
|
||||
Range::NoInt32LowerBound,
|
||||
exp));
|
||||
else
|
||||
setRange(Range::NewDoubleRange(Range::NoInt32UpperBound,
|
||||
Range::NoInt32UpperBound,
|
||||
exp));
|
||||
if (value().isNumber()) {
|
||||
double d = value().toNumber();
|
||||
setRange(Range::NewDoubleRange(d, d));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1049,8 +1095,6 @@ MUrsh::computeRange()
|
||||
}
|
||||
|
||||
JS_ASSERT(range()->lower() >= 0);
|
||||
if (type() == MIRType_Int32 && !range()->hasInt32UpperBound())
|
||||
range()->extendUInt32ToInt32Min();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1060,10 +1104,10 @@ MAbs::computeRange()
|
||||
return;
|
||||
|
||||
Range other(getOperand(0));
|
||||
setRange(Range::abs(&other));
|
||||
|
||||
Range *next = Range::abs(&other);
|
||||
if (implicitTruncate_)
|
||||
range()->wrapAroundToInt32();
|
||||
next->wrapAroundToInt32();
|
||||
setRange(next);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1085,10 +1129,9 @@ MAdd::computeRange()
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
Range *next = Range::add(&left, &right);
|
||||
setRange(next);
|
||||
|
||||
if (isTruncated())
|
||||
range()->wrapAroundToInt32();
|
||||
next->wrapAroundToInt32();
|
||||
setRange(next);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1099,10 +1142,9 @@ MSub::computeRange()
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
Range *next = Range::sub(&left, &right);
|
||||
setRange(next);
|
||||
|
||||
if (isTruncated())
|
||||
range()->wrapAroundToInt32();
|
||||
next->wrapAroundToInt32();
|
||||
setRange(next);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1114,11 +1156,11 @@ MMul::computeRange()
|
||||
Range right(getOperand(1));
|
||||
if (canBeNegativeZero())
|
||||
canBeNegativeZero_ = Range::negativeZeroMul(&left, &right);
|
||||
setRange(Range::mul(&left, &right));
|
||||
|
||||
Range *next = Range::mul(&left, &right);
|
||||
// Truncated multiplications could overflow in both directions
|
||||
if (isTruncated())
|
||||
range()->wrapAroundToInt32();
|
||||
next->wrapAroundToInt32();
|
||||
setRange(next);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1265,34 +1307,34 @@ static Range *GetTypedArrayRange(int type)
|
||||
void
|
||||
MLoadTypedArrayElement::computeRange()
|
||||
{
|
||||
if (Range *range = GetTypedArrayRange(arrayType())) {
|
||||
if (type() == MIRType_Int32 && !range->hasInt32UpperBound())
|
||||
range->extendUInt32ToInt32Min();
|
||||
setRange(range);
|
||||
}
|
||||
// We have an Int32 type and if this is a UInt32 load it may produce a value
|
||||
// outside of our range, but we have a bailout to handle those cases.
|
||||
setRange(GetTypedArrayRange(arrayType()));
|
||||
}
|
||||
|
||||
void
|
||||
MLoadTypedArrayElementStatic::computeRange()
|
||||
{
|
||||
if (Range *range = GetTypedArrayRange(typedArray_->type()))
|
||||
setRange(range);
|
||||
// We don't currently use MLoadTypedArrayElementStatic for uint32, so we
|
||||
// don't have to worry about it returning a value outside our type.
|
||||
JS_ASSERT(typedArray_->type() != ScalarTypeRepresentation::TYPE_UINT32);
|
||||
|
||||
setRange(GetTypedArrayRange(typedArray_->type()));
|
||||
}
|
||||
|
||||
void
|
||||
MArrayLength::computeRange()
|
||||
{
|
||||
Range *r = Range::NewUInt32Range(0, UINT32_MAX);
|
||||
r->extendUInt32ToInt32Min();
|
||||
setRange(r);
|
||||
// Array lengths can go up to UINT32_MAX, but we only create MArrayLength
|
||||
// nodes when the value is known to be int32 (see the
|
||||
// OBJECT_FLAG_LENGTH_OVERFLOW flag).
|
||||
setRange(Range::NewUInt32Range(0, INT32_MAX));
|
||||
}
|
||||
|
||||
void
|
||||
MInitializedLength::computeRange()
|
||||
{
|
||||
Range *r = Range::NewUInt32Range(0, UINT32_MAX);
|
||||
r->extendUInt32ToInt32Min();
|
||||
setRange(r);
|
||||
setRange(Range::NewUInt32Range(0, JSObject::NELEMENTS_LIMIT));
|
||||
}
|
||||
|
||||
void
|
||||
@ -1845,14 +1887,25 @@ RangeAnalysis::addRangeAssertions()
|
||||
for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
|
||||
MInstruction *ins = *iter;
|
||||
|
||||
if (ins->type() == MIRType_None)
|
||||
// Perform range checking for all numeric and numeric-like types.
|
||||
if (!IsNumberType(ins->type()) &&
|
||||
ins->type() != MIRType_Boolean &&
|
||||
ins->type() != MIRType_Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Range r(ins);
|
||||
|
||||
// Don't insert assertions if there's nothing interesting to assert.
|
||||
if (r.isUnknown() || (ins->type() == MIRType_Int32 && r.isUnknownInt32()))
|
||||
continue;
|
||||
|
||||
Range *r = ins->range();
|
||||
if (!r)
|
||||
// Range-checking PassArgs breaks stuff.
|
||||
if (ins->isPassArg())
|
||||
continue;
|
||||
|
||||
MAssertRange *guard = MAssertRange::New(ins, new Range(*r));
|
||||
MAssertRange *guard = MAssertRange::New(ins, new Range(r));
|
||||
|
||||
// The code that removes beta nodes assumes that it can find them
|
||||
// in a contiguous run at the top of each block. Don't insert
|
||||
@ -1990,22 +2043,13 @@ MDiv::truncate()
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncated(true);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
|
||||
unsigned_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ASSERT(specialization() != MIRType_Int32); // fixme
|
||||
|
||||
// No modifications.
|
||||
return false;
|
||||
}
|
||||
@ -2156,7 +2200,7 @@ static void
|
||||
RemoveTruncatesOnOutput(MInstruction *truncated)
|
||||
{
|
||||
JS_ASSERT(truncated->type() == MIRType_Int32);
|
||||
JS_ASSERT_IF(truncated->range(), truncated->range()->isInt32());
|
||||
JS_ASSERT(Range(truncated).isInt32());
|
||||
|
||||
for (MUseDefIterator use(truncated); use; use++) {
|
||||
MDefinition *def = use.def();
|
||||
@ -2226,7 +2270,9 @@ RangeAnalysis::truncate()
|
||||
}
|
||||
|
||||
// Set truncated flag if range analysis ensure that it has no
|
||||
// rounding errors and no fractional part.
|
||||
// rounding errors and no fractional part. Note that we can't use
|
||||
// the MDefinition Range constructor, because we need to know if
|
||||
// the value will have rounding errors before any bailout checks.
|
||||
const Range *r = iter->range();
|
||||
bool canHaveRoundingErrors = !r || r->canHaveRoundingErrors();
|
||||
|
||||
@ -2299,25 +2345,27 @@ RangeAnalysis::truncate()
|
||||
void
|
||||
MInArray::collectRangeInfo()
|
||||
{
|
||||
needsNegativeIntCheck_ = !index()->range() || !index()->range()->isFiniteNonNegative();
|
||||
Range indexRange(index());
|
||||
needsNegativeIntCheck_ = !indexRange.isFiniteNonNegative();
|
||||
}
|
||||
|
||||
void
|
||||
MLoadElementHole::collectRangeInfo()
|
||||
{
|
||||
needsNegativeIntCheck_ = !index()->range() || !index()->range()->isFiniteNonNegative();
|
||||
Range indexRange(index());
|
||||
needsNegativeIntCheck_ = !indexRange.isFiniteNonNegative();
|
||||
}
|
||||
|
||||
void
|
||||
MMod::collectRangeInfo()
|
||||
{
|
||||
canBeNegativeDividend_ = !lhs()->range() || !lhs()->range()->isFiniteNonNegative();
|
||||
Range lhsRange(lhs());
|
||||
canBeNegativeDividend_ = !lhsRange.isFiniteNonNegative();
|
||||
}
|
||||
|
||||
void
|
||||
MBoundsCheckLower::collectRangeInfo()
|
||||
{
|
||||
fallible_ = !index()->range() ||
|
||||
!index()->range()->hasInt32LowerBound() ||
|
||||
index()->range()->lower() < minimum_;
|
||||
Range indexRange(index());
|
||||
fallible_ = !indexRange.hasInt32LowerBound() || indexRange.lower() < minimum_;
|
||||
}
|
||||
|
@ -176,15 +176,34 @@ class Range : public TempObject {
|
||||
// This function simply makes several JS_ASSERTs to verify the internal
|
||||
// consistency of this range.
|
||||
void assertInvariants() const {
|
||||
// Basic sanity :).
|
||||
JS_ASSERT(lower_ <= upper_);
|
||||
|
||||
// When hasInt32LowerBound_ or hasInt32UpperBound_ are false, we set
|
||||
// lower_ and upper_ to these specific values as it simplifies the
|
||||
// implementation in some places.
|
||||
JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN);
|
||||
JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX);
|
||||
JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_, max_exponent_ >= MaxInt32Exponent);
|
||||
|
||||
// max_exponent_ must be one of three possible things.
|
||||
JS_ASSERT(max_exponent_ <= MaxFiniteExponent ||
|
||||
max_exponent_ == IncludesInfinity ||
|
||||
max_exponent_ == IncludesInfinityAndNaN);
|
||||
JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(upper_)));
|
||||
JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(lower_)));
|
||||
|
||||
// Forbid the max_exponent_ field from implying better bounds for
|
||||
// lower_/upper_ fields. We have to add 1 to the max_exponent_ when
|
||||
// canHaveFractionalPart_ is true in order to accomodate fractional
|
||||
// offsets. For example, 2147483647.9 is greater than INT32_MAX, so a
|
||||
// range containing that value will have hasInt32UpperBound_ set to
|
||||
// false, however that value also has exponent 30, which is strictly
|
||||
// less than MaxInt32Exponent. For another example, 1.9 has an exponent
|
||||
// of 0 but requires upper_ to be at least 2, which has exponent 1.
|
||||
JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_,
|
||||
max_exponent_ + canHaveFractionalPart_ >= MaxInt32Exponent);
|
||||
JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
|
||||
mozilla::FloorLog2(mozilla::Abs(upper_)));
|
||||
JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
|
||||
mozilla::FloorLog2(mozilla::Abs(lower_)));
|
||||
|
||||
// The following are essentially static assertions, but FloorLog2 isn't
|
||||
// trivially suitable for constexpr :(.
|
||||
@ -307,6 +326,9 @@ class Range : public TempObject {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
// Construct a range from the given MDefinition. This differs from the
|
||||
// MDefinition's range() method in that it describes the range of values
|
||||
// *after* any bailout checks.
|
||||
Range(const MDefinition *def);
|
||||
|
||||
static Range *NewInt32Range(int32_t l, int32_t h) {
|
||||
@ -319,12 +341,13 @@ class Range : public TempObject {
|
||||
return new Range(l, h, false, MaxUInt32Exponent);
|
||||
}
|
||||
|
||||
static Range *NewDoubleRange(int64_t l, int64_t h, uint16_t e = IncludesInfinityAndNaN) {
|
||||
return new Range(l, h, true, e);
|
||||
}
|
||||
static Range *NewDoubleRange(double l, double h) {
|
||||
if (mozilla::IsNaN(l) && mozilla::IsNaN(h))
|
||||
return nullptr;
|
||||
|
||||
static Range *NewSingleValueRange(int64_t v) {
|
||||
return new Range(v, v, false, IncludesInfinityAndNaN);
|
||||
Range *r = new Range();
|
||||
r->setDouble(l, h);
|
||||
return r;
|
||||
}
|
||||
|
||||
void print(Sprinter &sp) const;
|
||||
@ -356,6 +379,17 @@ class Range : public TempObject {
|
||||
|
||||
static bool negativeZeroMul(const Range *lhs, const Range *rhs);
|
||||
|
||||
bool isUnknownInt32() const {
|
||||
return isInt32() && lower() == INT32_MIN && upper() == INT32_MAX;
|
||||
}
|
||||
|
||||
bool isUnknown() const {
|
||||
return !hasInt32LowerBound_ &&
|
||||
!hasInt32UpperBound_ &&
|
||||
canHaveFractionalPart_ &&
|
||||
max_exponent_ == IncludesInfinityAndNaN;
|
||||
}
|
||||
|
||||
bool hasInt32LowerBound() const {
|
||||
return hasInt32LowerBound_;
|
||||
}
|
||||
@ -471,12 +505,11 @@ class Range : public TempObject {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
void setUnknown() {
|
||||
setDouble(NoInt32LowerBound, NoInt32UpperBound);
|
||||
}
|
||||
void setDouble(double l, double h);
|
||||
|
||||
void setDouble(int64_t l, int64_t h, uint16_t e = IncludesInfinityAndNaN) {
|
||||
set(l, h, true, e);
|
||||
void setUnknown() {
|
||||
set(NoInt32LowerBound, NoInt32UpperBound, true, IncludesInfinityAndNaN);
|
||||
JS_ASSERT(isUnknown());
|
||||
}
|
||||
|
||||
void set(int64_t l, int64_t h, bool f, uint16_t e) {
|
||||
@ -503,14 +536,6 @@ class Range : public TempObject {
|
||||
// it to the [0, 1] range. Otherwise do nothing.
|
||||
void wrapAroundToBoolean();
|
||||
|
||||
// As we lack support of MIRType_UInt32, we need to work around the int32
|
||||
// representation by doing an overflow while keeping the upper infinity to
|
||||
// repesent the fact that the value might reach bigger numbers.
|
||||
void extendUInt32ToInt32Min() {
|
||||
JS_ASSERT(!hasInt32UpperBound());
|
||||
lower_ = JSVAL_INT_MIN;
|
||||
}
|
||||
|
||||
const SymbolicBound *symbolicLower() const {
|
||||
return symbolicLower_;
|
||||
}
|
||||
|
@ -907,7 +907,7 @@ CodeGeneratorARM::visitShiftI(LShiftI *ins)
|
||||
} else {
|
||||
// x >>> 0 can overflow.
|
||||
masm.ma_mov(lhs, dest);
|
||||
if (ins->mir()->toUrsh()->canOverflow()) {
|
||||
if (ins->mir()->toUrsh()->fallible()) {
|
||||
masm.ma_cmp(dest, Imm32(0));
|
||||
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
|
||||
return false;
|
||||
@ -932,7 +932,7 @@ CodeGeneratorARM::visitShiftI(LShiftI *ins)
|
||||
break;
|
||||
case JSOP_URSH:
|
||||
masm.ma_lsr(dest, lhs, dest);
|
||||
if (ins->mir()->toUrsh()->canOverflow()) {
|
||||
if (ins->mir()->toUrsh()->fallible()) {
|
||||
// x >>> 0 can overflow.
|
||||
masm.ma_cmp(dest, Imm32(0));
|
||||
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
|
||||
|
@ -1104,7 +1104,7 @@ CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
|
||||
case JSOP_URSH:
|
||||
if (shift) {
|
||||
masm.shrl(Imm32(shift), lhs);
|
||||
} else if (ins->mir()->toUrsh()->canOverflow()) {
|
||||
} else if (ins->mir()->toUrsh()->fallible()) {
|
||||
// x >>> 0 can overflow.
|
||||
masm.testl(lhs, lhs);
|
||||
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
|
||||
@ -1125,7 +1125,7 @@ CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
|
||||
break;
|
||||
case JSOP_URSH:
|
||||
masm.shrl_cl(lhs);
|
||||
if (ins->mir()->toUrsh()->canOverflow()) {
|
||||
if (ins->mir()->toUrsh()->fallible()) {
|
||||
// x >>> 0 can overflow.
|
||||
masm.testl(lhs, lhs);
|
||||
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
|
||||
|
@ -1122,8 +1122,8 @@ static size_t
|
||||
ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind)
|
||||
{
|
||||
size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, zone->runtimeFromMainThread()->gcAllocationThreshold);
|
||||
float trigger = float(base) * zone->gcHeapGrowthFactor;
|
||||
return size_t(Min(float(maxBytes), trigger));
|
||||
double trigger = double(base) * zone->gcHeapGrowthFactor;
|
||||
return size_t(Min(double(maxBytes), trigger));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -409,6 +409,7 @@ class ForkJoinShared : public TaskExecutor, public Monitor
|
||||
|
||||
JSRuntime *runtime() { return cx_->runtime(); }
|
||||
JS::Zone *zone() { return cx_->zone(); }
|
||||
JSCompartment *compartment() { return cx_->compartment(); }
|
||||
|
||||
JSContext *acquireContext() { PR_Lock(cxLock_); return cx_; }
|
||||
void releaseContext() { PR_Unlock(cxLock_); }
|
||||
@ -1689,6 +1690,13 @@ ForkJoinSlice::ForkJoinSlice(PerThreadData *perThreadData,
|
||||
* trigger GCs and is otherwise not thread-safe to access.
|
||||
*/
|
||||
zone_ = shared->zone();
|
||||
|
||||
/*
|
||||
* Unsafely set the compartment. This is used to get read-only access to
|
||||
* shared tables.
|
||||
*/
|
||||
compartment_ = shared->compartment();
|
||||
|
||||
allocator_ = allocator;
|
||||
}
|
||||
|
||||
|
@ -458,6 +458,13 @@ class MozbuildObject(ProcessExecutionMixin):
|
||||
return fn(**params)
|
||||
|
||||
def _make_path(self, force_pymake=False):
|
||||
if self._is_windows() and not force_pymake:
|
||||
# Use mozmake if it's available.
|
||||
try:
|
||||
return [which.which('mozmake')]
|
||||
except which.WhichError:
|
||||
pass
|
||||
|
||||
if self._is_windows() or force_pymake:
|
||||
make_py = os.path.join(self.topsrcdir, 'build', 'pymake',
|
||||
'make.py').replace(os.sep, '/')
|
||||
|
@ -129,10 +129,6 @@ DEFAULT_GMAKE_FLAGS += NSPR_LIB_DIR=$(NSPR_LIB_DIR)
|
||||
DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1
|
||||
DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1
|
||||
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
|
||||
DEFAULT_GMAKE_FLAGS += NSINSTALL="$(NSINSTALL)"
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DEFAULT_GMAKE_FLAGS += INSTALL="$(NSINSTALL) -t"
|
||||
endif
|
||||
ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_1)
|
||||
DEFAULT_GMAKE_FLAGS += OS_DLLFLAGS="-static-libgcc"
|
||||
endif
|
||||
@ -147,14 +143,16 @@ endif
|
||||
ifdef NSS_DISABLE_DBM
|
||||
DEFAULT_GMAKE_FLAGS += NSS_DISABLE_DBM=1
|
||||
endif
|
||||
ABS_topsrcdir := $(shell cd $(topsrcdir); pwd)
|
||||
ifeq ($(HOST_OS_ARCH),WINNT)
|
||||
ifdef .PYMAKE
|
||||
ABS_topsrcdir := $(shell cd $(topsrcdir); pwd -W)
|
||||
endif
|
||||
else
|
||||
ABS_topsrcdir := $(shell cd $(topsrcdir); pwd)
|
||||
endif
|
||||
# Hack to force NSS build system to use "normal" object directories
|
||||
DEFAULT_GMAKE_FLAGS += BUILD='$(MOZ_BUILD_ROOT)/security/$$(subst $(ABS_topsrcdir)/security/,,$$(CURDIR))'
|
||||
DEFAULT_GMAKE_FLAGS += ABS_topsrcdir='$(ABS_topsrcdir)'
|
||||
# ABS_topsrcdir can't be expanded here because msys path mangling likes to break
|
||||
# paths in that case.
|
||||
DEFAULT_GMAKE_FLAGS += BUILD='$(MOZ_BUILD_ROOT)/security/$$(subst $$(ABS_topsrcdir)/security/,,$$(CURDIR))'
|
||||
DEFAULT_GMAKE_FLAGS += BUILD_TREE='$$(BUILD)' OBJDIR='$$(BUILD)' DEPENDENCIES='$$(BUILD)/.deps' SINGLE_SHLIB_DIR='$$(BUILD)'
|
||||
DEFAULT_GMAKE_FLAGS += SOURCE_XP_DIR=$(ABS_DIST)
|
||||
ifndef MOZ_DEBUG
|
||||
@ -450,6 +448,16 @@ libs-nss/lib/freebl: $(DIST)/lib/$(IMPORT_PREFIX)nssutil3$(IMPORT_SUFFIX) $(NSPR
|
||||
$(addprefix libs-,$(NSS_STATIC_DIRS)): DEFAULT_GMAKE_FLAGS += SHARED_LIBRARY= IMPORT_LIBRARY=
|
||||
endif # MOZ_FOLD_LIBS
|
||||
|
||||
ifeq ($(NSINSTALL_PY),$(NSINSTALL))
|
||||
DEFAULT_GMAKE_FLAGS += PYTHON='$(PYTHON)'
|
||||
DEFAULT_GMAKE_FLAGS += NSINSTALL_PY='$(call core_abspath,$(topsrcdir)/config/nsinstall.py)'
|
||||
DEFAULT_GMAKE_FLAGS += NSINSTALL='$$(PYTHON) $$(NSINSTALL_PY)'
|
||||
else
|
||||
DEFAULT_GMAKE_FLAGS += NSINSTALL='$(NSINSTALL)'
|
||||
endif
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DEFAULT_GMAKE_FLAGS += INSTALL='$$(NSINSTALL) -t'
|
||||
endif
|
||||
DEFAULT_GMAKE_FLAGS += $(EXTRA_GMAKE_FLAGS)
|
||||
|
||||
$(addprefix libs-,$(NSS_DIRS)): libs-%:
|
||||
|
@ -5,7 +5,10 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
@ -13,69 +16,104 @@ from mach.decorators import (
|
||||
Command,
|
||||
)
|
||||
|
||||
MARIONETTE_DISABLED = '''
|
||||
The %s command requires a Marionette-enabled build.
|
||||
|
||||
Add 'ENABLE_MARIONETTE=1' to your mozconfig file and re-build the application.
|
||||
Your currently active mozconfig is %s.
|
||||
'''.lstrip()
|
||||
|
||||
MARIONETTE_DISABLED_B2G = '''
|
||||
The %s command requires a Marionette-enabled build.
|
||||
|
||||
Please create an engineering build, which has Marionette enabled. You can do
|
||||
this by ommitting the VARIANT variable when building, or using:
|
||||
|
||||
VARIANT=eng ./build.sh
|
||||
'''
|
||||
|
||||
def run_marionette(tests, b2g_path=None, emulator=None, testtype=None,
|
||||
address=None, bin=None, topsrcdir=None):
|
||||
from marionette.runtests import (
|
||||
MarionetteTestRunner,
|
||||
MarionetteTestOptions,
|
||||
startTestRunner
|
||||
)
|
||||
|
||||
parser = MarionetteTestOptions()
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if not tests:
|
||||
tests = [os.path.join(topsrcdir,
|
||||
'testing/marionette/client/marionette/tests/unit-tests.ini')]
|
||||
|
||||
options.type = testtype
|
||||
if b2g_path:
|
||||
options.homedir = b2g_path
|
||||
if emulator:
|
||||
options.emulator = emulator
|
||||
else:
|
||||
options.bin = bin
|
||||
path, exe = os.path.split(options.bin)
|
||||
if 'b2g' in exe:
|
||||
options.app = 'b2gdesktop'
|
||||
|
||||
options.address = address
|
||||
|
||||
parser.verify_usage(options, tests)
|
||||
|
||||
runner = startTestRunner(MarionetteTestRunner, options, tests)
|
||||
if runner.failed > 0:
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
@CommandProvider
|
||||
class B2GCommands(MachCommandBase):
|
||||
def __init__(self, context):
|
||||
MachCommandBase.__init__(self, context)
|
||||
|
||||
for attr in ('b2g_home', 'device_name'):
|
||||
setattr(self, attr, getattr(context, attr, None))
|
||||
@Command('marionette-webapi', category='testing',
|
||||
description='Run a Marionette webapi test',
|
||||
conditions=[conditions.is_b2g])
|
||||
@CommandArgument('--emulator', choices=['x86', 'arm'],
|
||||
help='Run an emulator of the specified architecture.')
|
||||
@CommandArgument('--type', dest='testtype',
|
||||
help='Test type, usually one of: browser, b2g, b2g-qemu.',
|
||||
default='b2g')
|
||||
@CommandArgument('tests', nargs='*', metavar='TESTS',
|
||||
help='Path to test(s) to run.')
|
||||
def run_marionette_webapi(self, tests, emulator=None, testtype=None):
|
||||
if not emulator and self.device_name in ('emulator', 'emulator-jb'):
|
||||
emulator='arm'
|
||||
|
||||
if self.substs.get('ENABLE_MARIONETTE') != '1':
|
||||
print(MARIONETTE_DISABLED_B2G % 'marionette-webapi')
|
||||
return 1
|
||||
|
||||
return run_marionette(tests, b2g_path=self.b2g_home, emulator=emulator,
|
||||
testtype=testtype, topsrcdir=self.topsrcdir, address=None)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command('marionette-test', category='testing',
|
||||
description='Run a Marionette test.')
|
||||
@CommandArgument('--homedir', dest='b2g_path',
|
||||
help='For B2G testing, the path to the B2G repo.')
|
||||
@CommandArgument('--emulator', choices=['x86', 'arm'],
|
||||
help='Run an emulator of the specified architecture.')
|
||||
description='Run a Marionette test.',
|
||||
conditions=[conditions.is_firefox])
|
||||
@CommandArgument('--address',
|
||||
help='host:port of running Gecko instance to connect to.')
|
||||
@CommandArgument('--type', dest='testtype',
|
||||
help='Test type, usually one of: browser, b2g, b2g-qemu.')
|
||||
help='Test type, usually one of: browser, b2g, b2g-qemu.',
|
||||
default='browser')
|
||||
@CommandArgument('tests', nargs='*', metavar='TESTS',
|
||||
help='Path to test(s) to run.')
|
||||
def run_marionette(self, tests, emulator=None, address=None, b2g_path=None,
|
||||
testtype=None):
|
||||
from marionette.runtests import (
|
||||
MarionetteTestRunner,
|
||||
MarionetteTestOptions,
|
||||
startTestRunner
|
||||
)
|
||||
|
||||
parser = MarionetteTestOptions()
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if not tests:
|
||||
tests = ['testing/marionette/client/marionette/tests/unit-tests.ini']
|
||||
|
||||
options.type = testtype
|
||||
if emulator:
|
||||
if b2g_path:
|
||||
options.homedir = b2g_path
|
||||
if not testtype:
|
||||
options.type = "b2g"
|
||||
else:
|
||||
if not testtype:
|
||||
options.type = "browser"
|
||||
try:
|
||||
bin = self.get_binary_path('app')
|
||||
options.bin = bin
|
||||
except Exception as e:
|
||||
print("It looks like your program isn't built.",
|
||||
"You can run |mach build| to build it.")
|
||||
print(e)
|
||||
return 1
|
||||
path, exe = os.path.split(options.bin)
|
||||
if 'b2g' in exe:
|
||||
options.app = 'b2gdesktop'
|
||||
|
||||
if not emulator:
|
||||
if self.substs.get('ENABLE_MARIONETTE') != '1':
|
||||
print("Marionette doesn't appear to be enabled; please "
|
||||
"add ENABLE_MARIONETTE=1 to your mozconfig and "
|
||||
"perform a clobber build.")
|
||||
return 1
|
||||
|
||||
options.address = address
|
||||
|
||||
parser.verify_usage(options, tests)
|
||||
|
||||
runner = startTestRunner(MarionetteTestRunner, options, tests)
|
||||
if runner.failed > 0:
|
||||
def run_marionette_test(self, tests, address=None, testtype=None):
|
||||
if self.substs.get('ENABLE_MARIONETTE') != '1':
|
||||
print(MARIONETTE_DISABLED % ('marionette-test',
|
||||
self.mozconfig['path']))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
return run_marionette(tests, bin=bin, testtype=testtype,
|
||||
topsrcdir=self.topsrcdir, address=address)
|
||||
|
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 122 B |
Before Width: | Height: | Size: 124 B After Width: | Height: | Size: 116 B |
@ -7,10 +7,6 @@ ac_add_options --enable-application=xulrunner
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-tests
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
|
||||
. $topsrcdir/build/win32/mozconfig.vs2010-win64
|
||||
else
|
||||
|
@ -10,8 +10,4 @@ ac_add_options --enable-application=xulrunner
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-tests
|
||||
|
||||
if test -z "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
. "$topsrcdir/xulrunner/config/mozconfigs/common.override"
|
||||
|