Merge latest green fx-team changeset and mozilla-central

This commit is contained in:
Ed Morley 2013-09-13 15:02:24 +01:00
commit 976b3a737e
185 changed files with 3222 additions and 2218 deletions

View File

@ -279,7 +279,7 @@ DocAccessibleWrap::DoInitialUpdate()
// Create window for tab document.
if (mDocFlags & eTabDocument) {
mozilla::dom::TabChild* tabChild =
mozilla::dom::GetTabChildFrom(mDocumentNode->GetShell());
mozilla::dom::TabChild::GetFrom(mDocumentNode->GetShell());
a11y::RootAccessible* rootDocument = RootAccessible();

View File

@ -15,6 +15,8 @@
<!ENTITY % browserDTD
SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
]>
@ -30,6 +32,11 @@
<p id="helper-error-msg">&tabCrashed.message;</p>
</div>
<div id="report-box">
<input type="checkbox" id="checkSendReport" checked="checked"/>
<label for="checkSendReport">&tabCrashed.checkSendReport;</label>
</div>
<div id="button-box">
<button id="tryAgain">&tabCrashed.tryAgain;</button>
</div>

View File

@ -137,6 +137,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "SitePermissions",
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
#ifdef MOZ_CRASHREPORTER
XPCOMUtils.defineLazyModuleGetter(this, "TabCrashReporter",
"resource:///modules/TabCrashReporter.jsm");
#endif
let gInitialPages = [
"about:blank",
"about:newtab",
@ -1046,6 +1051,11 @@ var gBrowserInit = {
// Ensure login manager is up and running.
Services.logins;
#ifdef MOZ_CRASHREPORTER
if (gMultiProcessBrowser)
TabCrashReporter.init();
#endif
if (mustLoadSidebar) {
let sidebar = document.getElementById("sidebar");
let sidebarBox = document.getElementById("sidebar-box");
@ -2498,6 +2508,12 @@ let BrowserOnClick = {
let button = aEvent.originalTarget;
if (button.id == "tryAgain") {
#ifdef MOZ_CRASHREPORTER
if (aOwnerDoc.getElementById("checkSendReport").checked) {
let browser = gBrowser.getBrowserForDocument(aOwnerDoc);
TabCrashReporter.submitCrashReport(browser);
}
#endif
openUILinkIn(button.getAttribute("url"), "current");
}
},
@ -4266,6 +4282,11 @@ var TabsProgressListener = {
if (event.target.documentElement)
event.target.documentElement.removeAttribute("hasBrowserHandlers");
}, true);
#ifdef MOZ_CRASHREPORTER
if (doc.documentURI.startsWith("about:tabcrashed"))
TabCrashReporter.onAboutTabCrashedLoad(aBrowser);
#endif
}
},

View File

@ -48,8 +48,7 @@ if (Services.prefs.getBoolPref("browser.tabs.remote")) {
let AboutHomeListener = {
init: function(chromeGlobal) {
let self = this;
chromeGlobal.addEventListener('AboutHomeLoad', function(e) { self.onPageLoad(); }, false, true);
chromeGlobal.addEventListener('AboutHomeLoad', () => this.onPageLoad(), false, true);
},
handleEvent: function(aEvent) {

View File

@ -673,6 +673,7 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY tabCrashed.header "Tab crashed">
<!ENTITY tabCrashed.message "Well, this is embarrassing. We tried to display this Web page, but it's not responding.">
<!ENTITY tabCrashed.checkSendReport "Tell &vendorShortName; about this crash so they can fix it.">
<!ENTITY tabCrashed.tryAgain "Try Again">
<!-- LOCALIZATION NOTE: the following strings are unused in Australis, they're

View File

@ -0,0 +1,73 @@
/* 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/. */
"use strict";
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "TabCrashReporter" ];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
"resource://gre/modules/CrashSubmit.jsm");
this.TabCrashReporter = {
init: function () {
if (this.initialized)
return;
this.initialized = true;
Services.obs.addObserver(this, "ipc:content-shutdown", false);
Services.obs.addObserver(this, "oop-frameloader-crashed", false);
this.childMap = new Map();
this.browserMap = new WeakMap();
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "ipc:content-shutdown":
aSubject.QueryInterface(Ci.nsIPropertyBag2);
if (!aSubject.get("abnormal"))
return;
this.childMap.set(aSubject.get("childID"), aSubject.get("dumpID"));
break;
case "oop-frameloader-crashed":
aSubject.QueryInterface(Ci.nsIFrameLoader);
let browser = aSubject.ownerElement;
if (!browser)
return;
this.browserMap.set(browser, aSubject.childID);
break;
}
},
submitCrashReport: function (aBrowser) {
let childID = this.browserMap.get(aBrowser);
let dumpID = this.childMap.get(childID);
if (!dumpID)
return
if (CrashSubmit.submit(dumpID)) {
this.childMap.set(childID, null); // Avoid resubmission.
}
},
onAboutTabCrashedLoad: function (aBrowser) {
let dumpID = this.childMap.get(this.browserMap.get(aBrowser));
if (!dumpID)
return;
aBrowser.contentDocument.documentElement.classList.add("crashDumpAvaible");
}
}

View File

@ -14,6 +14,7 @@ EXTRA_JS_MODULES += [
'SignInToWebsite.jsm',
'SitePermissions.jsm',
'Social.jsm',
'TabCrashReporter.jsm',
'offlineAppCache.jsm',
'openLocationLastURL.jsm',
'webappsUI.jsm',

View File

@ -23,6 +23,16 @@ p {
font-weight: bold;
}
#report-box {
text-align: center;
width: 75%;
margin: 0 auto;
display: none;
}
.crashDumpAvaible #report-box {
display: block
}
#button-box {
text-align: center;

View File

@ -23,6 +23,16 @@ p {
font-weight: bold;
}
#report-box {
text-align: center;
width: 75%;
margin: 0 auto;
display: none;
}
.crashDumpAvaible #report-box {
display: block
}
#button-box {
text-align: center;

View File

@ -23,6 +23,16 @@ p {
font-weight: bold;
}
#report-box {
text-align: center;
width: 75%;
margin: 0 auto;
display: none;
}
.crashDumpAvaible #report-box {
display: block
}
#button-box {
text-align: center;

View File

@ -111,7 +111,7 @@ interface nsIContentViewManager : nsISupports
readonly attribute nsIContentView rootContentView;
};
[scriptable, builtinclass, uuid(e4333e51-f2fa-4fdd-becd-75d000703355)]
[scriptable, builtinclass, uuid(5b9949dc-56f1-47b6-b6d2-3785bb90ed6d)]
interface nsIFrameLoader : nsISupports
{
/**
@ -257,6 +257,13 @@ interface nsIFrameLoader : nsISupports
*/
readonly attribute nsIDOMElement ownerElement;
/**
* Cached childID of the ContentParent owning the TabParent in this frame
* loader. This can be used to obtain the childID after the TabParent died.
*/
readonly attribute unsigned long long childID;
/**
* Get or set this frame loader's visibility.
*

View File

@ -288,6 +288,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mVisible(true)
, mCurrentRemoteFrame(nullptr)
, mRemoteBrowser(nullptr)
, mChildID(0)
, mRenderMode(RENDER_MODE_DEFAULT)
, mEventMode(EVENT_MODE_NORMAL_DISPATCH)
{
@ -2061,6 +2062,7 @@ nsFrameLoader::TryRemoteBrowser()
nsCOMPtr<Element> ownerElement = mOwnerContent;
mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement);
if (mRemoteBrowser) {
mChildID = mRemoteBrowser->Manager()->ChildID();
nsCOMPtr<nsIDocShellTreeItem> rootItem;
parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
@ -2444,6 +2446,13 @@ nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::GetChildID(uint64_t* aChildID)
{
*aChildID = mChildID;
return NS_OK;
}
void
nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
{
@ -2451,7 +2460,7 @@ nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
MOZ_ASSERT(!mCurrentRemoteFrame);
mRemoteFrame = true;
mRemoteBrowser = static_cast<TabParent*>(aTabParent);
mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
ShowRemoteFrame(nsIntSize(0, 0));
}

View File

@ -442,6 +442,7 @@ private:
nsRefPtr<mozilla::dom::ContentParent> mContentParent;
RenderFrameParent* mCurrentRemoteFrame;
TabParent* mRemoteBrowser;
uint64_t mChildID;
// See nsIFrameLoader.idl. Short story, if !(mRenderMode &
// RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in

View File

@ -775,7 +775,7 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
JS::Rooted<JSObject*> global(cx, unrootedGlobal);
JS::CompileOptions options(cx);
FillCompileOptionsForRequest(aRequest, &options);
FillCompileOptionsForRequest(aRequest, global, &options);
if (!JS::CanCompileOffThread(cx, options)) {
return NS_ERROR_FAILURE;
@ -915,7 +915,9 @@ nsIScriptContext *
nsScriptLoader::GetScriptContext(JSObject **aGlobal)
{
nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
NS_ASSERTION(pwin, "shouldn't be called with a null inner window");
if (!pwin) {
return nullptr;
}
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
NS_ASSERTION(globalObject, "windows must be global objects");
@ -932,6 +934,7 @@ nsScriptLoader::GetScriptContext(JSObject **aGlobal)
void
nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
JS::Handle<JSObject *> scopeChain,
JS::CompileOptions *aOptions)
{
// It's very important to use aRequest->mURI, not the final URI of the channel
@ -940,6 +943,7 @@ nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
aOptions->setVersion(JSVersion(aRequest->mJSVersion));
aOptions->setCompileAndGo(JS_IsGlobalObject(scopeChain));
if (aRequest->mOriginPrincipal) {
aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
}
@ -988,7 +992,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
JSVersion version = JSVersion(aRequest->mJSVersion);
if (version != JSVERSION_UNKNOWN) {
JS::CompileOptions options(cx);
FillCompileOptionsForRequest(aRequest, &options);
FillCompileOptionsForRequest(aRequest, global, &options);
rv = context->EvaluateString(aScript, global,
options, /* aCoerceToString = */ false, nullptr,
aOffThreadToken);

View File

@ -281,6 +281,7 @@ private:
nsIScriptContext *GetScriptContext(JSObject **aGlobal);
void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
JS::Handle<JSObject *> scopeChain,
JS::CompileOptions *aOptions);
nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,

View File

@ -14,8 +14,8 @@
#include "mozilla/RefPtr.h"
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
{ 0x8b8da863, 0xd151, 0x4014, \
{ 0x8b, 0xdc, 0x62, 0xb5, 0x0d, 0xc0, 0x2b, 0x62 } }
{ 0x9a6a5bdf, 0x1261, 0x4057, \
{ 0x85, 0xcc, 0xaf, 0x97, 0x6c, 0x36, 0x99, 0xa9 } }
class gfxContext;
class gfxASurface;
@ -65,6 +65,9 @@ public:
gfxPattern::GraphicsFilter aFilter,
uint32_t aFlags = RenderFlagPremultAlpha) = 0;
// Creates an image buffer. Returns null on failure.
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0;
// Gives you a stream containing the image represented by this context.
// The format is given in aMimeTime, for example "image/png".
//

View File

@ -41,7 +41,7 @@
#include "nsTArray.h"
#include "imgIEncoder.h"
#include "ImageEncoder.h"
#include "gfxContext.h"
#include "gfxASurface.h"
@ -1036,71 +1036,71 @@ CanvasRenderingContext2D::Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFi
return rv;
}
NS_IMETHODIMP
CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
void
CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
int32_t* aFormat)
{
EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
}
*aImageBuffer = nullptr;
*aFormat = 0;
nsRefPtr<gfxASurface> surface;
if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
return NS_ERROR_FAILURE;
nsresult rv = GetThebesSurface(getter_AddRefs(surface));
if (NS_FAILED(rv)) {
return;
}
nsresult rv;
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<char> conid(new (fallible) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
if (!conid) {
return NS_ERROR_OUT_OF_MEMORY;
}
strcpy(conid, encoderPrefix);
strcat(conid, aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
if (!encoder) {
return NS_ERROR_FAILURE;
}
nsAutoArrayPtr<uint8_t> imageBuffer(new (fallible) uint8_t[mWidth * mHeight * 4]);
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!imageBuffer) {
return NS_ERROR_OUT_OF_MEMORY;
return;
}
nsRefPtr<gfxImageSurface> imgsurf =
new gfxImageSurface(imageBuffer.get(),
new gfxImageSurface(imageBuffer,
gfxIntSize(mWidth, mHeight),
mWidth * 4,
gfxASurface::ImageFormatARGB32);
if (!imgsurf || imgsurf->CairoStatus()) {
return NS_ERROR_FAILURE;
delete[] imageBuffer;
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) {
return NS_ERROR_FAILURE;
delete[] imageBuffer;
return;
}
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(surface, gfxPoint(0, 0));
ctx->Paint();
rv = encoder->InitFromData(imageBuffer.get(),
mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
nsDependentString(aEncoderOptions));
NS_ENSURE_SUCCESS(rv, rv);
*aImageBuffer = imageBuffer;
*aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
}
return CallQueryInterface(encoder, aStream);
NS_IMETHODIMP
CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
{
uint8_t* imageBuffer = nullptr;
int32_t format = 0;
GetImageBuffer(&imageBuffer, &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE;
}
nsCString enccid("@mozilla.org/image/encoder;2?type=");
enccid += aMimeType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
if (!encoder) {
return NS_ERROR_FAILURE;
}
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
encoder, aEncoderOptions, aStream);
}
SurfaceFormat
@ -3739,6 +3739,9 @@ NS_IMETHODIMP
CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
{
EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxASurface> thebesSurface =
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);

View File

@ -20,6 +20,7 @@
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
#include "mozilla/dom/CanvasPattern.h"
#include "mozilla/gfx/Rect.h"
#include "imgIEncoder.h"
class nsXULElement;
@ -448,6 +449,8 @@ public:
friend class CanvasRenderingContext2DUserData;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight,

View File

@ -0,0 +1,299 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ImageEncoder.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
namespace mozilla {
namespace dom {
class EncodingCompleteEvent : public nsRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
EncodingCompleteEvent(nsIScriptContext* aScriptContext,
nsIThread* aEncoderThread,
FileCallback& aCallback)
: mImgSize(0)
, mType()
, mImgData(nullptr)
, mScriptContext(aScriptContext)
, mEncoderThread(aEncoderThread)
, mCallback(&aCallback)
{}
virtual ~EncodingCompleteEvent() {}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<nsDOMMemoryFile> blob =
new nsDOMMemoryFile(mImgData, mImgSize, mType);
if (mScriptContext) {
JSContext* jsContext = mScriptContext->GetNativeContext();
if (jsContext) {
JS_updateMallocCounter(jsContext, mImgSize);
}
}
mozilla::ErrorResult rv;
mCallback->Call(blob, rv);
NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
mEncoderThread->Shutdown();
return rv.ErrorCode();
}
void SetMembers(void* aImgData, uint64_t aImgSize, const nsAutoString& aType)
{
mImgData = aImgData;
mImgSize = aImgSize;
mType = aType;
}
private:
uint64_t mImgSize;
nsAutoString mType;
void* mImgData;
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMPtr<nsIThread> mEncoderThread;
nsRefPtr<FileCallback> mCallback;
};
NS_IMPL_ISUPPORTS1(EncodingCompleteEvent, nsIRunnable);
class EncodingRunnable : public nsRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
EncodingRunnable(const nsAString& aType,
const nsAString& aOptions,
uint8_t* aImageBuffer,
imgIEncoder* aEncoder,
EncodingCompleteEvent* aEncodingCompleteEvent,
int32_t aFormat,
const nsIntSize aSize,
bool aUsingCustomOptions)
: mType(aType)
, mOptions(aOptions)
, mImageBuffer(aImageBuffer)
, mEncoder(aEncoder)
, mEncodingCompleteEvent(aEncodingCompleteEvent)
, mFormat(aFormat)
, mSize(aSize)
, mUsingCustomOptions(aUsingCustomOptions)
{}
virtual ~EncodingRunnable() {}
NS_IMETHOD Run()
{
nsCOMPtr<nsIInputStream> stream;
nsresult rv = ImageEncoder::ExtractDataInternal(mType,
mOptions,
mImageBuffer,
mFormat,
mSize,
nullptr,
getter_AddRefs(stream),
mEncoder);
// If there are unrecognized custom parse options, we should fall back to
// the default values for the encoder without any options at all.
if (rv == NS_ERROR_INVALID_ARG && mUsingCustomOptions) {
rv = ImageEncoder::ExtractDataInternal(mType,
EmptyString(),
mImageBuffer,
mFormat,
mSize,
nullptr,
getter_AddRefs(stream),
mEncoder);
}
NS_ENSURE_SUCCESS(rv, rv);
uint64_t imgSize;
rv = stream->Available(&imgSize);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
void* imgData = nullptr;
rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
NS_ENSURE_SUCCESS(rv, rv);
mEncodingCompleteEvent->SetMembers(imgData, imgSize, mType);
rv = NS_DispatchToMainThread(mEncodingCompleteEvent, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
private:
nsAutoString mType;
nsAutoString mOptions;
nsAutoArrayPtr<uint8_t> mImageBuffer;
nsCOMPtr<imgIEncoder> mEncoder;
nsRefPtr<EncodingCompleteEvent> mEncodingCompleteEvent;
int32_t mFormat;
const nsIntSize mSize;
bool mUsingCustomOptions;
};
NS_IMPL_ISUPPORTS1(EncodingRunnable, nsIRunnable)
/* static */
nsresult
ImageEncoder::ExtractData(nsAString& aType,
const nsAString& aOptions,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIInputStream** aStream)
{
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
if (!encoder) {
return NS_IMAGELIB_ERROR_NO_ENCODER;
}
return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, aContext,
aStream, encoder);
}
/* static */
nsresult
ImageEncoder::ExtractDataAsync(nsAString& aType,
const nsAString& aOptions,
bool aUsingCustomOptions,
uint8_t* aImageBuffer,
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIScriptContext* aScriptContext,
FileCallback& aCallback)
{
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
if (!encoder) {
return NS_IMAGELIB_ERROR_NO_ENCODER;
}
nsCOMPtr<nsIThread> encoderThread;
nsresult rv = NS_NewThread(getter_AddRefs(encoderThread), nullptr);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<EncodingCompleteEvent> completeEvent =
new EncodingCompleteEvent(aScriptContext, encoderThread, aCallback);
nsCOMPtr<nsIRunnable> event = new EncodingRunnable(aType,
aOptions,
aImageBuffer,
encoder,
completeEvent,
aFormat,
aSize,
aUsingCustomOptions);
return encoderThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
/*static*/ nsresult
ImageEncoder::GetInputStream(int32_t aWidth,
int32_t aHeight,
uint8_t* aImageBuffer,
int32_t aFormat,
imgIEncoder* aEncoder,
const PRUnichar* aEncoderOptions,
nsIInputStream** aStream)
{
nsresult rv =
aEncoder->InitFromData(aImageBuffer,
aWidth * aHeight * 4, aWidth, aHeight, aWidth * 4,
aFormat,
nsDependentString(aEncoderOptions));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(aEncoder, aStream);
}
/* static */
nsresult
ImageEncoder::ExtractDataInternal(const nsAString& aType,
const nsAString& aOptions,
uint8_t* aImageBuffer,
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIInputStream** aStream,
imgIEncoder* aEncoder)
{
nsCOMPtr<nsIInputStream> imgStream;
// get image bytes
nsresult rv;
if (aImageBuffer) {
rv = ImageEncoder::GetInputStream(
aSize.width,
aSize.height,
aImageBuffer,
aFormat,
aEncoder,
nsPromiseFlatString(aOptions).get(),
getter_AddRefs(imgStream));
} else if (aContext) {
NS_ConvertUTF16toUTF8 encoderType(aType);
rv = aContext->GetInputStream(encoderType.get(),
nsPromiseFlatString(aOptions).get(),
getter_AddRefs(imgStream));
} else {
// no context, so we have to encode an empty image
// note that if we didn't have a current context, the spec says we're
// supposed to just return transparent black pixels of the canvas
// dimensions.
nsRefPtr<gfxImageSurface> emptyCanvas =
new gfxImageSurface(gfxIntSize(aSize.width, aSize.height),
gfxASurface::ImageFormatARGB32);
if (emptyCanvas->CairoStatus()) {
return NS_ERROR_INVALID_ARG;
}
rv = aEncoder->InitFromData(emptyCanvas->Data(),
aSize.width * aSize.height * 4,
aSize.width,
aSize.height,
aSize.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
aOptions);
if (NS_SUCCEEDED(rv)) {
imgStream = do_QueryInterface(aEncoder);
}
}
NS_ENSURE_SUCCESS(rv, rv);
imgStream.forget(aStream);
return rv;
}
/* static */
already_AddRefed<imgIEncoder>
ImageEncoder::GetImageEncoder(nsAString& aType)
{
// Get an image encoder for the media type.
nsCString encoderCID("@mozilla.org/image/encoder;2?type=");
NS_ConvertUTF16toUTF8 encoderType(aType);
encoderCID += encoderType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
if (!encoder && aType != NS_LITERAL_STRING("image/png")) {
// Unable to create an encoder instance of the specified type. Falling back
// to PNG.
aType.AssignLiteral("image/png");
nsCString PNGEncoderCID("@mozilla.org/image/encoder;2?type=image/png");
encoder = do_CreateInstance(PNGEncoderCID.get());
}
return encoder.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ImageEncoder_h
#define ImageEncoder_h
#include "imgIEncoder.h"
#include "nsDOMFile.h"
#include "nsError.h"
#include "mozilla/dom/HTMLCanvasElementBinding.h"
#include "nsLayoutUtils.h"
#include "nsNetUtil.h"
#include "nsSize.h"
class nsICanvasRenderingContextInternal;
namespace mozilla {
namespace dom {
class EncodingRunnable;
class ImageEncoder
{
public:
// Extracts data synchronously and gives you a stream containing the image
// represented by aContext. aType may change to "image/png" if we had to fall
// back to a PNG encoder. A return value of NS_OK implies successful data
// extraction. If there are any unrecognized custom parse options in
// aOptions, NS_ERROR_INVALID_ARG will be returned. When encountering this
// error it is usual to call this function again without any options at all.
static nsresult ExtractData(nsAString& aType,
const nsAString& aOptions,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIInputStream** aStream);
// Extracts data asynchronously. aType may change to "image/png" if we had to
// fall back to a PNG encoder. aOptions are the options to be passed to the
// encoder and aUsingCustomOptions specifies whether custom parse options were
// used (i.e. by using -moz-parse-options). If there are any unrecognized
// custom parse options, we fall back to the default values for the encoder
// without any options at all. A return value of NS_OK only implies
// successful dispatching of the extraction step to the encoding thread.
static nsresult ExtractDataAsync(nsAString& aType,
const nsAString& aOptions,
bool aUsingCustomOptions,
uint8_t* aImageBuffer,
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIScriptContext* aScriptContext,
FileCallback& aCallback);
// Gives you a stream containing the image represented by aImageBuffer.
// The format is given in aFormat, for example
// imgIEncoder::INPUT_FORMAT_HOSTARGB.
static nsresult GetInputStream(int32_t aWidth,
int32_t aHeight,
uint8_t* aImageBuffer,
int32_t aFormat,
imgIEncoder* aEncoder,
const PRUnichar* aEncoderOptions,
nsIInputStream** aStream);
private:
// When called asynchronously, aContext is null.
static nsresult
ExtractDataInternal(const nsAString& aType,
const nsAString& aOptions,
uint8_t* aImageBuffer,
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIInputStream** aStream,
imgIEncoder* aEncoder);
// Creates and returns an encoder instance of the type specified in aType.
// aType may change to "image/png" if no instance of the original type could
// be created and we had to fall back to a PNG encoder. A return value of
// NULL should be interpreted as NS_IMAGELIB_ERROR_NO_ENCODER and aType is
// undefined in this case.
static already_AddRefed<imgIEncoder> GetImageEncoder(nsAString& aType);
friend class EncodingRunnable;
};
} // namespace dom
} // namespace mozilla
#endif // ImageEncoder_h

View File

@ -22,5 +22,6 @@ INCLUDES += \
-I$(srcdir)/../../html/content/src \
-I$(srcdir)/../../../js/xpconnect/src \
-I$(srcdir)/../../../dom/base \
-I$(srcdir)/../../../image/src \
-I$(topsrcdir)/content/xul/content/src \
$(NULL)

View File

@ -27,7 +27,7 @@
#include "nsIVariant.h"
#include "imgIEncoder.h"
#include "ImageEncoder.h"
#include "gfxContext.h"
#include "gfxPattern.h"
@ -721,6 +721,54 @@ void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
}
}
void
WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
{
*aImageBuffer = nullptr;
*aFormat = 0;
nsRefPtr<gfxImageSurface> imgsurf =
new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxASurface::ImageFormatARGB32);
if (!imgsurf || imgsurf->CairoStatus()) {
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) {
return;
}
// Use Render() to make sure that appropriate y-flip gets applied
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
nsresult rv = Render(ctx, gfxPattern::FILTER_NEAREST, flags);
if (NS_FAILED(rv)) {
return;
}
int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
if (!mOptions.premultipliedAlpha) {
// We need to convert to INPUT_FORMAT_RGBA, otherwise
// we are automatically considered premult, and unpremult'd.
// Yes, it is THAT silly.
// Except for different lossy conversions by color,
// we could probably just change the label, and not change the data.
gfxUtils::ConvertBGRAtoRGBA(imgsurf);
format = imgIEncoder::INPUT_FORMAT_RGBA;
}
static const fallible_t fallible = fallible_t();
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!imageBuffer) {
return;
}
memcpy(imageBuffer, imgsurf->Data(), mWidth * mHeight * 4);
*aImageBuffer = imageBuffer;
*aFormat = format;
}
NS_IMETHODIMP
WebGLContext::GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions,
@ -730,48 +778,22 @@ WebGLContext::GetInputStream(const char* aMimeType,
if (!gl)
return NS_ERROR_FAILURE;
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxASurface::ImageFormatARGB32);
if (surf->CairoStatus() != 0)
uint8_t* imageBuffer = nullptr;
int32_t format = 0;
GetImageBuffer(&imageBuffer, &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE;
nsRefPtr<gfxContext> tmpcx = new gfxContext(surf);
// Use Render() to make sure that appropriate y-flip gets applied
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
nsresult rv = Render(tmpcx, gfxPattern::FILTER_NEAREST, flags);
if (NS_FAILED(rv))
return rv;
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
nsAutoArrayPtr<char> conid(new char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
strcpy(conid, encoderPrefix);
strcat(conid, aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
if (!encoder)
return NS_ERROR_FAILURE;
int format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
if (!mOptions.premultipliedAlpha) {
// We need to convert to INPUT_FORMAT_RGBA, otherwise
// we are automatically considered premult, and unpremult'd.
// Yes, it is THAT silly.
// Except for different lossy conversions by color,
// we could probably just change the label, and not change the data.
gfxUtils::ConvertBGRAtoRGBA(surf);
format = imgIEncoder::INPUT_FORMAT_RGBA;
}
rv = encoder->InitFromData(surf->Data(),
mWidth * mHeight * 4,
mWidth, mHeight,
surf->Stride(),
format,
nsDependentString(aEncoderOptions));
NS_ENSURE_SUCCESS(rv, rv);
nsCString enccid("@mozilla.org/image/encoder;2?type=");
enccid += aMimeType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
if (!encoder) {
return NS_ERROR_FAILURE;
}
return CallQueryInterface(encoder, aStream);
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
encoder, aEncoderOptions, aStream);
}
NS_IMETHODIMP

View File

@ -160,6 +160,7 @@ public:
NS_IMETHOD Render(gfxContext *ctx,
gfxPattern::GraphicsFilter f,
uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions,
nsIInputStream **aStream) MOZ_OVERRIDE;

View File

@ -22,6 +22,7 @@ CPP_SOURCES += [
'DocumentRendererChild.cpp',
'DocumentRendererParent.cpp',
'ImageData.cpp',
'ImageEncoder.cpp',
]
if CONFIG['MOZ_WEBGL']:

View File

@ -7,42 +7,43 @@
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
var gCompares = 0;
function compareAsync(file, canvas, type)
function compareAsync(file, canvas, type, callback)
{
++gCompares;
var reader = new FileReader();
reader.onload =
function(e) {
is(e.target.result, canvas.toDataURL(type),
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
if (--gCompares == 0) {
SimpleTest.finish();
}
callback(canvas);
};
reader.readAsDataURL(file);
}
function test1(canvas)
{
var pngfile = canvas.mozGetAsFile("foo.png");
is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
compareAsync(pngfile, canvas, "image/png", test2);
is(pngfile.name, "foo.png", "File name should be what we passed in");
}
function test2(canvas)
{
var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
is(jpegfile.type, "image/jpeg",
"When a valid type is specified that should be returned");
compareAsync(jpegfile, canvas, "image/jpeg", SimpleTest.finish);
is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
var pngfile = canvas.mozGetAsFile("foo.png");
is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
compareAsync(pngfile, canvas, "image/png");
is(pngfile.name, "foo.png", "File name should be what we passed in");
var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
is(jpegfile.type, "image/jpeg",
"When a valid type is specified that should be returned");
compareAsync(jpegfile, canvas, "image/jpeg");
is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
test1(canvas);
});
</script>

View File

@ -1,5 +1,5 @@
<!DOCTYPE HTML>
<title>Canvas test: mozGetAsFile</title>
<title>Canvas test: toBlob</title>
<script src="/MochiKit/MochiKit.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
@ -7,34 +7,40 @@
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
var gCompares = 2;
function BlobListener(type, canvas, file)
function BlobListener(type, canvas, callback, file)
{
is(file.type, type,
"When a valid type is specified that should be returned");
var reader = new FileReader();
reader.onload =
reader.onload =
function(e) {
is(e.target.result, canvas.toDataURL(type),
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
if (--gCompares == 0) {
SimpleTest.finish();
}
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
callback(canvas);
};
reader.readAsDataURL(file);
}
function test1(canvas)
{
canvas.toBlob(BlobListener.bind(undefined, "image/png", canvas, test2));
}
function test2(canvas)
{
canvas.toBlob(
BlobListener.bind(undefined, "image/jpeg", canvas, SimpleTest.finish),
"image/jpeg");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
canvas.toBlob(BlobListener.bind(undefined, "image/png", canvas));
canvas.toBlob(BlobListener.bind(undefined, "image/jpeg", canvas), "image/jpeg");
test1(canvas);
});
</script>

View File

@ -223,10 +223,9 @@ protected:
const JS::Value& aEncoderOptions,
nsAString& aParams,
bool* usingCustomParseOptions);
nsresult ExtractData(const nsAString& aType,
nsresult ExtractData(nsAString& aType,
const nsAString& aOptions,
nsIInputStream** aStream,
bool& aFellBackToPNG);
nsIInputStream** aStream);
nsresult ToDataURLImpl(JSContext* aCx,
const nsAString& aMimeType,
const JS::Value& aEncoderOptions,

View File

@ -5,10 +5,10 @@
#include "mozilla/dom/HTMLCanvasElement.h"
#include "Layers.h"
#include "imgIEncoder.h"
#include "ImageEncoder.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "Layers.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
@ -22,6 +22,7 @@
#include "nsContentUtils.h"
#include "nsDisplayList.h"
#include "nsDOMFile.h"
#include "nsDOMJSUtils.h"
#include "nsFrameManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsITimer.h"
@ -45,29 +46,6 @@ namespace {
typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
HTMLImageOrCanvasOrVideoElement;
class ToBlobRunnable : public nsRunnable
{
public:
ToBlobRunnable(mozilla::dom::FileCallback& aCallback,
nsIDOMBlob* aBlob)
: mCallback(&aCallback),
mBlob(aBlob)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
}
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mozilla::ErrorResult rv;
mCallback->Call(mBlob, rv);
return rv.ErrorCode();
}
private:
nsRefPtr<mozilla::dom::FileCallback> mCallback;
nsCOMPtr<nsIDOMBlob> mBlob;
};
} // anonymous namespace
namespace mozilla {
@ -352,10 +330,10 @@ HTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
return NS_ERROR_FAILURE;
nsresult rv;
bool fellBackToPNG = false;
nsCOMPtr<nsIInputStream> inputData;
rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG);
nsAutoString type(aType);
rv = ExtractData(type, EmptyString(), getter_AddRefs(inputData));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
@ -387,68 +365,15 @@ HTMLCanvasElement::GetMozPrintCallback() const
}
nsresult
HTMLCanvasElement::ExtractData(const nsAString& aType,
HTMLCanvasElement::ExtractData(nsAString& aType,
const nsAString& aOptions,
nsIInputStream** aStream,
bool& aFellBackToPNG)
nsIInputStream** aStream)
{
// note that if we don't have a current context, the spec says we're
// supposed to just return transparent black pixels of the canvas
// dimensions.
nsRefPtr<gfxImageSurface> emptyCanvas;
nsIntSize size = GetWidthHeight();
if (!mCurrentContext) {
emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
if (emptyCanvas->CairoStatus()) {
return NS_ERROR_INVALID_ARG;
}
}
nsresult rv;
// get image bytes
nsCOMPtr<nsIInputStream> imgStream;
NS_ConvertUTF16toUTF8 encoderType(aType);
try_again:
if (mCurrentContext) {
rv = mCurrentContext->GetInputStream(encoderType.get(),
nsPromiseFlatString(aOptions).get(),
getter_AddRefs(imgStream));
} else {
// no context, so we have to encode the empty image we created above
nsCString enccid("@mozilla.org/image/encoder;2?type=");
enccid += encoderType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get(), &rv);
if (NS_SUCCEEDED(rv) && encoder) {
rv = encoder->InitFromData(emptyCanvas->Data(),
size.width * size.height * 4,
size.width,
size.height,
size.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
aOptions);
if (NS_SUCCEEDED(rv)) {
imgStream = do_QueryInterface(encoder);
}
} else {
rv = NS_ERROR_FAILURE;
}
}
if (NS_FAILED(rv) && !aFellBackToPNG) {
// Try image/png instead.
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
aFellBackToPNG = true;
encoderType.AssignLiteral("image/png");
goto try_again;
}
NS_ENSURE_SUCCESS(rv, rv);
imgStream.forget(aStream);
return NS_OK;
return ImageEncoder::ExtractData(aType,
aOptions,
GetSize(),
mCurrentContext,
aStream);
}
nsresult
@ -499,8 +424,6 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
const JS::Value& aEncoderOptions,
nsAString& aDataURL)
{
bool fallbackToPNG = false;
nsIntSize size = GetWidthHeight();
if (size.height == 0 || size.width == 0) {
aDataURL = NS_LITERAL_STRING("data:,");
@ -521,23 +444,18 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
}
nsCOMPtr<nsIInputStream> stream;
rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
rv = ExtractData(type, params, getter_AddRefs(stream));
// If there are unrecognized custom parse options, we should fall back to
// the default values for the encoder without any options at all.
if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
fallbackToPNG = false;
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
}
NS_ENSURE_SUCCESS(rv, rv);
// build data URL string
if (fallbackToPNG)
aDataURL = NS_LITERAL_STRING("data:image/png;base64,");
else
aDataURL = NS_LITERAL_STRING("data:") + type +
NS_LITERAL_STRING(";base64,");
aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
uint64_t count;
rv = stream->Available(&count);
@ -547,7 +465,6 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
}
// XXXkhuey the encoding should be off the main thread, but we're lazy.
void
HTMLCanvasElement::ToBlob(JSContext* aCx,
FileCallback& aCallback,
@ -578,52 +495,24 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
return;
}
bool fallbackToPNG = false;
nsCOMPtr<nsIScriptContext> scriptContext =
GetScriptContextFromJSContext(nsContentUtils::GetCurrentJSContext());
nsCOMPtr<nsIInputStream> stream;
aRv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
// If there are unrecognized custom parse options, we should fall back to
// the default values for the encoder without any options at all.
if (aRv.ErrorCode() == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
fallbackToPNG = false;
aRv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
uint8_t* imageBuffer = nullptr;
int32_t format = 0;
if (mCurrentContext) {
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
}
if (aRv.Failed()) {
return;
}
if (fallbackToPNG) {
type.AssignLiteral("image/png");
}
uint64_t imgSize;
aRv = stream->Available(&imgSize);
if (aRv.Failed()) {
return;
}
if (imgSize > UINT32_MAX) {
aRv.Throw(NS_ERROR_FILE_TOO_BIG);
return;
}
void* imgData = nullptr;
aRv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
if (aRv.Failed()) {
return;
}
// The DOMFile takes ownership of the buffer
nsRefPtr<nsDOMMemoryFile> blob =
new nsDOMMemoryFile(imgData, imgSize, type);
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
JS_updateMallocCounter(cx, imgSize);
}
nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
aRv = NS_DispatchToCurrentThread(runnable);
aRv = ImageEncoder::ExtractDataAsync(type,
params,
usingCustomParseOptions,
imageBuffer,
format,
GetSize(),
mCurrentContext,
scriptContext,
aCallback);
}
already_AddRefed<nsIDOMFile>
@ -657,17 +546,10 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType,
nsIDOMFile** aResult)
{
bool fallbackToPNG = false;
nsCOMPtr<nsIInputStream> stream;
nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
fallbackToPNG);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString type(aType);
if (fallbackToPNG) {
type.AssignLiteral("image/png");
}
nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
uint64_t imgSize;
rv = stream->Available(&imgSize);

View File

@ -22,6 +22,7 @@ INCLUDES += \
-I$(srcdir)/../../../../editor/libeditor/text \
-I$(srcdir)/../../../../editor/txmgr/src \
-I$(srcdir)/../../../../netwerk/base/src \
-I$(srcdir)/../../../../content/canvas/src \
-I$(srcdir) \
-I$(topsrcdir)/xpcom/ds \
-I$(topsrcdir)/content/media/ \

View File

@ -912,6 +912,10 @@ void MediaDecoderStateMachine::DecodeLoop()
TimeStamp start = TimeStamp::Now();
videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, currentTime);
decodeTime = TimeStamp::Now() - start;
if (!videoPlaying) {
// Playback ended for this stream, close the sample queue.
mReader->VideoQueue().Finish();
}
}
if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > lowAudioThreshold &&
!HasLowUndecodedData())
@ -935,6 +939,10 @@ void MediaDecoderStateMachine::DecodeLoop()
if (!mDidThrottleAudioDecoding) {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
audioPlaying = mReader->DecodeAudioData();
if (!audioPlaying) {
// Playback ended for this stream, close the sample queue.
mReader->AudioQueue().Finish();
}
}
SendStreamData();

View File

@ -214,7 +214,6 @@ DirectShowReader::Finish(HRESULT aStatus)
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
LOG("DirectShowReader::Finish(0x%x)", aStatus);
mAudioQueue.Finish();
// Notify the filter graph of end of stream.
RefPtr<IMediaEventSink> eventSink;
HRESULT hr = mGraph->QueryInterface(static_cast<IMediaEventSink**>(byRef(eventSink)));

View File

@ -77,10 +77,9 @@ public:
private:
// Calls mAudioQueue.Finish(), and notifies the filter graph that playback
// is complete. aStatus is the code to send to the filter graph.
// Always returns false, so that we can just "return Finish()" from
// DecodeAudioData().
// Notifies the filter graph that playback is complete. aStatus is
// the code to send to the filter graph. Always returns false, so
// that we can just "return Finish()" from DecodeAudioData().
bool Finish(HRESULT aStatus);
// DirectShow filter graph, and associated playback and seeking

View File

@ -463,7 +463,6 @@ bool GStreamerReader::DecodeAudioData()
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
if (mReachedEos) {
mAudioQueue.Finish();
return false;
}
@ -528,7 +527,6 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
if (mReachedEos) {
mVideoQueue.Finish();
return false;
}
@ -1039,8 +1037,6 @@ void GStreamerReader::Eos()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
/* Potentially unblock the decode thread in ::DecodeLoop */
mVideoQueue.Finish();
mAudioQueue.Finish();
mon.NotifyAll();
}
}

View File

@ -623,7 +623,6 @@ bool OggReader::DecodeAudioData()
} while (packet && codecState->IsHeader(packet));
if (!packet) {
mAudioQueue.Finish();
return false;
}
@ -642,7 +641,6 @@ bool OggReader::DecodeAudioData()
// We've encountered an end of bitstream packet, or we've hit the end of
// file while trying to decode, so inform the audio queue that there'll
// be no more samples.
mAudioQueue.Finish();
return false;
}
@ -840,7 +838,6 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
packet = NextOggPacket(mTheoraState);
} while (packet && mTheoraState->IsHeader(packet));
if (!packet) {
mVideoQueue.Finish();
return false;
}
nsAutoRef<ogg_packet> autoRelease(packet);
@ -864,7 +861,6 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
if (eos) {
// We've encountered an end of bitstream packet. Inform the queue that
// there will be no more frames.
mVideoQueue.Finish();
return false;
}

View File

@ -171,7 +171,6 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
frame.mGraphicBuffer = nullptr;
frame.mShouldSkip = false;
if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) {
mVideoQueue.Finish();
return false;
}
doSeek = false;
@ -289,7 +288,6 @@ bool MediaOmxReader::DecodeAudioData()
// Read next frame
MPAPI::AudioFrame frame;
if (!mOmxDecoder->ReadAudio(&frame, mAudioSeekTimeUs)) {
mAudioQueue.Finish();
return false;
}
mAudioSeekTimeUs = -1;

View File

@ -148,7 +148,6 @@ bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
mVideoQueue.Push(mLastVideoFrame);
mLastVideoFrame = NULL;
}
mVideoQueue.Finish();
return false;
}
mVideoSeekTimeUs = -1;
@ -292,7 +291,6 @@ bool MediaPluginReader::DecodeAudioData()
// Read next frame
MPAPI::AudioFrame frame;
if (!mPlugin->ReadAudio(mPlugin, &frame, mAudioSeekTimeUs)) {
mAudioQueue.Finish();
return false;
}
mAudioSeekTimeUs = -1;

View File

@ -208,7 +208,6 @@ bool WaveReader::DecodeAudioData()
nsAutoArrayPtr<char> dataBuffer(new char[static_cast<size_t>(readSize)]);
if (!ReadAll(dataBuffer, readSize)) {
mAudioQueue.Finish();
return false;
}

View File

@ -773,7 +773,6 @@ bool WebMReader::DecodeAudioData()
nsAutoRef<NesteggPacketHolder> holder(NextPacket(AUDIO));
if (!holder) {
AudioQueue().Finish();
return false;
}
@ -792,7 +791,6 @@ bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
nsAutoRef<NesteggPacketHolder> holder(NextPacket(VIDEO));
if (!holder) {
VideoQueue().Finish();
return false;
}

View File

@ -688,7 +688,6 @@ WMFReader::DecodeAudioData()
if (FAILED(hr)) {
LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr);
// End the stream.
mAudioQueue.Finish();
return false;
}
@ -703,7 +702,6 @@ WMFReader::DecodeAudioData()
LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
hr, flags);
// End the stream.
mAudioQueue.Finish();
return false;
}
@ -925,8 +923,6 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
nullptr);
if (FAILED(hr)) {
LOG("WMFReader::DecodeVideoData() ReadSample failed with hr=0x%x", hr);
// End the stream.
mVideoQueue.Finish();
return false;
}
@ -938,7 +934,6 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
if (flags & MF_SOURCE_READERF_ERROR) {
NS_WARNING("WMFReader: Catastrophic failure reading video sample");
// Future ReadSample() calls will fail, so give up and report end of stream.
mVideoQueue.Finish();
return false;
}
@ -950,8 +945,6 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
if (!sample) {
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
LOG("WMFReader; Null sample after video decode, at end of stream");
// End the stream.
mVideoQueue.Finish();
return false;
}
LOG("WMFReader; Null sample after video decode. Maybe insufficient data...");
@ -966,7 +959,6 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
if (FAILED(hr) ||
FAILED(ConfigureVideoFrameGeometry(mediaType))) {
NS_WARNING("Failed to reconfigure video media type");
mVideoQueue.Finish();
return false;
}
}
@ -997,7 +989,6 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
// End of stream.
mVideoQueue.Finish();
LOG("End of video stream");
return false;
}

View File

@ -12731,7 +12731,7 @@ nsDocShell::GetAppId(uint32_t* aAppId)
NS_IMETHODIMP
nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
{
if (TabChild* tabChild = GetTabChildFrom(this)) {
if (TabChild* tabChild = TabChild::GetFrom(this)) {
*aOut = tabChild->IsAsyncPanZoomEnabled();
return NS_OK;
}

View File

@ -2343,7 +2343,7 @@ nsJSContext::LoadEnd()
void
nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
{
if (sGCTimer || sShuttingDown) {
if (sGCTimer || sInterSliceGCTimer || sShuttingDown) {
// There's already a timer for GC'ing, just return
return;
}

View File

@ -1801,6 +1801,42 @@ public:
}
};
template<typename T>
class MOZ_STACK_CLASS RootedUnion : public T,
private JS::CustomAutoRooter
{
public:
RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
T(),
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
{
}
virtual void trace(JSTracer *trc) MOZ_OVERRIDE
{
this->TraceUnion(trc);
}
};
template<typename T>
class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
private JS::CustomAutoRooter
{
public:
NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
Nullable<T>(),
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
{
}
virtual void trace(JSTracer *trc) MOZ_OVERRIDE
{
if (!this->IsNull()) {
this->Value().TraceUnion(trc);
}
}
};
inline bool
IdEquals(jsid id, const char* string)
{

View File

@ -808,11 +808,8 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
config)
# FIXME: Unions are broken in workers. See bug 809899.
unionStructs[name] = CGUnionStruct(t, providers[0])
# Unions cannot contain JSObject*.
if not any(member.isObject() or member.isSpiderMonkeyInterface() for member in t.flatMemberTypes):
unionReturnValues[name] = CGUnionStruct(t,
providers[0],
isReturnValue=True)
unionReturnValues[name] = CGUnionStruct(t, providers[0],
isReturnValue=True)
for f in t.flatMemberTypes:
f = f.unroll()
@ -2740,8 +2737,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return templateBody
# A helper function for converting things that look like a JSObject*.
def handleJSObjectType(type, isMember, failureCode):
if not isMember:
def handleJSObjectType(type, isMember, isInUnionReturnValue,
failureCode):
if not isMember and not isInUnionReturnValue:
if isOptional:
# We have a specialization of Optional that will use a
# Rooted for the storage here.
@ -2750,8 +2748,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declType = CGGeneric("JS::Rooted<JSObject*>")
else:
assert (isMember == "Sequence" or isMember == "Variadic" or
isMember == "Dictionary")
# We'll get traced by the sequence or dictionary tracer
isMember == "Dictionary" or isInUnionReturnValue)
# We'll get traced by the sequence or dictionary or union tracer
declType = CGGeneric("JSObject*")
templateBody = "${declName} = &${val}.toObject();"
setToNullCode = "${declName} = nullptr;"
@ -3139,7 +3137,8 @@ for (uint32_t i = 0; i < length; ++i) {
if descriptor.nativeType == 'JSObject':
# XXXbz Workers code does this sometimes
assert descriptor.workers
return handleJSObjectType(type, isMember, failureCode)
return handleJSObjectType(type, isMember, isInUnionReturnValue,
failureCode)
if (descriptor.interface.isCallback() and
(descriptor.interface.identifier.name != "EventListener" or
@ -3301,7 +3300,7 @@ for (uint32_t i = 0; i < length; ++i) {
CGIndenter(onFailureBadType(failureCode, type.name)).define()))
template = wrapObjectTemplate(template, type, "${declName}.SetNull()",
failureCode)
if not isMember:
if not isMember and not isInUnionReturnValue:
# This is a bit annoying. In a union we don't want to have a
# holder, since unions don't support that. But if we're optional we
# want to have a holder, so that the callee doesn't see
@ -3572,7 +3571,8 @@ for (uint32_t i = 0; i < length; ++i) {
if type.isObject():
assert not isEnforceRange and not isClamp
return handleJSObjectType(type, isMember, failureCode)
return handleJSObjectType(type, isMember, isInUnionReturnValue,
failureCode)
if type.isDictionary():
if failureCode is not None and not isDefinitelyObject:
@ -4486,15 +4486,24 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
else:
result = CGTemplatedType("RootedDictionary", result)
resultArgs = "cx"
elif nullable:
result = CGTemplatedType("Nullable", result)
else:
if nullable:
result = CGTemplatedType("Nullable", result)
resultArgs = None
return result, True, None, resultArgs
if returnType.isUnion():
result = CGGeneric(returnType.unroll().name + "ReturnValue")
if returnType.nullable():
result = CGTemplatedType("Nullable", result)
return result, True, None, None
if not isMember and typeNeedsRooting(returnType, descriptorProvider):
if returnType.nullable():
result = CGTemplatedType("NullableRootedUnion", result)
else:
result = CGTemplatedType("RootedUnion", result)
resultArgs = "cx"
else:
if returnType.nullable():
result = CGTemplatedType("Nullable", result)
resultArgs = None
return result, True, None, resultArgs
if returnType.isDate():
result = CGGeneric("Date")
if returnType.nullable():
@ -4711,11 +4720,12 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
if type.isUnion():
memberWraps = []
for member in type.flatMemberTypes:
memberName = getUnionMemberName(member)
memberWrap = wrapTypeIntoCurrentCompartment(
member,
"%s.%s" % (value, getUnionMemberName(member)))
member, "%s.GetAs%s()" % (value, memberName))
if memberWrap:
memberWrap = CGIfWrapper(memberWrap, "mType == %s" % member)
memberWrap = CGIfWrapper(
memberWrap, "%s.Is%s()" % (value, memberName))
memberWraps.append(memberWrap)
return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None
@ -6134,7 +6144,8 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isReturnValue=
name = getUnionMemberName(type)
ctorArgs = "cx" if type.isSpiderMonkeyInterface() else ""
ctorNeedsCx = type.isSpiderMonkeyInterface() and not isReturnValue
ctorArgs = "cx" if ctorNeedsCx else ""
tryNextCode = ("tryNext = true;\n"
"return true;")
@ -6156,8 +6167,12 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isReturnValue=
externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
if type.isObject():
body = ("mUnion.mValue.mObject.SetValue(cx, obj);\n"
"mUnion.mType = mUnion.eObject;")
if isReturnValue:
body = ("mValue.mObject.SetValue(obj);\n"
"mType = eObject;")
else:
body = ("mUnion.mValue.mObject.SetValue(cx, obj);\n"
"mUnion.mType = mUnion.eObject;")
setter = ClassMethod("SetToObject", "void",
[Argument("JSContext*", "cx"),
Argument("JSObject*", "obj")],
@ -6193,7 +6208,7 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isReturnValue=
"setter": setter,
"holderType": conversionInfo.holderType.define() if conversionInfo.holderType else None,
"ctorArgs": ctorArgs,
"ctorArgList": [Argument("JSContext*", "cx")] if type.isSpiderMonkeyInterface() else []
"ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else []
}
def mapTemplate(template, templateVarArray):
@ -6225,6 +6240,7 @@ class CGUnionStruct(CGThing):
enumValues = ["eUninitialized"]
toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;"))]
destructorCases = [CGCase("eUninitialized", None)]
traceCases = []
unionValues = []
if self.type.hasNullableType:
enumValues.append("eNull")
@ -6242,7 +6258,7 @@ class CGUnionStruct(CGThing):
vars = getUnionTypeTemplateVars(self.type,
t, self.descriptorProvider,
isReturnValue=self.isReturnValue)
if vars["name"] != "Object":
if vars["name"] != "Object" or self.isReturnValue:
body=string.Template("mType = e${name};\n"
"return mValue.m${name}.SetValue(${ctorArgs});").substitute(vars)
# bodyInHeader must be false for return values because they own
@ -6279,15 +6295,20 @@ class CGUnionStruct(CGThing):
const=True,
bodyInHeader=True,
body=body))
if not self.isReturnValue:
body = string.Template('MOZ_ASSERT(Is${name}(), "Wrong type!");\n'
'return const_cast<${structType}&>(mValue.m${name}.Value());').substitute(vars)
methods.append(ClassMethod("GetAs" + vars["name"],
vars["externalType"],
[],
const=True,
bodyInHeader=True,
body=body))
body = string.Template('MOZ_ASSERT(Is${name}(), "Wrong type!");\n'
'return const_cast<${structType}&>(mValue.m${name}.Value());').substitute(vars)
if self.isReturnValue:
getterReturnType = "%s&" % vars["structType"]
else:
getterReturnType = vars["externalType"]
methods.append(ClassMethod("GetAs" + vars["name"],
getterReturnType,
[],
const=True,
bodyInHeader=True,
body=body))
unionValues.append(string.Template("UnionMember<${structType} > "
"m${name}").substitute(vars))
enumValues.append("e" + vars["name"])
@ -6297,6 +6318,19 @@ class CGUnionStruct(CGThing):
destructorCases.append(CGCase("e" + vars["name"],
CGGeneric("Destroy%s();"
% vars["name"])))
if self.isReturnValue and typeNeedsRooting(t, self.descriptorProvider):
if t.isObject():
traceCases.append(
CGCase("e" + vars["name"],
CGGeneric('JS_CallObjectTracer(trc, %s, "%s");' %
("&mValue.m" + vars["name"] + ".Value()",
"mValue.m" + vars["name"]))))
else:
assert t.isSpiderMonkeyInterface()
traceCases.append(
CGCase("e" + vars["name"],
CGGeneric("mValue.m%s.Value().TraceSelf(trc);" %
vars["name"])))
dtor = CGSwitch("mType", destructorCases).define()
@ -6307,6 +6341,16 @@ class CGUnionStruct(CGThing):
], body=CGSwitch("mType", toJSValCases,
default=CGGeneric("return false;")).define(), const=True))
if self.isReturnValue:
if len(traceCases):
traceBody = CGSwitch("mType", traceCases,
default=CGGeneric("")).define()
else:
traceBody = ""
methods.append(ClassMethod("TraceUnion", "void",
[Argument("JSTracer*", "trc")],
body=traceBody))
friend=" friend class %sArgument;\n" % str(self.type) if not self.isReturnValue else ""
return CGClass(str(self.type) + ("ReturnValue" if self.isReturnValue else ""),
members=members,
@ -8473,7 +8517,7 @@ if (""",
trace = CGGeneric('JS_CallValueTracer(trc, %s, "%s");' %
("&"+memberData, memberName))
elif (type.isSequence() or type.isDictionary() or
type.isSpiderMonkeyInterface()):
type.isSpiderMonkeyInterface() or type.isUnion()):
if type.nullable():
memberNullable = memberData
memberData = "%s.Value()" % memberData
@ -8481,6 +8525,8 @@ if (""",
trace = CGGeneric('DoTraceSequence(trc, %s);' % memberData)
elif type.isDictionary():
trace = CGGeneric('%s.TraceDictionary(trc);' % memberData)
elif type.isUnion():
trace = CGGeneric('%s.TraceUnion(trc);' % memberData)
else:
assert type.isSpiderMonkeyInterface()
trace = CGGeneric('%s.TraceSelf(trc);' % memberData)

View File

@ -541,14 +541,16 @@ public:
void PassNullableUnionWithDefaultValue11(const Nullable<UnrestrictedFloatOrString>& arg);
void PassNullableUnionWithDefaultValue12(const Nullable<UnrestrictedFloatOrString>& arg);
void ReceiveUnion(const CanvasPatternOrCanvasGradientReturnValue&);
void ReceiveUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&);
void ReceiveNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
void GetWritableUnion(const CanvasPatternOrCanvasGradientReturnValue&);
void ReceiveUnion(CanvasPatternOrCanvasGradientReturnValue&);
void ReceiveUnion2(JSContext*, ObjectOrLongReturnValue&);
void ReceiveUnionContainingNull(CanvasPatternOrNullOrCanvasGradientReturnValue&);
void ReceiveNullableUnion(Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
void ReceiveNullableUnion2(JSContext*, Nullable<ObjectOrLongReturnValue>&);
void GetWritableUnion(CanvasPatternOrCanvasGradientReturnValue&);
void SetWritableUnion(const CanvasPatternOrCanvasGradient&);
void GetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&);
void GetWritableUnionContainingNull(CanvasPatternOrNullOrCanvasGradientReturnValue&);
void SetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradient&);
void GetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
void GetWritableNullableUnion(Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
void SetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradient>&);
// Date types

View File

@ -494,8 +494,10 @@ interface TestInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
(CanvasPattern or CanvasGradient) receiveUnion();
(object or long) receiveUnion2();
(CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
(CanvasPattern or CanvasGradient)? receiveNullableUnion();
(object or long)? receiveNullableUnion2();
attribute (CanvasPattern or CanvasGradient) writableUnion;
attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;
@ -741,6 +743,7 @@ dictionary Dict : ParentDict {
unrestricted double nanUrDouble = NaN;
(float or DOMString) floatOrString = "str";
(object or long) objectOrLong;
ArrayBuffer arrayBuffer;
ArrayBuffer? nullableArrayBuffer;

View File

@ -390,8 +390,10 @@ interface TestExampleInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
//(CanvasPattern or CanvasGradient) receiveUnion();
//(object or long) receiveUnion2();
//(CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
//(CanvasPattern or CanvasGradient)? receiveNullableUnion();
//(object or long)? receiveNullableUnion2();
//attribute (CanvasPattern or CanvasGradient) writableUnion;
//attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;

View File

@ -414,8 +414,10 @@ interface TestJSImplInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
//(CanvasPattern or CanvasGradient) receiveUnion();
//(object or long) receiveUnion2();
//(CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
//(CanvasPattern or CanvasGradient)? receiveNullableUnion();
//(object or long)? receiveNullableUnion2();
//attribute (CanvasPattern or CanvasGradient) writableUnion;
//attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;

View File

@ -2154,7 +2154,7 @@ public:
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = GetTabChildFrom(mWindow->GetDocShell());
TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
if (!child) {
return NS_OK;
}
@ -3173,7 +3173,7 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath,
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = GetTabChildFrom(win->GetDocShell());
TabChild* child = TabChild::GetFrom(win->GetDocShell());
if (!child) {
return cursor.forget();
}

View File

@ -148,7 +148,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
factory->mContentParent = aContentParent;
if (!IndexedDatabaseManager::IsMainProcess()) {
TabChild* tabChild = GetTabChildFrom(aWindow);
TabChild* tabChild = TabChild::GetFrom(aWindow);
NS_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
IndexedDBChild* actor = new IndexedDBChild(origin);

View File

@ -388,13 +388,13 @@ TabChild::Observe(nsISupports *aSubject,
{
if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
if (tabChild == this) {
mRemoteFrame->CancelDefaultPanZoom();
}
} else if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
if (tabChild == this) {
CSSRect rect;
sscanf(NS_ConvertUTF16toUTF8(aData).get(),
@ -442,7 +442,7 @@ TabChild::Observe(nsISupports *aSubject,
}
} else if (!strcmp(aTopic, DETECT_SCROLLABLE_SUBFRAME)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
if (tabChild == this) {
mRemoteFrame->DetectScrollableSubframe();
}

View File

@ -342,6 +342,33 @@ public:
void UpdateHitRegion(const nsRegion& aRegion);
static inline TabChild*
GetFrom(nsIDocShell* aDocShell)
{
nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
return static_cast<TabChild*>(tc.get());
}
static inline TabChild*
GetFrom(nsIPresShell* aPresShell)
{
nsIDocument* doc = aPresShell->GetDocument();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
return GetFrom(docShell);
}
static inline TabChild*
GetFrom(nsIDOMWindow* aWindow)
{
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
return GetFrom(docShell);
}
protected:
virtual PRenderFrameChild* AllocPRenderFrameChild(ScrollingBehavior* aScrolling,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
@ -477,33 +504,6 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};
inline TabChild*
GetTabChildFrom(nsIDocShell* aDocShell)
{
nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
return static_cast<TabChild*>(tc.get());
}
inline TabChild*
GetTabChildFrom(nsIPresShell* aPresShell)
{
nsIDocument* doc = aPresShell->GetDocument();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
return GetTabChildFrom(docShell);
}
inline TabChild*
GetTabChildFrom(nsIDOMWindow* aWindow)
{
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
return GetTabChildFrom(docShell);
}
}
}

View File

@ -1461,7 +1461,7 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = GetTabChildFrom(window->GetDocShell());
TabChild* child = TabChild::GetFrom(window->GetDocShell());
if (!child) {
return false;
}

View File

@ -161,7 +161,7 @@ DesktopNotification::Init()
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild for this docshell.
TabChild* child = GetTabChildFrom(GetOwner()->GetDocShell());
TabChild* child = TabChild::GetFrom(GetOwner()->GetDocShell());
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.

View File

@ -140,7 +140,7 @@ NotificationPermissionRequest::Run()
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = GetTabChildFrom(mWindow->GetDocShell());
TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
if (!child) {
return NS_ERROR_NOT_AVAILABLE;
}

View File

@ -42,9 +42,11 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
{
if (aType == CanvasClientGLContext &&
aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
aFlags &= ~TEXTURE_DEALLOCATE_HOST;
return new DeprecatedCanvasClientSurfaceStream(aForwarder, aFlags);
}
if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
aFlags &= ~TEXTURE_DEALLOCATE_HOST;
return new DeprecatedCanvasClient2D(aForwarder, aFlags);
}
return new CanvasClient2D(aForwarder, aFlags);

View File

@ -162,6 +162,9 @@ CompositableHost::RemoveMaskEffect()
}
}
// implemented in TextureHostOGL.cpp
TemporaryRef<CompositableQuirks> CreateCompositableQuirksOGL();
/* static */ TemporaryRef<CompositableHost>
CompositableHost::Create(const TextureInfo& aTextureInfo)
{
@ -169,28 +172,33 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
switch (aTextureInfo.mCompositableType) {
case COMPOSITABLE_IMAGE:
result = new ImageHost(aTextureInfo);
return result;
break;
case BUFFER_IMAGE_BUFFERED:
result = new DeprecatedImageHostBuffered(aTextureInfo);
return result;
break;
case BUFFER_IMAGE_SINGLE:
result = new DeprecatedImageHostSingle(aTextureInfo);
return result;
break;
case BUFFER_TILED:
result = new TiledContentHost(aTextureInfo);
return result;
break;
case BUFFER_CONTENT:
result = new ContentHostSingleBuffered(aTextureInfo);
return result;
break;
case BUFFER_CONTENT_DIRECT:
result = new ContentHostDoubleBuffered(aTextureInfo);
return result;
break;
case BUFFER_CONTENT_INC:
result = new ContentHostIncremental(aTextureInfo);
return result;
break;
default:
MOZ_CRASH("Unknown CompositableType");
}
if (result) {
RefPtr<CompositableQuirks> quirks = CreateCompositableQuirksOGL();
result->SetCompositableQuirks(quirks);
}
return result;
}
#ifdef MOZ_DUMP_PAINTING

View File

@ -57,6 +57,23 @@ class ThebesBufferData;
class TiledLayerComposer;
struct EffectChain;
/**
* A base class for doing CompositableHost and platform dependent task on TextureHost.
*/
class CompositableQuirks : public RefCounted<CompositableQuirks>
{
public:
CompositableQuirks()
{
MOZ_COUNT_CTOR(CompositableQuirks);
}
virtual ~CompositableQuirks()
{
MOZ_COUNT_DTOR(CompositableQuirks);
}
virtual void SetCompositor(Compositor* aCompositor) {}
};
/**
* The compositor-side counterpart to CompositableClient. Responsible for
* updating textures and data about textures from IPC and how textures are
@ -82,6 +99,13 @@ public:
virtual CompositableType GetType() = 0;
virtual CompositableQuirks* GetCompositableQuirks() { return mQuirks; }
virtual void SetCompositableQuirks(CompositableQuirks* aQuirks)
{
mQuirks = aQuirks;
}
// If base class overrides, it should still call the parent implementation
virtual void SetCompositor(Compositor* aCompositor);
@ -268,6 +292,7 @@ protected:
TextureInfo mTextureInfo;
Compositor* mCompositor;
Layer* mLayer;
RefPtr<CompositableQuirks> mQuirks;
RefPtr<TextureHost> mFirstTexture;
bool mAttached;
bool mKeepAttached;

View File

@ -274,7 +274,8 @@ ContentHostSingleBuffered::EnsureDeprecatedTextureHost(TextureIdentifier aTextur
*newHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(aSurface.type(),
aTextureInfo.mDeprecatedTextureHostFlags,
aTextureInfo.mTextureFlags);
aTextureInfo.mTextureFlags,
this);
(*newHost)->SetBuffer(new SurfaceDescriptor(aSurface), aAllocator);
Compositor* compositor = GetCompositor();
@ -365,7 +366,8 @@ ContentHostDoubleBuffered::EnsureDeprecatedTextureHost(TextureIdentifier aTextur
{
RefPtr<DeprecatedTextureHost> newHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(aSurface.type(),
aTextureInfo.mDeprecatedTextureHostFlags,
aTextureInfo.mTextureFlags);
aTextureInfo.mTextureFlags,
this);
newHost->SetBuffer(new SurfaceDescriptor(aSurface), aAllocator);
@ -522,7 +524,8 @@ ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental*
RefPtr<DeprecatedTextureHost> newHost =
DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptor::TShmem,
mTextureInfo.mDeprecatedTextureHostFlags,
mTextureInfo.mTextureFlags);
mTextureInfo.mTextureFlags,
nullptr);
Compositor* compositor = aHost->GetCompositor();
if (compositor) {
newHost->SetCompositor(compositor);
@ -532,7 +535,8 @@ ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental*
newHostOnWhite =
DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptor::TShmem,
mTextureInfo.mDeprecatedTextureHostFlags,
mTextureInfo.mTextureFlags);
mTextureInfo.mTextureFlags,
nullptr);
Compositor* compositor = aHost->GetCompositor();
if (compositor) {
newHostOnWhite->SetCompositor(compositor);

View File

@ -241,7 +241,8 @@ DeprecatedImageHostSingle::MakeDeprecatedTextureHost(TextureIdentifier aTextureI
{
mDeprecatedTextureHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(aSurface.type(),
mTextureInfo.mDeprecatedTextureHostFlags,
mTextureInfo.mTextureFlags);
mTextureInfo.mTextureFlags,
this);
NS_ASSERTION(mDeprecatedTextureHost, "Failed to create texture host");

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/TextureHost.h"
#include "CompositableHost.h" // for CompositableHost
#include "LayersLogging.h" // for AppendToString
#include "gfx2DGlue.h" // for ToIntSize
#include "gfxImageSurface.h" // for gfxImageSurface
@ -45,13 +46,21 @@ TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostD3D11(SurfaceDesc
/* static */ TemporaryRef<DeprecatedTextureHost>
DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
uint32_t aDeprecatedTextureHostFlags,
uint32_t aTextureFlags)
uint32_t aTextureFlags,
CompositableHost* aCompositableHost)
{
switch (Compositor::GetBackend()) {
case LAYERS_OPENGL:
return CreateDeprecatedTextureHostOGL(aDescriptorType,
{
RefPtr<DeprecatedTextureHost> result;
result = CreateDeprecatedTextureHostOGL(aDescriptorType,
aDeprecatedTextureHostFlags,
aTextureFlags);
if (aCompositableHost) {
result->SetCompositableQuirks(aCompositableHost->GetCompositableQuirks());
}
return result;
}
#ifdef XP_WIN
case LAYERS_D3D9:
return CreateDeprecatedTextureHostD3D9(aDescriptorType,
@ -135,6 +144,37 @@ CreateBackendIndependentTextureHost(uint64_t aID,
return result;
}
void TextureHost::SetCompositableQuirks(CompositableQuirks* aQuirks)
{
mQuirks = aQuirks;
}
TextureHost::TextureHost(uint64_t aID,
TextureFlags aFlags)
: mID(aID)
, mNextTexture(nullptr)
, mFlags(aFlags)
{}
TextureHost::~TextureHost()
{
}
void TextureSource::SetCompositableQuirks(CompositableQuirks* aQuirks)
{
mQuirks = aQuirks;
}
TextureSource::TextureSource()
{
MOZ_COUNT_CTOR(TextureSource);
}
TextureSource::~TextureSource()
{
MOZ_COUNT_DTOR(TextureSource);
}
DeprecatedTextureHost::DeprecatedTextureHost()
: mFlags(0)
, mBuffer(nullptr)

View File

@ -38,6 +38,8 @@ class Shmem;
namespace layers {
class Compositor;
class CompositableHost;
class CompositableQuirks;
class SurfaceDescriptor;
class ISurfaceAllocator;
class TextureSourceOGL;
@ -77,14 +79,8 @@ public:
class TextureSource : public RefCounted<TextureSource>
{
public:
TextureSource()
{
MOZ_COUNT_CTOR(TextureSource);
}
virtual ~TextureSource()
{
MOZ_COUNT_DTOR(TextureSource);
}
TextureSource();
virtual ~TextureSource();
/**
* Return the size of the texture in texels.
@ -122,9 +118,14 @@ public:
*/
virtual TileIterator* AsTileIterator() { return nullptr; }
virtual void SetCompositableQuirks(CompositableQuirks* aQuirks);
#ifdef MOZ_LAYERS_HAVE_LOG
virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
#endif
protected:
RefPtr<CompositableQuirks> mQuirks;
};
@ -264,13 +265,9 @@ class TextureHost : public RefCounted<TextureHost>
{
public:
TextureHost(uint64_t aID,
TextureFlags aFlags)
: mID(aID)
, mNextTexture(nullptr)
, mFlags(aFlags)
{}
TextureFlags aFlags);
virtual ~TextureHost() {}
virtual ~TextureHost();
/**
* Factory method.
@ -389,6 +386,8 @@ public:
return LayerRenderState();
}
virtual void SetCompositableQuirks(CompositableQuirks* aQuirks);
#ifdef MOZ_LAYERS_HAVE_LOG
virtual void PrintInfo(nsACString& aTo, const char* aPrefix)
{
@ -403,6 +402,7 @@ protected:
uint64_t mID;
RefPtr<TextureHost> mNextTexture;
TextureFlags mFlags;
RefPtr<CompositableQuirks> mQuirks;
};
/**
@ -582,7 +582,8 @@ public:
*/
static TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
uint32_t aDeprecatedTextureHostFlags,
uint32_t aTextureFlags);
uint32_t aTextureFlags,
CompositableHost* aCompositableHost);
DeprecatedTextureHost();
virtual ~DeprecatedTextureHost();

View File

@ -300,7 +300,8 @@ TiledTexture::Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor*
// convert placeholder tile to a real tile
mDeprecatedTextureHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptor::Tnull_t,
TEXTURE_HOST_TILED,
flags);
flags,
nullptr);
mDeprecatedTextureHost->SetCompositor(aCompositor);
flags |= TEXTURE_NEW_TILE;
}

View File

@ -239,6 +239,11 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
op.textureFlags());
MOZ_ASSERT(tex.get());
tex->SetCompositor(compositable->GetCompositor());
// set CompositableQuirks
// on gonk, create EGLImage if possible.
// create EGLImage during buffer swap could reduce the graphic driver's task
// during rendering.
tex->SetCompositableQuirks(compositable->GetCompositableQuirks());
compositable->AddTextureHost(tex);
MOZ_ASSERT(compositable->GetTextureHost(op.textureID()) == tex.get());
break;

View File

@ -98,6 +98,12 @@ GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
MOZ_ASSERT(mGraphicBuffer.get());
}
GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
{
DeallocateDeviceData();
mCompositor = nullptr;
}
void GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
{
/*
@ -111,21 +117,13 @@ void GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
MOZ_ASSERT(gl());
gl()->MakeCurrent();
GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
GLuint textureTarget = GetTextureTarget();
gl()->fActiveTexture(aTextureUnit);
gl()->fBindTexture(textureTarget, tex);
if (!mEGLImage) {
mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
}
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
// XXX - Bug 909356
// This is a temporary fix to a bad lock/unlock race with the camera.
// It is bad for performances so we need to find a better way asap.
DeallocateDeviceData();
}
bool
@ -140,6 +138,16 @@ GrallocTextureSourceOGL::gl() const
return mCompositor ? mCompositor->gl() : nullptr;
}
void
GrallocTextureSourceOGL::SetCompositor(CompositorOGL* aCompositor)
{
if (mCompositor && !aCompositor) {
DeallocateDeviceData();
}
mCompositor = aCompositor;
}
GLenum
GrallocTextureSourceOGL::GetTextureTarget() const
{
@ -158,6 +166,30 @@ GrallocTextureSourceOGL::GetFormat() const {
return mFormat;
}
void
GrallocTextureSourceOGL::SetCompositableQuirks(CompositableQuirks* aQuirks)
{
mQuirks = aQuirks;
if (!mCompositor) {
return;
}
// delete old EGLImage
DeallocateDeviceData();
gl()->MakeCurrent();
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
GLuint textureTarget = GetTextureTarget();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(textureTarget, tex);
// create new EGLImage
mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
}
gfx::IntSize
GrallocTextureSourceOGL::GetSize() const
{
@ -200,10 +232,6 @@ GrallocTextureHostOGL::GrallocTextureHostOGL(uint64_t aID,
GrallocTextureHostOGL::~GrallocTextureHostOGL()
{
if (mTextureSource) {
mTextureSource->mGraphicBuffer = nullptr;
mTextureSource->SetCompositor(nullptr);
}
mTextureSource = nullptr;
}
@ -282,7 +310,8 @@ GrallocTextureSourceOGL::GetAsSurface() {
MOZ_ASSERT(gl());
gl()->MakeCurrent();
GLuint tex = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(GetTextureTarget(), tex);
if (!mEGLImage) {
@ -297,5 +326,14 @@ GrallocTextureSourceOGL::GetAsSurface() {
return surf.forget();
}
void
GrallocTextureHostOGL::SetCompositableQuirks(CompositableQuirks* aQuirks)
{
mQuirks = aQuirks;
if (mTextureSource) {
mTextureSource->SetCompositableQuirks(aQuirks);
}
}
} // namepsace layers
} // namepsace mozilla

View File

@ -26,6 +26,8 @@ public:
android::GraphicBuffer* aGraphicBuffer,
gfx::SurfaceFormat aFormat);
virtual ~GrallocTextureSourceOGL();
virtual bool IsValid() const MOZ_OVERRIDE;
virtual void BindTexture(GLenum aTextureUnit) MOZ_OVERRIDE;
@ -45,14 +47,13 @@ public:
return LOCAL_GL_CLAMP_TO_EDGE;
}
virtual void SetCompositableQuirks(CompositableQuirks* aQuirks) MOZ_OVERRIDE;
void DeallocateDeviceData();
gl::GLContext* gl() const;
void SetCompositor(CompositorOGL* aCompositor)
{
mCompositor = aCompositor;
}
void SetCompositor(CompositorOGL* aCompositor);
void ForgetBuffer()
{
@ -103,6 +104,8 @@ public:
virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
virtual void SetCompositableQuirks(CompositableQuirks* aQuirks) MOZ_OVERRIDE;
bool IsValid() const;
#ifdef MOZ_LAYERS_HAVE_LOG

View File

@ -41,6 +41,16 @@ namespace layers {
class Compositor;
TemporaryRef<CompositableQuirks>
CreateCompositableQuirksOGL()
{
#ifdef MOZ_WIDGET_GONK
return new CompositableQuirksGonkOGL();
#else
return nullptr;
#endif
}
TemporaryRef<DeprecatedTextureHost>
CreateDeprecatedTextureHostOGL(SurfaceDescriptorType aDescriptorType,
uint32_t aDeprecatedTextureHostFlags,
@ -156,6 +166,38 @@ WrapMode(gl::GLContext *aGl, bool aAllowRepeat)
return LOCAL_GL_CLAMP_TO_EDGE;
}
CompositableQuirksGonkOGL::CompositableQuirksGonkOGL()
: mTexture(0)
{
}
CompositableQuirksGonkOGL::~CompositableQuirksGonkOGL()
{
if (mTexture) {
gl()->MakeCurrent();
gl()->fDeleteTextures(1, &mTexture);
}
}
gl::GLContext*
CompositableQuirksGonkOGL::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
void CompositableQuirksGonkOGL::SetCompositor(Compositor* aCompositor)
{
mCompositor = static_cast<CompositorOGL*>(aCompositor);
}
GLuint CompositableQuirksGonkOGL::GetTexture()
{
if (!mTexture) {
gl()->MakeCurrent();
gl()->fGenTextures(1, &mTexture);
}
return mTexture;
}
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
TextureFlags aFlags,
@ -1081,8 +1123,20 @@ GrallocDeprecatedTextureHostOGL::SwapTexturesImpl(const SurfaceDescriptor& aImag
mIsRBSwapped);
mTextureTarget = TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
// delete old EGLImage
DeleteTextures();
#if 1
gl()->MakeCurrent();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(mTextureTarget, tex);
// create new EGLImage
// create EGLImage during buffer swap could reduce the graphic driver's task
// during rendering.
mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
#endif
}
@ -1109,14 +1163,11 @@ void GrallocDeprecatedTextureHostOGL::BindTexture(GLenum aTextureUnit)
MOZ_ASSERT(gl());
gl()->MakeCurrent();
GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
gl()->fActiveTexture(aTextureUnit);
gl()->fBindTexture(mTextureTarget, tex);
if (!mEGLImage) {
mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
}
gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
}
@ -1249,7 +1300,8 @@ already_AddRefed<gfxImageSurface>
GrallocDeprecatedTextureHostOGL::GetAsSurface() {
gl()->MakeCurrent();
GLuint tex = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
mQuirks->SetCompositor(mCompositor);
GLuint tex = static_cast<CompositableQuirksGonkOGL*>(mQuirks.get())->GetTexture();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(mTextureTarget, tex);
if (!mEGLImage) {

View File

@ -8,6 +8,7 @@
#include <stddef.h> // for size_t
#include <stdint.h> // for uint64_t
#include "CompositableHost.h"
#include "GLContextTypes.h" // for GLContext
#include "GLDefs.h" // for GLenum, LOCAL_GL_CLAMP_TO_EDGE, etc
#include "GLTextureImage.h" // for TextureImage
@ -53,6 +54,29 @@ class Compositor;
class CompositorOGL;
class TextureImageDeprecatedTextureHostOGL;
/**
* CompositableQuirks implementation for the Gonk OpenGL backend.
* Share a same texture between TextureHosts in the same CompositableHost.
* By shareing the texture among the TextureHosts, number of texture allocations
* can be reduced than texture allocation in every TextureHosts.
* From Bug 912134, use only one texture among all TextureHosts degrade
* the rendering performance.
* CompositableQuirksGonkOGL chooses in a middile of them.
*/
class CompositableQuirksGonkOGL : public CompositableQuirks
{
public:
CompositableQuirksGonkOGL();
virtual ~CompositableQuirksGonkOGL();
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
GLuint GetTexture();
gl::GLContext* gl() const;
protected:
RefPtr<CompositorOGL> mCompositor;
GLuint mTexture;
};
/*
* TextureHost implementations for the OpenGL backend.
*

View File

@ -240,11 +240,11 @@ gfxFontEntry::GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
bool
gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
int aDrawMode, gfxTextObjectPaint *aObjectPaint)
int aDrawMode, gfxTextContextPaint *aContextPaint)
{
NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
return mSVGGlyphs->RenderGlyph(aContext, aGlyphId, gfxFont::DrawMode(aDrawMode),
aObjectPaint);
aContextPaint);
}
bool
@ -2035,7 +2035,7 @@ struct GlyphBuffer {
}
void Flush(cairo_t *aCR, gfxFont::DrawMode aDrawMode, bool aReverse,
gfxTextObjectPaint *aObjectPaint,
gfxTextContextPaint *aContextPaint,
const gfxMatrix& aGlobalMatrix, bool aFinish = false) {
// Ensure there's enough room for a glyph to be added to the buffer
// and we actually have glyphs to draw
@ -2056,13 +2056,13 @@ struct GlyphBuffer {
} else {
if ((aDrawMode & (gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) ==
(gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) {
FlushStroke(aCR, aObjectPaint, aGlobalMatrix);
FlushStroke(aCR, aContextPaint, aGlobalMatrix);
}
if (aDrawMode & gfxFont::GLYPH_FILL) {
PROFILER_LABEL("GlyphBuffer", "cairo_show_glyphs");
nsRefPtr<gfxPattern> pattern;
if (aObjectPaint &&
!!(pattern = aObjectPaint->GetFillPattern(aGlobalMatrix))) {
if (aContextPaint &&
!!(pattern = aContextPaint->GetFillPattern(aGlobalMatrix))) {
cairo_save(aCR);
cairo_set_source(aCR, pattern->CairoPattern());
}
@ -2075,7 +2075,7 @@ struct GlyphBuffer {
}
if ((aDrawMode & (gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) ==
gfxFont::GLYPH_STROKE) {
FlushStroke(aCR, aObjectPaint, aGlobalMatrix);
FlushStroke(aCR, aContextPaint, aGlobalMatrix);
}
}
@ -2083,11 +2083,11 @@ struct GlyphBuffer {
}
private:
void FlushStroke(cairo_t *aCR, gfxTextObjectPaint *aObjectPaint,
void FlushStroke(cairo_t *aCR, gfxTextContextPaint *aContextPaint,
const gfxMatrix& aGlobalMatrix) {
nsRefPtr<gfxPattern> pattern;
if (aObjectPaint &&
!!(pattern = aObjectPaint->GetStrokePattern(aGlobalMatrix))) {
if (aContextPaint &&
!!(pattern = aContextPaint->GetStrokePattern(aGlobalMatrix))) {
cairo_save(aCR);
cairo_set_source(aCR, pattern->CairoPattern());
}
@ -2129,7 +2129,7 @@ struct GlyphBufferAzure {
return &mGlyphBuffer[mNumGlyphs++];
}
void Flush(DrawTarget *aDT, gfxTextObjectPaint *aObjectPaint, ScaledFont *aFont,
void Flush(DrawTarget *aDT, gfxTextContextPaint *aContextPaint, ScaledFont *aFont,
gfxFont::DrawMode aDrawMode, bool aReverse, const GlyphRenderingOptions *aOptions,
gfxContext *aThebesContext, const Matrix *aInvFontMatrix, const DrawOptions &aDrawOptions,
bool aFinish = false)
@ -2152,15 +2152,15 @@ struct GlyphBufferAzure {
gfxContext::AzureState state = aThebesContext->CurrentState();
if ((aDrawMode & (gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) ==
(gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) {
FlushStroke(aDT, aObjectPaint, aFont, aThebesContext, buf, state);
FlushStroke(aDT, aContextPaint, aFont, aThebesContext, buf, state);
}
if (aDrawMode & gfxFont::GLYPH_FILL) {
if (state.pattern || aObjectPaint) {
if (state.pattern || aContextPaint) {
Pattern *pat;
nsRefPtr<gfxPattern> fillPattern;
if (!aObjectPaint ||
!(fillPattern = aObjectPaint->GetFillPattern(aThebesContext->CurrentMatrix()))) {
if (!aContextPaint ||
!(fillPattern = aContextPaint->GetFillPattern(aThebesContext->CurrentMatrix()))) {
if (state.pattern) {
pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nullptr);
} else {
@ -2217,21 +2217,21 @@ struct GlyphBufferAzure {
}
if ((aDrawMode & (gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) ==
gfxFont::GLYPH_STROKE) {
FlushStroke(aDT, aObjectPaint, aFont, aThebesContext, buf, state);
FlushStroke(aDT, aContextPaint, aFont, aThebesContext, buf, state);
}
mNumGlyphs = 0;
}
private:
void FlushStroke(DrawTarget *aDT, gfxTextObjectPaint *aObjectPaint,
void FlushStroke(DrawTarget *aDT, gfxTextContextPaint *aContextPaint,
ScaledFont *aFont, gfxContext *aThebesContext,
gfx::GlyphBuffer& aBuf, gfxContext::AzureState& aState)
{
RefPtr<Path> path = aFont->GetPathForGlyphs(aBuf, aDT);
if (aObjectPaint) {
if (aContextPaint) {
nsRefPtr<gfxPattern> strokePattern =
aObjectPaint->GetStrokePattern(aThebesContext->CurrentMatrix());
aContextPaint->GetStrokePattern(aThebesContext->CurrentMatrix());
if (strokePattern) {
aDT->Stroke(path, *strokePattern->GetPattern(aDT), aState.strokeOptions);
}
@ -2279,7 +2279,7 @@ ForcePaintingDrawMode(gfxFont::DrawMode aDrawMode)
void
gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aPt,
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint,
Spacing *aSpacing, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks)
{
NS_ASSERTION(aDrawMode == gfxFont::GLYPH_PATH || !(aDrawMode & gfxFont::GLYPH_PATH),
@ -2296,14 +2296,14 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxMatrix globalMatrix = aContext->CurrentMatrix();
bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData();
nsAutoPtr<gfxTextObjectPaint> objectPaint;
if (haveSVGGlyphs && !aObjectPaint) {
nsAutoPtr<gfxTextContextPaint> contextPaint;
if (haveSVGGlyphs && !aContextPaint) {
// If no pattern is specified for fill, use the current pattern
NS_ASSERTION((aDrawMode & GLYPH_STROKE) == 0, "no pattern supplied for stroking text");
nsRefPtr<gfxPattern> fillPattern = aContext->GetPattern();
objectPaint = new SimpleTextObjectPaint(fillPattern, nullptr,
aContext->CurrentMatrix());
aObjectPaint = objectPaint;
contextPaint = new SimpleTextContextPaint(fillPattern, nullptr,
aContext->CurrentMatrix());
aContextPaint = contextPaint;
}
// synthetic-bold strikes are each offset one device pixel in run direction
@ -2362,7 +2362,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
ToDeviceUnits(y, devUnitsPerAppUnit));
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
glyphData->GetSimpleGlyph(), aObjectPaint,
glyphData->GetSimpleGlyph(), aContextPaint,
aCallbacks, emittedGlyphs)) {
continue;
}
@ -2377,7 +2377,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyph->index = glyphData->GetSimpleGlyph();
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
// synthetic bolding by multi-striking with 1-pixel offsets
// at least once, more if there's room (large font sizes)
@ -2393,7 +2393,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
@ -2440,7 +2440,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
details->mGlyphID,
aObjectPaint, aCallbacks,
aContextPaint, aCallbacks,
emittedGlyphs)) {
continue;
}
@ -2450,7 +2450,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyph->index = details->mGlyphID;
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
@ -2465,7 +2465,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
@ -2494,7 +2494,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
// draw any remaining glyphs
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix, true);
glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix, true);
if (aCallbacks && emittedGlyphs) {
aCallbacks->NotifyGlyphPathEmitted();
}
@ -2577,7 +2577,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
ToDeviceUnits(y, devUnitsPerAppUnit));
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
glyphData->GetSimpleGlyph(), aObjectPaint,
glyphData->GetSimpleGlyph(), aContextPaint,
aCallbacks, emittedGlyphs)) {
continue;
}
@ -2593,7 +2593,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont,
glyphs.Flush(dt, aContextPaint, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix,
drawOptions);
@ -2613,7 +2613,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
doubleglyph->mPosition.y = glyph->mPosition.y;
doubleglyph->mPosition = matInv * doubleglyph->mPosition;
strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(dt, aObjectPaint, scaledFont,
glyphs.Flush(dt, aContextPaint, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix,
drawOptions);
@ -2663,7 +2663,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
details->mGlyphID,
aObjectPaint, aCallbacks,
aContextPaint, aCallbacks,
emittedGlyphs)) {
continue;
}
@ -2674,7 +2674,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont, aDrawMode,
glyphs.Flush(dt, aContextPaint, scaledFont, aDrawMode,
isRTL, renderingOptions, aContext, passedInvMatrix,
drawOptions);
@ -2692,7 +2692,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
doubleglyph->mPosition.y = glyph->mPosition.y;
strikeOffset += synBoldOnePixelOffset;
doubleglyph->mPosition = matInv * doubleglyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont,
glyphs.Flush(dt, aContextPaint, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix, drawOptions);
} while (--strikeCount > 0);
@ -2712,7 +2712,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
}
glyphs.Flush(dt, aObjectPaint, scaledFont, aDrawMode, isRTL,
glyphs.Flush(dt, aContextPaint, scaledFont, aDrawMode, isRTL,
renderingOptions, aContext, passedInvMatrix,
drawOptions, true);
if (aCallbacks && emittedGlyphs) {
@ -2729,7 +2729,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
bool
gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint)
uint32_t aGlyphId, gfxTextContextPaint *aContextPaint)
{
if (!GetFontEntry()->HasSVGGlyph(aGlyphId)) {
return false;
@ -2741,15 +2741,15 @@ gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMod
aContext->Translate(gfxPoint(aPoint.x, aPoint.y));
aContext->Scale(devUnitsPerSVGUnit, devUnitsPerSVGUnit);
aObjectPaint->InitStrokeGeometry(aContext, devUnitsPerSVGUnit);
aContextPaint->InitStrokeGeometry(aContext, devUnitsPerSVGUnit);
return GetFontEntry()->RenderSVGGlyph(aContext, aGlyphId, aDrawMode,
aObjectPaint);
aContextPaint);
}
bool
gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint,
uint32_t aGlyphId, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks,
bool& aEmittedGlyphs)
{
@ -2761,7 +2761,7 @@ gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMod
aCallbacks->NotifyBeforeSVGGlyphPainted();
}
bool rendered = RenderSVGGlyph(aContext, aPoint, aDrawMode, aGlyphId,
aObjectPaint);
aContextPaint);
if (aCallbacks) {
aCallbacks->NotifyAfterSVGGlyphPainted();
}
@ -5616,7 +5616,7 @@ gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd)
void
gfxTextRun::DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
gfxTextObjectPaint *aObjectPaint,
gfxTextContextPaint *aContextPaint,
uint32_t aStart, uint32_t aEnd,
PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd,
@ -5626,7 +5626,7 @@ gfxTextRun::DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
aSpacingStart, aSpacingEnd, &spacingBuffer);
aFont->Draw(this, aStart, aEnd, aContext, aDrawMode, aPt,
haveSpacing ? spacingBuffer.Elements() : nullptr, aObjectPaint,
haveSpacing ? spacingBuffer.Elements() : nullptr, aContextPaint,
aCallbacks);
}
@ -5767,7 +5767,7 @@ void
gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode,
uint32_t aStart, uint32_t aLength,
PropertyProvider *aProvider, gfxFloat *aAdvanceWidth,
gfxTextObjectPaint *aObjectPaint,
gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks)
{
NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
@ -5833,7 +5833,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode
aProvider, aCallbacks);
}
DrawGlyphs(font, aContext, aDrawMode, &pt, aObjectPaint, ligatureRunStart,
DrawGlyphs(font, aContext, aDrawMode, &pt, aContextPaint, ligatureRunStart,
ligatureRunEnd, aProvider, ligatureRunStart, ligatureRunEnd,
aCallbacks);

View File

@ -49,7 +49,7 @@ class gfxUserFontData;
class gfxShapedText;
class gfxShapedWord;
class gfxSVGGlyphs;
class gfxTextObjectPaint;
class gfxTextContextPaint;
class nsILanguageAtomService;
@ -329,7 +329,7 @@ public:
bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
gfxRect *aResult);
bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
gfxTextObjectPaint *aObjectPaint);
gfxTextContextPaint *aContextPaint);
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
return true;
@ -1555,7 +1555,7 @@ public:
* that there is no spacing.
* @param aDrawMode specifies whether the fill or stroke of the glyph should be
* drawn, or if it should be drawn into the current path
* @param aObjectPaint information about how to construct the fill and
* @param aContextPaint information about how to construct the fill and
* stroke pattern. Can be nullptr if we are not stroking the text, which
* indicates that the current source from aContext should be used for filling
*
@ -1568,7 +1568,7 @@ public:
*/
virtual void Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin,
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint,
Spacing *aSpacing, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks);
/**
@ -1969,9 +1969,9 @@ protected:
void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont);
bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint);
uint32_t aGlyphId, gfxTextContextPaint *aContextPaint);
bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint,
uint32_t aGlyphId, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks,
bool& aEmittedGlyphs);
@ -2825,7 +2825,7 @@ public:
gfxFont::DrawMode aDrawMode,
uint32_t aStart, uint32_t aLength,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidth, gfxTextObjectPaint *aObjectPaint,
gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks = nullptr);
/**
@ -3252,7 +3252,7 @@ private:
// **** drawing helper ****
void DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
gfxTextObjectPaint *aObjectPaint, uint32_t aStart,
gfxTextContextPaint *aContextPaint, uint32_t aStart,
uint32_t aEnd, PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd,
gfxTextRunDrawCallbacks *aCallbacks);

View File

@ -38,11 +38,11 @@
typedef mozilla::dom::Element Element;
mozilla::gfx::UserDataKey gfxTextObjectPaint::sUserDataKey;
mozilla::gfx::UserDataKey gfxTextContextPaint::sUserDataKey;
const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
const gfxRGBA SimpleTextObjectPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
const gfxRGBA SimpleTextContextPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable)
{
@ -199,7 +199,7 @@ gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem)
*/
bool
gfxSVGGlyphs::RenderGlyph(gfxContext *aContext, uint32_t aGlyphId,
DrawMode aDrawMode, gfxTextObjectPaint *aObjectPaint)
DrawMode aDrawMode, gfxTextContextPaint *aContextPaint)
{
if (aDrawMode == gfxFont::GLYPH_PATH) {
return false;
@ -210,7 +210,7 @@ gfxSVGGlyphs::RenderGlyph(gfxContext *aContext, uint32_t aGlyphId,
Element *glyph = mGlyphIdMap.Get(aGlyphId);
NS_ASSERTION(glyph, "No glyph element. Should check with HasSVGGlyph() first!");
return nsSVGUtils::PaintSVGGlyph(glyph, aContext, aDrawMode, aObjectPaint);
return nsSVGUtils::PaintSVGGlyph(glyph, aContext, aDrawMode, aContextPaint);
}
bool
@ -403,8 +403,8 @@ gfxSVGGlyphsDocument::InsertGlyphId(Element *aGlyphElement)
}
void
gfxTextObjectPaint::InitStrokeGeometry(gfxContext *aContext,
float devUnitsPerSVGUnit)
gfxTextContextPaint::InitStrokeGeometry(gfxContext *aContext,
float devUnitsPerSVGUnit)
{
mStrokeWidth = aContext->CurrentLineWidth() / devUnitsPerSVGUnit;
aContext->CurrentDash(mDashes, &mDashOffset);

View File

@ -105,11 +105,11 @@ public:
/**
* Render the SVG glyph for |aGlyphId|
* @param aDrawMode Whether to fill or stroke or both; see gfxFont::DrawMode
* @param aObjectPaint Information on outer text object paints.
* See |gfxTextObjectPaint|.
* @param aContextPaint Information on text context paints.
* See |gfxTextContextPaint|.
*/
bool RenderGlyph(gfxContext *aContext, uint32_t aGlyphId, DrawMode aDrawMode,
gfxTextObjectPaint *aObjectPaint);
gfxTextContextPaint *aContextPaint);
/**
* Get the extents for the SVG glyph associated with |aGlyphId|
@ -150,18 +150,17 @@ private:
/**
* Used for trickling down paint information through to SVG glyphs.
* Will be extended in later patch.
*/
class gfxTextObjectPaint
class gfxTextContextPaint
{
protected:
gfxTextObjectPaint() { }
gfxTextContextPaint() { }
public:
static mozilla::gfx::UserDataKey sUserDataKey;
/*
* Get outer text object pattern with the specified opacity value.
* Get text context pattern with the specified opacity value.
* This lets us inherit paints and paint opacities (i.e. fill/stroke and
* fill-opacity/stroke-opacity) separately.
*/
@ -196,7 +195,7 @@ public:
return GetStrokePattern(GetStrokeOpacity(), aCTM);
}
virtual ~gfxTextObjectPaint() { }
virtual ~gfxTextContextPaint() { }
private:
FallibleTArray<gfxFloat> mDashes;
@ -205,10 +204,10 @@ private:
};
/**
* For passing in patterns where the outer text object has no separate pattern
* For passing in patterns where the text context has no separate pattern
* opacity value.
*/
class SimpleTextObjectPaint : public gfxTextObjectPaint
class SimpleTextContextPaint : public gfxTextContextPaint
{
private:
static const gfxRGBA sZero;
@ -225,7 +224,7 @@ public:
return deviceToUser * aPattern->GetMatrix();
}
SimpleTextObjectPaint(gfxPattern *aFillPattern, gfxPattern *aStrokePattern,
SimpleTextContextPaint(gfxPattern *aFillPattern, gfxPattern *aStrokePattern,
const gfxMatrix& aCTM) :
mFillPattern(aFillPattern ? aFillPattern : new gfxPattern(sZero)),
mStrokePattern(aStrokePattern ? aStrokePattern : new gfxPattern(sZero))

View File

@ -52,7 +52,7 @@ Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
WindowIdentifier newID(id);
newID.AppendProcessID();
Hal()->SendVibrate(p, newID.AsArray(), GetTabChildFrom(newID.GetWindow()));
Hal()->SendVibrate(p, newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
}
void
@ -62,7 +62,7 @@ CancelVibrate(const WindowIdentifier &id)
WindowIdentifier newID(id);
newID.AppendProcessID();
Hal()->SendCancelVibrate(newID.AsArray(), GetTabChildFrom(newID.GetWindow()));
Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
}
void

View File

@ -401,6 +401,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
mFinishing(false),
mInUpdateImageContainer(false),
mWantFullDecode(false),
mPendingError(false),
mScaleRequest(nullptr)
{
// Set up the discard tracker node.
@ -2822,13 +2823,19 @@ RasterImage::DoError()
if (mError)
return;
// We can't safely handle errors off-main-thread, so dispatch a worker to do it.
if (!NS_IsMainThread()) {
HandleErrorWorker::DispatchIfNeeded(this);
return;
}
// If we're mid-decode, shut down the decoder.
if (mDecoder) {
MutexAutoLock lock(mDecodingMutex);
FinishedSomeDecoding(eShutdownIntent_Error);
}
// Put the container in an error state
// Put the container in an error state.
mError = true;
if (mDecodeRequest) {
@ -2841,6 +2848,30 @@ RasterImage::DoError()
LOG_CONTAINER_ERROR;
}
/* static */ void
RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
{
if (!aImage->mPendingError) {
aImage->mPendingError = true;
nsRefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
NS_DispatchToMainThread(worker);
}
}
RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
: mImage(aImage)
{
MOZ_ASSERT(mImage, "Should have image");
}
NS_IMETHODIMP
RasterImage::HandleErrorWorker::Run()
{
mImage->DoError();
return NS_OK;
}
// nsIInputStream callback to copy the incoming image data directly to the
// RasterImage without processing. The RasterImage is passed as the closure.
// Always reads everything it gets, even if the data is erroneous.
@ -3188,6 +3219,7 @@ RasterImage::DecodePool::DecodeJob::Run()
// this request to the back of the list.
else if (mImage->mDecoder &&
!mImage->mError &&
!mImage->mPendingError &&
!mImage->IsDecodeFinished() &&
bytesDecoded < mRequest->mBytesToDecode &&
bytesDecoded > 0) {

View File

@ -667,6 +667,11 @@ private: // data
// off a full decode.
bool mWantFullDecode:1;
// Set when a decode worker detects an error off-main-thread. Once the error
// is handled on the main thread, mError is set, but mPendingError is used to
// stop decode work immediately.
bool mPendingError:1;
// Decoding
nsresult WantDecodedFrames();
nsresult SyncDecode();
@ -699,8 +704,28 @@ private: // data
nsresult ShutdownDecoder(eShutdownIntent aIntent);
// Helpers
// Error handling.
void DoError();
class HandleErrorWorker : public nsRunnable
{
public:
/**
* Called from decoder threads when DoError() is called, since errors can't
* be handled safely off-main-thread. Dispatches an event which reinvokes
* DoError on the main thread if there isn't one already pending.
*/
static void DispatchIfNeeded(RasterImage* aImage);
NS_IMETHOD Run();
private:
HandleErrorWorker(RasterImage* aImage);
nsRefPtr<RasterImage> mImage;
};
// Helpers
bool CanDiscard();
bool CanForciblyDiscard();
bool DiscardingActive();

View File

@ -54,7 +54,7 @@ function takeReferenceSnapshot() {
"reference div should disappear when it becomes display:none");
}
function myOnStopFrame(aRequest) {
function myOnStopFrame() {
gOnStopFrameCounter++;
ok(true, "myOnStopFrame called");
let currentSnapshot = snapshotWindow(window, false);
@ -64,7 +64,8 @@ function myOnStopFrame(aRequest) {
"at call #" + gOnStopFrameCounter + " to onStopFrame");
cleanUpAndFinish();
}
setTimeout(function() { myOnStopFrame(0, 0); }, 1000);
else
setTimeout(myOnStopFrame, 1);
}
function failTest() {
@ -80,8 +81,6 @@ function cleanUpAndFinish() {
if (gIsTestFinished) {
return;
}
let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent);
imgLoadingContent.removeObserver(gMyDecoderObserver);
SimpleTest.finish();
gIsTestFinished = true;
}
@ -89,19 +88,12 @@ function cleanUpAndFinish() {
function main() {
takeReferenceSnapshot();
// Create, customize & attach decoder observer
observer = new ImageDecoderObserverStub();
observer.frameComplete = myOnStopFrame;
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();
setTimeout(myOnStopFrame, 1);
// kick off image-loading! myOnStopFrame handles the rest.
gImg.setAttribute("src", "lime-anim-100x100.svg");

View File

@ -132,7 +132,6 @@ struct TypeInferenceSizes
{
size_t typeScripts;
size_t typeResults;
size_t analysisPool;
size_t pendingArrays;
size_t allocationSiteTables;
size_t arrayTypeTables;
@ -143,7 +142,6 @@ struct TypeInferenceSizes
void add(TypeInferenceSizes &sizes) {
this->typeScripts += sizes.typeScripts;
this->typeResults += sizes.typeResults;
this->analysisPool += sizes.analysisPool;
this->pendingArrays += sizes.pendingArrays;
this->allocationSiteTables += sizes.allocationSiteTables;
this->arrayTypeTables += sizes.arrayTypeTables;

View File

@ -561,6 +561,13 @@ public:
m_formatter.oneByteOp64(OP_ADD_GvEv, dst, base, offset);
}
void addq_mr(const void* addr, RegisterID dst)
{
spew("addq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_ADD_GvEv, dst, addr);
}
void addq_ir(int imm, RegisterID dst)
{
spew("addq $0x%x, %s", imm, nameIReg(8,dst));
@ -585,10 +592,22 @@ public:
m_formatter.immediate32(imm);
}
}
#else
void addq_im(int imm, const void* addr)
{
spew("addq %d, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
m_formatter.immediate8(imm);
} else {
m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, addr);
m_formatter.immediate32(imm);
}
}
#endif
void addl_im(int imm, const void* addr)
{
FIXME_INSN_PRINTING;
spew("addl %d, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
m_formatter.immediate8(imm);
@ -597,7 +616,6 @@ public:
m_formatter.immediate32(imm);
}
}
#endif
void andl_rr(RegisterID src, RegisterID dst)
{
@ -665,6 +683,13 @@ public:
m_formatter.oneByteOp64(OP_OR_GvEv, dst, base, offset);
}
void orq_mr(const void* addr, RegisterID dst)
{
spew("orq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_OR_GvEv, dst, addr);
}
void andq_ir(int imm, RegisterID dst)
{
spew("andq $0x%x, %s", imm, nameIReg(8,dst));
@ -878,6 +903,13 @@ public:
m_formatter.oneByteOp64(OP_SUB_GvEv, dst, base, offset);
}
void subq_mr(const void* addr, RegisterID dst)
{
spew("subq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_SUB_GvEv, dst, addr);
}
void subq_ir(int imm, RegisterID dst)
{
spew("subq $0x%x, %s", imm, nameIReg(8,dst));
@ -1254,7 +1286,23 @@ public:
m_formatter.immediate32(imm);
}
}
#else
void cmpq_im(int imm, const void* addr)
{
spew("cmpq $0x%x, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr);
m_formatter.immediate8(imm);
} else {
m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, addr);
m_formatter.immediate32(imm);
}
}
void cmpq_rm(RegisterID reg, const void* addr)
{
spew("cmpq %s, %p", nameIReg(8, reg), addr);
m_formatter.oneByteOp64(OP_CMP_EvGv, reg, addr);
}
#endif
void cmpl_rm(RegisterID reg, const void* addr)
{
spew("cmpl %s, %p",
@ -1273,7 +1321,6 @@ public:
m_formatter.immediate32(imm);
}
}
#endif
void cmpw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
@ -1558,14 +1605,14 @@ public:
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
}
#if WTF_CPU_X86
void movl_mr(const void* base, RegisterID index, int scale, RegisterID dst)
{
spew("movl %d(%s,%d), %s",
int(base), nameIReg(index), scale, nameIReg(dst));
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, index, scale, int(base));
int32_t disp = addressImmediate(base);
spew("movl %d(,%s,%d), %s",
disp, nameIReg(index), scale, nameIReg(dst));
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, index, scale, disp);
}
#endif
void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
@ -1574,7 +1621,6 @@ public:
m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset);
}
#if !WTF_CPU_X86_64
void movl_mr(const void* addr, RegisterID dst)
{
spew("movl %p, %s",
@ -1584,7 +1630,6 @@ public:
else
m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
}
#endif
void movl_i32r(int imm, RegisterID dst)
{
@ -1683,6 +1728,16 @@ public:
m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset);
}
void movq_rm(RegisterID src, const void* addr)
{
spew("movq %s, %p",
nameIReg(8, src), addr);
if (src == X86Registers::eax)
movq_EAXm(addr);
else
m_formatter.oneByteOp64(OP_MOV_EvGv, src, addr);
}
void movq_mEAX(const void* addr)
{
FIXME_INSN_PRINTING;
@ -1717,6 +1772,16 @@ public:
m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset);
}
void movq_mr(const void* addr, RegisterID dst)
{
spew("movq %p, %s",
addr, nameIReg(8, dst));
if (dst == X86Registers::eax)
movq_mEAX(addr);
else
m_formatter.oneByteOp64(OP_MOV_GvEv, dst, addr);
}
void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
spew("leaq %d(%s,%s,%d), %s",
@ -1739,6 +1804,12 @@ public:
m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
m_formatter.immediate32(imm);
}
void movq_i32m(int imm, const void* addr)
{
spew("movq %d, %p", imm, addr);
m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, addr);
m_formatter.immediate32(imm);
}
// Note that this instruction sign-extends its 32-bit immediate field to 64
// bits and loads the 64-bit value into a 64-bit register.
@ -1791,7 +1862,7 @@ public:
m_formatter.oneByteRipOp64(OP_MOV_GvEv, dst, 0);
return JmpSrc(m_formatter.size());
}
#else
#endif
void movl_rm(RegisterID src, const void* addr)
{
spew("movl %s, %p",
@ -1804,11 +1875,10 @@ public:
void movl_i32m(int imm, const void* addr)
{
FIXME_INSN_PRINTING;
spew("movl %d, %p", imm, addr);
m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr);
m_formatter.immediate32(imm);
}
#endif
void movb_rm(RegisterID src, int offset, RegisterID base)
{
@ -2074,6 +2144,7 @@ public:
void immediate64(int64_t imm)
{
spew(".quad %lld", (long long)imm);
m_formatter.immediate64(imm);
}
#endif
@ -2204,7 +2275,6 @@ public:
m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, base, offset);
}
#if !WTF_CPU_X86_64
void addsd_mr(const void* address, XMMRegisterID dst)
{
spew("addsd %p, %s",
@ -2219,7 +2289,6 @@ public:
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, address);
}
#endif
void cvtss2sd_rr(XMMRegisterID src, XMMRegisterID dst)
{
@ -2897,7 +2966,7 @@ public:
JmpDst align(int alignment)
{
spew(".balign %d", alignment);
spew(".balign %d, 0x%x # hlt", alignment, OP_HLT);
while (!m_formatter.isAligned(alignment))
m_formatter.oneByteOp(OP_HLT);
@ -3143,6 +3212,26 @@ public:
reinterpret_cast<const void**>(where)[-1] = value;
}
// Test whether the given address will fit in an address immediate field.
// This is always true on x86, but on x64 it's only true for addreses
// which fit in the 32-bit immediate field.
static bool isAddressImmediate(const void *address) {
intptr_t value = reinterpret_cast<intptr_t>(address);
int32_t immediate = static_cast<int32_t>(value);
return value == immediate;
}
// Convert the given address to a 32-bit immediate field value. This is
// a no-op on x86, but on x64 it asserts that the address is actually
// a valid address immediate.
static int32_t addressImmediate(const void *address) {
#if WTF_CPU_X86_64
// x64's 64-bit addresses don't all fit in the 32-bit immediate.
ASSERT(isAddressImmediate(address));
#endif
return static_cast<int32_t>(reinterpret_cast<intptr_t>(address));
}
private:
static int32_t getInt32(void* where)
@ -3236,14 +3325,13 @@ private:
memoryModRM_disp32(reg, index, scale, offset);
}
#if !WTF_CPU_X86_64
void oneByteOp(OneByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
#else
#if WTF_CPU_X86_64
void oneByteRipOp(OneByteOpcodeID opcode, int reg, int ripOffset)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3316,7 +3404,6 @@ private:
memoryModRM(reg, base, index, scale, offset);
}
#if !WTF_CPU_X86_64
void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3324,7 +3411,6 @@ private:
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
#endif
void threeByteOp(ThreeByteOpcodeID opcode, ThreeByteEscape escape, int reg, RegisterID rm)
{
@ -3399,6 +3485,14 @@ private:
memoryModRM(reg, base, index, scale, offset);
}
void oneByteOp64(OneByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
emitRexW(reg, 0, 0);
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3765,14 +3859,19 @@ private:
m_buffer.putIntUnchecked(offset);
}
#if !WTF_CPU_X86_64
void memoryModRM(int reg, const void* address)
{
int32_t disp = addressImmediate(address);
#if WTF_CPU_X86_64
// On x64-64, non-RIP-relative absolute mode requires a SIB.
putModRmSib(ModRmMemoryNoDisp, reg, noBase, noIndex, 0);
#else
// noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32!
putModRm(ModRmMemoryNoDisp, reg, noBase);
m_buffer.putIntUnchecked(reinterpret_cast<int32_t>(address));
}
#endif
m_buffer.putIntUnchecked(disp);
}
AssemblerBuffer m_buffer;
} m_formatter;

View File

@ -23,6 +23,8 @@
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "vm/Shape-inl.h"
using mozilla::DebugOnly;
using namespace js;

View File

@ -10,6 +10,7 @@
#include "jit/IonCode.h"
#include "vm/ArgumentsObject.h"
#include "vm/ScopeObject.h"
#include "vm/Shape.h"
#include "vm/TypedArrayObject.h"
@ -17,7 +18,6 @@
#include "jsinferinlines.h"
#include "gc/Nursery-inl.h"
#include "vm/Shape-inl.h"
#include "vm/String-inl.h"
using namespace js;

View File

@ -26,7 +26,7 @@ class RelocationOverlay
friend class MinorCollectionTracer;
/* The low bit is set so this should never equal a normal pointer. */
const static uintptr_t Relocated = uintptr_t(0xbad0bad1);
static const uintptr_t Relocated = uintptr_t(0xbad0bad1);
/* Set to Relocated when moved. */
uintptr_t magic_;

View File

@ -44,10 +44,10 @@ class BaselineCompiler;
class Nursery
{
public:
const static int NumNurseryChunks = 16;
const static int LastNurseryChunk = NumNurseryChunks - 1;
const static size_t Alignment = gc::ChunkSize;
const static size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
static const int NumNurseryChunks = 16;
static const int LastNurseryChunk = NumNurseryChunks - 1;
static const size_t Alignment = gc::ChunkSize;
static const size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
explicit Nursery(JSRuntime *rt)
: runtime_(rt),
@ -138,8 +138,8 @@ class Nursery
HugeSlotsSet hugeSlots;
/* The marking bitmap for the fallback marker. */
const static size_t ThingAlignment = sizeof(JS::Value);
const static size_t FallbackBitmapBits = NurserySize / ThingAlignment;
static const size_t ThingAlignment = sizeof(JS::Value);
static const size_t FallbackBitmapBits = NurserySize / ThingAlignment;
BitArray<FallbackBitmapBits> fallbackBitmap;
#ifdef DEBUG
@ -147,16 +147,16 @@ class Nursery
* In DEBUG builds, these bytes indicate the state of an unused segment of
* nursery-allocated memory.
*/
const static uint8_t FreshNursery = 0x2a;
const static uint8_t SweptNursery = 0x2b;
const static uint8_t AllocatedThing = 0x2c;
static const uint8_t FreshNursery = 0x2a;
static const uint8_t SweptNursery = 0x2b;
static const uint8_t AllocatedThing = 0x2c;
#endif
/* The maximum number of slots allowed to reside inline in the nursery. */
const static size_t MaxNurserySlots = 100;
static const size_t MaxNurserySlots = 100;
/* The amount of space in the mapped nursery available to allocations. */
const static size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(JSRuntime *);
static const size_t NurseryChunkUsableSize = gc::ChunkSize - sizeof(JSRuntime *);
struct NurseryChunkLayout {
char data[NurseryChunkUsableSize];

View File

@ -36,7 +36,7 @@ class gcstats::StatisticsSerializer
bool needComma_;
bool oom_;
const static int MaxFieldValueLength = 128;
static const int MaxFieldValueLength = 128;
public:
enum Mode {

View File

@ -72,10 +72,10 @@ typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
class StoreBuffer
{
/* The size of a single block of store buffer storage space. */
const static size_t ChunkSize = 1 << 16; /* 64KiB */
static const size_t ChunkSize = 1 << 16; /* 64KiB */
/* The size at which a block is about to overflow. */
const static size_t MinAvailableSize = (size_t)(ChunkSize * 1.0 / 8.0);
static const size_t MinAvailableSize = (size_t)(ChunkSize * 1.0 / 8.0);
/*
* This buffer holds only a single type of edge. Using this buffer is more

View File

@ -528,7 +528,7 @@ IsMarkedOrAllocated(Cell *cell)
return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental;
}
const static uint32_t MAX_VERIFIER_EDGES = 1000;
static const uint32_t MAX_VERIFIER_EDGES = 1000;
/*
* This function is called by EndVerifyBarriers for every heap edge. If the edge

View File

@ -0,0 +1,20 @@
y = Float32Array(11);
x = [];
Object.defineProperty(x, 18, {
get: (function() {
y.length;
}),
});
this.toSource();
y = undefined;
for (var i = 0; i < 3; i++) {
try {
x.toString();
assertEq(0, 1);
} catch (e) {
assertEq(e.message, "y is undefined");
}
}

View File

@ -0,0 +1,23 @@
setJitCompilerOption("ion.usecount.trigger", 50);
var f32 = new Float32Array(32);
f32[0] = 0;
function g(x) {
eval(""); // don't inline
return x + 4;
}
function f(n) {
var x;
if (n > 10000) {
x = 4.5;
} else {
x = f32[0];
}
f32[0] = g(x);
}
for (var n = 0; n < 100; n++)
f(n);
assertEq(f32[0], 400);

View File

@ -0,0 +1,8 @@
function f1() {
var b = new Float32Array(50);
for (var i=0; i < 100; true ? ++i : x.foo()) {
var x = b[i];
typeof x;
}
}
f1();

View File

@ -5358,7 +5358,7 @@ class ICCall_ScriptedApplyArray : public ICMonitoredStub
// The maximum length of an inlineable funcall array.
// Keep this small to avoid controllable stack overflows by attackers passing large
// arrays to fun.apply.
const static uint32_t MAX_ARGS_ARRAY_LENGTH = 16;
static const uint32_t MAX_ARGS_ARRAY_LENGTH = 16;
protected:
uint32_t pcOffset_;

View File

@ -400,6 +400,7 @@ class TypeAnalyzer
bool adjustInputs(MDefinition *def);
bool insertConversions();
bool checkFloatCoherency();
bool graphContainsFloat32();
bool markPhiConsumers();
bool markPhiProducers();
@ -900,6 +901,42 @@ TypeAnalyzer::tryEmitFloatOperations()
return true;
}
bool
TypeAnalyzer::checkFloatCoherency()
{
#ifdef DEBUG
// Asserts that all Float32 instructions are flowing into Float32 consumers or specialized
// operations
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); ++block) {
if (mir->shouldCancel("Check Float32 coherency"))
return false;
for (MDefinitionIterator def(*block); def; def++) {
if (def->type() != MIRType_Float32)
continue;
if (def->isPassArg()) // no check for PassArg as it is broken, see bug 915479
continue;
for (MUseDefIterator use(*def); use; use++) {
MDefinition *consumer = use.def();
// The only valid uses of a Float32 are:
// - an operation that can consume Float32
// - an operation that has been specialized to Float32 (for instance, an add)
// - a conversion to Double
if (consumer->canConsumeFloat32())
continue;
if (consumer->type() == MIRType_Float32)
continue;
if (consumer->isToDouble())
continue;
MOZ_ASSUME_UNREACHABLE("Float32 flowing into a non float specialized operation");
}
}
}
#endif
return true;
}
bool
TypeAnalyzer::analyze()
{
@ -909,6 +946,8 @@ TypeAnalyzer::analyze()
return false;
if (!insertConversions())
return false;
if (!checkFloatCoherency())
return false;
return true;
}
@ -1587,8 +1626,8 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
{
JS_ASSERT(!*eliminated);
const types::StackTypeSet *barrierTypes = barrier->resultTypeSet();
const types::StackTypeSet *inputTypes = barrier->input()->resultTypeSet();
const types::TemporaryTypeSet *barrierTypes = barrier->resultTypeSet();
const types::TemporaryTypeSet *inputTypes = barrier->input()->resultTypeSet();
// Disregard the possible unbox added before the Typebarrier.
if (barrier->input()->isUnbox() &&
@ -2043,7 +2082,7 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
Vector<jsid> accessedProperties(cx);
LifoAlloc alloc(JSCompartment::ANALYSIS_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
LifoAlloc alloc(types::TypeZone::TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
TempAllocator temp(&alloc);
IonContext ictx(cx, &temp);

View File

@ -147,7 +147,7 @@ IonBuilder::CFGState::TableSwitch(jsbytecode *exitpc, MTableSwitch *ins)
}
JSFunction *
IonBuilder::getSingleCallTarget(types::StackTypeSet *calleeTypes)
IonBuilder::getSingleCallTarget(types::TemporaryTypeSet *calleeTypes)
{
if (!calleeTypes)
return NULL;
@ -160,7 +160,7 @@ IonBuilder::getSingleCallTarget(types::StackTypeSet *calleeTypes)
}
bool
IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
{
JS_ASSERT(targets.length() == 0);
@ -376,7 +376,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecod
last = earlier;
if (js_CodeSpec[*last].format & JOF_TYPESET) {
types::StackTypeSet *typeSet = types::TypeScript::BytecodeTypes(script(), last);
types::TemporaryTypeSet *typeSet = bytecodeTypes(last);
if (!typeSet->empty()) {
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
phi->addBackedgeType(type, typeSet);
@ -744,14 +744,7 @@ IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIn
{
JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
// Find the original (not cloned) type set for the MParameter, as we
// will be adding constraints to it.
types::StackTypeSet *types;
if (argIndex == MParameter::THIS_SLOT)
types = types::TypeScript::ThisTypes(script());
else
types = types::TypeScript::ArgTypes(script(), argIndex);
types::TemporaryTypeSet *types = param->resultTypeSet();
JSValueType definiteType = types->getKnownTypeTag();
if (definiteType == JSVAL_TYPE_UNKNOWN)
return;
@ -900,7 +893,7 @@ IonBuilder::initArgumentsObject()
bool
IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
MIRType type, types::StackTypeSet *typeSet)
MIRType type, types::TemporaryTypeSet *typeSet)
{
MInstruction *&def = *def_;
MBasicBlock *osrBlock = def->block();
@ -921,7 +914,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
// No unbox instruction will be added below, so check the type by
// adding a type barrier for a singleton type set.
types::Type ntype = types::Type::PrimitiveType(ValueTypeFromMIRType(type));
typeSet = GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
typeSet = GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
if (!typeSet)
return false;
MInstruction *barrier = MTypeBarrier::New(def, typeSet);
@ -1032,7 +1025,7 @@ IonBuilder::maybeAddOsrTypeBarriers()
MPhi *preheaderPhi = preheader->getSlot(i)->toPhi();
MIRType type = headerPhi->type();
types::StackTypeSet *typeSet = headerPhi->resultTypeSet();
types::TemporaryTypeSet *typeSet = headerPhi->resultTypeSet();
if (!addOsrValueTypeBarrier(i, &def, type, typeSet))
return false;
@ -1403,8 +1396,7 @@ IonBuilder::inspectOpcode(JSOp op)
{
types::TypeSet *argTypes = types::TypeScript::ArgTypes(script(), arg);
// During parallel compilation the parameter's type set
// will be a clone of the actual argument type set.
// Update both the original and cloned type set.
argTypes->addType(cx, types::Type::UnknownType());
op->resultTypeSet()->addType(cx, types::Type::UnknownType());
}
@ -4332,7 +4324,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets,
// During inlining the 'this' value is assigned a type set which is
// specialized to the type objects which can generate that inlining target.
// After inlining the original type set is restored.
types::StackTypeSet *cacheObjectTypeSet =
types::TemporaryTypeSet *cacheObjectTypeSet =
maybeCache ? maybeCache->object()->resultTypeSet() : NULL;
// Inline each of the inlineable targets.
@ -4378,7 +4370,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets,
if (maybeCache) {
JS_ASSERT(callInfo.thisArg() == maybeCache->object());
types::StackTypeSet *targetThisTypes =
types::TemporaryTypeSet *targetThisTypes =
maybeCache->propTable()->buildTypeSetForFunction(original);
if (!targetThisTypes)
return false;
@ -4704,7 +4696,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
int funcDepth = -((int)argc + 1);
// If |Function.prototype.call| may be overridden, don't optimize callsite.
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
RootedFunction native(cx, getSingleCallTarget(calleeTypes));
if (!native || !native->isNative() || native->native() != &js_fun_call) {
CallInfo callInfo(cx, false);
@ -4715,7 +4707,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
current->peek(calleeDepth)->setFoldedUnchecked();
// Extract call target.
types::StackTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
RootedFunction target(cx, getSingleCallTarget(funTypes));
// Unwrap the (JSFunction *) parameter.
@ -4759,7 +4751,7 @@ IonBuilder::jsop_funapply(uint32_t argc)
{
int calleeDepth = -((int)argc + 2);
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
RootedFunction native(cx, getSingleCallTarget(calleeTypes));
if (argc != 2) {
CallInfo callInfo(cx, false);
@ -4811,7 +4803,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
int funcDepth = -((int)argc + 1);
// Extract call target.
types::StackTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
RootedFunction target(cx, getSingleCallTarget(funTypes));
// When this script isn't inlined, use MApplyArgs,
@ -4848,7 +4840,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
if (!resumeAfter(apply))
return false;
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(apply, types, true);
}
@ -4922,7 +4914,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
// Acquire known call target if existent.
AutoObjectVector originals(cx);
bool gotLambda = false;
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
if (calleeTypes) {
if (!getPolyCallTargets(calleeTypes, constructing, originals, 4, &gotLambda))
return false;
@ -5066,7 +5058,7 @@ TestAreKnownDOMTypes(JSContext *cx, types::TypeSet *inTypes)
static bool
ArgumentTypesMatch(MDefinition *def, types::StackTypeSet *calleeTypes)
ArgumentTypesMatch(MDefinition *def, types::TemporaryTypeSet *calleeTypes)
{
if (def->resultTypeSet()) {
JS_ASSERT(def->type() == MIRType_Value || def->mightBeType(def->type()));
@ -5082,8 +5074,8 @@ ArgumentTypesMatch(MDefinition *def, types::StackTypeSet *calleeTypes)
return calleeTypes->mightBeType(ValueTypeFromMIRType(def->type()));
}
static bool
TestNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
bool
IonBuilder::testNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
{
// If we have a known target, check if the caller arg types are a subset of callee.
// Since typeset accumulates and can't decrease that means we don't need to check
@ -5095,15 +5087,15 @@ TestNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
if (!targetScript->hasAnalysis())
return true;
if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript)))
if (!ArgumentTypesMatch(callInfo.thisArg(), cloneTypeSet(types::TypeScript::ThisTypes(targetScript))))
return true;
uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs);
for (size_t i = 0; i < expected_args; i++) {
if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i)))
if (!ArgumentTypesMatch(callInfo.getArg(i), cloneTypeSet(types::TypeScript::ArgTypes(targetScript, i))))
return true;
}
for (size_t i = callInfo.argc(); i < target->nargs; i++) {
if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeType(JSVAL_TYPE_UNDEFINED))
if (!cloneTypeSet(types::TypeScript::ArgTypes(targetScript, i))->mightBeType(JSVAL_TYPE_UNDEFINED))
return true;
}
@ -5196,7 +5188,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
// We know we have a single call target. Check whether the "this" types
// are DOM types and our function a DOM function, and if so flag the
// MCall accordingly.
types::StackTypeSet *thisTypes = thisArg->resultTypeSet();
types::TemporaryTypeSet *thisTypes = thisArg->resultTypeSet();
if (thisTypes &&
TestAreKnownDOMTypes(cx, thisTypes) &&
TestShouldDOMCall(cx, thisTypes, target, JSJitInfo::Method))
@ -5205,7 +5197,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
}
}
if (target && !TestNeedsArgumentCheck(cx, target, callInfo))
if (target && !testNeedsArgumentCheck(cx, target, callInfo))
call->disableArgCheck();
call->initFunction(callInfo.fun());
@ -5215,7 +5207,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
}
static bool
DOMCallNeedsBarrier(const JSJitInfo* jitinfo, types::StackTypeSet *types)
DOMCallNeedsBarrier(const JSJitInfo* jitinfo, types::TemporaryTypeSet *types)
{
// If the return type of our DOM native is in "types" already, we don't
// actually need a barrier.
@ -5247,7 +5239,7 @@ IonBuilder::makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCall
if (!resumeAfter(call))
return false;
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool barrier = true;
if (call->isDOMFunction()) {
@ -5263,7 +5255,7 @@ bool
IonBuilder::jsop_eval(uint32_t argc)
{
int calleeDepth = -((int)argc + 2);
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
// Emit a normal call if the eval has never executed. This keeps us from
// disabling compilation for the script when testing with --ion-eager.
@ -5281,7 +5273,7 @@ IonBuilder::jsop_eval(uint32_t argc)
if (!info().fun())
return abort("Direct eval in global code");
types::StackTypeSet *thisTypes = types::TypeScript::ThisTypes(script());
types::TemporaryTypeSet *thisTypes = cloneTypeSet(types::TypeScript::ThisTypes(script()));
// The 'this' value for the outer and eval scripts must be the
// same. This is not guaranteed if a primitive string/number/etc.
@ -5342,7 +5334,7 @@ IonBuilder::jsop_eval(uint32_t argc)
current->add(ins);
current->push(ins);
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return resumeAfter(ins) && pushTypeBarrier(ins, types, true);
}
@ -5399,9 +5391,15 @@ IonBuilder::jsop_newarray(uint32_t count)
if (!templateObject)
return false;
types::StackTypeSet::DoubleConversion conversion =
types::TypeScript::BytecodeTypes(script(), pc)->convertDoubleElements(cx);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
if (templateObject->type()->unknownProperties()) {
// We will get confused in jsop_initelem_array if we can't find the
// type object being initialized.
return abort("New array has unknown properties");
}
types::TemporaryTypeSet::DoubleConversion conversion =
bytecodeTypes(pc)->convertDoubleElements(cx);
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
templateObject->setShouldConvertDoubleElements();
MNewArray *ins = new MNewArray(count, templateObject, MNewArray::NewArray_Allocating);
@ -5883,8 +5881,8 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
? MIRType_Double
: MIRTypeFromValueType(existingValue.extractNonDoubleType());
types::Type ntype = types::GetValueType(existingValue);
types::StackTypeSet *typeSet =
GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
types::TemporaryTypeSet *typeSet =
GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
if (!typeSet)
return NULL;
phi->addBackedgeType(type, typeSet);
@ -6034,7 +6032,7 @@ TestSingletonPropertyTypes(JSContext *cx, MDefinition *obj, JSObject *singleton,
*testObject = false;
*testString = false;
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types && obj->type() != MIRType_String)
return true;
@ -6145,7 +6143,7 @@ TestSingletonPropertyTypes(JSContext *cx, MDefinition *obj, JSObject *singleton,
// instruction replaces the top of the stack.
// (5) Lastly, a type barrier instruction replaces the top of the stack.
bool
IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needsBarrier)
IonBuilder::pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needsBarrier)
{
// Barriers are never needed for instructions whose result will not be used.
if (BytecodeIsPopped(pc))
@ -6184,9 +6182,9 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
current->pop();
current->add(replace);
current->push(replace);
replace->setResultTypeSet(cloneTypeSet(observed));
replace->setResultTypeSet(observed);
} else {
ins->setResultTypeSet(cloneTypeSet(observed));
ins->setResultTypeSet(observed);
}
return true;
}
@ -6196,7 +6194,7 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
current->pop();
MInstruction *barrier = MTypeBarrier::New(ins, cloneTypeSet(observed));
MInstruction *barrier = MTypeBarrier::New(ins, observed);
current->add(barrier);
if (barrier->type() == MIRType_Undefined)
@ -6251,13 +6249,14 @@ IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name, bo
return true;
}
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier;
if (!PropertyReadNeedsTypeBarrier(cx, staticType, name, types, /* updateObserved = */ true,
if (!PropertyReadNeedsTypeBarrier(cx, staticType, name, baseTypes, /* updateObserved = */ true,
&barrier))
{
return false;
}
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
// If the property is permanent, a shape guard isn't necessary.
@ -6426,14 +6425,14 @@ IonBuilder::jsop_getname(HandlePropertyName name)
if (!resumeAfter(ins))
return false;
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true);
}
bool
IonBuilder::jsop_intrinsic(HandlePropertyName name)
{
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
JSValueType type = types->getKnownTypeTag();
// If we haven't executed this opcode yet, we need to get the intrinsic
@ -6479,7 +6478,7 @@ IonBuilder::jsop_bindname(PropertyName *name)
}
static JSValueType
GetElemKnownType(bool needsHoleCheck, types::StackTypeSet *types)
GetElemKnownType(bool needsHoleCheck, types::TemporaryTypeSet *types)
{
JSValueType knownType = types->getKnownTypeTag();
@ -6540,7 +6539,7 @@ IonBuilder::jsop_getelem()
if (!resumeAfter(ins))
return false;
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true);
}
@ -6712,7 +6711,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
current->add(load);
current->push(load);
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
if (!pushTypeBarrier(load, types, true))
return false;
@ -6781,10 +6780,11 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
// Emit GetElementCache.
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier;
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, baseTypes, &barrier))
return false;
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
// Always add a barrier if the index might be a string, so that the cache
// can attach stubs for particular properties.
@ -6822,19 +6822,20 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
bool
IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
{
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String) && types->noConstraints()) {
if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String) && baseTypes->noConstraints()) {
// Indexed call on an element of an array. Populate the observed types
// with any objects that could be in the array, to avoid extraneous
// type barriers.
if (!AddObjectsForPropertyRead(cx, obj, NULL, types))
if (!AddObjectsForPropertyRead(cx, obj, NULL, baseTypes))
return false;
}
bool barrier;
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, baseTypes, &barrier))
return false;
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
bool needsHoleCheck = !ElementAccessIsPacked(cx, obj);
@ -6870,7 +6871,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
// NB: We disable this optimization in parallel execution mode
// because it is inherently not threadsafe (how do you convert the
// array atomically when there might be concurrent readers)?
types::StackTypeSet *objTypes = obj->resultTypeSet();
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
ExecutionMode executionMode = info().executionMode();
bool loadDouble =
executionMode == SequentialExecution &&
@ -6880,7 +6881,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
!needsHoleCheck &&
knownType == JSVAL_TYPE_DOUBLE &&
objTypes &&
objTypes->convertDoubleElements(cx) == types::StackTypeSet::AlwaysConvertToDoubles;
objTypes->convertDoubleElements(cx) == types::TemporaryTypeSet::AlwaysConvertToDoubles;
if (loadDouble)
elements = addConvertElementsToDoubles(elements);
@ -6987,7 +6988,7 @@ bool
IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
ScalarTypeRepresentation::Type arrayType)
{
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool maybeUndefined = types->hasType(types::Type::UndefinedType());
@ -7213,11 +7214,11 @@ IonBuilder::setElemTryDense(bool *emitted, MDefinition *object,
if (!object->resultTypeSet())
return true;
types::StackTypeSet::DoubleConversion conversion =
types::TemporaryTypeSet::DoubleConversion conversion =
object->resultTypeSet()->convertDoubleElements(cx);
// If AmbiguousDoubleConversion, only handle int32 values for now.
if (conversion == types::StackTypeSet::AmbiguousDoubleConversion &&
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion &&
value->type() != MIRType_Int32)
{
return true;
@ -7291,7 +7292,7 @@ IonBuilder::setElemTryCache(bool *emitted, MDefinition *object,
}
bool
IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
IonBuilder::jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition *obj, MDefinition *id, MDefinition *value)
{
@ -7320,15 +7321,15 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
// Ensure the value is a double, if double conversion might be needed.
MDefinition *newValue = value;
switch (conversion) {
case types::StackTypeSet::AlwaysConvertToDoubles:
case types::StackTypeSet::MaybeConvertToDoubles: {
case types::TemporaryTypeSet::AlwaysConvertToDoubles:
case types::TemporaryTypeSet::MaybeConvertToDoubles: {
MInstruction *valueDouble = MToDouble::New(value);
current->add(valueDouble);
newValue = valueDouble;
break;
}
case types::StackTypeSet::AmbiguousDoubleConversion: {
case types::TemporaryTypeSet::AmbiguousDoubleConversion: {
JS_ASSERT(value->type() == MIRType_Int32);
MInstruction *maybeDouble = MMaybeToDoubleElement::New(elements, value);
current->add(maybeDouble);
@ -7336,7 +7337,7 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
break;
}
case types::StackTypeSet::DontConvertToDoubles:
case types::TemporaryTypeSet::DontConvertToDoubles:
break;
default:
@ -7479,7 +7480,7 @@ IonBuilder::jsop_length()
bool
IonBuilder::jsop_length_fastPath()
{
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
if (types->getKnownTypeTag() != JSVAL_TYPE_INT32)
return false;
@ -7497,7 +7498,7 @@ IonBuilder::jsop_length_fastPath()
}
if (obj->mightBeType(MIRType_Object)) {
types::StackTypeSet *objTypes = obj->resultTypeSet();
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
if (objTypes &&
objTypes->getKnownClass() == &ArrayObject::class_ &&
@ -7625,7 +7626,7 @@ IonBuilder::jsop_rest()
}
inline types::HeapTypeSet *
GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
GetDefiniteSlot(JSContext *cx, types::TemporaryTypeSet *types, JSAtom *atom)
{
if (!types || types->unknownObject() || types->getObjectCount() != 1)
return NULL;
@ -7740,7 +7741,7 @@ TestCommonAccessorProtoChain(JSContext *cx, HandleId id, bool isGetter, JSObject
}
inline bool
SearchCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id, bool isGetter,
SearchCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types, HandleId id, bool isGetter,
JSObject *&found, JSObject *&foundProto, bool &cont)
{
cont = false;
@ -7834,7 +7835,7 @@ SearchCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id, boo
}
inline bool
FreezePropTypeSets(JSContext *cx, types::StackTypeSet *types, JSObject *foundProto, HandleId id)
FreezePropTypeSets(JSContext *cx, types::TemporaryTypeSet *types, JSObject *foundProto, HandleId id)
{
types::TypeObject *curType;
for (unsigned i = 0; i < types->getObjectCount(); i++) {
@ -7879,7 +7880,7 @@ FreezePropTypeSets(JSContext *cx, types::StackTypeSet *types, JSObject *foundPro
}
inline bool
IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id,
IonBuilder::TestCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types, HandleId id,
JSFunction **funcp, bool isGetter, bool *isDOM,
MDefinition **guardOut)
{
@ -7934,7 +7935,7 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
bool
IonBuilder::annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes)
types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes)
{
RootedId id(cx, NameToId(getPropCache->name()));
if (id != types::IdToTypeId(id))
@ -8047,7 +8048,7 @@ IonBuilder::invalidatedIdempotentCache()
bool
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
bool barrier, types::StackTypeSet *types)
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(shape->hasDefaultGetter());
JS_ASSERT(shape->hasSlot());
@ -8109,15 +8110,15 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
bool emitted = false;
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
// Try to optimize arguments.length.
if (!getPropTryArgumentsLength(&emitted) || emitted)
return emitted;
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier;
if (!PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, types, &barrier))
if (!PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, baseTypes, &barrier))
return false;
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
// Try to hardcode known constants.
if (!getPropTryConstant(&emitted, id, types) || emitted)
@ -8178,7 +8179,7 @@ IonBuilder::getPropTryArgumentsLength(bool *emitted)
}
bool
IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types)
IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
JSObject *singleton = types ? types->getSingleton() : NULL;
@ -8217,7 +8218,7 @@ IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *
bool
IonBuilder::getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
bool barrier, types::StackTypeSet *types)
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
types::TypeSet *propTypes = GetDefiniteSlot(cx, current->peek(-1)->resultTypeSet(), name);
@ -8248,14 +8249,14 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
bool
IonBuilder::getPropTryCommonGetter(bool *emitted, HandleId id,
bool barrier, types::StackTypeSet *types)
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
JSFunction *commonGetter;
bool isDOM;
MDefinition *guard;
types::StackTypeSet *objTypes = current->peek(-1)->resultTypeSet();
types::TemporaryTypeSet *objTypes = current->peek(-1)->resultTypeSet();
if (!TestCommonPropFunc(cx, objTypes, id, &commonGetter, true, &isDOM, &guard))
return false;
@ -8330,7 +8331,7 @@ CanInlinePropertyOpShapes(const Vector<Shape *> &shapes)
bool
IonBuilder::getPropTryInlineAccess(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types)
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
if (current->peek(-1)->type() != MIRType_Object)
@ -8391,7 +8392,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, HandlePropertyName name, Handl
bool
IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types)
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
bool accessGetter =
@ -8403,7 +8404,7 @@ IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
// The input value must either be an object, or we should have strong suspicions
// that it can be safely unboxed to an object.
if (obj->type() != MIRType_Object) {
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types || !types->objectOrSentinel())
return true;
}
@ -8464,7 +8465,7 @@ IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
}
bool
IonBuilder::needsToMonitorMissingProperties(types::StackTypeSet *types)
IonBuilder::needsToMonitorMissingProperties(types::TemporaryTypeSet *types)
{
// GetPropertyParIC and GetElementParIC cannot safely call
// TypeScript::Monitor to ensure that the observed type set contains
@ -8500,7 +8501,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
if (!setPropTryCommonSetter(&emitted, obj, name, id, value) || emitted)
return emitted;
types::StackTypeSet *objTypes = obj->resultTypeSet();
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
bool barrier;
if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value,
/* canModify = */ true, &barrier))
@ -8537,7 +8538,7 @@ IonBuilder::setPropTryCommonSetter(bool *emitted, MDefinition *obj,
JSFunction *commonSetter;
bool isDOM;
types::StackTypeSet *objTypes = obj->resultTypeSet();
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
if (!TestCommonPropFunc(cx, objTypes, id, &commonSetter, false, &isDOM, NULL))
return false;
@ -8623,7 +8624,7 @@ IonBuilder::setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
if (!isDOM)
return true;
types::StackTypeSet *objTypes = obj->resultTypeSet();
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
if (!TestShouldDOMCall(cx, objTypes, setter, JSJitInfo::Setter))
return true;
@ -8644,7 +8645,7 @@ IonBuilder::setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
bool
IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
HandlePropertyName name, MDefinition *value,
bool barrier, types::StackTypeSet *objTypes)
bool barrier, types::TemporaryTypeSet *objTypes)
{
JS_ASSERT(*emitted == false);
@ -8673,7 +8674,7 @@ bool
IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
HandlePropertyName name, HandleId id,
MDefinition *value, bool barrier,
types::StackTypeSet *objTypes)
types::TemporaryTypeSet *objTypes)
{
JS_ASSERT(*emitted == false);
@ -8736,7 +8737,7 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
bool
IonBuilder::setPropTryCache(bool *emitted, MDefinition *obj,
HandlePropertyName name, MDefinition *value,
bool barrier, types::StackTypeSet *objTypes)
bool barrier, types::TemporaryTypeSet *objTypes)
{
JS_ASSERT(*emitted == false);
@ -8889,7 +8890,7 @@ IonBuilder::jsop_this()
return true;
}
types::StackTypeSet *types = types::TypeScript::ThisTypes(script());
types::TemporaryTypeSet *types = cloneTypeSet(types::TypeScript::ThisTypes(script()));
if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
(types->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject())))
{
@ -9120,7 +9121,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
current->add(load);
current->push(load);
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(load, types, true);
}
@ -9234,7 +9235,7 @@ IonBuilder::jsop_instanceof()
// If this is an 'x instanceof function' operation and we can determine the
// exact function and prototype object being tested for, use a typed path.
do {
types::StackTypeSet *rhsTypes = rhs->resultTypeSet();
types::TemporaryTypeSet *rhsTypes = rhs->resultTypeSet();
JSObject *rhsObject = rhsTypes ? rhsTypes->getSingleton() : NULL;
if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
break;
@ -9301,7 +9302,13 @@ IonBuilder::addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bail
return guard;
}
types::StackTypeSet *
types::TemporaryTypeSet *
IonBuilder::bytecodeTypes(jsbytecode *pc)
{
return cloneTypeSet(types::TypeScript::BytecodeTypes(script(), pc));
}
types::TemporaryTypeSet *
IonBuilder::cloneTypeSet(types::StackTypeSet *types)
{
// Clone a type set so that it can be stored into the MIR and accessed

View File

@ -224,8 +224,8 @@ class IonBuilder : public MIRGenerator
return js_IonOptions.inlining;
}
JSFunction *getSingleCallTarget(types::StackTypeSet *calleeTypes);
bool getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
bool canInlineTarget(JSFunction *target, bool constructing);
@ -294,7 +294,7 @@ class IonBuilder : public MIRGenerator
// Incorporates a type/typeSet into an OSR value for a loop, after the loop
// body has been processed.
bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def,
MIRType type, types::StackTypeSet *typeSet);
MIRType type, types::TemporaryTypeSet *typeSet);
bool maybeAddOsrTypeBarriers();
// Restarts processing of a loop if the type information at its header was
@ -325,7 +325,7 @@ class IonBuilder : public MIRGenerator
// Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needBarrier);
bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier);
JSObject *getSingletonPrototype(JSFunction *target);
@ -349,22 +349,22 @@ class IonBuilder : public MIRGenerator
bool hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall);
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
bool barrier, types::StackTypeSet *types);
bool barrier, types::TemporaryTypeSet *types);
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
MIRType slotType = MIRType_None);
// jsop_getprop() helpers.
bool getPropTryArgumentsLength(bool *emitted);
bool getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types);
bool getPropTryConstant(bool *emitted, HandleId id, types::TemporaryTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
bool barrier, types::StackTypeSet *types);
bool barrier, types::TemporaryTypeSet *types);
bool getPropTryCommonGetter(bool *emitted, HandleId id,
bool barrier, types::StackTypeSet *types);
bool barrier, types::TemporaryTypeSet *types);
bool getPropTryInlineAccess(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types);
bool barrier, types::TemporaryTypeSet *types);
bool getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types);
bool needsToMonitorMissingProperties(types::StackTypeSet *types);
bool barrier, types::TemporaryTypeSet *types);
bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
// jsop_setprop() helpers.
bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
@ -375,14 +375,14 @@ class IonBuilder : public MIRGenerator
bool isDOM);
bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
HandlePropertyName name, MDefinition *value,
bool barrier, types::StackTypeSet *objTypes);
bool barrier, types::TemporaryTypeSet *objTypes);
bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
HandlePropertyName name, HandleId id,
MDefinition *value, bool barrier,
types::StackTypeSet *objTypes);
types::TemporaryTypeSet *objTypes);
bool setPropTryCache(bool *emitted, MDefinition *obj,
HandlePropertyName name, MDefinition *value,
bool barrier, types::StackTypeSet *objTypes);
bool barrier, types::TemporaryTypeSet *objTypes);
// jsop_setelem() helpers.
bool setElemTryTyped(bool *emitted, MDefinition *object,
@ -441,7 +441,7 @@ class IonBuilder : public MIRGenerator
bool jsop_getelem_dense(MDefinition *obj, MDefinition *index);
bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeRepresentation::Type arrayType);
bool jsop_setelem();
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
bool jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_setelem_typed(ScalarTypeRepresentation::Type arrayType,
@ -497,7 +497,8 @@ class IonBuilder : public MIRGenerator
uint32_t selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet);
// Native inlining helpers.
types::StackTypeSet *getInlineReturnTypeSet();
types::StackTypeSet *getOriginalInlineReturnTypeSet();
types::TemporaryTypeSet *getInlineReturnTypeSet();
MIRType getInlineReturnType();
// Array natives.
@ -547,7 +548,7 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineParallelArrayTail(CallInfo &callInfo,
HandleFunction target,
MDefinition *ctor,
types::StackTypeSet *ctorTypes,
types::TemporaryTypeSet *ctorTypes,
uint32_t discards);
// Utility intrinsics.
@ -580,6 +581,8 @@ class IonBuilder : public MIRGenerator
MTypeObjectDispatch *dispatch, MGetPropertyCache *cache,
MBasicBlock **fallbackTarget);
bool testNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo);
MDefinition *makeCallsiteClone(HandleFunction target, MDefinition *fun);
MCall *makeCallHelper(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
bool makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
@ -587,17 +590,18 @@ class IonBuilder : public MIRGenerator
MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasicBlock *bottom);
inline bool TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types,
inline bool TestCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types,
HandleId id, JSFunction **funcp,
bool isGetter, bool *isDOM,
MDefinition **guardOut);
bool annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes);
types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes);
MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
types::StackTypeSet *cloneTypeSet(types::StackTypeSet *types);
types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc);
types::TemporaryTypeSet *cloneTypeSet(types::StackTypeSet *types);
// Use one of the below methods for updating the current block, rather than
// updating |current| directly. setCurrent() should only be used in cases

View File

@ -20,6 +20,7 @@
#include "vm/Shape.h"
#include "vm/Interpreter-inl.h"
#include "vm/Shape-inl.h"
using namespace js;
using namespace js::jit;

View File

@ -93,7 +93,7 @@ class ICStubSpace
// OptimizedICStubSpace.
struct OptimizedICStubSpace : public ICStubSpace
{
const static size_t STUB_DEFAULT_CHUNK_SIZE = 4 * 1024;
static const size_t STUB_DEFAULT_CHUNK_SIZE = 4 * 1024;
public:
OptimizedICStubSpace()
@ -109,7 +109,7 @@ struct OptimizedICStubSpace : public ICStubSpace
// FallbackICStubSpace.
struct FallbackICStubSpace : public ICStubSpace
{
const static size_t STUB_DEFAULT_CHUNK_SIZE = 256;
static const size_t STUB_DEFAULT_CHUNK_SIZE = 256;
public:
FallbackICStubSpace()

View File

@ -138,9 +138,9 @@ MacroAssembler::guardType(const Source &address, types::Type type,
guardTypeSet(address, &wrapper, scratch, matched, miss);
}
template void MacroAssembler::guardTypeSet(const Address &address, const types::StackTypeSet *types,
template void MacroAssembler::guardTypeSet(const Address &address, const types::TemporaryTypeSet *types,
Register scratch, Label *matched, Label *miss);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::StackTypeSet *types,
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TemporaryTypeSet *types,
Register scratch, Label *matched, Label *miss);
template void MacroAssembler::guardTypeSet(const Address &address, const types::HeapTypeSet *types,
@ -160,7 +160,7 @@ template void MacroAssembler::guardTypeSet(const Address &address, const TypeWra
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const TypeWrapper *types,
Register scratch, Label *matched, Label *miss);
template void MacroAssembler::guardObjectType(Register obj, const types::StackTypeSet *types,
template void MacroAssembler::guardObjectType(Register obj, const types::TemporaryTypeSet *types,
Register scratch, Label *matched, Label *miss);
template void MacroAssembler::guardObjectType(Register obj, const types::TypeSet *types,
Register scratch, Label *matched, Label *miss);

View File

@ -1951,7 +1951,7 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
// Requesting a non-GC pointer is safe here since we never re-enter C++
// from inside a type barrier test.
const types::StackTypeSet *types = ins->resultTypeSet();
const types::TemporaryTypeSet *types = ins->resultTypeSet();
bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
MIRType inputType = ins->getOperand(0)->type();
@ -2002,7 +2002,7 @@ LIRGenerator::visitMonitorTypes(MMonitorTypes *ins)
// Requesting a non-GC pointer is safe here since we never re-enter C++
// from inside a type check.
const types::StackTypeSet *types = ins->typeSet();
const types::TemporaryTypeSet *types = ins->typeSet();
bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
LDefinition tmp = needTemp ? temp() : tempToUnbox();

View File

@ -159,15 +159,21 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
}
types::StackTypeSet *
IonBuilder::getInlineReturnTypeSet()
IonBuilder::getOriginalInlineReturnTypeSet()
{
return types::TypeScript::BytecodeTypes(script(), pc);
}
types::TemporaryTypeSet *
IonBuilder::getInlineReturnTypeSet()
{
return cloneTypeSet(getOriginalInlineReturnTypeSet());
}
MIRType
IonBuilder::getInlineReturnType()
{
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
}
@ -246,9 +252,9 @@ IonBuilder::inlineArray(CallInfo &callInfo)
if (!templateObject)
return InliningStatus_Error;
types::StackTypeSet::DoubleConversion conversion =
types::TemporaryTypeSet::DoubleConversion conversion =
getInlineReturnTypeSet()->convertDoubleElements(cx);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
templateObject->setShouldConvertDoubleElements();
MNewArray *ins = new MNewArray(initLength, templateObject, allocating);
@ -271,7 +277,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
current->add(id);
MDefinition *value = callInfo.getArg(i);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles) {
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
MInstruction *valueDouble = MToDouble::New(value);
current->add(valueDouble);
value = valueDouble;
@ -313,7 +319,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
types::OBJECT_FLAG_LENGTH_OVERFLOW |
types::OBJECT_FLAG_ITERATED;
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, unhandledFlags))
@ -324,7 +330,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
callInfo.unwrapArgs();
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
types::StackTypeSet *returnTypes = getOriginalInlineReturnTypeSet();
bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
@ -344,7 +350,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
if (!resumeAfter(ins))
return InliningStatus_Error;
if (!pushTypeBarrier(ins, returnTypes, barrier))
if (!pushTypeBarrier(ins, cloneTypeSet(returnTypes), barrier))
return InliningStatus_Error;
return InliningStatus_Inlined;
@ -373,7 +379,7 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
@ -385,15 +391,15 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
if (types::ArrayPrototypeHasIndexedProperty(cx, script))
return InliningStatus_NotInlined;
types::StackTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(cx);
if (conversion == types::StackTypeSet::AmbiguousDoubleConversion)
types::TemporaryTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(cx);
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
value = callInfo.getArg(0);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles ||
conversion == types::StackTypeSet::MaybeConvertToDoubles)
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles ||
conversion == types::TemporaryTypeSet::MaybeConvertToDoubles)
{
MInstruction *valueDouble = MToDouble::New(value);
current->add(valueDouble);
@ -427,8 +433,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
return InliningStatus_NotInlined;
// |this| and the argument must be dense arrays.
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::StackTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::TemporaryTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
if (!thisTypes || !argTypes)
return InliningStatus_NotInlined;
@ -481,7 +487,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
if (!thisElemTypes)
return InliningStatus_Error;
types::StackTypeSet *resTypes = getInlineReturnTypeSet();
types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet();
if (!resTypes->hasType(types::Type::ObjectType(thisType)))
return InliningStatus_NotInlined;
@ -1001,7 +1007,7 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
const Class *clasp = thisTypes ? thisTypes->getKnownClass() : NULL;
if (clasp != &RegExpObject::class_)
return InliningStatus_NotInlined;
@ -1113,7 +1119,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
MDefinition *id = callInfo.getArg(base + 1);
MDefinition *elem = callInfo.getArg(base + 2);
types::StackTypeSet::DoubleConversion conversion =
types::TemporaryTypeSet::DoubleConversion conversion =
obj->resultTypeSet()->convertDoubleElements(cx);
if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
return false;
@ -1186,7 +1192,7 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo)
if (argc < 1 || callInfo.constructing())
return InliningStatus_NotInlined;
types::StackTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
types::TemporaryTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
JSObject *targetObj = ctorTypes ? ctorTypes->getSingleton() : NULL;
RootedFunction target(cx);
if (targetObj && targetObj->is<JSFunction>())
@ -1233,7 +1239,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
HandleFunction target,
MDefinition *ctor,
types::StackTypeSet *ctorTypes,
types::TemporaryTypeSet *ctorTypes,
uint32_t discards)
{
// Rewrites either NewParallelArray(...) or new ParallelArray(...) from a
@ -1245,7 +1251,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
// Create the new parallel array object. Parallel arrays have specially
// constructed type objects, so we can only perform the inlining if we
// already have one of these type objects.
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
if (returnTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
return InliningStatus_NotInlined;
if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
@ -1358,7 +1364,7 @@ IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
// Create the new parallel array object. Parallel arrays have specially
// constructed type objects, so we can only perform the inlining if we
// already have one of these type objects.
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
if (returnTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
return InliningStatus_NotInlined;
if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
@ -1476,8 +1482,8 @@ IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
if (callInfo.getArg(1)->type() != MIRType_Object)
return InliningStatus_NotInlined;
types::StackTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
types::StackTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
types::TemporaryTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
types::TemporaryTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
const Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : NULL;
const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : NULL;
if (arg1Clasp && arg2Clasp) {
@ -1515,7 +1521,7 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
isCallableKnown = true;
isCallableConstant = false;
} else {
types::StackTypeSet *types = callInfo.getArg(0)->resultTypeSet();
types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
const Class *clasp = types ? types->getKnownClass() : NULL;
if (clasp) {
isCallableKnown = true;

View File

@ -204,7 +204,7 @@ MaybeEmulatesUndefined(JSContext *cx, MDefinition *op)
if (!op->mightBeType(MIRType_Object))
return false;
types::StackTypeSet *types = op->resultTypeSet();
types::TemporaryTypeSet *types = op->resultTypeSet();
if (!types)
return true;
@ -219,7 +219,7 @@ MaybeCallable(JSContext *cx, MDefinition *op)
if (!op->mightBeType(MIRType_Object))
return false;
types::StackTypeSet *types = op->resultTypeSet();
types::TemporaryTypeSet *types = op->resultTypeSet();
if (!types)
return true;
@ -402,16 +402,11 @@ MConstant::New(const Value &v)
return new MConstant(v);
}
types::StackTypeSet *
types::TemporaryTypeSet *
jit::MakeSingletonTypeSet(JSObject *obj)
{
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
if (!types)
return NULL;
types::Type objectType = types::Type::ObjectType(obj);
types->addObject(objectType.objectKey(), alloc);
return types;
return alloc->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
}
MConstant::MConstant(const js::Value &vp)
@ -545,7 +540,7 @@ MConstantElements::printOpcode(FILE *fp) const
}
MParameter *
MParameter::New(int32_t index, types::StackTypeSet *types)
MParameter::New(int32_t index, types::TemporaryTypeSet *types)
{
return new MParameter(index, types);
}
@ -768,19 +763,19 @@ MPhi::reserveLength(size_t length)
return inputs_.reserve(length);
}
static inline types::StackTypeSet *
static inline types::TemporaryTypeSet *
MakeMIRTypeSet(MIRType type)
{
JS_ASSERT(type != MIRType_Value);
types::Type ntype = type == MIRType_Object
? types::Type::AnyObjectType()
: types::Type::PrimitiveType(ValueTypeFromMIRType(type));
return GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
}
void
jit::MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
MIRType newType, types::StackTypeSet *newTypeSet)
jit::MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
MIRType newType, types::TemporaryTypeSet *newTypeSet)
{
if (newTypeSet && newTypeSet->empty())
return;
@ -832,7 +827,7 @@ MPhi::specializeType()
}
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
for (size_t i = start; i < inputs_.length(); i++) {
MDefinition *def = getOperand(i);
@ -844,13 +839,13 @@ MPhi::specializeType()
}
void
MPhi::addBackedgeType(MIRType type, types::StackTypeSet *typeSet)
MPhi::addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet)
{
JS_ASSERT(!specialized_);
if (hasBackedgeType_) {
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
MergeTypes(&resultType, &resultTypeSet, type, typeSet);
@ -869,7 +864,7 @@ MPhi::typeIncludes(MDefinition *def)
if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
return true;
if (types::StackTypeSet *types = def->resultTypeSet()) {
if (types::TemporaryTypeSet *types = def->resultTypeSet()) {
if (this->resultTypeSet())
return types->isSubset(this->resultTypeSet());
if (this->type() == MIRType_Value || types->empty())
@ -926,7 +921,7 @@ MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
if (ptypeChange) {
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet());
@ -1564,7 +1559,7 @@ MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
// either to avoid degrading subsequent analysis.
if (getOperand(0)->emptyResultTypeSet() || getOperand(1)->emptyResultTypeSet()) {
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
if (types)
setResultTypeSet(types);
}
@ -2501,11 +2496,11 @@ InlinePropertyTable::hasFunction(JSFunction *func) const
return false;
}
types::StackTypeSet *
types::TemporaryTypeSet *
InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
{
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
if (!types)
return NULL;
for (size_t i = 0; i < numEntries(); i++) {
@ -2640,7 +2635,7 @@ jit::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
return false;
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types)
return false;
@ -2658,7 +2653,7 @@ jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
return false;
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types)
return false;
@ -2669,14 +2664,14 @@ jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
bool
jit::ElementAccessIsPacked(JSContext *cx, MDefinition *obj)
{
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
return types && !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
}
bool
jit::ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj)
{
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types || types->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW))
return true;
@ -2690,7 +2685,7 @@ jit::DenseNativeElementType(JSContext *cx, MDefinition *obj, MIRType *result)
JS_ASSERT(result);
*result = MIRType_None;
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
MIRType elementType = MIRType_None;
unsigned count = types->getObjectCount();
@ -2877,7 +2872,7 @@ jit::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *na
JS_ASSERT(observed->noConstraints());
types::StackTypeSet *types = obj->resultTypeSet();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject()) {
observed->addType(cx, types::Type::AnyObjectType());
return true;
@ -2916,7 +2911,7 @@ jit::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *na
}
static bool
TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeSet *objTypes,
TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::TemporaryTypeSet *objTypes,
jsid id, MDefinition **pvalue)
{
// Return whether pvalue was modified to include a type barrier ensuring
@ -2986,7 +2981,7 @@ TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeS
if ((*pvalue)->type() != MIRType_Value)
return false;
types::StackTypeSet *types = aggregateProperty->clone(GetIonContext()->temp->lifoAlloc());
types::TemporaryTypeSet *types = aggregateProperty->clone(GetIonContext()->temp->lifoAlloc());
if (!types)
return false;
@ -3022,7 +3017,7 @@ jit::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinit
// properties that are accounted for by type information, i.e. normal data
// properties and elements.
types::StackTypeSet *types = (*pobj)->resultTypeSet();
types::TemporaryTypeSet *types = (*pobj)->resultTypeSet();
if (!types || types->unknownObject()) {
*result = true;
return true;

View File

@ -283,7 +283,7 @@ class MDefinition : public MNode
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
Range *range_; // Any computed range for this def.
MIRType resultType_; // Representation of result type.
types::StackTypeSet *resultTypeSet_; // Optional refinement of the result type.
types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type.
uint32_t flags_; // Bit flags.
union {
MDefinition *dependency_; // Implicit dependency (store, call, etc.) of this instruction.
@ -436,7 +436,7 @@ class MDefinition : public MNode
return resultType_;
}
types::StackTypeSet *resultTypeSet() const {
types::TemporaryTypeSet *resultTypeSet() const {
return resultTypeSet_;
}
bool emptyResultTypeSet() const;
@ -548,7 +548,7 @@ class MDefinition : public MNode
void setResultType(MIRType type) {
resultType_ = type;
}
void setResultTypeSet(types::StackTypeSet *types) {
void setResultTypeSet(types::TemporaryTypeSet *types) {
resultTypeSet_ = types;
}
@ -979,7 +979,7 @@ class MParameter : public MNullaryInstruction
public:
static const int32_t THIS_SLOT = -1;
MParameter(int32_t index, types::StackTypeSet *types)
MParameter(int32_t index, types::TemporaryTypeSet *types)
: index_(index)
{
setResultType(MIRType_Value);
@ -988,7 +988,7 @@ class MParameter : public MNullaryInstruction
public:
INSTRUCTION_HEADER(Parameter)
static MParameter *New(int32_t index, types::StackTypeSet *types);
static MParameter *New(int32_t index, types::TemporaryTypeSet *types);
int32_t index() const {
return index_;
@ -1354,12 +1354,12 @@ class MNewParallelArray : public MNullaryInstruction
};
// Fabricate a type set containing only the type of the specified object.
types::StackTypeSet *
types::TemporaryTypeSet *
MakeSingletonTypeSet(JSObject *obj);
void
MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
MIRType newType, types::StackTypeSet *newTypeSet);
MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
MIRType newType, types::TemporaryTypeSet *newTypeSet);
class MNewArray : public MNullaryInstruction
{
@ -2133,7 +2133,7 @@ class MBox : public MUnaryInstruction
types::Type ntype = ins->type() == MIRType_Object
? types::Type::AnyObjectType()
: types::Type::PrimitiveType(ValueTypeFromMIRType(ins->type()));
setResultTypeSet(GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype));
setResultTypeSet(GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype));
}
setMovable();
}
@ -2197,7 +2197,7 @@ class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
setResultTypeSet(ins->resultTypeSet());
setMovable();
if (mode_ == TypeBarrier)
if (mode_ == TypeBarrier || mode_ == Fallible)
setGuard();
bailoutKind_ = kind;
@ -4076,7 +4076,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
// Add types for this phi which speculate about new inputs that may come in
// via a loop backedge.
void addBackedgeType(MIRType type, types::StackTypeSet *typeSet);
void addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet);
// Initializes the operands vector to the given capacity,
// permitting use of addInput() instead of addInputSlow().
@ -4454,7 +4454,7 @@ class MLambdaPar
CompilerRootFunction fun_;
MLambdaPar(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun,
types::StackTypeSet *resultTypes)
types::TemporaryTypeSet *resultTypes)
: MBinaryInstruction(slice, scopeChain), fun_(fun)
{
JS_ASSERT(!fun->hasSingletonType());
@ -4725,6 +4725,8 @@ class MInitializedLength
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
void computeRange();
};
// Set a dense array's initialized length to an elements vector.
@ -4778,6 +4780,8 @@ class MArrayLength
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
void computeRange();
};
// Read the length of a typed array.
@ -4813,6 +4817,8 @@ class MTypedArrayLength
// implicit dependency.
return AliasSet::None();
}
void computeRange();
};
// Load a typed array's elements vector.
@ -5880,7 +5886,7 @@ class InlinePropertyTable : public TempObject
}
bool hasFunction(JSFunction *func) const;
types::StackTypeSet *buildTypeSetForFunction(JSFunction *func) const;
types::TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const;
// Remove targets that vetoed inlining from the InlinePropertyTable.
void trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet);
@ -7262,6 +7268,8 @@ class MStringLength
// implicit dependency.
return AliasSet::None();
}
void computeRange();
};
// Inlined version of Math.floor().
@ -7569,6 +7577,8 @@ class MArgumentsLength : public MNullaryInstruction
// Arguments |length| cannot be mutated by Ion Code.
return AliasSet::None();
}
void computeRange();
};
// This MIR instruction is used to get an argument from the actual arguments.
@ -7666,7 +7676,7 @@ class MRestPar
public IntPolicy<1>
{
MRestPar(MDefinition *slice, MDefinition *numActuals, unsigned numFormals,
JSObject *templateObject, types::StackTypeSet *resultTypes)
JSObject *templateObject, types::TemporaryTypeSet *resultTypes)
: MBinaryInstruction(slice, numActuals),
MRestCommon(numFormals, templateObject)
{
@ -7749,7 +7759,7 @@ class MTypeBarrier
{
BailoutKind bailoutKind_;
MTypeBarrier(MDefinition *def, types::StackTypeSet *types, BailoutKind bailoutKind)
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types, BailoutKind bailoutKind)
: MUnaryInstruction(def)
{
JS_ASSERT(!types->unknown());
@ -7766,11 +7776,11 @@ class MTypeBarrier
public:
INSTRUCTION_HEADER(TypeBarrier)
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types) {
static MTypeBarrier *New(MDefinition *def, types::TemporaryTypeSet *types) {
BailoutKind kind = def->isEffectful() ? Bailout_TypeBarrier : Bailout_Normal;
return new MTypeBarrier(def, types, kind);
}
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types,
static MTypeBarrier *New(MDefinition *def, types::TemporaryTypeSet *types,
BailoutKind kind) {
return new MTypeBarrier(def, types, kind);
}
@ -7811,9 +7821,9 @@ class MTypeBarrier
// in the property types for the object.
class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
{
const types::StackTypeSet *typeSet_;
const types::TemporaryTypeSet *typeSet_;
MMonitorTypes(MDefinition *def, const types::StackTypeSet *types)
MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types)
: MUnaryInstruction(def),
typeSet_(types)
{
@ -7824,7 +7834,7 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
public:
INSTRUCTION_HEADER(MonitorTypes)
static MMonitorTypes *New(MDefinition *def, const types::StackTypeSet *types) {
static MMonitorTypes *New(MDefinition *def, const types::TemporaryTypeSet *types) {
return new MMonitorTypes(def, types);
}
@ -7832,7 +7842,7 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
return this;
}
const types::StackTypeSet *typeSet() const {
const types::TemporaryTypeSet *typeSet() const {
return typeSet_;
}
AliasSet getAliasSet() const {

View File

@ -773,7 +773,7 @@ ParallelSafetyVisitor::visitThrow(MThrow *thr)
static bool
GetPossibleCallees(JSContext *cx, HandleScript script, jsbytecode *pc,
types::StackTypeSet *calleeTypes, CallTargetVector &targets);
types::TemporaryTypeSet *calleeTypes, CallTargetVector &targets);
static bool
AddCallTarget(HandleScript script, CallTargetVector &targets);
@ -804,7 +804,7 @@ jit::AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets)
continue;
}
types::StackTypeSet *calleeTypes = callIns->getFunction()->resultTypeSet();
types::TemporaryTypeSet *calleeTypes = callIns->getFunction()->resultTypeSet();
RootedScript script(cx, callIns->block()->info().script());
if (!GetPossibleCallees(cx,
script,
@ -822,7 +822,7 @@ static bool
GetPossibleCallees(JSContext *cx,
HandleScript script,
jsbytecode *pc,
types::StackTypeSet *calleeTypes,
types::TemporaryTypeSet *calleeTypes,
CallTargetVector &targets)
{
if (!calleeTypes || calleeTypes->baseFlags() != 0)

View File

@ -1170,6 +1170,42 @@ MLoadTypedArrayElementStatic::computeRange()
setRange(range);
}
void
MArrayLength::computeRange()
{
Range *r = new Range(0, UINT32_MAX);
r->extendUInt32ToInt32Min();
setRange(r);
}
void
MInitializedLength::computeRange()
{
Range *r = new Range(0, UINT32_MAX);
r->extendUInt32ToInt32Min();
setRange(r);
}
void
MTypedArrayLength::computeRange()
{
setRange(new Range(0, INT32_MAX));
}
void
MStringLength::computeRange()
{
setRange(new Range(0, JSString::MAX_LENGTH));
}
void
MArgumentsLength::computeRange()
{
// This is is a conservative upper bound on what |TooManyArguments| checks.
// If exceeded, Ion will not be entered in the first place.
setRange(new Range(0, SNAPSHOT_MAX_NARGS));
}
///////////////////////////////////////////////////////////////////////////////
// Range Analysis
///////////////////////////////////////////////////////////////////////////////

Some files were not shown because too many files have changed in this diff Show More