author | Ryan VanderMeulen <ryanvm@gmail.com> |
Tue, 25 Nov 2014 16:57:18 -0500 | |
changeset 217489 | ced1402861b8e0d0c59b42ba379281bd3a80926b |
parent 217488 | bca4892bbe036cbb5f46aa136f4eb12b5147e2fd (current diff) |
parent 217413 | 997d1d16fc19878c0a370d972e2353184b59c09b (diff) |
child 217490 | b98e55fb98b798bea3fdd0390baba720db2836f3 |
child 217682 | 05c138a502c2841c718b3263fcba7c80fe151049 |
child 217708 | 48e460577514322a0d6875230a75464bbec37fcb |
push id | 52290 |
push user | ryanvm@gmail.com |
push date | Tue, 25 Nov 2014 21:57:44 +0000 |
treeherder | mozilla-inbound@ced1402861b8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 36.0a1 |
first release with | nightly linux32
ced1402861b8
/
36.0a1
/
20141126030207
/
files
nightly linux64
ced1402861b8
/
36.0a1
/
20141126030207
/
files
nightly mac
ced1402861b8
/
36.0a1
/
20141126030207
/
files
nightly win32
ced1402861b8
/
36.0a1
/
20141126030207
/
files
nightly win64
ced1402861b8
/
36.0a1
/
20141126030207
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
36.0a1
/
20141126030207
/
pushlog to previous
nightly linux64
36.0a1
/
20141126030207
/
pushlog to previous
nightly mac
36.0a1
/
20141126030207
/
pushlog to previous
nightly win32
36.0a1
/
20141126030207
/
pushlog to previous
nightly win64
36.0a1
/
20141126030207
/
pushlog to previous
|
--- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -356,39 +356,79 @@ nsImageLoadingContent::SetLoadingEnabled NS_IMETHODIMP nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus) { NS_PRECONDITION(aStatus, "Null out param"); *aStatus = ImageBlockingStatus(); return NS_OK; } +static void +ReplayImageStatus(imgIRequest* aRequest, imgINotificationObserver* aObserver) +{ + if (!aRequest) { + return; + } + + uint32_t status = 0; + nsresult rv = aRequest->GetImageStatus(&status); + if (NS_FAILED(rv)) { + return; + } + + if (status & imgIRequest::STATUS_SIZE_AVAILABLE) { + aObserver->Notify(aRequest, imgINotificationObserver::SIZE_AVAILABLE, nullptr); + } + if (status & imgIRequest::STATUS_FRAME_COMPLETE) { + aObserver->Notify(aRequest, imgINotificationObserver::FRAME_COMPLETE, nullptr); + } + if (status & imgIRequest::STATUS_HAS_TRANSPARENCY) { + aObserver->Notify(aRequest, imgINotificationObserver::HAS_TRANSPARENCY, nullptr); + } + if (status & imgIRequest::STATUS_IS_ANIMATED) { + aObserver->Notify(aRequest, imgINotificationObserver::IS_ANIMATED, nullptr); + } + if (status & imgIRequest::STATUS_DECODE_COMPLETE) { + aObserver->Notify(aRequest, imgINotificationObserver::DECODE_COMPLETE, nullptr); + } + if (status & imgIRequest::STATUS_LOAD_COMPLETE) { + aObserver->Notify(aRequest, imgINotificationObserver::LOAD_COMPLETE, nullptr); + } +} + NS_IMETHODIMP nsImageLoadingContent::AddObserver(imgINotificationObserver* aObserver) { NS_ENSURE_ARG_POINTER(aObserver); if (!mObserverList.mObserver) { + // Don't touch the linking of the list! mObserverList.mObserver = aObserver; - // Don't touch the linking of the list! + + ReplayImageStatus(mCurrentRequest, aObserver); + ReplayImageStatus(mPendingRequest, aObserver); + return NS_OK; } // otherwise we have to create a new entry ImageObserver* observer = &mObserverList; while (observer->mNext) { observer = observer->mNext; } observer->mNext = new ImageObserver(aObserver); if (! observer->mNext) { return NS_ERROR_OUT_OF_MEMORY; } + ReplayImageStatus(mCurrentRequest, aObserver); + ReplayImageStatus(mPendingRequest, aObserver); + return NS_OK; } NS_IMETHODIMP nsImageLoadingContent::RemoveObserver(imgINotificationObserver* aObserver) { NS_ENSURE_ARG_POINTER(aObserver);
--- a/gfx/layers/LayersLogging.cpp +++ b/gfx/layers/LayersLogging.cpp @@ -103,16 +103,33 @@ AppendToString(std::stringstream& aStrea aStream << pfx; aStream << nsPrintfCString( "(x=%d, y=%d, w=%d, h=%d)", r.x, r.y, r.width, r.height).get(); aStream << sfx; } void +AppendToString(std::stringstream& aStream, const nsRegion& r, + const char* pfx, const char* sfx) +{ + aStream << pfx; + + nsRegionRectIterator it(r); + aStream << "< "; + while (const nsRect* sr = it.Next()) { + AppendToString(aStream, *sr); + aStream << "; "; + } + aStream << ">"; + + aStream << sfx; +} + +void AppendToString(std::stringstream& aStream, const nsIntRegion& r, const char* pfx, const char* sfx) { aStream << pfx; nsIntRegionRectIterator it(r); aStream << "< "; while (const nsIntRect* sr = it.Next()) {
--- a/gfx/layers/LayersLogging.h +++ b/gfx/layers/LayersLogging.h @@ -8,17 +8,17 @@ #include "FrameMetrics.h" // for FrameMetrics, etc #include "GraphicsFilter.h" // for GraphicsFilter #include "mozilla/gfx/Point.h" // for IntSize, etc #include "mozilla/gfx/Types.h" // for Filter, SurfaceFormat #include "mozilla/layers/CompositorTypes.h" // for TextureFlags #include "nsAString.h" #include "nsPrintfCString.h" // for nsPrintfCString -#include "nsRegion.h" // for nsIntRegion +#include "nsRegion.h" // for nsRegion, nsIntRegion #include "nscore.h" // for nsACString, etc struct gfxRGBA; struct nsIntPoint; struct nsIntRect; struct nsIntSize; namespace mozilla { @@ -89,16 +89,20 @@ AppendToString(std::stringstream& aStrea aStream << pfx; aStream << nsPrintfCString( "(x=%d, y=%d, w=%d, h=%d)", r.x, r.y, r.width, r.height).get(); aStream << sfx; } void +AppendToString(std::stringstream& aStream, const nsRegion& r, + const char* pfx="", const char* sfx=""); + +void AppendToString(std::stringstream& aStream, const nsIntRegion& r, const char* pfx="", const char* sfx=""); void AppendToString(std::stringstream& aStream, const EventRegions& e, const char* pfx="", const char* sfx=""); void
--- a/gfx/layers/apz/src/InputQueue.cpp +++ b/gfx/layers/apz/src/InputQueue.cpp @@ -4,16 +4,17 @@ * 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 "InputQueue.h" #include "AsyncPanZoomController.h" #include "gfxPrefs.h" #include "InputBlockState.h" +#include "LayersLogging.h" #include "OverscrollHandoffState.h" #define INPQ_LOG(...) // #define INPQ_LOG(...) printf_stderr("INPQ: " __VA_ARGS__) namespace mozilla { namespace layers {
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -202,23 +202,21 @@ CompositableParentManager::ReceiveCompos case CompositableOperation::TOpUseTexture: { const OpUseTexture& op = aEdit.get_OpUseTexture(); CompositableHost* compositable = AsCompositable(op); RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent()); MOZ_ASSERT(tex.get()); compositable->UseTextureHost(tex); - if (IsAsync()) { + if (IsAsync() && compositable->GetLayer()) { ScheduleComposition(op); // Async layer updates don't trigger invalidation, manually tell the layer // that its content have changed. - if (compositable->GetLayer()) { - compositable->GetLayer()->SetInvalidRectToVisibleRegion(); - } + compositable->GetLayer()->SetInvalidRectToVisibleRegion(); } break; } case CompositableOperation::TOpUseComponentAlphaTextures: { const OpUseComponentAlphaTextures& op = aEdit.get_OpUseComponentAlphaTextures(); CompositableHost* compositable = AsCompositable(op); RefPtr<TextureHost> texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent()); RefPtr<TextureHost> texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent());
--- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -823,16 +823,28 @@ nsGIFDecoder2::WriteInternal(const char* mGIFStruct.is_transparent = *q & 0x1; mGIFStruct.tpixel = q[3]; mGIFStruct.disposal_method = ((*q) >> 2) & 0x7; // Some specs say 3rd bit (value 4), other specs say value 3 // Let's choose 3 (the more popular) if (mGIFStruct.disposal_method == 4) { mGIFStruct.disposal_method = 3; } + + { + int32_t method = + FrameBlender::FrameDisposalMethod(mGIFStruct.disposal_method); + if (method == FrameBlender::kDisposeClearAll || + method == FrameBlender::kDisposeClear) { + // We may have to display the background under this image during + // animation playback, so we regard it as transparent. + PostHasTransparency(); + } + } + mGIFStruct.delay_time = GETINT16(q + 1) * 10; GETN(1, gif_consume_block); break; case gif_comment_extension: if (*q) { GETN(*q, gif_consume_comment); } else {
--- a/image/decoders/nsIconDecoder.cpp +++ b/image/decoders/nsIconDecoder.cpp @@ -54,16 +54,19 @@ nsIconDecoder::WriteInternal(const char* case iconStateHaveHeight: // Grab the Height mHeight = (uint8_t)*aBuffer; // Post our size to the superclass PostSize(mWidth, mHeight); + + PostHasTransparency(); + if (HasError()) { // Setting the size led to an error. mState = iconStateFinished; return; } // If We're doing a size decode, we're done if (IsSizeDecode()) {
--- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -150,19 +150,27 @@ void nsPNGDecoder::CreateFrame(png_uint_ if (format == gfx::SurfaceFormat::B8G8R8A8) { PostHasTransparency(); } // Our first full frame is automatically created by the image decoding // infrastructure. Just use it as long as it matches up. nsIntRect neededRect(x_offset, y_offset, width, height); nsRefPtr<imgFrame> currentFrame = GetCurrentFrame(); - if (mNumFrames != 0 || !currentFrame->GetRect().IsEqualEdges(neededRect)) { + if (!currentFrame->GetRect().IsEqualEdges(neededRect)) { + if (mNumFrames == 0) { + // We need padding on the first frame, which means that we don't draw into + // part of the image at all. Report that as transparency. + PostHasTransparency(); + } + NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format); - } else if (mNumFrames == 0) { + } else if (mNumFrames != 0) { + NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format); + } else { // Our preallocated frame matches up, with the possible exception of alpha. if (format == gfx::SurfaceFormat::B8G8R8X8) { currentFrame->SetHasNoAlpha(); } } mFrameRect = neededRect; mFrameHasNoAlpha = true; @@ -171,16 +179,22 @@ void nsPNGDecoder::CreateFrame(png_uint_ ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created " "image frame with %dx%d pixels in container %p", width, height, &mImage)); #ifdef PNG_APNG_SUPPORTED if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) { mAnimInfo = AnimFrameInfo(mPNG, mInfo); + + if (mAnimInfo.mDispose == FrameBlender::kDisposeClear) { + // We may have to display the background under this image during + // animation playback, so we regard it as transparent. + PostHasTransparency(); + } } #endif } // set timeout and frame disposal method for the current frame void nsPNGDecoder::EndImageFrame() {
--- a/image/public/imgIContainer.idl +++ b/image/public/imgIContainer.idl @@ -64,17 +64,17 @@ native nsIntSizeByVal(nsIntSize); /** * imgIContainer is the interface that represents an image. It allows * access to frames as Thebes surfaces. It also allows drawing of images * onto Thebes contexts. * * Internally, imgIContainer also manages animation of images. */ -[scriptable, builtinclass, uuid(f8bb7671-5f36-490b-b828-3f4c6ad38665)] +[scriptable, builtinclass, uuid(14ea6fa5-183e-4409-ac88-110bd2e05292)] interface imgIContainer : nsISupports { /** * The width of the container rectangle. In the case of any error, * zero is returned, and an exception will be thrown. */ readonly attribute int32_t width; @@ -210,22 +210,19 @@ interface imgIContainer : nsISupports * * @param aWhichFrame Frame specifier of the FRAME_* variety. * @param aFlags Flags of the FLAG_* variety */ [noscript, notxpcom] TempRefSourceSurface getFrame(in uint32_t aWhichFrame, in uint32_t aFlags); /** - * Whether the given frame is opaque; that is, needs the background painted - * behind it. - * - * @param aWhichFrame Frame specifier of the FRAME_* variety. + * Whether this image is opaque (i.e., needs a background painted behind it). */ - [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); + [notxpcom] boolean isOpaque(); /** * Attempts to create an ImageContainer (and Image) containing the current * frame. Only valid for RASTER type images. */ [noscript] ImageContainer getImageContainer(in LayerManager aManager); /**
--- a/image/public/imgIRequest.idl +++ b/image/public/imgIRequest.idl @@ -14,17 +14,17 @@ interface nsIPrincipal; /** * imgIRequest interface * * @author Stuart Parmenter <stuart@mozilla.com> * @version 0.1 * @see imagelib2 */ -[scriptable, builtinclass, uuid(dc61f0ea-4139-4c2a-ae69-cec82d33e089)] +[scriptable, builtinclass, uuid(83a7708b-5c35-409f-bab3-7fc08be6a264)] interface imgIRequest : nsIRequest { /** * the image container... * @return the image object associated with the request. * @attention NEED DOCS */ readonly attribute imgIContainer image; @@ -49,25 +49,31 @@ interface imgIRequest : nsIRequest * * STATUS_DECODE_STARTED: The decoding process has begun, but not yet * finished. * * STATUS_FRAME_COMPLETE: The first frame has been * completely decoded. * * STATUS_DECODE_COMPLETE: The whole image has been decoded. + * + * STATUS_IS_ANIMATED: The image is animated. + * + * STATUS_HAS_TRANSPARENCY: The image is partially or completely transparent. */ //@{ const long STATUS_NONE = 0x0; const long STATUS_SIZE_AVAILABLE = 0x1; const long STATUS_LOAD_COMPLETE = 0x2; const long STATUS_ERROR = 0x4; const long STATUS_DECODE_STARTED = 0x8; const long STATUS_FRAME_COMPLETE = 0x10; const long STATUS_DECODE_COMPLETE = 0x20; + const long STATUS_IS_ANIMATED = 0x40; + const long STATUS_HAS_TRANSPARENCY = 0x80; //@} /** * Status flags of the STATUS_* variety. */ readonly attribute unsigned long imageStatus; /*
--- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -210,16 +210,25 @@ protected: // Called by decoders when they determine the size of the image. Informs // the image of its size and sends notifications. void PostSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation = Orientation()); // Called by decoders if they determine that the image has transparency. + // + // This should be fired as early as possible to allow observers to do things + // that affect content, so it's necessarily pessimistic - if there's a + // possibility that the image has transparency, for example because its header + // specifies that it has an alpha channel, we fire PostHasTransparency + // immediately. PostFrameStop's aFrameAlpha argument, on the other hand, is + // only used internally to ImageLib. Because PostFrameStop isn't delivered + // until the entire frame has been decoded, decoders may take into account the + // actual contents of the frame and give a more accurate result. void PostHasTransparency(); // Called by decoders when they begin a frame. Informs the image, sends // notifications, and does internal book-keeping. void PostFrameStart(); // Called by decoders when they end a frame. Informs the image, sends // notifications, and does internal book-keeping.
--- a/image/src/DynamicImage.cpp +++ b/image/src/DynamicImage.cpp @@ -223,17 +223,17 @@ DynamicImage::GetFrame(uint32_t aWhichFr aWhichFrame, GraphicsFilter::FILTER_NEAREST, Nothing(), aFlags); NS_ENSURE_SUCCESS(rv, nullptr); return dt->Snapshot(); } NS_IMETHODIMP_(bool) -DynamicImage::FrameIsOpaque(uint32_t aWhichFrame) +DynamicImage::IsOpaque() { // XXX(seth): For performance reasons it'd be better to return true here, but // I'm not sure how we can guarantee it for an arbitrary gfxDrawable. return false; } NS_IMETHODIMP DynamicImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
--- a/image/src/FrozenImage.cpp +++ b/image/src/FrozenImage.cpp @@ -45,22 +45,16 @@ FrozenImage::GetAnimated(bool* aAnimated NS_IMETHODIMP_(TemporaryRef<SourceSurface>) FrozenImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) { return InnerImage()->GetFrame(FRAME_FIRST, aFlags); } -NS_IMETHODIMP_(bool) -FrozenImage::FrameIsOpaque(uint32_t aWhichFrame) -{ - return InnerImage()->FrameIsOpaque(FRAME_FIRST); -} - NS_IMETHODIMP FrozenImage::GetImageContainer(layers::LayerManager* aManager, layers::ImageContainer** _retval) { // XXX(seth): GetImageContainer does not currently support anything but the // current frame. We work around this by always returning null, but if it ever // turns out that FrozenImage is widely used on codepaths that can actually // benefit from GetImageContainer, it would be a good idea to fix that method
--- a/image/src/FrozenImage.h +++ b/image/src/FrozenImage.h @@ -33,17 +33,16 @@ public: virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE; virtual void IncrementAnimationConsumers() MOZ_OVERRIDE; virtual void DecrementAnimationConsumers() MOZ_OVERRIDE; NS_IMETHOD GetAnimated(bool* aAnimated) MOZ_OVERRIDE; NS_IMETHOD_(TemporaryRef<SourceSurface>) GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE; - NS_IMETHOD_(bool) FrameIsOpaque(uint32_t aWhichFrame) MOZ_OVERRIDE; NS_IMETHOD GetImageContainer(layers::LayerManager* aManager, layers::ImageContainer** _retval) MOZ_OVERRIDE; NS_IMETHOD Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, GraphicsFilter aFilter, const Maybe<SVGImageContext>& aSVGContext,
--- a/image/src/ImageWrapper.cpp +++ b/image/src/ImageWrapper.cpp @@ -204,19 +204,19 @@ ImageWrapper::GetAnimated(bool* aAnimate NS_IMETHODIMP_(TemporaryRef<SourceSurface>) ImageWrapper::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) { return mInnerImage->GetFrame(aWhichFrame, aFlags); } NS_IMETHODIMP_(bool) -ImageWrapper::FrameIsOpaque(uint32_t aWhichFrame) +ImageWrapper::IsOpaque() { - return mInnerImage->FrameIsOpaque(aWhichFrame); + return mInnerImage->IsOpaque(); } NS_IMETHODIMP ImageWrapper::GetImageContainer(LayerManager* aManager, ImageContainer** _retval) { return mInnerImage->GetImageContainer(aManager, _retval); }
--- a/image/src/OrientedImage.cpp +++ b/image/src/OrientedImage.cpp @@ -107,17 +107,17 @@ OrientedImage::GetFrame(uint32_t aWhichF gfxIntSize size; rv = InnerImage()->GetWidth(&size.width); NS_ENSURE_SUCCESS(rv, nullptr); rv = InnerImage()->GetHeight(&size.height); NS_ENSURE_SUCCESS(rv, nullptr); // Determine an appropriate format for the surface. gfx::SurfaceFormat surfaceFormat; - if (InnerImage()->FrameIsOpaque(aWhichFrame)) { + if (InnerImage()->IsOpaque()) { surfaceFormat = gfx::SurfaceFormat::B8G8R8X8; } else { surfaceFormat = gfx::SurfaceFormat::B8G8R8A8; } // Create a surface to draw into. RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->
--- a/image/src/ProgressTracker.cpp +++ b/image/src/ProgressTracker.cpp @@ -74,17 +74,16 @@ CheckProgressConsistency(Progress aProgr FLAG_IS_MULTIPART | FLAG_HAS_ERROR)); } if (aProgress & FLAG_IS_ANIMATED) { MOZ_ASSERT(aProgress & FLAG_DECODE_STARTED); MOZ_ASSERT(aProgress & FLAG_SIZE_AVAILABLE); } if (aProgress & FLAG_HAS_TRANSPARENCY) { - MOZ_ASSERT(aProgress & FLAG_DECODE_STARTED); MOZ_ASSERT(aProgress & FLAG_SIZE_AVAILABLE); } if (aProgress & FLAG_IS_MULTIPART) { // No preconditions. } if (aProgress & FLAG_LAST_PART_COMPLETE) { MOZ_ASSERT(aProgress & FLAG_LOAD_COMPLETE); } @@ -148,16 +147,22 @@ ProgressTracker::GetImageStatus() const status |= imgIRequest::STATUS_DECODE_COMPLETE; } if (mProgress & FLAG_FRAME_COMPLETE) { status |= imgIRequest::STATUS_FRAME_COMPLETE; } if (mProgress & FLAG_LOAD_COMPLETE) { status |= imgIRequest::STATUS_LOAD_COMPLETE; } + if (mProgress & FLAG_IS_ANIMATED) { + status |= imgIRequest::STATUS_IS_ANIMATED; + } + if (mProgress & FLAG_HAS_TRANSPARENCY) { + status |= imgIRequest::STATUS_HAS_TRANSPARENCY; + } if (mProgress & FLAG_HAS_ERROR) { status |= imgIRequest::STATUS_ERROR; } return status; } // A helper class to allow us to call SyncNotify asynchronously.
--- a/image/src/ProgressTracker.h +++ b/image/src/ProgressTracker.h @@ -29,18 +29,18 @@ class Image; enum { FLAG_SIZE_AVAILABLE = 1u << 0, // STATUS_SIZE_AVAILABLE FLAG_DECODE_STARTED = 1u << 1, // STATUS_DECODE_STARTED FLAG_DECODE_COMPLETE = 1u << 2, // STATUS_DECODE_COMPLETE FLAG_FRAME_COMPLETE = 1u << 3, // STATUS_FRAME_COMPLETE FLAG_LOAD_COMPLETE = 1u << 4, // STATUS_LOAD_COMPLETE FLAG_ONLOAD_BLOCKED = 1u << 5, FLAG_ONLOAD_UNBLOCKED = 1u << 6, - FLAG_IS_ANIMATED = 1u << 7, - FLAG_HAS_TRANSPARENCY = 1u << 8, + FLAG_IS_ANIMATED = 1u << 7, // STATUS_IS_ANIMATED + FLAG_HAS_TRANSPARENCY = 1u << 8, // STATUS_HAS_TRANSPARENCY FLAG_IS_MULTIPART = 1u << 9, FLAG_LAST_PART_COMPLETE = 1u << 10, FLAG_HAS_ERROR = 1u << 11 // STATUS_ERROR }; typedef uint32_t Progress; const uint32_t NoProgress = 0; @@ -96,16 +96,19 @@ public: // Returns whether we are in the process of loading; that is, whether we have // not received OnStopRequest from Necko. bool IsLoading() const; // Get the current image status (as in imgIRequest). uint32_t GetImageStatus() const; + // Get the current Progress. + Progress GetProgress() const { return mProgress; } + // Schedule an asynchronous "replaying" of all the notifications that would // have to happen to put us in the current state. // We will also take note of any notifications that happen between the time // Notify() is called and when we call SyncNotify on |proxy|, and replay them // as well. // Should be called on the main thread only, since imgRequestProxy and GetURI // are not threadsafe. void Notify(imgRequestProxy* proxy);
--- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -649,43 +649,32 @@ RasterImage::GetFirstFrameRect() if (mAnim) { return mAnim->GetFirstFrameRefreshArea(); } // Fall back to our size. This is implicitly zero-size if !mHasSize. return nsIntRect(nsIntPoint(0,0), mSize); } -//****************************************************************************** -/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */ NS_IMETHODIMP_(bool) -RasterImage::FrameIsOpaque(uint32_t aWhichFrame) +RasterImage::IsOpaque() { - if (aWhichFrame > FRAME_MAX_VALUE) { - NS_WARNING("aWhichFrame outside valid range!"); + if (mError) { return false; } - if (mError) + Progress progress = mProgressTracker->GetProgress(); + + // If we haven't yet finished decoding, the safe answer is "not opaque". + if (!(progress & FLAG_DECODE_COMPLETE)) { return false; - - // See if we can get an image frame. - nsRefPtr<imgFrame> frame = - LookupFrameNoDecode(GetRequestedFrameIndex(aWhichFrame)); - - // If we don't get a frame, the safe answer is "not opaque". - if (!frame) - return false; - - // Other, the frame is transparent if either: - // 1. It needs a background. - // 2. Its size doesn't cover our entire area. - nsIntRect framerect = frame->GetRect(); - return !frame->GetNeedsBackground() && - framerect.IsEqualInterior(nsIntRect(0, 0, mSize.width, mSize.height)); + } + + // Other, we're opaque if FLAG_HAS_TRANSPARENCY is not set. + return !(progress & FLAG_HAS_TRANSPARENCY); } nsIntRect RasterImage::FrameRect(uint32_t aWhichFrame) { if (aWhichFrame > FRAME_MAX_VALUE) { NS_WARNING("aWhichFrame outside valid range!"); return nsIntRect(); @@ -762,17 +751,17 @@ RasterImage::CopyFrame(uint32_t aWhichFr bool aShouldSyncNotify /* = true */) { if (aWhichFrame > FRAME_MAX_VALUE) return nullptr; if (mError) return nullptr; - if (!ApplyDecodeFlags(aFlags, aWhichFrame)) + if (!ApplyDecodeFlags(aFlags)) return nullptr; // Get the frame. If it's not there, it's probably the caller's fault for // not waiting for the data to be loaded from the network or not passing // FLAG_SYNC_DECODE DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame), aFlags, aShouldSyncNotify); if (!frameRef) { @@ -839,17 +828,17 @@ RasterImage::GetFrameInternal(uint32_t a MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE); if (aWhichFrame > FRAME_MAX_VALUE) return nullptr; if (mError) return nullptr; - if (!ApplyDecodeFlags(aFlags, aWhichFrame)) + if (!ApplyDecodeFlags(aFlags)) return nullptr; // Get the frame. If it's not there, it's probably the caller's fault for // not waiting for the data to be loaded from the network or not passing // FLAG_SYNC_DECODE DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame), aFlags, aShouldSyncNotify); if (!frameRef) { @@ -1115,30 +1104,30 @@ RasterImage::InternalAddFrame(uint32_t f rv = InternalAddFrameHelper(framenum, frame, imageData, imageLength, paletteData, paletteLength, aRetFrame); return rv; } bool -RasterImage::ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame) +RasterImage::ApplyDecodeFlags(uint32_t aNewFlags) { if (mFrameDecodeFlags == (aNewFlags & DECODE_FLAGS_MASK)) return true; // Not asking very much of us here. if (mDecoded) { // If the requested frame is opaque and the current and new decode flags // only differ in the premultiply alpha bit then we can use the existing // frame, we don't need to discard and re-decode. uint32_t currentNonAlphaFlags = (mFrameDecodeFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA; uint32_t newNonAlphaFlags = (aNewFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA; - if (currentNonAlphaFlags == newNonAlphaFlags && FrameIsOpaque(aWhichFrame)) { + if (currentNonAlphaFlags == newNonAlphaFlags && IsOpaque()) { return true; } // if we can't discard, then we're screwed; we have no way // to re-decode. Similarly if we aren't allowed to do a sync // decode. if (!(aNewFlags & FLAG_SYNC_DECODE)) return false; @@ -2532,18 +2521,17 @@ RasterImage::Draw(gfxContext* aContext, NS_ENSURE_ARG_POINTER(aContext); // We can only draw without discarding and redecoding in these cases: // * We have the default decode flags. // * We have exactly FLAG_DECODE_NO_PREMULTIPLY_ALPHA and the current frame // is opaque. bool haveDefaultFlags = (mFrameDecodeFlags == DECODE_FLAGS_DEFAULT); bool haveSafeAlphaFlags = - (mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) && - FrameIsOpaque(FRAME_CURRENT); + (mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) && IsOpaque(); if (!(haveDefaultFlags || haveSafeAlphaFlags)) { if (!CanForciblyDiscardAndRedecode()) return NS_ERROR_NOT_AVAILABLE; ForceDiscard(); mFrameDecodeFlags = DECODE_FLAGS_DEFAULT; }
--- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -333,17 +333,17 @@ private: nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth, uint8_t **imageData, uint32_t *imageLength, uint32_t **paletteData, uint32_t *paletteLength, imgFrame** aRetFrame); nsresult DoImageDataComplete(); - bool ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame); + bool ApplyDecodeFlags(uint32_t aNewFlags); already_AddRefed<layers::Image> GetCurrentImage(); void UpdateImageContainer(); enum RequestDecodeType { ASYNCHRONOUS, SYNCHRONOUS_NOTIFY, SYNCHRONOUS_NOTIFY_AND_SOME_DECODE
--- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -682,25 +682,19 @@ VectorImage::GetFirstFrameDelay() if (!mSVGDocumentWrapper->IsAnimated()) return -1; // We don't really have a frame delay, so just pretend that we constantly // need updates. return 0; } - -//****************************************************************************** -/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */ NS_IMETHODIMP_(bool) -VectorImage::FrameIsOpaque(uint32_t aWhichFrame) +VectorImage::IsOpaque() { - if (aWhichFrame > FRAME_MAX_VALUE) - NS_WARNING("aWhichFrame outside valid range!"); - return false; // In general, SVG content is not opaque. } //****************************************************************************** /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame, * in uint32_t aFlags; */ NS_IMETHODIMP_(TemporaryRef<SourceSurface>) VectorImage::GetFrame(uint32_t aWhichFrame,
--- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -579,22 +579,16 @@ imgFrame::GetStride() const return VolatileSurfaceStride(mSize, mFormat); } SurfaceFormat imgFrame::GetFormat() const { return mFormat; } -bool imgFrame::GetNeedsBackground() const -{ - // We need a background painted if we have alpha or we're incomplete. - return (mFormat == SurfaceFormat::B8G8R8A8 || !ImageComplete()); -} - uint32_t imgFrame::GetImageBytesPerRow() const { if (mVBuf) return mSize.width * BytesPerPixel(mFormat); if (mPaletteDepth) return mSize.width;
--- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -83,17 +83,16 @@ public: nsresult ImageUpdated(const nsIntRect &aUpdateRect); nsIntRect GetRect() const; IntSize GetSize() const { return mSize; } bool NeedsPadding() const { return mOffset != nsIntPoint(0, 0); } int32_t GetStride() const; SurfaceFormat GetFormat() const; - bool GetNeedsBackground() const; uint32_t GetImageBytesPerRow() const; uint32_t GetImageDataLength() const; bool GetIsPaletted() const; bool GetHasAlpha() const; void GetImageData(uint8_t **aData, uint32_t *length) const; uint8_t* GetImageData() const; void GetPaletteData(uint32_t **aPalette, uint32_t *length) const; uint32_t* GetPaletteData() const;
--- a/image/test/mochitest/animationPolling.js +++ b/image/test/mochitest/animationPolling.js @@ -75,17 +75,17 @@ function failTest() * chain tests together, so they are all finished exactly once. * @returns {AnimationTest} */ function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId, debugElementId, cleanId, srcAttr, xulTest, closeFunc) { // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); this.wereFailures = false; this.pollFreq = pollFreq; this.timeout = timeout; this.imageElementId = imageElementId; this.referenceElementId = referenceElementId; if (!document.getElementById(referenceElementId)) {
--- a/image/test/mochitest/imgutils.js +++ b/image/test/mochitest/imgutils.js @@ -1,14 +1,24 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ // Helper file for shared image functionality // // Note that this is use by tests elsewhere in the source tree. When in doubt, // check mxr before removing or changing functionality. +// Helper function to clear both the content and chrome image caches +function clearAllImageCaches() +{ + var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"] + .getService(SpecialPowers.Ci.imgITools); + var imageCache = tools.getImgCacheForDocument(window.document); + imageCache.clearCache(true); // true=chrome + imageCache.clearCache(false); // false=content +} + // Helper function to clear the image cache of content images function clearImageCache() { var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"] .getService(SpecialPowers.Ci.imgITools); var imageCache = tools.getImgCacheForDocument(window.document); imageCache.clearCache(false); // true=chrome, false=content }
--- a/image/test/mochitest/test_animSVGImage.html +++ b/image/test/mochitest/test_animSVGImage.html @@ -27,17 +27,17 @@ SimpleTest.waitForExplicitFinish(); const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes) const Cc = Components.classes; const Ci = Components.interfaces; const gImg = document.getElementsByTagName("img")[0]; var gMyDecoderObserver; // value will be set in main() var gReferenceSnapshot; // value will be set in takeReferenceSnapshot() -var gOnStopFrameCounter = 0; +var gPollCounter = 0; var gIsTestFinished = false; function takeReferenceSnapshot() { // Take a snapshot of the initial (essentially blank) page let blankSnapshot = snapshotWindow(window, false); // Show reference div, & take a snapshot @@ -49,57 +49,57 @@ function takeReferenceSnapshot() { // Re-hide reference div, and take another snapshot to be sure it's gone referenceDiv.style.display = "none"; let blankSnapshot2 = snapshotWindow(window, false); ok(compareSnapshots(blankSnapshot, blankSnapshot2, true)[0], "reference div should disappear when it becomes display:none"); } -function myOnStopFrame() { - gOnStopFrameCounter++; - ok(true, "myOnStopFrame called"); +function myPoll() { + gPollCounter++; + ok(true, "myPoll called"); let currentSnapshot = snapshotWindow(window, false); if (compareSnapshots(currentSnapshot, gReferenceSnapshot, true)[0]) { // SUCCESS! ok(true, "Animated image looks correct, " + - "at call #" + gOnStopFrameCounter + " to onStopFrame"); + "at call #" + gPollCounter + " to myPoll"); cleanUpAndFinish(); } else - setTimeout(myOnStopFrame, 1); + setTimeout(myPoll, 1); } function failTest() { ok(false, "timing out after " + FAILURE_TIMEOUT + "ms. " + "Animated image still doesn't look correct, " + - "after call #" + gOnStopFrameCounter + " to onStopFrame"); + "after call #" + gPollCounter + " to myPoll"); cleanUpAndFinish(); } function cleanUpAndFinish() { - // On the off chance that failTest and myOnStopFrame are triggered + // On the off chance that failTest and myPoll are triggered // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish. if (gIsTestFinished) { return; } SimpleTest.finish(); gIsTestFinished = true; } function main() { takeReferenceSnapshot(); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); - setTimeout(myOnStopFrame, 1); + setTimeout(myPoll, 1); - // kick off image-loading! myOnStopFrame handles the rest. + // kick off image-loading! myPoll handles the rest. gImg.setAttribute("src", "lime-anim-100x100.svg"); // In case something goes wrong, fail earlier than mochitest timeout, // and with more information. setTimeout(failTest, FAILURE_TIMEOUT); } window.onload = main;
--- a/image/test/mochitest/test_animSVGImage2.html +++ b/image/test/mochitest/test_animSVGImage2.html @@ -27,19 +27,18 @@ SimpleTest.waitForExplicitFinish(); const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes) const Cc = Components.classes; const Ci = Components.interfaces; const gImg = document.getElementsByTagName("img")[0]; var gMyDecoderObserver; // value will be set in main() var gReferenceSnapshot; // value will be set in takeReferenceSnapshot() -var gOnStopFrameCounter = 0; +var gOnFrameUpdateCounter = 0; var gIsTestFinished = false; -var gTimer = null; function takeReferenceSnapshot() { // Take a snapshot of the initial (essentially blank) page let blankSnapshot = snapshotWindow(window, false); // Show reference div, & take a snapshot let referenceDiv = document.getElementById("referenceDiv"); @@ -50,67 +49,70 @@ function takeReferenceSnapshot() { // Re-hide reference div, and take another snapshot to be sure it's gone referenceDiv.style.display = "none"; let blankSnapshot2 = snapshotWindow(window, false); ok(compareSnapshots(blankSnapshot, blankSnapshot2, true)[0], "reference div should disappear when it becomes display:none"); } -function myOnStopFrame(aRequest) { - gOnStopFrameCounter++; - ok(true, "myOnStopFrame called"); +function myOnFrameUpdate(aRequest) { + if (gIsTestFinished) { + return; + } + gOnFrameUpdateCounter++; + ok(true, "myOnFrameUpdate called"); let currentSnapshot = snapshotWindow(window, false); if (compareSnapshots(currentSnapshot, gReferenceSnapshot, true)[0]) { // SUCCESS! ok(true, "Animated image looks correct, " + - "at call #" + gOnStopFrameCounter + " to onStopFrame"); + "at call #" + gOnFrameUpdateCounter + " to myOnFrameUpdate"); cleanUpAndFinish(); } - if (!gTimer) - gTimer = setTimeout(function() { gTimer = null; myOnStopFrame(0, 0); }, 1000); } function failTest() { + if (gIsTestFinished) { + return; + } ok(false, "timing out after " + FAILURE_TIMEOUT + "ms. " + "Animated image still doesn't look correct, " + - "after call #" + gOnStopFrameCounter + " to onStopFrame"); + "after call #" + gOnFrameUpdateCounter + " to myOnFrameUpdate"); cleanUpAndFinish(); } function cleanUpAndFinish() { - clearTimeout(gTimer); - // On the off chance that failTest and myOnStopFrame are triggered + // On the off chance that failTest and myOnFrameUpdate are triggered // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish. if (gIsTestFinished) { return; } let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.removeObserver(gMyDecoderObserver); SimpleTest.finish(); gIsTestFinished = true; } function main() { takeReferenceSnapshot(); // Create, customize & attach decoder observer observer = new ImageDecoderObserverStub(); - observer.frameComplete = myOnStopFrame; + observer.frameUpdate = myOnFrameUpdate; gMyDecoderObserver = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) .createScriptedObserver(observer); let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.addObserver(gMyDecoderObserver); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); - // kick off image-loading! myOnStopFrame handles the rest. + // kick off image-loading! myOnFrameUpdate handles the rest. gImg.setAttribute("src", "lime-anim-100x100-2.svg"); // In case something goes wrong, fail earlier than mochitest timeout, // and with more information. setTimeout(failTest, FAILURE_TIMEOUT); } window.onload = main;
--- a/image/test/mochitest/test_has_transparency.html +++ b/image/test/mochitest/test_has_transparency.html @@ -22,16 +22,18 @@ https://bugzilla.mozilla.org/show_bug.cg SimpleTest.waitForExplicitFinish(); const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes) const Cc = Components.classes; const Ci = Components.interfaces; const gContent = document.getElementById("content"); +var gCanvas; +var gCanvasCtx; var gImg; var gMyDecoderObserver; var gIsTestFinished = false; var gFiles; var gCurrentFileIsTransparent = false; var gHasTransparencyWasCalled = false; function testFiles() { @@ -94,16 +96,21 @@ function onError() { loadNext(); } function onLoad() { if (gIsTestFinished) { return; } ok(true, "Should successfully load " + gImg.src); + + // Force decoding of the image. + SimpleTest.executeSoon(function() { + gCanvasCtx.drawImage(gImg, 0, 0); + }); } function failTest() { ok(false, "timing out after " + FAILURE_TIMEOUT + "ms. " + "currently displaying " + gImg.src); cleanUpAndFinish(); } @@ -114,33 +121,35 @@ function cleanUpAndFinish() { gIsTestFinished = true; let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.removeObserver(gMyDecoderObserver); SimpleTest.finish(); } function main() { gFiles = testFiles(); + gCanvas = document.createElement('canvas'); + gCanvasCtx = gCanvas.getContext('2d'); gImg = new Image(); gImg.onload = onLoad; gImg.onerror = onError; // Create, customize & attach decoder observer. observer = new ImageDecoderObserverStub(); observer.hasTransparency = onHasTransparency; observer.decodeComplete = onDecodeComplete; gMyDecoderObserver = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) .createScriptedObserver(observer); let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.addObserver(gMyDecoderObserver); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); // Load the first image. loadNext(); // In case something goes wrong, fail earlier than mochitest timeout, // and with more information. setTimeout(failTest, FAILURE_TIMEOUT); }
--- a/image/test/mochitest/test_removal_ondecode.html +++ b/image/test/mochitest/test_removal_ondecode.html @@ -104,17 +104,17 @@ function main() { gMyDecoderObserver = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) .createScriptedObserver(observer); let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.addObserver(gMyDecoderObserver); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); // kick off image-loading! myOnStopFrame handles the rest. gImg.setAttribute("src", gFiles.next()); // In case something goes wrong, fail earlier than mochitest timeout, // and with more information. setTimeout(failTest, FAILURE_TIMEOUT); }
--- a/image/test/mochitest/test_removal_onload.html +++ b/image/test/mochitest/test_removal_onload.html @@ -104,17 +104,17 @@ function main() { gMyDecoderObserver = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) .createScriptedObserver(observer); let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); imgLoadingContent.addObserver(gMyDecoderObserver); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); // kick off image-loading! myOnStopFrame handles the rest. gImg.setAttribute("src", gFiles.next()); // In case something goes wrong, fail earlier than mochitest timeout, // and with more information. setTimeout(failTest, FAILURE_TIMEOUT); }
--- a/image/test/mochitest/test_synchronized_animation.html +++ b/image/test/mochitest/test_synchronized_animation.html @@ -101,17 +101,17 @@ function main() { // Create and customize decoder observer var obs = new ImageDecoderObserverStub(); obs.frameUpdate = frameUpdate; gOuter = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools).createScriptedObserver(obs); // We want to test the cold loading behavior, so clear cache in case an // earlier test got our image in there already. - clearImageCache(); + clearAllImageCaches(); // These are two copies of the same image; hence, they have the same frame rate. gImg1.src = "animated1.gif"; gImg2.src = "animated2.gif"; // Wait for each image to load. gImg1.addEventListener('load', waitForLoadAndTest(gImg1)); gImg2.addEventListener('load', waitForLoadAndTest(gImg2));
--- a/ipc/chromium/src/chrome/common/ipc_message.cc +++ b/ipc/chromium/src/chrome/common/ipc_message.cc @@ -31,17 +31,17 @@ Message::Message() : Pickle(sizeof(Header)) { header()->routing = header()->type = header()->flags = 0; #if defined(OS_POSIX) header()->num_fds = 0; #endif #ifdef MOZ_TASK_TRACER header()->source_event_id = 0; header()->parent_task_id = 0; - header()->source_event_type = SourceEventType::UNKNOWN; + header()->source_event_type = SourceEventType::Unknown; #endif InitLoggingVariables(); } Message::Message(int32_t routing_id, msgid_t type, PriorityValue priority, MessageCompression compression, const char* const name) : Pickle(sizeof(Header)) { header()->routing = routing_id; @@ -56,17 +56,17 @@ Message::Message(int32_t routing_id, msg header()->interrupt_local_stack_depth = static_cast<uint32_t>(-1); header()->seqno = 0; #if defined(OS_MACOSX) header()->cookie = 0; #endif #ifdef MOZ_TASK_TRACER header()->source_event_id = 0; header()->parent_task_id = 0; - header()->source_event_type = SourceEventType::UNKNOWN; + header()->source_event_type = SourceEventType::Unknown; #endif InitLoggingVariables(name); } Message::Message(const char* data, int data_len) : Pickle(data, data_len) { InitLoggingVariables(); }
--- a/js/src/asmjs/AsmJSFrameIterator.cpp +++ b/js/src/asmjs/AsmJSFrameIterator.cpp @@ -74,17 +74,17 @@ AsmJSFrameIterator::settle() case AsmJSModule::CodeRange::Function: callsite_ = module_->lookupCallSite(returnAddress); MOZ_ASSERT(callsite_); break; case AsmJSModule::CodeRange::Entry: fp_ = nullptr; MOZ_ASSERT(done()); break; - case AsmJSModule::CodeRange::IonFFI: + case AsmJSModule::CodeRange::JitFFI: case AsmJSModule::CodeRange::SlowFFI: case AsmJSModule::CodeRange::Interrupt: case AsmJSModule::CodeRange::Inline: case AsmJSModule::CodeRange::Thunk: MOZ_CRASH("Should not encounter an exit during iteration"); } } @@ -453,17 +453,17 @@ AsmJSProfilingFrameIterator::initFromFP( callerFP_ = nullptr; break; case AsmJSModule::CodeRange::Function: fp = CallerFPFromFP(fp); callerPC_ = ReturnAddressFromFP(fp); callerFP_ = CallerFPFromFP(fp); AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, fp); break; - case AsmJSModule::CodeRange::IonFFI: + case AsmJSModule::CodeRange::JitFFI: case AsmJSModule::CodeRange::SlowFFI: case AsmJSModule::CodeRange::Interrupt: case AsmJSModule::CodeRange::Inline: case AsmJSModule::CodeRange::Thunk: MOZ_CRASH("Unexpected CodeRange kind"); } // Since, despite the above reasoning for skipping a frame, we do want FFI @@ -508,17 +508,17 @@ AsmJSProfilingFrameIterator::AsmJSProfil } // Note: fp may be null while entering and leaving the activation. uint8_t *fp = activation.fp(); const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(state.pc); switch (codeRange->kind()) { case AsmJSModule::CodeRange::Function: - case AsmJSModule::CodeRange::IonFFI: + case AsmJSModule::CodeRange::JitFFI: case AsmJSModule::CodeRange::SlowFFI: case AsmJSModule::CodeRange::Interrupt: case AsmJSModule::CodeRange::Thunk: { // While codeRange describes the *current* frame, the fp/pc state stored in // the iterator is the *caller's* frame. The reason for this is that the // activation.fp isn't always the AsmJSFrame for state.pc; during the // prologue/epilogue, activation.fp will point to the caller's frame. // Naively unwinding starting at activation.fp could thus lead to the @@ -610,17 +610,17 @@ AsmJSProfilingFrameIterator::operator++( switch (codeRange->kind()) { case AsmJSModule::CodeRange::Entry: MOZ_ASSERT(callerFP_ == nullptr); MOZ_ASSERT(callerPC_ != nullptr); callerPC_ = nullptr; break; case AsmJSModule::CodeRange::Function: - case AsmJSModule::CodeRange::IonFFI: + case AsmJSModule::CodeRange::JitFFI: case AsmJSModule::CodeRange::SlowFFI: case AsmJSModule::CodeRange::Interrupt: case AsmJSModule::CodeRange::Inline: case AsmJSModule::CodeRange::Thunk: stackAddress_ = callerFP_; callerPC_ = ReturnAddressFromFP(callerFP_); AssertMatchesCallSite(*module_, codeRange, callerPC_, CallerFPFromFP(callerFP_), callerFP_); callerFP_ = CallerFPFromFP(callerFP_); @@ -667,38 +667,38 @@ AsmJSProfilingFrameIterator::label() con { MOZ_ASSERT(!done()); // Use the same string for both time inside and under so that the two // entries will be coalesced by the profiler. // // NB: these labels are regexp-matched by // browser/devtools/profiler/cleopatra/js/parserWorker.js. - const char *ionFFIDescription = "fast FFI trampoline (in asm.js)"; + const char *jitFFIDescription = "fast FFI trampoline (in asm.js)"; const char *slowFFIDescription = "slow FFI trampoline (in asm.js)"; const char *interruptDescription = "interrupt due to out-of-bounds or long execution (in asm.js)"; switch (AsmJSExit::ExtractReasonKind(exitReason_)) { case AsmJSExit::Reason_None: break; - case AsmJSExit::Reason_IonFFI: - return ionFFIDescription; + case AsmJSExit::Reason_JitFFI: + return jitFFIDescription; case AsmJSExit::Reason_SlowFFI: return slowFFIDescription; case AsmJSExit::Reason_Interrupt: return interruptDescription; case AsmJSExit::Reason_Builtin: return BuiltinToName(AsmJSExit::ExtractBuiltinKind(exitReason_)); } auto codeRange = reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_); switch (codeRange->kind()) { case AsmJSModule::CodeRange::Function: return codeRange->functionProfilingLabel(*module_); case AsmJSModule::CodeRange::Entry: return "entry trampoline (in asm.js)"; - case AsmJSModule::CodeRange::IonFFI: return ionFFIDescription; + case AsmJSModule::CodeRange::JitFFI: return jitFFIDescription; case AsmJSModule::CodeRange::SlowFFI: return slowFFIDescription; case AsmJSModule::CodeRange::Interrupt: return interruptDescription; case AsmJSModule::CodeRange::Inline: return "inline stub (in asm.js)"; case AsmJSModule::CodeRange::Thunk: return BuiltinToName(codeRange->thunkTarget()); } MOZ_CRASH("Bad exit kind"); }
--- a/js/src/asmjs/AsmJSFrameIterator.h +++ b/js/src/asmjs/AsmJSFrameIterator.h @@ -64,17 +64,17 @@ namespace AsmJSExit { // List of reasons for execution leaving asm.js-generated code, stored in // AsmJSActivation. The initial and default state is AsmJSNoExit. If // AsmJSNoExit is observed when the pc isn't in asm.js code, execution must // have been interrupted asynchronously (viz., by a exception/signal // handler). enum ReasonKind { Reason_None, - Reason_IonFFI, + Reason_JitFFI, Reason_SlowFFI, Reason_Interrupt, Reason_Builtin }; // For Reason_Builtin, the list of builtins, so they can be displayed in the // profile call stack. enum BuiltinKind { @@ -101,17 +101,17 @@ namespace AsmJSExit Builtin_Limit }; // A Reason contains both a ReasonKind and (if Reason_Builtin) a // BuiltinKind. typedef uint32_t Reason; static const uint32_t None = Reason_None; - static const uint32_t IonFFI = Reason_IonFFI; + static const uint32_t JitFFI = Reason_JitFFI; static const uint32_t SlowFFI = Reason_SlowFFI; static const uint32_t Interrupt = Reason_Interrupt; static inline Reason Builtin(BuiltinKind builtin) { return uint16_t(Reason_Builtin) | (uint16_t(builtin) << 16); } static inline ReasonKind ExtractReasonKind(Reason reason) { return ReasonKind(uint16_t(reason)); }
--- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -100,21 +100,21 @@ AsmJSModule::~AsmJSModule() { MOZ_ASSERT(!interrupted_); scriptSource_->decref(); if (code_) { for (unsigned i = 0; i < numExits(); i++) { AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i); - if (!exitDatum.ionScript) + if (!exitDatum.baselineScript) continue; jit::DependentAsmJSModuleExit exit(this, i); - exitDatum.ionScript->removeDependentAsmJSModule(exit); + exitDatum.baselineScript->removeDependentAsmJSModule(exit); } DeallocateExecutableMemory(code_, pod.totalBytes_, AsmJSPageSize); } for (size_t i = 0; i < numFunctionCounts(); i++) js_delete(functionCounts(i)); @@ -496,69 +496,77 @@ CoerceInPlace_ToNumber(MutableHandleValu if (!ToNumber(cx, val, &dbl)) return false; val.set(DoubleValue(dbl)); return true; } static bool -TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex, +TryEnablingJit(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex, int32_t argc, Value *argv) { if (!fun->hasScript()) return true; - // Test if the function is Ion compiled + // Test if the function is JIT compiled. JSScript *script = fun->nonLazyScript(); - if (!script->hasIonScript()) + if (!script->hasBaselineScript()) { + MOZ_ASSERT(!script->hasIonScript()); return true; + } // Currently we can't rectify arguments. Therefore disabling if argc is too low. if (fun->nargs() > size_t(argc)) return true; - // Normally the types should correspond, since we just ran with those types, - // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only. + // Ensure the argument types are included in the argument TypeSets stored in + // the TypeScript. This is necessary for Ion, because the FFI exit will + // use the skip-arg-checks entry point. + // + // Note that the TypeScript is never discarded while the script has a + // BaselineScript, so if those checks hold now they must hold at least until + // the BaselineScript is discarded and when that happens the FFI exit is + // patched back. if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType())) return true; for (uint32_t i = 0; i < fun->nargs(); i++) { types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i); types::Type type = types::Type::DoubleType(); if (!argv[i].isDouble()) type = types::Type::PrimitiveType(argv[i].extractNonDoubleType()); if (!typeset->hasType(type)) return true; } // The exit may have become optimized while executing the FFI. if (module.exitIsOptimized(exitIndex)) return true; - IonScript *ionScript = script->ionScript(); - if (!ionScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex))) + BaselineScript *baselineScript = script->baselineScript(); + if (!baselineScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex))) return false; - module.optimizeExit(exitIndex, ionScript); + module.optimizeExit(exitIndex, baselineScript); return true; } static bool InvokeFromAsmJS(AsmJSActivation *activation, int32_t exitIndex, int32_t argc, Value *argv, MutableHandleValue rval) { JSContext *cx = activation->cx(); AsmJSModule &module = activation->module(); RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun); RootedValue fval(cx, ObjectValue(*fun)); if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval)) return false; - return TryEnablingIon(cx, module, fun, exitIndex, argc, argv); + return TryEnablingJit(cx, module, fun, exitIndex, argc, argv); } // Use an int32_t return type instead of bool since bool does not have a // specified width and the caller is assuming a word-sized return. static int32_t InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv) { AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); @@ -743,17 +751,17 @@ AsmJSModule::staticallyLink(ExclusiveCon } // Initialize global data segment for (size_t i = 0; i < exits_.length(); i++) { AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i); exitDatum.exit = interpExitTrampoline(exits_[i]); exitDatum.fun = nullptr; - exitDatum.ionScript = nullptr; + exitDatum.baselineScript = nullptr; } MOZ_ASSERT(isStaticallyLinked()); } #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) static inline size_t ViewTypeByteSize(AsmJSHeapAccess::ViewType vt) @@ -899,17 +907,17 @@ AsmJSModule::detachHeap(JSContext *cx) if (interrupted_) { JS_ReportError(cx, "attempt to detach from inside interrupt handler"); return false; } // Even if this->active(), to reach here, the activation must have called // out via an FFI stub. FFI stubs check if heapDatum() is null on reentry // and throw an exception if so. - MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_IonFFI || + MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_JitFFI || activation()->exitReason() == AsmJSExit::Reason_SlowFFI); restoreHeapToInitialState(maybeHeap_); MOZ_ASSERT(hasDetachedHeap()); return true; } @@ -1333,17 +1341,17 @@ AsmJSModule::CodeRange::CodeRange(Kind k : begin_(begin), profilingReturn_(profilingReturn), end_(end) { u.kind_ = kind; MOZ_ASSERT(begin_ < profilingReturn_); MOZ_ASSERT(profilingReturn_ < end_); - MOZ_ASSERT(u.kind_ == IonFFI || u.kind_ == SlowFFI || u.kind_ == Interrupt); + MOZ_ASSERT(u.kind_ == JitFFI || u.kind_ == SlowFFI || u.kind_ == Interrupt); } AsmJSModule::CodeRange::CodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin, uint32_t profilingReturn, uint32_t end) : begin_(begin), profilingReturn_(profilingReturn), end_(end) {
--- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -366,43 +366,43 @@ class AsmJSModule bool clone(ExclusiveContext *cx, Global *out) const; }; class Exit { unsigned ffiIndex_; unsigned globalDataOffset_; unsigned interpCodeOffset_; - unsigned ionCodeOffset_; + unsigned jitCodeOffset_; friend class AsmJSModule; public: Exit() {} Exit(unsigned ffiIndex, unsigned globalDataOffset) : ffiIndex_(ffiIndex), globalDataOffset_(globalDataOffset), - interpCodeOffset_(0), ionCodeOffset_(0) + interpCodeOffset_(0), jitCodeOffset_(0) {} unsigned ffiIndex() const { return ffiIndex_; } unsigned globalDataOffset() const { return globalDataOffset_; } void initInterpOffset(unsigned off) { MOZ_ASSERT(!interpCodeOffset_); interpCodeOffset_ = off; } - void initIonOffset(unsigned off) { - MOZ_ASSERT(!ionCodeOffset_); - ionCodeOffset_ = off; + void initJitOffset(unsigned off) { + MOZ_ASSERT(!jitCodeOffset_); + jitCodeOffset_ = off; } void updateOffsets(jit::MacroAssembler &masm) { interpCodeOffset_ = masm.actualOffset(interpCodeOffset_); - ionCodeOffset_ = masm.actualOffset(ionCodeOffset_); + jitCodeOffset_ = masm.actualOffset(jitCodeOffset_); } size_t serializedSize() const; uint8_t *serialize(uint8_t *cursor) const; const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); bool clone(ExclusiveContext *cx, Exit *out) const; }; @@ -414,17 +414,17 @@ class AsmJSModule typedef int32_t (*CodePtr)(EntryArg *args, uint8_t *global); // An Exit holds bookkeeping information about an exit; the ExitDatum // struct overlays the actual runtime data stored in the global data // section. struct ExitDatum { uint8_t *exit; - jit::IonScript *ionScript; + jit::BaselineScript *baselineScript; HeapPtrFunction fun; }; typedef Vector<AsmJSCoercion, 0, SystemAllocPolicy> ArgCoercionVector; enum ReturnType { Return_Int32, Return_Double, Return_Int32x4, Return_Float32x4, Return_Void }; class ExportedFunction @@ -553,29 +553,29 @@ class AsmJSModule uint16_t target_; } thunk; uint8_t kind_; } u; void setDeltas(uint32_t entry, uint32_t profilingJump, uint32_t profilingEpilogue); public: - enum Kind { Function, Entry, IonFFI, SlowFFI, Interrupt, Thunk, Inline }; + enum Kind { Function, Entry, JitFFI, SlowFFI, Interrupt, Thunk, Inline }; CodeRange() {} CodeRange(uint32_t nameIndex, uint32_t lineNumber, const AsmJSFunctionLabels &l); CodeRange(Kind kind, uint32_t begin, uint32_t end); CodeRange(Kind kind, uint32_t begin, uint32_t profilingReturn, uint32_t end); CodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin, uint32_t pret, uint32_t end); void updateOffsets(jit::MacroAssembler &masm); Kind kind() const { return Kind(u.kind_); } bool isFunction() const { return kind() == Function; } bool isEntry() const { return kind() == Entry; } - bool isFFI() const { return kind() == IonFFI || kind() == SlowFFI; } + bool isFFI() const { return kind() == JitFFI || kind() == SlowFFI; } bool isInterrupt() const { return kind() == Interrupt; } bool isThunk() const { return kind() == Thunk; } uint32_t begin() const { return begin_; } uint32_t entry() const { MOZ_ASSERT(isFunction()); @@ -1320,20 +1320,20 @@ class AsmJSModule return pc >= code_ && pc < (code_ + codeBytes()); } private: uint8_t *interpExitTrampoline(const Exit &exit) const { MOZ_ASSERT(isFinished()); MOZ_ASSERT(exit.interpCodeOffset_); return code_ + exit.interpCodeOffset_; } - uint8_t *ionExitTrampoline(const Exit &exit) const { + uint8_t *jitExitTrampoline(const Exit &exit) const { MOZ_ASSERT(isFinished()); - MOZ_ASSERT(exit.ionCodeOffset_); - return code_ + exit.ionCodeOffset_; + MOZ_ASSERT(exit.jitCodeOffset_); + return code_ + exit.jitCodeOffset_; } public: // Lookup a callsite by the return pc (from the callee to the caller). // Return null if no callsite was found. const jit::CallSite *lookupCallSite(void *returnAddress) const; // Lookup the name the code range containing the given pc. Return null if no @@ -1458,27 +1458,27 @@ class AsmJSModule MOZ_ASSERT(isFinished()); return *(ExitDatum *)(globalData() + exitIndexToGlobalDataOffset(exitIndex)); } bool exitIsOptimized(unsigned exitIndex) const { MOZ_ASSERT(isFinished()); ExitDatum &exitDatum = exitIndexToGlobalDatum(exitIndex); return exitDatum.exit != interpExitTrampoline(exit(exitIndex)); } - void optimizeExit(unsigned exitIndex, jit::IonScript *ionScript) const { + void optimizeExit(unsigned exitIndex, jit::BaselineScript *baselineScript) const { MOZ_ASSERT(!exitIsOptimized(exitIndex)); ExitDatum &exitDatum = exitIndexToGlobalDatum(exitIndex); - exitDatum.exit = ionExitTrampoline(exit(exitIndex)); - exitDatum.ionScript = ionScript; + exitDatum.exit = jitExitTrampoline(exit(exitIndex)); + exitDatum.baselineScript = baselineScript; } - void detachIonCompilation(size_t exitIndex) const { + void detachJitCompilation(size_t exitIndex) const { MOZ_ASSERT(isFinished()); ExitDatum &exitDatum = exitIndexToGlobalDatum(exitIndex); exitDatum.exit = interpExitTrampoline(exit(exitIndex)); - exitDatum.ionScript = nullptr; + exitDatum.baselineScript = nullptr; } /*************************************************************************/ // These functions are called after finish() but before staticallyLink(): bool addRelativeLink(RelativeLink link) { MOZ_ASSERT(isFinished() && !isStaticallyLinked()); return staticLinkData_.relativeLinks.append(link);
--- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -1865,23 +1865,23 @@ class MOZ_STACK_CLASS ModuleCompiler bool finishGeneratingInterpExit(unsigned exitIndex, Label *begin, Label *profilingReturn) { MOZ_ASSERT(finishedFunctionBodies_); uint32_t beg = begin->offset(); module_->exit(exitIndex).initInterpOffset(beg); uint32_t pret = profilingReturn->offset(); uint32_t end = masm_.currentOffset(); return module_->addCodeRange(AsmJSModule::CodeRange::SlowFFI, beg, pret, end); } - bool finishGeneratingIonExit(unsigned exitIndex, Label *begin, Label *profilingReturn) { + bool finishGeneratingJitExit(unsigned exitIndex, Label *begin, Label *profilingReturn) { MOZ_ASSERT(finishedFunctionBodies_); uint32_t beg = begin->offset(); - module_->exit(exitIndex).initIonOffset(beg); + module_->exit(exitIndex).initJitOffset(beg); uint32_t pret = profilingReturn->offset(); uint32_t end = masm_.currentOffset(); - return module_->addCodeRange(AsmJSModule::CodeRange::IonFFI, beg, pret, end); + return module_->addCodeRange(AsmJSModule::CodeRange::JitFFI, beg, pret, end); } bool finishGeneratingInterrupt(Label *begin, Label *profilingReturn) { MOZ_ASSERT(finishedFunctionBodies_); uint32_t beg = begin->offset(); uint32_t pret = profilingReturn->offset(); uint32_t end = masm_.currentOffset(); return module_->addCodeRange(AsmJSModule::CodeRange::Interrupt, beg, pret, end); } @@ -8448,17 +8448,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co coerceArgTypes.infallibleAppend(MIRType_Pointer); // argv unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(double)); unsigned totalCoerceBytes = offsetToCoerceArgv + sizeof(Value) + MaybeSavedGlobalReg; unsigned coerceFrameSize = StackDecrementForCall(masm, AsmJSStackAlignment, totalCoerceBytes); unsigned framePushed = Max(ionFrameSize, coerceFrameSize); Label begin; - GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::IonFFI, &begin); + GenerateAsmJSExitPrologue(masm, framePushed, AsmJSExit::JitFFI, &begin); // 1. Descriptor size_t argOffset = offsetToIonArgs; uint32_t descriptor = MakeFrameDescriptor(framePushed, JitFrame_Entry); masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, argOffset)); argOffset += sizeof(size_t); // 2. Callee @@ -8496,17 +8496,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co argOffset += sizeof(Value); // 5. Fill the arguments unsigned offsetToCallerStackArgs = framePushed + sizeof(AsmJSFrame); FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch); argOffset += exit.sig().args().length() * sizeof(Value); MOZ_ASSERT(argOffset == offsetToIonArgs + ionArgBytes); - // 6. Ion will clobber all registers, even non-volatiles. GlobalReg and + // 6. Jit code will clobber all registers, even non-volatiles. GlobalReg and // HeapReg are removed from the general register set for asm.js code, so // these will not have been saved by the caller like all other registers, // so they must be explicitly preserved. Only save GlobalReg since // HeapReg must be reloaded (from global data) after the call since the // heap may change during the FFI call. #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) JS_STATIC_ASSERT(MaybeSavedGlobalReg > 0); unsigned savedGlobalOffset = framePushed - MaybeSavedGlobalReg; @@ -8548,17 +8548,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop())); masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2); masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext())); masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext)); } // 2. Call AssertStackAlignment(masm, AsmJSStackAlignment); - masm.callIonFromAsmJS(callee); + masm.callJitFromAsmJS(callee); AssertStackAlignment(masm, AsmJSStackAlignment); { // Disable Activation. // // This sequence needs three registers, and must preserve the JSReturnReg_Data and // JSReturnReg_Type, so there are five live registers. MOZ_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData); @@ -8620,17 +8620,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co #endif // The heap pointer has to be reloaded anyway since Ion could have clobbered // it. Additionally, the FFI may have detached the heap buffer. masm.loadAsmJSHeapRegisterFromGlobalData(); GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0); Label profilingReturn; - GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::IonFFI, &profilingReturn); + GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::JitFFI, &profilingReturn); if (oolConvert.used()) { masm.bind(&oolConvert); masm.setFramePushed(framePushed); // Store return value into argv[0] masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToCoerceArgv)); @@ -8664,17 +8664,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co } masm.jump(&done); masm.setFramePushed(0); } MOZ_ASSERT(masm.framePushed() == 0); - return m.finishGeneratingIonExit(exitIndex, &begin, &profilingReturn) && !masm.oom(); + return m.finishGeneratingJitExit(exitIndex, &begin, &profilingReturn) && !masm.oom(); } // See "asm.js FFI calls" comment above. static bool GenerateFFIExits(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit, unsigned exitIndex, Label *throwLabel) { // Generate the slow path through the interpreter
--- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -378,16 +378,24 @@ class LifoAlloc // Get the total size of the arena chunks (including unused space). size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = 0; for (BumpChunk *chunk = first; chunk; chunk = chunk->next()) n += chunk->sizeOfIncludingThis(mallocSizeOf); return n; } + // Get the total size of the arena chunks (including unused space). + size_t computedSizeOfExcludingThis() const { + size_t n = 0; + for (BumpChunk *chunk = first; chunk; chunk = chunk->next()) + n += chunk->computedSizeOfIncludingThis(); + return n; + } + // Like sizeOfExcludingThis(), but includes the size of the LifoAlloc itself. size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); } // Get the peak size of the arena chunks (including unused space and // bookkeeping space). size_t peakSizeOfExcludingThis() const { return peakSize_; }
--- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -142,13 +142,12 @@ struct MovingTracer : JSTracer { static void Visit(JSTracer *jstrc, void **thingp, JSGCTraceKind kind); static bool IsMovingTracer(JSTracer *trc) { return trc->callback == Visit; } }; #endif - } /* namespace gc */ } /* namespace js */ #endif /* gc_GCInternals_h */
--- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -594,23 +594,24 @@ class GCRuntime bool shouldReleaseObservedTypes(); void endSweepingZoneGroup(); bool sweepPhase(SliceBudget &sliceBudget); void endSweepPhase(bool lastGC); void sweepZones(FreeOp *fop, bool lastGC); void decommitAllWithoutUnlocking(const AutoLockGC &lock); void decommitArenas(AutoLockGC &lock); void expireChunksAndArenas(bool shouldShrink, AutoLockGC &lock); - void sweepBackgroundThings(); + void queueZonesForBackgroundSweep(js::gc::ZoneList& zones); + void sweepBackgroundThings(js::gc::ZoneList &zones, ThreadType threadType); void assertBackgroundSweepingFinished(); bool shouldCompact(); + bool compactPhase(bool lastGC); #ifdef JSGC_COMPACTING void sweepTypesAfterCompacting(Zone *zone); void sweepZoneAfterCompacting(Zone *zone); - void compactPhase(bool lastGC); ArenaHeader *relocateArenas(); void updateAllCellPointersParallel(ArenasToUpdate &source); void updateAllCellPointersSerial(MovingTracer *trc, ArenasToUpdate &source); void updatePointersToRelocatedCells(); void releaseRelocatedArenas(ArenaHeader *relocatedList); void releaseRelocatedArenasWithoutUnlocking(ArenaHeader *relocatedList, const AutoLockGC& lock); #ifdef DEBUG void protectRelocatedArenas(ArenaHeader *relocatedList); @@ -753,19 +754,18 @@ class GCRuntime bool sweepOnBackgroundThread; /* Whether observed type information is being released in the current GC. */ bool releaseObservedTypes; /* Whether any black->gray edges were found during marking. */ bool foundBlackGrayEdges; - /* List head of zones to be swept in the background. */ - JS::Zone *sweepingZones; - + /* Singly linekd list of zones to be swept in the background. */ + js::gc::ZoneList backgroundSweepZones; /* * Free LIFO blocks are transferred to this allocator before being freed on * the background GC thread. */ js::LifoAlloc freeLifoAlloc; /* Index of current zone group (for stats). */ unsigned zoneGroupIndex;
--- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -14,16 +14,18 @@ #include "vm/Debugger.h" #include "vm/Runtime.h" #include "jsgcinlines.h" using namespace js; using namespace js::gc; +Zone * const Zone::NotOnList = reinterpret_cast<Zone *>(1); + JS::Zone::Zone(JSRuntime *rt) : JS::shadow::Zone(rt, &rt->gc.marker), allocator(this), types(this), compartments(), gcGrayRoots(), gcMallocBytes(0), gcMallocGCTriggered(false), @@ -32,17 +34,18 @@ JS::Zone::Zone(JSRuntime *rt) data(nullptr), isSystem(false), usedByExclusiveThread(false), active(false), jitZone_(nullptr), gcState_(NoGC), gcScheduled_(false), gcPreserveCode_(false), - jitUsingBarriers_(false) + jitUsingBarriers_(false), + listNext_(NotOnList) { /* Ensure that there are no vtables to mess us up here. */ MOZ_ASSERT(reinterpret_cast<JS::shadow::Zone *>(this) == static_cast<JS::shadow::Zone *>(this)); threshold.updateAfterGC(8192, GC_NORMAL, rt->gc.tunables, rt->gc.schedulingState); setGCMaxMallocBytes(rt->gc.maxMallocBytesAllocated() * 0.9); } @@ -260,8 +263,100 @@ js::ZoneOfValue(const JS::Value &value) return js::gc::TenuredCell::fromPointer(value.toGCThing())->zone(); } bool js::ZonesIter::atAtomsZone(JSRuntime *rt) { return rt->isAtomsZone(*it); } + +bool Zone::isOnList() +{ + return listNext_ != NotOnList; +} + +ZoneList::ZoneList() + : head(nullptr), tail(nullptr) +{} + +ZoneList::ZoneList(Zone *zone) + : head(zone), tail(zone) +{ + MOZ_ASSERT(!zone->isOnList()); + zone->listNext_ = nullptr; +} + +void +ZoneList::check() const +{ +#ifdef DEBUG + MOZ_ASSERT((head == nullptr) == (tail == nullptr)); + if (head) { + Zone *zone = head; + while (zone != tail) { + zone = zone->listNext_; + MOZ_ASSERT(zone); + } + MOZ_ASSERT(!zone->listNext_); + } +#endif +} + +bool ZoneList::isEmpty() const +{ + return head == nullptr; +} + +Zone * +ZoneList::front() const +{ + MOZ_ASSERT(!isEmpty()); + return head; +} + +void +ZoneList::append(Zone *zone) +{ + ZoneList singleZone(zone); + append(singleZone); +} + +void +ZoneList::append(ZoneList &other) +{ + check(); + other.check(); + MOZ_ASSERT(tail != other.tail); + + if (tail) + tail->listNext_ = other.head; + else + head = other.head; + tail = other.tail; +} + +Zone * +ZoneList::removeFront() +{ + MOZ_ASSERT(!isEmpty()); + check(); + + Zone *front = head; + head = head->listNext_; + if (!head) + tail = nullptr; + + front->listNext_ = Zone::NotOnList; + return front; +} + +void +ZoneList::transferFrom(ZoneList& other) +{ + MOZ_ASSERT(isEmpty()); + other.check(); + + head = other.head; + tail = other.tail; + other.head = nullptr; + other.tail = nullptr; +}
--- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -245,16 +245,20 @@ struct Zone : public JS::shadow::Zone, #endif private: void sweepBreakpoints(js::FreeOp *fop); void sweepCompartments(js::FreeOp *fop, bool keepAtleastOne, bool lastGC); js::jit::JitZone *createJitZone(JSContext *cx); + bool isQueuedForBackgroundSweep() { + return isOnList(); + } + public: js::Allocator allocator; js::types::TypeZone types; // The set of compartments in this zone. typedef js::Vector<JSCompartment *, 1, js::SystemAllocPolicy> CompartmentVector; CompartmentVector compartments; @@ -309,16 +313,22 @@ struct Zone : public JS::shadow::Zone, private: js::jit::JitZone *jitZone_; GCState gcState_; bool gcScheduled_; bool gcPreserveCode_; bool jitUsingBarriers_; + // Allow zones to be linked into a list + friend class js::gc::ZoneList; + static Zone * const NotOnList; + Zone *listNext_; + bool isOnList(); + friend bool js::CurrentThreadCanAccessZone(Zone *zone); friend class js::gc::GCRuntime; }; } // namespace JS namespace js {
--- a/js/src/jit/AtomicOp.h +++ b/js/src/jit/AtomicOp.h @@ -34,40 +34,40 @@ enum MemoryBarrierBits { MembarSynchronizing = 16, // For validity testing MembarNobits = 0, MembarAllbits = 31, }; -inline MemoryBarrierBits +static inline MOZ_CONSTEXPR MemoryBarrierBits operator|(MemoryBarrierBits a, MemoryBarrierBits b) { return MemoryBarrierBits(int(a) | int(b)); } -inline MemoryBarrierBits +static inline MOZ_CONSTEXPR MemoryBarrierBits operator&(MemoryBarrierBits a, MemoryBarrierBits b) { return MemoryBarrierBits(int(a) & int(b)); } -inline MemoryBarrierBits +static inline MOZ_CONSTEXPR MemoryBarrierBits operator~(MemoryBarrierBits a) { return MemoryBarrierBits(~int(a)); } // Standard barrier bits for a full barrier. -static const MemoryBarrierBits MembarFull = MembarLoadLoad|MembarLoadStore|MembarStoreLoad|MembarStoreStore; +static MOZ_CONSTEXPR_VAR MemoryBarrierBits MembarFull = MembarLoadLoad|MembarLoadStore|MembarStoreLoad|MembarStoreStore; // Standard sets of barrier bits for atomic loads and stores. // See http://gee.cs.oswego.edu/dl/jmm/cookbook.html for more. -static const MemoryBarrierBits MembarBeforeLoad = MembarNobits; -static const MemoryBarrierBits MembarAfterLoad = MembarLoadLoad|MembarLoadStore; -static const MemoryBarrierBits MembarBeforeStore = MembarStoreStore; -static const MemoryBarrierBits MembarAfterStore = MembarStoreLoad; +static MOZ_CONSTEXPR_VAR MemoryBarrierBits MembarBeforeLoad = MembarNobits; +static MOZ_CONSTEXPR_VAR MemoryBarrierBits MembarAfterLoad = MembarLoadLoad|MembarLoadStore; +static MOZ_CONSTEXPR_VAR MemoryBarrierBits MembarBeforeStore = MembarStoreStore; +static MOZ_CONSTEXPR_VAR MemoryBarrierBits MembarAfterStore = MembarStoreLoad; } // namespace jit } // namespace js #endif /* jit_AtomicOp_h */
--- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -3,16 +3,17 @@ * 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 "jit/BaselineJIT.h" #include "mozilla/MemoryReporting.h" +#include "asmjs/AsmJSModule.h" #include "jit/BaselineCompiler.h" #include "jit/BaselineIC.h" #include "jit/CompileInfo.h" #include "jit/JitCommon.h" #include "jit/JitSpewer.h" #include "vm/Interpreter.h" #include "vm/TraceLogging.h" @@ -40,16 +41,17 @@ PCMappingSlotInfo::ToSlotLocation(const return SlotIgnore; } BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset, uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset) : method_(nullptr), templateScope_(nullptr), fallbackStubSpace_(), + dependentAsmJSModules_(nullptr), prologueOffset_(prologueOffset), epilogueOffset_(epilogueOffset), #ifdef DEBUG spsOn_(false), #endif spsPushToggleOffset_(spsPushToggleOffset), postDebugPrologueOffset_(postDebugPrologueOffset), flags_(0) @@ -435,19 +437,64 @@ BaselineScript::Destroy(FreeOp *fop, Bas * will contain entries refering to the referenced things. Since we can * destroy scripts outside the context of a GC, this situation can result * in invalid store buffer entries. Assert that if we do destroy scripts * outside of a GC that we at least emptied the nursery first. */ MOZ_ASSERT(fop->runtime()->gc.nursery.isEmpty()); #endif + script->unlinkDependentAsmJSModules(fop); + fop->delete_(script); } +void +BaselineScript::unlinkDependentAsmJSModules(FreeOp *fop) +{ + // Remove any links from AsmJSModules that contain optimized FFI calls into + // this BaselineScript. + if (dependentAsmJSModules_) { + for (size_t i = 0; i < dependentAsmJSModules_->length(); i++) { + DependentAsmJSModuleExit exit = (*dependentAsmJSModules_)[i]; + exit.module->detachJitCompilation(exit.exitIndex); + } + + fop->delete_(dependentAsmJSModules_); + dependentAsmJSModules_ = nullptr; + } +} + +bool +BaselineScript::addDependentAsmJSModule(JSContext *cx, DependentAsmJSModuleExit exit) +{ + if (!dependentAsmJSModules_) { + dependentAsmJSModules_ = cx->new_<Vector<DependentAsmJSModuleExit> >(cx); + if (!dependentAsmJSModules_) + return false; + } + return dependentAsmJSModules_->append(exit); +} + +void +BaselineScript::removeDependentAsmJSModule(DependentAsmJSModuleExit exit) +{ + if (!dependentAsmJSModules_) + return; + + for (size_t i = 0; i < dependentAsmJSModules_->length(); i++) { + if ((*dependentAsmJSModules_)[i].module == exit.module && + (*dependentAsmJSModules_)[i].exitIndex == exit.exitIndex) + { + dependentAsmJSModules_->erase(dependentAsmJSModules_->begin() + i); + break; + } + } +} + ICEntry & BaselineScript::icEntry(size_t index) { MOZ_ASSERT(index < numICEntries()); return icEntryList()[index]; } PCMappingIndexEntry &
--- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -88,16 +88,29 @@ struct PCMappingIndexEntry // Native code offset. uint32_t nativeOffset; // Offset in the CompactBuffer where data for pcOffset starts. uint32_t bufferOffset; }; +// Describes a single AsmJSModule which jumps (via an FFI exit with the given +// index) directly to a BaselineScript or IonScript. +struct DependentAsmJSModuleExit +{ + const AsmJSModule *module; + size_t exitIndex; + + DependentAsmJSModuleExit(const AsmJSModule *module, size_t exitIndex) + : module(module), + exitIndex(exitIndex) + { } +}; + struct BaselineScript { public: static const uint32_t MAX_JSSCRIPT_LENGTH = 0x0fffffffu; // Limit the locals on a given script so that stack check on baseline frames // doesn't overflow a uint32_t value. // (MAX_JSSCRIPT_SLOTS * sizeof(Value)) must fit within a uint32_t. @@ -109,16 +122,20 @@ struct BaselineScript // For heavyweight scripts, template objects to use for the call object and // decl env object (linked via the call object's enclosing scope). HeapPtrObject templateScope_; // Allocated space for fallback stubs. FallbackICStubSpace fallbackStubSpace_; + // If non-null, the list of AsmJSModules that contain an optimized call + // directly to this script. + Vector<DependentAsmJSModuleExit> *dependentAsmJSModules_; + // Native code offset right before the scope chain is initialized. uint32_t prologueOffset_; // Native code offset right before the frame is popped and the method // returned from. uint32_t epilogueOffset_; // The offsets for the toggledJump instructions for SPS update ICs. @@ -342,16 +359,20 @@ struct BaselineScript uint8_t *nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo = nullptr); jsbytecode *pcForReturnOffset(JSScript *script, uint32_t nativeOffset); jsbytecode *pcForReturnAddress(JSScript *script, uint8_t *nativeAddress); jsbytecode *pcForNativeAddress(JSScript *script, uint8_t *nativeAddress); jsbytecode *pcForNativeOffset(JSScript *script, uint32_t nativeOffset); + bool addDependentAsmJSModule(JSContext *cx, DependentAsmJSModuleExit exit); + void unlinkDependentAsmJSModules(FreeOp *fop); + void removeDependentAsmJSModule(DependentAsmJSModuleExit exit); + private: jsbytecode *pcForNativeOffset(JSScript *script, uint32_t nativeOffset, bool isReturn); public: // Toggle debug traps (used for breakpoints and step mode) in the script. // If |pc| is nullptr, toggle traps for all ops in the script. Else, only // toggle traps at |pc|. void toggleDebugTraps(JSScript *script, jsbytecode *pc);
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1212,18 +1212,18 @@ PrepareAndExecuteRegExp(JSContext *cx, M masm.storePtr(temp3, lazySourceAddress); masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3); masm.store32(temp3, Address(temp1, RegExpStatics::offsetOfLazyFlags())); return true; } static void -CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch, - size_t fromWidth, size_t toWidth); +CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, + Register byteOpScratch, size_t fromWidth, size_t toWidth); static void CreateDependentString(MacroAssembler &masm, const JSAtomState &names, bool latin1, Register string, Register base, Register temp1, Register temp2, BaseIndex startIndexAddress, BaseIndex limitIndexAddress, Label *failure) { @@ -5916,18 +5916,18 @@ CodeGenerator::visitConcatPar(LConcatPar MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2); MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3); MOZ_ASSERT(output == CallTempReg5); return emitConcat(lir, lhs, rhs, output); } static void -CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch, - size_t fromWidth, size_t toWidth) +CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, + Register byteOpScratch, size_t fromWidth, size_t toWidth) { // Copy |len| char16_t code units from |from| to |to|. Assumes len > 0 // (checked below in debug builds), and when done |to| must point to the // next available char. #ifdef DEBUG Label ok; masm.branch32(Assembler::GreaterThan, len, Imm32(0), &ok); @@ -5937,23 +5937,23 @@ CopyStringChars(MacroAssembler &masm, Re MOZ_ASSERT(fromWidth == 1 || fromWidth == 2); MOZ_ASSERT(toWidth == 1 || toWidth == 2); MOZ_ASSERT_IF(toWidth == 1, fromWidth == 1); Label start; masm.bind(&start); if (fromWidth == 2) - masm.load16ZeroExtend(Address(from, 0), scratch); + masm.load16ZeroExtend(Address(from, 0), byteOpScratch); else - masm.load8ZeroExtend(Address(from, 0), scratch); + masm.load8ZeroExtend(Address(from, 0), byteOpScratch); if (toWidth == 2) - masm.store16(scratch, Address(to, 0)); + masm.store16(byteOpScratch, Address(to, 0)); else - masm.store8(scratch, Address(to, 0)); + masm.store8(byteOpScratch, Address(to, 0)); masm.addPtr(Imm32(fromWidth), from); masm.addPtr(Imm32(toWidth), to); masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start); } static void CopyStringCharsMaybeInflate(MacroAssembler &masm, Register input, Register destChars, Register temp1, Register temp2) @@ -6060,18 +6060,22 @@ static const VMFunction SubstringKernelI bool CodeGenerator::visitSubstr(LSubstr *lir) { Register string = ToRegister(lir->string()); Register begin = ToRegister(lir->begin()); Register length = ToRegister(lir->length()); Register output = ToRegister(lir->output()); Register temp = ToRegister(lir->temp()); - Register temp2 = ToRegister(lir->temp2()); Register temp3 = ToRegister(lir->temp3()); + + // On x86 there are not enough registers. In that case reuse the string + // register as temporary. + Register temp2 = lir->temp2()->isBogusTemp() ? string : ToRegister(lir->temp2()); + Address stringFlags(string, JSString::offsetOfFlags()); Label isLatin1, notInline, nonZero, isInlinedLatin1; // For every edge case use the C++ variant. // Note: we also use this upon allocation failure in newGCString and // newGCFatInlineString. To squeeze out even more performance those failures // can be handled by allocate in ool code and returning to jit code to fill @@ -6105,35 +6109,43 @@ bool CodeGenerator::visitSubstr(LSubstr Address outputStorage(output, JSInlineString::offsetOfInlineStorage()); masm.branchTest32(Assembler::NonZero, stringFlags, Imm32(JSString::LATIN1_CHARS_BIT), &isInlinedLatin1); { masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS), Address(output, JSString::offsetOfFlags())); masm.computeEffectiveAddress(stringStorage, temp); + if (temp2 == string) + masm.push(string); BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t))); masm.computeEffectiveAddress(chars, temp2); masm.computeEffectiveAddress(outputStorage, temp); CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char16_t), sizeof(char16_t)); masm.load32(Address(output, JSString::offsetOfLength()), length); masm.store16(Imm32(0), Address(temp, 0)); + if (temp2 == string) + masm.pop(string); masm.jump(done); } masm.bind(&isInlinedLatin1); { masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS | JSString::LATIN1_CHARS_BIT), Address(output, JSString::offsetOfFlags())); + if (temp2 == string) + masm.push(string); masm.computeEffectiveAddress(stringStorage, temp2); static_assert(sizeof(char) == 1, "begin index shouldn't need scaling"); masm.addPtr(begin, temp2); masm.computeEffectiveAddress(outputStorage, temp); CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char), sizeof(char)); masm.load32(Address(output, JSString::offsetOfLength()), length); masm.store8(Imm32(0), Address(temp, 0)); + if (temp2 == string) + masm.pop(string); masm.jump(done); } // Handle other cases with a DependentString. masm.bind(¬Inline); masm.newGCString(output, temp, slowPath); masm.store32(length, Address(output, JSString::offsetOfLength())); masm.storePtr(string, Address(output, JSDependentString::offsetOfBase()));
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -7,17 +7,16 @@ #include "jit/Ion.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ThreadLocal.h" #include "jscompartment.h" #include "jsprf.h" -#include "asmjs/AsmJSModule.h" #include "gc/Marking.h" #include "jit/AliasAnalysis.h" #include "jit/BacktrackingAllocator.h" #include "jit/BaselineFrame.h" #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/CodeGenerator.h" #include "jit/EdgeCaseAnalysis.h" @@ -839,17 +838,16 @@ IonScript::IonScript() callTargetList_(0), callTargetEntries_(0), backedgeList_(0), backedgeEntries_(0), invalidationCount_(0), parallelAge_(0), recompileInfo_(), osrPcMismatchCounter_(0), - dependentAsmJSModules(nullptr), pendingBuilder_(nullptr) { } IonScript * IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo, uint32_t frameSlots, uint32_t frameSize, size_t snapshotsListSize, size_t snapshotsRVATableSize, @@ -1217,42 +1215,19 @@ IonScript::purgeCaches() void IonScript::destroyCaches() { for (size_t i = 0; i < numCaches(); i++) getCacheFromIndex(i).destroy(); } -bool -IonScript::addDependentAsmJSModule(JSContext *cx, DependentAsmJSModuleExit exit) -{ - if (!dependentAsmJSModules) { - dependentAsmJSModules = cx->new_<Vector<DependentAsmJSModuleExit> >(cx); - if (!dependentAsmJSModules) - return false; - } - return dependentAsmJSModules->append(exit); -} - void IonScript::unlinkFromRuntime(FreeOp *fop) { - // Remove any links from AsmJSModules that contain optimized FFI calls into - // this IonScript. - if (dependentAsmJSModules) { - for (size_t i = 0; i < dependentAsmJSModules->length(); i++) { - DependentAsmJSModuleExit exit = dependentAsmJSModules->begin()[i]; - exit.module->detachIonCompilation(exit.exitIndex); - } - - fop->delete_(dependentAsmJSModules); - dependentAsmJSModules = nullptr; - } - // The writes to the executable buffer below may clobber backedge jumps, so // make sure that those backedges are unlinked from the runtime and not // reclobbered with garbage if an interrupt is requested. JitRuntime *jrt = fop->runtime()->jitRuntime(); JitRuntime::AutoMutateBackedges amb(jrt); for (size_t i = 0; i < backedgeEntries_; i++) jrt->removePatchableBackedge(&backedgeList()[i]);
--- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -155,29 +155,16 @@ class SnapshotWriter; class RecoverWriter; class SafepointWriter; class SafepointIndex; class OsiIndex; class IonCache; struct PatchableBackedgeInfo; struct CacheLocation; -// Describes a single AsmJSModule which jumps (via an FFI exit with the given -// index) directly into an IonScript. -struct DependentAsmJSModuleExit -{ - const AsmJSModule *module; - size_t exitIndex; - - DependentAsmJSModuleExit(const AsmJSModule *module, size_t exitIndex) - : module(module), - exitIndex(exitIndex) - { } -}; - // An IonScript attaches Ion-generated information to a JSScript. struct IonScript { private: // Code pointer containing the actual method. PreBarrieredJitCode method_; // Deoptimization table used by this method. @@ -293,20 +280,16 @@ struct IonScript // The optimization level this script was compiled in. OptimizationLevel optimizationLevel_; // Number of times we tried to enter this script via OSR but failed due to // a LOOPENTRY pc other than osrPc_. uint32_t osrPcMismatchCounter_; - // If non-null, the list of AsmJSModules - // that contain an optimized call directly into this IonScript. - Vector<DependentAsmJSModuleExit> *dependentAsmJSModules; - IonBuilder *pendingBuilder_; private: inline uint8_t *bottomBuffer() { return reinterpret_cast<uint8_t *>(this); } inline const uint8_t *bottomBuffer() const { return reinterpret_cast<const uint8_t *>(this); @@ -347,29 +330,16 @@ struct IonScript return &bottomBuffer()[runtimeData_]; } JSScript **callTargetList() { return (JSScript **) &bottomBuffer()[callTargetList_]; } PatchableBackedge *backedgeList() { return (PatchableBackedge *) &bottomBuffer()[backedgeList_]; } - bool addDependentAsmJSModule(JSContext *cx, DependentAsmJSModuleExit exit); - void removeDependentAsmJSModule(DependentAsmJSModuleExit exit) { - if (!dependentAsmJSModules) - return; - for (size_t i = 0; i < dependentAsmJSModules->length(); i++) { - if (dependentAsmJSModules->begin()[i].module == exit.module && - dependentAsmJSModules->begin()[i].exitIndex == exit.exitIndex) - { - dependentAsmJSModules->erase(dependentAsmJSModules->begin() + i); - break; - } - } - } private: void trace(JSTracer *trc); public: // Do not call directly, use IonScript::New. This is public for cx->new_. IonScript();
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2177,31 +2177,16 @@ LIRGenerator::visitStringReplace(MString LStringReplace *lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()), useRegisterAtStart(ins->pattern()), useRegisterOrConstantAtStart(ins->replacement())); return defineReturn(lir, ins) && assignSafepoint(lir, ins); } bool -LIRGenerator::visitSubstr(MSubstr *ins) -{ - // The last temporary need to be a register that can handle 8bit moves, but - // there is no way to signal that to register allocator, except to give a - // fixed temporary that is able to do this. - LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()), - useRegister(ins->begin()), - useRegister(ins->length()), - temp(), - temp(), - tempFixed(CallTempReg1)); - return define(lir, ins) && assignSafepoint(lir, ins); -} - -bool LIRGenerator::visitLambda(MLambda *ins) { if (ins->info().singletonType || ins->info().useNewTypeForClone) { // If the function has a singleton type, this instruction will only be // executed once so we don't bother inlining it. // // If UseNewTypeForClone is true, we will assign a singleton type to // the clone and we have to clone the script, we can't do that inline.
--- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -141,17 +141,16 @@ class LIRGenerator : public LIRGenerator bool visitMul(MMul *ins); bool visitDiv(MDiv *ins); bool visitMod(MMod *ins); bool visitConcat(MConcat *ins); bool visitConcatPar(MConcatPar *ins); bool visitCharCodeAt(MCharCodeAt *ins); bool visitFromCharCode(MFromCharCode *ins); bool visitStringSplit(MStringSplit *ins); - bool visitSubstr(MSubstr *ins); bool visitStart(MStart *start); bool visitOsrEntry(MOsrEntry *entry); bool visitNop(MNop *nop); bool visitLimitedTruncate(MLimitedTruncate *nop); bool visitOsrValue(MOsrValue *value); bool visitOsrScopeChain(MOsrScopeChain *object); bool visitOsrReturnValue(MOsrReturnValue *value); bool visitOsrArgumentsObject(MOsrArgumentsObject *object);
--- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -50,16 +50,22 @@ LIRGeneratorARM::useByteOpRegister(MDefi } LAllocation LIRGeneratorARM::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir) { return useRegisterOrNonDoubleConstant(mir); } +LDefinition +LIRGeneratorARM::tempByteOpRegister() +{ + return temp(); +} + bool LIRGeneratorARM::lowerConstantDouble(double d, MInstruction *mir) { return define(new(alloc()) LDouble(d), mir); } bool LIRGeneratorARM::lowerConstantFloat32(float d, MInstruction *mir) @@ -669,8 +675,20 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHe LAsmJSAtomicBinopHeap *lir = new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), useRegister(ins->value()), LDefinition::BogusTemp()); return define(lir, ins); } + +bool +LIRGeneratorARM::visitSubstr(MSubstr *ins) +{ + LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()), + useRegister(ins->begin()), + useRegister(ins->length()), + temp(), + temp(), + tempByteOpRegister()); + return define(lir, ins) && assignSafepoint(lir, ins); +}
--- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -25,16 +25,17 @@ class LIRGeneratorARM : public LIRGenera bool useBox(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy = LUse::REGISTER, bool useAtStart = false); bool useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2); // x86 has constraints on what registers can be formatted for 1-byte // stores and loads; on ARM all registers are okay. LAllocation useByteOpRegister(MDefinition *mir); LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir); + LDefinition tempByteOpRegister(); inline LDefinition tempToUnbox() { return LDefinition::BogusTemp(); } bool needTempForPostBarrier() { return false; } // x64 has a scratch register, so no need for another temp for dispatch @@ -106,16 +107,17 @@ class LIRGeneratorARM : public LIRGenera bool visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins); bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins); bool visitForkJoinGetSlice(MForkJoinGetSlice *ins); bool visitSimdTernaryBitwise(MSimdTernaryBitwise *ins); bool visitSimdSplatX4(MSimdSplatX4 *ins); bool visitSimdValueX4(MSimdValueX4 *ins); bool visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins); bool visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins); + bool visitSubstr(MSubstr *ins); }; typedef LIRGeneratorARM LIRGeneratorSpecific; } // namespace jit } // namespace js #endif /* jit_arm_Lowering_arm_h */
--- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1856,21 +1856,21 @@ MacroAssemblerARMCompat::callIon(Registe ma_callIonHalfPush(callee); } else { adjustFrame(sizeof(void*)); ma_callIon(callee); } } void -MacroAssemblerARMCompat::callIonFromAsmJS(Register callee) +MacroAssemblerARMCompat::callJitFromAsmJS(Register callee) { ma_callIonNoPush(callee); - // The Ion ABI has the callee pop the return address off the stack. + // The JIT ABI has the callee pop the return address off the stack. // The asm.js caller assumes that the call leaves sp unchanged, so bump // the stack. subPtr(Imm32(sizeof(void*)), sp); } void MacroAssembler::alignFrameForICArguments(AfterICSaveLive &aic) {
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1288,17 +1288,17 @@ class MacroAssemblerARMCompat : public M void callWithExitFrame(Label *target); void callWithExitFrame(JitCode *target); void callWithExitFrame(JitCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // independent code to make a call. void callIon(Register callee); - void callIonFromAsmJS(Register callee); + void callJitFromAsmJS(Register callee); void reserveStack(uint32_t amount); void freeStack(uint32_t amount); void freeStack(Register amount); void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/mips/Lowering-mips.cpp +++ b/js/src/jit/mips/Lowering-mips.cpp @@ -52,16 +52,22 @@ LIRGeneratorMIPS::useByteOpRegister(MDef } LAllocation LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir) { return useRegisterOrNonDoubleConstant(mir); } +LDefinition +LIRGeneratorMIPS::tempByteOpRegister() +{ + return temp(); +} + bool LIRGeneratorMIPS::lowerConstantDouble(double d, MInstruction *mir) { return define(new(alloc()) LDouble(d), mir); } bool LIRGeneratorMIPS::lowerConstantFloat32(float d, MInstruction *mir) @@ -521,16 +527,28 @@ LIRGeneratorMIPS::lowerTruncateFToInt32( { MDefinition *opd = ins->input(); MOZ_ASSERT(opd->type() == MIRType_Float32); return define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } bool +LIRGeneratorMIPS::visitSubstr(MSubstr *ins) +{ + LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()), + useRegister(ins->begin()), + useRegister(ins->length()), + temp(), + temp(), + tempByteOpRegister()); + return define(lir, ins) && assignSafepoint(lir, ins); +} + +bool LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins) { MOZ_CRASH("NYI"); } bool LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins) {
--- a/js/src/jit/mips/Lowering-mips.h +++ b/js/src/jit/mips/Lowering-mips.h @@ -25,16 +25,17 @@ class LIRGeneratorMIPS : public LIRGener bool useBox(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy = LUse::REGISTER, bool useAtStart = false); bool useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2); // x86 has constraints on what registers can be formatted for 1-byte // stores and loads; on MIPS all registers are okay. LAllocation useByteOpRegister(MDefinition *mir); LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir); + LDefinition tempByteOpRegister(); inline LDefinition tempToUnbox() { return LDefinition::BogusTemp(); } bool needTempForPostBarrier() { return false; } // MIPS has a scratch register, so no need for another temp for dispatch @@ -104,16 +105,17 @@ class LIRGeneratorMIPS : public LIRGener bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins); bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins); bool visitForkJoinGetSlice(MForkJoinGetSlice *ins); bool visitSimdTernaryBitwise(MSimdTernaryBitwise *ins); bool visitSimdSplatX4(MSimdSplatX4 *ins); bool visitSimdValueX4(MSimdValueX4 *ins); bool visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins); bool visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins); + bool visitSubstr(MSubstr *ins); }; typedef LIRGeneratorMIPS LIRGeneratorSpecific; } // namespace jit } // namespace js #endif /* jit_mips_Lowering_mips_h */
--- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -1544,21 +1544,21 @@ MacroAssemblerMIPSCompat::callIon(Regist if ((framePushed() & 7) == 4) { ma_callIonHalfPush(callee); } else { adjustFrame(sizeof(uint32_t)); ma_callIon(callee); } } void -MacroAssemblerMIPSCompat::callIonFromAsmJS(Register callee) +MacroAssemblerMIPSCompat::callJitFromAsmJS(Register callee) { ma_callIonNoPush(callee); - // The Ion ABI has the callee pop the return address off the stack. + // The JIT ABI has the callee pop the return address off the stack. // The asm.js caller assumes that the call leaves sp unchanged, so bump // the stack. subPtr(Imm32(sizeof(void*)), StackPointer); } void MacroAssemblerMIPSCompat::reserveStack(uint32_t amount) {
--- a/js/src/jit/mips/MacroAssembler-mips.h +++ b/js/src/jit/mips/MacroAssembler-mips.h @@ -1135,17 +1135,17 @@ public: void callWithExitFrame(Label *target); void callWithExitFrame(JitCode *target); void callWithExitFrame(JitCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // indep code to make a call void callIon(Register callee); - void callIonFromAsmJS(Register callee); + void callJitFromAsmJS(Register callee); void reserveStack(uint32_t amount); void freeStack(uint32_t amount); void freeStack(Register amount); void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -24,16 +24,17 @@ class LIRGeneratorNone : public LIRGener bool useBox(LInstruction *, size_t, MDefinition *, LUse::Policy a = LUse::REGISTER, bool b = false) { MOZ_CRASH(); } bool useBoxFixed(LInstruction *, size_t, MDefinition *, Register, Register) { MOZ_CRASH(); } LAllocation useByteOpRegister(MDefinition *) { MOZ_CRASH(); } LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *) { MOZ_CRASH(); } + LDefinition tempByteOpRegister() { MOZ_CRASH(); } LDefinition tempToUnbox() { MOZ_CRASH(); } bool needTempForPostBarrier() { MOZ_CRASH(); } LDefinition tempForDispatchCache(MIRType v = MIRType_None) { MOZ_CRASH(); } void lowerUntypedPhiInput(MPhi *, uint32_t, LBlock *, size_t) { MOZ_CRASH(); } bool defineUntypedPhi(MPhi *, size_t) { MOZ_CRASH(); } bool lowerForShift(LInstructionHelper<1, 2, 0> *, MDefinition *, MDefinition *, MDefinition *) { MOZ_CRASH(); }
--- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -186,17 +186,17 @@ class MacroAssemblerNone : public Assemb void setupUnalignedABICall(uint32_t, Register) { MOZ_CRASH(); } template <typename T> void passABIArg(T, MoveOp::Type v = MoveOp::GENERAL) { MOZ_CRASH(); } void callWithExitFrame(Label *) { MOZ_CRASH(); } void callWithExitFrame(JitCode *) { MOZ_CRASH(); } void callWithExitFrame(JitCode *, Register) { MOZ_CRASH(); } void callIon(Register callee) { MOZ_CRASH(); } - void callIonFromAsmJS(Register callee) { MOZ_CRASH(); } + void callJitFromAsmJS(Register callee) { MOZ_CRASH(); } void nop() { MOZ_CRASH(); } void breakpoint() { MOZ_CRASH(); } void abiret() { MOZ_CRASH(); } void ret() { MOZ_CRASH(); } CodeOffsetLabel toggledJump(Label *) { MOZ_CRASH(); } CodeOffsetLabel toggledCall(JitCode *, bool) { MOZ_CRASH(); }
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -1200,17 +1200,17 @@ class MacroAssemblerX86Shared : public A } void call(const CallSiteDesc &desc, Register reg) { call(reg); append(desc, currentOffset(), framePushed_); } void callIon(Register callee) { call(callee); } - void callIonFromAsmJS(Register callee) { + void callJitFromAsmJS(Register callee) { call(callee); } void call(AsmJSImmPtr target) { mov(target, eax); call(eax); } void callAndPushReturnAddress(Label *label) { call(label);
--- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -45,16 +45,22 @@ LIRGeneratorX64::useByteOpRegister(MDefi LAllocation LIRGeneratorX64::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir) { return useRegisterOrNonDoubleConstant(mir); } LDefinition +LIRGeneratorX64::tempByteOpRegister() +{ + return temp(); +} + +LDefinition LIRGeneratorX64::tempToUnbox() { return temp(); } bool LIRGeneratorX64::visitBox(MBox *box) { @@ -186,12 +192,24 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAs bool LIRGeneratorX64::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins) { return define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins); } bool +LIRGeneratorX64::visitSubstr(MSubstr *ins) +{ + LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()), + useRegister(ins->begin()), + useRegister(ins->length()), + temp(), + temp(), + tempByteOpRegister()); + return define(lir, ins) && assignSafepoint(lir, ins); +} + +bool LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins) { MOZ_CRASH("NYI"); }
--- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -27,16 +27,17 @@ class LIRGeneratorX64 : public LIRGenera bool useBox(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy = LUse::REGISTER, bool useAtStart = false); bool useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register); // x86 has constraints on what registers can be formatted for 1-byte // stores and loads; on x64 all registers are okay. LAllocation useByteOpRegister(MDefinition *mir); LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir); + LDefinition tempByteOpRegister(); LDefinition tempToUnbox(); bool needTempForPostBarrier() { return false; } // x64 has a scratch register, so no need for another temp for dispatch // ICs. LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) { @@ -48,16 +49,17 @@ class LIRGeneratorX64 : public LIRGenera bool visitUnbox(MUnbox *unbox); bool visitReturn(MReturn *ret); bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins); bool visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins); bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins); bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins); bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins); bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins); + bool visitSubstr(MSubstr *ins); static bool allowInlineForkJoinGetSlice() { return true; } }; typedef LIRGeneratorX64 LIRGeneratorSpecific;
--- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -71,16 +71,22 @@ LIRGeneratorX86::useByteOpRegister(MDefi } LAllocation LIRGeneratorX86::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir) { return useFixed(mir, eax); } +LDefinition +LIRGeneratorX86::tempByteOpRegister() +{ + return tempFixed(eax); +} + bool LIRGeneratorX86::visitBox(MBox *box) { MDefinition *inner = box->getOperand(0); // If the box wrapped a double, it needs a new register. if (IsFloatingPointType(inner->type())) return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0), @@ -304,8 +310,23 @@ LIRGeneratorX86::visitStoreTypedArrayEle return add(lir, ins); } bool LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins) { return define(new(alloc()) LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins); } + +bool +LIRGeneratorX86::visitSubstr(MSubstr *ins) +{ + // Due to lack of registers on x86, we reuse the string register as + // temporary. As a result we only need two temporary registers and take a + // bugos temporary as fifth argument. + LSubstr *lir = new (alloc()) LSubstr(useRegister(ins->string()), + useRegister(ins->begin()), + useRegister(ins->length()), + temp(), + LDefinition::BogusTemp(), + tempByteOpRegister()); + return define(lir, ins) && assignSafepoint(lir, ins); +}
--- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -28,16 +28,17 @@ class LIRGeneratorX86 : public LIRGenera // It's a trap! On x86, the 1-byte store can only use one of // {al,bl,cl,dl,ah,bh,ch,dh}. That means if the register allocator // gives us one of {edi,esi,ebp,esp}, we're out of luck. (The formatter // will assert on us.) Ideally, we'd just ask the register allocator to // give us one of {al,bl,cl,dl}. For now, just useFixed(al). LAllocation useByteOpRegister(MDefinition *mir); LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir); + LDefinition tempByteOpRegister(); inline LDefinition tempToUnbox() { return LDefinition::BogusTemp(); } bool needTempForPostBarrier() { return true; } LDefinition tempForDispatchCache(MIRType outputType = MIRType_None); @@ -50,16 +51,17 @@ class LIRGeneratorX86 : public LIRGenera bool visitUnbox(MUnbox *unbox); bool visitReturn(MReturn *ret); bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins); bool visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins); bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins); bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins); bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins); bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins); + bool visitSubstr(MSubstr *ins); bool lowerPhi(MPhi *phi); static bool allowTypedElementHoleCheck() { return true; } static bool allowStaticTypedArrayAccesses() { return true;
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -555,17 +555,17 @@ FinalizeTypedArenas(FreeOp *fop, ArenaHeader **src, SortedArenaList &dest, AllocKind thingKind, SliceBudget &budget, ArenaLists::KeepArenasEnum keepArenas) { // When operating in the foreground, take the lock at the top. Maybe<AutoLockGC> maybeLock; - if (!fop->runtime()->gc.isBackgroundSweeping()) + if (!fop->onBackgroundThread()) maybeLock.emplace(fop->runtime()); /* * During parallel sections, we sometimes finalize the parallel arenas, * but in that case, we want to hold on to the memory in our arena * lists, not offer it up for reuse. */ MOZ_ASSERT_IF(InParallelSection(), keepArenas); @@ -575,19 +575,19 @@ FinalizeTypedArenas(FreeOp *fop, while (ArenaHeader *aheader = *src) { *src = aheader->next; size_t nmarked = aheader->getArena()->finalize<T>(fop, thingKind, thingSize); size_t nfree = thingsPerArena - nmarked; if (nmarked) { dest.insertAt(aheader, nfree); - } else if (keepArenas) { + } else if (keepArenas == ArenaLists::KEEP_ARENAS) { aheader->chunk()->recycleArena(aheader, dest, thingKind, thingsPerArena); - } else if (fop->runtime()->gc.isBackgroundSweeping()) { + } else if (fop->onBackgroundThread()) { // When background sweeping, take the lock around each release so // that we do not block the foreground for extended periods. AutoLockGC lock(fop->runtime()); fop->runtime()->gc.releaseArena(aheader, lock); } else { fop->runtime()->gc.releaseArena(aheader, maybeLock.ref()); } @@ -1154,17 +1154,16 @@ GCRuntime::GCRuntime(JSRuntime *rt) : isFull(false), #ifdef DEBUG disableStrictProxyCheckingCount(0), #endif incrementalState(gc::NO_INCREMENTAL), lastMarkSlice(false), sweepOnBackgroundThread(false), foundBlackGrayEdges(false), - sweepingZones(nullptr), freeLifoAlloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), zoneGroupIndex(0), zoneGroups(nullptr), currentZoneGroup(nullptr), sweepZone(nullptr), sweepKindIndex(0), abortSweepAfterCurrentGroup(false), arenasAllocatedDuringSweep(nullptr), @@ -2864,47 +2863,49 @@ ArenaLists::queueForBackgroundSweep(Free for (unsigned i = 0; i < phase.length; ++i) queueForBackgroundSweep(fop, phase.kinds[i]); } inline void ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind) { MOZ_ASSERT(IsBackgroundFinalized(thingKind)); - MOZ_ASSERT(!fop->runtime()->gc.isBackgroundSweeping()); ArenaList *al = &arenaLists[thingKind]; if (al->isEmpty()) { MOZ_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE); return; } MOZ_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE); arenaListsToSweep[thingKind] = al->head(); al->clear(); backgroundFinalizeState[thingKind] = BFS_RUN; } /*static*/ void -ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead) +ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, ArenaHeader **empty) { MOZ_ASSERT(listHead); MOZ_ASSERT(!InParallelSection()); + MOZ_ASSERT(empty); AllocKind thingKind = listHead->getAllocKind(); Zone *zone = listHead->zone; size_t thingsPerArena = Arena::thingsPerArena(Arena::thingSize(thingKind)); SortedArenaList finalizedSorted(thingsPerArena); SliceBudget budget; - FinalizeArenas(fop, &listHead, finalizedSorted, thingKind, budget, RELEASE_ARENAS); + FinalizeArenas(fop, &listHead, finalizedSorted, thingKind, budget, KEEP_ARENAS); MOZ_ASSERT(!listHead); + finalizedSorted.extractEmpty(empty); + // When arenas are queued for background finalization, all arenas are moved // to arenaListsToSweep[], leaving the arenaLists[] empty. However, new // arenas may be allocated before background finalization finishes; now that // finalization is complete, we want to merge these lists back together. ArenaLists *lists = &zone->allocator.arenas; ArenaList *al = &lists->arenaLists[thingKind]; // Flatten |finalizedSorted| into a regular ArenaList. @@ -3439,48 +3440,51 @@ GCRuntime::expireChunksAndArenas(bool sh FreeChunkPool(rt, toFree); } if (shouldShrink) decommitArenas(lock); } void -GCRuntime::sweepBackgroundThings() -{ - /* - * We must finalize in the correct order, see comments in - * finalizeObjects. - */ - FreeOp fop(rt); - for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) { - for (Zone *zone = sweepingZones; zone; zone = zone->gcNextGraphNode) { +GCRuntime::sweepBackgroundThings(ZoneList &zones, ThreadType threadType) +{ + // We must finalize thing kinds in the order specified by BackgroundFinalizePhases. + FreeOp fop(rt, threadType); + while (!zones.isEmpty()) { + Zone *zone = zones.front(); + ArenaHeader *emptyArenas = nullptr; + for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) { for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) { AllocKind kind = BackgroundFinalizePhases[phase].kinds[index]; ArenaHeader *arenas = zone->allocator.arenas.arenaListsToSweep[kind]; if (arenas) - ArenaLists::backgroundFinalize(&fop, arenas); + ArenaLists::backgroundFinalize(&fop, arenas, &emptyArenas); } } - } - - sweepingZones = nullptr; + + AutoLockGC lock(rt); + ReleaseArenaList(rt, emptyArenas, lock); + zones.removeFront(); + } } void GCRuntime::assertBackgroundSweepingFinished() { #ifdef DEBUG - MOZ_ASSERT(!sweepingZones); + MOZ_ASSERT(backgroundSweepZones.isEmpty()); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { + MOZ_ASSERT(!zone->isOnList()); for (unsigned i = 0; i < FINALIZE_LIMIT; ++i) { MOZ_ASSERT(!zone->allocator.arenas.arenaListsToSweep[i]); MOZ_ASSERT(zone->allocator.arenas.doneBackgroundFinalize(AllocKind(i))); } } + MOZ_ASSERT(freeLifoAlloc.computedSizeOfExcludingThis() == 0); #endif } unsigned js::GetCPUCount() { static unsigned ncpus = 0; if (ncpus == 0) { @@ -3617,32 +3621,53 @@ BackgroundAllocTask::run() if (!chunk) break; } chunkPool_.push(chunk); } } void -GCHelperState::startBackgroundSweep() -{ - MOZ_ASSERT(CanUseExtraThreads()); - +GCRuntime::queueZonesForBackgroundSweep(ZoneList &zones) +{ AutoLockHelperThreadState helperLock; AutoLockGC lock(rt); - MOZ_ASSERT(state() == IDLE); - MOZ_ASSERT(!sweepFlag); + backgroundSweepZones.append(zones); + helperState.maybeStartBackgroundSweep(lock); +} + +void +GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo) +{ + MOZ_ASSERT(isHeapBusy()); + AutoLockGC lock(rt); + freeLifoAlloc.transferUnusedFrom(lifo); +} + +void +GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo) +{ + MOZ_ASSERT(isHeapBusy()); + AutoLockGC lock(rt); + freeLifoAlloc.transferFrom(lifo); +} + +void +GCHelperState::maybeStartBackgroundSweep(const AutoLockGC &lock) +{ + MOZ_ASSERT(CanUseExtraThreads()); + sweepFlag = true; shrinkFlag = false; - startBackgroundThread(SWEEPING); -} - -/* Must be called with the GC lock taken. */ -void -GCHelperState::startBackgroundShrink() + if (state() == IDLE) + startBackgroundThread(SWEEPING); +} + +void +GCHelperState::startBackgroundShrink(const AutoLockGC &lock) { MOZ_ASSERT(CanUseExtraThreads()); switch (state()) { case IDLE: MOZ_ASSERT(!sweepFlag); shrinkFlag = true; startBackgroundThread(SWEEPING); break; @@ -3662,23 +3687,26 @@ GCHelperState::waitBackgroundSweepEnd() waitForBackgroundThread(); if (rt->gc.incrementalState == NO_INCREMENTAL) rt->gc.assertBackgroundSweepingFinished(); } void GCHelperState::doSweep(AutoLockGC &lock) { - if (sweepFlag) { + while (sweepFlag) { sweepFlag = false; + ZoneList zones; + zones.transferFrom(rt->gc.backgroundSweepZones); + LifoAlloc freeLifoAlloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE); + freeLifoAlloc.transferFrom(&rt->gc.freeLifoAlloc); AutoUnlockGC unlock(lock); - rt->gc.sweepBackgroundThings(); - - rt->gc.freeLifoAlloc.freeAll(); + rt->gc.sweepBackgroundThings(zones, BackgroundThread); + freeLifoAlloc.freeAll(); } bool shrinking = shrinkFlag; rt->gc.expireChunksAndArenas(shrinking, lock); /* * The main thread may have called ShrinkGCBuffers while * ExpireChunksAndArenas(rt, false) was running, so we recheck the flag @@ -3757,68 +3785,58 @@ Zone::sweepCompartments(FreeOp *fop, boo } compartments.resize(write - compartments.begin()); MOZ_ASSERT_IF(keepAtleastOne, !compartments.empty()); } void GCRuntime::sweepZones(FreeOp *fop, bool lastGC) { + AutoLockGC lock(rt); // Avoid race with background sweeping. + JSZoneCallback callback = rt->destroyZoneCallback; /* Skip the atomsCompartment zone. */ Zone **read = zones.begin() + 1; Zone **end = zones.end(); Zone **write = read; MOZ_ASSERT(zones.length() >= 1); MOZ_ASSERT(rt->isAtomsZone(zones[0])); while (read < end) { Zone *zone = *read++; if (zone->wasGCStarted()) { - if ((zone->allocator.arenas.arenaListsAreEmpty() && !zone->hasMarkedCompartments()) || - lastGC) + if ((!zone->isQueuedForBackgroundSweep() && + zone->allocator.arenas.arenaListsAreEmpty() && + !zone->hasMarkedCompartments()) || lastGC) { zone->allocator.arenas.checkEmptyFreeLists(); + AutoUnlockGC unlock(lock); + if (callback) callback(zone); zone->sweepCompartments(fop, false, lastGC); MOZ_ASSERT(zone->compartments.empty()); fop->delete_(zone); continue; } zone->sweepCompartments(fop, true, lastGC); } *write++ = zone; } zones.resize(write - zones.begin()); } void -GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo) -{ - MOZ_ASSERT(isHeapBusy()); - freeLifoAlloc.transferUnusedFrom(lifo); -} - -void -GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo) -{ - MOZ_ASSERT(isHeapBusy()); - freeLifoAlloc.transferFrom(lifo); -} - -void GCRuntime::purgeRuntime() { for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) comp->purge(); - freeUnusedLifoBlocksAfterSweeping(&rt->tempLifoAlloc); rt->interpreterStack().purge(rt); rt->gsnCache.purge(); rt->scopeCoordinateNameCache.purge(); rt->newObjectCache.purge(); rt->nativeIterCache.purge(); rt->uncompressedSourceCache.purge(); @@ -4259,16 +4277,18 @@ js::gc::MarkingValidator::nonIncremental */ if (!map.init()) return; JSRuntime *runtime = gc->rt; GCMarker *gcmarker = &gc->marker; + gc->waitBackgroundSweepEnd(); + /* Save existing mark bits. */ for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) { ChunkBitmap *bitmap = &chunk->bitmap; ChunkBitmap *entry = js_new<ChunkBitmap>(); if (!entry) return; memcpy((void *)entry->bitmap, (void *)bitmap->bitmap, sizeof(bitmap->bitmap)); @@ -4367,16 +4387,18 @@ js::gc::MarkingValidator::validate() /* * Validates the incremental marking for a single compartment by comparing * the mark bits to those previously recorded for a non-incremental mark. */ if (!initialized) return; + gc->waitBackgroundSweepEnd(); + for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) { BitmapMap::Ptr ptr = map.lookup(chunk); if (!ptr) continue; /* Allocated after we did the non-incremental mark. */ ChunkBitmap *bitmap = ptr->value(); ChunkBitmap *incBitmap = &chunk->bitmap; @@ -5164,22 +5186,30 @@ GCRuntime::beginSweepingZoneGroup() gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_END); callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_END); } } void GCRuntime::endSweepingZoneGroup() { - /* Update the GC state for zones we have swept and unlink the list. */ + /* Update the GC state for zones we have swept. */ for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCSweeping()); zone->setGCState(Zone::Finished); } + /* Start background thread to sweep zones if required. */ + if (sweepOnBackgroundThread) { + ZoneList zones; + for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + zones.append(zone); + queueZonesForBackgroundSweep(zones); + } + /* Reset the list of arenas marked as being allocated during sweep phase. */ while (ArenaHeader *arena = arenasAllocatedDuringSweep) { arenasAllocatedDuringSweep = arena->getNextAllocDuringSweep(); arena->unsetAllocDuringSweep(); } } void @@ -5201,17 +5231,17 @@ GCRuntime::beginSweepPhase(bool lastGC) relocatedArenasToRelease = nullptr; #endif computeNonIncrementalMarkingForValidation(); gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP); sweepOnBackgroundThread = - !lastGC && !TraceEnabled() && CanUseExtraThreads() && !shouldCompact(); + !lastGC && !TraceEnabled() && CanUseExtraThreads(); releaseObservedTypes = shouldReleaseObservedTypes(); #ifdef DEBUG for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { MOZ_ASSERT(!c->gcIncomingGrayPointers); for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { if (e.front().key().kind != CrossCompartmentKey::StringWrapper) @@ -5478,28 +5508,24 @@ GCRuntime::endSweepPhase(bool lastGC) gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_END); callFinalizeCallbacks(&fop, JSFINALIZE_COLLECTION_END); /* If we finished a full GC, then the gray bits are correct. */ if (isFull) grayBitsValid = true; } - /* Set up list of zones for sweeping of background things. */ - MOZ_ASSERT(!sweepingZones); - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - zone->gcNextGraphNode = sweepingZones; - sweepingZones = zone; - } - /* If not sweeping on background thread then we must do it here. */ if (!sweepOnBackgroundThread) { gcstats::AutoPhase ap(stats, gcstats::PHASE_DESTROY); - sweepBackgroundThings(); + ZoneList zones; + for (GCZonesIter zone(rt); !zone.done(); zone.next()) + zones.append(zone); + sweepBackgroundThings(zones, MainThread); /* * Destroy arenas after we finished the sweeping so finalizers can * safely use IsAboutToBeFinalized(). This is done on the * GCHelperState if possible. We acquire the lock only because * Expire needs to unlock it for other callers. */ { @@ -5529,29 +5555,37 @@ GCRuntime::endSweepPhase(bool lastGC) MOZ_ASSERT(!c->gcIncomingGrayPointers); for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { if (e.front().key().kind != CrossCompartmentKey::StringWrapper) AssertNotOnGrayList(&e.front().value().unbarrieredGet().toObject()); } } #endif - - if (sweepOnBackgroundThread) - helperState.startBackgroundSweep(); -} - -#ifdef JSGC_COMPACTING -void +} + +bool GCRuntime::compactPhase(bool lastGC) { +#ifndef JSGC_COMPACTING + MOZ_CRASH(); +#else + gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT); + + if (isIncremental) { + // Poll for end of background sweeping + AutoLockGC lock(rt); + if (isBackgroundSweeping()) + return false; + } else { + waitBackgroundSweepEnd(); + } + MOZ_ASSERT(rt->gc.nursery.isEmpty()); - MOZ_ASSERT(!sweepOnBackgroundThread); - - gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT); + assertBackgroundSweepingFinished(); ArenaHeader *relocatedList = relocateArenas(); updatePointersToRelocatedCells(); #ifdef DEBUG for (ArenaHeader *arena = relocatedList; arena; arena = arena->next) { for (ArenaCellIterUnderFinalize i(arena); !i.done(); i.next()) { TenuredCell *src = i.getCell(); @@ -5578,18 +5612,20 @@ GCRuntime::compactPhase(bool lastGC) #ifdef DEBUG CheckHashTablesAfterMovingGC(rt); for (GCZonesIter zone(rt); !zone.done(); zone.next()) { if (CanRelocateZone(rt, zone) && !zone->isPreservingCode()) zone->allocator.arenas.checkEmptyFreeLists(); } #endif -} + #endif // JSGC_COMPACTING + return true; +} void GCRuntime::finishCollection() { MOZ_ASSERT(marker.isDrained()); marker.stop(); uint64_t currentTime = PRMJ_Now(); @@ -5705,16 +5741,18 @@ GCRuntime::resetIncrementalGC(const char for (GCZonesIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCMarking()); zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); zone->setGCState(Zone::NoGC); } rt->setNeedsIncrementalBarrier(false); AssertNeedsBarrierFlagsConsistent(rt); + freeLifoAlloc.freeAll(); + incrementalState = NO_INCREMENTAL; MOZ_ASSERT(!marker.shouldCheckCompartments()); break; } case SWEEP: { @@ -5730,16 +5768,21 @@ GCRuntime::resetIncrementalGC(const char { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); rt->gc.waitBackgroundSweepOrAllocEnd(); } break; } +#ifdef JSGC_COMPACTING + case COMPACT: + break; +#endif + default: MOZ_CRASH("Invalid incremental GC state"); } stats.reset(reason); #ifdef DEBUG for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { @@ -5922,34 +5965,41 @@ GCRuntime::incrementalCollectSlice(Slice * mode, so RunDebugGC can reset the slice buget. */ if (isIncremental && zeal == ZealIncrementalMultipleSlices) break; /* fall through */ } - case SWEEP: { - bool finished = sweepPhase(budget); - if (!finished) - break; + case SWEEP: + { + bool finished = sweepPhase(budget); + if (!finished) + break; + } endSweepPhase(lastGC); -#ifdef JSGC_COMPACTING + incrementalState = COMPACT; + + /* Yield before compacting since it is not incremental. */ + if (shouldCompact() && isIncremental) + break; + + case COMPACT: if (shouldCompact()) { - incrementalState = COMPACT; - compactPhase(lastGC); + bool finished = compactPhase(lastGC); + if (!finished) + break; } -#endif finishCollection(); incrementalState = NO_INCREMENTAL; break; - } default: MOZ_ASSERT(false); } } IncrementalSafety gc::IsIncrementalGCSafe(JSRuntime *rt) @@ -6073,19 +6123,18 @@ GCRuntime::gcCycle(bool incremental, Sli MOZ_ASSERT(!rt->mainThread.suppressGC); // Assert if this is a GC unsafe region. JS::AutoAssertOnGC::VerifyIsSafeToGC(rt); { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); - // As we are about to purge caches and clear the mark bits, wait for - // background finalization to finish. It cannot run between slices - // so we only need to wait on the first slice. + // As we are about to clear the mark bits, wait for background + // finalization to finish. We only need to wait on the first slice. if (incrementalState == NO_INCREMENTAL) waitBackgroundSweepEnd(); // We must also wait for background allocation to finish so we can // avoid taking the GC lock when manipulating the chunks during the GC. // The background alloc task can run between slices, so we must wait // for it at the start of every slice. allocTask.cancel(GCParallelTask::CancelAndWait); @@ -6384,17 +6433,17 @@ JS::ShrinkGCBuffers(JSRuntime *rt) void GCRuntime::shrinkBuffers() { AutoLockHelperThreadState helperLock; AutoLockGC lock(rt); MOZ_ASSERT(!rt->isHeapBusy()); if (CanUseExtraThreads()) - helperState.startBackgroundShrink(); + helperState.startBackgroundShrink(lock); else expireChunksAndArenas(true, lock); } void GCRuntime::onOutOfMallocMemory() { // Stop allocating new chunks.
--- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -34,32 +34,36 @@ unsigned GetCPUCount(); enum HeapState { Idle, // doing nothing with the GC heap Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() MajorCollecting, // doing a GC of the major heap MinorCollecting // doing a GC of the minor heap (nursery) }; +enum ThreadType +{ + MainThread, + BackgroundThread +}; + namespace jit { class JitCode; } namespace gc { struct FinalizePhase; enum State { NO_INCREMENTAL, MARK_ROOTS, MARK, SWEEP, -#ifdef JSGC_COMPACTING COMPACT -#endif }; /* Return a printable string for the given kind, for diagnostic purposes. */ const char * TraceKindAsAscii(JSGCTraceKind kind); /* Map from C++ type to alloc kind. JSObject does not have a 1:1 mapping, so must use Arena::thingSize. */ template <typename T> struct MapTypeToFinalizeKind {}; @@ -840,17 +844,17 @@ class ArenaLists void queueForegroundObjectsForSweep(FreeOp *fop); void queueForegroundThingsForSweep(FreeOp *fop); void mergeForegroundSweptObjectArenas(); bool foregroundFinalize(FreeOp *fop, AllocKind thingKind, SliceBudget &sliceBudget, SortedArenaList &sweepList); - static void backgroundFinalize(FreeOp *fop, ArenaHeader *listHead); + static void backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, ArenaHeader **empty); void wipeDuringParallelExecution(JSRuntime *rt); // When finalizing arenas, whether to keep empty arenas on the list or // release them immediately. enum KeepArenasEnum { RELEASE_ARENAS, KEEP_ARENAS @@ -1035,21 +1039,18 @@ class GCHelperState shrinkFlag(false) { } bool init(); void finish(); void work(); - /* Must be called with the GC lock taken. */ - void startBackgroundSweep(); - - /* Must be called with the GC lock taken. */ - void startBackgroundShrink(); + void maybeStartBackgroundSweep(const AutoLockGC &lock); + void startBackgroundShrink(const AutoLockGC &lock); /* Must be called without the GC lock taken. */ void waitBackgroundSweepEnd(); bool onBackgroundThread(); /* * Outside the GC lock may give true answer when in fact the sweeping has @@ -1452,16 +1453,44 @@ class AutoEnterOOMUnsafeRegion {}; #endif /* DEBUG */ // This tests whether something is inside the GGC's nursery only; // use sparingly, mostly testing for any nursery, using IsInsideNursery, // is appropriate. bool IsInsideGGCNursery(const gc::Cell *cell); +// A singly linked list of zones. +class ZoneList +{ + static Zone * const End; + + Zone *head; + Zone *tail; + + public: + ZoneList(); + explicit ZoneList(Zone *singleZone); + + bool isEmpty() const; + Zone *front() const; + + void append(Zone *zone); + void append(ZoneList& list); + Zone *removeFront(); + + void transferFrom(ZoneList &other); + + private: + void check() const; + + ZoneList(const ZoneList &other) MOZ_DELETE; + ZoneList &operator=(const ZoneList &other) MOZ_DELETE; +}; + } /* namespace gc */ #ifdef DEBUG /* Use this to avoid assertions when manipulating the wrapper map. */ class AutoDisableProxyCheck { MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER; gc::GCRuntime &gc;
--- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -359,31 +359,36 @@ class NewObjectCache * convenience methods that also call destructors. * * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not * need to pass a JSContext to those hooks. */ class FreeOp : public JSFreeOp { Vector<void *, 0, SystemAllocPolicy> freeLaterList; + ThreadType threadType; public: static FreeOp *get(JSFreeOp *fop) { return static_cast<FreeOp *>(fop); } - explicit FreeOp(JSRuntime *rt) - : JSFreeOp(rt) + explicit FreeOp(JSRuntime *rt, ThreadType thread = MainThread) + : JSFreeOp(rt), threadType(thread) {} ~FreeOp() { for (size_t i = 0; i < freeLaterList.length(); i++) free_(freeLaterList[i]); } + bool onBackgroundThread() { + return threadType == BackgroundThread; + } + inline void free_(void *p); inline void freeLater(void *p); template <class T> inline void delete_(T *p) { if (p) { p->~T(); free_(p);
--- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1944,21 +1944,23 @@ nsDisplaySolidColor::Paint(nsDisplayList DrawTarget* drawTarget = aCtx->GetDrawTarget(); Rect rect = NSRectToSnappedRect(mVisibleRect, appUnitsPerDevPixel, *drawTarget); drawTarget->FillRect(rect, ColorPattern(ToDeviceColor(mColor))); } #ifdef MOZ_DUMP_PAINTING void -nsDisplaySolidColor::WriteDebugInfo(nsACString& aTo) -{ - aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", - NS_GET_R(mColor), NS_GET_G(mColor), - NS_GET_B(mColor), NS_GET_A(mColor)); +nsDisplaySolidColor::WriteDebugInfo(std::stringstream& aStream) +{ + aStream << " (rgba " + << (int)NS_GET_R(mColor) << "," + << (int)NS_GET_G(mColor) << "," + << (int)NS_GET_B(mColor) << "," + << (int)NS_GET_A(mColor) << ")"; } #endif static void RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) { if (!aBuilder->IsInSubdocument() && !aBuilder->IsInTransform()) { nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame); @@ -2658,19 +2660,19 @@ nsDisplayThemedBackground::~nsDisplayThe { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_DTOR(nsDisplayThemedBackground); #endif } #ifdef MOZ_DUMP_PAINTING void -nsDisplayThemedBackground::WriteDebugInfo(nsACString& aTo) -{ - aTo += nsPrintfCString(" (themed, appearance:%d)", mAppearance); +nsDisplayThemedBackground::WriteDebugInfo(std::stringstream& aStream) +{ + aStream << " (themed, appearance:" << (int)mAppearance << ")"; } #endif void nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) @@ -2863,21 +2865,20 @@ nsDisplayBackgroundColor::HitTest(nsDisp return; } aOutFrames->AppendElement(mFrame); } #ifdef MOZ_DUMP_PAINTING void -nsDisplayBackgroundColor::WriteDebugInfo(nsACString& aTo) -{ - aTo += nsPrintfCString(" (rgba %f,%f,%f,%f)", - mColor.r, mColor.g, - mColor.b, mColor.a); +nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream& aStream) +{ + aStream << " (rgba " << mColor.r << "," << mColor.g << "," + << mColor.b << "," << mColor.a << ")"; } #endif already_AddRefed<Layer> nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aParameters) { @@ -2982,16 +2983,32 @@ nsDisplayLayerEventRegions::AddFrame(nsD } void nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect& aRect) { mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aRect); } +#ifdef MOZ_DUMP_PAINTING +void +nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream& aStream) +{ + if (!mHitRegion.IsEmpty()) { + AppendToString(aStream, mHitRegion, " (hitRegion ", ")"); + } + if (!mMaybeHitRegion.IsEmpty()) { + AppendToString(aStream, mMaybeHitRegion, " (maybeHitRegion ", ")"); + } + if (!mDispatchToContentHitRegion.IsEmpty()) { + AppendToString(aStream, mDispatchToContentHitRegion, " (dispatchToContentRegion ", ")"); + } +} +#endif + nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame) : nsDisplayItem(aBuilder, aCaretFrame) , mCaret(aBuilder->GetCaret()) , mBounds(aBuilder->GetCaretRect() + ToReferenceFrame()) { MOZ_COUNT_CTOR(nsDisplayCaret); } @@ -3673,19 +3690,19 @@ bool nsDisplayOpacity::TryMerge(nsDispla if (aItem->GetClip() != GetClip()) return false; MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem)); return true; } #ifdef MOZ_DUMP_PAINTING void -nsDisplayOpacity::WriteDebugInfo(nsACString& aTo) -{ - aTo += nsPrintfCString(" (opacity %f)", mOpacity); +nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream) +{ + aStream << " (opacity " << mOpacity << ")"; } #endif nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, uint32_t aFlags) : nsDisplayWrapList(aBuilder, aFrame, aList) { MOZ_COUNT_CTOR(nsDisplayMixBlendMode); @@ -4438,20 +4455,20 @@ nsDisplayScrollLayer::GetScrollLayerCoun return result; #else return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount())); #endif } #ifdef MOZ_DUMP_PAINTING void -nsDisplayScrollLayer::WriteDebugInfo(nsACString& aTo) -{ - aTo += nsPrintfCString(" (scrollframe %p scrolledframe %p)", - mScrollFrame, mScrolledFrame); +nsDisplayScrollLayer::WriteDebugInfo(std::stringstream& aStream) +{ + aStream << " (scrollframe " << mScrollFrame + << " scrolledFrame " << mScrolledFrame << ")"; } #endif nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer( nsDisplayListBuilder* aBuilder, nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame) : nsDisplayScrollLayer(aBuilder, aScrollFrame, aScrolledFrame, aScrollFrame) @@ -5626,21 +5643,19 @@ bool nsDisplayTransform::UntransformVisi *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result), factor); return true; } #ifdef MOZ_DUMP_PAINTING void -nsDisplayTransform::WriteDebugInfo(nsACString& aTo) -{ - std::stringstream ss; - AppendToString(ss, GetTransform()); - aTo += ss.str().c_str(); +nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream) +{ + AppendToString(aStream, GetTransform()); } #endif nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) : nsDisplayWrapList(aBuilder, aFrame, aList), mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf()) {
--- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1340,17 +1340,17 @@ public: } #ifdef MOZ_DUMP_PAINTING /** * For debugging and stuff */ virtual const char* Name() = 0; - virtual void WriteDebugInfo(nsACString& aTo) {} + virtual void WriteDebugInfo(std::stringstream& aStream) {} #endif nsDisplayItem* GetAbove() { return mAbove; } /** * Like ComputeVisibility, but does the work that nsDisplayList * does per-item: * -- Intersects GetBounds with aVisibleRegion and puts the result @@ -2160,17 +2160,17 @@ public: bool dummy; aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); return; } ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); } #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR) private: nsRect mBounds; nscolor mColor; }; @@ -2321,17 +2321,17 @@ public: return new nsDisplayThemedBackgroundGeometry(this, aBuilder); } virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) MOZ_OVERRIDE; #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif protected: nsRect GetBoundsInternal(); void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, const nsRect& aBounds, nsRect* aClipRect); nsRect mBounds; @@ -2384,17 +2384,17 @@ public: aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); return; } ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); } NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR) #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif protected: const nsStyleBackground* mBackgroundStyle; gfxRGBA mColor; }; class nsDisplayClearBackground : public nsDisplayItem @@ -2624,16 +2624,20 @@ public: // dispatch-to-content region, to ensure that APZ lets content create a // displayport. void AddInactiveScrollPort(const nsRect& aRect); const nsRegion& HitRegion() { return mHitRegion; } const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; } const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; } +#ifdef MOZ_DUMP_PAINTING + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; +#endif + private: // Relative to aFrame's reference frame. // These are the points that are definitely in the hit region. nsRegion mHitRegion; // These are points that may or may not be in the hit region. Only main-thread // event handling can tell for sure (e.g. because complex shapes are present). nsRegion mMaybeHitRegion; // These are points that need to be dispatched to the content thread for @@ -2829,17 +2833,17 @@ public: } virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity, const DisplayItemClip* aClip) MOZ_OVERRIDE; virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder); NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; private: float mOpacity; }; @@ -3127,17 +3131,17 @@ public: // number does not include nsDisplayScrollInfoLayers. If this number is not 1 // after merging, all the nsDisplayScrollLayers should flatten away. intptr_t GetScrollLayerCount(); virtual nsIFrame* GetScrollFrame() { return mScrollFrame; } virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; } #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif bool IsDisplayPortOpaque() { return mDisplayPortContentsOpaque; } static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame, nsIFrame* aScrollFrame, const nsIFrame* aReferenceFrame, Layer* aLayer, @@ -3538,17 +3542,17 @@ public: bool MaybePrerender() const { return mMaybePrerender; } /** * Check if this element will be prerendered. This must be done after the * display list has been fully built. */ bool ShouldPrerender(nsDisplayListBuilder* aBuilder); #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif private: void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder); void Init(nsDisplayListBuilder* aBuilder); static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, const nsPoint& aOrigin,
--- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -186,19 +186,17 @@ PrintDisplayItemTo(nsDisplayListBuilder* aStream << ","; } aStream << NS_LossyConvertUTF16toASCII(aItem->Frame()->StyleDisplay()->mWillChange[i]).get(); } aStream << ")"; } // Display item specific debug info - nsCString itemStr; - aItem->WriteDebugInfo(itemStr); - aStream << itemStr.get(); + aItem->WriteDebugInfo(aStream); if (aDumpHtml && aItem->Painted()) { aStream << "</a>"; } uint32_t key = aItem->GetPerFrameKey(); Layer* layer = mozilla::FrameLayerBuilder::GetDebugOldLayerFor(f, key); if (layer) { if (aDumpHtml) {
--- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -281,21 +281,23 @@ nsDisplayCanvasBackgroundColor::Paint(ns Rect devPxRect = NSRectToSnappedRect(bgClipRect, appUnitsPerDevPixel, *drawTarget); drawTarget->FillRect(devPxRect, ColorPattern(ToDeviceColor(mColor))); } } #ifdef MOZ_DUMP_PAINTING void -nsDisplayCanvasBackgroundColor::WriteDebugInfo(nsACString& aTo) +nsDisplayCanvasBackgroundColor::WriteDebugInfo(std::stringstream& aStream) { - aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", - NS_GET_R(mColor), NS_GET_G(mColor), - NS_GET_B(mColor), NS_GET_A(mColor)); + aStream << " (rgba " + << (int)NS_GET_R(mColor) << "," + << (int)NS_GET_G(mColor) << "," + << (int)NS_GET_B(mColor) << "," + << (int)NS_GET_A(mColor) << ")"; } #endif static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource) { RefPtr<SourceSurface> source = aSource->Snapshot(); aDest->DrawSurface(source, Rect(aRect.x, aRect.y, aRect.width, aRect.height),
--- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -209,17 +209,17 @@ public: void SetExtraBackgroundColor(nscolor aColor) { mColor = aColor; } NS_DISPLAY_DECL_NAME("CanvasBackgroundColor", TYPE_CANVAS_BACKGROUND_COLOR) #ifdef MOZ_DUMP_PAINTING - virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; + virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE; #endif private: nscolor mColor; }; class nsDisplayCanvasBackgroundImage : public nsDisplayBackgroundImage { public:
--- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1448,19 +1448,17 @@ nsDisplayImage::GetLayerState(nsDisplayL } /* virtual */ nsRegion nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) { *aSnap = true; - bool animated; - if (mImage && mImage->GetAnimated(&animated) == NS_OK && !animated && - mImage->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) { + if (mImage && mImage->IsOpaque()) { // OK, the entire region painted by the image is opaque. But what is that // region? It's the image's "dest rect" (the rect where a full copy of // the image is mapped), clipped to the container's content box (which is // what GetBounds() returns). So, we grab those rects and intersect them. const nsRect frameContentBox = GetBounds(aSnap); // Note: To get the "dest rect", we have to provide the "constraint rect" // (which is the content-box, with the effects of fragmentation undone).
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2049,18 +2049,18 @@ nsStyleImage::IsOpaque() const return false; NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type"); nsCOMPtr<imgIContainer> imageContainer; mImage->GetImage(getter_AddRefs(imageContainer)); NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready"); - // Check if the crop region of the current image frame is opaque. - if (imageContainer->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) { + // Check if the crop region of the image is opaque. + if (imageContainer->IsOpaque()) { if (!mCropRect) return true; // Must make sure if mCropRect contains at least a pixel. // XXX Is this optimization worth it? Maybe I should just return false. nsIntRect actualCropRect; bool rv = ComputeActualCropRect(actualCropRect); NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
--- a/netwerk/streamconv/converters/ParseFTPList.cpp +++ b/netwerk/streamconv/converters/ParseFTPList.cpp @@ -718,17 +718,17 @@ int ParseFTPList(const char *line, struc /* * "10-23-00 01:27PM <DIR> veronist" * "06-15-00 07:37AM <DIR> zoe" * "07-14-00 01:35PM 2094926 canprankdesk.tif" * "07-21-00 01:19PM 95077 Jon Kauffman Enjoys the Good Life.jpg" * "07-21-00 01:19PM 52275 Name Plate.jpg" * "07-14-00 01:38PM 2250540 Valentineoffprank-HiRes.jpg" */ - if ((numtoks >= 4) && toklen[0] == 8 && toklen[1] == 7 && + if ((numtoks >= 4) && (toklen[0] == 8 || toklen[0] == 10) && toklen[1] == 7 && (*tokens[2] == '<' || isdigit(*tokens[2])) ) { p = tokens[0]; if ( isdigit(p[0]) && isdigit(p[1]) && p[2]=='-' && isdigit(p[3]) && isdigit(p[4]) && p[5]=='-' && isdigit(p[6]) && isdigit(p[7]) ) { p = tokens[1];
--- a/security/certverifier/ExtendedValidation.cpp +++ b/security/certverifier/ExtendedValidation.cpp @@ -1002,16 +1002,99 @@ static struct nsMyTrustedEVInfo myTruste SEC_OID_UNKNOWN, { 0x8F, 0xE4, 0xFB, 0x0A, 0xF9, 0x3A, 0x4D, 0x0D, 0x67, 0xDB, 0x0B, 0xEB, 0xB2, 0x3E, 0x37, 0xC7, 0x1B, 0xF3, 0x25, 0xDC, 0xBC, 0xDD, 0x24, 0x0E, 0xA0, 0x4D, 0xAF, 0x58, 0xB4, 0x7E, 0x18, 0x40 }, "MEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYD" "VQQDExVRdW9WYWRpcyBSb290IENBIDIgRzM=", "RFc0JFuBiZs18s64KztbpybwdSg=", nullptr + }, + { + // CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB + "1.3.6.1.4.1.6449.1.2.1.5.1", + "COMODORSACertificationAuthority", + SEC_OID_UNKNOWN, + { 0x52, 0xF0, 0xE1, 0xC4, 0xE5, 0x8E, 0xC6, 0x29, 0x29, 0x1B, 0x60, + 0x31, 0x7F, 0x07, 0x46, 0x71, 0xB8, 0x5D, 0x7E, 0xA8, 0x0D, 0x5B, + 0x07, 0x27, 0x34, 0x63, 0x53, 0x4B, 0x32, 0xB4, 0x02, 0x34 }, + "MIGFMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAw" + "DgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDErMCkG" + "A1UEAxMiQ09NT0RPIFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==", + "TKr5yttjb+Af907YWwOGnQ==", + nullptr + }, + { + // CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US + "1.3.6.1.4.1.6449.1.2.1.5.1", + "USERTrustRSACertificationAuthority", + SEC_OID_UNKNOWN, + { 0xE7, 0x93, 0xC9, 0xB0, 0x2F, 0xD8, 0xAA, 0x13, 0xE2, 0x1C, 0x31, + 0x22, 0x8A, 0xCC, 0xB0, 0x81, 0x19, 0x64, 0x3B, 0x74, 0x9C, 0x89, + 0x89, 0x64, 0xB1, 0x74, 0x6D, 0x46, 0xC3, 0xD4, 0xCB, 0xD2 }, + "MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxML" + "SmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwG" + "A1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==", + "Af1tMPyjylGoG7xkDjUDLQ==", + nullptr + }, + { + // CN=USERTrust ECC Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US + "1.3.6.1.4.1.6449.1.2.1.5.1", + "USERTrust ECC Certification Authority", + SEC_OID_UNKNOWN, + { 0x4F, 0xF4, 0x60, 0xD5, 0x4B, 0x9C, 0x86, 0xDA, 0xBF, 0xBC, 0xFC, + 0x57, 0x12, 0xE0, 0x40, 0x0D, 0x2B, 0xED, 0x3F, 0xBC, 0x4D, 0x4F, + 0xBD, 0xAA, 0x86, 0xE0, 0x6A, 0xDC, 0xD2, 0xA9, 0xAD, 0x7A }, + "MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxML" + "SmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwG" + "A1UEAxMlVVNFUlRydXN0IEVDQyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==", + "XIuZxVqUxdJxVt7NiYDMJg==", + nullptr + }, + { + // CN=GlobalSign,O=GlobalSign,OU=GlobalSign ECC Root CA - R4 + "1.3.6.1.4.1.4146.1.1", + "GlobalSign ECC Root CA - R4", + SEC_OID_UNKNOWN, + { 0xBE, 0xC9, 0x49, 0x11, 0xC2, 0x95, 0x56, 0x76, 0xDB, 0x6C, 0x0A, + 0x55, 0x09, 0x86, 0xD7, 0x6E, 0x3B, 0xA0, 0x05, 0x66, 0x7C, 0x44, + 0x2C, 0x97, 0x62, 0xB4, 0xFB, 0xB7, 0x73, 0xDE, 0x22, 0x8C }, + "MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNDETMBEGA1UE" + "ChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==", + "KjikHJYKBN5CsiilC+g0mAI=", + nullptr + }, + { + // CN=GlobalSign,O=GlobalSign,OU=GlobalSign ECC Root CA - R5 + "1.3.6.1.4.1.4146.1.1", + "GlobalSign ECC Root CA - R5", + SEC_OID_UNKNOWN, + { 0x17, 0x9F, 0xBC, 0x14, 0x8A, 0x3D, 0xD0, 0x0F, 0xD2, 0x4E, 0xA1, + 0x34, 0x58, 0xCC, 0x43, 0xBF, 0xA7, 0xF5, 0x9C, 0x81, 0x82, 0xD7, + 0x83, 0xA5, 0x13, 0xF6, 0xEB, 0xEC, 0x10, 0x0C, 0x89, 0x24 }, + "MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNTETMBEGA1UE" + "ChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==", + "YFlJ4CYuu1X5CneKcflK2Gw=", + nullptr + }, + { + // CN=Entrust.net Certification Authority (2048),OU=(c) 1999 Entrust.net Limited,OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),O=Entrust.net + "2.16.840.1.114028.10.1.2", + "EntrustCA2048", + SEC_OID_UNKNOWN, + { 0x6D, 0xC4, 0x71, 0x72, 0xE0, 0x1C, 0xBC, 0xB0, 0xBF, 0x62, 0x58, + 0x0D, 0x89, 0x5F, 0xE2, 0xB8, 0xAC, 0x9A, 0xD4, 0xF8, 0x73, 0x80, + 0x1E, 0x0C, 0x10, 0xB9, 0xC8, 0x37, 0xD2, 0x1E, 0xB1, 0x77 }, + "MIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3Qu" + "bmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMG" + "A1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50" + "cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp", + "OGPe+A==", + nullptr } }; static SECOidTag register_oid(const SECItem* oid_item, const char* oid_name) { if (!oid_item) return SEC_OID_UNKNOWN;
--- a/security/manager/ssl/tests/unit/test_ocsp_fetch_method.js +++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method.js @@ -8,17 +8,17 @@ // In which we try to validate several ocsp responses, checking in particular // that we use the specified method for fetching ocsp. We also check what // POST fallback when an invalid GET response is received. do_get_profile(); // must be called before getting nsIX509CertDB const certdb = Cc["@mozilla.org/security/x509certdb;1"] .getService(Ci.nsIX509CertDB); -const SERVER_PORT = 8080; +const SERVER_PORT = 8888; function start_ocsp_responder(expectedCertNames, expectedPaths, expectedMethods) { return startOCSPResponder(SERVER_PORT, "www.example.com", [], "test_ocsp_fetch_method", expectedCertNames, expectedPaths, expectedMethods); }
index a8a0f65507efd184ddb5e22f31dd6250825f34b1..48b71256a6befd2675b22410362d6bc5d6160464 GIT binary patch literal 898 zc$_n6Vy-i2VoF=U%*4pV#LOMB!GM>IQ>)FR?K>|cBR4C9L7XAC0Vf-CC<~h~Q)sZE zuz?_m!y(M&oS2iDmS2>YnP@0xAOaF(7v}ZNFU>1S%*;~=%S<gd6fqD2iE{~a2L$^n zgrpXiWagzC@)&S|M45$|GxJIe<ivRmO$-f<3=K?;42+GV#CeU7xdt&*x1Y;^17bg8 zqCpd*60(OGSs9p{82K51;#^EkjEoE`qE04UziDZv`ypaC6PIK0a=%-u%T^h)2TK^8 zYw5A<?%mm8a_r~lB>qW@L)@FDX9h<t+wpei>9au#qa^Mf=$^(aZV}7)rCs5C9nXhT z%dLvuKY6+5ZQ)a~g2LX3`!5Kc_-Ik{WkcHKg{9kKZ=QP*dcoyk$DGufV3o2*^Rif< z>ppF1T;yoceg1^f(|JtaZRUpl%6C3?zGPo;RL033UBSiY_Qa}Aezxkk!;A1|yN(22 zd44y1^2*AlD6eZ5Rvwl9*8F%;pRh=8f|hsN_uY>KZQe^yotw6M_B6Re97}q3F|h9w zKA<vF(laocvvW(Ga%))3MepX)7f0ooSQWZ+njWb;Rx>d(GB7T7H*htuVB^qcV`ODz zXJlm2G0-y5fbk6&+hj6IN(!v>^~=l4^-?Pma|?1(^^)^*tt@~*9~^tK!YoV%3}|VK z85F{6m+#&q7{wNM#JggzjOv_qxhw`+$}(XuecJD9>;LpgJ`wADso8t7jrv^I36+A} z$1WLu{A%&r!|LuM?{BK%pZhCIr))j*T6jifRMM9{7d80<KL5*lnHRsQ+2rQQD*o*M ziv_*8=ZWcw9N(mM)F81aSx>?3zTBMDim<s^8%@ktGF`A^@lLPIub)?ZDPZ^6<ue$b z$ehUS+PL|6ZoKznp;YhHe#TkFoC2S=C|&p+DXc7_7Z$d1iPJq@k>Yjx_HMpsWFa0e z-@~>e&zbei<O$0bd{;d4J$HZOb?Xe)@5xz46^A>YbDdcczG2@-f!MF}O9kqeF&<hu QC&M&krgvY|f^VF^0V?H50RR91
index b488321fb0868281225a2cfcd2cf79afee9d4d14..b7a751f540da98e11903956f1413ed14611a5701 GIT binary patch literal 899 zc$_n6Vy-u6VoG1Y%*4pV#KN%8_@V(X8>d#AN85K^Mn-N{27@?5ZUas>=1>+kVW!Yv zLtz6!5QjsU%Q-P8GcCU;FEi0l%s>Pr$S%z5n_rq&l9-vN5SE!*ZYW|P1QO>G<_-w< zRR~EfF3HSGH{>zk0*NvUGiT<N7|4n98k!gy8W|dx8W|XyMv3zpA#)94sBS-(0SCl> z#w3F#MkQnqGqN%;H!<=v0L8hOniv@wPIA66cJi53DSOXGuksJWopn9W&*a@Sc~fv} zqnL1+!htnK(;g&DQ#IJVjAtXyHTk^o2GNXrUwbF0J~%Z&K<Lb;($X*AmTs`y%)4AZ zOhWN;%A=<xMSuUrXnvox(!2TwV~W9>1&O;1-x<`s`XKn5Eo;H{D(*!GSK60H%>Vr^ zGP3LWY^R>76`xj~J-m0%35D}D;-a3?4-02~Qh1PfXzixn>rKrE)lxdQ*d#1Hlh<-C zw?yZJ$0oU4t(2n)pU#%&g=D`K>szQ}*BN@j&#cDwK!R<N_@$7y9p#SSa?h_5V>tiz z^5Q^-=G_PFt%`Wp8@Nx9npZtpDdE^H?FaMtguk5$m*`|-W@KPo>~7#{V8O<r&Bn;e z%Ff8hqGO<CpaJ6>Ft*8Ll#~=$>Fbx5m+PfgB<2?6r0ON-=UQ0+fj&6)WQAFn3>eVT z7BeV><Cn6z|A@YQFX(<@j$s=s`&EN89W2Wa-w8OtTHJPI$*haIKU^Y&o~}7xGiT{N zuX5Md!Yd2+w#|r3+5Ivzxwb~{*t%e&xUP8~MYEPa+L|0IDO?{_@pNxA*HN>Y#t9L3 z=1Z}@?P=K3f9$r_qee}Ic|9GE9M*)aRMIjxnV>em@UwcXEW7ijM&9pRCLUuA{FLh} zX<eN2pH-p5ZL-y(^GB~s{8isNnWgXEj}<;GAG&vBYp(jK+I{o>oT7B`8;dn1)@5IJ z&=(as`tgMDsT17Np)waP3(Tya&Ycp(_)MPH-iV3QCBETOO6%T3ykcQ9H|9s$mRIhI SSQetuyYWx1!};&$&H@0nuS-4v
index a100132d1e0591f7d795b8cd2170f5b70cb56fe1..20e8db54b0893a46b85356ab5c59bdd83cdd4e9f GIT binary patch literal 845 zc$_n6V)is>VlrI7%*4pV#LBRc>vMnsFB_*;n@8JsUPeZ4RtAGuLv903Hs(+kHesgF zU_)U8K@f*Sn9DgaCo?U-C@(Y7P|QFCB*-qz>ziMiSCW{Srx2EzT5c#}AOsTU66OvF z_EiW;EiTE-ONW`qEX<UgXdoxfYiMF<Xk=($YGhz+7$weYgv_P2^-YXQ$R1{7WngY% z<Yxeib1^kBGBP~iZC0F_^=y&ir+rTQKP&C&RWn)r=-Im1pL>pZiEI<Ge=R6nx^a`l z6UIHyXP!RC@tjX#t&hY<Z`QY*0m+HZY!7Q^@T?6`cqA6-93&sNI#!p{^WB}i|E7HJ z)4b-Esb{PapFfj@CH#%tt1IP_4=#m$d*Rf~<g_lnV*zj6yUFHp9~Z9vI%~_ORQ&*f z2*v-*d0pO4e?{x>eXel2vO%ppVs+08#aq{ZmvUE!n8z=3uM9KY(WZN+yC-JeRj#>* zrgyp}B_{7%|9<(QgpO6pe?uNwxfw3-Ty$)UdE1S1sXbCFCtdi+_4&?Yzgo^&|3lrj zxb9}$%6iR4?VnBDv_%e=Ed6V@GchwVFfJA_;4|O>2AZre3#$P$BjbOxM8XUTs<n;3 ztfe|;^Ca>fn9TI^-E^%hn|}s|7~C}0*&us4Z3};|(Ua)4{K4DK&9aue7$q2DddbGV zxW+l-mC*gGw-3)s;hgEz5w&)zSIt)ApA1_JH%^X<{!re%GS~C4(H*rz%KiS6=CJB) zNGt9&oO77BSYN70=eE&QS9|ZUOHbrZI_IT@*IX@I!g2cfwMnWxMZI@(Yl|-|j+pdV zuSVCqYU|83_J@7u@I+qklFz7((n*_t+5T(a<A9l4JTH{}n{N9-^O?yFeMa%K8}G)X zyS#U}mw$|z<!M@B%c@x+B6p+rP70c#c{h8jmP9Tm??j2RC$}cWUbuglBW0e|){nE+ L9^LkTU&1#4B&a;l
index bf248fdf9dbabcd0fefa1f75f778a5e0df8205af..e54db78087a5091c79ff2756a5bbabbbb2577001 GIT binary patch literal 17408 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
--- a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/generate.py +++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/generate.py @@ -17,13 +17,13 @@ def generate_child_cert(db_dir, dest_dir ocsp_url): return CertUtils.generate_child_cert(db_dir, dest_dir, noise_file, name, ca_nick, 3, True, is_ee, ocsp_url) def generate_certs(): [noise_file, pwd_file] = CertUtils.init_nss_db(srcdir) generate_ca_cert(srcdir, srcdir, noise_file, 'ca') generate_child_cert(srcdir, srcdir, noise_file, 'int', 'ca', False, '') - ocsp_url = "http://www.example.com:8080/" + ocsp_url = "http://www.example.com:8888/" generate_child_cert(srcdir, srcdir, noise_file, "a", 'int', True, ocsp_url) generate_child_cert(srcdir, srcdir, noise_file, "b", 'int', True, ocsp_url) generate_certs()
index 717c55d32105705eb7a21c35937442d1f1207aa3..661e814efaa9f67bc37bcef536b7f358ee34a666 GIT binary patch literal 845 zc$_n6V)is>VlrI7%*4pV#KLgu$_oQtHcqWJkGAi;jEvl@3<j}=+y<O%%%Lo7!c3vT zhQbDdAP$ExmvdrHW?FtxUS^`9n1KjLkX@M9H@`HmBr!8jAuKbs+)%_o2qexW%pDNy zs}Pb}T#}iW4l|Egm?=5YKu(<3(8SQt$k4#l$iUb*N}SgSnQIV7b?bQyxFFUuXXcd{ zG%+e6`<RiHfw_s1p8+V&#ni;e$Z)4KL#Csm<Dbx-t*@V1F~`|eW=E`FEq2oQ;hhT+ zy8SvAdgVWbGrv~dlovI%=wy~%^p29h0;&%du3Dd0r|)><^QZW=VR@QcH^*e$R`25e zURL1q@5H5VoZk7Kf!4h9cO}<7-(U0DPw-@L&hP5|%#J&%w^*#2)T~vZ(I6|n@92V) zn_FCdTv>X=|BcB(<tcm1+%pUP`&4Q!WbJcdR?=g(t!BTvKh-?jJnLp*!P!lv7pC*u zzN>TJyZ#vK6*2L+hjVoF#5fLco2aE6k_ZW2mwe~MpXsOGEtaqUBq(jj+xk;CzIflW zETh$%STDZF%Gv5Ov)s;q!qa*$*5fSk3ufzn(=cXYW@KPoEMUNAzyl05Sz#7d17=3X z|7fX%85C4WY*#wxo|)1t6=AD(;@E3dtw_1}xpGY0bMKtK-h8BStBhh&j`gYhJ<r+_ zlwHp%eJv=v;`mS2BvVgK#O!#j;XLLCyLo$G<%%bUE>Lgr`uhLT4F4Zo_tsxB;hX#T z)hQ3=vp2Q>M-{M}I&6Fzu;n(-gys|7%36!{(|<6;HJSvM_8C~*o%7W{tnu2cJFYh_ zJ$~S@*(|vE!I1{r28MgOtc{1SRzCSYX<7QLmp@|?&a;cnw`;7QJ?&@m61(@WIiwZ~ zE9mk%EwKLZqg3QW<t(+In=kOKw7q8e@mB7HuXg`!8l4#8?L023EkF9d)h)aISp2lP V>mNTk%qJS<Ipbk#sGYv>UjTQPJ`?}|
index 7471e140d8a821ccac14d0fa016e91b7358095e0..ada3335ecf24660ab3a4e0979a133ed8df901389 GIT binary patch literal 29696 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
--- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -86,33 +86,28 @@ skip-if = os == "android" skip-if = os == "android" || (buildapp == "b2g" && processor == "arm") requesttimeoutfactor = 4 [test_pinning.js] run-sequentially = hardcoded ports # Bug 1009158: this test times out on Android skip-if = os == "android" [test_ocsp_url.js] run-sequentially = hardcoded ports -# Bug 1009158: this test times out on Android -skip-if = os == "android" [test_ocsp_fetch_method.js] run-sequentially = hardcoded ports -# Bug 1009158: this test times out on Android -skip-if = os == "android" [test_ocsp_no_hsts_upgrade.js] run-sequentially = hardcoded ports # Bug 1009158: this test times out on Android skip-if = os == "android" [test_add_preexisting_cert.js] [test_keysize.js] [test_keysize_ev.js] run-sequentially = hardcoded ports -# Bug 1009158: this test times out on Android # Bug 1008316: B2G doesn't have EV enabled -skip-if = os == "android" || buildapp == "b2g" +skip-if = buildapp == "b2g" [test_cert_chains.js] run-sequentially = hardcoded ports # Bug 1009158: this test times out on Android skip-if = os == "android" [test_client_cert.js] run-sequentially = hardcoded ports # Bug 1009158: this test times out on Android skip-if = os == "android"
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/advanced/actions.rst @@ -0,0 +1,46 @@ +Actions +======= + +.. py:currentmodule:: marionette + +Action Sequences +---------------- + +:class:`Actions` are designed as a way to simulate user input as closely as possible +on a touch device like a smart phone. A common operation is to tap the screen +and drag your finger to another part of the screen and lift it off. + +This can be simulated using an Action:: + + from marionette import Actions + + start_element = marionette.find_element('id', 'start') + end_element = marionette.find_element('id', 'end') + + action = Actions(marionette) + action.press(start_element).wait(1).move(end_element).release() + action.perform() + +This will simulate pressing an element, waiting for one second, moving the +finger over to another element and then lifting the finger off the screen. The +wait is optional in this case, but can be useful for simulating delays typical +to a users behaviour. + +Multi-Action Sequences +---------------------- + +Sometimes it may be necessary to simulate multiple actions at the same time. +For example a user may be dragging one finger while tapping another. This is +where :class:`MultiActions` come in. MultiActions are simply a way of combining +two or more actions together and performing them all at the same time:: + + action1 = Actions(marionette) + action1.press(start_element).move(end_element).release() + + action2 = Actions(marionette) + action2.press(another_element).wait(1).release() + + multi = MultiActions(marionette) + multi.add(action1) + multi.add(action2) + multi.perform()
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/advanced/debug.rst @@ -0,0 +1,54 @@ +Debugging +========= + +.. py:currentmodule:: marionette + +Sometimes when working with Marionette you'll run into unexpected behaviour and +need to do some debugging. This page outlines some of the Marionette methods +that can be useful to you. + +Please note that the best tools for debugging are the `ones that ship with +Gecko`_. This page doesn't describe how to use those with Marionette. Also see +a related topic about `using the debugger with Marionette`_ on MDN. + +.. _ones that ship with Gecko: https://developer.mozilla.org/en-US/docs/Tools +.. _using the debugger with Marionette: https://developer.mozilla.org/en-US/docs/Marionette/Debugging + + +Storing Logs on the Server +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By calling `~Marionette.log` it is possible to store a message on the server. +Logs can later be retrieved using `~Marionette.get_logs`. For example:: + + try: + marionette.log("Sending a click event") # logged at INFO level + elem.click() + except: + marionette.log("Something went wrong!", "ERROR") + + print(marionette.get_logs()) + +Disclaimer: Example for illustrative purposes only, don't actually hide +tracebacks like that! + + +Seeing What's on the Page +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it's difficult to tell what is actually on the page that is being +manipulated. Either because it happens too fast, the window isn't big enough or +you are manipulating a remote server! There are two methods that can help you +out. The first is `~Marionette.screenshot`:: + + marionette.screenshot() # takes screenshot of entire frame + elem = marionette.find_element(By.ID, 'some-div') + marionette.screenshot(elem) # takes a screenshot of only the given element + +Sometimes you just want to see the DOM layout. You can do this with the +`~Marionette.page_source` property. Note that the page source depends on the +context you are in:: + + print(marionette.page_source) + marionette.set_context('chrome') + print(marionette.page_source)
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/advanced/findelement.rst @@ -0,0 +1,126 @@ +Finding Elements +================ +.. py:currentmodule:: marionette + +One of the most common and yet often most difficult tasks in Marionette is +finding a DOM element on a webpage or in the chrome UI. Marionette provides +several different search strategies to use when finding elements. All search +strategies work with both :func:`~Marionette.find_element` and +:func:`~Marionette.find_elements`, though some strategies are not implemented +in chrome scope. + +In the event that more than one element is matched by the query, +:func:`~Marionette.find_element` will only return the first element found. In +the event that no elements are matched by the query, +:func:`~Marionette.find_element` will raise `NoSuchElementException` while +:func:`~Marionette.find_elements` will return an empty list. + +Search Strategies +----------------- + +Search strategies are defined in the :class:`By` class:: + + from marionette import By + print(By.ID) + +The strategies are: + +* `id` - The easiest way to find an element is to refer to its id directly:: + + container = client.find_element(By.ID, 'container') + +* `class name` - To find elements belonging to a certain class, use `class name`:: + + buttons = client.find_elements(By.CLASS_NAME, 'button') + +* `css selector` - It's also possible to find elements using a `css selector`_:: + + container_buttons = client.find_elements(By.CSS_SELECTOR, '#container .buttons') + +* `name` - Find elements by their name attribute (not implemented in chrome + scope):: + + form = client.find_element(By.NAME, 'signup') + +* `tag name` - To find all the elements with a given tag, use `tag name`:: + + paragraphs = client.find_elements(By.TAG_NAME, 'p') + +* `link text` - A convenience strategy for finding link elements by their + innerHTML (not implemented in chrome scope):: + + link = client.find_element(By.LINK_TEXT, 'Click me!') + +* `partial link text` - Same as `link text` except substrings of the innerHTML + are matched (not implemented in chrome scope):: + + link = client.find_element(By.PARTIAL_LINK_TEXT, 'Clic') + +* `xpath` - Find elements using an xpath_ query:: + + elem = client.find_element(By.XPATH, './/*[@id="foobar"') + +.. _css selector: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors +.. _xpath: https://developer.mozilla.org/en-US/docs/Web/XPath + + + +Chaining Searches +----------------- + +In addition to the methods on the Marionette object, HTMLElement objects also +provide :func:`~HTMLElement.find_element` and :func:`~HTMLElement.find_elements` +methods. The difference is that only child nodes of the element will be searched. +Consider the following html snippet:: + + <div id="content"> + <span id="main"></span> + </div> + <div id="footer"></div> + +Doing the following will work:: + + client.find_element(By.ID, 'container').find_element(By.ID, 'main') + +But this will raise a `NoSuchElementException`:: + + client.find_element(By.ID, 'container').find_element(By.ID, 'footer') + + +Finding Anonymous Nodes +----------------------- + +When working in chrome scope, for example manipulating the Firefox user +interface, you may run into something called an anonymous node. + +Firefox uses a markup language called XUL_ for its interface. XUL is similar +to HTML in that it has a DOM and tags that render controls on the display. One +ability of XUL is to create re-useable widgets that are made up out of several +smaller XUL elements. These widgets can be bound to the DOM using something +called the `XML binding language (XBL)`_. + +The end result is that the DOM sees the widget as a single entity. It doesn't +know anything about how that widget is made up. All of the smaller XUL elements +that make up the widget are called `anonymous content`_. It is not possible to +query such elements using traditional DOM methods like `getElementById`. + +Marionette provides two special strategies used for finding anonymous content. +Unlike normal elements, anonymous nodes can only be seen by their parent. So +it's necessary to first find the parent element and then search for the +anonymous children from there. + +* `anon` - Finds all anonymous children of the element, there is no search term + so `None` must be passed in:: + + anon_children = client.find_element('id', 'parent').find_elements('anon', None) + +* `anon attribute` - Find an anonymous child based on an attribute. An + unofficial convention is for anonymous nodes to have an + `anonid` attribute:: + + anon_child = client.find_element('id', 'parent').find_element('anon attribute', {'anonid': 'container'}) + + +.. _XUL: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL +.. _XML binding language (XBL): https://developer.mozilla.org/en-US/docs/XBL +.. _anonymous content: https://developer.mozilla.org/en-US/docs/XBL/XBL_1.0_Reference/Anonymous_Content
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/advanced/landing.rst @@ -0,0 +1,13 @@ +Advanced Topics +=============== + +Here are a collection of articles explaining some of the more complicated +aspects of Marionette. + +.. toctree:: + :maxdepth: 1 + + findelement + stale + actions + debug
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/advanced/stale.rst @@ -0,0 +1,71 @@ +Dealing with Stale Elements +=========================== +.. py:currentmodule:: marionette + +Marionette does not keep a live representation of the DOM saved. All it can do +is send commands to the Marionette server which queries the DOM on the client's +behalf. References to elements are also not passed from server to client. A +unique id is generated for each element that gets referenced and a mapping of +id to element object is stored on the server. When commands such as +:func:`~HTMLElement.click()` are run, the client sends the element's id along +with the command. The server looks up the proper DOM element in its reference +table and executes the command on it. + +In practice this means that the DOM can change state and Marionette will never +know until it sends another query. For example, look at the following HTML:: + + <head> + <script type=text/javascript> + function addDiv() { + var div = document.createElement("div"); + document.getElementById("container").appendChild(div); + } + </script> + </head> + + <body> + <div id="container"> + </div> + <input id="button" type=button onclick="addDiv();"> + </body> + +Care needs to be taken as the DOM is being modified after the page has loaded. +The following code has a race condition:: + + button = client.find_element('id', 'button') + button.click() + assert len(client.find_elements('css selector', '#container div')) > 0 + + +Explicit Waiting and Expected Conditions +---------------------------------------- + +To avoid the above scenario, manual synchronisation is needed. Waits are used +to pause program execution until a given condition is true. This is a useful +technique to employ when documents load new content or change after +``Document.readyState``'s value changes to "complete". + +The :class:`Wait` helper class provided by Marionette avoids some of the +caveats of ``time.sleep(n)``. It will return immediately once the provided +condition evaluates to true. + +To avoid the race condition in the above example, one could do:: + + button = client.find_element('id', 'button') + button.click() + + def find_divs(): + return client.find_elements('css selector', '#container div') + + divs = Wait(client).until(find_divs) + assert len(divs) > 0 + +This avoids the race condition. Because finding elements is a common condition +to wait for, it is built in to Marionette. Instead of the above, you could +write:: + + button = client.find_element('id', 'button') + button.click() + assert len(Wait(client).until(expected.elements_present('css selector', '#container div'))) > 0 + +For a full list of built-in conditions, see :mod:`~marionette.expected`.
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/basics.rst @@ -0,0 +1,185 @@ +.. py:currentmodule:: marionette + +Marionette Python Client +======================== + +The Marionette python client library allows you to remotely control a +Gecko-based browser or device which is running a Marionette_ +server. This includes desktop Firefox and FirefoxOS (support for +Firefox for Android is planned, but not yet fully implemented). + +The Marionette server is built directly into Gecko and can be started by +passing in a command line option to Gecko, or by using a Marionette-enabled +build. The server listens for connections from various clients. Clients can +then control Gecko by sending commands to the server. + +This is the official python client for Marionette. There also exists a +`NodeJS client`_ maintained by the Firefox OS automation team. + +.. _Marionette: https://developer.mozilla.org/en-US/docs/Marionette +.. _NodeJS client: https://github.com/mozilla-b2g/marionette-js-client + +Getting the Client +------------------ + +The python client is officially supported. To install it, first make sure you +have `pip installed`_ then run: + +.. parsed-literal:: + pip install marionette_client + +It's highly recommended to use virtualenv_ when installing Marionette to avoid +package conflicts and other general nastiness. + +You should now be ready to start using Marionette. The best way to learn is to +play around with it. Start a `Marionette-enabled instance of Firefox`_, fire up +a python shell and follow along with the +:doc:`interactive tutorial <interactive>`! + +.. _pip installed: https://pip.pypa.io/en/latest/installing.html +.. _virtualenv: http://virtualenv.readthedocs.org/en/latest/ +.. _Marionette-enabled instance of Firefox: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Builds + +Using the Client for Testing +---------------------------- + +Please visit the `Marionette Tests`_ section on MDN for information regarding +testing with Marionette. + +.. _Marionette Tests: https://developer.mozilla.org/en/Marionette/Tests + +Session Management +------------------ +A session is a single instance of a Marionette client connected to a Marionette +server. Before you can start executing commands, you need to start a session +with :func:`start_session() <Marionette.start_session>`: + +.. parsed-literal:: + client = Marionette('localhost', port=2828) + client.start_session() + +This returns a session id and an object listing the capabilities of the +Marionette server. For example, a server running on a Firefox OS device will +have the ability to rotate the window, while a server running from Firefox +won't. It's also possible to access the capabilities using the +:attr:`~Marionette.session_capabilities` attribute. After finishing with a +session, you can delete it with :func:`~Marionette.delete_session()`. Note that +this will also happen automatically when the Marionette object is garbage +collected. + +Context Management +------------------ +Commands can only be executed in a single window, frame and scope at a time. In +order to run commands elsewhere, it's necessary to explicitly switch to the +appropriate context. + +Use :func:`~Marionette.switch_to_window` to execute commands in the context of a +new window: + +.. parsed-literal:: + original_window = client.current_window_handle + for handle in client.window_handles: + if handle != original_window: + client.switch_to_window(handle) + print("Switched to window with '{}' loaded.".format(client.get_url())) + client.switch_to_window(original_window) + +Similarly, use :func:`~Marionette.switch_to_frame` to execute commands in the +context of a new frame (e.g an <iframe> element): + +.. parsed-literal:: + iframe = client.find_element(By.TAG_NAME, 'iframe') + client.switch_to_frame(iframe) + assert iframe == client.get_active_frame() + +Finally Marionette can switch between `chrome` and `content` scope. Chrome is a +privileged scope where you can access things like the Firefox UI itself or the +system app in Firefox OS. Content scope is where things like webpages or normal +Firefox OS apps live. You can switch between `chrome` and `content` using the +:func:`~Marionette.set_context` and :func:`~Marionette.using_context` functions: + +.. parsed-literal:: + client.set_context(client.CONTEXT_CONTENT) + # content scope + with client.using_context(client.CONTEXT_CHROME): + #chrome scope + ... do stuff ... + # content scope restored + + +Navigation +---------- + +Use :func:`~Marionette.navigate` to open a new website. It's also possible to +move through the back/forward cache using :func:`~Marionette.go_forward` and +:func:`~Marionette.go_back` respectively. To retrieve the currently +open website, use :func:`~Marionette.get_url`: + +.. parsed-literal:: + url = 'http://mozilla.org' + client.navigate(url) + client.go_back() + client.go_forward() + assert client.get_url() == url + + +DOM Elements +------------ + +In order to inspect or manipulate actual DOM elements, they must first be found +using the :func:`~Marionette.find_element` or :func:`~Marionette.find_elements` +methods: + +.. parsed-literal:: + from marionette import HTMLElement + element = client.find_element(By.ID, 'my-id') + assert type(element) == HTMLElement + elements = client.find_elements(By.TAG_NAME, 'a') + assert type(elements) == list + +For a full list of valid search strategies, see :doc:`advanced/findelement`. + +Now that an element has been found, it's possible to manipulate it: + +.. parsed-literal:: + element.click() + element.send_keys('hello!') + print(element.get_attribute('style')) + +For the full list of possible commands, see the :class:`HTMLElement` +reference. + +Be warned that a reference to an element object can become stale if it was +modified or removed from the document. See :doc:`advanced/stale` for tips +on working around this limitation. + +Script Execution +---------------- + +Sometimes Marionette's provided APIs just aren't enough and it is necessary to +run arbitrary javascript. This is accomplished with the +:func:`~Marionette.execute_script` and :func:`~Marionette.execute_async_script` +functions. They accomplish what their names suggest, the former executes some +synchronous JavaScript, while the latter provides a callback mechanism for +running asynchronous JavaScript: + +.. parsed-literal:: + result = client.execute_script("return arguments[0] + arguments[1];", + script_args=[2, 3]) + assert result == 5 + +The async method works the same way, except it won't return until a special +`marionetteScriptFinished()` function is called: + +.. parsed-literal:: + result = client.execute_async_script(""" + setTimeout(function() { + marionetteScriptFinished("all done"); + }, arguments[0]); + """, script_args=[1000]) + assert result == "all done" + +Beware that running asynchronous scripts can potentially hang the program +indefinitely if they are not written properly. It is generally a good idea to +set a script timeout using :func:`~Marionette.set_script_timeout` and handling +`ScriptTimeoutException`.
--- a/testing/marionette/client/docs/conf.py +++ b/testing/marionette/client/docs/conf.py @@ -90,18 +90,30 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. + html_theme = 'default' +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + except ImportError: + pass + + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = []
--- a/testing/marionette/client/docs/index.rst +++ b/testing/marionette/client/docs/index.rst @@ -1,220 +1,16 @@ -.. Marionette Python Client documentation master file, created by - sphinx-quickstart on Tue Aug 6 13:54:46 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Marionette Python Client -======================== - -The Marionette python client library allows you to remotely control a -Gecko-based browser or device which is running a Marionette_ -server. This includes desktop Firefox and FirefoxOS (support for -Firefox for Android is planned, but not yet fully implemented). - -.. _Marionette: https://developer.mozilla.org/en-US/docs/Marionette - -Getting Started ---------------- - -Getting the Client -^^^^^^^^^^^^^^^^^^ - -We officially support a python client. The latest supported version of -the client is available on pypi_, so you can download it via pip. -This client should be used within a virtual environment to ensure that -your environment is pristine: - -.. parsed-literal:: - - virtualenv venv - source venv/bin/activate - pip install marionette_client - -.. _pypi: https://pypi.python.org/pypi/marionette_client/ - -Using the Client Interactively -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Once you installed the client and have Marionette running, you can fire -up your favourite interactive python environment and start playing with -Marionette. Let's use a typical python shell: - -.. parsed-literal:: - - python - -First, import Marionette: - -.. parsed-literal:: - from marionette import Marionette - -Now create the client for this session. Assuming you're using the default -port on a Marionette instance running locally: - -.. parsed-literal:: - - client = Marionette(host='localhost', port=2828) - client.start_session() - -This will return some id representing your session id. Now that you've -established a connection, let's start doing interesting things: - -.. parsed-literal:: - - client.execute_script("alert('o hai there!');") - -You should now see this alert pop up! How exciting! Okay, let's do -something practical. Close the dialog and try this: - -.. parsed-literal:: - - client.navigate("http://www.mozilla.org") - -Now you're at mozilla.org! You can even verify it using the following: - -.. parsed-literal:: - client.get_url() - -You can even find an element and click on it. Let's say you want to get -the first link: - -.. parsed-literal:: - first_link = client.find_element("tag name", "a") - -first_link now holds a reference to the first link on the page. You can click it: - -.. parsed-literal:: - first_link.click() - -Using the Client for Testing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Please visit, our `Marionette Tests`_ section for information regarding testing. - -.. _Marionette Tests: https://developer.mozilla.org/en/Marionette/Tests - -.. automodule:: marionette - -Marionette Objects ------------------- -.. autoclass:: Marionette - -Session Management -^^^^^^^^^^^^^^^^^^ -.. automethod:: Marionette.start_session -.. automethod:: Marionette.delete_session -.. autoattribute:: Marionette.session_capabilities -.. automethod:: Marionette.get_cookie -.. automethod:: Marionette.get_cookies -.. automethod:: Marionette.add_cookie -.. automethod:: Marionette.delete_all_cookies - -Context Management -^^^^^^^^^^^^^^^^^^ -.. autoattribute:: Marionette.current_window_handle -.. autoattribute:: Marionette.window_handles -.. automethod:: Marionette.set_context -.. automethod:: Marionette.switch_to_frame -.. automethod:: Marionette.switch_to_window -.. automethod:: Marionette.get_active_frame -.. automethod:: Marionette.close - -Navigation Methods -^^^^^^^^^^^^^^^^^^ -.. autoattribute:: Marionette.title -.. automethod:: Marionette.navigate -.. automethod:: Marionette.get_url -.. automethod:: Marionette.go_back -.. automethod:: Marionette.go_forward -.. automethod:: Marionette.refresh -.. automethod:: Marionette.absolute_url -.. automethod:: Marionette.get_window_type - -DOM Element Methods -^^^^^^^^^^^^^^^^^^^ -.. automethod:: Marionette.set_search_timeout -.. automethod:: Marionette.find_element -.. automethod:: Marionette.find_elements - -Script Execution -^^^^^^^^^^^^^^^^ -.. automethod:: Marionette.execute_script -.. automethod:: Marionette.execute_async_script -.. automethod:: Marionette.set_script_timeout - -Debugging -^^^^^^^^^ -.. autoattribute:: Marionette.page_source -.. automethod:: Marionette.log -.. automethod:: Marionette.get_logs -.. automethod:: Marionette.screenshot - -Querying and Modifying Document Content ---------------------------------------- -.. autoclass:: HTMLElement - :members: - -.. autoclass:: DateTimeValue - :members: - -Action Objects --------------- - -Action Sequences -^^^^^^^^^^^^^^^^ -.. autoclass:: Actions - :members: - -Multi-action Sequences -^^^^^^^^^^^^^^^^^^^^^^ -.. autoclass:: MultiActions - :members: - -Explicit Waiting and Expected Conditions ----------------------------------------- - -Waits are used to pause program execution -until a given condition is true. -This is a useful technique to employ -when documents load new content or change -after ``Document.readyState``'s value changes to "complete". - -Because Marionette returns control to the user -when the document is completely loaded, -any subsequent interaction with elements -are subject to manual synchronisation. -The reason for this is that Marionette -does not keep a direct representation of the DOM, -but instead exposes a way for the user to -query the browser's DOM state. - -The `Wait` helper class provided by Marionette -avoids some of the caveats of ``time.sleep(n)``, -which sets the condition to an exact time period to wait. -It will return immediately -once the provided condition evaluates to true. - -In addition to writing your own custom conditions -you can combine `Wait` -with a number of ready-made expected conditions -that are listed below. - -Waits -^^^^^ -.. autoclass:: marionette.wait.Wait - :members: - :special-members: -.. autoattribute marionette.wait.DEFAULT_TIMEOUT -.. autoattribute marionette.wait.DEFAULT_INTERVAL - -Expected Conditions -^^^^^^^^^^^^^^^^^^^ -.. automodule:: marionette.expected - :members: +.. include:: basics.rst Indices and tables -================== +------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` + +.. toctree:: + :hidden: + + Getting Started <basics> + Interactive Tutorial <interactive> + advanced/landing + reference
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/interactive.rst @@ -0,0 +1,55 @@ +Using the Client Interactively +============================== + +Once you installed the client and have Marionette running, you can fire +up your favourite interactive python environment and start playing with +Marionette. Let's use a typical python shell: + +.. parsed-literal:: + + python + +First, import Marionette: + +.. parsed-literal:: + from marionette import Marionette + +Now create the client for this session. Assuming you're using the default +port on a Marionette instance running locally: + +.. parsed-literal:: + + client = Marionette(host='localhost', port=2828) + client.start_session() + +This will return some id representing your session id. Now that you've +established a connection, let's start doing interesting things: + +.. parsed-literal:: + + client.execute_script("alert('o hai there!');") + +You should now see this alert pop up! How exciting! Okay, let's do +something practical. Close the dialog and try this: + +.. parsed-literal:: + + client.navigate("http://www.mozilla.org") + +Now you're at mozilla.org! You can even verify it using the following: + +.. parsed-literal:: + client.get_url() + +You can even find an element and click on it. Let's say you want to get +the first link: + +.. parsed-literal:: + from marionette import By + first_link = client.find_element(By.TAG_NAME, "a") + +first_link now holds a reference to the first link on the page. You can click it: + +.. parsed-literal:: + first_link.click() +
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/docs/reference.rst @@ -0,0 +1,43 @@ +============= +API Reference +============= +.. py:currentmodule:: marionette + +Marionette +---------- +.. autoclass:: Marionette + :members: + +HTMLElement +----------- +.. autoclass:: HTMLElement + :members: + +DateTimeValue +------------- +.. autoclass:: DateTimeValue + :members: + +Actions +------- +.. autoclass:: Actions + :members: + +MultiActions +------------ +.. autoclass:: MultiActions + :members: + +Wait +---- + +.. autoclass:: Wait + :members: + :special-members: +.. autoattribute marionette.wait.DEFAULT_TIMEOUT +.. autoattribute marionette.wait.DEFAULT_INTERVAL + +Built-in Conditions +^^^^^^^^^^^^^^^^^^^ +.. automodule:: marionette.expected + :members:
--- a/testing/marionette/client/marionette/wait.py +++ b/testing/marionette/client/marionette/wait.py @@ -120,17 +120,17 @@ class Wait(object): while not until(self.clock, self.end): try: rv = condition(self.marionette) except (KeyboardInterrupt, SystemExit) as e: raise e except self.exceptions as e: last_exc = sys.exc_info() - if isinstance(rv, bool) and not rv: + if not rv: self.clock.sleep(self.interval) continue if rv is not None: return rv self.clock.sleep(self.interval)
--- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -11,16 +11,20 @@ #endif #include "nsUTF8Utils.h" #ifndef XRE_DONT_PROTECT_DLL_LOAD #include "nsSetDllDirectory.h" #endif +#if defined(MOZ_METRO) || defined(__GNUC__) +#define XRE_DONT_SUPPORT_XPSP2 +#endif + #ifndef XRE_DONT_SUPPORT_XPSP2 #include "WindowsCrtPatch.h" #endif #ifdef __MINGW32__ /* MingW currently does not implement a wide version of the startup routines. Workaround is to implement something like @@ -75,17 +79,17 @@ FreeAllocStrings(int argc, char **argv) delete [] argv[argc]; } delete [] argv; } int wmain(int argc, WCHAR **argv) { -#if !defined(XRE_DONT_SUPPORT_XPSP2) && !defined(MOZ_METRO) +#if !defined(XRE_DONT_SUPPORT_XPSP2) WindowsCrtPatch::Init(); #endif #ifndef XRE_DONT_PROTECT_DLL_LOAD mozilla::SanitizeEnvironmentVariables(); SetDllDirectoryW(L""); #endif