--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -54,15 +54,20 @@ MOZ_TIME_MANAGER=1
MOZ_PAY=1
MOZ_TOOLKIT_SEARCH=
MOZ_PLACES=
MOZ_B2G=1
if test "$OS_TARGET" = "Android"; then
MOZ_NUWA_PROCESS=1
MOZ_B2G_LOADER=1
+# Warnings-as-errors cannot be enabled on gcc <= 4.4 due to bug 915555.
+if test "$GCC_MAJOR_VERSION" -gt 4 -o \
+ "$GCC_MAJOR_VERSION" -eq 4 -a "$GCC_MINOR_VERSION" -gt 4; then
+MOZ_ENABLE_WARNINGS_AS_ERRORS=1
+fi
fi
MOZ_JSDOWNLOADS=1
MOZ_BUNDLED_FONTS=1
export JS_GC_SMALL_CHUNK_SIZE=1
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -20,17 +20,17 @@
<command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" />
<command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" />
<command id="cmd_newNavigatorTab" oncommand="BrowserOpenNewTabOrWindow(event);"/>
<command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/>
<command id="Browser:SavePage" oncommand="saveDocument(gBrowser.selectedBrowser.contentDocumentAsCPOW);"/>
<command id="Browser:SendLink"
- oncommand="MailIntegration.sendLinkForWindow(window.content);"/>
+ oncommand="MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);"/>
<command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
<command id="cmd_print" oncommand="PrintUtils.print(window.gBrowser.selectedBrowser.contentWindowAsCPOW, window.gBrowser.selectedBrowser);"/>
<command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
<command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
<command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/>
<command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/>
<command id="cmd_quitApplication" oncommand="goQuitApplication()"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1733,17 +1733,17 @@ function HandleAppCommandEvent(evt) {
case "Print":
PrintUtils.print(gBrowser.selectedBrowser.contentWindowAsCPOW,
gBrowser.selectedBrowser);
break;
case "Save":
saveDocument(gBrowser.selectedBrowser.contentDocumentAsCPOW);
break;
case "SendMail":
- MailIntegration.sendLinkForWindow(window.content);
+ MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
break;
default:
return;
}
evt.stopPropagation();
evt.preventDefault();
}
@@ -6519,19 +6519,18 @@ function warnAboutClosingWindow() {
// closing multiple tabs.
return isPBWindow || gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL);
#else
return true;
#endif
}
var MailIntegration = {
- sendLinkForWindow: function (aWindow) {
- this.sendMessage(aWindow.location.href,
- aWindow.document.title);
+ sendLinkForBrowser: function (aBrowser) {
+ this.sendMessage(aBrowser.currentURI.spec, aBrowser.contentTitle);
},
sendMessage: function (aBody, aSubject) {
// generate a mailto url based on the url and the url's title
var mailtoUrl = "mailto:";
if (aBody) {
mailtoUrl += "?body=" + encodeURIComponent(aBody);
mailtoUrl += "&subject=" + encodeURIComponent(aSubject);
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -915,17 +915,17 @@ const CustomizableWidgets = [
this.charsetInfo = CharsetMenu.getData();
}
}
}, {
id: "email-link-button",
tooltiptext: "email-link-button.tooltiptext3",
onCommand: function(aEvent) {
let win = aEvent.view;
- win.MailIntegration.sendLinkForWindow(win.content);
+ win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser)
}
}, {
id: "loop-button",
type: "custom",
label: "loop-call-button3.label",
tooltiptext: "loop-call-button3.tooltiptext",
defaultArea: CustomizableUI.AREA_NAVBAR,
introducedInVersion: 4,
--- a/browser/components/loop/standalone/content/libs/l10n-gaia-02ca67948fe8.js
+++ b/browser/components/loop/standalone/content/libs/l10n-gaia-02ca67948fe8.js
@@ -1236,21 +1236,29 @@
return locales[code] = new Locale(code, this);
};
// Getting ready
function negotiate(available, requested, defaultLocale) {
- if (available.indexOf(requested[0]) === -1 ||
- requested[0] === defaultLocale) {
+ var supportedLocale;
+ for (var i = 0; i < requested.length; ++i) {
+ var locale = requested[i];
+ if (available.indexOf(locale) !== -1) {
+ supportedLocale = locale;
+ break;
+ }
+ }
+ if (!supportedLocale ||
+ supportedLocale === defaultLocale) {
return [defaultLocale];
} else {
- return [requested[0], defaultLocale];
+ return [supportedLocale, defaultLocale];
}
}
function freeze(supported) {
var locale = this.getLocale(supported[0]);
if (locale.isReady) {
setReady.call(this, supported);
} else {
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -142,16 +142,24 @@ DEFINES += -DMOZ_JEMALLOC3
endif
DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
ifdef CLANG_CXX
DEFINES += -DCLANG_CXX
endif
ifdef CLANG_CL
DEFINES += -DCLANG_CL
endif
+ifeq (x86,$(CPU_ARCH))
+ifdef _MSC_VER
+ifndef CLANG_CL
+DEFINES += -DWOW_HELPER
+endif
+endif
+endif
+
libs::
$(MAKE) -C $(DEPTH)/browser/locales langpack
ifeq (WINNT,$(OS_ARCH))
PKGCOMP_FIND_OPTS =
else
PKGCOMP_FIND_OPTS = -L
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -778,16 +778,19 @@
@RESPATH@/components/pipboot.xpt
@RESPATH@/components/pipnss.xpt
@RESPATH@/components/pippki.xpt
; For process sandboxing
#if defined(MOZ_SANDBOX)
#if defined(XP_WIN)
@BINPATH@/@DLL_PREFIX@sandboxbroker@DLL_SUFFIX@
+#if defined(WOW_HELPER)
+@BINPATH@/wow_helper.exe
+#endif
#endif
#endif
; for Solaris SPARC
#ifdef SOLARIS
bin/libfreebl_32fpu_3.so
bin/libfreebl_32int_3.so
bin/libfreebl_32int64_3.so
--- a/build/stlport/moz.build
+++ b/build/stlport/moz.build
@@ -4,19 +4,16 @@
# 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/.
Library('stlport')
# Keep the same name as the NDK-provided library, while using a shorter
# name for the Library for convenience in moz.build.
STATIC_LIBRARY_NAME = 'stlport_static'
-if not CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
- OS_LIBS += ['-static-libstdc++']
-
FORCE_STATIC_LIB = True
SOURCES += [
'src/allocators.cpp',
'src/bitset.cpp',
'src/codecvt.cpp',
'src/collate.cpp',
'src/complex.cpp',
--- a/docshell/base/LoadInfo.cpp
+++ b/docshell/base/LoadInfo.cpp
@@ -23,31 +23,48 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
: mLoadingPrincipal(aLoadingContext ?
aLoadingContext->NodePrincipal() : aLoadingPrincipal)
, mTriggeringPrincipal(aTriggeringPrincipal ?
aTriggeringPrincipal : mLoadingPrincipal.get())
, mLoadingContext(do_GetWeakReference(aLoadingContext))
, mSecurityFlags(aSecurityFlags)
, mContentPolicyType(aContentPolicyType)
, mBaseURI(aBaseURI)
+ , mInnerWindowID(aLoadingContext ?
+ aLoadingContext->OwnerDoc()->InnerWindowID() : 0)
{
MOZ_ASSERT(mLoadingPrincipal);
MOZ_ASSERT(mTriggeringPrincipal);
// if consumers pass both, aLoadingContext and aLoadingPrincipal
// then the loadingPrincipal must be the same as the node's principal
MOZ_ASSERT(!aLoadingContext || !aLoadingPrincipal ||
aLoadingContext->NodePrincipal() == aLoadingPrincipal);
// if the load is sandboxed, we can not also inherit the principal
if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
}
+LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
+ nsIPrincipal* aTriggeringPrincipal,
+ nsSecurityFlags aSecurityFlags,
+ nsContentPolicyType aContentPolicyType,
+ uint32_t aInnerWindowID)
+ : mLoadingPrincipal(aLoadingPrincipal)
+ , mTriggeringPrincipal(aTriggeringPrincipal)
+ , mSecurityFlags(aSecurityFlags)
+ , mContentPolicyType(aContentPolicyType)
+ , mInnerWindowID(aInnerWindowID)
+{
+ MOZ_ASSERT(mLoadingPrincipal);
+ MOZ_ASSERT(mTriggeringPrincipal);
+}
+
LoadInfo::~LoadInfo()
{
}
NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo)
NS_IMETHODIMP
LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal)
@@ -130,9 +147,16 @@ LoadInfo::GetBaseURI(nsIURI** aBaseURI)
}
nsIURI*
LoadInfo::BaseURI()
{
return mBaseURI;
}
+NS_IMETHODIMP
+LoadInfo::GetInnerWindowID(uint32_t* outInnerWindowID)
+{
+ *outInnerWindowID = mInnerWindowID;
+ return NS_OK;
+}
+
} // namespace mozilla
--- a/docshell/base/LoadInfo.h
+++ b/docshell/base/LoadInfo.h
@@ -12,16 +12,21 @@
#include "nsIPrincipal.h"
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
#include "nsIURI.h"
class nsINode;
namespace mozilla {
+namespace net {
+class HttpChannelParent;
+class FTPChannelParent;
+}
+
/**
* Class that provides an nsILoadInfo implementation.
*/
class MOZ_EXPORT LoadInfo MOZ_FINAL : public nsILoadInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSILOADINFO
@@ -30,22 +35,35 @@ public:
LoadInfo(nsIPrincipal* aLoadingPrincipal,
nsIPrincipal* aTriggeringPrincipal,
nsINode* aLoadingContext,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsIURI* aBaseURI = nullptr);
private:
+ // private constructor that is only allowed to be called from within
+ // HttpChannelParent and FTPChannelParent declared as friends undeneath.
+ // In e10s we can not serialize nsINode, hence we store the innerWindowID.
+ LoadInfo(nsIPrincipal* aLoadingPrincipal,
+ nsIPrincipal* aTriggeringPrincipal,
+ nsSecurityFlags aSecurityFlags,
+ nsContentPolicyType aContentPolicyType,
+ uint32_t aInnerWindowID);
+
+ friend class net::HttpChannelParent;
+ friend class net::FTPChannelParent;
+
~LoadInfo();
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
nsWeakPtr mLoadingContext;
nsSecurityFlags mSecurityFlags;
nsContentPolicyType mContentPolicyType;
nsCOMPtr<nsIURI> mBaseURI;
+ uint32_t mInnerWindowID;
};
} // namespace mozilla
#endif // mozilla_LoadInfo_h
--- a/docshell/base/nsILoadInfo.idl
+++ b/docshell/base/nsILoadInfo.idl
@@ -175,9 +175,29 @@ interface nsILoadInfo : nsISupports
*/
readonly attribute nsIURI baseURI;
/**
* A C++-friendly version of baseURI.
*/
[noscript, notxpcom, nostdcall, binaryname(BaseURI)]
nsIURI binaryBaseURI();
+
+ /**
+ * The innerWindowId of the loadingDocument, used to identify
+ * the loadingDocument in e10s where the loadingDocument is
+ * not available.
+ *
+ * Warning: If the loadingDocument is null, then the
+ * innerWindowId is 0.
+ */
+ readonly attribute unsigned long innerWindowID;
+
+%{ C++
+ inline uint32_t GetInnerWindowID()
+ {
+ uint32_t result;
+ mozilla::DebugOnly<nsresult> rv = GetInnerWindowID(&result);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ return result;
+ }
+%}
};
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -225,19 +225,17 @@ NS_GetContentList(nsINode* aRootNode,
ContentListHashEntry *entry = nullptr;
// First we look in our hashtable. Then we create a content list if needed
if (gContentListHashTable.ops) {
// A PL_DHASH_ADD is equivalent to a PL_DHASH_LOOKUP for cases
// when the entry is already in the hashtable.
entry = static_cast<ContentListHashEntry *>
- (PL_DHashTableOperate(&gContentListHashTable,
- &hashKey,
- PL_DHASH_ADD));
+ (PL_DHashTableAdd(&gContentListHashTable, &hashKey));
if (entry)
list = entry->mContentList;
}
if (!list) {
// We need to create a ContentList and add it to our new entry, if
// we have an entry
nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
@@ -341,19 +339,18 @@ GetFuncStringContentList(nsINode* aRootN
FuncStringContentListHashEntry *entry = nullptr;
// First we look in our hashtable. Then we create a content list if needed
if (gFuncStringContentListHashTable.ops) {
nsFuncStringCacheKey hashKey(aRootNode, aFunc, aString);
// A PL_DHASH_ADD is equivalent to a PL_DHASH_LOOKUP for cases
// when the entry is already in the hashtable.
entry = static_cast<FuncStringContentListHashEntry *>
- (PL_DHashTableOperate(&gFuncStringContentListHashTable,
- &hashKey,
- PL_DHASH_ADD));
+ (PL_DHashTableAdd(&gFuncStringContentListHashTable,
+ &hashKey));
if (entry) {
list = entry->mContentList;
#ifdef DEBUG
MOZ_ASSERT_IF(list, list->mType == ListType::sType);
#endif
}
}
@@ -984,19 +981,17 @@ nsContentList::RemoveFromHashtable()
uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(key);
if (sRecentlyUsedContentLists[recentlyUsedCacheIndex] == this) {
sRecentlyUsedContentLists[recentlyUsedCacheIndex] = nullptr;
}
if (!gContentListHashTable.ops)
return;
- PL_DHashTableOperate(&gContentListHashTable,
- &key,
- PL_DHASH_REMOVE);
+ PL_DHashTableRemove(&gContentListHashTable, &key);
if (gContentListHashTable.EntryCount() == 0) {
PL_DHashTableFinish(&gContentListHashTable);
gContentListHashTable.ops = nullptr;
}
}
void
@@ -1027,19 +1022,17 @@ nsCacheableFuncStringContentList::~nsCac
void
nsCacheableFuncStringContentList::RemoveFromFuncStringHashtable()
{
if (!gFuncStringContentListHashTable.ops) {
return;
}
nsFuncStringCacheKey key(mRootNode, mFunc, mString);
- PL_DHashTableOperate(&gFuncStringContentListHashTable,
- &key,
- PL_DHASH_REMOVE);
+ PL_DHashTableRemove(&gFuncStringContentListHashTable, &key);
if (gFuncStringContentListHashTable.EntryCount() == 0) {
PL_DHashTableFinish(&gFuncStringContentListHashTable);
gFuncStringContentListHashTable.ops = nullptr;
}
}
#ifdef DEBUG_CONTENT_LIST
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3949,18 +3949,17 @@ nsContentUtils::TraverseListenerManager(
{
if (!sEventListenerManagersHash.ops) {
// We're already shut down, just return.
return;
}
EventListenerManagerMapEntry *entry =
static_cast<EventListenerManagerMapEntry *>
- (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sEventListenerManagersHash, aNode));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
CycleCollectionNoteChild(cb, entry->mListenerManager.get(),
"[via hash] mListenerManager");
}
}
EventListenerManager*
nsContentUtils::GetListenerManagerForNode(nsINode *aNode)
@@ -3969,18 +3968,17 @@ nsContentUtils::GetListenerManagerForNod
// We're already shut down, don't bother creating an event listener
// manager.
return nullptr;
}
EventListenerManagerMapEntry *entry =
static_cast<EventListenerManagerMapEntry *>
- (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
- PL_DHASH_ADD));
+ (PL_DHashTableAdd(&sEventListenerManagersHash, aNode));
if (!entry) {
return nullptr;
}
if (!entry->mListenerManager) {
entry->mListenerManager = new EventListenerManager(aNode);
@@ -4001,34 +3999,32 @@ nsContentUtils::GetExistingListenerManag
// We're already shut down, don't bother creating an event listener
// manager.
return nullptr;
}
EventListenerManagerMapEntry *entry =
static_cast<EventListenerManagerMapEntry *>
- (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sEventListenerManagersHash, aNode));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
return entry->mListenerManager;
}
return nullptr;
}
/* static */
void
nsContentUtils::RemoveListenerManager(nsINode *aNode)
{
if (sEventListenerManagersHash.ops) {
EventListenerManagerMapEntry *entry =
static_cast<EventListenerManagerMapEntry *>
- (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sEventListenerManagersHash, aNode));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
nsRefPtr<EventListenerManager> listenerManager;
listenerManager.swap(entry->mListenerManager);
// Remove the entry and *then* do operations that could cause further
// modification of sEventListenerManagersHash. See bug 334177.
PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
if (listenerManager) {
listenerManager->Disconnect();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3277,16 +3277,25 @@ nsDocument::GetUndoManager()
if (!mUndoManager) {
mUndoManager = new UndoManager(rootElement);
}
nsRefPtr<UndoManager> undoManager = mUndoManager;
return undoManager.forget();
}
+bool
+nsDocument::IsWebAnimationsEnabled(JSContext* /*unused*/, JSObject* /*unused*/)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ return nsContentUtils::IsCallerChrome() ||
+ Preferences::GetBool("dom.animations-api.core.enabled");
+}
+
AnimationTimeline*
nsDocument::Timeline()
{
if (!mAnimationTimeline) {
mAnimationTimeline = new AnimationTimeline(this);
}
return mAnimationTimeline;
@@ -3946,18 +3955,17 @@ nsDocument::SetSubDocumentFor(Element* a
NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
if (!aSubDoc) {
// aSubDoc is nullptr, remove the mapping
if (mSubDocuments) {
SubDocMapEntry *entry =
static_cast<SubDocMapEntry*>
- (PL_DHashTableOperate(mSubDocuments, aElement,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mSubDocuments, aElement));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
PL_DHashTableRawRemove(mSubDocuments, entry);
}
}
} else {
if (!mSubDocuments) {
// Create a new hashtable
@@ -3979,18 +3987,17 @@ nsDocument::SetSubDocumentFor(Element* a
if (!mSubDocuments) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
// Add a mapping to the hash table
SubDocMapEntry *entry =
static_cast<SubDocMapEntry*>
- (PL_DHashTableOperate(mSubDocuments, aElement,
- PL_DHASH_ADD));
+ (PL_DHashTableAdd(mSubDocuments, aElement));
if (!entry) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (entry->mSubDocument) {
entry->mSubDocument->SetParentDocument(nullptr);
@@ -4008,18 +4015,17 @@ nsDocument::SetSubDocumentFor(Element* a
}
nsIDocument*
nsDocument::GetSubDocumentFor(nsIContent *aContent) const
{
if (mSubDocuments && aContent->IsElement()) {
SubDocMapEntry *entry =
static_cast<SubDocMapEntry*>
- (PL_DHashTableOperate(mSubDocuments, aContent->AsElement(),
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mSubDocuments, aContent->AsElement()));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
return entry->mSubDocument;
}
}
return nullptr;
}
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -777,16 +777,17 @@ public:
nsViewManager* aViewManager,
nsStyleSet* aStyleSet) MOZ_OVERRIDE;
virtual void DeleteShell() MOZ_OVERRIDE;
virtual nsresult GetAllowPlugins(bool* aAllowPlugins) MOZ_OVERRIDE;
virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager() MOZ_OVERRIDE;
+ static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
virtual mozilla::dom::AnimationTimeline* Timeline() MOZ_OVERRIDE;
virtual nsresult SetSubDocumentFor(Element* aContent,
nsIDocument* aSubDoc) MOZ_OVERRIDE;
virtual nsIDocument* GetSubDocumentFor(nsIContent* aContent) const MOZ_OVERRIDE;
virtual Element* FindContentForSubDocument(nsIDocument *aDocument) const MOZ_OVERRIDE;
virtual Element* GetRootElementInternal() const MOZ_OVERRIDE;
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -90,18 +90,17 @@ nsPropertyTable::DeleteAllPropertiesFor(
nsresult
nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
nsPropertyTable *aOtherTable)
{
nsresult rv = NS_OK;
for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
if (prop->mTransfer) {
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
- (PL_DHashTableOperate(&prop->mObjectValueMap, aObject,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&prop->mObjectValueMap, aObject));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
rv = aOtherTable->SetProperty(aObject, prop->mName,
entry->value, prop->mDtorFunc,
prop->mDtorData, prop->mTransfer);
if (NS_FAILED(rv)) {
DeleteAllPropertiesFor(aObject);
aOtherTable->DeleteAllPropertiesFor(aObject);
@@ -121,17 +120,17 @@ nsPropertyTable::TransferOrDeleteAllProp
void
nsPropertyTable::Enumerate(nsPropertyOwner aObject,
NSPropertyFunc aCallback, void *aData)
{
PropertyList* prop;
for (prop = mPropertyList; prop; prop = prop->mNext) {
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
- (PL_DHashTableOperate(&prop->mObjectValueMap, aObject, PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&prop->mObjectValueMap, aObject));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
aData);
}
}
}
struct PropertyEnumeratorData
@@ -169,18 +168,17 @@ nsPropertyTable::GetPropertyInternal(nsP
{
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
void *propValue = nullptr;
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
if (propertyList) {
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
- (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&propertyList->mObjectValueMap, aObject));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
propValue = entry->value;
if (aRemove) {
// don't call propertyList->mDtorFunc. That's the caller's job now.
PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
}
rv = NS_OK;
}
@@ -225,17 +223,17 @@ nsPropertyTable::SetPropertyInternal(nsP
propertyList->mNext = mPropertyList;
mPropertyList = propertyList;
}
// The current property value (if there is one) is replaced and the current
// value is destroyed
nsresult result = NS_OK;
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
- (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject, PL_DHASH_ADD));
+ (PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject));
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
// A nullptr entry->key is the sign that the entry has just been allocated
// for us. If it's non-nullptr then we have an existing entry.
if (entry->key) {
if (aOldValue)
*aOldValue = entry->value;
else if (propertyList->mDtorFunc)
@@ -324,17 +322,17 @@ nsPropertyTable::PropertyList::Destroy()
PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
nullptr);
}
bool
nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
{
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
- (PL_DHashTableOperate(&mObjectValueMap, aObject, PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&mObjectValueMap, aObject));
if (!PL_DHASH_ENTRY_IS_BUSY(entry))
return false;
void* value = entry->value;
PL_DHashTableRawRemove(&mObjectValueMap, entry);
if (mDtorFunc)
mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -139,47 +139,46 @@ nsScriptNameSpaceManager::~nsScriptNameS
}
nsGlobalNameStruct *
nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
const char16_t **aClassName)
{
GlobalNameMapEntry *entry =
static_cast<GlobalNameMapEntry *>
- (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
+ (PL_DHashTableAdd(aTable, aKey));
if (!entry) {
return nullptr;
}
if (aClassName) {
*aClassName = entry->mKey.get();
}
return &entry->mGlobalName;
}
void
nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable,
const nsAString *aKey)
{
- PL_DHashTableOperate(aTable, aKey, PL_DHASH_REMOVE);
+ PL_DHashTableRemove(aTable, aKey);
}
nsGlobalNameStruct*
nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
{
NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
"This function only works on constructor aliases!");
if (!aStruct->mAlias->mProto) {
GlobalNameMapEntry *proto =
static_cast<GlobalNameMapEntry *>
- (PL_DHashTableOperate(&mGlobalNames,
- &aStruct->mAlias->mProtoName,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&mGlobalNames,
+ &aStruct->mAlias->mProtoName));
if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
aStruct->mAlias->mProto = &proto->mGlobalName;
}
}
return aStruct->mAlias->mProto;
}
@@ -384,18 +383,17 @@ nsScriptNameSpaceManager::Init()
}
nsGlobalNameStruct*
nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
const char16_t **aClassName)
{
GlobalNameMapEntry *entry =
static_cast<GlobalNameMapEntry *>
- (PL_DHashTableOperate(&mGlobalNames, &aName,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&mGlobalNames, &aName));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
if (aClassName) {
*aClassName = entry->mKey.get();
}
return &entry->mGlobalName;
}
@@ -405,18 +403,17 @@ nsScriptNameSpaceManager::LookupNameInte
return nullptr;
}
const nsGlobalNameStruct*
nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName)
{
GlobalNameMapEntry *entry =
static_cast<GlobalNameMapEntry *>
- (PL_DHashTableOperate(&mNavigatorNames, &aName,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&mNavigatorNames, &aName));
if (!PL_DHASH_ENTRY_IS_BUSY(entry)) {
return nullptr;
}
return &entry->mGlobalName;
}
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -89,17 +89,17 @@ function BrowserElementChild() {
// true.
this._forcedVisible = true;
this._ownerVisible = true;
this._nextPaintHandler = null;
this._isContentWindowCreated = false;
this._pendingSetInputMethodActive = [];
- this._forceDispatchSelectionStateChanged = false;
+ this._selectionStateChangedTarget = null;
this._init();
};
BrowserElementChild.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
@@ -595,17 +595,17 @@ BrowserElementChild.prototype = {
_selectionStateChangedHandler: function(e) {
e.stopPropagation();
let boundingClientRect = e.boundingClientRect;
let isCollapsed = (e.selectedText.length == 0);
let isMouseUp = (e.states.indexOf('mouseup') == 0);
let canPaste = this._isCommandEnabled("paste");
- if (!this._forceDispatchSelectionStateChanged) {
+ if (this._selectionStateChangedTarget != e.target) {
// SelectionStateChanged events with the following states are not
// necessary to trigger the text dialog, bypass these events
// by default.
//
if(e.states.length == 0 ||
e.states.indexOf('drag') == 0 ||
e.states.indexOf('keypress') == 0 ||
e.states.indexOf('mousedown') == 0) {
@@ -619,24 +619,25 @@ BrowserElementChild.prototype = {
if (isMouseUp && canPaste) {
//Dispatch this selection change event to support shortcut mode
} else {
return;
}
}
}
- // If we select something and selection range is visible, we set the
- // forceDispatchSelectionStateChanged flag as true to dispatch the
- // next SelectionStateChange event so that the parent side can
- // hide the text dialog.
+ // If we select something and selection range is visible, we cache current
+ // event's target to selectionStateChangedTarget.
+ // And dispatch the next SelectionStateChagne event if target is matched, so
+ // that the parent side can hide the text dialog.
+ // We clear selectionStateChangedTarget if selection carets are invisible.
if (e.visible && !isCollapsed) {
- this._forceDispatchSelectionStateChanged = true;
+ this._selectionStateChangedTarget = e.target;
} else {
- this._forceDispatchSelectionStateChanged = false;
+ this._selectionStateChangedTarget = null;
}
let zoomFactor = content.screen.width / content.innerWidth;
let detail = {
rect: {
width: boundingClientRect ? boundingClientRect.width : 0,
height: boundingClientRect ? boundingClientRect.height : 0,
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -28,18 +28,18 @@ WebGLContext::GetExtensionString(WebGLEx
#define WEBGL_EXTENSION_IDENTIFIER(x) \
sExtensionNamesEnumeratedArray[WebGLExtensionID::x] = #x;
WEBGL_EXTENSION_IDENTIFIER(ANGLE_instanced_arrays)
WEBGL_EXTENSION_IDENTIFIER(EXT_blend_minmax)
WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_half_float)
WEBGL_EXTENSION_IDENTIFIER(EXT_frag_depth)
+ WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod)
WEBGL_EXTENSION_IDENTIFIER(EXT_sRGB)
- WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod)
WEBGL_EXTENSION_IDENTIFIER(EXT_texture_filter_anisotropic)
WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint)
WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
@@ -90,99 +90,107 @@ bool WebGLContext::IsExtensionSupported(
// For warnings-as-errors.
break;
}
}
return IsExtensionSupported(ext);
}
-bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
+bool
+WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
if (mDisableExtensions)
return false;
+ // In alphabetical order
switch (ext) {
- case WebGLExtensionID::OES_vertex_array_object:
- case WebGLExtensionID::WEBGL_lose_context:
- // Always supported.
- return true;
+ // ANGLE_
+ case WebGLExtensionID::ANGLE_instanced_arrays:
+ return WebGLExtensionInstancedArrays::IsSupported(this);
+ // EXT_
case WebGLExtensionID::EXT_blend_minmax:
return WebGLExtensionBlendMinMax::IsSupported(this);
+ case WebGLExtensionID::EXT_color_buffer_half_float:
+ return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
+ case WebGLExtensionID::EXT_frag_depth:
+ return WebGLExtensionFragDepth::IsSupported(this);
+ case WebGLExtensionID::EXT_shader_texture_lod:
+ return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
+ case WebGLExtensionID::EXT_sRGB:
+ return WebGLExtensionSRGB::IsSupported(this);
+ case WebGLExtensionID::EXT_texture_filter_anisotropic:
+ return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
+
+ // OES_
case WebGLExtensionID::OES_element_index_uint:
return gl->IsSupported(gl::GLFeature::element_index_uint);
case WebGLExtensionID::OES_standard_derivatives:
return gl->IsSupported(gl::GLFeature::standard_derivatives);
-
case WebGLExtensionID::OES_texture_float:
return gl->IsSupported(gl::GLFeature::texture_float);
case WebGLExtensionID::OES_texture_float_linear:
return gl->IsSupported(gl::GLFeature::texture_float_linear);
case WebGLExtensionID::OES_texture_half_float:
// If we have Feature::texture_half_float, we must not be on ES2
// and need to translate HALF_FLOAT_OES -> HALF_FLOAT. We do that
// right before making the relevant calls.
return gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float) ||
gl->IsSupported(gl::GLFeature::texture_half_float);
case WebGLExtensionID::OES_texture_half_float_linear:
return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
- case WebGLExtensionID::EXT_texture_filter_anisotropic:
- return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
+ case WebGLExtensionID::OES_vertex_array_object:
+ return true;
+
+ // WEBGL_
+ case WebGLExtensionID::WEBGL_color_buffer_float:
+ return WebGLExtensionColorBufferFloat::IsSupported(this);
+ case WebGLExtensionID::WEBGL_compressed_texture_atc:
+ return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
+ case WebGLExtensionID::WEBGL_compressed_texture_etc1:
+ return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
+ case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
+ return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
return true;
return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);
-
- case WebGLExtensionID::WEBGL_compressed_texture_atc:
- return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
- case WebGLExtensionID::WEBGL_compressed_texture_etc1:
- return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
- case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
- return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
case WebGLExtensionID::WEBGL_depth_texture:
// WEBGL_depth_texture supports DEPTH_STENCIL textures
if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
return false;
return gl->IsSupported(gl::GLFeature::depth_texture) ||
gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
-
- case WebGLExtensionID::ANGLE_instanced_arrays:
- return WebGLExtensionInstancedArrays::IsSupported(this);
- case WebGLExtensionID::EXT_sRGB:
- return WebGLExtensionSRGB::IsSupported(this);
case WebGLExtensionID::WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
- case WebGLExtensionID::EXT_frag_depth:
- return WebGLExtensionFragDepth::IsSupported(this);
- case WebGLExtensionID::EXT_shader_texture_lod:
- return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
+ case WebGLExtensionID::WEBGL_lose_context:
+ // We always support this extension.
+ return true;
default:
// For warnings-as-errors.
break;
}
if (Preferences::GetBool("webgl.enable-draft-extensions", false) ||
IsWebGL2())
{
+ /* None for now.
switch (ext) {
- case WebGLExtensionID::EXT_color_buffer_half_float:
- return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
- case WebGLExtensionID::WEBGL_color_buffer_float:
- return WebGLExtensionColorBufferFloat::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
+ */
}
return false;
}
static bool
CompareWebGLExtensionName(const nsACString& name, const char* other)
{
@@ -287,91 +295,98 @@ WebGLContext::GetExtension(JSContext* cx
void
WebGLContext::EnableExtension(WebGLExtensionID ext)
{
MOZ_ASSERT(IsExtensionEnabled(ext) == false);
WebGLExtensionBase* obj = nullptr;
switch (ext) {
+ // ANGLE_
+ case WebGLExtensionID::ANGLE_instanced_arrays:
+ obj = new WebGLExtensionInstancedArrays(this);
+ break;
+
+ // EXT_
+ case WebGLExtensionID::EXT_blend_minmax:
+ obj = new WebGLExtensionBlendMinMax(this);
+ break;
+ case WebGLExtensionID::EXT_color_buffer_half_float:
+ obj = new WebGLExtensionColorBufferHalfFloat(this);
+ break;
+ case WebGLExtensionID::EXT_frag_depth:
+ obj = new WebGLExtensionFragDepth(this);
+ break;
+ case WebGLExtensionID::EXT_shader_texture_lod:
+ obj = new WebGLExtensionShaderTextureLod(this);
+ break;
+ case WebGLExtensionID::EXT_sRGB:
+ obj = new WebGLExtensionSRGB(this);
+ break;
+ case WebGLExtensionID::EXT_texture_filter_anisotropic:
+ obj = new WebGLExtensionTextureFilterAnisotropic(this);
+ break;
+
+ // OES_
case WebGLExtensionID::OES_element_index_uint:
obj = new WebGLExtensionElementIndexUint(this);
break;
case WebGLExtensionID::OES_standard_derivatives:
obj = new WebGLExtensionStandardDerivatives(this);
break;
- case WebGLExtensionID::EXT_texture_filter_anisotropic:
- obj = new WebGLExtensionTextureFilterAnisotropic(this);
- break;
- case WebGLExtensionID::WEBGL_lose_context:
- obj = new WebGLExtensionLoseContext(this);
- break;
- case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
- obj = new WebGLExtensionCompressedTextureS3TC(this);
- break;
- case WebGLExtensionID::WEBGL_compressed_texture_atc:
- obj = new WebGLExtensionCompressedTextureATC(this);
- break;
- case WebGLExtensionID::WEBGL_compressed_texture_etc1:
- obj = new WebGLExtensionCompressedTextureETC1(this);
- break;
- case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
- obj = new WebGLExtensionCompressedTexturePVRTC(this);
- break;
- case WebGLExtensionID::WEBGL_debug_renderer_info:
- obj = new WebGLExtensionDebugRendererInfo(this);
- break;
- case WebGLExtensionID::WEBGL_debug_shaders:
- obj = new WebGLExtensionDebugShaders(this);
- break;
- case WebGLExtensionID::WEBGL_depth_texture:
- obj = new WebGLExtensionDepthTexture(this);
- break;
case WebGLExtensionID::OES_texture_float:
obj = new WebGLExtensionTextureFloat(this);
break;
case WebGLExtensionID::OES_texture_float_linear:
obj = new WebGLExtensionTextureFloatLinear(this);
break;
case WebGLExtensionID::OES_texture_half_float:
obj = new WebGLExtensionTextureHalfFloat(this);
break;
case WebGLExtensionID::OES_texture_half_float_linear:
obj = new WebGLExtensionTextureHalfFloatLinear(this);
break;
+ case WebGLExtensionID::OES_vertex_array_object:
+ obj = new WebGLExtensionVertexArray(this);
+ break;
+
+ // WEBGL_
case WebGLExtensionID::WEBGL_color_buffer_float:
obj = new WebGLExtensionColorBufferFloat(this);
break;
- case WebGLExtensionID::EXT_color_buffer_half_float:
- obj = new WebGLExtensionColorBufferHalfFloat(this);
+ case WebGLExtensionID::WEBGL_compressed_texture_atc:
+ obj = new WebGLExtensionCompressedTextureATC(this);
+ break;
+ case WebGLExtensionID::WEBGL_compressed_texture_etc1:
+ obj = new WebGLExtensionCompressedTextureETC1(this);
+ break;
+ case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
+ obj = new WebGLExtensionCompressedTexturePVRTC(this);
+ break;
+ case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
+ obj = new WebGLExtensionCompressedTextureS3TC(this);
+ break;
+ case WebGLExtensionID::WEBGL_debug_renderer_info:
+ obj = new WebGLExtensionDebugRendererInfo(this);
+ break;
+ case WebGLExtensionID::WEBGL_debug_shaders:
+ obj = new WebGLExtensionDebugShaders(this);
+ break;
+ case WebGLExtensionID::WEBGL_depth_texture:
+ obj = new WebGLExtensionDepthTexture(this);
break;
case WebGLExtensionID::WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this);
break;
- case WebGLExtensionID::OES_vertex_array_object:
- obj = new WebGLExtensionVertexArray(this);
- break;
- case WebGLExtensionID::ANGLE_instanced_arrays:
- obj = new WebGLExtensionInstancedArrays(this);
- break;
- case WebGLExtensionID::EXT_sRGB:
- obj = new WebGLExtensionSRGB(this);
+ case WebGLExtensionID::WEBGL_lose_context:
+ obj = new WebGLExtensionLoseContext(this);
break;
- case WebGLExtensionID::EXT_frag_depth:
- obj = new WebGLExtensionFragDepth(this);
- break;
- case WebGLExtensionID::EXT_blend_minmax:
- obj = new WebGLExtensionBlendMinMax(this);
- break;
- case WebGLExtensionID::EXT_shader_texture_lod:
- obj = new WebGLExtensionShaderTextureLod(this);
- break;
+
default:
MOZ_ASSERT(false, "should not get there.");
- break;
}
mExtensions[ext] = obj;
}
void
WebGLContext::GetSupportedExtensions(JSContext* cx,
Nullable< nsTArray<nsString> >& retval)
--- a/dom/canvas/test/_webgl-conformance.ini
+++ b/dom/canvas/test/_webgl-conformance.ini
@@ -494,17 +494,16 @@ support-files = webgl-conformance/../web
[webgl-conformance/_wrappers/test_conformance__buffers__buffer-bind-test.html]
[webgl-conformance/_wrappers/test_conformance__buffers__buffer-data-array-buffer.html]
[webgl-conformance/_wrappers/test_conformance__buffers__index-validation-copies-indices.html]
[webgl-conformance/_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html]
[webgl-conformance/_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html]
[webgl-conformance/_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html]
[webgl-conformance/_wrappers/test_conformance__buffers__index-validation.html]
[webgl-conformance/_wrappers/test_conformance__canvas__buffer-offscreen-test.html]
-skip-if = os == 'android' # Bug 1102402 - It fails intermittently and causes a lot of retried jobs
[webgl-conformance/_wrappers/test_conformance__canvas__buffer-preserve-test.html]
[webgl-conformance/_wrappers/test_conformance__canvas__canvas-test.html]
[webgl-conformance/_wrappers/test_conformance__canvas__canvas-zero-size.html]
[webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
skip-if = os == 'mac'
[webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html]
[webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html]
[webgl-conformance/_wrappers/test_conformance__context__constants.html]
@@ -515,16 +514,17 @@ skip-if = (os == 'b2g')
[webgl-conformance/_wrappers/test_conformance__context__context-type-test.html]
[webgl-conformance/_wrappers/test_conformance__context__incorrect-context-object-behaviour.html]
[webgl-conformance/_wrappers/test_conformance__context__methods.html]
[webgl-conformance/_wrappers/test_conformance__context__premultiplyalpha-test.html]
[webgl-conformance/_wrappers/test_conformance__context__resource-sharing-test.html]
[webgl-conformance/_wrappers/test_conformance__extensions__oes-standard-derivatives.html]
[webgl-conformance/_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html]
[webgl-conformance/_wrappers/test_conformance__extensions__oes-texture-float.html]
+fail-if = (os == 'linux')
[webgl-conformance/_wrappers/test_conformance__extensions__oes-vertex-array-object.html]
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html]
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-debug-shaders.html]
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html]
[webgl-conformance/_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
[webgl-conformance/_wrappers/test_conformance__extensions__ext-sRGB.html]
[webgl-conformance/_wrappers/test_conformance__extensions__ext-shader-texture-lod.html]
[webgl-conformance/_wrappers/test_conformance__glsl__functions__glsl-function.html]
@@ -763,17 +763,17 @@ skip-if = (os == 'android') || (os == 'b
[webgl-conformance/_wrappers/test_conformance__textures__tex-sub-image-2d.html]
[webgl-conformance/_wrappers/test_conformance__textures__texparameter-test.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind-2.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-active-bind.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-complete.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html]
-skip-if = os == 'win' || buildapp == 'mulet' # Mulet - bug 1089453 (crashes in libLLVM-3.0.so)
+skip-if = os == 'win'
[webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-size.html]
skip-if = os == 'android'
[webgl-conformance/_wrappers/test_conformance__textures__texture-size-cube-maps.html]
skip-if = os == 'android'
[webgl-conformance/_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html]
[webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-crash.html]
[webgl-conformance/_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html]
--- a/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py
+++ b/dom/canvas/test/webgl-conformance/generate-wrappers-and-manifest.py
@@ -26,16 +26,17 @@ EXTRA_SUPPORT_FILES = [
'always-fail.html',
'iframe-autoresize.js',
'mochi-single.html',
'../webgl-mochitest/driver-info.js',
]
ACCEPTABLE_ERRATA_KEYS = set([
'skip-if',
+ 'fail-if',
])
GENERATED_HEADER = '''
# This is a GENERATED FILE. Do not edit it directly.
# Regenerated it by using `python generate-wrapper-and-manifest.py`.
# Mark skipped tests in mochitest-errata.ini.
# Mark failing tests in mochi-single.html.
'''.strip()
--- a/dom/canvas/test/webgl-conformance/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conformance/mochitest-errata.ini
@@ -73,16 +73,22 @@ skip-if = os == 'android'
[_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html]
# Asserts on 'B2G ICS Emulator Debug'.
skip-if = (os == 'b2g')
[_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html]
# Intermittently asserts on 'B2G ICS Emulator Debug'.
skip-if = (os == 'b2g')
########################################################################
+# Linux
+[_wrappers/test_conformance__extensions__oes-texture-float.html]
+# Failures after enabling color_buffer_[half_]float.
+fail-if = (os == 'linux')
+
+########################################################################
# Mac
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
# Intermittent crash on OSX.
skip-if = os == 'mac'
########################################################################
# Win
[_wrappers/test_conformance__textures__texture-npot-video.html]
--- a/dom/fmradio/FMRadioService.cpp
+++ b/dom/fmradio/FMRadioService.cpp
@@ -15,16 +15,17 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/FMRadioChild.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIObserverService.h"
#include "nsISettingsService.h"
#include "nsJSUtils.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
+#include "mozilla/DebugOnly.h"
#define TUNE_THREAD_TIMEOUT_MS 5000
#define BAND_87500_108000_kHz 1
#define BAND_76000_108000_kHz 2
#define BAND_76000_90000_kHz 3
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
@@ -775,17 +776,17 @@ FMRadioService::CancelSeek(FMRadioReplyR
NS_DispatchToMainThread(aReplyRunnable);
}
void
FMRadioService::SetRDSGroupMask(uint32_t aRDSGroupMask)
{
mRDSGroupMask = aRDSGroupMask;
if (IsFMRadioOn() && mRDSEnabled) {
- bool enabled = hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS);
+ DebugOnly<bool> enabled = hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS);
MOZ_ASSERT(enabled);
}
}
void
FMRadioService::EnableRDS(FMRadioReplyRunnable* aReplyRunnable)
{
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
--- a/dom/icc/Icc.cpp
+++ b/dom/icc/Icc.cpp
@@ -30,19 +30,19 @@ IsPukCardLockType(IccLockType aLockType)
case IccLockType::Nck1Puk:
case IccLockType::Nck2Puk:
case IccLockType::HnckPuk:
case IccLockType::CckPuk:
case IccLockType::SpckPuk:
case IccLockType::RcckPuk:
case IccLockType::RspckPuk:
return true;
+ default:
+ return false;
}
-
- return false;
}
} // anonymous namespace
NS_IMPL_CYCLE_COLLECTION_INHERITED(Icc, DOMEventTargetHelper, mIccInfo)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Icc)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -60,16 +60,19 @@ public:
// Called by the decode thread to keep track of the number of bytes read
// from the resource.
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) = 0;
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) = 0;
+ // For decoders with a notion of timestamp offset, returns the value in microseconds.
+ virtual int64_t GetTimestampOffset() const { return 0; }
+
// Return the duration of the media in microseconds.
virtual int64_t GetMediaDuration() = 0;
// Set the duration of the media in microseconds.
virtual void SetMediaDuration(int64_t aDuration) = 0;
// Sets the duration of the media in microseconds. The MediaDecoder
// fires a durationchange event to its owner (e.g., an HTML audio
--- a/dom/media/encoder/OmxTrackEncoder.cpp
+++ b/dom/media/encoder/OmxTrackEncoder.cpp
@@ -21,16 +21,23 @@
using namespace android;
namespace mozilla {
#define ENCODER_CONFIG_FRAME_RATE 30 // fps
#define GET_ENCODED_VIDEO_FRAME_TIMEOUT 100000 // microseconds
+OmxVideoTrackEncoder::OmxVideoTrackEncoder()
+ : VideoTrackEncoder()
+{}
+
+OmxVideoTrackEncoder::~OmxVideoTrackEncoder()
+{}
+
nsresult
OmxVideoTrackEncoder::Init(int aWidth, int aHeight, int aDisplayWidth,
int aDisplayHeight, TrackRate aTrackRate)
{
mFrameWidth = aWidth;
mFrameHeight = aHeight;
mTrackRate = aTrackRate;
mDisplayWidth = aDisplayWidth;
@@ -157,16 +164,23 @@ OmxVideoTrackEncoder::GetEncodedTrack(En
if (outFlags & OMXCodecWrapper::BUFFER_EOS) {
mEncodingComplete = true;
OMX_LOG("Done encoding video.");
}
return NS_OK;
}
+OmxAudioTrackEncoder::OmxAudioTrackEncoder()
+ : AudioTrackEncoder()
+{}
+
+OmxAudioTrackEncoder::~OmxAudioTrackEncoder()
+{}
+
nsresult
OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
{
nsTArray<uint8_t> frameData;
int outFlags = 0;
int64_t outTimeUs = -1;
nsresult rv = mEncoder->GetNextEncodedFrame(&frameData, &outTimeUs, &outFlags,
--- a/dom/media/encoder/OmxTrackEncoder.h
+++ b/dom/media/encoder/OmxTrackEncoder.h
@@ -21,19 +21,18 @@ class OMXAudioEncoder;
* Bean platform.
*/
namespace mozilla {
class OmxVideoTrackEncoder: public VideoTrackEncoder
{
public:
- OmxVideoTrackEncoder()
- : VideoTrackEncoder()
- {}
+ OmxVideoTrackEncoder();
+ ~OmxVideoTrackEncoder();
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
protected:
nsresult Init(int aWidth, int aHeight,
int aDisplayWidth, int aDisplayHeight,
@@ -41,19 +40,18 @@ protected:
private:
nsAutoPtr<android::OMXVideoEncoder> mEncoder;
};
class OmxAudioTrackEncoder : public AudioTrackEncoder
{
public:
- OmxAudioTrackEncoder()
- : AudioTrackEncoder()
- {}
+ OmxAudioTrackEncoder();
+ ~OmxAudioTrackEncoder();
already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
protected:
nsresult Init(int aChannels, int aSamplingRate) = 0;
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -152,17 +152,17 @@ MP4Reader::InitLayersBackendType()
static bool sIsEMEEnabled = false;
nsresult
MP4Reader::Init(MediaDecoderReader* aCloneDonor)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
PlatformDecoderModule::Init();
- mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource(), &mDemuxerMonitor), &mDemuxerMonitor);
+ mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource(), &mDemuxerMonitor), GetDecoder()->GetTimestampOffset(), &mDemuxerMonitor);
InitLayersBackendType();
mAudio.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
mVideo.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -33,17 +33,17 @@ public:
virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE {}
virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE {}
virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
MOZ_OVERRIDE
{
return NS_OK;
}
virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
- uint32_t* aBytes);
+ uint32_t* aBytes) MOZ_OVERRIDE;
virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE
{
return NS_OK;
}
virtual int64_t Tell() MOZ_OVERRIDE { return 0; }
virtual void Pin() MOZ_OVERRIDE {}
virtual void Unpin() MOZ_OVERRIDE {}
virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { return 0; }
@@ -52,17 +52,17 @@ public:
virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE;
virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE
{
return false;
}
virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; }
virtual bool IsSuspended() MOZ_OVERRIDE { return false; }
virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
- uint32_t aCount)
+ uint32_t aCount) MOZ_OVERRIDE
{
return NS_OK;
}
virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE;
virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
MOZ_OVERRIDE;
virtual const nsCString& GetContentType() const MOZ_OVERRIDE
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -19,17 +19,17 @@ public:
nsRefPtr<MockMediaResource> resource;
Monitor mMonitor;
nsAutoPtr<MP4Demuxer> demuxer;
explicit MP4DemuxerBinding(const char* aFileName = "dash_dashinit.mp4")
: resource(new MockMediaResource(aFileName))
, mMonitor("TestMP4Demuxer monitor")
- , demuxer(new MP4Demuxer(new MP4Stream(resource, &mMonitor), &mMonitor))
+ , demuxer(new MP4Demuxer(new MP4Stream(resource, &mMonitor), 0, &mMonitor))
{
EXPECT_EQ(NS_OK, resource->Open(nullptr));
}
private:
virtual ~MP4DemuxerBinding()
{
}
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -232,29 +232,33 @@ public:
return false;
}
uint32_t chunk_size = BigEndian::readUint32(aData);
if (chunk_size < 8) {
return false;
}
- return aData[4] == 'm' && aData[5] == 'o' && aData[6] == 'o' &&
- aData[7] == 'f';
+ return (aData[4] == 'm' && aData[5] == 'o' && aData[6] == 'o' && aData[7] == 'f') ||
+ (aData[4] == 's' && aData[5] == 't' && aData[6] == 'y' && aData[7] == 'p');
}
bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
int64_t& aStart, int64_t& aEnd)
{
MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
// but mParser requires us to hold a monitor.
bool initSegment = IsInitSegmentPresent(aData, aLength);
if (initSegment) {
mStream = new mp4_demuxer::BufferStream();
- mParser = new mp4_demuxer::MoofParser(mStream, 0, &mMonitor);
+ // We use a timestampOffset of 0 for ContainerParser, and require
+ // consumers of ParseStartAndEndTimestamps to add their timestamp offset
+ // manually. This allows the ContainerParser to be shared across different
+ // timestampOffsets.
+ mParser = new mp4_demuxer::MoofParser(mStream, 0, 0, &mMonitor);
} else if (!mStream || !mParser) {
return false;
}
mStream->AppendBytes(aData, aLength);
nsTArray<MediaByteRange> byteRanges;
byteRanges.AppendElement(mStream->GetByteRange());
mParser->RebuildFragmentedIndex(byteRanges);
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -124,20 +124,20 @@ MediaSourceDecoder::AttachMediaSource(do
void
MediaSourceDecoder::DetachMediaSource()
{
MOZ_ASSERT(mMediaSource && NS_IsMainThread());
mMediaSource = nullptr;
}
already_AddRefed<SourceBufferDecoder>
-MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
+MediaSourceDecoder::CreateSubDecoder(const nsACString& aType, int64_t aTimestampOffset)
{
MOZ_ASSERT(mReader);
- return mReader->CreateSubDecoder(aType);
+ return mReader->CreateSubDecoder(aType, aTimestampOffset);
}
void
MediaSourceDecoder::AddTrackBuffer(TrackBuffer* aTrackBuffer)
{
MOZ_ASSERT(mReader);
mReader->AddTrackBuffer(aTrackBuffer);
}
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -41,17 +41,18 @@ public:
virtual void Shutdown() MOZ_OVERRIDE;
static already_AddRefed<MediaResource> CreateResource(nsIPrincipal* aPrincipal = nullptr);
void AttachMediaSource(dom::MediaSource* aMediaSource);
void DetachMediaSource();
- already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
+ already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType,
+ int64_t aTimestampOffset /* microseconds */);
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
void Ended();
bool IsExpectingMoreData() MOZ_OVERRIDE;
void SetDecodedDuration(int64_t aDuration);
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -452,24 +452,24 @@ CreateReaderForType(const nsACString& aT
MP4Decoder::IsEnabled()) {
return new MP4Reader(aDecoder);
}
#endif
return DecoderTraits::CreateReader(aType, aDecoder);
}
already_AddRefed<SourceBufferDecoder>
-MediaSourceReader::CreateSubDecoder(const nsACString& aType)
+MediaSourceReader::CreateSubDecoder(const nsACString& aType, int64_t aTimestampOffset)
{
if (IsShutdown()) {
return nullptr;
}
MOZ_ASSERT(GetTaskQueue());
nsRefPtr<SourceBufferDecoder> decoder =
- new SourceBufferDecoder(new SourceBufferResource(aType), mDecoder);
+ new SourceBufferDecoder(new SourceBufferResource(aType), mDecoder, aTimestampOffset);
nsRefPtr<MediaDecoderReader> reader(CreateReaderForType(aType, decoder));
if (!reader) {
return nullptr;
}
// MSE uses a start time of 0 everywhere. Set that immediately on the
// subreader to make sure that it's always in a state where we can invoke
// GetBuffered on it.
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -94,17 +94,18 @@ public:
void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE;
nsRefPtr<SeekPromise>
Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
// Acquires the decoder monitor, and is thus callable on any thread.
nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
- already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
+ already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType,
+ int64_t aTimestampOffset /* microseconds */);
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual void BreakCycles();
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -330,17 +330,19 @@ void
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
{
MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
if (!PrepareAppend(aRv)) {
return;
}
StartUpdating();
- if (!mTrackBuffer->AppendData(aData, aLength)) {
+ MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
+ "We don't handle timestampOffset for sequence mode yet");
+ if (!mTrackBuffer->AppendData(aData, aLength, mTimestampOffset * USECS_PER_S)) {
Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
ErrorResult dummy;
mMediaSource->EndOfStream(decodeError, dummy);
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (mTrackBuffer->HasInitSegment()) {
--- a/dom/media/mediasource/SourceBufferDecoder.cpp
+++ b/dom/media/mediasource/SourceBufferDecoder.cpp
@@ -28,20 +28,22 @@ namespace layers {
class ImageContainer;
} // namespace layers
NS_IMPL_ISUPPORTS0(SourceBufferDecoder)
SourceBufferDecoder::SourceBufferDecoder(MediaResource* aResource,
- AbstractMediaDecoder* aParentDecoder)
+ AbstractMediaDecoder* aParentDecoder,
+ int64_t aTimestampOffset)
: mResource(aResource)
, mParentDecoder(aParentDecoder)
, mReader(nullptr)
+ , mTimestampOffset(aTimestampOffset)
, mMediaDuration(-1)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(SourceBufferDecoder);
}
SourceBufferDecoder::~SourceBufferDecoder()
{
--- a/dom/media/mediasource/SourceBufferDecoder.h
+++ b/dom/media/mediasource/SourceBufferDecoder.h
@@ -27,25 +27,27 @@ class TimeRanges;
} // namespace dom
class SourceBufferDecoder MOZ_FINAL : public AbstractMediaDecoder
{
public:
// This class holds a weak pointer to MediaResource. It's the responsibility
// of the caller to manage the memory of the MediaResource object.
- SourceBufferDecoder(MediaResource* aResource, AbstractMediaDecoder* aParentDecoder);
+ SourceBufferDecoder(MediaResource* aResource, AbstractMediaDecoder* aParentDecoder,
+ int64_t aTimestampOffset /* microseconds */);
NS_DECL_THREADSAFE_ISUPPORTS
virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE;
virtual bool IsShutdown() const MOZ_FINAL MOZ_OVERRIDE;
virtual bool IsTransportSeekable() MOZ_FINAL MOZ_OVERRIDE;
virtual bool OnDecodeThread() const MOZ_FINAL MOZ_OVERRIDE;
virtual bool OnStateMachineThread() const MOZ_FINAL MOZ_OVERRIDE;
+ virtual int64_t GetTimestampOffset() const MOZ_FINAL MOZ_OVERRIDE { return mTimestampOffset; }
virtual int64_t GetMediaDuration() MOZ_FINAL MOZ_OVERRIDE;
virtual layers::ImageContainer* GetImageContainer() MOZ_FINAL MOZ_OVERRIDE;
virtual MediaDecoderOwner* GetOwner() MOZ_FINAL MOZ_OVERRIDE;
virtual SourceBufferResource* GetResource() const MOZ_FINAL MOZ_OVERRIDE;
virtual ReentrantMonitor& GetReentrantMonitor() MOZ_FINAL MOZ_OVERRIDE;
virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE;
virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) MOZ_FINAL MOZ_OVERRIDE;
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo) MOZ_FINAL MOZ_OVERRIDE;
@@ -124,16 +126,17 @@ private:
// Our TrackBuffer's task queue, this is only non-null during initialization.
RefPtr<MediaTaskQueue> mTaskQueue;
nsRefPtr<MediaResource> mResource;
AbstractMediaDecoder* mParentDecoder;
nsRefPtr<MediaDecoderReader> mReader;
+ int64_t mTimestampOffset;
int64_t mMediaDuration;
#ifdef MOZ_EME
nsRefPtr<CDMProxy> mCDMProxy;
#endif
};
} // namespace mozilla
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -34,16 +34,17 @@ extern PRLogModuleInfo* GetMediaSourceAP
#endif
namespace mozilla {
TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType)
: mParentDecoder(aParentDecoder)
, mType(aType)
, mLastStartTimestamp(0)
+ , mLastTimestampOffset(0)
, mShutdown(false)
{
MOZ_COUNT_CTOR(TrackBuffer);
mParser = ContainerParser::CreateForMIMEType(aType);
mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
aParentDecoder->AddTrackBuffer(this);
mDecoderPerSegment = Preferences::GetBool("media.mediasource.decoder-per-segment", false);
MSE_DEBUG("TrackBuffer(%p) created for parent decoder %p", this, aParentDecoder);
@@ -80,19 +81,19 @@ public:
~DecodersToInitialize()
{
for (size_t i = 0; i < mDecoders.Length(); i++) {
mOwner->QueueInitializeDecoder(mDecoders[i]);
}
}
- bool NewDecoder()
+ bool NewDecoder(int64_t aTimestampOffset)
{
- nsRefPtr<SourceBufferDecoder> decoder = mOwner->NewDecoder();
+ nsRefPtr<SourceBufferDecoder> decoder = mOwner->NewDecoder(aTimestampOffset);
if (!decoder) {
return false;
}
mDecoders.AppendElement(decoder);
return true;
}
private:
@@ -133,43 +134,46 @@ TrackBuffer::ContinueShutdown()
mInitializedDecoders.Clear();
mParentDecoder = nullptr;
mShutdownPromise.Resolve(true, __func__);
}
bool
-TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
+TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength, int64_t aTimestampOffset)
{
MOZ_ASSERT(NS_IsMainThread());
DecodersToInitialize decoders(this);
// TODO: Run more of the buffer append algorithm asynchronously.
if (mParser->IsInitSegmentPresent(aData, aLength)) {
MSE_DEBUG("TrackBuffer(%p)::AppendData: New initialization segment.", this);
- if (!decoders.NewDecoder()) {
+ if (!decoders.NewDecoder(aTimestampOffset)) {
return false;
}
} else if (!mParser->HasInitData()) {
MSE_DEBUG("TrackBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
return false;
}
int64_t start, end;
if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
+ start += aTimestampOffset;
+ end += aTimestampOffset;
if (mParser->IsMediaSegmentPresent(aData, aLength) &&
mLastEndTimestamp &&
(!mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp.value()) ||
+ mLastTimestampOffset != aTimestampOffset ||
mDecoderPerSegment)) {
MSE_DEBUG("TrackBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
this, mLastStartTimestamp, mLastEndTimestamp.value(), start, end);
// This data is earlier in the timeline than data we have already
// processed, so we must create a new decoder to handle the decoding.
- if (!decoders.NewDecoder()) {
+ if (!decoders.NewDecoder(aTimestampOffset)) {
return false;
}
MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this);
const nsTArray<uint8_t>& initData = mParser->InitData();
AppendDataToCurrentResource(initData.Elements(), initData.Length());
mLastStartTimestamp = start;
} else {
MSE_DEBUG("TrackBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]",
@@ -326,33 +330,34 @@ TrackBuffer::Buffered(dom::TimeRanges* a
aRanges->Union(r, double(mParser->GetRoundingError()) / USECS_PER_S);
}
}
return highestEndTime;
}
already_AddRefed<SourceBufferDecoder>
-TrackBuffer::NewDecoder()
+TrackBuffer::NewDecoder(int64_t aTimestampOffset)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mParentDecoder);
DiscardDecoder();
- nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType);
+ nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType, aTimestampOffset);
if (!decoder) {
return nullptr;
}
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
mCurrentDecoder = decoder;
mDecoders.AppendElement(decoder);
mLastStartTimestamp = 0;
mLastEndTimestamp.reset();
+ mLastTimestampOffset = aTimestampOffset;
decoder->SetTaskQueue(mTaskQueue);
return decoder.forget();
}
bool
TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
{
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -34,17 +34,17 @@ public:
TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
nsRefPtr<ShutdownPromise> Shutdown();
// Append data to the current decoder. Also responsible for calling
// NotifyDataArrived on the decoder to keep buffered range computation up
// to date. Returns false if the append failed.
- bool AppendData(const uint8_t* aData, uint32_t aLength);
+ bool AppendData(const uint8_t* aData, uint32_t aLength, int64_t aTimestampOffset /* microseconds */);
bool EvictData(uint32_t aThreshold);
void EvictBefore(double aTime);
// Returns the highest end time of all of the buffered ranges in the
// decoders managed by this TrackBuffer, and returns the union of the
// decoders buffered ranges in aRanges. This may be called on any thread.
double Buffered(dom::TimeRanges* aRanges);
@@ -87,17 +87,17 @@ private:
friend class DecodersToInitialize;
~TrackBuffer();
// Create a new decoder, set mCurrentDecoder to the new decoder and
// returns it. The new decoder must be queued using QueueInitializeDecoder
// for initialization.
// The decoder is not considered initialized until it is added to
// mInitializedDecoders.
- already_AddRefed<SourceBufferDecoder> NewDecoder();
+ already_AddRefed<SourceBufferDecoder> NewDecoder(int64_t aTimestampOffset /* microseconds */);
// Helper for AppendData, ensures NotifyDataArrived is called whenever
// data is appended to the current decoder's SourceBufferResource.
bool AppendDataToCurrentResource(const uint8_t* aData, uint32_t aLength);
// Queue execution of InitializeDecoder on mTaskQueue.
bool QueueInitializeDecoder(SourceBufferDecoder* aDecoder);
@@ -151,16 +151,19 @@ private:
nsRefPtr<MediaSourceDecoder> mParentDecoder;
const nsCString mType;
// The last start and end timestamps added to the TrackBuffer via
// AppendData. Accessed on the main thread only.
int64_t mLastStartTimestamp;
Maybe<int64_t> mLastEndTimestamp;
+ // The timestamp offset used by our current decoder, in microseconds.
+ int64_t mLastTimestampOffset;
+
// Set when the first decoder used by this TrackBuffer is initialized.
// Protected by mParentDecoder's monitor.
MediaInfo mInfo;
void ContinueShutdown();
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
bool mDecoderPerSegment;
bool mShutdown;
--- a/dom/media/omx/AudioOffloadPlayer.cpp
+++ b/dom/media/omx/AudioOffloadPlayer.cpp
@@ -50,28 +50,28 @@ PRLogModuleInfo* gAudioOffloadPlayerLog;
#define AUDIO_OFFLOAD_LOG(type, msg)
#endif
// maximum time in paused state when offloading audio decompression.
// When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
- mObserver(aObserver),
- mInputBuffer(nullptr),
- mSampleRate(0),
- mSeeking(false),
- mSeekDuringPause(false),
- mReachedEOS(false),
- mSeekTimeUs(0),
- mStartPosUs(0),
- mPositionTimeMediaUs(-1),
mStarted(false),
mPlaying(false),
- mIsElementVisible(true)
+ mSeeking(false),
+ mReachedEOS(false),
+ mSeekDuringPause(false),
+ mIsElementVisible(true),
+ mSampleRate(0),
+ mStartPosUs(0),
+ mSeekTimeUs(0),
+ mPositionTimeMediaUs(-1),
+ mInputBuffer(nullptr),
+ mObserver(aObserver)
{
MOZ_ASSERT(NS_IsMainThread());
#ifdef PR_LOGGING
if (!gAudioOffloadPlayerLog) {
gAudioOffloadPlayerLog = PR_NewLogModule("AudioOffloadPlayer");
}
#endif
--- a/dom/media/omx/AudioOutput.cpp
+++ b/dom/media/omx/AudioOutput.cpp
@@ -28,21 +28,21 @@ extern PRLogModuleInfo* gAudioOffloadPla
PR_LOG(gAudioOffloadPlayerLog, type, msg)
#else
#define AUDIO_OFFLOAD_LOG(type, msg)
#endif
using namespace android;
AudioOutput::AudioOutput(int aSessionId, int aUid) :
+ mCallbackCookie(nullptr),
mCallback(nullptr),
- mCallbackCookie(nullptr),
mCallbackData(nullptr),
- mSessionId(aSessionId),
- mUid(aUid)
+ mUid(aUid),
+ mSessionId(aSessionId)
{
#ifdef PR_LOGGING
if (!gAudioOffloadPlayerLog) {
gAudioOffloadPlayerLog = PR_NewLogModule("AudioOffloadPlayer");
}
#endif
}
--- a/dom/media/omx/AudioOutput.h
+++ b/dom/media/omx/AudioOutput.h
@@ -21,18 +21,16 @@
#define AUDIOOUTPUT_H_
#include <stagefright/foundation/ABase.h>
#include <utils/Mutex.h>
#include <AudioTrack.h>
#include "AudioSink.h"
-#define LOG_TAG "AudioOffloadPlayer"
-
namespace mozilla {
/**
* Stripped version of Android KK MediaPlayerService::AudioOutput class
* Android MediaPlayer uses AudioOutput as a wrapper to handle
* Android::AudioTrack
* Similarly to ease handling offloaded tracks, part of AudioOutput is used here
*/
--- a/dom/media/omx/MediaCodecProxy.cpp
+++ b/dom/media/omx/MediaCodecProxy.cpp
@@ -7,19 +7,18 @@
#include "MediaCodecProxy.h"
#include <string.h>
#include <binder/IPCThreadState.h>
#include <stagefright/foundation/ABuffer.h>
#include <stagefright/foundation/ADebug.h>
#include <stagefright/MetaData.h>
#include "stagefright/MediaErrors.h"
-#define LOG_TAG "MediaCodecProxy"
#include <android/log.h>
-#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__)
#define TIMEOUT_DEQUEUE_INPUTBUFFER_MS 1000000ll
namespace android {
// General Template: MediaCodec::getOutputGraphicBufferFromIndex(...)
template <typename T, bool InterfaceSupported>
struct OutputGraphicBufferStub
{
@@ -178,17 +177,17 @@ MediaCodecProxy::releaseCodec()
{
// Write Lock for mCodec
RWLock::AutoWLock awl(mCodecLock);
codec = mCodec;
// Release MediaCodec
if (mCodec != nullptr) {
- status_t err = mCodec->stop();
+ mCodec->stop();
mCodec->release();
mCodec = nullptr;
}
}
while (codec.promote() != nullptr) {
// this value come from stagefright's AwesomePlayer.
usleep(1000);
@@ -489,86 +488,85 @@ MediaCodecProxy::resourceCanceled()
if (listener != nullptr) {
listener->codecCanceled();
}
}
bool MediaCodecProxy::Prepare()
{
- status_t err;
if (start() != OK) {
- ALOG("Couldn't start MediaCodec");
+ MCP_LOG("Couldn't start MediaCodec");
return false;
}
if (getInputBuffers(&mInputBuffers) != OK) {
- ALOG("Couldn't get input buffers from MediaCodec");
+ MCP_LOG("Couldn't get input buffers from MediaCodec");
return false;
}
if (getOutputBuffers(&mOutputBuffers) != OK) {
- ALOG("Couldn't get output buffers from MediaCodec");
+ MCP_LOG("Couldn't get output buffers from MediaCodec");
return false;
}
return true;
}
bool MediaCodecProxy::UpdateOutputBuffers()
{
if (mCodec == nullptr) {
- ALOG("MediaCodec has not been inited from input!");
+ MCP_LOG("MediaCodec has not been inited from input!");
return false;
}
status_t err = getOutputBuffers(&mOutputBuffers);
if (err != OK){
- ALOG("Couldn't update output buffers from MediaCodec");
+ MCP_LOG("Couldn't update output buffers from MediaCodec");
return false;
}
return true;
}
status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize,
int64_t aTimestampUsecs, uint64_t aflags)
{
if (mCodec == nullptr) {
- ALOG("MediaCodec has not been inited from input!");
+ MCP_LOG("MediaCodec has not been inited from input!");
return NO_INIT;
}
size_t index;
status_t err = dequeueInputBuffer(&index, TIMEOUT_DEQUEUE_INPUTBUFFER_MS);
if (err != OK) {
- ALOG("dequeueInputBuffer returned %d", err);
+ MCP_LOG("dequeueInputBuffer returned %d", err);
return err;
}
if (aData) {
const sp<ABuffer> &dstBuffer = mInputBuffers.itemAt(index);
CHECK_LE(aDataSize, dstBuffer->capacity());
dstBuffer->setRange(0, aDataSize);
memcpy(dstBuffer->data(), aData, aDataSize);
err = queueInputBuffer(index, 0, dstBuffer->size(), aTimestampUsecs, aflags);
} else {
err = queueInputBuffer(index, 0, 0, 0ll, MediaCodec::BUFFER_FLAG_EOS);
}
if (err != OK) {
- ALOG("queueInputBuffer returned %d", err);
+ MCP_LOG("queueInputBuffer returned %d", err);
return err;
}
return err;
}
status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
{
if (mCodec == nullptr) {
- ALOG("MediaCodec has not been inited from output!");
+ MCP_LOG("MediaCodec has not been inited from output!");
return NO_INIT;
}
size_t index = 0;
size_t offset = 0;
size_t size = 0;
int64_t timeUs = 0;
uint32_t flags = 0;
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -133,25 +133,25 @@ void MediaOmxReader::CancelProcessCached
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
mIsShutdown = true;
}
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
: MediaOmxCommonReader(aDecoder)
, mMutex("MediaOmxReader.Data")
- , mMP3FrameParser(-1)
, mHasVideo(false)
, mHasAudio(false)
, mVideoSeekTimeUs(-1)
, mAudioSeekTimeUs(-1)
+ , mLastParserDuration(-1)
, mSkipCount(0)
, mUseParserDuration(false)
- , mLastParserDuration(-1)
, mIsShutdown(false)
+ , mMP3FrameParser(-1)
, mIsWaitingResources(false)
{
#ifdef PR_LOGGING
if (!gMediaDecoderLog) {
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
}
#endif
--- a/dom/media/omx/OMXCodecDescriptorUtil.cpp
+++ b/dom/media/omx/OMXCodecDescriptorUtil.cpp
@@ -79,18 +79,18 @@ struct AVCParamSet {
return mSize + 2; // 2 more bytes for length value.
}
// Append 2 bytes length value and NAL unit bitstream to aOutputBuf.
void AppendTo(nsTArray<uint8_t>* aOutputBuf)
{
// 2 bytes length value.
uint8_t size[] = {
- (mSize & 0xFF00) >> 8, // MSB.
- mSize & 0x00FF, // LSB.
+ uint8_t((mSize & 0xFF00) >> 8), // MSB.
+ uint8_t(mSize & 0x00FF), // LSB.
};
aOutputBuf->AppendElements(size, sizeof(size));
aOutputBuf->AppendElements(mPtr, mSize);
}
const uint8_t* mPtr; // Pointer to NAL unit.
const size_t mSize; // NAL unit length in bytes.
@@ -184,17 +184,16 @@ GenerateAVCDescriptorBlob(sp<AMessage>&
}
}
MOZ_ASSERT(sps != nullptr && pps != nullptr);
if (sps == nullptr || pps == nullptr) {
return ERROR_MALFORMED;
}
- status_t result = OK;
if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) {
// SPS + PPS.
aOutputBuf->AppendElements(sps->data(), sps->size());
aOutputBuf->AppendElements(pps->data(), pps->size());
return OK;
} else {
status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf);
MOZ_ASSERT(result == OK);
--- a/dom/media/omx/OMXCodecProxy.cpp
+++ b/dom/media/omx/OMXCodecProxy.cpp
@@ -50,21 +50,21 @@ OMXCodecProxy::OMXCodecProxy(
const sp<MetaData> &meta,
bool createEncoder,
const sp<MediaSource> &source,
const char *matchComponentName,
uint32_t flags,
const sp<ANativeWindow> &nativeWindow)
: mOMX(omx),
mSrcMeta(meta),
+ mComponentName(nullptr),
mIsEncoder(createEncoder),
- mSource(source),
- mComponentName(nullptr),
mFlags(flags),
mNativeWindow(nativeWindow),
+ mSource(source),
mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
{
}
OMXCodecProxy::~OMXCodecProxy()
{
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
--- a/dom/media/omx/OMXCodecWrapper.cpp
+++ b/dom/media/omx/OMXCodecWrapper.cpp
@@ -282,21 +282,21 @@ ConvertPlanarYCbCrToNV12(const PlanarYCb
ySize.height % uvSize.height == 0);
size_t uvWidth = ySize.width / 2;
size_t uvHeight = ySize.height / 2;
size_t horiSubsample = uvSize.width / uvWidth;
size_t uPixStride = horiSubsample * (1 + aSource->mCbSkip);
size_t vPixStride = horiSubsample * (1 + aSource->mCrSkip);
size_t lineStride = uvSize.height / uvHeight * aSource->mCbCrStride;
- for (int i = 0; i < uvHeight; i++) {
+ for (size_t i = 0; i < uvHeight; i++) {
// 1st pixel per line.
uint8_t* uSrc = u;
uint8_t* vSrc = v;
- for (int j = 0; j < uvWidth; j++) {
+ for (size_t j = 0; j < uvWidth; j++) {
*aDestination++ = *uSrc;
*aDestination++ = *vSrc;
// Pick next source pixel.
uSrc += uPixStride;
vSrc += vPixStride;
}
// Pick next source line.
u += lineStride;
@@ -490,20 +490,20 @@ OMXVideoEncoder::AppendFrame(nsTArray<ui
if (mBlobFormat == BlobFormat::AVC_NAL) {
// Append NAL format data without modification.
aOutputBuf->AppendElements(aData, aSize);
return;
}
// Replace start code with data length.
uint8_t length[] = {
- (aSize >> 24) & 0xFF,
- (aSize >> 16) & 0xFF,
- (aSize >> 8) & 0xFF,
- aSize & 0xFF,
+ uint8_t((aSize >> 24) & 0xFF),
+ uint8_t((aSize >> 16) & 0xFF),
+ uint8_t((aSize >> 8) & 0xFF),
+ uint8_t(aSize & 0xFF),
};
aOutputBuf->AppendElements(length, sizeof(length));
aOutputBuf->AppendElements(aData + sizeof(length), aSize);
}
// MediaCodec::setParameters() is available only after API level 18.
#if ANDROID_VERSION >= 18
nsresult
@@ -587,18 +587,18 @@ public:
InputBufferHelper(sp<MediaCodec>& aCodec, Vector<sp<ABuffer> >& aBuffers,
OMXAudioEncoder& aEncoder, int aInputFlags)
: mCodec(aCodec)
, mBuffers(aBuffers)
, mOMXAEncoder(aEncoder)
, mInputFlags(aInputFlags)
, mIndex(0)
, mData(nullptr)
+ , mCapicity(0)
, mOffset(0)
- , mCapicity(0)
{}
~InputBufferHelper()
{
// Unflushed data in buffer.
MOZ_ASSERT(!mData);
}
@@ -903,24 +903,24 @@ OMXAudioEncoder::AppendDecoderConfig(nsT
NS_ENSURE_TRUE(csdSize == 2, ERROR_MALFORMED);
// Encoder output must be consistent with kAACFrameDuration:
// 14th bit (frame length flag) == 0 => 1024 (kAACFrameDuration) samples.
NS_ENSURE_TRUE((aData->data()[1] & 0x04) == 0, ERROR_MALFORMED);
// Decoder config descriptor
const uint8_t decConfig[] = {
0x04, // Decoder config descriptor tag.
- 15 + csdSize, // Size: following bytes + csd size.
+ uint8_t(15 + csdSize), // Size: following bytes + csd size.
0x40, // Object type: MPEG-4 audio.
0x15, // Stream type: audio, reserved: 1.
0x00, 0x03, 0x00, // Buffer size: 768 (kAACFrameSize).
0x00, 0x01, 0x77, 0x00, // Max bitrate: 96000 (kAACBitrate).
0x00, 0x01, 0x77, 0x00, // Avg bitrate: 96000 (kAACBitrate).
0x05, // Decoder specific descriptor tag.
- csdSize, // Data size.
+ uint8_t(csdSize), // Data size.
};
// SL config descriptor.
const uint8_t slConfig[] = {
0x06, // SL config descriptor tag.
0x01, // Size.
0x02, // Fixed value.
};
--- a/dom/media/omx/OmxDecoder.cpp
+++ b/dom/media/omx/OmxDecoder.cpp
@@ -28,19 +28,18 @@
#include "MPAPI.h"
#include "prlog.h"
#include "GonkNativeWindow.h"
#include "GonkNativeWindowClient.h"
#include "OMXCodecProxy.h"
#include "OmxDecoder.h"
-#define LOG_TAG "OmxDecoder"
#include <android/log.h>
-#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define OD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "OmxDecoder", __VA_ARGS__)
#ifdef PR_LOGGING
PRLogModuleInfo *gOmxDecoderLog;
#define LOG(type, msg...) PR_LOG(gOmxDecoderLog, type, (msg))
#else
#define LOG(x...)
#endif
@@ -60,23 +59,23 @@ OmxDecoder::OmxDecoder(MediaResource *aR
mVideoHeight(0),
mVideoColorFormat(0),
mVideoStride(0),
mVideoSliceHeight(0),
mVideoRotation(0),
mAudioChannels(-1),
mAudioSampleRate(-1),
mDurationUs(-1),
+ mVideoLastFrameTime(-1),
mVideoBuffer(nullptr),
mAudioBuffer(nullptr),
mIsVideoSeeking(false),
mAudioMetadataRead(false),
mAudioPaused(false),
- mVideoPaused(false),
- mVideoLastFrameTime(-1)
+ mVideoPaused(false)
{
mLooper = new ALooper;
mLooper->setName("OmxDecoder");
mReflector = new AHandlerReflector<OmxDecoder>(this);
// Register AMessage handler to ALooper.
mLooper->registerHandler(mReflector);
// Start ALooper thread.
@@ -114,17 +113,16 @@ static sp<IOMX> GetOMX()
bool OmxDecoder::Init(sp<MediaExtractor>& extractor) {
#ifdef PR_LOGGING
if (!gOmxDecoderLog) {
gOmxDecoderLog = PR_NewLogModule("OmxDecoder");
}
#endif
- const char* extractorMime;
sp<MetaData> meta = extractor->getMetaData();
ssize_t audioTrackIndex = -1;
ssize_t videoTrackIndex = -1;
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<MetaData> meta = extractor->getTrackMetaData(i);
@@ -172,17 +170,16 @@ bool OmxDecoder::EnsureMetadata() {
int64_t totalDurationUs = 0;
int64_t durationUs = 0;
if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
if (durationUs > totalDurationUs)
totalDurationUs = durationUs;
}
if (mAudioTrack.get()) {
durationUs = -1;
- const char* audioMime;
sp<MetaData> meta = mAudioTrack->getFormat();
if ((durationUs == -1) && meta->findInt64(kKeyDuration, &durationUs)) {
if (durationUs > totalDurationUs) {
totalDurationUs = durationUs;
}
}
}
@@ -599,17 +596,17 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
findNextBuffer = true;
{
Mutex::Autolock autoLock(mSeekLock);
mIsVideoSeeking = true;
}
continue;
} else if (err != OK) {
- ALOG("Unexpected error when seeking to %lld", aTimeUs);
+ OD_LOG("Unexpected error when seeking to %lld", aTimeUs);
break;
}
// For some codecs, the length of first decoded frame after seek is 0.
// Need to ignore it and continue to find the next one
if (mVideoBuffer->range_length() == 0) {
ReleaseVideoBuffer();
findNextBuffer = true;
}
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
+++ b/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
@@ -143,17 +143,17 @@ void MediaResourceManagerService::onMess
return;
}
// Exit if no request.
if (!mResources.hasRequest(type)) {
return;
}
- const sp<IBinder>& req = mResources.nextRequest(type);
+ sp<IBinder> req = mResources.nextRequest(type);
mResources.aquireResource(req, type, found);
// Notify resource assignment to the client.
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
mResources.dequeueRequest(type);
}
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
@@ -287,17 +287,17 @@ uint32_t MediaResourceManagerService::Re
// Unsupported type.
return 0;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
return queue.size();
}
-const sp<IBinder>& MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
+sp<IBinder> MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
{
ssize_t found = mMap.indexOfKey(type);
if (found == NAME_NOT_FOUND) {
// Unsupported type.
return nullptr;
}
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
@@ -328,17 +328,17 @@ status_t MediaResourceManagerService::Re
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
queue.erase(queue.begin());
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
{
// Traverse all resources.
- for (int i = 0; i < mMap.size(); i++) {
+ for (size_t i = 0; i < mMap.size(); i++) {
forgetClient(client, mMap.keyAt(i));
}
return OK;
}
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
{
MOZ_ASSERT(supportsType(type));
@@ -353,17 +353,17 @@ status_t MediaResourceManagerService::Re
queue.erase(it);
break;
}
it++;
}
// Revoke ownership for given client.
Slots& slots = resources.mSlots;
- for (int i = 0; i < slots.size(); i++) {
+ for (size_t i = 0; i < slots.size(); i++) {
ResourceSlot& slot = slots.editItemAt(i);
if (client.get() == slot.mClient.get()) {
slot.mClient = nullptr;
}
}
return OK;
}
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h
+++ b/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h
@@ -94,17 +94,17 @@ private:
bool supportsType(ResourceType type);
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
// Request operations.
bool hasRequest(ResourceType type);
uint32_t countRequests(ResourceType type);
- const sp<IBinder>& nextRequest(ResourceType type);
+ sp<IBinder> nextRequest(ResourceType type);
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
status_t dequeueRequest(ResourceType type);
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
status_t forgetClient(const sp<IBinder>& client);
friend class MediaResourceManagerService;
// A map for all types of supported resources.
--- a/dom/media/omx/mediaresourcemanager/moz.build
+++ b/dom/media/omx/mediaresourcemanager/moz.build
@@ -19,16 +19,23 @@ SOURCES += [
'IMediaResourceManagerService.cpp',
'MediaResourceHandler.cpp',
'MediaResourceManagerClient.cpp',
'MediaResourceManagerService.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
+# Suppress some GCC/clang warnings being treated as errors:
+# - about multi-character constants which are used in codec-related code
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+ CXXFLAGS += [
+ '-Wno-error=multichar'
+ ]
+
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'frameworks/base/include',
'frameworks/base/include/binder',
'frameworks/base/include/utils',
'frameworks/base/include/media/',
'frameworks/base/include/media/stagefright/openmax',
'frameworks/base/media/libstagefright/include',
--- a/dom/media/omx/moz.build
+++ b/dom/media/omx/moz.build
@@ -74,16 +74,26 @@ if CONFIG['ANDROID_VERSION'] >= '18':
'I420ColorConverterHelper.cpp',
'MediaCodecDecoder.cpp',
'MediaCodecProxy.cpp',
'MediaCodecReader.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
+# Suppress some GCC/clang warnings being treated as errors:
+# - about attributes on forward declarations for types that are already
+# defined, which complains about an important MOZ_EXPORT for android::AString
+# - about multi-character constants which are used in codec-related code
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+ CXXFLAGS += [
+ '-Wno-error=attributes',
+ '-Wno-error=multichar'
+ ]
+
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base',
'/dom/html',
'/ipc/chromium/src',
'mediaresourcemanager',
]
--- a/dom/media/webrtc/GonkCameraImage.cpp
+++ b/dom/media/webrtc/GonkCameraImage.cpp
@@ -21,17 +21,17 @@ GonkCameraImage::GonkCameraImage()
GonkCameraImage::~GonkCameraImage()
{
ReentrantMonitorAutoEnter mon(mMonitor);
// mMediaBuffer must be cleared before destructor.
MOZ_ASSERT(mMediaBuffer == nullptr);
}
nsresult
-GonkCameraImage::GetBuffer(android::MediaBuffer** aBuffer)
+GonkCameraImage::GetMediaBuffer(android::MediaBuffer** aBuffer)
{
ReentrantMonitorAutoEnter mon(mMonitor);
if (!mMediaBuffer) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
@@ -45,30 +45,30 @@ GonkCameraImage::GetBuffer(android::Medi
bool
GonkCameraImage::HasMediaBuffer()
{
ReentrantMonitorAutoEnter mon(mMonitor);
return mMediaBuffer != nullptr;
}
nsresult
-GonkCameraImage::SetBuffer(android::MediaBuffer* aBuffer)
+GonkCameraImage::SetMediaBuffer(android::MediaBuffer* aBuffer)
{
ReentrantMonitorAutoEnter mon(mMonitor);
MOZ_ASSERT(!mMediaBuffer);
mMediaBuffer = aBuffer;
mMediaBuffer->add_ref();
mThread = NS_GetCurrentThread();
return NS_OK;
}
nsresult
-GonkCameraImage::ClearBuffer()
+GonkCameraImage::ClearMediaBuffer()
{
ReentrantMonitorAutoEnter mon(mMonitor);
if (mMediaBuffer) {
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
mMediaBuffer->release();
mMediaBuffer = nullptr;
mThread = nullptr;
--- a/dom/media/webrtc/GonkCameraImage.h
+++ b/dom/media/webrtc/GonkCameraImage.h
@@ -19,57 +19,57 @@ namespace mozilla {
/**
* GonkCameraImage has two parts. One is preview image which will be saved in
* GrallocImage, another kind is the MediaBuffer keeps in mMediaBuffer
* which is from gonk camera recording callback. The data in MediaBuffer is Gonk
* shared memory based on android binder (IMemory), the actual format in IMemory
* is platform dependent.
* This instance is created in MediaEngine when the preview image arrives.
- * The MediaBuffer is attached to the current created GonkCameraImage via SetBuffer().
- * After sending this image to MediaStreamGraph by AppendToTrack(), ClearBuffer()
+ * The MediaBuffer is attached to the current created GonkCameraImage via SetMediaBuffer().
+ * After sending this image to MediaStreamGraph by AppendToTrack(), ClearMediaBuffer()
* must be called to clear MediaBuffer to avoid MediaBuffer be kept in MSG thread.
* The reason to keep MediaBuffer be accessed from MSG thread is MediaBuffer is
* limited resource and it could cause frame rate jitter if MediaBuffer stay too
* long in other threads.
* So there will be 3 threads to accessed this class. First is camera preview
* thread which creates an instance of this class and initialize the preview
* image in the base class GrallocImage. Second is the camera recording
* thread which attaches MediaBuffer and sends this image to MediaStreamDirectListener.
* Third is the MSG thread via NotifyPull, the image should have preview image
* only in NotifyPull.
*
- * Note: SetBuffer() and GetBuffer() should be called from the same thread. It
- * is forbidden to call GetBuffer() from other threads.
+ * Note: SetMediaBuffer() and GetMediaBuffer() should be called from the same
+ * thread. It is forbidden to call GetMediaBuffer() from other threads.
*/
class GonkCameraImage : public layers::GrallocImage
{
public:
GonkCameraImage();
// The returned aBuffer has called aBuffer->add_ref() already, so it is caller's
// duty to release aBuffer. It should be called from the same thread which
- // called SetBuffer().
- nsresult GetBuffer(android::MediaBuffer** aBuffer);
+ // called SetMediaBuffer().
+ nsresult GetMediaBuffer(android::MediaBuffer** aBuffer);
- // Set MediaBuffer to image. It is caller's responsibility to call ClearBuffer()
+ // Set MediaBuffer to image. It is caller's responsibility to call ClearMediaBuffer()
// after the MediaBuffer is sent via MediaStreamGraph.
- nsresult SetBuffer(android::MediaBuffer* aBuffer);
+ nsresult SetMediaBuffer(android::MediaBuffer* aBuffer);
- // It should be called from the same thread which called SetBuffer().
- nsresult ClearBuffer();
+ // It should be called from the same thread which called SetMediaBuffer().
+ nsresult ClearMediaBuffer();
bool HasMediaBuffer();
protected:
virtual ~GonkCameraImage();
// mMonitor protects mMediaBuffer and mThread.
ReentrantMonitor mMonitor;
android::MediaBuffer* mMediaBuffer;
- // Check if current thread is the same one which called SetBuffer().
+ // Check if current thread is the same one which called SetMediaBuffer().
// It doesn't need to hold reference count.
DebugOnly<nsIThread*> mThread;
};
} // namespace mozilla
#endif /* GONKCAMERAIMAGE_H */
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -1,13 +1,14 @@
/* 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 "MediaEngineGonkVideoSource.h"
+#undef LOG_TAG
#define LOG_TAG "MediaEngineGonkVideoSource"
#include <utils/Log.h>
#include "GrallocImages.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "VideoUtils.h"
@@ -795,17 +796,17 @@ MediaEngineGonkVideoSource::OnNewMediaBu
}
MonitorAutoLock enter(mMonitor);
if (mImage) {
if (mImage->AsGrallocImage()) {
// MediaEngineGonkVideoSource expects that GrallocImage is GonkCameraImage.
// See Bug 938034.
GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
- cameraImage->SetBuffer(aBuffer);
+ cameraImage->SetMediaBuffer(aBuffer);
} else {
LOG(("mImage is non-GrallocImage"));
}
uint32_t len = mSources.Length();
for (uint32_t i = 0; i < len; i++) {
if (mSources[i]) {
// Duration is 1 here.
@@ -816,16 +817,16 @@ MediaEngineGonkVideoSource::OnNewMediaBu
// queued in MSG longer and longer as time going by in device like Frame)
AppendToTrack(mSources[i], mImage, mTrackID, 1);
}
}
if (mImage->AsGrallocImage()) {
GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
// Clear MediaBuffer immediately, it prevents MediaBuffer is kept in
// MediaStreamGraph thread.
- cameraImage->ClearBuffer();
+ cameraImage->ClearMediaBuffer();
}
}
return NS_OK;
}
} // namespace mozilla
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.h
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.h
@@ -92,17 +92,17 @@ public:
nsresult TakePhoto(PhotoCallback* aCallback) MOZ_OVERRIDE;
// It sets the correct photo orientation via camera parameter according to
// current screen orientation.
nsresult UpdatePhotoOrientation();
// It adds aBuffer to current preview image and sends this image to MediaStreamDirectListener
// via AppendToTrack(). Due to MediaBuffer is limited resource, it will clear
- // image's MediaBuffer by calling GonkCameraImage::ClearBuffer() before leaving
+ // image's MediaBuffer by calling GonkCameraImage::ClearMediaBuffer() before leaving
// this function.
nsresult OnNewMediaBufferFrame(android::MediaBuffer* aBuffer);
protected:
~MediaEngineGonkVideoSource()
{
Shutdown();
}
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -13,37 +13,37 @@ namespace mozilla {
class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventListener, nsITimerCallback {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSITIMERCALLBACK
MediaEngineTabVideoSource();
- virtual void GetName(nsAString_internal&);
- virtual void GetUUID(nsAString_internal&);
+ virtual void GetName(nsAString_internal&) MOZ_OVERRIDE;
+ virtual void GetUUID(nsAString_internal&) MOZ_OVERRIDE;
virtual nsresult Allocate(const VideoTrackConstraintsN &,
- const mozilla::MediaEnginePrefs&);
- virtual nsresult Deallocate();
- virtual nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID);
- virtual void SetDirectListeners(bool aHasDirectListeners) {};
+ const mozilla::MediaEnginePrefs&) MOZ_OVERRIDE;
+ virtual nsresult Deallocate() MOZ_OVERRIDE;
+ virtual nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID) MOZ_OVERRIDE;
+ virtual void SetDirectListeners(bool aHasDirectListeners) MOZ_OVERRIDE {};
virtual void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime) MOZ_OVERRIDE;
- virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID);
- virtual nsresult Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t);
- virtual bool IsFake();
- virtual const MediaSourceType GetMediaSource() {
+ virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID) MOZ_OVERRIDE;
+ virtual nsresult Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t) MOZ_OVERRIDE;
+ virtual bool IsFake() MOZ_OVERRIDE;
+ virtual const MediaSourceType GetMediaSource() MOZ_OVERRIDE {
return MediaSourceType::Browser;
}
virtual bool SatisfiesConstraintSets(
- const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets)
+ const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets) MOZ_OVERRIDE
{
return true;
}
- virtual nsresult TakePhoto(PhotoCallback* aCallback)
+ virtual nsresult TakePhoto(PhotoCallback* aCallback) MOZ_OVERRIDE
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void Draw();
class StartRunnable : public nsRunnable {
public:
--- a/dom/media/webrtc/moz.build
+++ b/dom/media/webrtc/moz.build
@@ -55,16 +55,25 @@ UNIFIED_SOURCES += [
]
EXPORTS.mozilla += [
'PeerIdentity.h',
]
include('/ipc/chromium/chromium-config.mozbuild')
+# Suppress some GCC/clang warnings being treated as errors:
+# - about attributes on forward declarations for types that are already
+# defined, which complains about important MOZ_EXPORT attributes for
+# android API types
+if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
+ CXXFLAGS += [
+ '-Wno-error=attributes'
+ ]
+
FINAL_LIBRARY = 'xul'
if CONFIG['OS_ARCH'] == 'WINNT':
DEFINES['NOMINMAX'] = True
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4275', # non dll-interface class used as base for dll-interface class
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -77,21 +77,21 @@ public:
NS_IMETHOD Setup(nsISpeechTaskCallback* aCallback,
uint32_t aChannels, uint32_t aRate, uint8_t argc) MOZ_OVERRIDE;
NS_IMETHOD SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks,
JSContext* aCx) MOZ_OVERRIDE;
NS_IMETHOD SendAudioNative(int16_t* aData, uint32_t aDataLen) MOZ_OVERRIDE;
- virtual void Pause();
+ virtual void Pause() MOZ_OVERRIDE;
- virtual void Resume();
+ virtual void Resume() MOZ_OVERRIDE;
- virtual void Cancel();
+ virtual void Cancel() MOZ_OVERRIDE;
private:
SpeechSynthesisRequestChild* mActor;
};
} // namespace dom
} // namespace mozilla
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -63,17 +63,17 @@ public:
case EVENT_REMOVED:
mSpeechTask = nullptr;
break;
default:
break;
}
}
- virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked)
+ virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) MOZ_OVERRIDE
{
if (aBlocked == MediaStreamListener::UNBLOCKED && !mStarted) {
mStarted = true;
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
}
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1745,17 +1745,17 @@ NPObjWrapper_Convert(JSContext *cx, JS::
}
static void
NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj)
{
NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
if (npobj) {
if (sNPObjWrappers.ops) {
- PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_REMOVE);
+ PL_DHashTableRemove(&sNPObjWrappers, npobj);
}
}
if (!sDelayedReleases)
sDelayedReleases = new nsTArray<NPObject*>;
sDelayedReleases->AppendElement(npobj);
}
@@ -1774,17 +1774,17 @@ NPObjWrapper_ObjectMoved(JSObject *obj,
return;
}
// The hazard analysis thinks that PL_DHashTableOperate() can GC but this is
// not possible if we pass PL_DHASH_LOOKUP.
JS::AutoSuppressGCAnalysis nogc;
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
- (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sNPObjWrappers, npobj));
MOZ_ASSERT(PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObj);
MOZ_ASSERT(entry->mJSObj == old);
entry->mJSObj = obj;
}
static bool
NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp)
{
@@ -1827,17 +1827,17 @@ nsNPObjWrapper::OnDestroy(NPObject *npob
if (!sNPObjWrappers.ops) {
// No hash yet (or any more), no used wrappers available.
return;
}
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
- (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sNPObjWrappers, npobj));
if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObj) {
// Found a live NPObject wrapper, null out its JSObjects' private
// data.
::JS_SetPrivate(entry->mJSObj, nullptr);
// Remove the npobj from the hash now that it went away.
@@ -1878,17 +1878,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
if (!sNPObjWrappers.ops) {
// No hash yet (or any more), initialize it.
if (!CreateNPObjWrapperTable()) {
return nullptr;
}
}
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
- (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_ADD));
+ (PL_DHashTableAdd(&sNPObjWrappers, npobj));
if (!entry) {
// Out of memory
JS_ReportOutOfMemory(cx);
return nullptr;
}
@@ -1912,17 +1912,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass),
JS::NullPtr(), JS::NullPtr()));
if (generation != sNPObjWrappers.Generation()) {
// Reload entry if the JS_NewObject call caused a GC and reallocated
// the table (see bug 445229). This is guaranteed to succeed.
entry = static_cast<NPObjWrapperHashEntry *>
- (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(&sNPObjWrappers, npobj));
NS_ASSERTION(entry && PL_DHASH_ENTRY_IS_BUSY(entry),
"Hashtable didn't find what we just added?");
}
if (!obj) {
// OOM? Remove the stale entry from the hash.
PL_DHashTableRawRemove(&sNPObjWrappers, entry);
@@ -2044,17 +2044,17 @@ static NPP
LookupNPP(NPObject *npobj)
{
if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
nsJSObjWrapper* o = static_cast<nsJSObjWrapper*>(npobj);
return o->mNpp;
}
NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
- (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_ADD));
+ (PL_DHashTableAdd(&sNPObjWrappers, npobj));
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
return nullptr;
}
NS_ASSERTION(entry->mNpp, "Live NPObject entry w/o an NPP!");
return entry->mNpp;
--- a/dom/svg/nsSVGPathGeometryElement.cpp
+++ b/dom/svg/nsSVGPathGeometryElement.cpp
@@ -82,17 +82,19 @@ nsSVGPathGeometryElement::GetOrBuildPath
bool cacheable = aDrawTarget.GetBackendType() ==
gfxPlatform::GetPlatform()->GetContentBackend();
// Checking for and returning mCachedPath before checking the pref means
// that the pref is only live on page reload (or app restart for SVG in
// chrome). The benefit is that we avoid causing a CPU memory cache miss by
// looking at the global variable that the pref's stored in.
if (cacheable && mCachedPath) {
- return mCachedPath;
+ if (aDrawTarget.GetBackendType() == mCachedPath->GetBackendType()) {
+ return mCachedPath;
+ }
}
RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(aFillRule);
RefPtr<Path> path = BuildPath(builder);
if (cacheable && NS_SVGPathCachingEnabled()) {
mCachedPath = path;
}
return path.forget();
}
--- a/dom/system/gonk/VolumeManager.cpp
+++ b/dom/system/gonk/VolumeManager.cpp
@@ -175,17 +175,16 @@ void VolumeManager::InitConfig()
int n = 0;
char line[255];
const char *filename = "/system/etc/volume.cfg";
if (!(fp = fopen(filename, "r"))) {
LOG("Unable to open volume configuration file '%s' - ignoring", filename);
return;
}
while(fgets(line, sizeof(line), fp)) {
- const char *delim = " \t\n";
n++;
if (line[0] == '#')
continue;
nsCString commandline(line);
nsCWhitespaceTokenizer tokenizer(commandline);
if (!tokenizer.hasMoreTokens()) {
--- a/dom/webidl/Animatable.webidl
+++ b/dom/webidl/Animatable.webidl
@@ -7,11 +7,11 @@
* http://dev.w3.org/fxtf/web-animations/#the-animatable-interface
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[NoInterfaceObject]
interface Animatable {
- [Pref="dom.animations-api.core.enabled"]
+ [Func="nsDocument::IsWebAnimationsEnabled"]
sequence<AnimationPlayer> getAnimationPlayers();
};
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -5,17 +5,17 @@
*
* The origin of this IDL file is
* http://dev.w3.org/fxtf/web-animations/#the-animation-interface
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
-[Pref="dom.animations-api.core.enabled"]
+[Func="nsDocument::IsWebAnimationsEnabled"]
interface Animation {
// FIXME: |effect| should have type (AnimationEffect or EffectCallback)?
// but we haven't implemented EffectCallback yet.
[Cached,Pure]
readonly attribute AnimationEffect? effect;
// FIXME: This should be writeable (bug 1067769)
readonly attribute Element? target;
};
--- a/dom/webidl/AnimationEffect.webidl
+++ b/dom/webidl/AnimationEffect.webidl
@@ -5,12 +5,12 @@
*
* The origin of this IDL file is
* http://dev.w3.org/fxtf/web-animations/#the-animationeffect-interface
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
-[Pref="dom.animations-api.core.enabled"]
+[Func="nsDocument::IsWebAnimationsEnabled"]
interface AnimationEffect {
readonly attribute DOMString name;
};
--- a/dom/webidl/AnimationPlayer.webidl
+++ b/dom/webidl/AnimationPlayer.webidl
@@ -7,17 +7,17 @@
* http://dev.w3.org/fxtf/web-animations/#idl-def-AnimationPlayer
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
-[Pref="dom.animations-api.core.enabled"]
+[Func="nsDocument::IsWebAnimationsEnabled"]
interface AnimationPlayer {
// Bug 1049975
// attribute AnimationNode? source;
[Pure]
readonly attribute Animation? source;
readonly attribute AnimationTimeline timeline;
[BinaryName="startTimeAsDouble"]
readonly attribute double? startTime;
--- a/dom/webidl/AnimationTimeline.webidl
+++ b/dom/webidl/AnimationTimeline.webidl
@@ -5,16 +5,16 @@
*
* The origin of this IDL file is
* http://dev.w3.org/fxtf/web-animations/#the-animationtimeline-interface
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
-[Pref="dom.animations-api.core.enabled"]
+[Func="nsDocument::IsWebAnimationsEnabled"]
interface AnimationTimeline {
[BinaryName="currentTimeAsDouble"]
readonly attribute double? currentTime;
// Not yet implemented:
// AnimationPlayer play (optional TimedItem? source = null);
// sequence<AnimationPlayer> getAnimationPlayers ();
};
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -282,17 +282,17 @@ partial interface Document {
NodeList querySelectorAll(DOMString selectors);
//(Not implemented)Element? find(DOMString selectors, optional (Element or sequence<Node>)? refNodes);
//(Not implemented)NodeList findAll(DOMString selectors, optional (Element or sequence<Node>)? refNodes);
};
// http://dev.w3.org/fxtf/web-animations/#extensions-to-the-document-interface
partial interface Document {
- [Pref="dom.animations-api.core.enabled"]
+ [Func="nsDocument::IsWebAnimationsEnabled"]
readonly attribute AnimationTimeline timeline;
};
// Mozilla extensions of various sorts
partial interface Document {
// nsIDOMDocumentXBL. Wish we could make these [ChromeOnly], but
// that would likely break bindings running with the page principal.
[Func="IsChromeOrXBL"]
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -777,24 +777,22 @@ XULDocument::AddBroadcastListenerFor(Ele
if (! mBroadcasterMap) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
BroadcasterMapEntry* entry =
static_cast<BroadcasterMapEntry*>
- (PL_DHashTableOperate(mBroadcasterMap, &aBroadcaster,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mBroadcasterMap, &aBroadcaster));
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
entry =
static_cast<BroadcasterMapEntry*>
- (PL_DHashTableOperate(mBroadcasterMap, &aBroadcaster,
- PL_DHASH_ADD));
+ (PL_DHashTableAdd(mBroadcasterMap, &aBroadcaster));
if (! entry) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
entry->mBroadcaster = &aBroadcaster;
@@ -845,34 +843,32 @@ XULDocument::RemoveBroadcastListenerFor(
{
// If we haven't added any broadcast listeners, then there sure
// aren't any to remove.
if (! mBroadcasterMap)
return;
BroadcasterMapEntry* entry =
static_cast<BroadcasterMapEntry*>
- (PL_DHashTableOperate(mBroadcasterMap, &aBroadcaster,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mBroadcasterMap, &aBroadcaster));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
nsCOMPtr<nsIAtom> attr = do_GetAtom(aAttr);
for (int32_t i = entry->mListeners.Count() - 1; i >= 0; --i) {
BroadcastListener* bl =
static_cast<BroadcastListener*>(entry->mListeners[i]);
nsCOMPtr<Element> blListener = do_QueryReferent(bl->mListener);
if (blListener == &aListener && bl->mAttribute == attr) {
entry->mListeners.RemoveElementAt(i);
delete bl;
if (entry->mListeners.Count() == 0)
- PL_DHashTableOperate(mBroadcasterMap, &aBroadcaster,
- PL_DHASH_REMOVE);
+ PL_DHashTableRemove(mBroadcasterMap, &aBroadcaster);
break;
}
}
}
}
nsresult
@@ -969,18 +965,17 @@ XULDocument::AttributeChanged(nsIDocumen
nsresult rv;
// Synchronize broadcast listeners
if (mBroadcasterMap &&
CanBroadcast(aNameSpaceID, aAttribute)) {
BroadcasterMapEntry* entry =
static_cast<BroadcasterMapEntry*>
- (PL_DHashTableOperate(mBroadcasterMap, aElement,
- PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mBroadcasterMap, aElement));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
// We've got listeners: push the value.
nsAutoString value;
bool attrSet = aElement->GetAttr(kNameSpaceID_None, aAttribute, value);
int32_t i;
for (i = entry->mListeners.Count() - 1; i >= 0; --i) {
@@ -4166,17 +4161,17 @@ XULDocument::BroadcastAttributeChangeFro
if (!mBroadcasterMap || !CanBroadcast(aNameSpaceID, aAttribute))
return rv;
if (!aNode->IsElement())
return rv;
BroadcasterMapEntry* entry = static_cast<BroadcasterMapEntry*>
- (PL_DHashTableOperate(mBroadcasterMap, aNode->AsElement(), PL_DHASH_LOOKUP));
+ (PL_DHashTableLookup(mBroadcasterMap, aNode->AsElement()));
if (!PL_DHASH_ENTRY_IS_BUSY(entry))
return rv;
// We've got listeners: push the value.
int32_t i;
for (i = entry->mListeners.Count() - 1; i >= 0; --i) {
BroadcastListener* bl = static_cast<BroadcastListener*>
(entry->mListeners[i]);
--- a/dom/xul/templates/nsContentSupportMap.cpp
+++ b/dom/xul/templates/nsContentSupportMap.cpp
@@ -22,16 +22,16 @@ nsContentSupportMap::Finish()
nsresult
nsContentSupportMap::Remove(nsIContent* aElement)
{
if (!mMap.ops)
return NS_ERROR_NOT_INITIALIZED;
nsIContent* child = aElement;
do {
- PL_DHashTableOperate(&mMap, child, PL_DHASH_REMOVE);
+ PL_DHashTableRemove(&mMap, child);
child = child->GetNextNode(aElement);
} while(child);
return NS_OK;
}
--- a/dom/xul/templates/nsContentSupportMap.h
+++ b/dom/xul/templates/nsContentSupportMap.h
@@ -23,31 +23,31 @@ class nsContentSupportMap {
public:
nsContentSupportMap() { Init(); }
~nsContentSupportMap() { Finish(); }
nsresult Put(nsIContent* aElement, nsTemplateMatch* aMatch) {
if (!mMap.ops)
return NS_ERROR_NOT_INITIALIZED;
- PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mMap, aElement, PL_DHASH_ADD);
+ PLDHashEntryHdr* hdr = PL_DHashTableAdd(&mMap, aElement);
if (!hdr)
return NS_ERROR_OUT_OF_MEMORY;
Entry* entry = reinterpret_cast<Entry*>(hdr);
NS_ASSERTION(entry->mMatch == nullptr, "over-writing entry");
entry->mContent = aElement;
entry->mMatch = aMatch;
return NS_OK; }
bool Get(nsIContent* aElement, nsTemplateMatch** aMatch) {
if (!mMap.ops)
return false;
- PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mMap, aElement, PL_DHASH_LOOKUP);
+ PLDHashEntryHdr* hdr = PL_DHashTableLookup(&mMap, aElement);
if (PL_DHASH_ENTRY_IS_FREE(hdr))
return false;
Entry* entry = reinterpret_cast<Entry*>(hdr);
*aMatch = entry->mMatch;
return true; }
nsresult Remove(nsIContent* aElement);
--- a/dom/xul/templates/nsTemplateMap.h
+++ b/dom/xul/templates/nsTemplateMap.h
@@ -31,44 +31,44 @@ protected:
public:
nsTemplateMap() { Init(); }
~nsTemplateMap() { Finish(); }
void
Put(nsIContent* aContent, nsIContent* aTemplate) {
- NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
+ NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mTable, aContent)),
"aContent already in map");
Entry* entry =
- reinterpret_cast<Entry*>(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_ADD));
+ reinterpret_cast<Entry*>(PL_DHashTableAdd(&mTable, aContent));
if (entry) {
entry->mContent = aContent;
entry->mTemplate = aTemplate;
}
}
void
Remove(nsIContent* aContent) {
- PL_DHashTableOperate(&mTable, aContent, PL_DHASH_REMOVE);
+ PL_DHashTableRemove(&mTable, aContent);
for (nsIContent* child = aContent->GetFirstChild();
child;
child = child->GetNextSibling()) {
Remove(child);
}
}
void
GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
Entry* entry =
- reinterpret_cast<Entry*>(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP));
+ reinterpret_cast<Entry*>(PL_DHashTableLookup(&mTable, aContent));
if (PL_DHASH_ENTRY_IS_BUSY(&entry->mHdr))
NS_IF_ADDREF(*aResult = entry->mTemplate);
else
*aResult = nullptr;
}
void
--- a/embedding/components/commandhandler/nsCommandParams.cpp
+++ b/embedding/components/commandhandler/nsCommandParams.cpp
@@ -209,45 +209,42 @@ nsCommandParams::SetISupportsValue(const
return NS_OK;
}
NS_IMETHODIMP
nsCommandParams::RemoveValue(const char* aName)
{
// PL_DHASH_REMOVE doesn't tell us if the entry was really removed, so we
// return NS_OK unconditionally.
- (void)PL_DHashTableOperate(&mValuesHash, (void *)aName, PL_DHASH_REMOVE);
+ (void)PL_DHashTableRemove(&mValuesHash, (void *)aName);
return NS_OK;
}
nsCommandParams::HashEntry*
nsCommandParams::GetNamedEntry(const char* aName)
{
HashEntry *foundEntry =
- (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)aName,
- PL_DHASH_LOOKUP);
+ (HashEntry *)PL_DHashTableLookup(&mValuesHash, (void *)aName);
if (PL_DHASH_ENTRY_IS_BUSY(foundEntry)) {
return foundEntry;
}
return nullptr;
}
nsCommandParams::HashEntry*
nsCommandParams::GetOrMakeEntry(const char* aName, uint8_t entryType)
{
HashEntry *foundEntry =
- (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)aName,
- PL_DHASH_LOOKUP);
+ (HashEntry *)PL_DHashTableLookup(&mValuesHash, (void *)aName);
if (PL_DHASH_ENTRY_IS_BUSY(foundEntry)) { // reuse existing entry
foundEntry->Reset(entryType);
return foundEntry;
}
- foundEntry = (HashEntry *)PL_DHashTableOperate(&mValuesHash, (void *)aName,
- PL_DHASH_ADD);
+ foundEntry = (HashEntry *)PL_DHashTableAdd(&mValuesHash, (void *)aName);
if (!foundEntry) {
return nullptr;
}
// Use placement new. Our ctor does not clobber keyHash, which is important.
new (foundEntry) HashEntry(entryType, aName);
return foundEntry;
}
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1176,16 +1176,18 @@ public:
/*
* This creates a new tiled DrawTarget. When a tiled drawtarget is used the
* drawing is distributed over number of tiles which may each hold an
* individual offset. The tiles in the set must each have the same backend
* and format.
*/
static TemporaryRef<DrawTarget> CreateTiledDrawTarget(const TileSet& aTileSet);
+ static bool DoesBackendSupportDataDrawtarget(BackendType aType);
+
#ifdef XP_MACOSX
static TemporaryRef<DrawTarget> CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize);
static TemporaryRef<GlyphRenderingOptions>
CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor);
#endif
#ifdef WIN32
static TemporaryRef<DrawTarget> CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1269,17 +1269,17 @@ DrawTargetD2D::CreatePathBuilder(FillRul
gfxWarning() << "Failed to access Direct2D Path Geometry. Code: " << hexa(hr);
return nullptr;
}
if (aFillRule == FillRule::FILL_WINDING) {
sink->SetFillMode(D2D1_FILL_MODE_WINDING);
}
- return new PathBuilderD2D(sink, path, aFillRule);
+ return new PathBuilderD2D(sink, path, aFillRule, BackendType::DIRECT2D);
}
TemporaryRef<GradientStops>
DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
{
D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
for (uint32_t i = 0; i < aNumStops; i++) {
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -406,17 +406,17 @@ DrawTargetD2D1::StrokeLine(const Point &
}
void
DrawTargetD2D1::Stroke(const Path *aPath,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions,
const DrawOptions &aOptions)
{
- if (aPath->GetBackendType() != BackendType::DIRECT2D) {
+ if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
return;
}
const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
@@ -429,17 +429,17 @@ DrawTargetD2D1::Stroke(const Path *aPath
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
}
void
DrawTargetD2D1::Fill(const Path *aPath,
const Pattern &aPattern,
const DrawOptions &aOptions)
{
- if (aPath->GetBackendType() != BackendType::DIRECT2D) {
+ if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
return;
}
const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
@@ -555,17 +555,17 @@ DrawTargetD2D1::Mask(const Pattern &aSou
mDC->PopLayer();
FinalizeDrawing(aOptions.mCompositionOp, aSource);
}
void
DrawTargetD2D1::PushClip(const Path *aPath)
{
- if (aPath->GetBackendType() != BackendType::DIRECT2D) {
+ if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
return;
}
mCurrentClippedGeometry = nullptr;
RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
@@ -689,17 +689,17 @@ DrawTargetD2D1::CreatePathBuilder(FillRu
gfxWarning() << *this << ": Failed to access Direct2D Path Geometry. Code: " << hexa(hr);
return nullptr;
}
if (aFillRule == FillRule::FILL_WINDING) {
sink->SetFillMode(D2D1_FILL_MODE_WINDING);
}
- return new PathBuilderD2D(sink, path, aFillRule);
+ return new PathBuilderD2D(sink, path, aFillRule, BackendType::DIRECT2D1_1);
}
TemporaryRef<GradientStops>
DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
{
if (aNumStops == 0) {
gfxWarning() << *this << ": Failed to create GradientStopCollection with no stops.";
return nullptr;
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -425,16 +425,35 @@ Factory::CreateTiledDrawTarget(const Til
if (!dt->Init(aTileSet)) {
return nullptr;
}
return dt.forget();
}
+bool
+Factory::DoesBackendSupportDataDrawtarget(BackendType aType)
+{
+ switch (aType) {
+ case BackendType::DIRECT2D:
+ case BackendType::DIRECT2D1_1:
+ case BackendType::RECORDING:
+ case BackendType::NONE:
+ case BackendType::COREGRAPHICS_ACCELERATED:
+ return false;
+ case BackendType::CAIRO:
+ case BackendType::COREGRAPHICS:
+ case BackendType::SKIA:
+ return true;
+ }
+
+ return false;
+}
+
TemporaryRef<ScaledFont>
Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize)
{
switch (aNativeFont.mType) {
#ifdef WIN32
case NativeFontType::DWRITE_FONT_FACE:
{
return new ScaledFontDWrite(static_cast<IDWriteFontFace*>(aNativeFont.mFont), aSize);
@@ -625,16 +644,20 @@ Factory::SetDirect3D11Device(ID3D11Devic
{
mD3D11Device = aDevice;
if (mD2D1Device) {
mD2D1Device->Release();
mD2D1Device = nullptr;
}
+ if (!aDevice) {
+ return;
+ }
+
RefPtr<ID2D1Factory1> factory = D2DFactory1();
RefPtr<IDXGIDevice> device;
aDevice->QueryInterface((IDXGIDevice**)byRef(device));
factory->CreateDevice(device, &mD2D1Device);
}
ID3D11Device*
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -298,17 +298,17 @@ PathBuilderD2D::Finish()
}
HRESULT hr = mSink->Close();
if (FAILED(hr)) {
gfxDebug() << "Failed to close PathSink. Code: " << hexa(hr);
return nullptr;
}
- return new PathD2D(mGeometry, mFigureActive, mCurrentPoint, mFillRule);
+ return new PathD2D(mGeometry, mFigureActive, mCurrentPoint, mFillRule, mBackendType);
}
TemporaryRef<PathBuilder>
PathD2D::CopyToBuilder(FillRule aFillRule) const
{
return TransformedCopyToBuilder(Matrix(), aFillRule);
}
@@ -340,17 +340,17 @@ PathD2D::TransformedCopyToBuilder(const
D2DMatrix(aTransform),
&wrapSink);
} else {
mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
D2DMatrix(aTransform),
sink);
}
- RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule);
+ RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule, mBackendType);
pathBuilder->mCurrentPoint = aTransform * mEndPoint;
if (mEndedActive) {
pathBuilder->mFigureActive = true;
}
return pathBuilder.forget();
--- a/gfx/2d/PathD2D.h
+++ b/gfx/2d/PathD2D.h
@@ -14,21 +14,22 @@ namespace mozilla {
namespace gfx {
class PathD2D;
class PathBuilderD2D : public PathBuilder
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderD2D)
- PathBuilderD2D(ID2D1GeometrySink *aSink, ID2D1PathGeometry *aGeom, FillRule aFillRule)
+ PathBuilderD2D(ID2D1GeometrySink *aSink, ID2D1PathGeometry *aGeom, FillRule aFillRule, BackendType aBackendType)
: mSink(aSink)
, mGeometry(aGeom)
, mFigureActive(false)
, mFillRule(aFillRule)
+ , mBackendType(aBackendType)
{
}
virtual ~PathBuilderD2D();
virtual void MoveTo(const Point &aPoint);
virtual void LineTo(const Point &aPoint);
virtual void BezierTo(const Point &aCP1,
const Point &aCP2,
@@ -37,47 +38,49 @@ public:
const Point &aCP2);
virtual void Close();
virtual void Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
Float aEndAngle, bool aAntiClockwise = false);
virtual Point CurrentPoint() const;
virtual TemporaryRef<Path> Finish();
- virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; }
+ virtual BackendType GetBackendType() const { return mBackendType; }
ID2D1GeometrySink *GetSink() { return mSink; }
private:
friend class PathD2D;
void EnsureActive(const Point &aPoint);
RefPtr<ID2D1GeometrySink> mSink;
RefPtr<ID2D1PathGeometry> mGeometry;
bool mFigureActive;
Point mCurrentPoint;
Point mBeginPoint;
FillRule mFillRule;
+ BackendType mBackendType;
};
class PathD2D : public Path
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathD2D)
PathD2D(ID2D1PathGeometry *aGeometry, bool aEndedActive,
- const Point &aEndPoint, FillRule aFillRule)
+ const Point &aEndPoint, FillRule aFillRule, BackendType aBackendType)
: mGeometry(aGeometry)
, mEndedActive(aEndedActive)
, mEndPoint(aEndPoint)
, mFillRule(aFillRule)
+ , mBackendType(aBackendType)
{}
- virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; }
+ virtual BackendType GetBackendType() const { return mBackendType; }
virtual TemporaryRef<PathBuilder> CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const;
virtual TemporaryRef<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
FillRule aFillRule = FillRule::FILL_WINDING) const;
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
@@ -98,14 +101,15 @@ public:
private:
friend class DrawTargetD2D;
friend class DrawTargetD2D1;
mutable RefPtr<ID2D1PathGeometry> mGeometry;
bool mEndedActive;
Point mEndPoint;
FillRule mFillRule;
+ BackendType mBackendType;
};
}
}
#endif /* MOZILLA_GFX_PATHD2D_H_ */
--- a/gfx/2d/SourceSurfaceD2D1.cpp
+++ b/gfx/2d/SourceSurfaceD2D1.cpp
@@ -103,17 +103,23 @@ SourceSurfaceD2D1::DrawTargetWillChange(
RefPtr<ID2D1Bitmap1> oldBitmap = mRealizedBitmap;
D2D1_BITMAP_PROPERTIES1 props;
props.dpiX = 96;
props.dpiY = 96;
props.pixelFormat = D2DPixelFormat(mFormat);
props.colorContext = nullptr;
props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
- mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mRealizedBitmap));
+ HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mRealizedBitmap));
+
+ if (FAILED(hr)) {
+ gfxCriticalError() << "Failed to create bitmap to make DrawTarget copy. Size: " << mSize << " Code: " << hexa(hr);
+ MarkIndependent();
+ return;
+ }
D2D1_POINT_2U point = D2D1::Point2U(0, 0);
D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height);
mRealizedBitmap->CopyFromBitmap(&point, oldBitmap, &rect);
mImage = mRealizedBitmap;
DrawTargetD2D1::mVRAMUsageSS += mSize.width * mSize.height * BytesPerPixel(mFormat);
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1277,18 +1277,18 @@ ClientTiledLayerBuffer::ValidateTile(Til
ctxt = nullptr;
drawTarget = nullptr;
nsIntRegion tileRegion =
nsIntRect(aTileOrigin.x, aTileOrigin.y,
GetScaledTileSize().width, GetScaledTileSize().height);
// Intersect this area with the portion that's invalid.
- tileRegion = tileRegion.Sub(tileRegion, GetValidRegion());
- tileRegion = tileRegion.Sub(tileRegion, aDirtyRegion); // Has now been validated
+ tileRegion.SubOut(GetValidRegion());
+ tileRegion.SubOut(aDirtyRegion); // Has now been validated
backBuffer->SetWaste(tileRegion.Area() * mResolution * mResolution);
backBuffer->Unlock();
if (createdTextureClient) {
if (!mCompositableClient->AddTextureClient(backBuffer)) {
NS_WARNING("Failed to add tile TextureClient.");
aTile.DiscardFrontBuffer();
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1040,17 +1040,17 @@ CompositorD3D11::BeginFrame(const nsIntR
const Rect& aRenderBounds,
Rect* aClipRectOut,
Rect* aRenderBoundsOut)
{
// Don't composite if we are minimised. Other than for the sake of efficency,
// this is important because resizing our buffers when mimised will fail and
// cause a crash when we're restored.
NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
- if (::IsIconic(mHwnd)) {
+ if (::IsIconic(mHwnd) || gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
*aRenderBoundsOut = Rect();
return;
}
UpdateRenderTarget();
// Failed to create a render target or the view.
if (!mDefaultRT || !mDefaultRT->mRTView ||
@@ -1175,55 +1175,55 @@ void
CompositorD3D11::EnsureSize()
{
nsIntRect rect;
mWidget->GetClientBounds(rect);
mSize = rect.Size();
}
-void
+bool
CompositorD3D11::VerifyBufferSize()
{
DXGI_SWAP_CHAIN_DESC swapDesc;
HRESULT hr;
hr = mSwapChain->GetDesc(&swapDesc);
if (Failed(hr)) {
- return;
+ return false;
}
if ((swapDesc.BufferDesc.Width == mSize.width &&
swapDesc.BufferDesc.Height == mSize.height) ||
mSize.width <= 0 || mSize.height <= 0) {
- return;
+ return true;
}
if (mDefaultRT) {
// Make sure the texture, which belongs to the swapchain, is destroyed
// before resizing the swapchain.
if (mCurrentRT == mDefaultRT) {
mCurrentRT = nullptr;
}
MOZ_ASSERT(mDefaultRT->hasOneRef());
mDefaultRT = nullptr;
}
if (IsRunningInWindowsMetro()) {
hr = mSwapChain->ResizeBuffers(2, mSize.width, mSize.height,
DXGI_FORMAT_B8G8R8A8_UNORM,
0);
- HandleError(hr);
mDisableSequenceForNextFrame = true;
} else {
hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
DXGI_FORMAT_B8G8R8A8_UNORM,
0);
- HandleError(hr);
}
+
+ return Succeeded(hr);
}
void
CompositorD3D11::UpdateRenderTarget()
{
EnsureSize();
VerifyBufferSize();
@@ -1417,17 +1417,17 @@ CompositorD3D11::PaintToTarget()
void
CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
{
if (SUCCEEDED(hr)) {
return;
}
// XXX - It would be nice to use gfxCriticalError, but it needs to
// be made to work off the main thread first.
- MOZ_ASSERT(aSeverity != DebugAssert);
+ //MOZ_ASSERT(aSeverity != DebugAssert);
if (aSeverity == Critical) {
MOZ_CRASH("Unrecoverable D3D11 error");
}
if (mDevice && hr == DXGI_ERROR_DEVICE_REMOVED) {
hr = mDevice->GetDeviceRemovedReason();
}
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -154,17 +154,17 @@ private:
};
void HandleError(HRESULT hr, Severity aSeverity = DebugAssert);
bool Failed(HRESULT hr, Severity aSeverity = DebugAssert);
bool Succeeded(HRESULT hr, Severity aSeverity = DebugAssert);
// ensure mSize is up to date with respect to mWidget
void EnsureSize();
- void VerifyBufferSize();
+ bool VerifyBufferSize();
void UpdateRenderTarget();
bool CreateShaders();
bool UpdateConstantBuffers();
void SetSamplerForFilter(gfx::Filter aFilter);
void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
void PaintToTarget();
virtual gfx::IntSize GetWidgetSize() const MOZ_OVERRIDE { return gfx::ToIntSize(mSize); }
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -226,17 +226,17 @@ GrallocTextureHostOGL::GetRenderState()
return LayerRenderState();
}
TemporaryRef<gfx::DataSourceSurface>
GrallocTextureHostOGL::GetAsSurface() {
android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
uint8_t* grallocData;
- int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
+ graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
RefPtr<gfx::DataSourceSurface> grallocTempSurf =
gfx::Factory::CreateWrappingDataSourceSurface(grallocData,
graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()),
GetSize(), GetFormat());
RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
graphicBuffer->unlock();
--- a/gfx/thebes/VsyncSource.cpp
+++ b/gfx/thebes/VsyncSource.cpp
@@ -2,16 +2,17 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VsyncSource.h"
#include "gfxPlatform.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/VsyncDispatcher.h"
+#include "MainThreadUtils.h"
using namespace mozilla;
using namespace mozilla::gfx;
void
VsyncSource::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
{
MOZ_ASSERT(NS_IsMainThread());
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -22,17 +22,17 @@
#include "gfxPlatform.h"
#include "gfxTeeSurface.h"
#include "GeckoProfiler.h"
#include "gfx2DGlue.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/gfx/DrawTargetTiled.h"
#include <algorithm>
-#if CAIRO_HAS_DWRITE_FONT
+#if XP_WIN
#include "gfxWindowsPlatform.h"
#endif
using namespace mozilla;
using namespace mozilla::gfx;
UserDataKey gfxContext::sDontUseAsSourceKey;
@@ -1304,17 +1304,21 @@ gfxContext::PushNewDT(gfxContentType con
mDT->CreateSimilarDrawTarget(IntSize(int32_t(clipBounds.width), int32_t(clipBounds.height)),
format);
if (!newDT) {
NS_WARNING("Failed to create DrawTarget of sufficient size.");
newDT = mDT->CreateSimilarDrawTarget(IntSize(64, 64), format);
if (!newDT) {
- if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+ if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()
+#ifdef XP_WIN
+ && !(mDT->GetBackendType() == BackendType::DIRECT2D1_1 && !gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice())
+#endif
+ ) {
// If even this fails.. we're most likely just out of memory!
NS_ABORT_OOM(BytesPerPixel(format) * 64 * 64);
}
newDT = CurrentState().drawTarget;
}
}
Save();
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -687,17 +687,17 @@ public:
beginning = end + 1;
if (!(end = strchr(beginning, ';'))) {
break;
}
uint32_t filesize = strtoul(beginning, nullptr, 10);
FNCMapEntry* mapEntry =
static_cast<FNCMapEntry*>
- (PL_DHashTableOperate(&mMap, filename.get(), PL_DHASH_ADD));
+ (PL_DHashTableAdd(&mMap, filename.get()));
if (mapEntry) {
mapEntry->mFilename.Assign(filename);
mapEntry->mTimestamp = timestamp;
mapEntry->mFilesize = filesize;
mapEntry->mFaces.Assign(faceList);
// entries from the startupcache are marked "non-existing"
// until we have confirmed that the file still exists
mapEntry->mFileExists = false;
@@ -714,17 +714,17 @@ public:
virtual void
GetInfoForFile(const nsCString& aFileName, nsCString& aFaceList,
uint32_t *aTimestamp, uint32_t *aFilesize)
{
if (!mMap.ops) {
return;
}
PLDHashEntryHdr *hdr =
- PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_LOOKUP);
+ PL_DHashTableLookup(&mMap, aFileName.get());
if (!hdr) {
return;
}
FNCMapEntry* entry = static_cast<FNCMapEntry*>(hdr);
if (entry && entry->mFilesize) {
*aTimestamp = entry->mTimestamp;
*aFilesize = entry->mFilesize;
aFaceList.Assign(entry->mFaces);
@@ -739,17 +739,17 @@ public:
CacheFileInfo(const nsCString& aFileName, const nsCString& aFaceList,
uint32_t aTimestamp, uint32_t aFilesize)
{
if (!mMap.ops) {
return;
}
FNCMapEntry* entry =
static_cast<FNCMapEntry*>
- (PL_DHashTableOperate(&mMap, aFileName.get(), PL_DHASH_ADD));
+ (PL_DHashTableAdd(&mMap, aFileName.get()));
if (entry) {
entry->mFilename.Assign(aFileName);
entry->mTimestamp = aTimestamp;
entry->mFilesize = aFilesize;
entry->mFaces.Assign(aFaceList);
entry->mFileExists = true;
}
mWriteNeeded = true;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1177,26 +1177,26 @@ gfxPlatform::CreateOffscreenContentDrawT
return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
}
TemporaryRef<DrawTarget>
gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
{
NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
- RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(mContentBackend,
+ BackendType backendType = mContentBackend;
+
+ if (!Factory::DoesBackendSupportDataDrawtarget(mContentBackend)) {
+ backendType = BackendType::CAIRO;
+ }
+
+ RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
aData, aSize,
aStride, aFormat);
- if (!dt) {
- // Factory::CreateDrawTargetForData does not support mContentBackend; retry
- // with BackendType::CAIRO:
- dt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
- aData, aSize,
- aStride, aFormat);
- }
+
return dt.forget();
}
/* static */ BackendType
gfxPlatform::BackendTypeForName(const nsCString& aName)
{
if (aName.EqualsLiteral("cairo"))
return BackendType::CAIRO;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -18,16 +18,17 @@
#include "mozilla/WindowsVersion.h"
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsIWindowsRegKey.h"
#include "nsIFile.h"
#include "plbase64.h"
#include "nsIXULRuntime.h"
+#include "imgLoader.h"
#include "nsIGfxInfo.h"
#include "GfxDriverInfo.h"
#include "gfxCrashReporterUtils.h"
#include "gfxGDIFontList.h"
#include "gfxGDIFont.h"
@@ -379,16 +380,27 @@ gfxWindowsPlatform::GetDPIScale()
}
void
gfxWindowsPlatform::UpdateRenderMode()
{
/* Pick the default render mode for
* desktop.
*/
+ if (DidRenderingDeviceReset()) {
+ mD3D11DeviceInitialized = false;
+ mD3D11Device = nullptr;
+ mD3D11ContentDevice = nullptr;
+ mAdapter = nullptr;
+
+ imgLoader::Singleton()->ClearCache(true);
+ imgLoader::Singleton()->ClearCache(false);
+ Factory::SetDirect3D11Device(nullptr);
+ }
+
mRenderMode = RENDER_GDI;
bool isVistaOrHigher = IsVistaOrLater();
bool safeMode = false;
nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
if (xr)
xr->GetInSafeMode(&safeMode);
@@ -1030,17 +1042,32 @@ gfxWindowsPlatform::IsFontFormatSupporte
// no format hint set, need to look at data
return true;
}
bool
gfxWindowsPlatform::DidRenderingDeviceReset()
{
- return GetD3D10Device() && GetD3D10Device()->GetDeviceRemovedReason() != S_OK;
+ if (mD3D11Device) {
+ if (mD3D11Device->GetDeviceRemovedReason() != S_OK) {
+ return true;
+ }
+ }
+ if (mD3D11ContentDevice) {
+ if (mD3D11ContentDevice->GetDeviceRemovedReason() != S_OK) {
+ return true;
+ }
+ }
+ if (GetD3D10Device()) {
+ if (GetD3D10Device()->GetDeviceRemovedReason() != S_OK) {
+ return true;
+ }
+ }
+ return false;
}
gfxFontFamily *
gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
{
return gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
}
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -43,16 +43,17 @@
#include "base/message_loop.h"
#include "Hal.h"
#include "HalImpl.h"
#include "HalLog.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/battery/Constants.h"
+#include "mozilla/DebugOnly.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Preferences.h"
#include "nsAlgorithm.h"
#include "nsPrintfCString.h"
@@ -524,17 +525,17 @@ GetCurrentBatteryCharge(int* aCharge)
#endif
return (*aCharge >= 0) && (*aCharge <= 100);
}
static bool
GetCurrentBatteryCharging(int* aCharging)
{
- static const int BATTERY_NOT_CHARGING = 0;
+ static const DebugOnly<int> BATTERY_NOT_CHARGING = 0;
static const int BATTERY_CHARGING_USB = 1;
static const int BATTERY_CHARGING_AC = 2;
// Generic device support
int chargingSrc;
bool success =
ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc);
@@ -1308,18 +1309,18 @@ EnsureKernelLowMemKillerParamsSet()
// notify_trigger is a single integer. If we set notify_trigger=Z, then
// we'll get notified when there are fewer than Z pages of memory free. (See
// GonkMemoryPressureMonitoring.cpp.)
// Build the adj and minfree strings.
nsAutoCString adjParams;
nsAutoCString minfreeParams;
- int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
- int32_t lowerBoundOfNextKillUnderKB = 0;
+ DebugOnly<int32_t> lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
+ DebugOnly<int32_t> lowerBoundOfNextKillUnderKB = 0;
int32_t countOfLowmemorykillerParametersSets = 0;
long page_size = sysconf(_SC_PAGESIZE);
for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) {
// The system doesn't function correctly if we're missing these prefs, so
// crash loudly.
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -139,19 +139,19 @@ nsBMPDecoder::FinishInternal()
// Send notifications if appropriate
if (!IsSizeDecode() && HasSize()) {
// Invalidate
nsIntRect r(0, 0, mBIH.width, GetHeight());
PostInvalidation(r);
if (mUseAlphaData) {
- PostFrameStop(FrameBlender::kFrameHasAlpha);
+ PostFrameStop(Opacity::SOME_TRANSPARENCY);
} else {
- PostFrameStop(FrameBlender::kFrameOpaque);
+ PostFrameStop(Opacity::OPAQUE);
}
PostDecodeDone();
}
}
// ----------------------------------------
// Actual Data Processing
// ----------------------------------------
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -211,17 +211,17 @@ nsGIFDecoder2::BeginImageFrame(uint16_t
mCurrentFrameIndex = mGIFStruct.images_decoded;
}
//******************************************************************************
void
nsGIFDecoder2::EndImageFrame()
{
- FrameBlender::FrameAlpha alpha = FrameBlender::kFrameHasAlpha;
+ Opacity opacity = Opacity::SOME_TRANSPARENCY;
// First flush all pending image data
if (!mGIFStruct.images_decoded) {
// Only need to flush first frame
FlushImageData();
// If the first frame is smaller in height than the entire image, send an
// invalidation for the area it does not have data for.
@@ -230,17 +230,17 @@ nsGIFDecoder2::EndImageFrame()
if (realFrameHeight < mGIFStruct.screen_height) {
nsIntRect r(0, realFrameHeight,
mGIFStruct.screen_width,
mGIFStruct.screen_height - realFrameHeight);
PostInvalidation(r);
}
// This transparency check is only valid for first frame
if (mGIFStruct.is_transparent && !mSawTransparency) {
- alpha = FrameBlender::kFrameOpaque;
+ opacity = Opacity::OPAQUE;
}
}
mCurrentRow = mLastFlushedRow = -1;
mCurrentPass = mLastFlushedPass = 0;
// Only add frame if we have any rows at all
if (mGIFStruct.rows_remaining != mGIFStruct.height) {
if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
@@ -254,18 +254,18 @@ nsGIFDecoder2::EndImageFrame()
// Unconditionally increment images_decoded, because we unconditionally
// append frames in BeginImageFrame(). This ensures that images_decoded
// always refers to the frame in mImage we're currently decoding,
// even if some of them weren't decoded properly and thus are blank.
mGIFStruct.images_decoded++;
// Tell the superclass we finished a frame
- PostFrameStop(alpha,
- FrameBlender::FrameDisposalMethod(mGIFStruct.disposal_method),
+ PostFrameStop(opacity,
+ DisposalMethod(mGIFStruct.disposal_method),
mGIFStruct.delay_time);
// Reset the transparent pixel
if (mOldColor) {
mColormap[mGIFStruct.tpixel] = mOldColor;
mOldColor = 0;
}
@@ -825,20 +825,19 @@ nsGIFDecoder2::WriteInternal(const char*
mGIFStruct.disposal_method = ((*q) >> 2) & 0x7;
// Some specs say 3rd bit (value 4), other specs say value 3
// Let's choose 3 (the more popular)
if (mGIFStruct.disposal_method == 4) {
mGIFStruct.disposal_method = 3;
}
{
- int32_t method =
- FrameBlender::FrameDisposalMethod(mGIFStruct.disposal_method);
- if (method == FrameBlender::kDisposeClearAll ||
- method == FrameBlender::kDisposeClear) {
+ DisposalMethod method = DisposalMethod(mGIFStruct.disposal_method);
+ if (method == DisposalMethod::CLEAR_ALL ||
+ method == DisposalMethod::CLEAR) {
// We may have to display the background under this image during
// animation playback, so we regard it as transparent.
PostHasTransparency();
}
}
mGIFStruct.delay_time = GETINT16(q + 1) * 10;
GETN(1, gif_consume_block);
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -575,17 +575,17 @@ nsJPEGDecoder::ReadOrientationFromEXIF()
EXIFData exif = EXIFParser::Parse(marker->data,
static_cast<uint32_t>(marker->data_length));
return exif.orientation;
}
void
nsJPEGDecoder::NotifyDone()
{
- PostFrameStop(FrameBlender::kFrameOpaque);
+ PostFrameStop(Opacity::OPAQUE);
PostDecodeDone();
}
void
nsJPEGDecoder::OutputScanlines(bool* suspend)
{
*suspend = false;
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -49,25 +49,25 @@ GetPNGDecoderAccountingLog()
#endif
// For size decodes
#define WIDTH_OFFSET 16
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
- : mDispose(FrameBlender::kDisposeKeep)
- , mBlend(FrameBlender::kBlendOver)
+ : mDispose(DisposalMethod::KEEP)
+ , mBlend(BlendMethod::OVER)
, mTimeout(0)
{ }
#ifdef PNG_APNG_SUPPORTED
nsPNGDecoder::AnimFrameInfo::AnimFrameInfo(png_structp aPNG, png_infop aInfo)
- : mDispose(FrameBlender::kDisposeKeep)
- , mBlend(FrameBlender::kBlendOver)
+ : mDispose(DisposalMethod::KEEP)
+ , mBlend(BlendMethod::OVER)
, mTimeout(0)
{
png_uint_16 delay_num, delay_den;
// delay, in seconds is delay_num/delay_den
png_byte dispose_op;
png_byte blend_op;
delay_num = png_get_next_frame_delay_num(aPNG, aInfo);
delay_den = png_get_next_frame_delay_den(aPNG, aInfo);
@@ -83,27 +83,27 @@ nsPNGDecoder::AnimFrameInfo::AnimFrameIn
// Need to cast delay_num to float to have a proper division and
// the result to int to avoid compiler warning
mTimeout = static_cast<int32_t>(static_cast<double>(delay_num) *
1000 / delay_den);
}
if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) {
- mDispose = FrameBlender::kDisposeRestorePrevious;
+ mDispose = DisposalMethod::RESTORE_PREVIOUS;
} else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) {
- mDispose = FrameBlender::kDisposeClear;
+ mDispose = DisposalMethod::CLEAR;
} else {
- mDispose = FrameBlender::kDisposeKeep;
+ mDispose = DisposalMethod::KEEP;
}
if (blend_op == PNG_BLEND_OP_SOURCE) {
- mBlend = FrameBlender::kBlendSource;
+ mBlend = BlendMethod::SOURCE;
} else {
- mBlend = FrameBlender::kBlendOver;
+ mBlend = BlendMethod::OVER;
}
}
#endif
// First 8 bytes of a PNG file
const uint8_t
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
@@ -180,17 +180,17 @@ void nsPNGDecoder::CreateFrame(png_uint_
"image frame with %dx%d pixels in container %p",
width, height,
&mImage));
#ifdef PNG_APNG_SUPPORTED
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
mAnimInfo = AnimFrameInfo(mPNG, mInfo);
- if (mAnimInfo.mDispose == FrameBlender::kDisposeClear) {
+ if (mAnimInfo.mDispose == DisposalMethod::CLEAR) {
// We may have to display the background under this image during
// animation playback, so we regard it as transparent.
PostHasTransparency();
}
}
#endif
}
@@ -199,33 +199,33 @@ void
nsPNGDecoder::EndImageFrame()
{
if (mFrameIsHidden) {
return;
}
mNumFrames++;
- FrameBlender::FrameAlpha alpha;
+ Opacity opacity;
if (mFrameHasNoAlpha) {
- alpha = FrameBlender::kFrameOpaque;
+ opacity = Opacity::OPAQUE;
} else {
- alpha = FrameBlender::kFrameHasAlpha;
+ opacity = Opacity::SOME_TRANSPARENCY;
}
#ifdef PNG_APNG_SUPPORTED
uint32_t numFrames = GetFrameCount();
// We can't use mPNG->num_frames_read as it may be one ahead.
if (numFrames > 1) {
PostInvalidation(mFrameRect);
}
#endif
- PostFrameStop(alpha, mAnimInfo.mDispose, mAnimInfo.mTimeout,
+ PostFrameStop(opacity, mAnimInfo.mDispose, mAnimInfo.mTimeout,
mAnimInfo.mBlend);
}
void
nsPNGDecoder::InitInternal()
{
// For size decodes, we don't need to initialize the png decoder
if (IsSizeDecode()) {
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -93,18 +93,18 @@ public:
struct AnimFrameInfo
{
AnimFrameInfo();
#ifdef PNG_APNG_SUPPORTED
AnimFrameInfo(png_structp aPNG, png_infop aInfo);
#endif
- FrameBlender::FrameDisposalMethod mDispose;
- FrameBlender::FrameBlendMethod mBlend;
+ DisposalMethod mDispose;
+ BlendMethod mBlend;
int32_t mTimeout;
};
AnimFrameInfo mAnimInfo;
// The number of frames we've finished.
uint32_t mNumFrames;
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -328,34 +328,34 @@ Decoder::PostFrameStart()
// Decoder implementations should only call this method if they successfully
// appended the frame to the image. So mFrameCount should always match that
// reported by the Image.
MOZ_ASSERT(mFrameCount == mImage.GetNumFrames(),
"Decoder frame count doesn't match image's!");
}
void
-Decoder::PostFrameStop(FrameBlender::FrameAlpha aFrameAlpha /* = FrameBlender::kFrameHasAlpha */,
- FrameBlender::FrameDisposalMethod aDisposalMethod /* = FrameBlender::kDisposeKeep */,
+Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */,
+ DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
int32_t aTimeout /* = 0 */,
- FrameBlender::FrameBlendMethod aBlendMethod /* = FrameBlender::kBlendOver */)
+ BlendMethod aBlendMethod /* = BlendMethod::OVER */)
{
// We should be mid-frame
MOZ_ASSERT(!IsSizeDecode(), "Stopping frame during a size decode");
MOZ_ASSERT(mInFrame, "Stopping frame when we didn't start one");
MOZ_ASSERT(mCurrentFrame, "Stopping frame when we don't have one");
// Update our state
mInFrame = false;
- if (aFrameAlpha == FrameBlender::kFrameOpaque) {
+ if (aFrameOpacity == Opacity::OPAQUE) {
mCurrentFrame->SetHasNoAlpha();
}
- mCurrentFrame->SetFrameDisposalMethod(aDisposalMethod);
+ mCurrentFrame->SetDisposalMethod(aDisposalMethod);
mCurrentFrame->SetRawTimeout(aTimeout);
mCurrentFrame->SetBlendMethod(aBlendMethod);
mCurrentFrame->ImageUpdated(mCurrentFrame->GetRect());
mProgress |= FLAG_FRAME_COMPLETE | FLAG_ONLOAD_UNBLOCKED;
}
void
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -1,16 +1,17 @@
/* -*- 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 MOZILLA_IMAGELIB_DECODER_H_
#define MOZILLA_IMAGELIB_DECODER_H_
+#include "FrameAnimator.h"
#include "RasterImage.h"
#include "mozilla/RefPtr.h"
#include "DecodePool.h"
#include "ImageMetadata.h"
#include "Orientation.h"
#include "mozilla/Telemetry.h"
namespace mozilla {
@@ -221,35 +222,35 @@ protected:
Orientation aOrientation = Orientation());
// Called by decoders if they determine that the image has transparency.
//
// This should be fired as early as possible to allow observers to do things
// that affect content, so it's necessarily pessimistic - if there's a
// possibility that the image has transparency, for example because its header
// specifies that it has an alpha channel, we fire PostHasTransparency
- // immediately. PostFrameStop's aFrameAlpha argument, on the other hand, is
+ // immediately. PostFrameStop's aFrameOpacity argument, on the other hand, is
// only used internally to ImageLib. Because PostFrameStop isn't delivered
// until the entire frame has been decoded, decoders may take into account the
// actual contents of the frame and give a more accurate result.
void PostHasTransparency();
// Called by decoders when they begin a frame. Informs the image, sends
// notifications, and does internal book-keeping.
void PostFrameStart();
// Called by decoders when they end a frame. Informs the image, sends
// notifications, and does internal book-keeping.
// Specify whether this frame is opaque as an optimization.
// For animated images, specify the disposal, blend method and timeout for
// this frame.
- void PostFrameStop(FrameBlender::FrameAlpha aFrameAlpha = FrameBlender::kFrameHasAlpha,
- FrameBlender::FrameDisposalMethod aDisposalMethod = FrameBlender::kDisposeKeep,
+ void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
+ DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
int32_t aTimeout = 0,
- FrameBlender::FrameBlendMethod aBlendMethod = FrameBlender::kBlendOver);
+ BlendMethod aBlendMethod = BlendMethod::OVER);
// Called by the decoders when they have a region to invalidate. We may not
// actually pass these invalidations on right away.
void PostInvalidation(nsIntRect& aRect);
// Called by the decoders when they have successfully decoded the image. This
// may occur as the result of the decoder getting to the appropriate point in
// the stream, or by us calling FinishInternal().
--- a/image/src/FrameAnimator.cpp
+++ b/image/src/FrameAnimator.cpp
@@ -1,20 +1,27 @@
/* -*- 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 "FrameAnimator.h"
-#include "FrameBlender.h"
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
+#include "imgIContainer.h"
+#include "MainThreadUtils.h"
#include "RasterImage.h"
-#include "imgIContainer.h"
+#include "pixman.h"
namespace mozilla {
+
+using namespace gfx;
+
namespace image {
int32_t
FrameAnimator::GetSingleLoopTime() const
{
// If we aren't done decoding, we don't know the image's full play time.
if (!mDoneDecoding) {
return -1;
@@ -22,17 +29,17 @@ FrameAnimator::GetSingleLoopTime() const
// If we're not looping, a single loop time has no meaning
if (mAnimationMode != imgIContainer::kNormalAnimMode) {
return -1;
}
uint32_t looptime = 0;
for (uint32_t i = 0; i < mImage->GetNumFrames(); ++i) {
- int32_t timeout = mFrameBlender.GetTimeoutForFrame(i);
+ int32_t timeout = GetTimeoutForFrame(i);
if (timeout >= 0) {
looptime += static_cast<uint32_t>(timeout);
} else {
// If we have a frame that never times out, we're probably in an error
// case, but let's handle it more gracefully.
NS_WARNING("Negative frame timeout - how did this happen?");
return -1;
}
@@ -41,17 +48,17 @@ FrameAnimator::GetSingleLoopTime() const
return looptime;
}
TimeStamp
FrameAnimator::GetCurrentImgFrameEndTime() const
{
TimeStamp currentFrameTime = mCurrentAnimationFrameTime;
int32_t timeout =
- mFrameBlender.GetTimeoutForFrame(mCurrentAnimationFrameIndex);
+ GetTimeoutForFrame(mCurrentAnimationFrameIndex);
if (timeout < 0) {
// We need to return a sentinel value in this case, because our logic
// doesn't work correctly if we have a negative timeout value. We use
// one year in the future as the sentinel because it works with the loop
// in RequestRefresh() below.
// XXX(seth): It'd be preferable to make our logic work correctly with
// negative timeouts.
@@ -72,17 +79,17 @@ FrameAnimator::AdvanceFrame(TimeStamp aT
NS_ASSERTION(aTime <= TimeStamp::Now(),
"Given time appears to be in the future");
uint32_t currentFrameIndex = mCurrentAnimationFrameIndex;
uint32_t nextFrameIndex = currentFrameIndex + 1;
int32_t timeout = 0;
RefreshResult ret;
- RawAccessFrameRef nextFrame = mFrameBlender.GetRawFrame(nextFrameIndex);
+ RawAccessFrameRef nextFrame = GetRawFrame(nextFrameIndex);
// If we're done decoding, we know we've got everything we're going to get.
// If we aren't, we only display fully-downloaded frames; everything else
// gets delayed.
bool canDisplay = mDoneDecoding || (nextFrame && nextFrame->ImageComplete());
if (!canDisplay) {
// Uh oh, the frame we want to show is currently being decoded (partial)
@@ -91,56 +98,56 @@ FrameAnimator::AdvanceFrame(TimeStamp aT
}
// If we're done decoding the next frame, go ahead and display it now and
// reinit with the next frame's delay time.
if (mImage->GetNumFrames() == nextFrameIndex) {
// End of an animation loop...
// If we are not looping forever, initialize the loop counter
- if (mLoopCounter < 0 && mFrameBlender.LoopCount() >= 0) {
- mLoopCounter = mFrameBlender.LoopCount();
+ if (mLoopRemainingCount < 0 && LoopCount() >= 0) {
+ mLoopRemainingCount = LoopCount();
}
// If animation mode is "loop once", or we're at end of loop counter,
- // it's time to stop animating
+ // it's time to stop animating.
if (mAnimationMode == imgIContainer::kLoopOnceAnimMode ||
- mLoopCounter == 0) {
+ mLoopRemainingCount == 0) {
ret.animationFinished = true;
}
nextFrameIndex = 0;
- if (mLoopCounter > 0) {
- mLoopCounter--;
+ if (mLoopRemainingCount > 0) {
+ mLoopRemainingCount--;
}
// If we're done, exit early.
if (ret.animationFinished) {
return ret;
}
}
- timeout = mFrameBlender.GetTimeoutForFrame(nextFrameIndex);
+ timeout = GetTimeoutForFrame(nextFrameIndex);
// Bad data
if (timeout < 0) {
ret.animationFinished = true;
ret.error = true;
}
if (nextFrameIndex == 0) {
ret.dirtyRect = mFirstFrameRefreshArea;
} else {
// Change frame
if (nextFrameIndex != currentFrameIndex + 1) {
- nextFrame = mFrameBlender.GetRawFrame(nextFrameIndex);
+ nextFrame = GetRawFrame(nextFrameIndex);
}
- if (!mFrameBlender.DoBlend(&ret.dirtyRect, currentFrameIndex,
+ if (!DoBlend(&ret.dirtyRect, currentFrameIndex,
nextFrameIndex)) {
// something went wrong, move on to next
NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed");
nextFrame->SetCompositingFailed(true);
mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime();
mCurrentAnimationFrameIndex = nextFrameIndex;
ret.error = true;
@@ -205,16 +212,17 @@ FrameAnimator::RequestRefresh(const Time
return ret;
}
void
FrameAnimator::ResetAnimation()
{
mCurrentAnimationFrameIndex = 0;
+ mLastCompositedFrameIndex = -1;
}
void
FrameAnimator::SetDoneDecoding(bool aDone)
{
mDoneDecoding = aDone;
}
@@ -257,10 +265,508 @@ FrameAnimator::GetCurrentAnimationFrameI
}
nsIntRect
FrameAnimator::GetFirstFrameRefreshArea() const
{
return mFirstFrameRefreshArea;
}
+DrawableFrameRef
+FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
+{
+ MOZ_ASSERT(aFrameNum != 0, "First frame is never composited");
+
+ // If we have a composited version of this frame, return that.
+ if (mLastCompositedFrameIndex == int32_t(aFrameNum)) {
+ return mCompositingFrame->DrawableRef();
+ }
+
+ // Otherwise return the raw frame. DoBlend is required to ensure that we only
+ // hit this case if the frame is not paletted and doesn't require compositing.
+ DrawableFrameRef ref =
+ SurfaceCache::Lookup(ImageKey(mImage),
+ RasterSurfaceKey(mSize,
+ 0, // Default decode flags.
+ aFrameNum));
+ MOZ_ASSERT(!ref || !ref->GetIsPaletted(), "About to return a paletted frame");
+ return ref;
+}
+
+int32_t
+FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const
+{
+ RawAccessFrameRef frame = GetRawFrame(aFrameNum);
+ const int32_t timeout = frame->GetRawTimeout();
+
+ // Ensure a minimal time between updates so we don't throttle the UI thread.
+ // consider 0 == unspecified and make it fast but not too fast. Unless we
+ // have a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug
+ // 207059. The behavior of recent IE and Opera versions seems to be:
+ // IE 6/Win:
+ // 10 - 50ms go 100ms
+ // >50ms go correct speed
+ // Opera 7 final/Win:
+ // 10ms goes 100ms
+ // >10ms go correct speed
+ // It seems that there are broken tools out there that set a 0ms or 10ms
+ // timeout when they really want a "default" one. So munge values in that
+ // range.
+ if (timeout >= 0 && timeout <= 10 && mLoopCount != 0) {
+ return 100;
+ }
+
+ return timeout;
+}
+
+size_t
+FrameAnimator::SizeOfCompositingFrames(gfxMemoryLocation aLocation,
+ MallocSizeOf aMallocSizeOf) const
+{
+ size_t n = 0;
+
+ if (mCompositingFrame) {
+ n += mCompositingFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf);
+ }
+ if (mCompositingPrevFrame) {
+ n += mCompositingPrevFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf);
+ }
+
+ return n;
+}
+
+RawAccessFrameRef
+FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
+{
+ DrawableFrameRef ref =
+ SurfaceCache::Lookup(ImageKey(mImage),
+ RasterSurfaceKey(mSize,
+ 0, // Default decode flags.
+ aFrameNum));
+ return ref ? ref->RawAccessRef()
+ : RawAccessFrameRef();
+}
+
+//******************************************************************************
+// DoBlend gets called when the timer for animation get fired and we have to
+// update the composited frame of the animation.
+bool
+FrameAnimator::DoBlend(nsIntRect* aDirtyRect,
+ uint32_t aPrevFrameIndex,
+ uint32_t aNextFrameIndex)
+{
+ RawAccessFrameRef prevFrame = GetRawFrame(aPrevFrameIndex);
+ RawAccessFrameRef nextFrame = GetRawFrame(aNextFrameIndex);
+
+ MOZ_ASSERT(prevFrame && nextFrame, "Should have frames here");
+
+ DisposalMethod prevFrameDisposalMethod = prevFrame->GetDisposalMethod();
+ if (prevFrameDisposalMethod == DisposalMethod::RESTORE_PREVIOUS &&
+ !mCompositingPrevFrame) {
+ prevFrameDisposalMethod = DisposalMethod::CLEAR;
+ }
+
+ nsIntRect prevFrameRect = prevFrame->GetRect();
+ bool isFullPrevFrame = (prevFrameRect.x == 0 && prevFrameRect.y == 0 &&
+ prevFrameRect.width == mSize.width &&
+ prevFrameRect.height == mSize.height);
+
+ // Optimization: DisposeClearAll if the previous frame is the same size as
+ // container and it's clearing itself
+ if (isFullPrevFrame &&
+ (prevFrameDisposalMethod == DisposalMethod::CLEAR)) {
+ prevFrameDisposalMethod = DisposalMethod::CLEAR_ALL;
+ }
+
+ DisposalMethod nextFrameDisposalMethod = nextFrame->GetDisposalMethod();
+ nsIntRect nextFrameRect = nextFrame->GetRect();
+ bool isFullNextFrame = (nextFrameRect.x == 0 && nextFrameRect.y == 0 &&
+ nextFrameRect.width == mSize.width &&
+ nextFrameRect.height == mSize.height);
+
+ if (!nextFrame->GetIsPaletted()) {
+ // Optimization: Skip compositing if the previous frame wants to clear the
+ // whole image
+ if (prevFrameDisposalMethod == DisposalMethod::CLEAR_ALL) {
+ aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
+ return true;
+ }
+
+ // Optimization: Skip compositing if this frame is the same size as the
+ // container and it's fully drawing over prev frame (no alpha)
+ if (isFullNextFrame &&
+ (nextFrameDisposalMethod != DisposalMethod::RESTORE_PREVIOUS) &&
+ !nextFrame->GetHasAlpha()) {
+ aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
+ return true;
+ }
+ }
+
+ // Calculate area that needs updating
+ switch (prevFrameDisposalMethod) {
+ default:
+ case DisposalMethod::NOT_SPECIFIED:
+ case DisposalMethod::KEEP:
+ *aDirtyRect = nextFrameRect;
+ break;
+
+ case DisposalMethod::CLEAR_ALL:
+ // Whole image container is cleared
+ aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
+ break;
+
+ case DisposalMethod::CLEAR:
+ // Calc area that needs to be redrawn (the combination of previous and
+ // this frame)
+ // XXX - This could be done with multiple framechanged calls
+ // Having prevFrame way at the top of the image, and nextFrame
+ // way at the bottom, and both frames being small, we'd be
+ // telling framechanged to refresh the whole image when only two
+ // small areas are needed.
+ aDirtyRect->UnionRect(nextFrameRect, prevFrameRect);
+ break;
+
+ case DisposalMethod::RESTORE_PREVIOUS:
+ aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
+ break;
+ }
+
+ // Optimization:
+ // Skip compositing if the last composited frame is this frame
+ // (Only one composited frame was made for this animation. Example:
+ // Only Frame 3 of a 10 frame image required us to build a composite frame
+ // On the second loop, we do not need to rebuild the frame
+ // since it's still sitting in compositingFrame)
+ if (mLastCompositedFrameIndex == int32_t(aNextFrameIndex)) {
+ return true;
+ }
+
+ bool needToBlankComposite = false;
+
+ // Create the Compositing Frame
+ if (!mCompositingFrame) {
+ nsRefPtr<imgFrame> newFrame = new imgFrame;
+ nsresult rv = newFrame->InitForDecoder(ThebesIntSize(mSize),
+ SurfaceFormat::B8G8R8A8);
+ if (NS_FAILED(rv)) {
+ mCompositingFrame.reset();
+ return false;
+ }
+ mCompositingFrame = newFrame->RawAccessRef();
+ needToBlankComposite = true;
+ } else if (int32_t(aNextFrameIndex) != mLastCompositedFrameIndex+1) {
+
+ // If we are not drawing on top of last composited frame,
+ // then we are building a new composite frame, so let's clear it first.
+ needToBlankComposite = true;
+ }
+
+ // More optimizations possible when next frame is not transparent
+ // But if the next frame has DisposalMethod::RESTORE_PREVIOUS,
+ // this "no disposal" optimization is not possible,
+ // because the frame in "after disposal operation" state
+ // needs to be stored in compositingFrame, so it can be
+ // copied into compositingPrevFrame later.
+ bool doDisposal = true;
+ if (!nextFrame->GetHasAlpha() &&
+ nextFrameDisposalMethod != DisposalMethod::RESTORE_PREVIOUS) {
+ if (isFullNextFrame) {
+ // Optimization: No need to dispose prev.frame when
+ // next frame is full frame and not transparent.
+ doDisposal = false;
+ // No need to blank the composite frame
+ needToBlankComposite = false;
+ } else {
+ if ((prevFrameRect.x >= nextFrameRect.x) &&
+ (prevFrameRect.y >= nextFrameRect.y) &&
+ (prevFrameRect.x + prevFrameRect.width <=
+ nextFrameRect.x + nextFrameRect.width) &&
+ (prevFrameRect.y + prevFrameRect.height <=
+ nextFrameRect.y + nextFrameRect.height)) {
+ // Optimization: No need to dispose prev.frame when
+ // next frame fully overlaps previous frame.
+ doDisposal = false;
+ }
+ }
+ }
+
+ if (doDisposal) {
+ // Dispose of previous: clear, restore, or keep (copy)
+ switch (prevFrameDisposalMethod) {
+ case DisposalMethod::CLEAR:
+ if (needToBlankComposite) {
+ // If we just created the composite, it could have anything in its
+ // buffer. Clear whole frame
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ } else {
+ // Only blank out previous frame area (both color & Mask/Alpha)
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect(),
+ prevFrameRect);
+ }
+ break;
+
+ case DisposalMethod::CLEAR_ALL:
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ break;
+
+ case DisposalMethod::RESTORE_PREVIOUS:
+ // It would be better to copy only the area changed back to
+ // compositingFrame.
+ if (mCompositingPrevFrame) {
+ CopyFrameImage(mCompositingPrevFrame->GetRawData(),
+ mCompositingPrevFrame->GetRect(),
+ mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+
+ // destroy only if we don't need it for this frame's disposal
+ if (nextFrameDisposalMethod !=
+ DisposalMethod::RESTORE_PREVIOUS) {
+ mCompositingPrevFrame.reset();
+ }
+ } else {
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ }
+ break;
+
+ default:
+ // Copy previous frame into compositingFrame before we put the new
+ // frame on top
+ // Assumes that the previous frame represents a full frame (it could be
+ // smaller in size than the container, as long as the frame before it
+ // erased itself)
+ // Note: Frame 1 never gets into DoBlend(), so (aNextFrameIndex - 1)
+ // will always be a valid frame number.
+ if (mLastCompositedFrameIndex != int32_t(aNextFrameIndex - 1)) {
+ if (isFullPrevFrame && !prevFrame->GetIsPaletted()) {
+ // Just copy the bits
+ CopyFrameImage(prevFrame->GetRawData(),
+ prevFrame->GetRect(),
+ mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ } else {
+ if (needToBlankComposite) {
+ // Only blank composite when prev is transparent or not full.
+ if (prevFrame->GetHasAlpha() || !isFullPrevFrame) {
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ }
+ }
+ DrawFrameTo(prevFrame->GetRawData(), prevFrameRect,
+ prevFrame->PaletteDataLength(),
+ prevFrame->GetHasAlpha(),
+ mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect(),
+ prevFrame->GetBlendMethod());
+ }
+ }
+ }
+ } else if (needToBlankComposite) {
+ // If we just created the composite, it could have anything in its
+ // buffers. Clear them
+ ClearFrame(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect());
+ }
+
+ // Check if the frame we are composing wants the previous image restored after
+ // it is done. Don't store it (again) if last frame wanted its image restored
+ // too
+ if ((nextFrameDisposalMethod == DisposalMethod::RESTORE_PREVIOUS) &&
+ (prevFrameDisposalMethod != DisposalMethod::RESTORE_PREVIOUS)) {
+ // We are storing the whole image.
+ // It would be better if we just stored the area that nextFrame is going to
+ // overwrite.
+ if (!mCompositingPrevFrame) {
+ nsRefPtr<imgFrame> newFrame = new imgFrame;
+ nsresult rv = newFrame->InitForDecoder(ThebesIntSize(mSize),
+ SurfaceFormat::B8G8R8A8);
+ if (NS_FAILED(rv)) {
+ mCompositingPrevFrame.reset();
+ return false;
+ }
+
+ mCompositingPrevFrame = newFrame->RawAccessRef();
+ }
+
+ CopyFrameImage(mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect(),
+ mCompositingPrevFrame->GetRawData(),
+ mCompositingPrevFrame->GetRect());
+ }
+
+ // blit next frame into it's correct spot
+ DrawFrameTo(nextFrame->GetRawData(), nextFrameRect,
+ nextFrame->PaletteDataLength(),
+ nextFrame->GetHasAlpha(),
+ mCompositingFrame->GetRawData(),
+ mCompositingFrame->GetRect(),
+ nextFrame->GetBlendMethod());
+
+ // Set timeout of CompositeFrame to timeout of frame we just composed
+ // Bug 177948
+ int32_t timeout = nextFrame->GetRawTimeout();
+ mCompositingFrame->SetRawTimeout(timeout);
+
+ // Tell the image that it is fully 'downloaded'.
+ nsresult rv =
+ mCompositingFrame->ImageUpdated(mCompositingFrame->GetRect());
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+
+ mLastCompositedFrameIndex = int32_t(aNextFrameIndex);
+
+ return true;
+}
+
+//******************************************************************************
+// Fill aFrame with black. Does also clears the mask.
+void
+FrameAnimator::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect)
+{
+ if (!aFrameData) {
+ return;
+ }
+
+ memset(aFrameData, 0, aFrameRect.width * aFrameRect.height * 4);
+}
+
+//******************************************************************************
+void
+FrameAnimator::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect,
+ const nsIntRect& aRectToClear)
+{
+ if (!aFrameData || aFrameRect.width <= 0 || aFrameRect.height <= 0 ||
+ aRectToClear.width <= 0 || aRectToClear.height <= 0) {
+ return;
+ }
+
+ nsIntRect toClear = aFrameRect.Intersect(aRectToClear);
+ if (toClear.IsEmpty()) {
+ return;
+ }
+
+ uint32_t bytesPerRow = aFrameRect.width * 4;
+ for (int row = toClear.y; row < toClear.y + toClear.height; ++row) {
+ memset(aFrameData + toClear.x * 4 + row * bytesPerRow, 0,
+ toClear.width * 4);
+ }
+}
+
+//******************************************************************************
+// Whether we succeed or fail will not cause a crash, and there's not much
+// we can do about a failure, so there we don't return a nsresult
+bool
+FrameAnimator::CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc,
+ uint8_t* aDataDest, const nsIntRect& aRectDest)
+{
+ uint32_t dataLengthSrc = aRectSrc.width * aRectSrc.height * 4;
+ uint32_t dataLengthDest = aRectDest.width * aRectDest.height * 4;
+
+ if (!aDataDest || !aDataSrc || dataLengthSrc != dataLengthDest) {
+ return false;
+ }
+
+ memcpy(aDataDest, aDataSrc, dataLengthDest);
+
+ return true;
+}
+
+nsresult
+FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
+ uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
+ uint8_t* aDstPixels, const nsIntRect& aDstRect,
+ BlendMethod aBlendMethod)
+{
+ NS_ENSURE_ARG_POINTER(aSrcData);
+ NS_ENSURE_ARG_POINTER(aDstPixels);
+
+ // According to both AGIF and APNG specs, offsets are unsigned
+ if (aSrcRect.x < 0 || aSrcRect.y < 0) {
+ NS_WARNING("FrameAnimator::DrawFrameTo: negative offsets not allowed");
+ return NS_ERROR_FAILURE;
+ }
+ // Outside the destination frame, skip it
+ if ((aSrcRect.x > aDstRect.width) || (aSrcRect.y > aDstRect.height)) {
+ return NS_OK;
+ }
+
+ if (aSrcPaletteLength) {
+ // Larger than the destination frame, clip it
+ int32_t width = std::min(aSrcRect.width, aDstRect.width - aSrcRect.x);
+ int32_t height = std::min(aSrcRect.height, aDstRect.height - aSrcRect.y);
+
+ // The clipped image must now fully fit within destination image frame
+ NS_ASSERTION((aSrcRect.x >= 0) && (aSrcRect.y >= 0) &&
+ (aSrcRect.x + width <= aDstRect.width) &&
+ (aSrcRect.y + height <= aDstRect.height),
+ "FrameAnimator::DrawFrameTo: Invalid aSrcRect");
+
+ // clipped image size may be smaller than source, but not larger
+ NS_ASSERTION((width <= aSrcRect.width) && (height <= aSrcRect.height),
+ "FrameAnimator::DrawFrameTo: source must be smaller than dest");
+
+ // Get pointers to image data
+ const uint8_t* srcPixels = aSrcData + aSrcPaletteLength;
+ uint32_t* dstPixels = reinterpret_cast<uint32_t*>(aDstPixels);
+ const uint32_t* colormap = reinterpret_cast<const uint32_t*>(aSrcData);
+
+ // Skip to the right offset
+ dstPixels += aSrcRect.x + (aSrcRect.y * aDstRect.width);
+ if (!aSrcHasAlpha) {
+ for (int32_t r = height; r > 0; --r) {
+ for (int32_t c = 0; c < width; c++) {
+ dstPixels[c] = colormap[srcPixels[c]];
+ }
+ // Go to the next row in the source resp. destination image
+ srcPixels += aSrcRect.width;
+ dstPixels += aDstRect.width;
+ }
+ } else {
+ for (int32_t r = height; r > 0; --r) {
+ for (int32_t c = 0; c < width; c++) {
+ const uint32_t color = colormap[srcPixels[c]];
+ if (color) {
+ dstPixels[c] = color;
+ }
+ }
+ // Go to the next row in the source resp. destination image
+ srcPixels += aSrcRect.width;
+ dstPixels += aDstRect.width;
+ }
+ }
+ } else {
+ pixman_image_t* src =
+ pixman_image_create_bits(
+ aSrcHasAlpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+ aSrcRect.width, aSrcRect.height,
+ reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(aSrcData)),
+ aSrcRect.width * 4);
+ pixman_image_t* dst =
+ pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ aDstRect.width,
+ aDstRect.height,
+ reinterpret_cast<uint32_t*>(aDstPixels),
+ aDstRect.width * 4);
+
+ auto op = aBlendMethod == BlendMethod::SOURCE ? PIXMAN_OP_SRC
+ : PIXMAN_OP_OVER;
+ pixman_image_composite32(op,
+ src,
+ nullptr,
+ dst,
+ 0, 0,
+ 0, 0,
+ aSrcRect.x, aSrcRect.y,
+ aSrcRect.width, aSrcRect.height);
+
+ pixman_image_unref(src);
+ pixman_image_unref(dst);
+ }
+
+ return NS_OK;
+}
+
} // namespace image
} // namespace mozilla
--- a/image/src/FrameAnimator.h
+++ b/image/src/FrameAnimator.h
@@ -2,35 +2,42 @@
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_src_FrameAnimator_h
#define mozilla_image_src_FrameAnimator_h
+#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"
+#include "gfx2DGlue.h"
+#include "gfxTypes.h"
+#include "imgFrame.h"
+#include "nsCOMPtr.h"
#include "nsRect.h"
+#include "SurfaceCache.h"
namespace mozilla {
namespace image {
-class FrameBlender;
class RasterImage;
class FrameAnimator
{
public:
FrameAnimator(RasterImage* aImage,
- FrameBlender& aFrameBlender,
+ gfx::IntSize aSize,
uint16_t aAnimationMode)
- : mCurrentAnimationFrameIndex(0)
- , mLoopCounter(-1)
- , mImage(aImage)
- , mFrameBlender(aFrameBlender)
+ : mImage(aImage)
+ , mSize(aSize)
+ , mCurrentAnimationFrameIndex(0)
+ , mLoopRemainingCount(-1)
+ , mLastCompositedFrameIndex(-1)
+ , mLoopCount(-1)
, mAnimationMode(aAnimationMode)
, mDoneDecoding(false)
{ }
/**
* Return value from RequestRefresh. Tells callers what happened in that call
* to RequestRefresh.
*/
@@ -119,16 +126,40 @@ public:
*/
uint32_t GetCurrentAnimationFrameIndex() const;
/**
* Get the area we refresh when we loop around to the first frame.
*/
nsIntRect GetFirstFrameRefreshArea() const;
+ /**
+ * If we have a composited frame for @aFrameNum, returns it. Otherwise, returns
+ * an empty DrawableFrameRef. It is an error to call this method with
+ * aFrameNum == 0, because the first frame is never composited.
+ */
+ DrawableFrameRef GetCompositedFrame(uint32_t aFrameNum);
+
+ /*
+ * Returns the frame's adjusted timeout. If the animation loops and the
+ * timeout falls in between a certain range then the timeout is adjusted so
+ * that it's never 0. If the animation does not loop then no adjustments are
+ * made.
+ */
+ int32_t GetTimeoutForFrame(uint32_t aFrameNum) const;
+
+ /*
+ * Set number of times to loop the image.
+ * @note -1 means loop forever.
+ */
+ void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; }
+ int32_t LoopCount() const { return mLoopCount; }
+
+ size_t SizeOfCompositingFrames(gfxMemoryLocation aLocation,
+ MallocSizeOf aMallocSizeOf) const;
private: // methods
/**
* Gets the length of a single loop of this image, in milliseconds.
*
* If this image is not finished decoding, is not animated, or it is animated
* but does not loop, returns -1. Can return 0 in the case of an animated
* image that has a 0ms delay between its frames and does not loop.
*/
@@ -150,34 +181,105 @@ private: // methods
/**
* Get the time the frame we're currently displaying is supposed to end.
*
* In the error case, returns an "infinity" timestamp.
*/
TimeStamp GetCurrentImgFrameEndTime() const;
+ bool DoBlend(nsIntRect* aDirtyRect, uint32_t aPrevFrameIndex,
+ uint32_t aNextFrameIndex);
+
+ /**
+ * Get the @aIndex-th frame in the frame index, ignoring results of blending.
+ */
+ RawAccessFrameRef GetRawFrame(uint32_t aFrameNum) const;
+
+ /** Clears an area of <aFrame> with transparent black.
+ *
+ * @param aFrameData Target Frame data
+ * @param aFrameRect The rectangle of the data pointed ot by aFrameData
+ *
+ * @note Does also clears the transparency mask
+ */
+ static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect);
+
+ //! @overload
+ static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect,
+ const nsIntRect& aRectToClear);
+
+ //! Copy one frame's image and mask into another
+ static bool CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc,
+ uint8_t* aDataDest, const nsIntRect& aRectDest);
+
+ /**
+ * Draws one frame's image to into another, at the position specified by
+ * aSrcRect.
+ *
+ * @aSrcData the raw data of the current frame being drawn
+ * @aSrcRect the size of the source frame, and the position of that frame in
+ * the composition frame
+ * @aSrcPaletteLength the length (in bytes) of the palette at the beginning
+ * of the source data (0 if image is not paletted)
+ * @aSrcHasAlpha whether the source data represents an image with alpha
+ * @aDstPixels the raw data of the composition frame where the current frame
+ * is drawn into (32-bit ARGB)
+ * @aDstRect the size of the composition frame
+ * @aBlendMethod the blend method for how to blend src on the composition
+ * frame.
+ */
+ static nsresult DrawFrameTo(const uint8_t* aSrcData,
+ const nsIntRect& aSrcRect,
+ uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
+ uint8_t* aDstPixels, const nsIntRect& aDstRect,
+ BlendMethod aBlendMethod);
+
private: // data
+ //! A weak pointer to our owning image.
+ RasterImage* mImage;
+
+ //! The intrinsic size of the image.
+ gfx::IntSize mSize;
+
+ /** For managing blending of frames
+ *
+ * Some animations will use the compositingFrame to composite images
+ * and just hand this back to the caller when it is time to draw the frame.
+ * NOTE: When clearing compositingFrame, remember to set
+ * lastCompositedFrameIndex to -1. Code assume that if
+ * lastCompositedFrameIndex >= 0 then compositingFrame exists.
+ */
+ RawAccessFrameRef mCompositingFrame;
+
+ /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
+ *
+ * The Previous Frame (all frames composited up to the current) needs to be
+ * stored in cases where the image specifies it wants the last frame back
+ * when it's done with the current frame.
+ */
+ RawAccessFrameRef mCompositingPrevFrame;
+
//! Area of the first frame that needs to be redrawn on subsequent loops.
nsIntRect mFirstFrameRefreshArea;
//! the time that the animation advanced to the current frame
TimeStamp mCurrentAnimationFrameTime;
//! The current frame index we're on. 0 to (numFrames - 1).
uint32_t mCurrentAnimationFrameIndex;
//! number of loops remaining before animation stops (-1 no stop)
- int32_t mLoopCounter;
+ int32_t mLoopRemainingCount;
- //! A weak pointer to our owner.
- RasterImage* mImage;
+ //! Track the last composited frame for Optimizations (See DoComposite code)
+ int32_t mLastCompositedFrameIndex;
- //! All the frames of the image, shared with our owner
- FrameBlender& mFrameBlender;
+ //! The total number of loops for the image.
+ int32_t mLoopCount;
//! The animation mode of this image. Constants defined in imgIContainer.
uint16_t mAnimationMode;
//! Whether this image is done being decoded.
bool mDoneDecoding;
};
deleted file mode 100644
--- a/image/src/FrameBlender.cpp
+++ /dev/null
@@ -1,525 +0,0 @@
-/* -*- 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 "FrameBlender.h"
-
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/Move.h"
-#include "MainThreadUtils.h"
-
-#include "pixman.h"
-
-namespace mozilla {
-
-using namespace gfx;
-
-namespace image {
-
-DrawableFrameRef
-FrameBlender::GetCompositedFrame(uint32_t aFrameNum)
-{
- MOZ_ASSERT(aFrameNum != 0, "First frame is never composited");
-
- // If we have a composited version of this frame, return that.
- if (mLastCompositedFrameIndex == int32_t(aFrameNum)) {
- return mCompositingFrame->DrawableRef();
- }
-
- // Otherwise return the raw frame. DoBlend is required to ensure that we only
- // hit this case if the frame is not paletted and doesn't require compositing.
- DrawableFrameRef ref =
- SurfaceCache::Lookup(mImageKey,
- RasterSurfaceKey(mSize,
- 0, // Default decode flags.
- aFrameNum));
- MOZ_ASSERT(!ref || !ref->GetIsPaletted(), "About to return a paletted frame");
- return ref;
-}
-
-RawAccessFrameRef
-FrameBlender::GetRawFrame(uint32_t aFrameNum)
-{
- DrawableFrameRef ref =
- SurfaceCache::Lookup(mImageKey,
- RasterSurfaceKey(mSize,
- 0, // Default decode flags.
- aFrameNum));
- return ref ? ref->RawAccessRef()
- : RawAccessFrameRef();
-}
-
-int32_t
-FrameBlender::GetTimeoutForFrame(uint32_t aFrameNum)
-{
- RawAccessFrameRef frame = GetRawFrame(aFrameNum);
- const int32_t timeout = frame->GetRawTimeout();
-
- // Ensure a minimal time between updates so we don't throttle the UI thread.
- // consider 0 == unspecified and make it fast but not too fast. Unless we
- // have a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug
- // 207059. The behavior of recent IE and Opera versions seems to be:
- // IE 6/Win:
- // 10 - 50ms go 100ms
- // >50ms go correct speed
- // Opera 7 final/Win:
- // 10ms goes 100ms
- // >10ms go correct speed
- // It seems that there are broken tools out there that set a 0ms or 10ms
- // timeout when they really want a "default" one. So munge values in that
- // range.
- if (timeout >= 0 && timeout <= 10 && mLoopCount != 0) {
- return 100;
- }
-
- return timeout;
-}
-
-//******************************************************************************
-// DoBlend gets called when the timer for animation get fired and we have to
-// update the composited frame of the animation.
-bool
-FrameBlender::DoBlend(nsIntRect* aDirtyRect,
- uint32_t aPrevFrameIndex,
- uint32_t aNextFrameIndex)
-{
- RawAccessFrameRef prevFrame = GetRawFrame(aPrevFrameIndex);
- RawAccessFrameRef nextFrame = GetRawFrame(aNextFrameIndex);
-
- MOZ_ASSERT(prevFrame && nextFrame, "Should have frames here");
-
- int32_t prevFrameDisposalMethod = prevFrame->GetFrameDisposalMethod();
- if (prevFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious &&
- !mCompositingPrevFrame) {
- prevFrameDisposalMethod = FrameBlender::kDisposeClear;
- }
-
- nsIntRect prevFrameRect = prevFrame->GetRect();
- bool isFullPrevFrame = (prevFrameRect.x == 0 && prevFrameRect.y == 0 &&
- prevFrameRect.width == mSize.width &&
- prevFrameRect.height == mSize.height);
-
- // Optimization: DisposeClearAll if the previous frame is the same size as
- // container and it's clearing itself
- if (isFullPrevFrame &&
- (prevFrameDisposalMethod == FrameBlender::kDisposeClear)) {
- prevFrameDisposalMethod = FrameBlender::kDisposeClearAll;
- }
-
- int32_t nextFrameDisposalMethod = nextFrame->GetFrameDisposalMethod();
- nsIntRect nextFrameRect = nextFrame->GetRect();
- bool isFullNextFrame = (nextFrameRect.x == 0 && nextFrameRect.y == 0 &&
- nextFrameRect.width == mSize.width &&
- nextFrameRect.height == mSize.height);
-
- if (!nextFrame->GetIsPaletted()) {
- // Optimization: Skip compositing if the previous frame wants to clear the
- // whole image
- if (prevFrameDisposalMethod == FrameBlender::kDisposeClearAll) {
- aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
- return true;
- }
-
- // Optimization: Skip compositing if this frame is the same size as the
- // container and it's fully drawing over prev frame (no alpha)
- if (isFullNextFrame &&
- (nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious) &&
- !nextFrame->GetHasAlpha()) {
- aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
- return true;
- }
- }
-
- // Calculate area that needs updating
- switch (prevFrameDisposalMethod) {
- default:
- case FrameBlender::kDisposeNotSpecified:
- case FrameBlender::kDisposeKeep:
- *aDirtyRect = nextFrameRect;
- break;
-
- case FrameBlender::kDisposeClearAll:
- // Whole image container is cleared
- aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
- break;
-
- case FrameBlender::kDisposeClear:
- // Calc area that needs to be redrawn (the combination of previous and
- // this frame)
- // XXX - This could be done with multiple framechanged calls
- // Having prevFrame way at the top of the image, and nextFrame
- // way at the bottom, and both frames being small, we'd be
- // telling framechanged to refresh the whole image when only two
- // small areas are needed.
- aDirtyRect->UnionRect(nextFrameRect, prevFrameRect);
- break;
-
- case FrameBlender::kDisposeRestorePrevious:
- aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
- break;
- }
-
- // Optimization:
- // Skip compositing if the last composited frame is this frame
- // (Only one composited frame was made for this animation. Example:
- // Only Frame 3 of a 10 frame image required us to build a composite frame
- // On the second loop, we do not need to rebuild the frame
- // since it's still sitting in compositingFrame)
- if (mLastCompositedFrameIndex == int32_t(aNextFrameIndex)) {
- return true;
- }
-
- bool needToBlankComposite = false;
-
- // Create the Compositing Frame
- if (!mCompositingFrame) {
- nsRefPtr<imgFrame> newFrame = new imgFrame;
- nsresult rv = newFrame->InitForDecoder(ThebesIntSize(mSize),
- SurfaceFormat::B8G8R8A8);
- if (NS_FAILED(rv)) {
- mCompositingFrame.reset();
- return false;
- }
- mCompositingFrame = newFrame->RawAccessRef();
- needToBlankComposite = true;
- } else if (int32_t(aNextFrameIndex) != mLastCompositedFrameIndex+1) {
-
- // If we are not drawing on top of last composited frame,
- // then we are building a new composite frame, so let's clear it first.
- needToBlankComposite = true;
- }
-
- // More optimizations possible when next frame is not transparent
- // But if the next frame has FrameBlender::kDisposeRestorePrevious,
- // this "no disposal" optimization is not possible,
- // because the frame in "after disposal operation" state
- // needs to be stored in compositingFrame, so it can be
- // copied into compositingPrevFrame later.
- bool doDisposal = true;
- if (!nextFrame->GetHasAlpha() &&
- nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious) {
- if (isFullNextFrame) {
- // Optimization: No need to dispose prev.frame when
- // next frame is full frame and not transparent.
- doDisposal = false;
- // No need to blank the composite frame
- needToBlankComposite = false;
- } else {
- if ((prevFrameRect.x >= nextFrameRect.x) &&
- (prevFrameRect.y >= nextFrameRect.y) &&
- (prevFrameRect.x + prevFrameRect.width <=
- nextFrameRect.x + nextFrameRect.width) &&
- (prevFrameRect.y + prevFrameRect.height <=
- nextFrameRect.y + nextFrameRect.height)) {
- // Optimization: No need to dispose prev.frame when
- // next frame fully overlaps previous frame.
- doDisposal = false;
- }
- }
- }
-
- if (doDisposal) {
- // Dispose of previous: clear, restore, or keep (copy)
- switch (prevFrameDisposalMethod) {
- case FrameBlender::kDisposeClear:
- if (needToBlankComposite) {
- // If we just created the composite, it could have anything in its
- // buffer. Clear whole frame
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- } else {
- // Only blank out previous frame area (both color & Mask/Alpha)
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect(),
- prevFrameRect);
- }
- break;
-
- case FrameBlender::kDisposeClearAll:
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- break;
-
- case FrameBlender::kDisposeRestorePrevious:
- // It would be better to copy only the area changed back to
- // compositingFrame.
- if (mCompositingPrevFrame) {
- CopyFrameImage(mCompositingPrevFrame->GetRawData(),
- mCompositingPrevFrame->GetRect(),
- mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
-
- // destroy only if we don't need it for this frame's disposal
- if (nextFrameDisposalMethod !=
- FrameBlender::kDisposeRestorePrevious) {
- mCompositingPrevFrame.reset();
- }
- } else {
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- }
- break;
-
- default:
- // Copy previous frame into compositingFrame before we put the new
- // frame on top
- // Assumes that the previous frame represents a full frame (it could be
- // smaller in size than the container, as long as the frame before it
- // erased itself)
- // Note: Frame 1 never gets into DoBlend(), so (aNextFrameIndex - 1)
- // will always be a valid frame number.
- if (mLastCompositedFrameIndex != int32_t(aNextFrameIndex - 1)) {
- if (isFullPrevFrame && !prevFrame->GetIsPaletted()) {
- // Just copy the bits
- CopyFrameImage(prevFrame->GetRawData(),
- prevFrame->GetRect(),
- mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- } else {
- if (needToBlankComposite) {
- // Only blank composite when prev is transparent or not full.
- if (prevFrame->GetHasAlpha() || !isFullPrevFrame) {
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- }
- }
- DrawFrameTo(prevFrame->GetRawData(), prevFrameRect,
- prevFrame->PaletteDataLength(),
- prevFrame->GetHasAlpha(),
- mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect(),
- FrameBlendMethod(prevFrame->GetBlendMethod()));
- }
- }
- }
- } else if (needToBlankComposite) {
- // If we just created the composite, it could have anything in its
- // buffers. Clear them
- ClearFrame(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect());
- }
-
- // Check if the frame we are composing wants the previous image restored after
- // it is done. Don't store it (again) if last frame wanted its image restored
- // too
- if ((nextFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious) &&
- (prevFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)) {
- // We are storing the whole image.
- // It would be better if we just stored the area that nextFrame is going to
- // overwrite.
- if (!mCompositingPrevFrame) {
- nsRefPtr<imgFrame> newFrame = new imgFrame;
- nsresult rv = newFrame->InitForDecoder(ThebesIntSize(mSize),
- SurfaceFormat::B8G8R8A8);
- if (NS_FAILED(rv)) {
- mCompositingPrevFrame.reset();
- return false;
- }
-
- mCompositingPrevFrame = newFrame->RawAccessRef();
- }
-
- CopyFrameImage(mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect(),
- mCompositingPrevFrame->GetRawData(),
- mCompositingPrevFrame->GetRect());
- }
-
- // blit next frame into it's correct spot
- DrawFrameTo(nextFrame->GetRawData(), nextFrameRect,
- nextFrame->PaletteDataLength(),
- nextFrame->GetHasAlpha(),
- mCompositingFrame->GetRawData(),
- mCompositingFrame->GetRect(),
- FrameBlendMethod(nextFrame->GetBlendMethod()));
-
- // Set timeout of CompositeFrame to timeout of frame we just composed
- // Bug 177948
- int32_t timeout = nextFrame->GetRawTimeout();
- mCompositingFrame->SetRawTimeout(timeout);
-
- // Tell the image that it is fully 'downloaded'.
- nsresult rv =
- mCompositingFrame->ImageUpdated(mCompositingFrame->GetRect());
- if (NS_FAILED(rv)) {
- return false;
- }
-
- mLastCompositedFrameIndex = int32_t(aNextFrameIndex);
-
- return true;
-}
-
-//******************************************************************************
-// Fill aFrame with black. Does also clears the mask.
-void
-FrameBlender::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect)
-{
- if (!aFrameData) {
- return;
- }
-
- memset(aFrameData, 0, aFrameRect.width * aFrameRect.height * 4);
-}
-
-//******************************************************************************
-void
-FrameBlender::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect,
- const nsIntRect& aRectToClear)
-{
- if (!aFrameData || aFrameRect.width <= 0 || aFrameRect.height <= 0 ||
- aRectToClear.width <= 0 || aRectToClear.height <= 0) {
- return;
- }
-
- nsIntRect toClear = aFrameRect.Intersect(aRectToClear);
- if (toClear.IsEmpty()) {
- return;
- }
-
- uint32_t bytesPerRow = aFrameRect.width * 4;
- for (int row = toClear.y; row < toClear.y + toClear.height; ++row) {
- memset(aFrameData + toClear.x * 4 + row * bytesPerRow, 0,
- toClear.width * 4);
- }
-}
-
-//******************************************************************************
-// Whether we succeed or fail will not cause a crash, and there's not much
-// we can do about a failure, so there we don't return a nsresult
-bool
-FrameBlender::CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc,
- uint8_t* aDataDest, const nsIntRect& aRectDest)
-{
- uint32_t dataLengthSrc = aRectSrc.width * aRectSrc.height * 4;
- uint32_t dataLengthDest = aRectDest.width * aRectDest.height * 4;
-
- if (!aDataDest || !aDataSrc || dataLengthSrc != dataLengthDest) {
- return false;
- }
-
- memcpy(aDataDest, aDataSrc, dataLengthDest);
-
- return true;
-}
-
-nsresult
-FrameBlender::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
- uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
- uint8_t* aDstPixels, const nsIntRect& aDstRect,
- FrameBlender::FrameBlendMethod aBlendMethod)
-{
- NS_ENSURE_ARG_POINTER(aSrcData);
- NS_ENSURE_ARG_POINTER(aDstPixels);
-
- // According to both AGIF and APNG specs, offsets are unsigned
- if (aSrcRect.x < 0 || aSrcRect.y < 0) {
- NS_WARNING("FrameBlender::DrawFrameTo: negative offsets not allowed");
- return NS_ERROR_FAILURE;
- }
- // Outside the destination frame, skip it
- if ((aSrcRect.x > aDstRect.width) || (aSrcRect.y > aDstRect.height)) {
- return NS_OK;
- }
-
- if (aSrcPaletteLength) {
- // Larger than the destination frame, clip it
- int32_t width = std::min(aSrcRect.width, aDstRect.width - aSrcRect.x);
- int32_t height = std::min(aSrcRect.height, aDstRect.height - aSrcRect.y);
-
- // The clipped image must now fully fit within destination image frame
- NS_ASSERTION((aSrcRect.x >= 0) && (aSrcRect.y >= 0) &&
- (aSrcRect.x + width <= aDstRect.width) &&
- (aSrcRect.y + height <= aDstRect.height),
- "FrameBlender::DrawFrameTo: Invalid aSrcRect");
-
- // clipped image size may be smaller than source, but not larger
- NS_ASSERTION((width <= aSrcRect.width) && (height <= aSrcRect.height),
- "FrameBlender::DrawFrameTo: source must be smaller than dest");
-
- // Get pointers to image data
- const uint8_t* srcPixels = aSrcData + aSrcPaletteLength;
- uint32_t* dstPixels = reinterpret_cast<uint32_t*>(aDstPixels);
- const uint32_t* colormap = reinterpret_cast<const uint32_t*>(aSrcData);
-
- // Skip to the right offset
- dstPixels += aSrcRect.x + (aSrcRect.y * aDstRect.width);
- if (!aSrcHasAlpha) {
- for (int32_t r = height; r > 0; --r) {
- for (int32_t c = 0; c < width; c++) {
- dstPixels[c] = colormap[srcPixels[c]];
- }
- // Go to the next row in the source resp. destination image
- srcPixels += aSrcRect.width;
- dstPixels += aDstRect.width;
- }
- } else {
- for (int32_t r = height; r > 0; --r) {
- for (int32_t c = 0; c < width; c++) {
- const uint32_t color = colormap[srcPixels[c]];
- if (color) {
- dstPixels[c] = color;
- }
- }
- // Go to the next row in the source resp. destination image
- srcPixels += aSrcRect.width;
- dstPixels += aDstRect.width;
- }
- }
- } else {
- pixman_image_t* src =
- pixman_image_create_bits(
- aSrcHasAlpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
- aSrcRect.width, aSrcRect.height,
- reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(aSrcData)),
- aSrcRect.width * 4);
- pixman_image_t* dst =
- pixman_image_create_bits(PIXMAN_a8r8g8b8,
- aDstRect.width,
- aDstRect.height,
- reinterpret_cast<uint32_t*>(aDstPixels),
- aDstRect.width * 4);
-
- auto op = aBlendMethod == FrameBlender::kBlendSource ? PIXMAN_OP_SRC
- : PIXMAN_OP_OVER;
- pixman_image_composite32(op,
- src,
- nullptr,
- dst,
- 0, 0,
- 0, 0,
- aSrcRect.x, aSrcRect.y,
- aSrcRect.width, aSrcRect.height);
-
- pixman_image_unref(src);
- pixman_image_unref(dst);
- }
-
- return NS_OK;
-}
-
-size_t
-FrameBlender::SizeOfDecoded(gfxMemoryLocation aLocation,
- MallocSizeOf aMallocSizeOf) const
-{
- size_t n = 0;
-
- if (mCompositingFrame) {
- n += mCompositingFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf);
- }
- if (mCompositingPrevFrame) {
- n += mCompositingPrevFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf);
- }
-
- return n;
-}
-
-void
-FrameBlender::ResetAnimation()
-{
- mLastCompositedFrameIndex = -1;
-}
-
-} // namespace image
-} // namespace mozilla
deleted file mode 100644
--- a/image/src/FrameBlender.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* -*- 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 mozilla_imagelib_FrameBlender_h_
-#define mozilla_imagelib_FrameBlender_h_
-
-#include "mozilla/MemoryReporting.h"
-#include "gfx2DGlue.h"
-#include "gfxTypes.h"
-#include "imgFrame.h"
-#include "nsCOMPtr.h"
-#include "SurfaceCache.h"
-
-namespace mozilla {
-namespace image {
-
-/**
- * FrameBlender stores and gives access to imgFrames. It also knows how to
- * blend frames from previous to next, looping if necessary.
- *
- * All logic about when and whether to blend are external to FrameBlender.
- */
-class FrameBlender
-{
-public:
- FrameBlender(ImageKey aImageKey, gfx::IntSize aSize)
- : mImageKey(aImageKey)
- , mSize(aSize)
- , mLastCompositedFrameIndex(-1)
- , mLoopCount(-1)
- { }
-
- bool DoBlend(nsIntRect* aDirtyRect, uint32_t aPrevFrameIndex,
- uint32_t aNextFrameIndex);
-
- /**
- * If we have a composited frame for @aFrameNum, returns it. Otherwise, returns
- * an empty DrawableFrameRef. It is an error to call this method with
- * aFrameNum == 0, because the first frame is never composited.
- */
- DrawableFrameRef GetCompositedFrame(uint32_t aFrameNum);
-
- /**
- * Get the @aIndex-th frame in the frame index, ignoring results of blending.
- */
- RawAccessFrameRef GetRawFrame(uint32_t aFrameNum);
-
- /*
- * Returns the frame's adjusted timeout. If the animation loops and the
- * timeout falls in between a certain range then the timeout is adjusted so
- * that it's never 0. If the animation does not loop then no adjustments are
- * made.
- */
- int32_t GetTimeoutForFrame(uint32_t aFrameNum);
-
- /*
- * Set number of times to loop the image.
- * @note -1 means loop forever.
- */
- void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; }
- int32_t LoopCount() const { return mLoopCount; }
-
- size_t SizeOfDecoded(gfxMemoryLocation aLocation,
- MallocSizeOf aMallocSizeOf) const;
-
- void ResetAnimation();
-
- // "Blend" method indicates how the current image is combined with the
- // previous image.
- enum FrameBlendMethod {
- // All color components of the frame, including alpha, overwrite the current
- // contents of the frame's output buffer region
- kBlendSource = 0,
-
- // The frame should be composited onto the output buffer based on its alpha,
- // using a simple OVER operation
- kBlendOver
- };
-
- enum FrameDisposalMethod {
- kDisposeClearAll = -1, // Clear the whole image, revealing
- // what was there before the gif displayed
- kDisposeNotSpecified, // Leave frame, let new frame draw on top
- kDisposeKeep, // Leave frame, let new frame draw on top
- kDisposeClear, // Clear the frame's area, revealing bg
- kDisposeRestorePrevious // Restore the previous (composited) frame
- };
-
- // A hint as to whether an individual frame is entirely opaque, or requires
- // alpha blending.
- enum FrameAlpha {
- kFrameHasAlpha,
- kFrameOpaque
- };
-
-private:
- /** Clears an area of <aFrame> with transparent black.
- *
- * @param aFrameData Target Frame data
- * @param aFrameRect The rectangle of the data pointed ot by aFrameData
- *
- * @note Does also clears the transparency mask
- */
- static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect);
-
- //! @overload
- static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect,
- const nsIntRect& aRectToClear);
-
- //! Copy one frame's image and mask into another
- static bool CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc,
- uint8_t* aDataDest, const nsIntRect& aRectDest);
-
- /**
- * Draws one frame's image to into another, at the position specified by
- * aSrcRect.
- *
- * @aSrcData the raw data of the current frame being drawn
- * @aSrcRect the size of the source frame, and the position of that frame in
- * the composition frame
- * @aSrcPaletteLength the length (in bytes) of the palette at the beginning
- * of the source data (0 if image is not paletted)
- * @aSrcHasAlpha whether the source data represents an image with alpha
- * @aDstPixels the raw data of the composition frame where the current frame
- * is drawn into (32-bit ARGB)
- * @aDstRect the size of the composition frame
- * @aBlendMethod the blend method for how to blend src on the composition
- * frame.
- */
- static nsresult DrawFrameTo(const uint8_t* aSrcData,
- const nsIntRect& aSrcRect,
- uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
- uint8_t* aDstPixels, const nsIntRect& aDstRect,
- FrameBlendMethod aBlendMethod);
-
-private: // data
- ImageKey mImageKey;
- gfx::IntSize mSize;
-
- //! Track the last composited frame for Optimizations (See DoComposite code)
- int32_t mLastCompositedFrameIndex;
-
- /** For managing blending of frames
- *
- * Some animations will use the compositingFrame to composite images
- * and just hand this back to the caller when it is time to draw the frame.
- * NOTE: When clearing compositingFrame, remember to set
- * lastCompositedFrameIndex to -1. Code assume that if
- * lastCompositedFrameIndex >= 0 then compositingFrame exists.
- */
- RawAccessFrameRef mCompositingFrame;
-
- /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
- *
- * The Previous Frame (all frames composited up to the current) needs to be
- * stored in cases where the image specifies it wants the last frame back
- * when it's done with the current frame.
- */
- RawAccessFrameRef mCompositingPrevFrame;
-
- int32_t mLoopCount;
-};
-
-} // namespace image
-} // namespace mozilla
-
-#endif /* mozilla_imagelib_FrameBlender_h_ */
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -547,20 +547,19 @@ RasterImage::LookupFrameInternal(uint32_
{
if (!mAnim) {
NS_ASSERTION(aFrameNum == 0,
"Don't ask for a frame > 0 if we're not animated!");
aFrameNum = 0;
}
if (mAnim && aFrameNum > 0) {
- MOZ_ASSERT(mFrameBlender, "mAnim but no mFrameBlender?");
MOZ_ASSERT(DecodeFlags(aFlags) == DECODE_FLAGS_DEFAULT,
"Can't composite frames with non-default decode flags");
- return mFrameBlender->GetCompositedFrame(aFrameNum);
+ return mAnim->GetCompositedFrame(aFrameNum);
}
return SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize.ToIntSize(),
DecodeFlags(aFlags),
aFrameNum));
}
@@ -697,18 +696,18 @@ RasterImage::GetFirstFrameDelay()
{
if (mError)
return -1;
bool animated = false;
if (NS_FAILED(GetAnimated(&animated)) || !animated)
return -1;
- MOZ_ASSERT(mFrameBlender, "Animated images should have a FrameBlender");
- return mFrameBlender->GetTimeoutForFrame(0);
+ MOZ_ASSERT(mAnim, "Animated images should have a FrameAnimator");
+ return mAnim->GetTimeoutForFrame(0);
}
TemporaryRef<SourceSurface>
RasterImage::CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags,
bool aShouldSyncNotify /* = true */)
{
if (aWhichFrame > FRAME_MAX_VALUE)
@@ -920,18 +919,18 @@ RasterImage::SizeOfSourceWithComputedFal
}
size_t
RasterImage::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
- if (mFrameBlender) {
- n += mFrameBlender->SizeOfDecoded(aLocation, aMallocSizeOf);
+ if (mAnim) {
+ n += mAnim->SizeOfCompositingFrames(aLocation, aMallocSizeOf);
}
return n;
}
RawAccessFrameRef
RasterImage::InternalAddFrame(uint32_t aFrameNum,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
@@ -979,20 +978,18 @@ RasterImage::InternalAddFrame(uint32_t a
aFrameNum),
Lifetime::Persistent);
if (!succeeded) {
return RawAccessFrameRef();
}
if (aFrameNum == 1) {
// We're becoming animated, so initialize animation stuff.
- MOZ_ASSERT(!mFrameBlender, "Already have a FrameBlender?");
MOZ_ASSERT(!mAnim, "Already have animation state?");
- mFrameBlender.emplace(ImageKey(this), mSize.ToIntSize());
- mAnim = MakeUnique<FrameAnimator>(this, *mFrameBlender, mAnimationMode);
+ mAnim = MakeUnique<FrameAnimator>(this, mSize.ToIntSize(), mAnimationMode);
// We don't support discarding animated images (See bug 414259).
// Lock the image and throw away the key.
//
// Note that this is inefficient, since we could get rid of the source data
// too. However, doing this is actually hard, because we're probably
// mid-decode, and thus we're decoding out of the source buffer. Since we're
// going to fix this anyway later, and since we didn't kill the source data
@@ -1000,19 +997,20 @@ RasterImage::InternalAddFrame(uint32_t a
LockImage();
MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated");
aPreviousFrame->SetRawAccessOnly();
// If we dispose of the first frame by clearing it, then the first frame's
// refresh area is all of itself.
// RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR).
- int32_t frameDisposalMethod = aPreviousFrame->GetFrameDisposalMethod();
- if (frameDisposalMethod == FrameBlender::kDisposeClear ||
- frameDisposalMethod == FrameBlender::kDisposeRestorePrevious) {
+ DisposalMethod disposalMethod = aPreviousFrame->GetDisposalMethod();
+ if (disposalMethod == DisposalMethod::CLEAR ||
+ disposalMethod == DisposalMethod::CLEAR_ALL ||
+ disposalMethod == DisposalMethod::RESTORE_PREVIOUS) {
mAnim->SetFirstFrameRefreshArea(aPreviousFrame->GetRect());
}
if (mPendingAnimation && ShouldAnimate()) {
StartAnimation();
}
}
@@ -1092,17 +1090,17 @@ RasterImage::EnsureFrame(uint32_t aFrame
// We're replacing a frame. It must be the first frame; there's no reason to
// ever replace any other frame, since the first frame is the only one we
// speculatively allocate without knowing what the decoder really needs.
// XXX(seth): I'm not convinced there's any reason to support this at all. We
// should figure out how to avoid triggering this and rip it out.
MOZ_ASSERT(aFrameNum == 0, "Replacing a frame other than the first?");
MOZ_ASSERT(GetNumFrames() == 1, "Should have only one frame");
MOZ_ASSERT(aPreviousFrame, "Need the previous frame to replace");
- MOZ_ASSERT(!mFrameBlender && !mAnim, "Shouldn't be animated");
+ MOZ_ASSERT(!mAnim, "Shouldn't be animated");
if (aFrameNum != 0 || !aPreviousFrame || GetNumFrames() != 1) {
return RawAccessFrameRef();
}
MOZ_ASSERT(!aPreviousFrame->GetRect().IsEqualEdges(aFrameRect) ||
aPreviousFrame->GetFormat() != aFormat ||
aPreviousFrame->GetPaletteDepth() != aPaletteDepth,
"Replacing first frame with the same kind of frame?");
@@ -1167,27 +1165,24 @@ RasterImage::StartAnimation()
// mPendingAnimation will cause us to start animating as soon as we have a
// second frame, which causes mAnim to be constructed.
mPendingAnimation = !mAnim;
if (mPendingAnimation) {
return NS_OK;
}
// A timeout of -1 means we should display this frame forever.
- MOZ_ASSERT(mFrameBlender, "Have an animation but no FrameBlender?");
- if (mFrameBlender->GetTimeoutForFrame(GetCurrentFrameIndex()) < 0) {
+ if (mAnim->GetTimeoutForFrame(GetCurrentFrameIndex()) < 0) {
mAnimationFinished = true;
return NS_ERROR_ABORT;
}
- if (mAnim) {
- // We need to set the time that this initial frame was first displayed, as
- // this is used in AdvanceFrame().
- mAnim->InitAnimationFrameTimeIfNecessary();
- }
+ // We need to set the time that this initial frame was first displayed, as
+ // this is used in AdvanceFrame().
+ mAnim->InitAnimationFrameTimeIfNecessary();
return NS_OK;
}
//******************************************************************************
/* void stopAnimation (); */
nsresult
RasterImage::StopAnimation()
@@ -1220,18 +1215,17 @@ RasterImage::ResetAnimation()
return NS_OK;
}
mAnimationFinished = false;
if (mAnimating)
StopAnimation();
- MOZ_ASSERT(mFrameBlender, "Should have a FrameBlender");
- mFrameBlender->ResetAnimation();
+ MOZ_ASSERT(mAnim, "Should have a FrameAnimator");
mAnim->ResetAnimation();
UpdateImageContainer();
// Note - We probably want to kick off a redecode somewhere around here when
// we fix bug 500402.
// Update display
@@ -1268,20 +1262,19 @@ RasterImage::GetFrameIndex(uint32_t aWhi
}
void
RasterImage::SetLoopCount(int32_t aLoopCount)
{
if (mError)
return;
+ // No need to set this if we're not an animation.
if (mAnim) {
- // No need to set this if we're not an animation
- MOZ_ASSERT(mFrameBlender, "Should have a FrameBlender");
- mFrameBlender->SetLoopCount(aLoopCount);
+ mAnim->SetLoopCount(aLoopCount);
}
}
NS_IMETHODIMP_(nsIntRect)
RasterImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
return aRect;
}
@@ -1533,18 +1526,17 @@ RasterImage::Discard()
// As soon as an image becomes animated, it becomes non-discardable and any
// timers are cancelled.
NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
// For post-operation logging
int old_frame_count = GetNumFrames();
- // Delete all the decoded frames
- mFrameBlender.reset();
+ // Delete all the decoded frames.
SurfaceCache::RemoveImage(ImageKey(this));
// Flag that we no longer have decoded frames for this image
mDecoded = false;
mFrameCount = 0;
// Notify that we discarded
if (mProgressTracker) {
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -13,17 +13,16 @@
* @author Arron Mogge <paper@animecity.nu>
* @author Andrew Smith <asmith15@learn.senecac.on.ca>
*/
#ifndef mozilla_imagelib_RasterImage_h_
#define mozilla_imagelib_RasterImage_h_
#include "Image.h"
-#include "FrameBlender.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "nsIProperties.h"
#include "nsTArray.h"
#include "imgFrame.h"
#include "nsThreadUtils.h"
#include "DecodePool.h"
#include "Orientation.h"
@@ -343,21 +342,19 @@ private: // data
// with the browser's needs for displaying the image to the user.
// As such, we may need to redecode if we're being asked for
// a frame with different flags. 0 indicates default flags.
//
// Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
// and imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION.
uint32_t mFrameDecodeFlags;
- //! All the frames of the image.
- Maybe<FrameBlender> mFrameBlender;
-
nsCOMPtr<nsIProperties> mProperties;
+ //! All the frames of the image.
// IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
// that the frames actually exist (they may have been discarded to save memory, or
// we maybe decoding on draw).
UniquePtr<FrameAnimator> mAnim;
// Image locking.
uint32_t mLockCount;
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -128,19 +128,19 @@ static bool AllowedImageAndFrameDimensio
}
imgFrame::imgFrame() :
mDecoded(0, 0, 0, 0),
mDecodedMutex("imgFrame::mDecoded"),
mPalettedImageData(nullptr),
mTimeout(100),
- mDisposalMethod(0), /* imgIContainer::kDisposeNotSpecified */
mLockCount(0),
- mBlendMethod(1), /* imgIContainer::kBlendOver */
+ mDisposalMethod(DisposalMethod::NOT_SPECIFIED),
+ mBlendMethod(BlendMethod::OVER),
mSinglePixel(false),
mCompositingFailed(false),
mHasNoAlpha(false),
mNonPremult(false),
mOptimizable(false)
{
static bool hasCheckedOptimize = false;
if (!hasCheckedOptimize) {
@@ -830,36 +830,16 @@ int32_t imgFrame::GetRawTimeout() const
return mTimeout;
}
void imgFrame::SetRawTimeout(int32_t aTimeout)
{
mTimeout = aTimeout;
}
-int32_t imgFrame::GetFrameDisposalMethod() const
-{
- return mDisposalMethod;
-}
-
-void imgFrame::SetFrameDisposalMethod(int32_t aFrameDisposalMethod)
-{
- mDisposalMethod = aFrameDisposalMethod;
-}
-
-int32_t imgFrame::GetBlendMethod() const
-{
- return mBlendMethod;
-}
-
-void imgFrame::SetBlendMethod(int32_t aBlendMethod)
-{
- mBlendMethod = (int8_t)aBlendMethod;
-}
-
// This can be called from any thread.
bool imgFrame::ImageComplete() const
{
MutexAutoLock lock(mDecodedMutex);
return mDecoded.IsEqualInterior(nsIntRect(mOffset.x, mOffset.y,
mSize.width, mSize.height));
}
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -5,27 +5,51 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef imgFrame_h
#define imgFrame_h
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/Mutex.h"
+#include "mozilla/TypedEnum.h"
#include "mozilla/VolatileBuffer.h"
#include "gfxDrawable.h"
#include "imgIContainer.h"
namespace mozilla {
namespace image {
class ImageRegion;
class DrawableFrameRef;
class RawAccessFrameRef;
+MOZ_BEGIN_ENUM_CLASS(BlendMethod, int8_t)
+ // All color components of the frame, including alpha, overwrite the current
+ // contents of the frame's output buffer region.
+ SOURCE,
+
+ // The frame should be composited onto the output buffer based on its alpha,
+ // using a simple OVER operation.
+ OVER
+MOZ_END_ENUM_CLASS(BlendMethod)
+
+MOZ_BEGIN_ENUM_CLASS(DisposalMethod, int8_t)
+ CLEAR_ALL = -1, // Clear the whole image, revealing what's underneath.
+ NOT_SPECIFIED, // Leave the frame and let the new frame draw on top.
+ KEEP, // Leave the frame and let the new frame draw on top.
+ CLEAR, // Clear the frame's area, revealing what's underneath.
+ RESTORE_PREVIOUS // Restore the previous (composited) frame.
+MOZ_END_ENUM_CLASS(DisposalMethod)
+
+MOZ_BEGIN_ENUM_CLASS(Opacity, uint8_t)
+ OPAQUE,
+ SOME_TRANSPARENCY
+MOZ_END_ENUM_CLASS(Opacity)
+
class imgFrame
{
typedef gfx::Color Color;
typedef gfx::DataSourceSurface DataSourceSurface;
typedef gfx::DrawTarget DrawTarget;
typedef gfx::IntSize IntSize;
typedef gfx::SourceSurface SourceSurface;
typedef gfx::SurfaceFormat SurfaceFormat;
@@ -108,20 +132,25 @@ public:
uint8_t* GetImageData() const;
void GetPaletteData(uint32_t **aPalette, uint32_t *length) const;
uint32_t* GetPaletteData() const;
uint8_t* GetRawData() const;
int32_t GetRawTimeout() const;
void SetRawTimeout(int32_t aTimeout);
- int32_t GetFrameDisposalMethod() const;
- void SetFrameDisposalMethod(int32_t aFrameDisposalMethod);
- int32_t GetBlendMethod() const;
- void SetBlendMethod(int32_t aBlendMethod);
+ DisposalMethod GetDisposalMethod() const { return mDisposalMethod; }
+ void SetDisposalMethod(DisposalMethod aDisposalMethod)
+ {
+ mDisposalMethod = aDisposalMethod;
+ }
+
+ BlendMethod GetBlendMethod() const { return mBlendMethod; }
+ void SetBlendMethod(BlendMethod aBlendMethod) { mBlendMethod = aBlendMethod; }
+
bool ImageComplete() const;
void SetHasNoAlpha();
void SetAsNonPremult(bool aIsNonPremult);
bool GetCompositingFailed() const;
void SetCompositingFailed(bool val);
@@ -197,27 +226,27 @@ private: // data
// The paletted data comes first, then the image data itself.
// Total length is PaletteDataLength() + GetImageDataLength().
uint8_t* mPalettedImageData;
// Note that the data stored in gfx::Color is *non-alpha-premultiplied*.
Color mSinglePixelColor;
int32_t mTimeout; // -1 means display forever
- int32_t mDisposalMethod;
/** Indicates how many readers currently have locked this frame */
int32_t mLockCount;
RefPtr<VolatileBuffer> mVBuf;
VolatileBufferPtr<uint8_t> mVBufPtr;
- SurfaceFormat mFormat;
- uint8_t mPaletteDepth;
- int8_t mBlendMethod;
+ SurfaceFormat mFormat;
+ uint8_t mPaletteDepth;
+ DisposalMethod mDisposalMethod;
+ BlendMethod mBlendMethod;
bool mSinglePixel;
bool mCompositingFailed;
bool mHasNoAlpha;
bool mNonPremult;
bool mOptimizable;
friend class DrawableFrameRef;
friend class RawAccessFrameRef;
--- a/image/src/moz.build
+++ b/image/src/moz.build
@@ -16,17 +16,16 @@ EXPORTS += [
]
UNIFIED_SOURCES += [
'ClippedImage.cpp',
'DecodePool.cpp',
'Decoder.cpp',
'DynamicImage.cpp',
'FrameAnimator.cpp',
- 'FrameBlender.cpp',
'FrozenImage.cpp',
'Image.cpp',
'ImageFactory.cpp',
'ImageMetadata.cpp',
'ImageOps.cpp',
'ImageWrapper.cpp',
'imgFrame.cpp',
'imgTools.cpp',
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -8487,17 +8487,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
// 2.3. Save callee
masm.storePtr(callee, Address(StackPointer, argOffset));
argOffset += sizeof(size_t);
// 2.4. Load callee executable entry point
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
- masm.loadBaselineOrIonNoArgCheck(callee, callee, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonNoArgCheck(callee, callee, nullptr);
// 3. Argc
unsigned argc = exit.sig().args().length();
masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, argOffset));
argOffset += sizeof(size_t);
// 4. |this| value
masm.storeValue(UndefinedValue(), Address(StackPointer, argOffset));
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -180,18 +180,17 @@ Zone::discardJitCode(FreeOp *fop)
/* Mark baseline scripts on the stack as active. */
jit::MarkActiveBaselineScripts(this);
/* Only mark OSI points if code is being discarded. */
jit::InvalidateAll(fop, this);
for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
- jit::FinishInvalidation<SequentialExecution>(fop, script);
- jit::FinishInvalidation<ParallelExecution>(fop, script);
+ jit::FinishInvalidation(fop, script);
/*
* Discard baseline script if it's not marked as active. Note that
* this also resets the active flag.
*/
jit::FinishDiscardBaselineScript(fop, script);
/*
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/execution-observability-03.js
@@ -0,0 +1,17 @@
+// Tests that bare callVMs (in the delprop below) are patched correctly.
+
+var o = {};
+var global = this;
+var p = new Proxy(o, {
+ "deleteProperty": function (target, key) {
+ var g = newGlobal();
+ g.parent = global;
+ g.eval("var dbg = new Debugger(parent); dbg.onEnterFrame = function(frame) {};");
+ return true;
+ }
+});
+function test() {
+ for (var i=0; i<100; i++) {}
+ assertEq(delete p.foo, true);
+}
+test();
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -546,17 +546,17 @@ BaselineCompiler::emitStackCheck(bool ea
pushArg(R1.scratchReg());
CallVMPhase phase = POST_INITIALIZE;
if (earlyCheck)
phase = PRE_INITIALIZE;
else if (needsEarlyStackCheck())
phase = CHECK_OVER_RECURSED;
- if (!callVM(CheckOverRecursedWithExtraInfo, phase))
+ if (!callVMNonOp(CheckOverRecursedWithExtraInfo, phase))
return false;
masm.bind(&skipCall);
return true;
}
typedef bool (*DebugPrologueFn)(JSContext *, BaselineFrame *, jsbytecode *, bool *);
static const VMFunction DebugPrologueInfo = FunctionInfo<DebugPrologueFn>(jit::DebugPrologue);
@@ -621,31 +621,31 @@ BaselineCompiler::initScopeChain()
if (fun->isHeavyweight()) {
// Call into the VM to create a new call object.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
- if (!callVM(HeavyweightFunPrologueInfo, phase))
+ if (!callVMNonOp(HeavyweightFunPrologueInfo, phase))
return false;
}
} else {
// ScopeChain pointer in BaselineFrame has already been initialized
// in prologue.
if (script->isForEval() && script->strict()) {
// Strict eval needs its own call object.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
- if (!callVM(StrictEvalPrologueInfo, phase))
+ if (!callVMNonOp(StrictEvalPrologueInfo, phase))
return false;
}
}
return true;
}
typedef bool (*InterruptCheckFn)(JSContext *);
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -345,18 +345,17 @@ PatchBaselineFramesForDebugMode(JSContex
// Recompile Patching Overview
//
// When toggling debug mode with live baseline scripts on the stack, we
// could have entered the VM via the following ways from the baseline
// script.
//
// Off to On:
// A. From a "can call" stub.
- // B. From a VM call (interrupt handler, debugger statement handler,
- // throw).
+ // B. From a VM call.
// H. From inside HandleExceptionBaseline.
//
// On to Off:
// - All the ways above.
// C. From the debug trap handler.
// D. From the debug prologue.
// E. From the debug epilogue.
//
@@ -468,35 +467,37 @@ PatchBaselineFramesForDebugMode(JSContex
}
// The RecompileInfo must already be allocated so that this
// function may be infallible.
BaselineDebugModeOSRInfo *recompInfo = entry.takeRecompInfo();
bool popFrameReg;
switch (kind) {
- case ICEntry::Kind_CallVM:
+ case ICEntry::Kind_CallVM: {
// Case B above.
//
- // Patching returns from an interrupt handler or the debugger
- // statement handler is similar in that we can resume at the
- // next op.
+ // Patching returns from a VM call. After fixing up the the
+ // continuation for unsynced values (the frame register is
+ // popped by the callVM trampoline), we resume at the
+ // return-from-callVM address. The assumption here is that all
+ // callVMs which can trigger debug mode OSR are the *only*
+ // callVMs generated for their respective pc locations in the
+ // baseline JIT code.
//
- // Throws are treated differently, as patching a throw means
- // we are recompiling on-stack scripts from inside an
- // onExceptionUnwind invocation. The resume address must be
- // settled on the throwing pc and not its successor, so that
- // Debugger.Frame may report the correct offset. Note we never
- // actually resume execution there, and it is set for the sake
- // of frame iterators.
- if (!iter.baselineFrame()->isDebuggerHandlingException())
- pc += GetBytecodeLength(pc);
- recompInfo->resumeAddr = bl->nativeCodeForPC(script, pc, &recompInfo->slotInfo);
- popFrameReg = true;
+ // Get the slot info for the next pc, but ignore the code
+ // address. We get the code address from the
+ // return-from-callVM entry instead.
+ (void) bl->maybeNativeCodeForPC(script, pc + GetBytecodeLength(pc),
+ &recompInfo->slotInfo);
+ ICEntry &callVMEntry = bl->callVMEntryFromPCOffset(pcOffset);
+ recompInfo->resumeAddr = bl->returnAddressForIC(callVMEntry);
+ popFrameReg = false;
break;
+ }
case ICEntry::Kind_DebugTrap:
// Case C above.
//
// Debug traps are emitted before each op, so we resume at the
// same op. Calling debug trap handlers is done via a toggled
// call to a thunk (DebugTrapHandler) that takes care tearing
// down its own stub frame so we don't need to worry about
@@ -901,22 +902,19 @@ HasForcedReturn(BaselineDebugModeOSRInfo
ICEntry::Kind kind = info->frameKind;
// The debug epilogue always checks its resumption value, so we don't need
// to check rv.
if (kind == ICEntry::Kind_DebugEpilogue)
return true;
// |rv| is the value in ReturnReg. If true, in the case of the prologue,
- // debug trap, and debugger statement handler, it means a forced return.
- if (kind == ICEntry::Kind_DebugPrologue ||
- (kind == ICEntry::Kind_CallVM && JSOp(*info->pc) == JSOP_DEBUGGER))
- {
+ // it means a forced return.
+ if (kind == ICEntry::Kind_DebugPrologue)
return rv;
- }
// N.B. The debug trap handler handles its own forced return, so no
// need to deal with it here.
return false;
}
static void
SyncBaselineDebugModeOSRInfo(BaselineFrame *frame, Value *vp, bool rv)
@@ -929,23 +927,29 @@ SyncBaselineDebugModeOSRInfo(BaselineFra
// Load the frame's rval and overwrite the resume address to go to the
// epilogue.
MOZ_ASSERT(R0 == JSReturnOperand);
info->valueR0 = frame->returnValue();
info->resumeAddr = frame->script()->baselineScript()->epilogueEntryAddr();
return;
}
- // Read stack values and make sure R0 and R1 have the right values.
- unsigned numUnsynced = info->slotInfo.numUnsynced();
- MOZ_ASSERT(numUnsynced <= 2);
- if (numUnsynced > 0)
- info->popValueInto(info->slotInfo.topSlotLocation(), vp);
- if (numUnsynced > 1)
- info->popValueInto(info->slotInfo.nextSlotLocation(), vp);
+ // Read stack values and make sure R0 and R1 have the right values if we
+ // aren't returning from a callVM.
+ //
+ // In the case of returning from a callVM, we don't need to restore R0 and
+ // R1 ourself since we'll return into code that does it if needed.
+ if (info->frameKind != ICEntry::Kind_CallVM) {
+ unsigned numUnsynced = info->slotInfo.numUnsynced();
+ MOZ_ASSERT(numUnsynced <= 2);
+ if (numUnsynced > 0)
+ info->popValueInto(info->slotInfo.topSlotLocation(), vp);
+ if (numUnsynced > 1)
+ info->popValueInto(info->slotInfo.nextSlotLocation(), vp);
+ }
// Scale stackAdjust.
info->stackAdjust *= sizeof(Value);
}
static void
FinishBaselineDebugModeOSR(BaselineFrame *frame)
{
@@ -980,16 +984,63 @@ JitRuntime::getBaselineDebugModeOSRHandl
{
if (!getBaselineDebugModeOSRHandler(cx))
return nullptr;
return popFrameReg
? baselineDebugModeOSRHandler_->raw()
: baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
}
+static void
+EmitBaselineDebugModeOSRHandlerTail(MacroAssembler &masm, Register temp, bool returnFromCallVM)
+{
+ // Save real return address on the stack temporarily.
+ //
+ // If we're returning from a callVM, we don't need to worry about R0 and
+ // R1 but do need to propagate the original ReturnReg value. Otherwise we
+ // need to worry about R0 and R1 but can clobber ReturnReg. Indeed, on
+ // x86, R1 contains ReturnReg.
+ if (returnFromCallVM) {
+ masm.push(ReturnReg);
+ } else {
+ masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR0)));
+ masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR1)));
+ }
+ masm.push(BaselineFrameReg);
+ masm.push(Address(temp, offsetof(BaselineDebugModeOSRInfo, resumeAddr)));
+
+ // Call a stub to free the allocated info.
+ masm.setupUnalignedABICall(1, temp);
+ masm.loadBaselineFramePtr(BaselineFrameReg, temp);
+ masm.passABIArg(temp);
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FinishBaselineDebugModeOSR));
+
+ // Restore saved values.
+ GeneralRegisterSet jumpRegs(GeneralRegisterSet::All());
+ if (returnFromCallVM) {
+ jumpRegs.take(ReturnReg);
+ } else {
+ jumpRegs.take(R0);
+ jumpRegs.take(R1);
+ }
+ jumpRegs.take(BaselineFrameReg);
+ Register target = jumpRegs.takeAny();
+
+ masm.pop(target);
+ masm.pop(BaselineFrameReg);
+ if (returnFromCallVM) {
+ masm.pop(ReturnReg);
+ } else {
+ masm.popValue(R1);
+ masm.popValue(R0);
+ }
+
+ masm.jump(target);
+}
+
JitCode *
JitRuntime::generateBaselineDebugModeOSRHandler(JSContext *cx, uint32_t *noFrameRegPopOffsetOut)
{
MacroAssembler masm(cx);
GeneralRegisterSet regs(GeneralRegisterSet::All());
regs.take(BaselineFrameReg);
regs.take(ReturnReg);
@@ -1000,58 +1051,49 @@ JitRuntime::generateBaselineDebugModeOSR
masm.pop(BaselineFrameReg);
// Not all patched baseline frames are returning from a situation where
// the frame reg is already fixed up.
CodeOffsetLabel noFrameRegPopOffset(masm.currentOffset());
// Record the stack pointer for syncing.
masm.movePtr(StackPointer, syncedStackStart);
+ masm.push(ReturnReg);
masm.push(BaselineFrameReg);
// Call a stub to fully initialize the info.
masm.setupUnalignedABICall(3, temp);
masm.loadBaselineFramePtr(BaselineFrameReg, temp);
masm.passABIArg(temp);
masm.passABIArg(syncedStackStart);
masm.passABIArg(ReturnReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, SyncBaselineDebugModeOSRInfo));
// Discard stack values depending on how many were unsynced, as we always
- // have a fully synced stack in the recompile handler. See assert in
- // DebugModeOSREntry constructor.
+ // have a fully synced stack in the recompile handler. We arrive here via
+ // a callVM, and prepareCallVM in BaselineCompiler always fully syncs the
+ // stack.
masm.pop(BaselineFrameReg);
+ masm.pop(ReturnReg);
masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue()), temp);
masm.addPtr(Address(temp, offsetof(BaselineDebugModeOSRInfo, stackAdjust)), StackPointer);
- // Save real return address on the stack temporarily.
- masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR0)));
- masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR1)));
- masm.push(BaselineFrameReg);
- masm.push(Address(temp, offsetof(BaselineDebugModeOSRInfo, resumeAddr)));
-
- // Call a stub to free the allocated info.
- masm.setupUnalignedABICall(1, temp);
- masm.loadBaselineFramePtr(BaselineFrameReg, temp);
- masm.passABIArg(temp);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FinishBaselineDebugModeOSR));
+ // Emit two tails for the case of returning from a callVM and all other
+ // cases, as the state we need to restore differs depending on the case.
+ Label returnFromCallVM, end;
+ masm.branch32(MacroAssembler::Equal,
+ Address(temp, offsetof(BaselineDebugModeOSRInfo, frameKind)),
+ Imm32(ICEntry::Kind_CallVM),
+ &returnFromCallVM);
- // Restore saved values.
- GeneralRegisterSet jumpRegs(GeneralRegisterSet::All());
- jumpRegs.take(R0);
- jumpRegs.take(R1);
- jumpRegs.take(BaselineFrameReg);
- Register target = jumpRegs.takeAny();
-
- masm.pop(target);
- masm.pop(BaselineFrameReg);
- masm.popValue(R1);
- masm.popValue(R0);
-
- masm.jump(target);
+ EmitBaselineDebugModeOSRHandlerTail(masm, temp, /* returnFromCallVM = */ false);
+ masm.jump(&end);
+ masm.bind(&returnFromCallVM);
+ EmitBaselineDebugModeOSRHandlerTail(masm, temp, /* returnFromCallVM = */ true);
+ masm.bind(&end);
Linker linker(masm);
AutoFlushICache afc("BaselineDebugModeOSRHandler");
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
if (!code)
return nullptr;
noFrameRegPopOffset.fixup(&masm);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4256,30 +4256,30 @@ ICGetElemNativeCompiler::emitCallScripte
masm.Push(Imm32(0)); // ActualArgc is 0
masm.Push(callee);
masm.Push(callScratch);
regs.add(callScratch);
}
Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(code, code, nullptr);
Register scratch = regs.takeAny();
// Handle arguments underflow.
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -4489,18 +4489,17 @@ ICGetElemNativeCompiler::generateStubCod
} else {
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
// Load function in scratchReg and ensure that it has a jit script.
masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()),
scratchReg);
masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure);
masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
- masm.loadBaselineOrIonRaw(scratchReg, scratchReg, SequentialExecution,
- popR1 ? &failurePopR1 : &failure);
+ masm.loadBaselineOrIonRaw(scratchReg, scratchReg, popR1 ? &failurePopR1 : &failure);
// At this point, we are guaranteed to successfully complete.
if (popR1)
masm.addPtr(Imm32(sizeof(size_t)), BaselineStackReg);
emitCallScripted(masm, objReg);
}
}
@@ -7416,17 +7415,17 @@ ICGetProp_CallScripted::Compiler::genera
regs.take(callee);
} else {
callee = regs.takeAny();
}
Register code = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfGetter()), callee);
masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
// Getter is called with 0 arguments, just |obj| as thisv.
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
masm.Push(R0);
EmitCreateStubFrameDescriptor(masm, scratch);
masm.Push(Imm32(0)); // ActualArgc is 0
masm.Push(callee);
@@ -7436,17 +7435,17 @@ ICGetProp_CallScripted::Compiler::genera
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -8788,17 +8787,17 @@ ICSetProp_CallScripted::Compiler::genera
regs.take(callee);
} else {
callee = regs.takeAny();
}
Register code = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfSetter()), callee);
masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
// Setter is called with the new value as the only argument, and |obj| as thisv.
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
// To Push R1, read it off of the stowed values on stack.
// Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
masm.movePtr(BaselineStackReg, scratch);
@@ -8813,17 +8812,17 @@ ICSetProp_CallScripted::Compiler::genera
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::BelowOrEqual, scratch, Imm32(1), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(1), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -9755,17 +9754,17 @@ ICCallStubCompiler::guardFunApply(MacroA
failure);
if (checkNative) {
masm.branchIfInterpreted(target, failure);
} else {
masm.branchIfFunctionHasNoScript(target, failure);
Register temp = regs.takeAny();
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp);
- masm.loadBaselineOrIonRaw(temp, temp, SequentialExecution, failure);
+ masm.loadBaselineOrIonRaw(temp, temp, failure);
regs.add(temp);
}
return target;
}
void
ICCallStubCompiler::pushCallerArguments(MacroAssembler &masm, GeneralRegisterSet regs)
{
@@ -9990,17 +9989,17 @@ ICCallScriptedCompiler::generateStubCode
masm.branchIfFunctionHasNoScript(callee, &failure);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
}
// Load the start of the target JitCode.
Register code;
if (!isConstructing_) {
code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
+ masm.loadBaselineOrIonRaw(callee, code, &failure);
} else {
Address scriptCode(callee, JSScript::offsetOfBaselineOrIonRaw());
masm.branchPtr(Assembler::Equal, scriptCode, ImmPtr(nullptr), &failure);
}
// We no longer need R1.
regs.add(R1);
@@ -10074,17 +10073,17 @@ ICCallScriptedCompiler::generateStubCode
masm.loadValue(calleeSlot3, R0);
}
callee = masm.extractObject(R0, ExtractTemp0);
regs.add(R0);
regs.takeUnchecked(callee);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(callee, code, &failureLeaveStubFrame);
// Release callee register, but don't add ExtractTemp0 back into the pool
// ExtractTemp0 is used later, and if it's allocated to some other register at that
// point, it will get clobbered when used.
if (callee != ExtractTemp0)
regs.add(callee);
if (canUseTailCallReg)
@@ -10118,17 +10117,17 @@ ICCallScriptedCompiler::generateStubCode
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -10595,28 +10594,28 @@ ICCall_ScriptedApplyArray::Compiler::gen
masm.Push(argcReg);
masm.Push(target);
masm.Push(scratch);
// Load nargs into scratch for underflow check, and then load jitcode pointer into target.
masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
- masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(target, target, nullptr);
// Handle arguments underflow.
Label noUnderflow;
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != target);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -10696,28 +10695,28 @@ ICCall_ScriptedApplyArguments::Compiler:
masm.loadPtr(Address(argcReg, BaselineFrame::offsetOfNumActualArgs()), argcReg);
masm.Push(argcReg);
masm.Push(target);
masm.Push(scratch);
// Load nargs into scratch for underflow check, and then load jitcode pointer into target.
masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
- masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(target, target, nullptr);
// Handle arguments underflow.
Label noUnderflow;
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != target);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -10776,17 +10775,17 @@ ICCall_ScriptedFunCall::Compiler::genera
masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
&failure);
masm.branchIfFunctionHasNoScript(callee, &failure);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
// Load the start of the target JitCode.
Register code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
+ masm.loadBaselineOrIonRaw(callee, code, &failure);
// We no longer need R1.
regs.add(R1);
// Push a stub frame so that we can perform a non-tail call.
enterStubFrame(masm, regs.getAny());
if (canUseTailCallReg)
regs.add(BaselineTailCallReg);
@@ -10829,17 +10828,17 @@ ICCall_ScriptedFunCall::Compiler::genera
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -217,19 +217,23 @@ class ICEntry
public:
enum Kind {
// A for-op IC entry.
Kind_Op = 0,
// A non-op IC entry.
Kind_NonOp,
- // A fake IC entry for returning from a callVM.
+ // A fake IC entry for returning from a callVM for an op.
Kind_CallVM,
+ // A fake IC entry for returning from a callVM not for an op (e.g., in
+ // the prologue).
+ Kind_NonOpCallVM,
+
// A fake IC entry for returning from DebugTrapHandler.
Kind_DebugTrap,
// A fake IC entry for returning from a callVM to
// Debug{Prologue,Epilogue}.
Kind_DebugPrologue,
Kind_DebugEpilogue,
@@ -294,16 +298,20 @@ class ICEntry
void setForDebugPrologue() {
MOZ_ASSERT(kind() == Kind_CallVM);
setKind(Kind_DebugPrologue);
}
void setForDebugEpilogue() {
MOZ_ASSERT(kind() == Kind_CallVM);
setKind(Kind_DebugEpilogue);
}
+ void setForNonOpCallVM() {
+ MOZ_ASSERT(kind() == Kind_CallVM);
+ setKind(Kind_NonOpCallVM);
+ }
bool hasStub() const {
return firstStub_ != nullptr;
}
ICStub *firstStub() const {
MOZ_ASSERT(hasStub());
return firstStub_;
}
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -558,34 +558,41 @@ BaselineScript::icEntryFromReturnOffset(
}
uint8_t *
BaselineScript::returnAddressForIC(const ICEntry &ent)
{
return method()->raw() + ent.returnOffset().offset();
}
-ICEntry &
-BaselineScript::icEntryFromPCOffset(uint32_t pcOffset)
+static inline size_t
+ComputeBinarySearchMid(BaselineScript *baseline, uint32_t pcOffset)
{
- // Multiple IC entries can have the same PC offset, but this method only looks for
- // those which have isForOp() set.
size_t bottom = 0;
- size_t top = numICEntries();
+ size_t top = baseline->numICEntries();
size_t mid = bottom + (top - bottom) / 2;
while (mid < top) {
- ICEntry &midEntry = icEntry(mid);
+ ICEntry &midEntry = baseline->icEntry(mid);
if (midEntry.pcOffset() < pcOffset)
bottom = mid + 1;
else if (midEntry.pcOffset() > pcOffset)
top = mid;
else
break;
mid = bottom + (top - bottom) / 2;
}
+ return mid;
+}
+
+ICEntry &
+BaselineScript::icEntryFromPCOffset(uint32_t pcOffset)
+{
+ // Multiple IC entries can have the same PC offset, but this method only looks for
+ // those which have isForOp() set.
+ size_t mid = ComputeBinarySearchMid(this, pcOffset);
// Found an IC entry with a matching PC offset. Search backward, and then
// forward from this IC entry, looking for one with the same PC offset which
// has isForOp() set.
for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--) {
if (icEntry(i).isForOp())
return icEntry(i);
}
@@ -614,16 +621,34 @@ BaselineScript::icEntryFromPCOffset(uint
}
MOZ_ASSERT(curEntry->pcOffset() == pcOffset && curEntry->isForOp());
return *curEntry;
}
return icEntryFromPCOffset(pcOffset);
}
+ICEntry &
+BaselineScript::callVMEntryFromPCOffset(uint32_t pcOffset)
+{
+ // Like icEntryFromPCOffset, but only looks for the fake ICEntries
+ // inserted by VM calls.
+ size_t mid = ComputeBinarySearchMid(this, pcOffset);
+
+ for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--) {
+ if (icEntry(i).kind() == ICEntry::Kind_CallVM)
+ return icEntry(i);
+ }
+ for (size_t i = mid+1; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i++) {
+ if (icEntry(i).kind() == ICEntry::Kind_CallVM)
+ return icEntry(i);
+ }
+ MOZ_CRASH("Invalid PC offset for callVM entry.");
+}
+
ICEntry *
BaselineScript::maybeICEntryFromReturnAddress(uint8_t *returnAddr)
{
MOZ_ASSERT(returnAddr > method_->raw());
MOZ_ASSERT(returnAddr < method_->raw() + method_->instructionsSize());
CodeOffsetLabel offset(returnAddr - method_->raw());
return maybeICEntryFromReturnOffset(offset);
}
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -341,16 +341,17 @@ struct BaselineScript
return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
}
ICEntry &icEntry(size_t index);
ICEntry *maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset);
ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset);
ICEntry &icEntryFromPCOffset(uint32_t pcOffset);
ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry);
+ ICEntry &callVMEntryFromPCOffset(uint32_t pcOffset);
ICEntry *maybeICEntryFromReturnAddress(uint8_t *returnAddr);
ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr);
uint8_t *returnAddressForIC(const ICEntry &ent);
size_t numICEntries() const {
return icEntries_;
}
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -26,20 +26,17 @@
#include "jit/IonCaches.h"
#include "jit/IonOptimizationLevels.h"
#include "jit/JitcodeMap.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/Lowering.h"
#include "jit/MIRGenerator.h"
#include "jit/MoveEmitter.h"
-#include "jit/ParallelFunctions.h"
-#include "jit/ParallelSafetyAnalysis.h"
#include "jit/RangeAnalysis.h"
-#include "vm/ForkJoin.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpStatics.h"
#include "vm/TraceLogging.h"
#include "jsboolinlines.h"
#include "jit/ExecutionMode-inl.h"
#include "jit/shared/CodeGenerator-shared-inl.h"
@@ -162,20 +159,17 @@ CodeGenerator::CodeGenerator(MIRGenerato
CodeGenerator::~CodeGenerator()
{
MOZ_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
js_delete(scriptCounts_);
}
typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
-typedef bool (*StringToNumberParFn)(ForkJoinContext *, JSString *, double *);
-static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
- FunctionInfo<StringToNumberFn>(StringToNumber),
- FunctionInfo<StringToNumberParFn>(StringToNumberPar));
+static const VMFunction StringToNumberInfo = FunctionInfo<StringToNumberFn>(StringToNumber);
void
CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
{
ValueOperand operand = ToValue(lir, LValueToInt32::Input);
Register output = ToRegister(lir->output());
FloatRegister temp = ToFloatRegister(lir->tempFloat());
@@ -816,40 +810,34 @@ CodeGenerator::emitIntToString(Register
masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
// Fast path for small integers.
masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().intStaticTable), output);
masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
}
typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
-typedef JSFlatString *(*IntToStringParFn)(ForkJoinContext *, int);
-static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
- FunctionInfo<IntToStringFn>(Int32ToString<CanGC>),
- FunctionInfo<IntToStringParFn>(IntToStringPar));
+static const VMFunction IntToStringInfo = FunctionInfo<IntToStringFn>(Int32ToString<CanGC>);
void
CodeGenerator::visitIntToString(LIntToString *lir)
{
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
StoreRegisterTo(output));
emitIntToString(input, output, ool->entry());
masm.bind(ool->rejoin());
}
typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
-typedef JSString *(*DoubleToStringParFn)(ForkJoinContext *, double);
-static const VMFunctionsModal DoubleToStringInfo = VMFunctionsModal(
- FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>),
- FunctionInfo<DoubleToStringParFn>(DoubleToStringPar));
+static const VMFunction DoubleToStringInfo = FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>);
void
CodeGenerator::visitDoubleToString(LDoubleToString *lir)
{
FloatRegister input = ToFloatRegister(lir->input());
Register temp = ToRegister(lir->tempInt());
Register output = ToRegister(lir->output());
@@ -859,20 +847,17 @@ CodeGenerator::visitDoubleToString(LDoub
// Try double to integer conversion and run integer to string code.
masm.convertDoubleToInt32(input, temp, ool->entry(), true);
emitIntToString(temp, output, ool->entry());
masm.bind(ool->rejoin());
}
typedef JSString *(*PrimitiveToStringFn)(JSContext *, HandleValue);
-typedef JSString *(*PrimitiveToStringParFn)(ForkJoinContext *, HandleValue);
-static const VMFunctionsModal PrimitiveToStringInfo = VMFunctionsModal(
- FunctionInfo<PrimitiveToStringFn>(ToStringSlow),
- FunctionInfo<PrimitiveToStringParFn>(PrimitiveToStringPar));
+static const VMFunction PrimitiveToStringInfo = FunctionInfo<PrimitiveToStringFn>(ToStringSlow);
void
CodeGenerator::visitValueToString(LValueToString *lir)
{
ValueOperand input = ToValue(lir, LValueToString::Input);
Register output = ToRegister(lir->output());
OutOfLineCode *ool = oolCallVM(PrimitiveToStringInfo, lir, (ArgList(), input),
@@ -1761,32 +1746,16 @@ CodeGenerator::emitLambdaInit(Register o
masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));
masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
Address(output, JSFunction::offsetOfNativeOrScript()));
masm.storePtr(scopeChain, Address(output, JSFunction::offsetOfEnvironment()));
masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
}
void
-CodeGenerator::visitLambdaPar(LLambdaPar *lir)
-{
- Register resultReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register scopeChainReg = ToRegister(lir->scopeChain());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- const LambdaFunctionInfo &info = lir->mir()->info();
-
- MOZ_ASSERT(scopeChainReg != resultReg);
-
- emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, info.fun);
- emitLambdaInit(resultReg, scopeChainReg, info);
-}
-
-void
CodeGenerator::visitLabel(LLabel *lir)
{
}
void
CodeGenerator::visitNop(LNop *lir)
{
}
@@ -1848,20 +1817,17 @@ class OutOfLineInterruptCheckImplicit :
{ }
void accept(CodeGenerator *codegen) {
codegen->visitOutOfLineInterruptCheckImplicit(this);
}
};
typedef bool (*InterruptCheckFn)(JSContext *);
-typedef bool (*InterruptCheckParFn)(ForkJoinContext *);
-static const VMFunctionsModal InterruptCheckInfo = VMFunctionsModal(
- FunctionInfo<InterruptCheckFn>(InterruptCheck),
- FunctionInfo<InterruptCheckParFn>(InterruptCheckPar));
+static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
void
CodeGenerator::visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ool)
{
#ifdef CHECK_OSIPOINT_REGISTERS
// This is path is entered from the patched back-edge of the loop. This
// means that the JitAtivation flags used for checking the validity of the
// OSI points are not reseted by the path generated by generateBody, so we
@@ -2016,20 +1982,18 @@ CodeGenerator::visitReturn(LReturn *lir)
void
CodeGenerator::visitOsrEntry(LOsrEntry *lir)
{
// Remember the OSR entry offset into the code buffer.
masm.flushBuffer();
setOsrEntryOffset(masm.size());
#ifdef JS_TRACE_LOGGING
- if (gen->info().executionMode() == SequentialExecution) {
- emitTracelogStopEvent(TraceLogger_Baseline);
- emitTracelogStartEvent(TraceLogger_IonMonkey);
- }
+ emitTracelogStopEvent(TraceLogger_Baseline);
+ emitTracelogStartEvent(TraceLogger_IonMonkey);
#endif
// Allocate the full frame for this function
// Note we have a new entry here. So we reset MacroAssembler::framePushed()
// to 0, before reserving the stack.
MOZ_ASSERT(masm.framePushed() == frameSize());
masm.setFramePushed(0);
masm.reserveStack(frameSize());
@@ -2448,40 +2412,16 @@ CodeGenerator::visitMaybeCopyElementsFor
void
CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment *lir)
{
Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
masm.loadPtr(environment, ToRegister(lir->output()));
}
void
-CodeGenerator::visitForkJoinContext(LForkJoinContext *lir)
-{
- const Register tempReg = ToRegister(lir->getTempReg());
-
- masm.setupUnalignedABICall(0, tempReg);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ForkJoinContextPar));
- MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
-}
-
-void
-CodeGenerator::visitGuardThreadExclusive(LGuardThreadExclusive *lir)
-{
- MOZ_ASSERT(gen->info().executionMode() == ParallelExecution);
-
- const Register tempReg = ToRegister(lir->getTempReg());
- masm.setupUnalignedABICall(2, tempReg);
- masm.passABIArg(ToRegister(lir->forkJoinContext()));
- masm.passABIArg(ToRegister(lir->object()));
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ParallelWriteGuard));
-
- bailoutIfFalseBool(ReturnReg, lir->snapshot());
-}
-
-void
CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity *guard)
{
Register obj = ToRegister(guard->input());
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
bailoutCmpPtr(cond, obj, ImmGCPtr(guard->mir()->singleObject()), guard->snapshot());
}
@@ -2664,71 +2604,51 @@ CodeGenerator::visitCallNative(LCallNati
// Misc. temporary registers.
const Register tempReg = ToRegister(call->getTempReg());
DebugOnly<uint32_t> initialStack = masm.framePushed();
masm.checkStackAlignment();
- // Sequential native functions have the signature:
+ // Native functions have the signature:
// bool (*)(JSContext *, unsigned, Value *vp)
- // and parallel native functions have the signature:
- // ParallelResult (*)(ForkJoinContext *, unsigned, Value *vp)
// Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
// are the function arguments.
// Allocate space for the outparam, moving the StackPointer to what will be &vp[1].
masm.adjustStack(unusedStack);
// Push a Value containing the callee object: natives are allowed to access their callee before
// setitng the return value. The StackPointer is moved to &vp[0].
masm.Push(ObjectValue(*target));
// Preload arguments into registers.
- //
- // Note that for parallel execution, loadContext does an ABI call, so we
- // need to do this before we load the other argument registers, otherwise
- // we'll hose them.
- ExecutionMode executionMode = gen->info().executionMode();
- masm.loadContext(argContextReg, tempReg, executionMode);
+ masm.loadJSContext(argContextReg);
masm.move32(Imm32(call->numStackArgs()), argUintNReg);
masm.movePtr(StackPointer, argVpReg);
masm.Push(argUintNReg);
// Construct native exit frame.
uint32_t safepointOffset;
masm.buildFakeExitFrame(tempReg, &safepointOffset);
- masm.enterFakeExitFrame(argContextReg, tempReg, executionMode,
- NativeExitFrameLayout::Token());
+ masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
markSafepointAt(safepointOffset, call);
// Construct and execute call.
masm.setupUnalignedABICall(3, tempReg);
masm.passABIArg(argContextReg);
masm.passABIArg(argUintNReg);
masm.passABIArg(argVpReg);
-
- switch (executionMode) {
- case SequentialExecution:
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->native()));
- break;
-
- case ParallelExecution:
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->parallelNative()));
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->native()));
// Test for failure.
- masm.branchIfFalseBool(ReturnReg, masm.failureLabel(executionMode));
+ masm.branchIfFalseBool(ReturnReg, masm.failureLabel());
// Load the outparam vp[0] into output register(s).
masm.loadValue(Address(StackPointer, NativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
// The next instruction is removing the footer of the exit frame, so there
// is no need for leaveFakeExitFrame.
// Move the StackPointer back to its original location, unwinding the native exit frame.
@@ -2903,24 +2823,23 @@ CodeGenerator::emitCallInvokeFunction(LI
void
CodeGenerator::visitCallGeneric(LCallGeneric *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
Register nargsreg = ToRegister(call->getNargsReg());
uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
- ExecutionMode executionMode = gen->info().executionMode();
Label invoke, thunk, makeCall, end;
// Known-target case is handled by LCallKnown.
MOZ_ASSERT(!call->hasSingleTarget());
// Generate an ArgumentsRectifier.
- JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
+ JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
masm.checkStackAlignment();
// Guard that calleereg is actually a function object.
masm.loadObjClass(calleereg, nargsreg);
masm.branchPtr(Assembler::NotEqual, nargsreg, ImmPtr(&JSFunction::class_), &invoke);
// Guard that calleereg is an interpreted function with a JSScript.
@@ -2929,17 +2848,17 @@ CodeGenerator::visitCallGeneric(LCallGen
masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
else
masm.branchIfFunctionHasNoScript(calleereg, &invoke);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
masm.Push(Imm32(call->numActualArgs()));
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
@@ -2967,65 +2886,39 @@ CodeGenerator::visitCallGeneric(LCallGen
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled or native functions.
masm.bind(&invoke);
- switch (executionMode) {
- case SequentialExecution:
- emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
- break;
-
- case ParallelExecution:
- emitCallToUncompiledScriptPar(call, calleereg);
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
masm.bind(&end);
// If the return value of the constructing function is Primitive,
// replace the return value with the Object from CreateThis.
if (call->mir()->isConstructing()) {
Label notPrimitive;
masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
masm.bind(¬Primitive);
}
dropArguments(call->numStackArgs() + 1);
}
-typedef bool (*CallToUncompiledScriptParFn)(ForkJoinContext *, JSObject *);
-static const VMFunction CallToUncompiledScriptParInfo =
- FunctionInfo<CallToUncompiledScriptParFn>(CallToUncompiledScriptPar);
-
-// Generates a call to CallToUncompiledScriptPar() and then bails out.
-// |calleeReg| should contain the JSFunction*.
-void
-CodeGenerator::emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg)
-{
- pushArg(calleeReg);
- callVM(CallToUncompiledScriptParInfo, lir);
- masm.assumeUnreachable("CallToUncompiledScriptParInfo always returns false.");
-}
-
void
CodeGenerator::visitCallKnown(LCallKnown *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
DebugOnly<JSFunction *> target = call->getSingleTarget();
- ExecutionMode executionMode = gen->info().executionMode();
Label end, uncompiled;
// Native single targets are handled by LCallNative.
MOZ_ASSERT(!target->isNative());
// Missing arguments must have been explicitly appended by the IonBuilder.
MOZ_ASSERT(target->nargs() <= call->numStackArgs());
MOZ_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor());
@@ -3036,19 +2929,19 @@ CodeGenerator::visitCallKnown(LCallKnown
// a LazyScript instead of a JSScript.
masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
if (call->mir()->needsArgCheck())
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &uncompiled);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &uncompiled);
else
- masm.loadBaselineOrIonNoArgCheck(objreg, objreg, executionMode, &uncompiled);
+ masm.loadBaselineOrIonNoArgCheck(objreg, objreg, &uncompiled);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
masm.Push(Imm32(call->numActualArgs()));
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
@@ -3061,28 +2954,17 @@ CodeGenerator::visitCallKnown(LCallKnown
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled functions.
masm.bind(&uncompiled);
- switch (executionMode) {
- case SequentialExecution:
- emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
- break;
-
- case ParallelExecution:
- emitCallToUncompiledScriptPar(call, calleereg);
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
masm.bind(&end);
// If the return value of the constructing function is Primitive,
// replace the return value with the Object from CreateThis.
if (call->mir()->isConstructing()) {
Label notPrimitive;
masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
@@ -3195,17 +3077,16 @@ CodeGenerator::visitApplyArgsGeneric(LAp
}
// Copy the arguments of the current function.
emitPushArguments(apply, copyreg);
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
- ExecutionMode executionMode = gen->info().executionMode();
if (apply->hasSingleTarget()) {
JSFunction *target = apply->getSingleTarget();
if (target->isNative()) {
emitCallInvokeFunction(apply, copyreg);
emitPopArguments(apply, copyreg);
return;
}
}
@@ -3219,17 +3100,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
// Native single targets are handled by LCallNative.
MOZ_ASSERT(!apply->getSingleTarget()->isNative());
}
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
// Call with an Ion frame or a rectifier frame.
{
// Create the frame descriptor.
unsigned pushed = masm.framePushed();
masm.addPtr(Imm32(pushed), copyreg);
masm.makeFrameDescriptor(copyreg, JitFrame_IonJS);
@@ -3252,17 +3133,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
// underflow.
masm.jump(&rejoin);
// Argument fixup needed. Get ready to call the argumentsRectifier.
{
masm.bind(&underflow);
// Hardcode the address of the argumentsRectifier code.
- JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
+ JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
MOZ_ASSERT(ArgumentsRectifierReg != objreg);
masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
masm.movePtr(argcreg, ArgumentsRectifierReg);
}
masm.bind(&rejoin);
@@ -3548,20 +3429,18 @@ CodeGenerator::visitDefFun(LDefFun *lir)
pushArg(ImmGCPtr(lir->mir()->fun()));
pushArg(scopeChain);
pushArg(ImmGCPtr(current->mir()->info().script()));
callVM(DefFunOperationInfo, lir);
}
typedef bool (*CheckOverRecursedFn)(JSContext *);
-typedef bool (*CheckOverRecursedParFn)(ForkJoinContext *);
-static const VMFunctionsModal CheckOverRecursedInfo = VMFunctionsModal(
- FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed),
- FunctionInfo<CheckOverRecursedParFn>(CheckOverRecursedPar));
+static const VMFunction CheckOverRecursedInfo =
+ FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed);
void
CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
{
// The OOL path is hit if the recursion depth has been exceeded.
// Throw an InternalError for over-recursion.
// LFunctionEnvironment can appear before LCheckOverRecursed, so we have
@@ -3570,52 +3449,16 @@ CodeGenerator::visitCheckOverRecursedFai
saveLive(ool->lir());
callVM(CheckOverRecursedInfo, ool->lir());
restoreLive(ool->lir());
masm.jump(ool->rejoin());
}
-void
-CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
-{
- // See above: unlike visitCheckOverRecursed(), this code runs in
- // parallel mode and hence uses the jitStackLimit from the current
- // thread state. Also, we must check the interrupt flags because
- // on interrupt or abort, only the stack limit for the main thread
- // is reset, not the worker threads. See comment in vm/ForkJoin.h
- // for more details.
-
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg = ToRegister(lir->getTempReg());
-
- masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
- masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg);
-
- // Conditional forward (unlikely) branch to failure.
- CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
- addOutOfLineCode(ool, lir->mir());
-
- masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
- masm.checkInterruptFlagPar(tempReg, ool->entry());
- masm.bind(ool->rejoin());
-}
-
-void
-CodeGenerator::visitInterruptCheckPar(LInterruptCheckPar *lir)
-{
- // First check for cx->shared->interrupt_.
- OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
-
- Register tempReg = ToRegister(lir->getTempReg());
- masm.checkInterruptFlagPar(tempReg, ool->entry());
- masm.bind(ool->rejoin());
-}
-
IonScriptCounts *
CodeGenerator::maybeCreateScriptCounts()
{
// If scripts are being profiled, create a new IonScriptCounts for the
// profiling data, which will be attached to the associated JSScript or
// AsmJS module after code generation finishes.
if (!GetJitContext()->runtime->profilingScripts())
return nullptr;
@@ -3768,44 +3611,42 @@ CodeGenerator::emitObjectOrStringResultC
masm.bind(&miss);
masm.assumeUnreachable("MIR instruction returned object with unexpected type");
masm.bind(&ok);
}
// Check that we have a valid GC pointer.
- if (gen->info().executionMode() != ParallelExecution) {
- saveVolatile();
- masm.setupUnalignedABICall(2, temp);
- masm.loadJSContext(temp);
- masm.passABIArg(temp);
- masm.passABIArg(output);
-
- void *callee;
- switch (mir->type()) {
- case MIRType_Object:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr);
- break;
- case MIRType_ObjectOrNull:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectOrNullPtr);
- break;
- case MIRType_String:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr);
- break;
- case MIRType_Symbol:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidSymbolPtr);
- break;
- default:
- MOZ_CRASH();
- }
-
- masm.callWithABINoProfiling(callee);
- restoreVolatile();
- }
+ saveVolatile();
+ masm.setupUnalignedABICall(2, temp);
+ masm.loadJSContext(temp);
+ masm.passABIArg(temp);
+ masm.passABIArg(output);
+
+ void *callee;
+ switch (mir->type()) {
+ case MIRType_Object:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr);
+ break;
+ case MIRType_ObjectOrNull:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectOrNullPtr);
+ break;
+ case MIRType_String:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr);
+ break;
+ case MIRType_Symbol:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidSymbolPtr);
+ break;
+ default:
+ MOZ_CRASH();
+ }
+
+ masm.callWithABINoProfiling(callee);
+ restoreVolatile();
masm.bind(&done);
masm.pop(temp);
}
void
CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
{
@@ -3839,30 +3680,28 @@ CodeGenerator::emitValueResultChecks(LIn
masm.bind(&miss);
masm.assumeUnreachable("MIR instruction returned value with unexpected type");
masm.bind(&ok);
}
// Check that we have a valid GC pointer.
- if (gen->info().executionMode() != ParallelExecution) {
- saveVolatile();
-
- masm.pushValue(output);
- masm.movePtr(StackPointer, temp1);
-
- masm.setupUnalignedABICall(2, temp2);
- masm.loadJSContext(temp2);
- masm.passABIArg(temp2);
- masm.passABIArg(temp1);
- masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
- masm.popValue(output);
- restoreVolatile();
- }
+ saveVolatile();
+
+ masm.pushValue(output);
+ masm.movePtr(StackPointer, temp1);
+
+ masm.setupUnalignedABICall(2, temp2);
+ masm.loadJSContext(temp2);
+ masm.passABIArg(temp2);
+ masm.passABIArg(temp1);
+ masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
+ masm.popValue(output);
+ restoreVolatile();
masm.bind(&done);
masm.pop(temp2);
masm.pop(temp1);
}
void
CodeGenerator::emitDebugResultChecks(LInstruction *ins)
@@ -4008,18 +3847,16 @@ class OutOfLineNewArray : public OutOfLi
typedef ArrayObject *(*NewDenseArrayFn)(ExclusiveContext *, uint32_t, HandleTypeObject,
AllocatingBehaviour);
static const VMFunction NewDenseArrayInfo = FunctionInfo<NewDenseArrayFn>(NewDenseArray);
void
CodeGenerator::visitNewArrayCallVM(LNewArray *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
Register objReg = ToRegister(lir->output());
MOZ_ASSERT(!lir->isCall());
saveLive(lir);
JSObject *templateObject = lir->mir()->templateObject();
types::TypeObject *type =
templateObject->hasSingletonType() ? nullptr : templateObject->type();
@@ -4041,19 +3878,16 @@ typedef JSObject *(*NewDerivedTypedObjec
HandleObject owner,
int32_t offset);
static const VMFunction CreateDerivedTypedObjInfo =
FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj);
void
CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
{
- // Not yet made safe for par exec:
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
pushArg(ToRegister(lir->offset()));
pushArg(ToRegister(lir->owner()));
pushArg(ToRegister(lir->type()));
callVM(CreateDerivedTypedObjInfo, lir);
}
void
CodeGenerator::visitAtan2D(LAtan2D *lir)
@@ -4083,17 +3917,16 @@ CodeGenerator::visitHypot(LHypot *lir)
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitNewArray(LNewArray *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
ArrayObject *templateObject = lir->mir()->templateObject();
DebugOnly<uint32_t> count = lir->mir()->count();
MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
if (lir->mir()->shouldUseVM()) {
@@ -4199,18 +4032,16 @@ static const VMFunction NewInitObjectInf
typedef JSObject *(*NewInitObjectWithClassPrototypeFn)(JSContext *, HandlePlainObject);
static const VMFunction NewInitObjectWithClassPrototypeInfo =
FunctionInfo<NewInitObjectWithClassPrototypeFn>(NewInitObjectWithClassPrototype);
void
CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
Register objReg = ToRegister(lir->output());
MOZ_ASSERT(!lir->isCall());
saveLive(lir);
pushArg(ImmGCPtr(lir->mir()->templateObject()));
// If we're making a new object with a class prototype (that is, an object
@@ -4310,17 +4141,16 @@ ShouldInitFixedSlots(LInstruction *lir,
}
MOZ_CRASH("Shouldn't get here");
}
void
CodeGenerator::visitNewObject(LNewObject *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
PlainObject *templateObject = lir->mir()->templateObject();
if (lir->mir()->shouldUseVM()) {
visitNewObjectVMCall(lir);
return;
}
@@ -4437,55 +4267,16 @@ CodeGenerator::visitNewSingletonCallObje
// Objects can only be given singleton types in VM calls. We make the call
// out of line to not bloat inline code, even if (naively) this seems like
// extra work.
masm.jump(ool->entry());
masm.bind(ool->rejoin());
}
-void
-CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
-{
- Register resultReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- CallObject *templateObj = lir->mir()->templateObj();
-
- emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
-}
-
-typedef ArrayObject *(*ExtendArrayParFn)(ForkJoinContext*, ArrayObject*, uint32_t);
-static const VMFunction ExtendArrayParInfo =
- FunctionInfo<ExtendArrayParFn>(ExtendArrayPar);
-
-void
-CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
-{
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register lengthReg = ToRegister(lir->length());
- Register tempReg0 = ToRegister(lir->getTemp0());
- Register tempReg1 = ToRegister(lir->getTemp1());
- Register tempReg2 = ToRegister(lir->getTemp2());
- ArrayObject *templateObj = lir->mir()->templateObject();
-
- emitAllocateGCThingPar(lir, tempReg2, cxReg, tempReg0, tempReg1, templateObj);
-
- // Invoke a C helper to allocate the elements. The helper returns
- // nullptr on allocation error or the array object.
-
- saveLive(lir);
- pushArg(lengthReg);
- pushArg(tempReg2);
- callVM(ExtendArrayParInfo, lir);
- storeResultTo(ToRegister(lir->output()));
- restoreLive(lir);
-}
-
typedef JSObject *(*NewStringObjectFn)(JSContext *, HandleString);
static const VMFunction NewStringObjectInfo = FunctionInfo<NewStringObjectFn>(NewStringObject);
void
CodeGenerator::visitNewStringObject(LNewStringObject *lir)
{
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
@@ -4501,86 +4292,16 @@ CodeGenerator::visitNewStringObject(LNew
masm.loadStringLength(input, temp);
masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
masm.bind(ool->rejoin());
}
-void
-CodeGenerator::visitNewPar(LNewPar *lir)
-{
- Register objReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- NativeObject *templateObject = lir->mir()->templateObject();
- emitAllocateGCThingPar(lir, objReg, cxReg, tempReg1, tempReg2, templateObject);
-}
-
-class OutOfLineNewGCThingPar : public OutOfLineCodeBase<CodeGenerator>
-{
-public:
- LInstruction *lir;
- gc::AllocKind allocKind;
- Register objReg;
- Register cxReg;
-
- OutOfLineNewGCThingPar(LInstruction *lir, gc::AllocKind allocKind, Register objReg,
- Register cxReg)
- : lir(lir), allocKind(allocKind), objReg(objReg), cxReg(cxReg)
- {}
-
- void accept(CodeGenerator *codegen) {
- codegen->visitOutOfLineNewGCThingPar(this);
- }
-};
-
-typedef JSObject *(*NewGCThingParFn)(ForkJoinContext *, js::gc::AllocKind allocKind);
-static const VMFunction NewGCThingParInfo =
- FunctionInfo<NewGCThingParFn>(NewGCThingPar);
-
-void
-CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
- Register tempReg1, Register tempReg2, NativeObject *templateObj)
-{
- MOZ_ASSERT(lir->mirRaw());
- MOZ_ASSERT(lir->mirRaw()->isInstruction());
-
- gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
- OutOfLineNewGCThingPar *ool = new(alloc()) OutOfLineNewGCThingPar(lir, allocKind, objReg, cxReg);
- addOutOfLineCode(ool, lir->mirRaw()->toInstruction());
-
- masm.newGCThingPar(objReg, cxReg, tempReg1, tempReg2, templateObj, ool->entry());
- masm.bind(ool->rejoin());
- masm.initGCThing(objReg, tempReg1, templateObj);
-}
-
-void
-CodeGenerator::visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool)
-{
- // As a fallback for allocation in par. exec. mode, we invoke the
- // C helper NewGCThingPar(), which calls into the GC code. If it
- // returns nullptr, we bail. If returns non-nullptr, we rejoin the
- // original instruction.
- Register out = ool->objReg;
-
- saveVolatile(out);
- masm.setupUnalignedABICall(2, out);
- masm.passABIArg(ool->cxReg);
- masm.move32(Imm32(ool->allocKind), out);
- masm.passABIArg(out);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewGCThingPar));
- masm.storeCallResult(out);
- restoreVolatile(out);
-
- bailoutTestPtr(Assembler::Zero, out, out, ool->lir->snapshot());
-}
-
typedef bool(*InitElemFn)(JSContext *cx, HandleObject obj,
HandleValue id, HandleValue value);
static const VMFunction InitElemInfo =
FunctionInfo<InitElemFn>(InitElemOperation);
void
CodeGenerator::visitInitElem(LInitElem *lir)
{
@@ -5182,26 +4903,23 @@ CodeGenerator::visitModD(LModD *ins)
if (gen->compilingAsmJS())
masm.callWithABI(AsmJSImm_ModD, MoveOp::DOUBLE);
else
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
}
typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, MutableHandleValue);
-typedef bool (*BinaryParFn)(ForkJoinContext *, HandleValue, HandleValue, MutableHandleValue);
static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
-static const VMFunctionsModal UrshInfo = VMFunctionsModal(
- FunctionInfo<BinaryFn>(js::UrshValues),
- FunctionInfo<BinaryParFn>(UrshValuesPar));
+static const VMFunction UrshInfo = FunctionInfo<BinaryFn>(js::UrshValues);
void
CodeGenerator::visitBinaryV(LBinaryV *lir)
{
pushArg(ToValue(lir, LBinaryV::RhsInput));
pushArg(ToValue(lir, LBinaryV::LhsInput));
switch (lir->jsop()) {
@@ -5230,23 +4948,20 @@ CodeGenerator::visitBinaryV(LBinaryV *li
break;
default:
MOZ_CRASH("Unexpected binary op");
}
}
typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
-typedef bool (*StringCompareParFn)(ForkJoinContext *, HandleString, HandleString, bool *);
-static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
- FunctionInfo<StringCompareFn>(jit::StringsEqual<true>),
- FunctionInfo<StringCompareParFn>(jit::StringsEqualPar));
-static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
- FunctionInfo<StringCompareFn>(jit::StringsEqual<false>),
- FunctionInfo<StringCompareParFn>(jit::StringsUnequalPar));
+static const VMFunction StringsEqualInfo =
+ FunctionInfo<StringCompareFn>(jit::StringsEqual<true>);
+static const VMFunction StringsNotEqualInfo =
+ FunctionInfo<StringCompareFn>(jit::StringsEqual<false>);
void
CodeGenerator::emitCompareS(LInstruction *lir, JSOp op, Register left, Register right,
Register output)
{
MOZ_ASSERT(lir->isCompareS() || lir->isCompareStrictS());
OutOfLineCode *ool = nullptr;
@@ -5294,41 +5009,24 @@ CodeGenerator::visitCompareS(LCompareS *
Register left = ToRegister(lir->left());
Register right = ToRegister(lir->right());
Register output = ToRegister(lir->output());
emitCompareS(lir, op, left, right, output);
}
typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
-typedef bool (*CompareParFn)(ForkJoinContext *, MutableHandleValue, MutableHandleValue, bool *);
-static const VMFunctionsModal EqInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LooselyEqual<true>),
- FunctionInfo<CompareParFn>(jit::LooselyEqualPar));
-static const VMFunctionsModal NeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LooselyEqual<false>),
- FunctionInfo<CompareParFn>(jit::LooselyUnequalPar));
-static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::StrictlyEqual<true>),
- FunctionInfo<CompareParFn>(jit::StrictlyEqualPar));
-static const VMFunctionsModal StrictNeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::StrictlyEqual<false>),
- FunctionInfo<CompareParFn>(jit::StrictlyUnequalPar));
-static const VMFunctionsModal LtInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LessThan),
- FunctionInfo<CompareParFn>(jit::LessThanPar));
-static const VMFunctionsModal LeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LessThanOrEqual),
- FunctionInfo<CompareParFn>(jit::LessThanOrEqualPar));
-static const VMFunctionsModal GtInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::GreaterThan),
- FunctionInfo<CompareParFn>(jit::GreaterThanPar));
-static const VMFunctionsModal GeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::GreaterThanOrEqual),
- FunctionInfo<CompareParFn>(jit::GreaterThanOrEqualPar));
+static const VMFunction EqInfo = FunctionInfo<CompareFn>(jit::LooselyEqual<true>);
+static const VMFunction NeInfo = FunctionInfo<CompareFn>(jit::LooselyEqual<false>);
+static const VMFunction StrictEqInfo = FunctionInfo<CompareFn>(jit::StrictlyEqual<true>);
+static const VMFunction StrictNeInfo = FunctionInfo<CompareFn>(jit::StrictlyEqual<false>);
+static const VMFunction LtInfo = FunctionInfo<CompareFn>(jit::LessThan);
+static const VMFunction LeInfo = FunctionInfo<CompareFn>(jit::LessThanOrEqual);
+static const VMFunction GtInfo = FunctionInfo<CompareFn>(jit::GreaterThan);
+static const VMFunction GeInfo = FunctionInfo<CompareFn>(jit::GreaterThanOrEqual);
void
CodeGenerator::visitCompareVM(LCompareVM *lir)
{
pushArg(ToValue(lir, LBinaryV::RhsInput));
pushArg(ToValue(lir, LBinaryV::LhsInput));
switch (lir->mir()->jsop()) {
@@ -5579,29 +5277,25 @@ CodeGenerator::visitEmulatesUndefinedAnd
}
Register objreg = ToRegister(lir->input());
testObjectEmulatesUndefined(objreg, equal, unequal, ToRegister(lir->temp()), ool);
}
typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
-typedef JSString *(*ConcatStringsParFn)(ForkJoinContext *, HandleString, HandleString);
-static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
- FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>),
- FunctionInfo<ConcatStringsParFn>(ConcatStringsPar));
+static const VMFunction ConcatStringsInfo = FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>);
void
CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
{
OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
StoreRegisterTo(output));
- ExecutionMode mode = gen->info().executionMode();
- JitCode *stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier(mode);
+ JitCode *stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier();
masm.call(stringConcatStub);
masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
masm.bind(ool->rejoin());
}
void
CodeGenerator::visitConcat(LConcat *lir)
@@ -5618,36 +5312,16 @@ CodeGenerator::visitConcat(LConcat *lir)
MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
MOZ_ASSERT(ToRegister(lir->temp5()) == CallTempReg4);
MOZ_ASSERT(output == CallTempReg5);
emitConcat(lir, lhs, rhs, output);
}
-void
-CodeGenerator::visitConcatPar(LConcatPar *lir)
-{
- DebugOnly<Register> cx = ToRegister(lir->forkJoinContext());
- Register lhs = ToRegister(lir->lhs());
- Register rhs = ToRegister(lir->rhs());
- Register output = ToRegister(lir->output());
-
- MOZ_ASSERT(lhs == CallTempReg0);
- MOZ_ASSERT(rhs == CallTempReg1);
- MOZ_ASSERT((Register)cx == CallTempReg4);
- MOZ_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
- MOZ_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
- MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
- MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
- MOZ_ASSERT(output == CallTempReg5);
-
- emitConcat(lir, lhs, rhs, output);
-}
-
static void
CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len,
Register byteOpScratch, size_t fromWidth, size_t toWidth)
{
// Copy |len| char16_t code units from |from| to |to|. Assumes len > 0
// (checked below in debug builds), and when done |to| must point to the
// next available char.
@@ -5698,58 +5372,39 @@ CopyStringCharsMaybeInflate(MacroAssembl
masm.loadStringChars(input, input);
CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char), sizeof(char16_t));
}
masm.bind(&done);
}
static void
ConcatFatInlineString(MacroAssembler &masm, Register lhs, Register rhs, Register output,
- Register temp1, Register temp2, Register temp3, Register forkJoinContext,
- ExecutionMode mode, Label *failure, Label *failurePopTemps, bool isTwoByte)
+ Register temp1, Register temp2, Register temp3,
+ Label *failure, Label *failurePopTemps, bool isTwoByte)
{
// State: result length in temp2.
// Ensure both strings are linear.
masm.branchIfRope(lhs, failure);
masm.branchIfRope(rhs, failure);
// Allocate a JSFatInlineString.
- switch (mode) {
- case SequentialExecution:
- masm.newGCFatInlineString(output, temp1, failure);
- break;
- case ParallelExecution:
- masm.push(temp1);
- masm.push(temp2);
- masm.newGCFatInlineStringPar(output, forkJoinContext, temp1, temp2, failurePopTemps);
- masm.pop(temp2);
- masm.pop(temp1);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.newGCFatInlineString(output, temp1, failure);
// Store length and flags.
uint32_t flags = JSString::INIT_FAT_INLINE_FLAGS;
if (!isTwoByte)
flags |= JSString::LATIN1_CHARS_BIT;
masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
// Load chars pointer in temp2.
masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
{
- // We use temp3 in this block, which in parallel execution also holds
- // a live ForkJoinContext pointer. If we are compiling for parallel
- // execution, be sure to save and restore the ForkJoinContext.
- if (mode == ParallelExecution)
- masm.push(temp3);
-
// Copy lhs chars. Note that this advances temp2 to point to the next
// char. This also clobbers the lhs register.
if (isTwoByte) {
CopyStringCharsMaybeInflate(masm, lhs, temp2, temp1, temp3);
} else {
masm.loadStringLength(lhs, temp3);
masm.loadStringChars(lhs, lhs);
CopyStringChars(masm, temp2, lhs, temp3, temp1, sizeof(char), sizeof(char));
@@ -5764,19 +5419,16 @@ ConcatFatInlineString(MacroAssembler &ma
CopyStringChars(masm, temp2, rhs, temp3, temp1, sizeof(char), sizeof(char));
}
// Null-terminate.
if (isTwoByte)
masm.store16(Imm32(0), Address(temp2, 0));
else
masm.store8(Imm32(0), Address(temp2, 0));
-
- if (mode == ParallelExecution)
- masm.pop(temp3);
}
masm.ret();
}
typedef JSString *(*SubstringKernelFn)(JSContext *cx, HandleString str, int32_t begin, int32_t len);
static const VMFunction SubstringKernelInfo =
FunctionInfo<SubstringKernelFn>(SubstringKernel);
@@ -5891,32 +5543,27 @@ CodeGenerator::visitSubstr(LSubstr *lir)
masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
masm.jump(done);
}
masm.bind(done);
}
JitCode *
-JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
+JitCompartment::generateStringConcatStub(JSContext *cx)
{
MacroAssembler masm(cx);
Register lhs = CallTempReg0;
Register rhs = CallTempReg1;
Register temp1 = CallTempReg2;
Register temp2 = CallTempReg3;
Register temp3 = CallTempReg4;
Register output = CallTempReg5;
- // In parallel execution, we pass in the ForkJoinContext in CallTempReg4, as
- // by the time we need to use the temp3 we no longer have need of the
- // cx.
- Register forkJoinContext = CallTempReg4;
-
Label failure, failurePopTemps;
#ifdef JS_USE_LINK_REGISTER
masm.pushReturnAddress();
#endif
// If lhs is empty, return rhs.
Label leftEmpty;
masm.loadStringLength(lhs, temp1);
masm.branchTest32(Assembler::Zero, temp1, temp1, &leftEmpty);
@@ -5949,30 +5596,17 @@ JitCompartment::generateStringConcatStub
masm.bind(¬Inline);
// Keep AND'ed flags in temp1.
// Ensure result length <= JSString::MAX_LENGTH.
masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
// Allocate a new rope.
- switch (mode) {
- case SequentialExecution:
- masm.newGCString(output, temp3, &failure);
- break;
- case ParallelExecution:
- masm.push(temp1);
- masm.push(temp2);
- masm.newGCStringPar(output, forkJoinContext, temp1, temp2, &failurePopTemps);
- masm.pop(temp2);
- masm.pop(temp1);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.newGCString(output, temp3, &failure);
// Store rope length and flags. temp1 still holds the result of AND'ing the
// lhs and rhs flags, so we just have to clear the other flags to get our
// rope flags (Latin1 if both lhs and rhs are Latin1).
static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
@@ -5986,22 +5620,22 @@ JitCompartment::generateStringConcatStub
masm.mov(rhs, output);
masm.ret();
masm.bind(&rightEmpty);
masm.mov(lhs, output);
masm.ret();
masm.bind(&isFatInlineTwoByte);
- ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
- mode, &failure, &failurePopTemps, true);
+ ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
+ &failure, &failurePopTemps, true);
masm.bind(&isFatInlineLatin1);
- ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
- mode, &failure, &failurePopTemps, false);
+ ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
+ &failure, &failurePopTemps, false);
masm.bind(&failurePopTemps);
masm.pop(temp2);
masm.pop(temp1);
masm.bind(&failure);
masm.movePtr(ImmPtr(nullptr), output);
masm.ret();
@@ -6520,20 +6154,17 @@ CodeGenerator::visitStoreElementHoleV(LS
else
masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
masm.bind(ool->rejoin());
}
typedef bool (*SetDenseElementFn)(JSContext *, HandleNativeObject, int32_t, HandleValue,
bool strict);
-typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
-static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
- FunctionInfo<SetDenseElementFn>(SetDenseElement),
- FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
+static const VMFunction SetDenseElementInfo = FunctionInfo<SetDenseElementFn>(SetDenseElement);
void
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
{
Register object, elements;
LInstruction *ins = ool->ins();
const LAllocation *index;
MIRType valueType;
@@ -7151,21 +6782,18 @@ void
CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
{
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
callVM(RunOnceScriptPrologueInfo, lir);
}
typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
HandleObject);
-typedef JSObject *(*InitRestParameterParFn)(ForkJoinContext *, uint32_t, Value *,
- HandleObject, HandleArrayObject);
-static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
- FunctionInfo<InitRestParameterFn>(InitRestParameter),
- FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
+static const VMFunction InitRestParameterInfo =
+ FunctionInfo<InitRestParameterFn>(InitRestParameter);
void
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, bool saveAndRestore, Register resultreg)
{
// Compute actuals() + numFormals.
size_t actualsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
@@ -7217,34 +6845,16 @@ CodeGenerator::visitRest(LRest *lir)
masm.bind(&failAlloc);
masm.movePtr(ImmPtr(nullptr), temp2);
}
masm.bind(&joinAlloc);
emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, false, ToRegister(lir->output()));
}
-// LRestPar cannot derive from LCallInstructionHelper because emitAllocateGCThingPar may
-// itself contain a VM call. Thus there's some manual work here and in emitRest().
-
-void
-CodeGenerator::visitRestPar(LRestPar *lir)
-{
- Register numActuals = ToRegister(lir->numActuals());
- Register cx = ToRegister(lir->forkJoinContext());
- Register temp0 = ToRegister(lir->getTemp(0));
- Register temp1 = ToRegister(lir->getTemp(1));
- Register temp2 = ToRegister(lir->getTemp(2));
- unsigned numFormals = lir->mir()->numFormals();
- ArrayObject *templateObject = lir->mir()->templateObject();
-
- emitAllocateGCThingPar(lir, temp2, cx, temp0, temp1, templateObject);
- emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, true, ToRegister(lir->output()));
-}
-
bool
CodeGenerator::generateAsmJS(AsmJSFunctionLabels *labels)
{
JitSpew(JitSpew_Codegen, "# Emitting asm.js code");
// AsmJS doesn't do SPS instrumentation.
sps_.disable();
@@ -7334,17 +6944,17 @@ CodeGenerator::generate()
setSkipArgCheckEntryOffset(masm.size());
masm.setFramePushed(0);
if (!generatePrologue())
return false;
masm.bind(&skipPrologue);
#ifdef JS_TRACE_LOGGING
- if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
+ if (!gen->compilingAsmJS()) {
emitTracelogScriptStart();
emitTracelogStartEvent(TraceLogger_IonMonkey);
}
#endif
#ifdef DEBUG
// Assert that the argument types are correct.
generateArgumentsChecks(/* bailout = */ false);
@@ -7418,29 +7028,24 @@ struct AutoDiscardIonCode
bool
CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
{
RootedScript script(cx, gen->info().script());
ExecutionMode executionMode = gen->info().executionMode();
OptimizationLevel optimizationLevel = gen->optimizationInfo().level();
- MOZ_ASSERT_IF(HasIonScript(script, executionMode), executionMode == SequentialExecution);
-
// We finished the new IonScript. Invalidate the current active IonScript,
// so we can replace it with this new (probably higher optimized) version.
if (HasIonScript(script, executionMode)) {
MOZ_ASSERT(GetIonScript(script, executionMode)->isRecompiling());
// Do a normal invalidate, except don't cancel offThread compilations,
// since that will cancel this compilation too.
- if (!Invalidate(cx, script, SequentialExecution,
- /* resetUses */ false, /* cancelOffThread*/ false))
- {
+ if (!Invalidate(cx, script, /* resetUses */ false, /* cancelOffThread*/ false))
return false;
- }
}
if (scriptCounts_ && !script->hasScriptCounts() && !script->initScriptCounts(cx))
return false;
// Check to make sure we didn't have a mid-build invalidation. If so, we
// will trickle to jit::Compile() and return Method_Skipped.
uint32_t warmUpCount = script->getWarmUpCount();
@@ -7457,45 +7062,36 @@ CodeGenerator::link(JSContext *cx, types
uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
? frameDepth_
: FrameSizeClass::FromDepth(frameDepth_).frameSize();
// We encode safepoints after the OSI-point offsets have been determined.
encodeSafepoints();
- // List of possible scripts that this graph may call. Currently this is
- // only tracked when compiling for parallel execution.
- CallTargetVector callTargets(alloc());
- if (executionMode == ParallelExecution)
- AddPossibleCallees(cx, graph.mir(), callTargets);
-
AutoDiscardIonCode discardIonCode(cx, &recompileInfo);
IonScript *ionScript =
IonScript::New(cx, recompileInfo,
graph.totalSlotCount(), scriptFrameSize,
snapshots_.listSize(), snapshots_.RVATableSize(),
recovers_.size(), bailouts_.length(), graph.numConstants(),
safepointIndices_.length(), osiIndices_.length(),
cacheList_.length(), runtimeData_.length(),
- safepoints_.size(), callTargets.length(),
- patchableBackedges_.length(), optimizationLevel);
+ safepoints_.size(), patchableBackedges_.length(), optimizationLevel);
if (!ionScript)
return false;
discardIonCode.ionScript = ionScript;
// Also, note that creating the code here during an incremental GC will
// trace the code and mark all GC things it refers to. This captures any
// read barriers which were skipped while compiling the script off thread.
Linker linker(masm);
AutoFlushICache afc("IonLink");
- JitCode *code = (executionMode == SequentialExecution)
- ? linker.newCodeForIonScript(cx)
- : linker.newCode<CanGC>(cx, ION_CODE);
+ JitCode *code = linker.newCodeForIonScript(cx);
if (!code)
return false;
// Encode native to bytecode map if profiling is enabled.
if (isNativeToBytecodeMapEnabled()) {
// Generate native-to-bytecode main table.
if (!generateCompactNativeToBytecodeMap(cx, code))
return false;
@@ -7545,22 +7141,16 @@ CodeGenerator::link(JSContext *cx, types
ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
// If SPS is enabled, mark IonScript as having been instrumented with SPS
if (sps_.enabled())
ionScript->setHasSPSInstrumentation();
SetIonScript(cx, script, executionMode, ionScript);
- // In parallel execution mode, when we first compile a script, we
- // don't know that its potential callees are compiled, so set a
- // flag warning that the callees may not be fully compiled.
- if (!callTargets.empty())
- ionScript->setHasUncompiledCallTarget();
-
invalidateEpilogueData_.fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
ImmPtr(ionScript),
ImmPtr((void*)-1));
JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
(void *) ionScript, (void *) code->raw());
@@ -7603,18 +7193,16 @@ CodeGenerator::link(JSContext *cx, types
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (snapshots_.listSize())
ionScript->copySnapshots(&snapshots_);
MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
if (recovers_.size())
ionScript->copyRecovers(&recovers_);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
- if (callTargets.length() > 0)
- ionScript->copyCallTargetEntries(callTargets.begin());
if (patchableBackedges_.length() > 0)
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
#ifdef JS_TRACE_LOGGING
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
patchableTraceLoggers_[i].fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
@@ -7631,31 +7219,21 @@ CodeGenerator::link(JSContext *cx, types
patchableTLScripts_[i].fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
ImmPtr((void *) uintptr_t(textId)),
ImmPtr((void *)0));
}
}
#endif
- switch (executionMode) {
- case SequentialExecution:
- // The correct state for prebarriers is unknown until the end of compilation,
- // since a GC can occur during code generation. All barriers are emitted
- // off-by-default, and are toggled on here if necessary.
- if (cx->zone()->needsIncrementalBarrier())
- ionScript->toggleBarriers(true);
- break;
- case ParallelExecution:
- // We don't run incremental GC during parallel execution; no need to
- // turn on barriers.
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ // The correct state for prebarriers is unknown until the end of compilation,
+ // since a GC can occur during code generation. All barriers are emitted
+ // off-by-default, and are toggled on here if necessary.
+ if (cx->zone()->needsIncrementalBarrier())
+ ionScript->toggleBarriers(true);
// Attach any generated script counts to the script.
if (IonScriptCounts *counts = extractScriptCounts())
script->addIonCounts(counts);
// Make sure that AutoDiscardIonCode does not free the relevant info.
discardIonCode.keepIonCode();
@@ -7748,20 +7326,17 @@ CodeGenerator::visitCallGetElement(LCall
} else {
MOZ_ASSERT(op == JSOP_CALLELEM);
callVM(CallElementInfo, lir);
}
}
typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
bool strict);
-typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
-static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
- FunctionInfo<SetObjectElementFn>(SetObjectElement),
- FunctionInfo<SetElementParFn>(SetElementPar));
+static const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(SetObjectElement);
void
CodeGenerator::visitCallSetElement(LCallSetElement *lir)
{
pushArg(Imm32(lir->mir()->strict()));
pushArg(ToValue(lir, LCallSetElement::Value));
pushArg(ToValue(lir, LCallSetElement::Index));
pushArg(ToRegister(lir->getOperand(0)));
@@ -7899,82 +7474,42 @@ CodeGenerator::visitNameIC(OutOfLineUpda
masm.jump(ool->rejoin());
}
void
CodeGenerator::addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
PropertyName *name, TypedOrValueRegister output,
bool monitoredResult, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- GetPropertyParIC cache(objReg, name, output);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
PropertyName *name, ConstantOrRegister value, bool strict,
bool needsTypeBarrier, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
Register temp, FloatRegister tempDouble,
FloatRegister tempFloat32, ValueOperand index,
ConstantOrRegister value, bool strict, bool guardHoles,
jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- SetElementIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
- guardHoles);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- SetElementParIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
- guardHoles);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ SetElementIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
+ guardHoles);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName *name = ins->mir()->name();
@@ -8020,57 +7555,25 @@ CodeGenerator::visitGetPropertyIC(OutOfL
pushArg(Imm32(ool->getCacheIndex()));
callVM(GetPropertyIC::UpdateInfo, lir);
StoreValueTo(ic->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
masm.jump(ool->rejoin());
}
-typedef bool (*GetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, MutableHandleValue);
-const VMFunction GetPropertyParIC::UpdateInfo =
- FunctionInfo<GetPropertyParICFn>(GetPropertyParIC::update);
-
-void
-CodeGenerator::visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(GetPropertyParIC::UpdateInfo, lir);
- StoreValueTo(ic->output()).generate(this);
- restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
-
- masm.jump(ool->rejoin());
-}
-
void
CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
TypedOrValueRegister output, bool monitoredResult,
bool allowDoubleResult, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- RegisterSet liveRegs = ins->safepoint()->liveRegs();
- GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- GetElementParIC cache(obj, index, output, monitoredResult, allowDoubleResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("No such execution mode");
- }
+ RegisterSet liveRegs = ins->safepoint()->liveRegs();
+ GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
{
Register obj = ToRegister(ins->object());
ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
@@ -8164,57 +7667,16 @@ CodeGenerator::visitSetElementIC(OutOfLi
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
callVM(SetElementIC::UpdateInfo, lir);
restoreLive(lir);
masm.jump(ool->rejoin());
}
-typedef bool (*SetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue, HandleValue);
-const VMFunction SetElementParIC::UpdateInfo =
- FunctionInfo<SetElementParICFn>(SetElementParIC::update);
-
-void
-CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->value());
- pushArg(ic->index());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(SetElementParIC::UpdateInfo, lir);
- restoreLive(lir);
-
- masm.jump(ool->rejoin());
-}
-
-typedef bool (*GetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue,
- MutableHandleValue);
-const VMFunction GetElementParIC::UpdateInfo =
- FunctionInfo<GetElementParICFn>(GetElementParIC::update);
-
-void
-CodeGenerator::visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->index());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(GetElementParIC::UpdateInfo, lir);
- StoreValueTo(ic->output()).generate(this);
- restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
-
- masm.jump(ool->rejoin());
-}
-
void
CodeGenerator::visitBindNameCache(LBindNameCache *ins)
{
Register scopeChain = ToRegister(ins->scopeChain());
Register output = ToRegister(ins->output());
BindNameIC cache(scopeChain, ins->mir()->name(), output);
cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
@@ -8237,21 +7699,17 @@ CodeGenerator::visitBindNameIC(OutOfLine
StoreRegisterTo(ic->outputReg()).generate(this);
restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
masm.jump(ool->rejoin());
}
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
HandlePropertyName, const HandleValue, bool, jsbytecode *);
-typedef bool (*SetPropertyParFn)(ForkJoinContext *, HandleObject,
- HandlePropertyName, const HandleValue, bool, jsbytecode *);
-static const VMFunctionsModal SetPropertyInfo = VMFunctionsModal(
- FunctionInfo<SetPropertyFn>(SetProperty),
- FunctionInfo<SetPropertyParFn>(SetPropertyPar));
+static const VMFunction SetPropertyInfo = FunctionInfo<SetPropertyFn>(SetProperty);
void
CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
{
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
const Register objReg = ToRegister(ins->getOperand(0));
@@ -8344,75 +7802,42 @@ CodeGenerator::visitSetPropertyIC(OutOfL
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
callVM(SetPropertyIC::UpdateInfo, lir);
restoreLive(lir);
masm.jump(ool->rejoin());
}
-typedef bool (*SetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue);
-const VMFunction SetPropertyParIC::UpdateInfo =
- FunctionInfo<SetPropertyParICFn>(SetPropertyParIC::update);
-
-void
-CodeGenerator::visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->value());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(SetPropertyParIC::UpdateInfo, lir);
- restoreLive(lir);
-
- masm.jump(ool->rejoin());
-}
-
typedef bool (*ThrowFn)(JSContext *, HandleValue);
static const VMFunction ThrowInfoCodeGen = FunctionInfo<ThrowFn>(js::Throw);
void
CodeGenerator::visitThrow(LThrow *lir)
{
pushArg(ToValue(lir, LThrow::Value));
callVM(ThrowInfoCodeGen, lir);
}
typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-typedef bool (*BitNotParFn)(ForkJoinContext *, HandleValue, int32_t *);
-static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
- FunctionInfo<BitNotFn>(BitNot),
- FunctionInfo<BitNotParFn>(BitNotPar));
+static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot);
void
CodeGenerator::visitBitNotV(LBitNotV *lir)
{
pushArg(ToValue(lir, LBitNotV::Input));
callVM(BitNotInfo, lir);
}
typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-typedef bool (*BitopParFn)(ForkJoinContext *, HandleValue, HandleValue, int32_t *);
-static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitAnd),
- FunctionInfo<BitopParFn>(BitAndPar));
-static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitOr),
- FunctionInfo<BitopParFn>(BitOrPar));
-static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitXor),
- FunctionInfo<BitopParFn>(BitXorPar));
-static const VMFunctionsModal BitLhsInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitLsh),
- FunctionInfo<BitopParFn>(BitLshPar));
-static const VMFunctionsModal BitRhsInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitRsh),
- FunctionInfo<BitopParFn>(BitRshPar));
+static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd);
+static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr);
+static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor);
+static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh);
+static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh);
void
CodeGenerator::visitBitOpV(LBitOpV *lir)
{
pushArg(ToValue(lir, LBitOpV::RhsInput));
pushArg(ToValue(lir, LBitOpV::LhsInput));
switch (lir->jsop()) {
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -28,24 +28,21 @@
namespace js {
namespace jit {
class OutOfLineTestObject;
class OutOfLineNewArray;
class OutOfLineNewObject;
class CheckOverRecursedFailure;
-class CheckOverRecursedFailurePar;
-class OutOfLineInterruptCheckPar;
class OutOfLineInterruptCheckImplicit;
class OutOfLineUnboxFloatingPoint;
class OutOfLineStoreElementHole;
class OutOfLineTypeOfV;
class OutOfLineLoadTypedArray;
-class OutOfLineNewGCThingPar;
class OutOfLineUpdateCache;
class OutOfLineCallPostWriteBarrier;
class OutOfLineIsCallable;
class OutOfLineRegExpExec;
class OutOfLineRegExpTest;
class CodeGenerator : public CodeGeneratorSpecific
{
@@ -108,17 +105,16 @@ class CodeGenerator : public CodeGenerat
void visitOutOfLineRegExpExec(OutOfLineRegExpExec *ool);
void visitRegExpTest(LRegExpTest *lir);
void visitOutOfLineRegExpTest(OutOfLineRegExpTest *ool);
void visitRegExpReplace(LRegExpReplace *lir);
void visitStringReplace(LStringReplace *lir);
void visitLambda(LLambda *lir);
void visitLambdaArrow(LLambdaArrow *lir);
void visitLambdaForSingleton(LLambdaForSingleton *lir);
- void visitLambdaPar(LLambdaPar *lir);
void visitPointer(LPointer *lir);
void visitSlots(LSlots *lir);
void visitLoadSlotT(LLoadSlotT *lir);
void visitLoadSlotV(LLoadSlotV *lir);
void visitStoreSlotT(LStoreSlotT *lir);
void visitStoreSlotV(LStoreSlotV *lir);
void visitElements(LElements *lir);
void visitConvertElementsToDoubles(LConvertElementsToDoubles *lir);
@@ -157,20 +153,17 @@ class CodeGenerator : public CodeGenerat
void visitNewArrayDynamicLength(LNewArrayDynamicLength *lir);
void visitNewObjectVMCall(LNewObject *lir);
void visitNewObject(LNewObject *lir);
void visitOutOfLineNewObject(OutOfLineNewObject *ool);
void visitNewTypedObject(LNewTypedObject *lir);
void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
void visitNewCallObject(LNewCallObject *lir);
void visitNewSingletonCallObject(LNewSingletonCallObject *lir);
- void visitNewCallObjectPar(LNewCallObjectPar *lir);
void visitNewStringObject(LNewStringObject *lir);
- void visitNewPar(LNewPar *lir);
- void visitNewDenseArrayPar(LNewDenseArrayPar *lir);
void visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
void visitInitElem(LInitElem *lir);
void visitInitElemGetterSetter(LInitElemGetterSetter *lir);
void visitMutateProto(LMutateProto *lir);
void visitInitProp(LInitProp *lir);
void visitInitPropGetterSetter(LInitPropGetterSetter *lir);
void visitCreateThis(LCreateThis *lir);
void visitCreateThisWithProto(LCreateThisWithProto *lir);
@@ -226,23 +219,20 @@ class CodeGenerator : public CodeGenerat
void visitCompareStrictS(LCompareStrictS *lir);
void visitCompareVM(LCompareVM *lir);
void visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir);
void visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir);
void visitEmulatesUndefined(LEmulatesUndefined *lir);
void visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir);
void emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output);
void visitConcat(LConcat *lir);
- void visitConcatPar(LConcatPar *lir);
void visitCharCodeAt(LCharCodeAt *lir);
void visitFromCharCode(LFromCharCode *lir);
void visitStringSplit(LStringSplit *lir);
void visitFunctionEnvironment(LFunctionEnvironment *lir);
- void visitForkJoinContext(LForkJoinContext *lir);
- void visitGuardThreadExclusive(LGuardThreadExclusive *lir);
void visitCallGetProperty(LCallGetProperty *lir);
void visitCallGetElement(LCallGetElement *lir);
void visitCallSetElement(LCallSetElement *lir);
void visitCallInitElementArray(LCallInitElementArray *lir);
void visitThrow(LThrow *lir);
void visitTypeOfV(LTypeOfV *lir);
void visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool);
void visitToIdV(LToIdV *lir);
@@ -286,17 +276,16 @@ class CodeGenerator : public CodeGenerat
void visitSetFrameArgumentT(LSetFrameArgumentT *lir);
void visitSetFrameArgumentC(LSetFrameArgumentC *lir);
void visitSetFrameArgumentV(LSetFrameArgumentV *lir);
void visitRunOncePrologue(LRunOncePrologue *lir);
void emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, bool saveAndRestore, Register resultreg);
void visitRest(LRest *lir);
- void visitRestPar(LRestPar *lir);
void visitCallSetProperty(LCallSetProperty *ins);
void visitCallDeleteProperty(LCallDeleteProperty *lir);
void visitCallDeleteElement(LCallDeleteElement *lir);
void visitBitNotV(LBitNotV *lir);
void visitBitOpV(LBitOpV *lir);
void emitInstanceOf(LInstruction *ins, JSObject *prototypeObject);
void visitIn(LIn *ins);
void visitInArray(LInArray *ins);
@@ -320,29 +309,23 @@ class CodeGenerator : public CodeGenerat
void visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
void visitLexicalCheck(LLexicalCheck *ins);
void visitThrowUninitializedLexical(LThrowUninitializedLexical *ins);
void visitDebugger(LDebugger *ins);
void visitCheckOverRecursed(LCheckOverRecursed *lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
- void visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
-
- void visitInterruptCheckPar(LInterruptCheckPar *lir);
- void visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
-
void visitInterruptCheckImplicit(LInterruptCheckImplicit *ins);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ins);
void visitUnboxFloatingPoint(LUnboxFloatingPoint *lir);
void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint *ool);
void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool);
- void visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool);
void loadJSScriptForBlock(MBasicBlock *block, Register reg);
void loadOutermostJSScript(Register reg);
// Inline caches visitors.
void visitOutOfLineCache(OutOfLineUpdateCache *ool);
void visitGetPropertyCacheV(LGetPropertyCacheV *ins);
void visitGetPropertyCacheT(LGetPropertyCacheT *ins);
@@ -353,23 +336,19 @@ class CodeGenerator : public CodeGenerat
void visitBindNameCache(LBindNameCache *ins);
void visitCallSetProperty(LInstruction *ins);
void visitSetPropertyCacheV(LSetPropertyCacheV *ins);
void visitSetPropertyCacheT(LSetPropertyCacheT *ins);
void visitGetNameCache(LGetNameCache *ins);
void visitCallsiteCloneCache(LCallsiteCloneCache *ins);
void visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic);
- void visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic);
void visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic);
- void visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic);
void visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
- void visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic);
void visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
- void visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic);
void visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
void visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
void visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
void visitAssertRangeI(LAssertRangeI *ins);
void visitAssertRangeD(LAssertRangeD *ins);
void visitAssertRangeF(LAssertRangeF *ins);
void visitAssertRangeV(LAssertRangeV *ins);
@@ -396,22 +375,16 @@ class CodeGenerator : public CodeGenerat
bool needsTypeBarrier, jsbytecode *profilerLeavePc);
void addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
FloatRegister tempDouble, FloatRegister tempFloat32,
ValueOperand index, ConstantOrRegister value,
bool strict, bool guardHoles, jsbytecode *profilerLeavePc);
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
- void emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
- Register tempReg1, Register tempReg2,
- NativeObject *templateObj);
-
- void emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg);
-
void emitLambdaInit(Register resultReg, Register scopeChainReg,
const LambdaFunctionInfo &info);
void emitFilterArgumentsOrEval(LInstruction *lir, Register string, Register temp1,
Register temp2);
IonScriptCounts *maybeCreateScriptCounts();
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -426,20 +426,16 @@ class CompileInfo
ExecutionMode executionMode() const {
return executionMode_;
}
bool executionModeIsAnalysis() const {
return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis;
}
- bool isParallelExecution() const {
- return executionMode_ == ParallelExecution;
- }
-
// Returns true if a slot can be observed out-side the current frame while
// the frame is active on the stack. This implies that these definitions
// would have to be executed and that they cannot be removed even if they
// are unused.
bool isObservableSlot(uint32_t slot) const {
if (isObservableFrameSlot(slot))
return true;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -28,24 +28,22 @@
#include "jit/JitCommon.h"
#include "jit/JitCompartment.h"
#include "jit/JitSpewer.h"
#include "jit/LICM.h"
#include "jit/LinearScan.h"
#include "jit/LIR.h"
#include "jit/LoopUnroller.h"
#include "jit/Lowering.h"
-#include "jit/ParallelSafetyAnalysis.h"
#include "jit/PerfSpewer.h"
#include "jit/RangeAnalysis.h"
#include "jit/ScalarReplacement.h"
#include "jit/Sink.h"
#include "jit/StupidAllocator.h"
#include "jit/ValueNumbering.h"
-#include "vm/ForkJoin.h"
#include "vm/HelperThreads.h"
#include "vm/TraceLogging.h"
#include "jscompartmentinlines.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
@@ -149,26 +147,23 @@ jit::InitializeIon()
CheckPerf();
return true;
}
JitRuntime::JitRuntime()
: execAlloc_(nullptr),
ionAlloc_(nullptr),
exceptionTail_(nullptr),
- exceptionTailParallel_(nullptr),
bailoutTail_(nullptr),
enterJIT_(nullptr),
bailoutHandler_(nullptr),
argumentsRectifier_(nullptr),
argumentsRectifierReturnAddr_(nullptr),
- parallelArgumentsRectifier_(nullptr),
invalidator_(nullptr),
debugTrapHandler_(nullptr),
- forkJoinGetSliceStub_(nullptr),
baselineDebugModeOSRHandler_(nullptr),
functionWrappers_(nullptr),
osrTempData_(nullptr),
mutatingBackedgeList_(false),
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
jitcodeGlobalTable_(nullptr)
{
}
@@ -205,26 +200,21 @@ JitRuntime::initialize(JSContext *cx)
functionWrappers_ = cx->new_<VMWrapperMap>(cx);
if (!functionWrappers_ || !functionWrappers_->init())
return false;
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
void *handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException);
- void *handlerParallel = JS_FUNC_TO_DATA_PTR(void *, jit::HandleParallelFailure);
exceptionTail_ = generateExceptionTailStub(cx, handler);
if (!exceptionTail_)
return false;
- exceptionTailParallel_ = generateExceptionTailStub(cx, handlerParallel);
- if (!exceptionTailParallel_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
bailoutTail_ = generateBailoutTailStub(cx);
if (!bailoutTail_)
return false;
if (cx->runtime()->jitSupportsFloatingPoint) {
JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
@@ -238,41 +228,31 @@ JitRuntime::initialize(JSContext *cx)
break;
bailoutTables_.infallibleAppend((JitCode *)nullptr);
bailoutTables_[id] = generateBailoutTable(cx, id);
if (!bailoutTables_[id])
return false;
}
JitSpew(JitSpew_Codegen, "# Emitting bailout handler");
- bailoutHandler_ = generateBailoutHandler(cx, SequentialExecution);
+ bailoutHandler_ = generateBailoutHandler(cx);
if (!bailoutHandler_)
return false;
- JitSpew(JitSpew_Codegen, "# Emitting parallel bailout handler");
- parallelBailoutHandler_ = generateBailoutHandler(cx, ParallelExecution);
- if (!parallelBailoutHandler_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting invalidator");
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return false;
}
JitSpew(JitSpew_Codegen, "# Emitting sequential arguments rectifier");
- argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_);
+ argumentsRectifier_ = generateArgumentsRectifier(cx, &argumentsRectifierReturnAddr_);
if (!argumentsRectifier_)
return false;
- JitSpew(JitSpew_Codegen, "# Emitting parallel arguments rectifier");
- parallelArgumentsRectifier_ = generateArgumentsRectifier(cx, ParallelExecution, nullptr);
- if (!parallelArgumentsRectifier_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting EnterJIT sequence");
enterJIT_ = generateEnterJIT(cx, EnterJitOptimized);
if (!enterJIT_)
return false;
JitSpew(JitSpew_Codegen, "# Emitting EnterBaselineJIT sequence");
enterBaselineJIT_ = generateEnterJIT(cx, EnterJitBaseline);
if (!enterBaselineJIT_)
@@ -339,28 +319,16 @@ JitRuntime::debugTrapHandler(JSContext *
// be allocated in the atoms compartment.
AutoLockForExclusiveAccess lock(cx);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
debugTrapHandler_ = generateDebugTrapHandler(cx);
}
return debugTrapHandler_;
}
-bool
-JitRuntime::ensureForkJoinGetSliceStubExists(JSContext *cx)
-{
- if (!forkJoinGetSliceStub_) {
- JitSpew(JitSpew_Codegen, "# Emitting ForkJoinGetSlice stub");
- AutoLockForExclusiveAccess lock(cx);
- AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
- forkJoinGetSliceStub_ = generateForkJoinGetSliceStub(cx);
- }
- return !!forkJoinGetSliceStub_;
-}
-
uint8_t *
JitRuntime::allocateOsrTempData(size_t size)
{
osrTempData_ = (uint8_t *)js_realloc(osrTempData_, size);
return osrTempData_;
}
void
@@ -400,17 +368,16 @@ JitRuntime::patchIonBackedges(JSRuntime
}
JitCompartment::JitCompartment()
: stubCodes_(nullptr),
baselineCallReturnAddr_(nullptr),
baselineGetPropReturnAddr_(nullptr),
baselineSetPropReturnAddr_(nullptr),
stringConcatStub_(nullptr),
- parallelStringConcatStub_(nullptr),
regExpExecStub_(nullptr),
regExpTestStub_(nullptr),
activeParallelEntryScripts_(nullptr)
{
}
JitCompartment::~JitCompartment()
{
@@ -427,27 +394,21 @@ JitCompartment::initialize(JSContext *cx
return true;
}
bool
JitCompartment::ensureIonStubsExist(JSContext *cx)
{
if (!stringConcatStub_) {
- stringConcatStub_ = generateStringConcatStub(cx, SequentialExecution);
+ stringConcatStub_ = generateStringConcatStub(cx);
if (!stringConcatStub_)
return false;
}
- if (!parallelStringConcatStub_) {
- parallelStringConcatStub_ = generateStringConcatStub(cx, ParallelExecution);
- if (!parallelStringConcatStub_)
- return false;
- }
-
return true;
}
bool
JitCompartment::notifyOfActiveParallelEntryScript(JSContext *cx, HandleScript script)
{
// Fast path. The isParallelEntryScript bit guarantees that the script is
// already in the set.
@@ -485,17 +446,17 @@ jit::FinishOffThreadBuilder(JSContext *c
// Clean the references to the pending IonBuilder, if we just finished it.
if (builder->script()->hasIonScript() && builder->script()->pendingIonBuilder() == builder)
builder->script()->setPendingIonBuilder(cx, nullptr);
if (builder->isInList())
builder->remove();
// Clear the recompiling flag of the old ionScript, since we continue to
// use the old ionScript if recompiling fails.
- if (executionMode == SequentialExecution && builder->script()->hasIonScript())
+ if (builder->script()->hasIonScript())
builder->script()->ionScript()->clearRecompiling();
// Clean up if compilation did not succeed.
if (CompilingOffThread(builder->script(), executionMode)) {
SetIonScript(cx, builder->script(), executionMode,
builder->abortReason() == AbortReason_Disable
? ION_DISABLED_SCRIPT
: nullptr);
@@ -645,19 +606,16 @@ JitCompartment::sweep(FreeOp *fop, JSCom
if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::GetProp_Fallback)))
baselineGetPropReturnAddr_ = nullptr;
if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::SetProp_Fallback)))
baselineSetPropReturnAddr_ = nullptr;
if (stringConcatStub_ && !IsJitCodeMarked(&stringConcatStub_))
stringConcatStub_ = nullptr;
- if (parallelStringConcatStub_ && !IsJitCodeMarked(¶llelStringConcatStub_))
- parallelStringConcatStub_ = nullptr;
-
if (regExpExecStub_ && !IsJitCodeMarked(®ExpExecStub_))
regExpExecStub_ = nullptr;
if (regExpTestStub_ && !IsJitCodeMarked(®ExpTestStub_))
regExpTestStub_ = nullptr;
if (activeParallelEntryScripts_) {
for (ScriptSet::Enum e(*activeParallelEntryScripts_); !e.empty(); e.popFront()) {
@@ -840,18 +798,16 @@ IonScript::IonScript()
bailoutEntries_(0),
osiIndexOffset_(0),
osiIndexEntries_(0),
snapshots_(0),
snapshotsListSize_(0),
snapshotsRVATableSize_(0),
constantTable_(0),
constantEntries_(0),
- callTargetList_(0),
- callTargetEntries_(0),
backedgeList_(0),
backedgeEntries_(0),
invalidationCount_(0),
parallelAge_(0),
recompileInfo_(),
osrPcMismatchCounter_(0),
pendingBuilder_(nullptr)
{
@@ -860,18 +816,17 @@ IonScript::IonScript()
IonScript *
IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameSlots, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
- size_t callTargetEntries, size_t backedgeEntries,
- OptimizationLevel optimizationLevel)
+ size_t backedgeEntries, OptimizationLevel optimizationLevel)
{
static const int DataAlignment = sizeof(void *);
if (snapshotsListSize >= MAX_BUFFER_SIZE ||
(bailoutEntries >= MAX_BUFFER_SIZE / sizeof(uint32_t)))
{
js_ReportOutOfMemory(cx);
return nullptr;
@@ -884,28 +839,26 @@ IonScript::New(JSContext *cx, types::Rec
size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment);
size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
- size_t paddedCallTargetSize = AlignBytes(callTargetEntries * sizeof(JSScript *), DataAlignment);
size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
size_t bytes = paddedSnapshotsSize +
paddedRecoversSize +
paddedBailoutSize +
paddedConstantsSize +
paddedSafepointIndicesSize+
paddedOsiIndicesSize +
paddedCacheEntriesSize +
paddedRuntimeSize +
paddedSafepointSize +
- paddedCallTargetSize +
paddedBackedgeSize;
IonScript *script = cx->zone()->pod_malloc_with_extra<IonScript, uint8_t>(bytes);
if (!script)
return nullptr;
new (script) IonScript();
uint32_t offsetCursor = sizeof(IonScript);
@@ -941,20 +894,16 @@ IonScript::New(JSContext *cx, types::Rec
script->recovers_ = offsetCursor;
script->recoversSize_ = recoversSize;
offsetCursor += paddedRecoversSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
- script->callTargetList_ = offsetCursor;
- script->callTargetEntries_ = callTargetEntries;
- offsetCursor += paddedCallTargetSize;
-
script->backedgeList_ = offsetCursor;
script->backedgeEntries_ = backedgeEntries;
offsetCursor += paddedBackedgeSize;
script->frameSlots_ = frameSlots;
script->frameSize_ = frameSize;
script->recompileInfo_ = recompileInfo;
@@ -969,21 +918,16 @@ IonScript::trace(JSTracer *trc)
if (method_)
MarkJitCode(trc, &method_, "method");
if (deoptTable_)
MarkJitCode(trc, &deoptTable_, "deoptimizationTable");
for (size_t i = 0; i < numConstants(); i++)
gc::MarkValue(trc, &getConstant(i), "constant");
-
- // No write barrier is needed for the call target list, as it's attached
- // at compilation time and is read only.
- for (size_t i = 0; i < callTargetEntries(); i++)
- gc::MarkScriptUnbarriered(trc, &callTargetList()[i], "callTarget");
}
/* static */ void
IonScript::writeBarrierPre(Zone *zone, IonScript *ionScript)
{
if (zone->needsIncrementalBarrier())
ionScript->trace(zone->barrierTracer());
}
@@ -1024,23 +968,16 @@ IonScript::copyBailoutTable(const Snapsh
void
IonScript::copyConstants(const Value *vp)
{
for (size_t i = 0; i < constantEntries_; i++)
constants()[i].init(vp[i]);
}
void
-IonScript::copyCallTargetEntries(JSScript **callTargets)
-{
- for (size_t i = 0; i < callTargetEntries_; i++)
- callTargetList()[i] = callTargets[i];
-}
-
-void
IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code,
PatchableBackedgeInfo *backedges,
MacroAssembler &masm)
{
JitRuntime *jrt = cx->runtime()->jitRuntime();
JitRuntime::AutoMutateBackedges amb(jrt);
for (size_t i = 0; i < backedgeEntries_; i++) {
@@ -1375,31 +1312,16 @@ OptimizeMIR(MIRGenerator *mir)
return false;
IonSpewPass("Apply types");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Apply types"))
return false;
}
- // Parallel Safety Analysis. Note that this may delete blocks containing
- // instructions pointed to by the dependency() field of instructions which
- // are not deleted, leaving them dangling. This is ok, since we'll rerun
- // AliasAnalysis, which recomputes them, before they're needed.
- if (graph.entryBlock()->info().executionMode() == ParallelExecution) {
- AutoTraceLog log(logger, TraceLogger_ParallelSafetyAnalysis);
- ParallelSafetyAnalysis analysis(mir, graph);
- if (!analysis.analyze())
- return false;
- IonSpewPass("Parallel Safety Analysis");
- AssertExtendedGraphCoherency(graph);
- if (mir->shouldCancel("Parallel Safety Analysis"))
- return false;
- }
-
ValueNumberer gvn(mir, graph);
if (!gvn.init())
return false;
// Alias analysis is required for LICM and GVN so that we don't move
// loads across stores.
if (mir->optimizationInfo().licmEnabled() ||
mir->optimizationInfo().gvnEnabled())
@@ -1762,19 +1684,17 @@ AttachFinishedCompilations(JSContext *cx
break;
}
}
if (!builder)
break;
// Try to defer linking if the script is on the stack, to postpone
// invalidating them.
- if (builder->info().executionMode() == SequentialExecution &&
- builder->script()->hasIonScript())
- {
+ if (builder->script()->hasIonScript()) {
bool onStack = false;
for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
for (JitFrameIterator it(iter); !it.done(); ++it) {
if (!it.isIonJS())
continue;
if (it.checkInvalidation())
continue;
@@ -1870,18 +1790,17 @@ TrackPropertiesForSingletonScopes(JSCont
if (scope->is<CallObject>() && scope->hasSingletonType())
TrackAllProperties(cx, scope);
}
}
static AbortReason
IonCompile(JSContext *cx, JSScript *script,
BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
- ExecutionMode executionMode, bool recompile,
- OptimizationLevel optimizationLevel)
+ bool recompile, OptimizationLevel optimizationLevel)
{
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
AutoTraceLog logScript(logger, event);
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
@@ -1906,33 +1825,26 @@ IonCompile(JSContext *cx, JSScript *scri
types::AutoEnterAnalysis enter(cx);
if (!cx->compartment()->ensureJitCompartmentExists(cx))
return AbortReason_Alloc;
if (!cx->compartment()->jitCompartment()->ensureIonStubsExist(cx))
return AbortReason_Alloc;
- if (executionMode == ParallelExecution &&
- LIRGenerator::allowInlineForkJoinGetSlice() &&
- !cx->runtime()->jitRuntime()->ensureForkJoinGetSliceStubExists(cx))
- {
- return AbortReason_Alloc;
- }
-
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
if (!graph)
return AbortReason_Alloc;
InlineScriptTree *inlineScriptTree = InlineScriptTree::New(temp, nullptr, nullptr, script);
if (!inlineScriptTree)
return AbortReason_Alloc;
CompileInfo *info = alloc->new_<CompileInfo>(script, script->functionNonDelazifying(), osrPc,
- constructing, executionMode,
+ constructing, SequentialExecution,
script->needsArgsObj(), inlineScriptTree);
if (!info)
return AbortReason_Alloc;
BaselineInspector *inspector = alloc->new_<BaselineInspector>(script);
if (!inspector)
return AbortReason_Alloc;
@@ -1953,25 +1865,23 @@ IonCompile(JSContext *cx, JSScript *scri
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
CompileCompartment::get(cx->compartment()),
options, temp, graph, constraints,
inspector, info, optimizationInfo,
baselineFrameInspector);
if (!builder)
return AbortReason_Alloc;
- MOZ_ASSERT(recompile == HasIonScript(builder->script(), executionMode));
- MOZ_ASSERT(CanIonCompile(builder->script(), executionMode));
+ MOZ_ASSERT(recompile == builder->script()->hasIonScript());
+ MOZ_ASSERT(CanIonCompile(builder->script(), SequentialExecution));
RootedScript builderScript(cx, builder->script());
- if (recompile) {
- MOZ_ASSERT(executionMode == SequentialExecution);
+ if (recompile)
builderScript->ionScript()->setRecompiling();
- }
#ifdef DEBUG
IonSpewFunction ionSpewFunction(graph, builderScript);
#endif
bool succeeded = builder->build();
builder->clearForBackEnd();
@@ -1988,17 +1898,17 @@ IonCompile(JSContext *cx, JSScript *scri
}
}
return reason;
}
// If possible, compile the script off thread.
if (OffThreadCompilationAvailable(cx)) {
if (!recompile)
- SetIonScript(cx, builderScript, executionMode, ION_COMPILING_SCRIPT);
+ builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
JitSpew(JitSpew_IonLogs, "Can't log script %s:%d. (Compiled on background thread.)",
builderScript->filename(), builderScript->lineno());
if (!StartOffThreadIonCompile(cx, builder)) {
JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation.");
return AbortReason_Alloc;
}
@@ -2100,35 +2010,28 @@ CanIonCompileScript(JSContext *cx, JSScr
{
if (!script->canIonCompile() || !CheckScript(cx, script, osr))
return false;
return CheckScriptSize(cx, script) == Method_Compiled;
}
static OptimizationLevel
-GetOptimizationLevel(HandleScript script, jsbytecode *pc, ExecutionMode executionMode)
+GetOptimizationLevel(HandleScript script, jsbytecode *pc)
{
- if (executionMode == ParallelExecution)
- return Optimization_Normal;
-
- MOZ_ASSERT(executionMode == SequentialExecution);
-
return js_IonOptimizations.levelForScript(script, pc);
}
static MethodStatus
Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
- bool constructing, ExecutionMode executionMode, bool forceRecompile = false)
+ bool constructing, bool forceRecompile = false)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
MOZ_ASSERT_IF(osrPc != nullptr, LoopEntryCanIonOsr(osrPc));
- MOZ_ASSERT_IF(executionMode == ParallelExecution, !osrFrame && !osrPc);
- MOZ_ASSERT_IF(executionMode == ParallelExecution, !HasIonScript(script, executionMode));
if (!script->hasBaselineScript())
return Method_Skipped;
if (script->isDebuggee() || (osrFrame && osrFrame->isDebuggee())) {
JitSpew(JitSpew_IonAbort, "debugging");
return Method_Skipped;
}
@@ -2140,21 +2043,21 @@ Compile(JSContext *cx, HandleScript scri
MethodStatus status = CheckScriptSize(cx, script);
if (status != Method_Compiled) {
JitSpew(JitSpew_IonAbort, "Aborted compilation of %s:%d", script->filename(), script->lineno());
return status;
}
bool recompile = false;
- OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc, executionMode);
+ OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc);
if (optimizationLevel == Optimization_DontCompile)
return Method_Skipped;
- IonScript *scriptIon = GetIonScript(script, executionMode);
+ IonScript *scriptIon = script->maybeIonScript();
if (scriptIon) {
if (!scriptIon->method())
return Method_CantCompile;
// Don't recompile/overwrite higher optimized code,
// with a lower optimization level.
if (optimizationLevel <= scriptIon->optimizationLevel() && !forceRecompile)
return Method_Compiled;
@@ -2164,31 +2067,31 @@ Compile(JSContext *cx, HandleScript scri
return Method_Compiled;
if (osrPc)
scriptIon->resetOsrPcMismatchCounter();
recompile = true;
}
- AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode,
+ AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing,
recompile, optimizationLevel);
if (reason == AbortReason_Error)
return Method_Error;
if (reason == AbortReason_Disable)
return Method_CantCompile;
if (reason == AbortReason_Alloc) {
js_ReportOutOfMemory(cx);
return Method_Error;
}
// Compilation succeeded or we invalidated right away or an inlining/alloc abort
- if (HasIonScript(script, executionMode))
+ if (script->hasIonScript())
return Method_Compiled;
return Method_Skipped;
}
} // namespace jit
} // namespace js
// Decide if a transition from interpreter execution to Ion code should occur.
@@ -2234,17 +2137,17 @@ jit::CanEnterAtBranch(JSContext *cx, JSS
// Attempt compilation.
// - Returns Method_Compiled if the right ionscript is present
// (Meaning it was present or a sequantial compile finished)
// - Returns Method_Skipped if pc doesn't match
// (This means a background thread compilation with that pc could have started or not.)
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
- SequentialExecution, force);
+ force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
// Return the compilation was skipped when the osr pc wasn't adjusted.
// This can happen when there was still an IonScript available and a
@@ -2304,18 +2207,17 @@ jit::CanEnter(JSContext *cx, RunState &s
if (js_JitOptions.eagerCompilation && !rscript->hasBaselineScript()) {
MethodStatus status = CanEnterBaselineMethod(cx, state);
if (status != Method_Compiled)
return status;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
bool constructing = state.isInvoke() && state.asInvoke()->constructing();
- MethodStatus status =
- Compile(cx, rscript, nullptr, nullptr, constructing, SequentialExecution);
+ MethodStatus status = Compile(cx, rscript, nullptr, nullptr, constructing);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, rscript);
return status;
}
return Method_Compiled;
}
@@ -2331,18 +2233,17 @@ jit::CompileFunctionForBaseline(JSContex
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(frame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
- MethodStatus status =
- Compile(cx, script, frame, nullptr, frame->isConstructing(), SequentialExecution);
+ MethodStatus status = Compile(cx, script, frame, nullptr, frame->isConstructing());
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
return Method_Compiled;
}
@@ -2350,71 +2251,27 @@ jit::CompileFunctionForBaseline(JSContex
MethodStatus
jit::Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
bool constructing, bool force)
{
MOZ_ASSERT(script->hasIonScript());
if (script->ionScript()->isRecompiling())
return Method_Compiled;
- MethodStatus status =
- Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution, force);
+ MethodStatus status = Compile(cx, script, osrFrame, osrPc, constructing, force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
return Method_Compiled;
}
MethodStatus
-jit::CanEnterInParallel(JSContext *cx, HandleScript script)
-{
- // Skip if the script has been disabled.
- //
- // Note: We return Method_Skipped in this case because the other
- // CanEnter() methods do so. However, ForkJoin.cpp detects this
- // condition differently treats it more like an error.
- if (!script->canParallelIonCompile())
- return Method_Skipped;
-
- // Skip if the script is being compiled off thread.
- if (script->isParallelIonCompilingOffThread())
- return Method_Skipped;
-
- MethodStatus status = Compile(cx, script, nullptr, nullptr, false, ParallelExecution);
- if (status != Method_Compiled) {
- if (status == Method_CantCompile)
- ForbidCompilation(cx, script, ParallelExecution);
- return status;
- }
-
- // This can GC, so afterward, script->parallelIon is
- // not guaranteed to be valid.
- if (!cx->runtime()->jitRuntime()->enterIon())
- return Method_Error;
-
- // Subtle: it is possible for GC to occur during
- // compilation of one of the invoked functions, which
- // would cause the earlier functions (such as the
- // kernel itself) to be collected. In this event, we
- // give up and fallback to sequential for now.
- if (!script->hasParallelIonScript()) {
- parallel::Spew(
- parallel::SpewCompile,
- "Script %p:%s:%u was garbage-collected or invalidated",
- script.get(), script->filename(), script->lineno());
- return Method_Skipped;
- }
-
- return Method_Compiled;
-}
-
-MethodStatus
jit::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
// Skip if the code is expected to result in a bailout.
if (!script->hasIonScript() || script->ionScript()->bailoutExpected())
return Method_Skipped;
@@ -2800,27 +2657,19 @@ jit::Invalidate(types::TypeZone &types,
continue;
SetIonScript(nullptr, script, executionMode, nullptr);
ionScript->decrementInvalidationCount(fop);
co->invalidate();
numInvalidations--;
// Wait for the scripts to get warm again before doing another
- // compile, unless either:
- // (1) we are recompiling *because* a script got hot;
- // (resetUses is false); or,
- // (2) we are invalidating a parallel script. This is because
- // the warmUpCounter only applies to sequential uses. Parallel
- // execution *requires* ion, and so we don't limit it to
- // methods with a high usage count (though we do check that
- // the warmUpCount is at least 1 when compiling the transitive
- // closure of potential callees, to avoid compiling things
- // that are never run at all).
- if (resetUses && executionMode != ParallelExecution)
+ // compile, unless we are recompiling *because* a script got hot
+ // (resetUses is false).
+ if (resetUses)
script->resetWarmUpCounter();
}
// Make sure we didn't leak references by invalidating the same IonScript
// multiple times in the above loop.
MOZ_ASSERT(!numInvalidations);
}
@@ -2839,18 +2688,17 @@ jit::IonScript::invalidate(JSContext *cx
types::RecompileInfoVector list;
if (!list.append(recompileInfo()))
return false;
Invalidate(cx, list, resetUses, true);
return true;
}
bool
-jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses,
- bool cancelOffThread)
+jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses, bool cancelOffThread)
{
MOZ_ASSERT(script->hasIonScript());
if (cx->runtime()->spsProfiler.enabled()) {
// Register invalidation with profiler.
// Format of event payload string:
// "<filename>:<lineno>"
@@ -2866,135 +2714,70 @@ jit::Invalidate(JSContext *cx, JSScript
// Construct the descriptive string.
JS_snprintf(buf, len, "Invalidate %s:%u", filename, (unsigned int)script->lineno());
cx->runtime()->spsProfiler.markEvent(buf);
js_free(buf);
}
types::RecompileInfoVector scripts;
-
- switch (mode) {
- case SequentialExecution:
- MOZ_ASSERT(script->hasIonScript());
- if (!scripts.append(script->ionScript()->recompileInfo()))
- return false;
- break;
- case ParallelExecution:
- MOZ_ASSERT(script->hasParallelIonScript());
- if (!scripts.append(script->parallelIonScript()->recompileInfo()))
- return false;
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ MOZ_ASSERT(script->hasIonScript());
+ if (!scripts.append(script->ionScript()->recompileInfo()))
+ return false;
Invalidate(cx, scripts, resetUses, cancelOffThread);
return true;
}
-bool
-jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses, bool cancelOffThread)
-{
- return Invalidate(cx, script, SequentialExecution, resetUses, cancelOffThread);
-}
-
static void
FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript)
{
types::TypeZone &types = script->zone()->types;
// Note: If the script is about to be swept, the compiler output may have
// already been destroyed.
if (types::CompilerOutput *output = ionScript->recompileInfo().compilerOutput(types))
output->invalidate();
// If this script has Ion code on the stack, invalidated() will return
// true. In this case we have to wait until destroying it.
if (!ionScript->invalidated())
jit::IonScript::Destroy(fop, ionScript);
}
-template <ExecutionMode mode>
void
jit::FinishInvalidation(FreeOp *fop, JSScript *script)
{
- // In all cases, nullptr out script->ion or script->parallelIon to avoid
- // re-entry.
- switch (mode) {
- case SequentialExecution:
- if (script->hasIonScript()) {
- IonScript *ion = script->ionScript();
- script->setIonScript(nullptr, nullptr);
- FinishInvalidationOf(fop, script, ion);
- }
- return;
-
- case ParallelExecution:
- if (script->hasParallelIonScript()) {
- IonScript *parallelIon = script->parallelIonScript();
- script->setParallelIonScript(nullptr);
- FinishInvalidationOf(fop, script, parallelIon);
- }
- return;
-
- default:
- MOZ_CRASH("bad execution mode");
+ // In all cases, nullptr out script->ion to avoid re-entry.
+ if (script->hasIonScript()) {
+ IonScript *ion = script->ionScript();
+ script->setIonScript(nullptr, nullptr);
+ FinishInvalidationOf(fop, script, ion);
}
}
-template void
-jit::FinishInvalidation<SequentialExecution>(FreeOp *fop, JSScript *script);
-
-template void
-jit::FinishInvalidation<ParallelExecution>(FreeOp *fop, JSScript *script);
-
void
jit::ForbidCompilation(JSContext *cx, JSScript *script)
{
- ForbidCompilation(cx, script, SequentialExecution);
-}
-
-void
-jit::ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode)
-{
- JitSpew(JitSpew_IonAbort, "Disabling Ion mode %d compilation of script %s:%d",
- mode, script->filename(), script->lineno());
+ JitSpew(JitSpew_IonAbort, "Disabling Ion compilation of script %s:%d",
+ script->filename(), script->lineno());
CancelOffThreadIonCompile(cx->compartment(), script);
- switch (mode) {
- case SequentialExecution:
- if (script->hasIonScript()) {
- // It is only safe to modify script->ion if the script is not currently
- // running, because JitFrameIterator needs to tell what ionScript to
- // use (either the one on the JSScript, or the one hidden in the
- // breadcrumbs Invalidation() leaves). Therefore, if invalidation
- // fails, we cannot disable the script.
- if (!Invalidate(cx, script, mode, false))
- return;
- }
-
- script->setIonScript(cx, ION_DISABLED_SCRIPT);
- return;
-
- case ParallelExecution:
- if (script->hasParallelIonScript()) {
- if (!Invalidate(cx, script, mode, false))
- return;
- }
-
- script->setParallelIonScript(ION_DISABLED_SCRIPT);
- return;
-
- default:
- MOZ_CRASH("No such execution mode");
+ if (script->hasIonScript()) {
+ // It is only safe to modify script->ion if the script is not currently
+ // running, because JitFrameIterator needs to tell what ionScript to
+ // use (either the one on the JSScript, or the one hidden in the
+ // breadcrumbs Invalidation() leaves). Therefore, if invalidation
+ // fails, we cannot disable the script.
+ if (!Invalidate(cx, script, false))
+ return;
}
- MOZ_CRASH("No such execution mode");
+ script->setIonScript(cx, ION_DISABLED_SCRIPT);
}
AutoFlushICache *
PerThreadData::autoFlushICache() const
{
return autoFlushICache_;
}
@@ -3134,57 +2917,45 @@ AutoFlushICache::~AutoFlushICache()
#endif
}
void
jit::PurgeCaches(JSScript *script)
{
if (script->hasIonScript())
script->ionScript()->purgeCaches();
-
- if (script->hasParallelIonScript())
- script->parallelIonScript()->purgeCaches();
}
size_t
jit::SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf)
{
size_t result = 0;
if (script->hasIonScript())
result += script->ionScript()->sizeOfIncludingThis(mallocSizeOf);
- if (script->hasParallelIonScript())
- result += script->parallelIonScript()->sizeOfIncludingThis(mallocSizeOf);
-
return result;
}
void
jit::DestroyJitScripts(FreeOp *fop, JSScript *script)
{
if (script->hasIonScript())
jit::IonScript::Destroy(fop, script->ionScript());
- if (script->hasParallelIonScript())
- jit::IonScript::Destroy(fop, script->parallelIonScript());
-
if (script->hasBaselineScript())
jit::BaselineScript::Destroy(fop, script->baselineScript());
}
void
jit::TraceJitScripts(JSTracer* trc, JSScript *script)
{
if (script->hasIonScript())
jit::IonScript::Trace(trc, scrip