Merge mozilla-central to autoland r=merge

This commit is contained in:
Dorel Luca 2018-01-23 19:54:54 +02:00
commit bad2421650
674 changed files with 196480 additions and 19008 deletions

View File

@ -834,7 +834,7 @@ logging::Node(const char* aDescr, nsINode* aNode)
}
nsINode* parentNode = aNode->GetParentNode();
int32_t idxInParent = parentNode ? parentNode->IndexOf(aNode) : - 1;
int32_t idxInParent = parentNode ? parentNode->ComputeIndexOf(aNode) : - 1;
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
printf("%s: %p, text node, idx in parent: %d\n",

View File

@ -428,7 +428,7 @@ HyperTextAccessible::OffsetToDOMPoint(int32_t aOffset)
nsINode* node = child->GetNode();
nsINode* parentNode = node->GetParentNode();
return parentNode ?
DOMPoint(parentNode, parentNode->IndexOf(node) + innerOffset) :
DOMPoint(parentNode, parentNode->ComputeIndexOf(node) + innerOffset) :
DOMPoint();
}
@ -2081,7 +2081,7 @@ HyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset,
nsIContent* parent = content->GetParent();
aPoint->idx = parent->IndexOf(content) + 1;
aPoint->idx = parent->ComputeIndexOf(content) + 1;
aPoint->node = parent;
} else if (aFrame->IsTextFrame()) {
@ -2101,7 +2101,7 @@ HyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset,
nsIContent* parent = content->GetParent();
NS_ENSURE_STATE(parent);
aPoint->idx = parent->IndexOf(content);
aPoint->idx = parent->ComputeIndexOf(content);
aPoint->node = parent;
}

View File

@ -4480,7 +4480,6 @@
window.addEventListener("MozAfterPaint", this);
window.addEventListener("MozLayerTreeReady", this);
window.addEventListener("MozLayerTreeCleared", this);
window.addEventListener("TabBrowserDiscarded", this);
window.addEventListener("TabRemotenessChange", this);
window.addEventListener("sizemodechange", this);
window.addEventListener("occlusionstatechange", this);
@ -4525,7 +4524,6 @@
window.removeEventListener("MozAfterPaint", this);
window.removeEventListener("MozLayerTreeReady", this);
window.removeEventListener("MozLayerTreeCleared", this);
window.removeEventListener("TabBrowserDiscarded", this);
window.removeEventListener("TabRemotenessChange", this);
window.removeEventListener("sizemodechange", this);
window.removeEventListener("occlusionstatechange", this);
@ -4969,12 +4967,6 @@
}
},
// Called when a tab is discarded
onTabDiscarded(tab) {
this.logState(`onTabDiscarded(${tab._tPos})`);
this.setTabStateNoAction(tab, this.STATE_UNLOADED);
},
// Called when a tab has been removed, and the browser node is
// about to be removed from the DOM.
onTabRemoved(tab) {
@ -5211,8 +5203,6 @@
this.onLayersCleared(event.originalTarget);
} else if (event.type == "TabRemotenessChange") {
this.onRemotenessChange(event.target);
} else if (event.type == "TabBrowserDiscarded") {
this.onTabDiscarded(event.target);
} else if (event.type == "sizemodechange" ||
event.type == "occlusionstatechange") {
this.onSizeModeOrOcclusionStateChange();
@ -6229,7 +6219,8 @@
if (this.selectedBrowser == browser) {
TabCrashHandler.onSelectedBrowserCrash(browser);
} else {
this.discardBrowser(browser);
this.updateBrowserRemoteness(browser, false);
SessionStore.reviveCrashedTab(tab);
}
tab.removeAttribute("soundplaying");

View File

@ -1903,12 +1903,8 @@ var SessionStoreInternal = {
// Only restore if browser has been lazy.
if (aTab.__SS_lazyData && !browser.__SS_restoreState && TabStateCache.get(browser)) {
if (TabCrashHandler.willShowCrashedTab(browser)) {
this.enterCrashedState(browser);
} else {
let tabState = TabState.clone(aTab);
this.restoreTab(aTab, tabState);
}
let tabState = TabState.clone(aTab);
this.restoreTab(aTab, tabState);
}
// The browser has been inserted now, so lazy data is no longer relevant.
@ -2124,7 +2120,20 @@ var SessionStoreInternal = {
if (browser.__SS_restoreState &&
browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
// If __SS_restoreState is still on the browser and it is
// TAB_STATE_NEEDS_RESTORE, then then we haven't restored
// this tab yet.
//
// It's possible that this tab was recently revived, and that
// we've deferred showing the tab crashed page for it (if the
// tab crashed in the background). If so, we need to re-enter
// the crashed state, since we'll be showing the tab crashed
// page.
if (TabCrashHandler.willShowCrashedTab(browser)) {
this.enterCrashedState(browser);
} else {
this.restoreTabContent(tab);
}
}
}
},
@ -2883,7 +2892,19 @@ var SessionStoreInternal = {
return;
}
// Sanity check - the browser to be revived should not be remote
// at this point.
if (browser.isRemoteBrowser) {
throw new Error("SessionStore.reviveCrashedTab: " +
"Somehow a crashed browser is still remote.");
}
// We put the browser at about:blank in case the user is
// restoring tabs on demand. This way, the user won't see
// a flash of the about:tabcrashed page after selecting
// the revived tab.
aTab.removeAttribute("crashed");
browser.loadURI("about:blank", null, null);
let data = TabState.collect(aTab);
this.restoreTab(aTab, data, {

View File

@ -81,13 +81,22 @@ async function crashBackgroundTabs(tabs) {
Assert.ok(tab.linkedBrowser.isRemoteBrowser, "tab is remote");
}
let remotenessChangePromises = tabs.map((t) => {
return BrowserTestUtils.waitForEvent(t, "TabRemotenessChange");
});
let tabsRevived = tabs.map((t) => {
return promiseTabRestoring(t);
});
await BrowserTestUtils.crashBrowser(tabs[0].linkedBrowser, false);
await Promise.all(remotenessChangePromises);
await Promise.all(tabsRevived);
// Both background tabs should now be in the pending restore
// state.
for (let tab of tabs) {
Assert.ok(!tab.linkedPanel, "The tab should be initially discarded.");
Assert.ok(tab.linkedBrowser.isRemoteBrowser, "tab is still remote");
Assert.ok(!tab.linkedBrowser.isRemoteBrowser, "tab is not remote");
Assert.ok(!tab.linkedBrowser.hasAttribute("crashed"), "tab is not crashed");
Assert.ok(tab.hasAttribute("pending"), "tab is pending");
}
@ -117,9 +126,9 @@ add_task(async function test_background_crash_simple() {
// Selecting the first tab should now send it to the tab crashed page.
let tabCrashedPagePromise =
BrowserTestUtils.waitForEvent(window,
"AboutTabCrashedReady",
false, null, true);
BrowserTestUtils.waitForContentEvent(tab1.linkedBrowser,
"AboutTabCrashedReady",
false, null, true);
await BrowserTestUtils.switchTab(gBrowser, tab1);
await tabCrashedPagePromise;

View File

@ -32,11 +32,15 @@ add_task(async function test_revive_bg_tabs_on_demand() {
await TabStateFlusher.flush(browser2);
// Now crash the selected tab
let windowReady = BrowserTestUtils.waitForEvent(window, "SSWindowStateReady");
await BrowserTestUtils.crashBrowser(browser1);
ok(newTab1.hasAttribute("crashed"), "Selected tab should be crashed");
ok(!newTab2.hasAttribute("crashed"), "Background tab should not be crashed");
// Wait until we've had a chance to restore all tabs immediately
await windowReady;
// But we should not have restored the background tab
ok(newTab2.hasAttribute("pending"), "Background tab should be pending");

View File

@ -2,6 +2,11 @@
ac_add_options --disable-debug
ac_add_options --enable-optimize="-O2 -gline-tables-only"
#add-on signing is checked but not enforced
MOZ_REQUIRE_SIGNING=0
# Enable MOZ_ALLOW_LEGACY_EXTENSIONS
ac_add_options "MOZ_ALLOW_LEGACY_EXTENSIONS=1"
. $topsrcdir/build/mozconfig.stylo
# ASan specific options on Linux

36
build/gn.mozbuild Normal file
View File

@ -0,0 +1,36 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
gn_vars = {}
if CONFIG['MOZ_DEBUG']:
gn_vars['is_debug'] = True
else:
gn_vars['is_debug'] = False
os = CONFIG['OS_TARGET']
flavors = {
'WINNT': 'win',
'Android': 'android',
'Linux': 'linux',
'Darwin': 'mac' if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa' else 'ios',
'SunOS': 'solaris',
'GNU/kFreeBSD': 'freebsd',
'DragonFly': 'dragonfly',
'FreeBSD': 'freebsd',
'NetBSD': 'netbsd',
'OpenBSD': 'openbsd',
}
gn_vars['target_os'] = flavors.get(os)
arches = {
'x86_64': 'x64',
'aarch64': 'arm64',
}
gn_vars['host_cpu'] = arches.get(CONFIG['HOST_CPU_ARCH'], CONFIG['HOST_CPU_ARCH'])
gn_vars['target_cpu'] = arches.get(CONFIG['CPU_ARCH'], CONFIG['CPU_ARCH'])

View File

@ -279,14 +279,14 @@ Attr::GetChildAt_Deprecated(uint32_t aIndex) const
}
int32_t
Attr::IndexOf(const nsINode* aPossibleChild) const
Attr::ComputeIndexOf(const nsINode* aPossibleChild) const
{
return -1;
}
nsresult
Attr::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
Attr::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -63,9 +63,9 @@ public:
virtual bool IsNodeOfType(uint32_t aFlags) const override;
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,

View File

@ -554,7 +554,7 @@ int32_t
nsAttrChildContentList::IndexOf(nsIContent* aContent)
{
if (mNode) {
return mNode->IndexOf(aContent);
return mNode->ComputeIndexOf(aContent);
}
return -1;
@ -1157,9 +1157,9 @@ nsIContent::SetXBLInsertionPoint(nsIContent* aContent)
}
nsresult
FragmentOrElement::InsertChildAt(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
FragmentOrElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
{
NS_PRECONDITION(aKid, "null ptr");
@ -1182,7 +1182,7 @@ FragmentOrElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
// Let's keep the node alive.
nsCOMPtr<nsIContent> kungFuDeathGrip = aKid;
doRemoveChildAt(IndexOf(aKid), aNotify, aKid, mAttrsAndChildren);
doRemoveChildAt(ComputeIndexOf(aKid), aNotify, aKid, mAttrsAndChildren);
}
void
@ -2140,7 +2140,7 @@ FragmentOrElement::GetChildAt_Deprecated(uint32_t aIndex) const
}
int32_t
FragmentOrElement::IndexOf(const nsINode* aPossibleChild) const
FragmentOrElement::ComputeIndexOf(const nsINode* aPossibleChild) const
{
return mAttrsAndChildren.IndexOfChild(aPossibleChild);
}

View File

@ -119,9 +119,9 @@ public:
// nsINode interface methods
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual void GetTextContentInternal(nsAString& aTextContent,

View File

@ -178,7 +178,7 @@ public:
MOZ_ASSERT(mRef);
MOZ_ASSERT(mRef->GetParentNode() == mParent);
mOffset = mozilla::Some(mParent->IndexOf(mRef) + 1);
mOffset = mozilla::Some(mParent->ComputeIndexOf(mRef) + 1);
return mOffset.value();
}

View File

@ -1686,7 +1686,7 @@ Selection::GetPrimaryFrameForFocusNode(nsIFrame** aReturnFrame,
if (NS_WARN_IF(!parent)) {
return NS_ERROR_FAILURE;
}
int32_t offset = parent->IndexOf(content);
int32_t offset = parent->ComputeIndexOf(content);
return GetPrimaryOrCaretFrameForNodeOffset(parent, offset, aReturnFrame,
aOffsetUsed, aVisual);
@ -2585,7 +2585,7 @@ Selection::Collapse(const RawRangeBoundary& aPoint, ErrorResult& aRv)
// done yet. However, it's called only when the container is a text
// node. In such case, offset has always been set since it cannot have
// any children. So, this doesn't cause computing offset with expensive
// method, nsINode::IndexOf().
// method, nsINode::ComputeIndexOf().
if ((aPoint.Container()->AsContent() == f->GetContent() &&
f->GetContentEnd() == static_cast<int32_t>(aPoint.Offset())) ||
(aPoint.Container() == f->GetContent()->GetParentNode() &&

View File

@ -182,8 +182,8 @@ protected:
// end to the common ancestor. If we used the index array, we would pay the
// price up front for n, and then pay the cost for m on the fly later on.
// With the simple cache, we only "pay as we go". Either way, we call
// IndexOf() once for each change of level in the hierarchy. Since a trivial
// index is much simpler, we use it for the subtree iterator.
// ComputeIndexOf() once for each change of level in the hierarchy. Since
// a trivial index is much simpler, we use it for the subtree iterator.
bool mIsDone;
bool mPre;
@ -563,7 +563,7 @@ nsContentIterator::RebuildIndexStack()
return NS_ERROR_FAILURE;
}
mIndexes.InsertElementAt(0, parent->IndexOf(current));
mIndexes.InsertElementAt(0, parent->ComputeIndexOf(current));
current = parent;
}
@ -689,12 +689,12 @@ nsContentIterator::GetNextSibling(nsINode* aNode,
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
// reverify that the index of the current node hasn't changed.
// not super cheap, but a lot cheaper than IndexOf(), and still O(1).
// ignore result this time - the index may now be out of range.
// not super cheap, but a lot cheaper than ComputeIndexOf(), and still
// O(1). ignore result this time - the index may now be out of range.
nsIContent* sib = parent->GetChildAt_Deprecated(indx);
if (sib != aNode) {
// someone changed our index - find the new index the painful way
indx = parent->IndexOf(aNode);
indx = parent->ComputeIndexOf(aNode);
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
}
@ -755,7 +755,7 @@ nsContentIterator::GetPrevSibling(nsINode* aNode,
nsIContent* sib = parent->GetChildAt_Deprecated(indx);
if (sib != aNode) {
// someone changed our index - find the new index the painful way
indx = parent->IndexOf(aNode);
indx = parent->ComputeIndexOf(aNode);
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
}
@ -826,14 +826,14 @@ nsContentIterator::NextNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
}
// reverify that the index of the current node hasn't changed. not super
// cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result
// this time - the index may now be out of range.
// cheap, but a lot cheaper than ComputeIndexOf(), and still O(1). ignore
// result this time - the index may now be out of range.
if (indx >= 0) {
sibling = parent->GetChildAt_Deprecated(indx);
}
if (sibling != node) {
// someone changed our index - find the new index the painful way
indx = parent->IndexOf(node);
indx = parent->ComputeIndexOf(node);
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
}
@ -895,8 +895,8 @@ nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
}
// reverify that the index of the current node hasn't changed. not super
// cheap, but a lot cheaper than IndexOf(), and still O(1). ignore result
// this time - the index may now be out of range.
// cheap, but a lot cheaper than ComputeIndexOf(), and still O(1).
// ignore result this time - the index may now be out of range.
if (indx >= 0) {
sibling = parent->GetChildAt_Deprecated(indx);
NS_WARNING_ASSERTION(sibling, "GetChildAt_Deprecated returned null");
@ -904,7 +904,7 @@ nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
if (sibling != node) {
// someone changed our index - find the new index the painful way
indx = parent->IndexOf(node);
indx = parent->ComputeIndexOf(node);
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
}
@ -1098,9 +1098,9 @@ nsContentIterator::PositionAt(nsINode* aCurNode)
// Get a list of the parents up to the root, then compare the new node with
// entries in that array until we find a match (lowest common ancestor). If
// no match, use IndexOf, take the parent, and repeat. This avoids using
// IndexOf() N times on possibly large arrays. We still end up doing it a
// fair bit. It's better to use Clone() if possible.
// no match, use ComputeIndexOf, take the parent, and repeat. This avoids
// using ComputeIndexOf() N times on possibly large arrays. We still end
// up doing it a fair bit. It's better to use Clone() if possible.
// we know the depth we're down (though we may not have started at the top).
oldParentStack.SetCapacity(mIndexes.Length() + 1);
@ -1140,7 +1140,7 @@ nsContentIterator::PositionAt(nsINode* aCurNode)
break;
}
int32_t indx = parent->IndexOf(newCurNode);
int32_t indx = parent->ComputeIndexOf(newCurNode);
NS_WARNING_ASSERTION(indx >= 0, "bad indx");
// insert at the head!

View File

@ -2314,7 +2314,7 @@ nsContentUtils::InProlog(nsINode *aNode)
nsIDocument* doc = static_cast<nsIDocument*>(parent);
nsIContent* root = doc->GetRootElement();
return !root || doc->IndexOf(aNode) < doc->IndexOf(root);
return !root || doc->ComputeIndexOf(aNode) < doc->ComputeIndexOf(root);
}
nsIDocument*
@ -2659,7 +2659,7 @@ nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode,
nsIContent* parent = child->GetParent();
while (parent) {
aAncestorNodes->AppendElement(parent);
aAncestorOffsets->AppendElement(parent->IndexOf(child));
aAncestorOffsets->AppendElement(parent->ComputeIndexOf(child));
child = parent;
parent = parent->GetParent();
}
@ -2769,8 +2769,8 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
{
if (aParent1 == aParent2) {
// XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
// of nsINode::IndexOf(), but this compares such invalid offset with
// valid offset.
// of nsINode::ComputeIndexOf(), but this compares such invalid
// offset with valid offset.
return aOffset1 < aOffset2 ? -1 :
aOffset1 > aOffset2 ? 1 :
0;
@ -2807,7 +2807,7 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* child1 = parents1.ElementAt(--pos1);
nsINode* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
return parent->IndexOf(child1) < parent->IndexOf(child2) ? -1 : 1;
return parent->ComputeIndexOf(child1) < parent->ComputeIndexOf(child2) ? -1 : 1;
}
parent = child1;
}
@ -2823,13 +2823,13 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* child2 = parents2.ElementAt(--pos2);
// XXX aOffset1 may be -1 as mentioned above. So, why does this return
// it's *before* of the valid DOM point?
return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
return aOffset1 <= parent->ComputeIndexOf(child2) ? -1 : 1;
}
nsINode* child1 = parents1.ElementAt(--pos1);
// XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
// *after* of the valid DOM point?
return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
return parent->ComputeIndexOf(child1) < aOffset2 ? -1 : 1;
}
/* static */
@ -3144,7 +3144,7 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent,
nsINode* parent = aContent->GetParentNode();
nsINode* content = aContent;
while (parent) {
KeyAppendInt(parent->IndexOf(content), aKey);
KeyAppendInt(parent->ComputeIndexOf(content), aKey);
content = parent;
parent = content->GetParentNode();
}

View File

@ -4351,7 +4351,7 @@ nsDocument::GetChildAt_Deprecated(uint32_t aIndex) const
}
int32_t
nsDocument::IndexOf(const nsINode* aPossibleChild) const
nsDocument::ComputeIndexOf(const nsINode* aPossibleChild) const
{
return mChildren.IndexOfChild(aPossibleChild);
}
@ -4363,8 +4363,8 @@ nsDocument::GetChildCount() const
}
nsresult
nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
nsDocument::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
{
if (aKid->IsElement() && GetRootElement()) {
NS_WARNING("Inserting root element when we already have one");
@ -4417,7 +4417,7 @@ nsDocument::RemoveChildNode(nsIContent* aKid, bool aNotify)
// Any call before that point would restore this soon-to-be-obsolete cached
// answer, and our clearing here would be fruitless.)
mCachedRootElement = nullptr;
doRemoveChildAt(IndexOf(aKid), aNotify, aKid, mChildren);
doRemoveChildAt(ComputeIndexOf(aKid), aNotify, aKid, mChildren);
MOZ_ASSERT(mCachedRootElement != aKid,
"Stale pointer in mCachedRootElement, after we tried to clear it "
"(maybe somebody called GetRootElement() too early?)");
@ -6881,7 +6881,7 @@ nsDocument::SetTitle(const nsAString& aTitle)
if (!title) {
return NS_OK;
}
rootElement->InsertChildAt(title, 0, true);
rootElement->InsertChildAt_Deprecated(title, 0, true);
}
} else if (rootElement->IsHTMLElement()) {
if (!title) {

View File

@ -555,10 +555,10 @@ public:
// nsINode
virtual bool IsNodeOfType(uint32_t aFlags) const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual uint32_t GetChildCount() const override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,

View File

@ -1797,7 +1797,7 @@ nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
if (!cChild || !content)
return NS_ERROR_NULL_POINTER;
*outOffset = content->IndexOf(cChild);
*outOffset = content->ComputeIndexOf(cChild);
}
}
return result;

View File

@ -3372,7 +3372,7 @@ nsFocusManager::GetNextTabbableMapArea(bool aForward,
uint32_t count = mapContent->GetChildCount();
// First see if the the start content is in this map
int32_t index = mapContent->IndexOf(aStartContent);
int32_t index = mapContent->ComputeIndexOf(aStartContent);
int32_t tabIndex;
if (index < 0 || (aStartContent->IsFocusable(&tabIndex) &&
tabIndex != aCurrentTabIndex)) {

View File

@ -646,14 +646,15 @@ nsGenericDOMDataNode::GetChildAt_Deprecated(uint32_t aIndex) const
int32_t
nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const
nsGenericDOMDataNode::ComputeIndexOf(const nsINode* aPossibleChild) const
{
return -1;
}
nsresult
nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
nsGenericDOMDataNode::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
{
return NS_OK;
}
@ -754,11 +755,11 @@ nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
nsCOMPtr<nsINode> parent = GetParentNode();
if (parent) {
int32_t insertionIndex = parent->IndexOf(this);
int32_t insertionIndex = parent->ComputeIndexOf(this);
if (aCloneAfterOriginal) {
++insertionIndex;
}
parent->InsertChildAt(newContent, insertionIndex, true);
parent->InsertChildAt_Deprecated(newContent, insertionIndex, true);
}
newContent.swap(*aReturn);
@ -820,7 +821,7 @@ nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
if (!parent)
return GetData(aWholeText);
int32_t index = parent->IndexOf(this);
int32_t index = parent->ComputeIndexOf(this);
NS_WARNING_ASSERTION(index >= 0,
"Trying to use .wholeText with an anonymous"
"text node child of a binding parent?");

View File

@ -106,9 +106,9 @@ public:
// nsINode methods
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual void GetTextContentInternal(nsAString& aTextContent,

View File

@ -607,7 +607,7 @@ nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError)
nsContentUtils::MaybeFireNodeRemoved(&aOldChild, this, OwnerDoc());
}
int32_t index = IndexOf(&aOldChild);
int32_t index = ComputeIndexOf(&aOldChild);
if (index == -1) {
// aOldChild isn't one of our children.
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
@ -721,7 +721,7 @@ nsINode::Normalize()
"Should always have a parent unless "
"mutation events messed us up");
if (parent) {
parent->RemoveChildAt_Deprecated(parent->IndexOf(node), true);
parent->RemoveChildAt_Deprecated(parent->ComputeIndexOf(node), true);
}
}
}
@ -1005,9 +1005,9 @@ nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
const nsINode* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
// child1 or child2 can be an attribute here. This will work fine since
// IndexOf will return -1 for the attribute making the attribute be
// considered before any child.
return parent->IndexOf(child1) < parent->IndexOf(child2) ?
// ComputeIndexOf will return -1 for the attribute making the
// attribute be considered before any child.
return parent->ComputeIndexOf(child1) < parent->ComputeIndexOf(child2) ?
static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING) :
static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
}
@ -1474,7 +1474,7 @@ nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
nsIContent* parent = tmp->GetParent();
if (parent && !parent->UnoptimizableCCNode() &&
parent->HasKnownLiveWrapper()) {
MOZ_ASSERT(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
MOZ_ASSERT(parent->ComputeIndexOf(tmp) >= 0, "Parent doesn't own us?");
return false;
}
}
@ -1930,7 +1930,7 @@ nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
// nsDocument::RemoveChildNode().
MOZ_ASSERT(aKid && aKid->GetParentNode() == this &&
aKid == GetChildAt_Deprecated(aIndex) &&
IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
ComputeIndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
MOZ_ASSERT(!IsNodeOfType(nsINode::eATTRIBUTE));
nsMutationGuard::DidMutate();
@ -2025,8 +2025,8 @@ bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
return true;
}
int32_t doctypeIndex = aParent->IndexOf(docTypeContent);
int32_t insertIndex = aParent->IndexOf(aRefChild);
int32_t doctypeIndex = aParent->ComputeIndexOf(docTypeContent);
int32_t insertIndex = aParent->ComputeIndexOf(aRefChild);
// Now we're OK in the following two cases only:
// 1) We're replacing something that's not before the doctype
@ -2061,8 +2061,8 @@ bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
return false;
}
int32_t rootIndex = aParent->IndexOf(rootElement);
int32_t insertIndex = aParent->IndexOf(aRefChild);
int32_t rootIndex = aParent->ComputeIndexOf(rootElement);
int32_t insertIndex = aParent->ComputeIndexOf(aRefChild);
// Now we're OK if and only if insertIndex <= rootIndex. Indeed, either
// we end up replacing aRefChild or we end up before it. Either one is
@ -2180,7 +2180,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
// Scope firing mutation events so that we don't carry any state that
// might be stale
{
// This check happens again further down (though then using IndexOf).
// This check happens again further down (though then using
// ComputeIndexOf).
// We're only checking this here to avoid firing mutation events when
// none should be fired.
// It's ok that we do the check twice in the case when firing mutation
@ -2240,7 +2241,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
nsIContent* newContent = aNewChild->AsContent();
nsCOMPtr<nsINode> oldParent = newContent->GetParentNode();
if (oldParent) {
int32_t removeIndex = oldParent->IndexOf(newContent);
int32_t removeIndex = oldParent->ComputeIndexOf(newContent);
if (removeIndex < 0) {
// newContent is anonymous. We can't deal with this, so just bail
NS_ERROR("How come our flags didn't catch this?");
@ -2415,7 +2416,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
// parent list.
int32_t insPos;
if (nodeToInsertBefore) {
insPos = IndexOf(nodeToInsertBefore);
insPos = ComputeIndexOf(nodeToInsertBefore);
if (insPos < 0) {
// XXXbz How the heck would _that_ happen, exactly?
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
@ -2491,8 +2492,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
for (uint32_t i = 0; i < count; ++i, ++insPos) {
// XXXbz how come no reparenting here? That seems odd...
// Insert the child.
aError = InsertChildAt(fragChildren->ElementAt(i), insPos,
!appending);
aError = InsertChildAt_Deprecated(fragChildren->ElementAt(i), insPos,
!appending);
if (aError.Failed()) {
// Make sure to notify on any children that we did succeed to insert
if (appending && i != 0) {
@ -2534,7 +2535,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
mb.SetPrevSibling(GetChildAt_Deprecated(insPos - 1));
mb.SetNextSibling(GetChildAt_Deprecated(insPos));
}
aError = InsertChildAt(newContent, insPos, true);
aError = InsertChildAt_Deprecated(newContent, insPos, true);
if (aError.Failed()) {
return nullptr;
}

View File

@ -519,7 +519,7 @@ public:
* If the return value is not -1, then calling GetChildAt_Deprecated() with
* that value will return aPossibleChild.
*/
virtual int32_t IndexOf(const nsINode* aPossibleChild) const = 0;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const = 0;
/**
* Returns the "node document" of this node.
@ -736,8 +736,8 @@ public:
*
* @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
*/
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) = 0;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) = 0;
/**
* Append a content node to the end of the child list. This method handles
@ -759,7 +759,7 @@ public:
*/
nsresult AppendChildTo(nsIContent* aKid, bool aNotify)
{
return InsertChildAt(aKid, GetChildCount(), aNotify);
return InsertChildAt_Deprecated(aKid, GetChildCount(), aNotify);
}
/**
@ -2093,7 +2093,7 @@ protected:
nsAttrAndChildArray& aChildArray);
/**
* Most of the implementation of the nsINode InsertChildAt method.
* Most of the implementation of the nsINode InsertChildAt_Deprecated method.
* Should only be called on document, element, and document fragment
* nodes. The aChildArray passed in should be the one for |this|.
*

View File

@ -123,7 +123,7 @@ nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
nodeEnd = static_cast<int32_t>(childCount);
}
else {
nodeStart = parent->IndexOf(aNode);
nodeStart = parent->ComputeIndexOf(aNode);
nodeEnd = nodeStart + 1;
MOZ_ASSERT(nodeStart < nodeEnd, "nodeStart shouldn't be INT32_MAX");
}
@ -969,7 +969,7 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
}
// Step 5.
int32_t nodeIndex = parent->IndexOf(&aNode);
int32_t nodeIndex = parent->ComputeIndexOf(&aNode);
// Steps 6-7.
// Note: if disconnected is true, ComparePoints returns 1.
@ -1104,7 +1104,7 @@ IndexOf(nsINode* aChild)
{
nsINode* parent = aChild->GetParentNode();
return parent ? parent->IndexOf(aChild) : -1;
return parent ? parent->ComputeIndexOf(aChild) : -1;
}
void
@ -1571,9 +1571,10 @@ nsRange::SelectNodesInContainer(nsINode* aContainer,
nsIContent* aEndContent)
{
MOZ_ASSERT(aContainer);
MOZ_ASSERT(aContainer->IndexOf(aStartContent) <= aContainer->IndexOf(aEndContent));
MOZ_ASSERT(aStartContent && aContainer->IndexOf(aStartContent) != -1);
MOZ_ASSERT(aEndContent && aContainer->IndexOf(aEndContent) != -1);
MOZ_ASSERT(aContainer->ComputeIndexOf(aStartContent) <=
aContainer->ComputeIndexOf(aEndContent));
MOZ_ASSERT(aStartContent && aContainer->ComputeIndexOf(aStartContent) != -1);
MOZ_ASSERT(aEndContent && aContainer->ComputeIndexOf(aEndContent) != -1);
nsINode* newRoot = ComputeRootNode(aContainer, mMaySpanAnonymousSubtrees);
MOZ_ASSERT(newRoot);
@ -1780,7 +1781,7 @@ nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
return;
}
int32_t index = container->IndexOf(&aNode);
int32_t index = container->ComputeIndexOf(&aNode);
// MOZ_ASSERT(index != -1);
// We need to compute the index here unfortunately, because, while we have
// support for XBL, |container| may be the node's binding parent without
@ -3676,7 +3677,7 @@ nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
if (content && content->HasIndependentSelection()) {
nsINode* parent = startContainer->GetParent();
if (parent) {
startOffset = parent->IndexOf(startContainer);
startOffset = parent->ComputeIndexOf(startContainer);
startContainer = parent;
}
}

View File

@ -257,7 +257,7 @@ public:
if (!parentNode) {
return nullptr;
}
int32_t indexInParent = parentNode->IndexOf(aNode);
int32_t indexInParent = parentNode->ComputeIndexOf(aNode);
if (NS_WARN_IF(indexInParent < 0)) {
return nullptr;
}
@ -273,7 +273,7 @@ public:
if (!parentNode) {
return nullptr;
}
int32_t indexInParent = parentNode->IndexOf(aNode);
int32_t indexInParent = parentNode->ComputeIndexOf(aNode);
if (NS_WARN_IF(indexInParent < 0)) {
return nullptr;
}
@ -475,8 +475,8 @@ protected:
/**
* XXX nsRange should accept 0 - UINT32_MAX as offset. However, users of
* nsRange treat offset as int32_t. Additionally, some other internal
* APIs like nsINode::IndexOf() use int32_t. Therefore, nsRange should
* accept only 0 - INT32_MAX as valid offset for now.
* APIs like nsINode::ComputeIndexOf() use int32_t. Therefore,
* nsRange should accept only 0 - INT32_MAX as valid offset for now.
*/
static bool IsValidOffset(uint32_t aOffset)
{

View File

@ -1208,7 +1208,7 @@ ContentEventHandler::SetRawRangeFromFlatTextOffset(
if (NS_WARN_IF(!startNode)) {
return NS_ERROR_FAILURE;
}
startNodeOffset = startNode->IndexOf(content);
startNodeOffset = startNode->ComputeIndexOf(content);
if (NS_WARN_IF(startNodeOffset == -1)) {
// The content is being removed from the parent!
return NS_ERROR_FAILURE;
@ -1219,7 +1219,7 @@ ContentEventHandler::SetRawRangeFromFlatTextOffset(
if (NS_WARN_IF(!startNode)) {
return NS_ERROR_FAILURE;
}
startNodeOffset = startNode->IndexOf(content) + 1;
startNodeOffset = startNode->ComputeIndexOf(content) + 1;
if (NS_WARN_IF(startNodeOffset == 0)) {
// The content is being removed from the parent!
return NS_ERROR_FAILURE;
@ -1312,7 +1312,7 @@ ContentEventHandler::SetRawRangeFromFlatTextOffset(
if (NS_WARN_IF(!endNode)) {
return NS_ERROR_FAILURE;
}
int32_t indexInParent = endNode->IndexOf(content);
int32_t indexInParent = endNode->ComputeIndexOf(content);
if (NS_WARN_IF(indexInParent == -1)) {
// The content is being removed from the parent!
return NS_ERROR_FAILURE;
@ -2871,7 +2871,7 @@ ContentEventHandler::GetFlatTextLengthInRange(
// array of children of its parent. So, be careful to handle this case.
if (aIsRemovingNode) {
DebugOnly<nsIContent*> parent = aStartPosition.Container()->GetParent();
MOZ_ASSERT(parent && parent->IndexOf(aStartPosition.Container()) == -1,
MOZ_ASSERT(parent && parent->ComputeIndexOf(aStartPosition.Container()) == -1,
"At removing the node, the node shouldn't be in the array of children "
"of its parent");
MOZ_ASSERT(aStartPosition.Container() == endPosition.Container(),
@ -2912,7 +2912,7 @@ ContentEventHandler::GetFlatTextLengthInRange(
if (NS_WARN_IF(!parentContent)) {
return NS_ERROR_FAILURE;
}
int32_t indexInParent = parentContent->IndexOf(endPosition.Container());
int32_t indexInParent = parentContent->ComputeIndexOf(endPosition.Container());
if (NS_WARN_IF(indexInParent < 0)) {
return NS_ERROR_FAILURE;
}
@ -3158,8 +3158,8 @@ static void AdjustRangeForSelection(nsIContent* aRoot,
}
*aNode = node->GetParent();
MOZ_ASSERT((*aNode)->IndexOf(node) != -1);
*aNodeOffset = (*aNode)->IndexOf(node) + 1;
MOZ_ASSERT((*aNode)->ComputeIndexOf(node) != -1);
*aNodeOffset = (*aNode)->ComputeIndexOf(node) + 1;
}
nsresult

View File

@ -319,7 +319,8 @@ Request::Constructor(const GlobalObject& aGlobal,
nsAutoString requestURL;
nsCString fragment;
if (NS_IsMainThread()) {
nsIDocument* doc = GetEntryDocument();
nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(global));
nsIDocument* doc = inner ? inner->GetExtantDoc() : nullptr;
if (doc) {
GetRequestURLFromDocument(doc, input, requestURL, fragment, aRv);
} else {
@ -368,7 +369,8 @@ Request::Constructor(const GlobalObject& aGlobal,
} else {
nsAutoString referrerURL;
if (NS_IsMainThread()) {
nsIDocument* doc = GetEntryDocument();
nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(global));
nsIDocument* doc = inner ? inner->GetExtantDoc() : nullptr;
nsCOMPtr<nsIURI> uri;
if (doc) {
uri = ParseURLFromDocument(doc, referrer, aRv);

View File

@ -100,7 +100,8 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
if (NS_IsMainThread()) {
nsCOMPtr<nsIURI> baseURI;
nsIDocument* doc = GetEntryDocument();
nsCOMPtr<nsPIDOMWindowInner> inner(do_QueryInterface(aGlobal.GetAsSupports()));
nsIDocument* doc = inner ? inner->GetExtantDoc() : nullptr;
if (doc) {
baseURI = doc->GetBaseURI();
}

View File

@ -140,8 +140,9 @@ HTMLFieldSetElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
}
nsresult
HTMLFieldSetElement::InsertChildAt(nsIContent* aChild, uint32_t aIndex,
bool aNotify)
HTMLFieldSetElement::InsertChildAt_Deprecated(nsIContent* aChild,
uint32_t aIndex,
bool aNotify)
{
bool firstLegendHasChanged = false;
@ -152,14 +153,15 @@ HTMLFieldSetElement::InsertChildAt(nsIContent* aChild, uint32_t aIndex,
} else {
// If mFirstLegend is before aIndex, we do not change it.
// Otherwise, mFirstLegend is now aChild.
if (int32_t(aIndex) <= IndexOf(mFirstLegend)) {
if (int32_t(aIndex) <= ComputeIndexOf(mFirstLegend)) {
mFirstLegend = aChild;
firstLegendHasChanged = true;
}
}
}
nsresult rv = nsGenericHTMLFormElement::InsertChildAt(aChild, aIndex, aNotify);
nsresult rv =
nsGenericHTMLFormElement::InsertChildAt_Deprecated(aChild, aIndex, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (firstLegendHasChanged) {

View File

@ -41,8 +41,8 @@ public:
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;

View File

@ -62,7 +62,7 @@ static bool IsPreviousSibling(nsINode *aSubject, nsINode *aNode)
nsINode *parent = aSubject->GetParentNode();
if (parent && parent == aNode->GetParentNode()) {
return parent->IndexOf(aSubject) < parent->IndexOf(aNode);
return parent->ComputeIndexOf(aSubject) < parent->ComputeIndexOf(aNode);
}
return false;

View File

@ -75,12 +75,13 @@ HTMLOptGroupElement::GetSelect()
}
nsresult
HTMLOptGroupElement::InsertChildAt(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
HTMLOptGroupElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
{
SafeOptionListMutation safeMutation(GetSelect(), this, aKid, aIndex, aNotify);
nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
nsresult rv = nsGenericHTMLElement::InsertChildAt_Deprecated(aKid, aIndex,
aNotify);
if (NS_FAILED(rv)) {
safeMutation.MutationFailed();
}
@ -98,8 +99,8 @@ HTMLOptGroupElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
void
HTMLOptGroupElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr, IndexOf(aKid),
aNotify);
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr,
ComputeIndexOf(aKid), aNotify);
nsGenericHTMLElement::RemoveChildNode(aKid, aNotify);
}

View File

@ -25,8 +25,8 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// nsINode
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;

View File

@ -83,9 +83,9 @@ HTMLPictureElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
}
nsresult
HTMLPictureElement::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify)
HTMLPictureElement::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex, bool aNotify)
{
nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
nsresult rv = nsGenericHTMLElement::InsertChildAt_Deprecated(aKid, aIndex, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(aKid, rv);

View File

@ -25,7 +25,7 @@ public:
bool aPreallocateChildren) const override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
protected:
virtual ~HTMLPictureElement();

View File

@ -204,13 +204,14 @@ HTMLSelectElement::GetAutocompleteInfo(AutocompleteInfo& aInfo)
}
nsresult
HTMLSelectElement::InsertChildAt(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
HTMLSelectElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
{
SafeOptionListMutation safeMutation(this, this, aKid, aIndex, aNotify);
nsresult rv = nsGenericHTMLFormElementWithState::InsertChildAt(aKid, aIndex,
aNotify);
nsresult rv =
nsGenericHTMLFormElementWithState::InsertChildAt_Deprecated(aKid, aIndex,
aNotify);
if (NS_FAILED(rv)) {
safeMutation.MutationFailed();
}
@ -227,7 +228,8 @@ HTMLSelectElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
void
HTMLSelectElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
SafeOptionListMutation safeMutation(this, this, nullptr, IndexOf(aKid), aNotify);
SafeOptionListMutation safeMutation(this, this, nullptr,
ComputeIndexOf(aKid), aNotify);
nsGenericHTMLFormElementWithState::RemoveChildNode(aKid, aNotify);
}
@ -499,7 +501,7 @@ HTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions)
nsCOMPtr<nsIContent> parent = aOptions->GetParent();
if (parent) {
int32_t index = parent->IndexOf(aOptions);
int32_t index = parent->ComputeIndexOf(aOptions);
int32_t count = parent->GetChildCount();
retval = GetFirstChildOptionIndex(parent, index+1, count);

View File

@ -291,8 +291,8 @@ public:
EventChainPostVisitor& aVisitor) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;

View File

@ -43,7 +43,7 @@ CompareTextTracks::TrackChildPosition(TextTrack* aTextTrack) const {
if (!trackElement) {
return -1;
}
return mMediaElement->IndexOf(trackElement);
return mMediaElement->ComputeIndexOf(trackElement);
}
bool
@ -527,7 +527,7 @@ private:
if (aEvent->mTrack) {
HTMLTrackElement* trackElement = aEvent->mTrack->GetTrackElement();
if (trackElement) {
return mMediaElement->IndexOf(trackElement);
return mMediaElement->ComputeIndexOf(trackElement);
}
}
return -1;

View File

@ -559,7 +559,7 @@ nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm)
// anonymous. Check for this the hard way.
for (nsIContent* child = this; child != content;
child = child->GetParent()) {
NS_ASSERTION(child->GetParent()->IndexOf(child) != -1,
NS_ASSERTION(child->GetParent()->ComputeIndexOf(child) != -1,
"Walked too far?");
}
}

View File

@ -397,7 +397,7 @@ SinkContext::Node::Add(nsIContent *child)
if (mInsertionPoint != -1) {
NS_ASSERTION(mNumFlushed == mContent->GetChildCount(),
"Inserting multiple children without flushing.");
mContent->InsertChildAt(child, mInsertionPoint++, false);
mContent->InsertChildAt_Deprecated(child, mInsertionPoint++, false);
} else {
mContent->AppendChildTo(child, false);
}
@ -983,7 +983,7 @@ HTMLContentSink::NotifyRootInsertion()
// document; in those cases we just want to put all the attrs on one
// tag.
mNotifiedRootInsertion = true;
int32_t index = mDocument->IndexOf(mRoot);
int32_t index = mDocument->ComputeIndexOf(mRoot);
NS_ASSERTION(index != -1, "mRoot not child of document?");
NotifyInsert(nullptr, mRoot, index);

View File

@ -84,3 +84,5 @@ BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a dis
# LOCALIZATION NOTE: Do not translate "data: URI".
BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
BlockSubresourceRedirectToData=Redirecting to insecure data: URI not allowed (Blocked loading of: “%1$S”)

View File

@ -3163,11 +3163,15 @@ ScriptLoader::ParsingComplete(bool aTerminated)
}
void
ScriptLoader::PreloadURI(nsIURI* aURI, const nsAString& aCharset,
ScriptLoader::PreloadURI(nsIURI* aURI,
const nsAString& aCharset,
const nsAString& aType,
const nsAString& aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead, bool aAsync, bool aDefer,
bool aScriptFromHead,
bool aAsync,
bool aDefer,
bool aNoModule,
const mozilla::net::ReferrerPolicy aReferrerPolicy)
{
NS_ENSURE_TRUE_VOID(mDocument);
@ -3176,9 +3180,16 @@ ScriptLoader::PreloadURI(nsIURI* aURI, const nsAString& aCharset,
return;
}
// TODO: Preload module scripts.
if (mDocument->ModuleScriptsEnabled() && aType.LowerCaseEqualsASCII("module")) {
return;
if (mDocument->ModuleScriptsEnabled()) {
// Don't load nomodule scripts.
if (aNoModule) {
return;
}
// TODO: Preload module scripts.
if (aType.LowerCaseEqualsASCII("module")) {
return;
}
}
SRIMetadata sriMetadata;

View File

@ -296,11 +296,15 @@ public:
* @param aIntegrity The expect hash url, if avail, of the request
* @param aScriptFromHead Whether or not the script was a child of head
*/
virtual void PreloadURI(nsIURI* aURI, const nsAString& aCharset,
virtual void PreloadURI(nsIURI* aURI,
const nsAString& aCharset,
const nsAString& aType,
const nsAString& aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead, bool aAsync, bool aDefer,
bool aScriptFromHead,
bool aAsync,
bool aDefer,
bool aNoModule,
const mozilla::net::ReferrerPolicy aReferrerPolicy);
/**

View File

@ -606,6 +606,36 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
Unused << NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
NS_ENSURE_STATE(oldPrincipal && newURI);
// Do not allow insecure redirects to data: URIs
if (loadInfo && loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SCRIPT) {
bool isDataURI = (NS_SUCCEEDED(newURI->SchemeIs("data", &isDataURI)) && isDataURI);
if (isDataURI) {
nsAutoCString dataSpec;
newURI->GetSpec(dataSpec);
if (dataSpec.Length() > 50) {
dataSpec.Truncate(50);
dataSpec.AppendLiteral("...");
}
nsCOMPtr<nsIDocument> doc;
nsINode* node = loadInfo->LoadingNode();
if (node) {
doc = node->OwnerDoc();
}
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
const char16_t* params[] = { specUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
doc,
nsContentUtils::eSECURITY_PROPERTIES,
"BlockSubresourceRedirectToData",
params, ArrayLength(params));
// cancel the old channel and return an error
aOldChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
return NS_ERROR_CONTENT_BLOCKED;
}
}
const uint32_t flags =
nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
nsIScriptSecurityManager::DISALLOW_SCRIPT;

View File

@ -0,0 +1,25 @@
"use strict";
let SCRIPT_DATA = "alert('this alert should be blocked');";
let WORKER_DATA = "onmessage = function(event) { postMessage('worker-loaded'); }";
function handleRequest(request, response)
{
const query = request.queryString;
response.setHeader("Cache-Control", "no-cache", false);
response.setStatusLine("1.1", 302, "Found");
if (query === "script" || query === "modulescript") {
response.setHeader("Location", "data:text/javascript," + escape(SCRIPT_DATA), false);
return;
}
if (query === "worker") {
response.setHeader("Location", "data:text/javascript," + escape(WORKER_DATA), false);
return;
}
// we should never get here; just in case return something unexpected
response.write("do'h");
}

View File

@ -7,6 +7,7 @@ support-files =
file_block_toplevel_data_navigation2.html
file_block_toplevel_data_navigation3.html
file_block_toplevel_data_redirect.sjs
file_block_subresource_redir_to_data.sjs
[test_contentpolicytype_targeted_link_iframe.html]
[test_nosniff.html]
@ -19,3 +20,4 @@ skip-if = toolkit == 'android' # intermittent failure
skip-if = toolkit == 'android'
[test_allow_opening_data_json.html]
skip-if = toolkit == 'android'
[test_block_subresource_redir_to_data.html]

View File

@ -0,0 +1,68 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1428793: Block insecure redirects to data: URIs</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script id="testScriptRedirectToData"></script>
<script id="testModuleScriptRedirectToData" type="module"></script>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
const NUM_TESTS = 3;
var testCounter = 0;
function checkFinish() {
testCounter++;
if (testCounter === NUM_TESTS) {
SimpleTest.finish();
}
}
// --- test regular scripts
let testScriptRedirectToData = document.getElementById("testScriptRedirectToData");
testScriptRedirectToData.onerror = function() {
ok(true, "script that redirects to data: URI should not load");
checkFinish();
}
testScriptRedirectToData.onload = function() {
ok(false, "script that redirects to data: URI should not load");
checkFinish();
}
testScriptRedirectToData.src = "file_block_subresource_redir_to_data.sjs?script";
// --- test workers
let worker = new Worker("file_block_subresource_redir_to_data.sjs?worker");
worker.onerror = function() {
// please note that workers need to be same origin, hence the data: URI
// redirect is blocked by worker code and not the content security manager!
ok(true, "worker script that redirects to data: URI should not load");
checkFinish();
}
worker.onmessage = function() {
ok(false, "worker script that redirects to data: URI should not load");
checkFinish();
};
worker.postMessage("dummy");
// --- test script modules
SpecialPowers.pushPrefEnv({set: [["dom.moduleScripts.enabled", true]]}, function() {
let testModuleScriptRedirectToData = document.getElementById("testModuleScriptRedirectToData");
testModuleScriptRedirectToData.onerror = function() {
ok(true, "module script that redirects to data: URI should not load");
checkFinish();
}
testModuleScriptRedirectToData.onload = function() {
ok(false, "module script that redirects to data: URI should not load");
checkFinish();
}
testModuleScriptRedirectToData.src = "file_block_subresource_redir_to_data.sjs?modulescript";
});
</script>
</body>
</html>

View File

@ -35,19 +35,20 @@ namespace dom {
// nsISupports methods:
nsresult
SVGDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify)
SVGDocument::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
{
if (aKid->IsElement() && !aKid->IsSVGElement()) {
// We can get here when well formed XML with a non-SVG root element is
// served with the SVG MIME type, for example. In that case we need to load
// the non-SVG UA sheets or else we can get bugs like bug 1016145. Note
// that we have to do this _before_ the XMLDocument::InsertChildAt call,
// since that can try to construct frames, and we need to have the sheets
// loaded by then.
// that we have to do this _before_ the
// XMLDocument::InsertChildAt_Deprecated call, since that can try to
// construct frames, and we need to have the sheets loaded by then.
EnsureNonSVGUserAgentStyleSheetsLoaded();
}
return XMLDocument::InsertChildAt(aKid, aIndex, aNotify);
return XMLDocument::InsertChildAt_Deprecated(aKid, aIndex, aNotify);
}
nsresult

View File

@ -29,8 +29,8 @@ public:
mType = eSVG;
}
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;

View File

@ -82,11 +82,12 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSwitchElement)
// nsINode methods
nsresult
SVGSwitchElement::InsertChildAt(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
SVGSwitchElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
bool aNotify)
{
nsresult rv = SVGSwitchElementBase::InsertChildAt(aKid, aIndex, aNotify);
nsresult rv = SVGSwitchElementBase::InsertChildAt_Deprecated(aKid, aIndex,
aNotify);
if (NS_SUCCEEDED(rv)) {
MaybeInvalidate();
}

View File

@ -40,8 +40,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSwitchElement,
SVGSwitchElementBase)
// nsINode
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;

View File

@ -164,7 +164,7 @@ nsAnonymousContentList::IndexOf(nsIContent* aContent)
index += point->InsertedChildrenLength();
}
else {
int32_t insIndex = point->IndexOf(aContent);
int32_t insIndex = point->ComputeIndexOf(aContent);
if (insIndex != -1) {
return index + insIndex;
}

View File

@ -483,7 +483,8 @@ nsXBLPrototypeBinding::LocateInstance(Element* aBoundElement,
if (!copyParent)
return nullptr;
nsIContent* child = copyParent->GetChildAt_Deprecated(templParent->IndexOf(aTemplChild));
nsIContent* child =
copyParent->GetChildAt_Deprecated(templParent->ComputeIndexOf(aTemplChild));
if (child && child->IsElement()) {
return child->AsElement();
}

View File

@ -388,7 +388,7 @@ nsXMLContentSink::OnTransformDone(nsresult aResult,
// documentElement?
nsIContent *rootElement = mDocument->GetRootElement();
if (rootElement) {
NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
NS_ASSERTION(mDocument->ComputeIndexOf(rootElement) != -1,
"rootElement not in doc?");
mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
nsNodeUtils::ContentInserted(mDocument, rootElement);

View File

@ -576,7 +576,7 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
return node < otherNode ? -1 : 1;
}
return parent->IndexOf(node) < parent->IndexOf(otherNode) ?
return parent->ComputeIndexOf(node) < parent->ComputeIndexOf(otherNode) ?
-1 : 1;
}
@ -613,8 +613,8 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
return node < otherNode ? -1 : 1;
}
int32_t index = parent->IndexOf(node);
int32_t otherIndex = parent->IndexOf(otherNode);
int32_t index = parent->ComputeIndexOf(node);
int32_t otherIndex = parent->ComputeIndexOf(otherNode);
NS_ASSERTION(index != otherIndex && index >= 0 && otherIndex >= 0,
"invalid index in compareTreePosition");

View File

@ -2089,7 +2089,7 @@ XULDocument::PrepareToWalk()
uint32_t piInsertionPoint = 0;
if (mState != eState_Master) {
int32_t indexOfRoot = IndexOf(GetRootElement());
int32_t indexOfRoot = ComputeIndexOf(GetRootElement());
NS_ASSERTION(indexOfRoot >= 0,
"No root content when preparing to walk overlay!");
piInsertionPoint = indexOfRoot;
@ -2161,7 +2161,7 @@ XULDocument::CreateAndInsertPI(const nsXULPrototypePI* aProtoPI,
rv = InsertXULOverlayPI(aProtoPI, aParent, aIndex, node);
} else {
// No special processing, just add the PI to the document.
rv = aParent->InsertChildAt(node, aIndex, false);
rv = aParent->InsertChildAt_Deprecated(node, aIndex, false);
}
return rv;
@ -2185,7 +2185,7 @@ XULDocument::InsertXMLStylesheetPI(const nsXULPrototypePI* aProtoPI,
ssle->SetEnableUpdates(false);
ssle->OverrideBaseURI(mCurrentPrototype->GetURI());
rv = aParent->InsertChildAt(aPINode, aIndex, false);
rv = aParent->InsertChildAt_Deprecated(aPINode, aIndex, false);
if (NS_FAILED(rv)) return rv;
ssle->SetEnableUpdates(true);
@ -2217,7 +2217,7 @@ XULDocument::InsertXULOverlayPI(const nsXULPrototypePI* aProtoPI,
{
nsresult rv;
rv = aParent->InsertChildAt(aPINode, aIndex, false);
rv = aParent->InsertChildAt_Deprecated(aPINode, aIndex, false);
if (NS_FAILED(rv)) return rv;
// xul-overlay PI is special only in prolog
@ -3983,11 +3983,11 @@ XULDocument::InsertElement(nsINode* aParent, nsIContent* aChild, bool aNotify)
free(str);
if (content) {
int32_t pos = aParent->IndexOf(content);
int32_t pos = aParent->ComputeIndexOf(content);
if (pos != -1) {
pos = isInsertAfter ? pos + 1 : pos;
nsresult rv = aParent->InsertChildAt(aChild, pos, aNotify);
nsresult rv = aParent->InsertChildAt_Deprecated(aChild, pos, aNotify);
if (NS_FAILED(rv))
return rv;
@ -4009,7 +4009,7 @@ XULDocument::InsertElement(nsINode* aParent, nsIContent* aChild, bool aNotify)
// appending.
if (NS_SUCCEEDED(rv) && pos > 0 &&
uint32_t(pos - 1) <= aParent->GetChildCount()) {
rv = aParent->InsertChildAt(aChild, pos - 1, aNotify);
rv = aParent->InsertChildAt_Deprecated(aChild, pos - 1, aNotify);
if (NS_SUCCEEDED(rv))
wasInserted = true;
// If the insertion fails, then we should still
@ -4029,7 +4029,7 @@ XULDocument::InsertElement(nsINode* aParent, nsIContent* aChild, bool aNotify)
nsresult
XULDocument::RemoveElement(nsINode* aParent, nsINode* aChild)
{
int32_t nodeOffset = aParent->IndexOf(aChild);
int32_t nodeOffset = aParent->ComputeIndexOf(aChild);
aParent->RemoveChildAt_Deprecated(nodeOffset, true);
return NS_OK;

View File

@ -1122,7 +1122,7 @@ EditorBase::BeginningOfDocument()
return NS_ERROR_NULL_POINTER;
}
MOZ_ASSERT(parent->IndexOf(firstNode) == 0,
MOZ_ASSERT(parent->ComputeIndexOf(firstNode) == 0,
"How come the first node isn't the left most child in its parent?");
return selection->Collapse(parent, 0);
}
@ -1618,7 +1618,7 @@ EditorBase::JoinNodes(nsINode& aLeftNode,
// Remember some values; later used for saved selection updating.
// Find the offset between the nodes to be joined.
int32_t offset = parent->IndexOf(&aRightNode);
int32_t offset = parent->ComputeIndexOf(&aRightNode);
// Find the number of children of the lefthand node
uint32_t oldLeftNodeLen = aLeftNode.Length();
@ -1912,7 +1912,7 @@ EditorBase::MoveNode(nsIContent* aNode,
if (NS_WARN_IF(!oldParent)) {
return NS_ERROR_FAILURE;
}
int32_t oldOffset = oldParent->IndexOf(aNode);
int32_t oldOffset = oldParent->ComputeIndexOf(aNode);
if (aOffset == -1) {
// Magic value meaning "move to end of aParent"
@ -3447,23 +3447,23 @@ EditorBase::GetChildOffset(nsINode* aChild,
MOZ_ASSERT(aChild);
MOZ_ASSERT(aParent);
// nsINode::IndexOf() is expensive. So, if we can return index without
// calling it, we should do that.
// nsINode::ComputeIndexOf() is expensive. So, if we can return index
// without calling it, we should do that.
// If there is no previous siblings, it means that it's the first child.
if (aParent->GetFirstChild() == aChild) {
MOZ_ASSERT(aParent->IndexOf(aChild) == 0);
MOZ_ASSERT(aParent->ComputeIndexOf(aChild) == 0);
return 0;
}
// If there is no next siblings, it means that it's the last child.
if (aParent->GetLastChild() == aChild) {
int32_t lastChildIndex = static_cast<int32_t>(aParent->Length() - 1);
MOZ_ASSERT(aParent->IndexOf(aChild) == lastChildIndex);
MOZ_ASSERT(aParent->ComputeIndexOf(aChild) == lastChildIndex);
return lastChildIndex;
}
int32_t index = aParent->IndexOf(aChild);
int32_t index = aParent->ComputeIndexOf(aChild);
MOZ_ASSERT(index != -1);
return index;
}

View File

@ -351,7 +351,7 @@ public:
const_cast<SelfType*>(this)->mOffset = mozilla::Some(0);
} else {
const_cast<SelfType*>(this)->mOffset =
mozilla::Some(mParent->IndexOf(mChild));
mozilla::Some(mParent->ComputeIndexOf(mChild));
}
return mOffset.value();
}

View File

@ -836,7 +836,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
OwningNonNull<Element> root = *htmlEditor->GetRoot();
int32_t rootOffset = root->GetParentNode() ?
root->GetParentNode()->IndexOf(root) : -1;
root->GetParentNode()->ComputeIndexOf(root) : -1;
nsRange* firstRange = selection->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
@ -2361,7 +2361,7 @@ HTMLEditRules::WillDeleteSelection(Selection* aSelection,
bool moveOnly = true;
selNode = visNode->GetParentNode();
selOffset = selNode ? selNode->IndexOf(visNode) : -1;
selOffset = selNode ? selNode->ComputeIndexOf(visNode) : -1;
bool interLineIsRight;
rv = aSelection->GetInterlinePosition(&interLineIsRight);
@ -5450,12 +5450,12 @@ HTMLEditRules::CheckForInvisibleBR(Element& aBlock,
testNode = rightmostNode->GetParentNode();
// Since rightmostNode is always the last child, its index is equal to the
// child count, so instead of IndexOf() we use the faster GetChildCount(),
// and assert the equivalence below.
// child count, so instead of ComputeIndexOf() we use the faster
// GetChildCount(), and assert the equivalence below.
testOffset = testNode->GetChildCount();
// Use offset + 1, so last node is included in our evaluation
MOZ_ASSERT(testNode->IndexOf(rightmostNode) + 1 == testOffset);
MOZ_ASSERT(testNode->ComputeIndexOf(rightmostNode) + 1 == testOffset);
} else if (aOffset) {
testNode = &aBlock;
// We'll check everything to the left of the input position
@ -5559,7 +5559,7 @@ HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
}
selStartNode = wsObj.mStartReasonNode->GetParentNode();
selStartOffset = selStartNode ?
selStartNode->IndexOf(wsObj.mStartReasonNode) : -1;
selStartNode->ComputeIndexOf(wsObj.mStartReasonNode) : -1;
}
}
@ -5579,7 +5579,7 @@ HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
}
selEndNode = wsObj.mEndReasonNode->GetParentNode();
selEndOffset = selEndNode
? selEndNode->IndexOf(wsObj.mEndReasonNode) + 1 : 0;
? selEndNode->ComputeIndexOf(wsObj.mEndReasonNode) + 1 : 0;
} else if (wsType == WSType::thisBlock) {
// We want to keep looking up. But stop if we are crossing table
// element boundaries, or if we hit the root.
@ -5589,7 +5589,7 @@ HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
break;
}
selEndNode = wsObj.mEndReasonNode->GetParentNode();
selEndOffset = 1 + selEndNode->IndexOf(wsObj.mEndReasonNode);
selEndOffset = 1 + selEndNode->ComputeIndexOf(wsObj.mEndReasonNode);
} else {
break;
}
@ -6772,7 +6772,7 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
// Remember where the header is
nsCOMPtr<nsINode> headerParent = aHeader.GetParentNode();
int32_t offset = headerParent ? headerParent->IndexOf(&aHeader) : -1;
int32_t offset = headerParent ? headerParent->ComputeIndexOf(&aHeader) : -1;
// Get ws code to adjust any ws
nsCOMPtr<nsINode> node = &aNode;
@ -7187,7 +7187,7 @@ HTMLEditRules::ReturnInListItem(Selection& aSelection,
RefPtr<nsAtom> nodeAtom = aListItem.NodeInfo()->NameAtom();
if (nodeAtom == nsGkAtoms::dd || nodeAtom == nsGkAtoms::dt) {
nsCOMPtr<nsINode> list = aListItem.GetParentNode();
int32_t itemOffset = list ? list->IndexOf(&aListItem) : -1;
int32_t itemOffset = list ? list->ComputeIndexOf(&aListItem) : -1;
nsAtom* listAtom = nodeAtom == nsGkAtoms::dt ? nsGkAtoms::dd
: nsGkAtoms::dt;
@ -7649,7 +7649,7 @@ HTMLEditRules::JoinNodesSmart(nsIContent& aNodeLeft,
if (NS_WARN_IF(!parent)) {
return EditorDOMPoint();
}
int32_t parOffset = parent->IndexOf(&aNodeLeft);
int32_t parOffset = parent->ComputeIndexOf(&aNodeLeft);
nsCOMPtr<nsINode> rightParent = aNodeRight.GetParentNode();
// If they don't have the same parent, first move the right node to after the

View File

@ -537,7 +537,7 @@ HTMLEditor::BeginningOfDocument()
done = true;
} else if (visType == WSType::br || visType == WSType::special) {
selNode = visNode->GetParentNode();
selOffset = selNode ? selNode->IndexOf(visNode) : -1;
selOffset = selNode ? selNode->ComputeIndexOf(visNode) : -1;
done = true;
} else if (visType == WSType::otherBlock) {
// By definition of WSRunObject, a block element terminates a
@ -554,7 +554,7 @@ HTMLEditor::BeginningOfDocument()
// makes sense if it is visible by itself, like a <hr>. We want to
// place the caret in front of that block.
selNode = visNode->GetParentNode();
selOffset = selNode ? selNode->IndexOf(visNode) : -1;
selOffset = selNode ? selNode->ComputeIndexOf(visNode) : -1;
done = true;
} else {
bool isEmptyBlock;
@ -562,7 +562,7 @@ HTMLEditor::BeginningOfDocument()
isEmptyBlock) {
// Skip the empty block
curNode = visNode->GetParentNode();
curOffset = curNode ? curNode->IndexOf(visNode) : -1;
curOffset = curNode ? curNode->ComputeIndexOf(visNode) : -1;
curOffset++;
} else {
curNode = visNode;
@ -1598,7 +1598,7 @@ HTMLEditor::SelectElement(nsIDOMElement* aElement)
return NS_ERROR_FAILURE;
}
int32_t offsetInParent = parent->IndexOf(element);
int32_t offsetInParent = parent->ComputeIndexOf(element);
// Collapse selection to just before desired element,
nsresult rv = selection->Collapse(parent, offsetInParent);

View File

@ -838,7 +838,7 @@ HTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange)
if (HTMLEditUtils::IsNamedAnchor(parent)) {
startNode = parent->GetParentNode();
startOffset = startNode ? startNode->IndexOf(parent) : -1;
startOffset = startNode ? startNode->ComputeIndexOf(parent) : -1;
}
parent = endNode;
@ -850,7 +850,7 @@ HTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange)
if (HTMLEditUtils::IsNamedAnchor(parent)) {
endNode = parent->GetParentNode();
endOffset = endNode ? endNode->IndexOf(parent) + 1 : 0;
endOffset = endNode ? endNode->ComputeIndexOf(parent) + 1 : 0;
}
nsresult rv = aRange.SetStartAndEnd(startNode, startOffset,
@ -874,7 +874,7 @@ HTMLEditor::PromoteInlineRange(nsRange& aRange)
IsEditable(startNode) && IsAtFrontOfNode(*startNode, startOffset)) {
nsCOMPtr<nsINode> parent = startNode->GetParentNode();
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
startOffset = parent->IndexOf(startNode);
startOffset = parent->ComputeIndexOf(startNode);
startNode = parent;
}
@ -883,7 +883,7 @@ HTMLEditor::PromoteInlineRange(nsRange& aRange)
nsCOMPtr<nsINode> parent = endNode->GetParentNode();
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
// We are AFTER this node
endOffset = 1 + parent->IndexOf(endNode);
endOffset = 1 + parent->ComputeIndexOf(endNode);
endNode = parent;
}
@ -910,7 +910,7 @@ HTMLEditor::IsAtFrontOfNode(nsINode& aNode,
nsCOMPtr<nsIContent> firstNode = GetFirstEditableChild(aNode);
NS_ENSURE_TRUE(firstNode, true);
if (aNode.IndexOf(firstNode) < aOffset) {
if (aNode.ComputeIndexOf(firstNode) < aOffset) {
return false;
}
return true;
@ -930,7 +930,7 @@ HTMLEditor::IsAtEndOfNode(nsINode& aNode,
nsCOMPtr<nsIContent> lastNode = GetLastEditableChild(aNode);
NS_ENSURE_TRUE(lastNode, true);
if (aNode.IndexOf(lastNode) < aOffset) {
if (aNode.ComputeIndexOf(lastNode) < aOffset) {
return true;
}
return false;

View File

@ -672,7 +672,7 @@ HTMLEditor::InsertTableRow(int32_t aNumber,
// The row parent and offset where we will insert new row
nsCOMPtr<nsINode> parentOfRow = parentRow->GetParentNode();
NS_ENSURE_TRUE(parentOfRow, NS_ERROR_NULL_POINTER);
int32_t newRowOffset = parentOfRow->IndexOf(parentRow);
int32_t newRowOffset = parentOfRow->ComputeIndexOf(parentRow);
// Adjust for when adding past the end
if (aAfter && startRowIndex >= rowCount) {

View File

@ -264,7 +264,7 @@ RangeUpdater::SelAdjDeleteNode(nsINode* aNode)
}
nsCOMPtr<nsINode> parent = aNode->GetParentNode();
int32_t offset = parent ? parent->IndexOf(aNode) : -1;
int32_t offset = parent ? parent->ComputeIndexOf(aNode) : -1;
// check for range endpoints that are after aNode and in the same parent
for (size_t i = 0; i < count; i++) {

View File

@ -143,7 +143,7 @@ WSRunObject::PrepareToDeleteNode(HTMLEditor* aHTMLEditor,
nsCOMPtr<nsINode> parent = aContent->GetParentNode();
NS_ENSURE_STATE(parent);
int32_t offset = parent->IndexOf(aContent);
int32_t offset = parent->ComputeIndexOf(aContent);
WSRunObject leftWSObj(aHTMLEditor, parent, offset);
WSRunObject rightWSObj(aHTMLEditor, parent, offset + 1);

View File

@ -250,7 +250,7 @@ ContentToParentOffset(nsIContent* aContent, nsIContent** aParent,
if (!parent)
return;
*aOffset = parent->IndexOf(aContent);
*aOffset = parent->ComputeIndexOf(aContent);
parent.forget(aParent);
}

View File

@ -2,7 +2,7 @@
function toint32() {
// The test case to trigger MToInt32 operation.
// The test case to trigger MToNumberInt32 operation.
var ToInteger = getSelfHostedValue("ToInteger");
// Case1: The input operand is constant int32.

View File

@ -175,7 +175,7 @@ function not() {
}
test(setupNot, not);
// MToInt32
// MToNumberInt32
var str = "can haz cheezburger? okthxbye;";
function setupToInt32() {
f32[0] = 0;

View File

@ -0,0 +1,153 @@
// Test multiple concurrent off-thread parse jobs.
if (helperThreadCount() === 0)
quit();
function assertFails(f) {
let failed = false;
try {
f();
} catch (e) {
failed = true;
}
assertEq(failed, true);
}
function encodeScript(source)
{
let entry = cacheEntry(source);
let global = newGlobal({ cloneSingletons: true });
evaluate(entry, { global: global, saveBytecode: true });
return entry;
}
let a, b, c;
// Calling run functions without arguments assumes a single off-thread job.
// Test run functions fail when no jobs exist.
assertFails(() => runOffThreadScript());
assertFails(() => finishOffThreadModule());
assertFails(() => runOffThreadDecodedScript());
// Test run functions fail when multiple jobs exist and no ID specified.
a = offThreadCompileScript("");
b = offThreadCompileScript("");
assertFails(() => runOffThreadScript());
runOffThreadScript(a);
runOffThreadScript(b);
a = offThreadCompileModule("");
b = offThreadCompileModule("");
assertFails(() => finishOffThreadModule());
finishOffThreadModule(a);
finishOffThreadModule(b);
a = offThreadDecodeScript(encodeScript(""));
b = offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadScript());
runOffThreadDecodedScript(a);
runOffThreadDecodedScript(b);
// Test fun functions succeed when a single job exist and no ID specified.
offThreadCompileScript("42");
assertEq(runOffThreadScript(), 42);
offThreadCompileModule("");
assertEq(typeof finishOffThreadModule(), "object");
offThreadDecodeScript(encodeScript("23"));
assertEq(runOffThreadDecodedScript(), 23);
// Run functions take an ID argument returned from the compile function.
// Test bad ID type and unknown ID.
offThreadCompileScript("");
assertFails(() => runOffThreadScript("foo"));
assertFails(() => runOffThreadScript(42));
runOffThreadScript();
offThreadCompileModule("");
assertFails(() => finishOffThreadModule("foo"));
assertFails(() => finishOffThreadModule(42));
finishOffThreadModule();
offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadDecodedScript("foo"));
assertFails(() => runOffThreadDecodedScript(42));
runOffThreadDecodedScript();
// Test stale ID.
a = offThreadCompileScript("");
runOffThreadScript(a);
assertFails(() => runOffThreadScript(a));
a = offThreadCompileModule("");
finishOffThreadModule(a);
assertFails(() => finishOffThreadModule(a));
a = offThreadDecodeScript(encodeScript(""));
runOffThreadDecodedScript(a);
assertFails(() => runOffThreadDecodedScript(a));
// Test wrong job kind.
a = offThreadCompileScript("");
b = offThreadCompileModule("");
c = offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadScript(b));
assertFails(() => runOffThreadScript(c));
assertFails(() => finishOffThreadModule(a));
assertFails(() => finishOffThreadModule(c));
assertFails(() => runOffThreadDecodedScript(a));
assertFails(() => runOffThreadDecodedScript(b));
runOffThreadScript(a);
finishOffThreadModule(b);
runOffThreadDecodedScript(c);
// Test running multiple jobs.
a = offThreadCompileScript("1");
b = offThreadCompileScript("2");
assertEq(runOffThreadScript(a), 1);
assertEq(runOffThreadScript(b), 2);
a = offThreadCompileModule("");
b = offThreadCompileModule("");
assertEq(typeof finishOffThreadModule(a), "object");
assertEq(typeof finishOffThreadModule(b), "object");
a = offThreadDecodeScript(encodeScript("3"));
b = offThreadDecodeScript(encodeScript("4"));
assertEq(runOffThreadDecodedScript(a), 3);
assertEq(runOffThreadDecodedScript(b), 4);
// Test many jobs.
const count = 100;
let jobs;
jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
jobs[i] = offThreadCompileScript(`${i} * ${i}`);
for (let i = 0; i < jobs.length; i++)
assertEq(runOffThreadScript(jobs[i]), i * i);
jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
jobs[i] = offThreadCompileModule("");
for (let i = 0; i < jobs.length; i++)
assertEq(typeof finishOffThreadModule(jobs[i]), "object");
jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
jobs[i] = offThreadDecodeScript(encodeScript(`${i} * ${i}`));
for (let i = 0; i < jobs.length; i++)
assertEq(runOffThreadDecodedScript(jobs[i]), i * i);

View File

@ -3432,7 +3432,7 @@ IonBuilder::powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* pow
// Cast to the right type
if (outputType == MIRType::Int32 && output->type() != MIRType::Int32) {
MToInt32* toInt = MToInt32::New(alloc(), output);
auto* toInt = MToNumberInt32::New(alloc(), output);
current->add(toInt);
output = toInt;
}
@ -7838,7 +7838,7 @@ IonBuilder::checkTypedObjectIndexInBounds(uint32_t elemSize,
BoundsCheckKind kind)
{
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
// If we know the length statically from the type, just embed it.
@ -8319,7 +8319,7 @@ IonBuilder::getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index
}
// Emit fast path for string[index].
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
@ -8363,7 +8363,7 @@ IonBuilder::getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* in
current->add(length);
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
@ -8448,7 +8448,7 @@ IonBuilder::getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj, MDe
MOZ_ASSERT(!info().argsObjAliasesFormals());
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
@ -8613,7 +8613,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index)
knownType = GetElemKnownType(needsHoleCheck, types);
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
@ -8810,7 +8810,7 @@ IonBuilder::jsop_getelem_typed(MDefinition* obj, MDefinition* index,
bool allowDouble = types->hasType(TypeSet::DoubleType());
// Ensure id is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
@ -9270,7 +9270,7 @@ IonBuilder::initOrSetElemDense(TemporaryTypeSet::DoubleConversion conversion,
*emitted = true;
// Ensure id is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), id);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), id);
current->add(idInt32);
id = idInt32;
@ -9377,7 +9377,7 @@ IonBuilder::jsop_setelem_typed(Scalar::Type arrayType,
spew("Emitting OOB TypedArray SetElem");
// Ensure id is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), id);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), id);
current->add(idInt32);
id = idInt32;
@ -12908,7 +12908,7 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id)
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
// Ensure id is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), id);
MInstruction* idInt32 = MToNumberInt32::New(alloc(), id);
current->add(idInt32);
id = idInt32;

View File

@ -2181,14 +2181,14 @@ LIRGenerator::visitToFloat32(MToFloat32* convert)
}
void
LIRGenerator::visitToInt32(MToInt32* convert)
LIRGenerator::visitToNumberInt32(MToNumberInt32* convert)
{
MDefinition* opd = convert->input();
switch (opd->type()) {
case MIRType::Value:
{
LValueToInt32* lir =
auto* lir =
new(alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(), LValueToInt32::NORMAL);
assignSnapshot(lir, Bailout_NonPrimitiveInput);
define(lir, convert);

View File

@ -170,7 +170,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitOsrArgumentsObject(MOsrArgumentsObject* object) override;
void visitToDouble(MToDouble* convert) override;
void visitToFloat32(MToFloat32* convert) override;
void visitToInt32(MToInt32* convert) override;
void visitToNumberInt32(MToNumberInt32* convert) override;
void visitTruncateToInt32(MTruncateToInt32* truncate) override;
void visitWasmTruncateToInt32(MWasmTruncateToInt32* truncate) override;
void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) override;

View File

@ -1862,7 +1862,7 @@ IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo)
callInfo.setImplicitlyUsedUnchecked();
MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
MInstruction* index = MToNumberInt32::New(alloc(), callInfo.getArg(0));
current->add(index);
MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
@ -1972,7 +1972,7 @@ IonBuilder::inlineStrCharAt(CallInfo& callInfo)
callInfo.setImplicitlyUsedUnchecked();
MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
MInstruction* index = MToNumberInt32::New(alloc(), callInfo.getArg(0));
current->add(index);
MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
@ -3142,7 +3142,7 @@ IonBuilder::inlineToInteger(CallInfo& callInfo)
callInfo.setImplicitlyUsedUnchecked();
MToInt32* toInt32 = MToInt32::New(alloc(), callInfo.getArg(0));
auto* toInt32 = MToNumberInt32::New(alloc(), callInfo.getArg(0));
current->add(toInt32);
current->push(toInt32);
return InliningStatus_Inlined;
@ -4261,7 +4261,7 @@ IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, M
if (!ElementAccessIsTypedArray(constraints(), array, *index, arrayType))
return false;
MInstruction* indexAsInt32 = MToInt32::New(alloc(), *index);
MInstruction* indexAsInt32 = MToNumberInt32::New(alloc(), *index);
current->add(indexAsInt32);
*index = indexAsInt32;

View File

@ -4312,7 +4312,7 @@ MResumePoint::isRecoverableOperand(MUse* u) const
}
MDefinition*
MToInt32::foldsTo(TempAllocator& alloc)
MToNumberInt32::foldsTo(TempAllocator& alloc)
{
MDefinition* input = getOperand(0);
@ -4356,7 +4356,7 @@ MToInt32::foldsTo(TempAllocator& alloc)
}
void
MToInt32::analyzeEdgeCasesBackward()
MToNumberInt32::analyzeEdgeCasesBackward()
{
if (!NeedNegativeZeroCheck(this))
setCanBeNegativeZero(false);
@ -5505,11 +5505,11 @@ DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2)
if (ins1 == ins2)
return false;
// Drop the MToInt32 added by the TypePolicy for double and float values.
if (ins1->isToInt32())
return DefinitelyDifferentValue(ins1->toToInt32()->input(), ins2);
if (ins2->isToInt32())
return DefinitelyDifferentValue(ins2->toToInt32()->input(), ins1);
// Drop the MToNumberInt32 added by the TypePolicy for double and float values.
if (ins1->isToNumberInt32())
return DefinitelyDifferentValue(ins1->toToNumberInt32()->input(), ins2);
if (ins2->isToNumberInt32())
return DefinitelyDifferentValue(ins2->toToNumberInt32()->input(), ins1);
// Ignore the bounds check, which in most cases will contain the same info.
if (ins1->isBoundsCheck())

View File

@ -3415,7 +3415,7 @@ class MNewArrayCopyOnWrite
class MNewArrayDynamicLength
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
CompilerObject templateObject_;
gc::InitialHeap initialHeap_;
@ -3494,7 +3494,7 @@ class MNewTypedArray
class MNewTypedArrayDynamicLength
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
CompilerObject templateObject_;
gc::InitialHeap initialHeap_;
@ -3841,7 +3841,7 @@ class MNewDerivedTypedObject
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>,
ObjectPolicy<1>,
IntPolicy<2> >::Data
UnboxedInt32Policy<2> >::Data
{
private:
TypedObjectPrediction prediction_;
@ -4357,7 +4357,7 @@ class MCallDOMNative : public MCall
// fun.apply(self, arguments)
class MApplyArgs
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2> >::Data
{
protected:
// Monomorphic cache of single target from TI, or nullptr.
@ -4367,6 +4367,7 @@ class MApplyArgs
: MTernaryInstruction(classOpcode, fun, argc, self),
target_(target)
{
MOZ_ASSERT(argc->type() == MIRType::Int32);
setResultType(MIRType::Value);
}
@ -5670,18 +5671,21 @@ class MInt64ToFloatingPoint
}
};
// Converts a primitive (either typed or untyped) to an int32. If the input is
// not primitive at runtime, a bailout occurs. If the input cannot be converted
// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
class MToInt32
// Applies ECMA's ToNumber on a primitive (either typed or untyped) and expects
// the result to be precisely representable as an Int32, otherwise bails.
//
// If the input is not primitive at runtime, a bailout occurs. If the input
// cannot be converted to an int32 without loss (i.e. 5.5 or undefined) then a
// bailout occurs.
class MToNumberInt32
: public MUnaryInstruction,
public ToInt32Policy::Data
{
bool canBeNegativeZero_;
MacroAssembler::IntConversionInputKind conversion_;
explicit MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion =
MacroAssembler::IntConversion_Any)
explicit MToNumberInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion
= MacroAssembler::IntConversion_Any)
: MUnaryInstruction(classOpcode, def),
canBeNegativeZero_(true),
conversion_(conversion)
@ -5696,7 +5700,7 @@ class MToInt32
}
public:
INSTRUCTION_HEADER(ToInt32)
INSTRUCTION_HEADER(ToNumberInt32)
TRIVIAL_NEW_WRAPPERS
MDefinition* foldsTo(TempAllocator& alloc) override;
@ -5716,7 +5720,7 @@ class MToInt32
}
bool congruentTo(const MDefinition* ins) const override {
if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
if (!ins->isToNumberInt32() || ins->toToNumberInt32()->conversion() != conversion())
return false;
return congruentIfOperandsEqual(ins);
}
@ -5731,7 +5735,7 @@ class MToInt32
bool isConsistentFloat32Use(MUse* use) const override { return true; }
#endif
ALLOW_CLONE(MToInt32)
ALLOW_CLONE(MToNumberInt32)
};
// Converts a value or typed input to a truncated int32, for use with bitwise
@ -7527,7 +7531,7 @@ class MConcat
class MCharCodeAt
: public MBinaryInstruction,
public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
public MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1> >::Data
{
MCharCodeAt(MDefinition* str, MDefinition* index)
: MBinaryInstruction(classOpcode, str, index)
@ -7561,7 +7565,7 @@ class MCharCodeAt
class MFromCharCode
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
explicit MFromCharCode(MDefinition* code)
: MUnaryInstruction(classOpcode, code)
@ -7591,7 +7595,7 @@ class MFromCharCode
class MFromCodePoint
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
explicit MFromCodePoint(MDefinition* codePoint)
: MUnaryInstruction(classOpcode, codePoint)
@ -8486,7 +8490,7 @@ class MRegExpMatcher
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>,
StringPolicy<1>,
IntPolicy<2> >::Data
UnboxedInt32Policy<2> >::Data
{
private:
@ -8518,7 +8522,7 @@ class MRegExpSearcher
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>,
StringPolicy<1>,
IntPolicy<2> >::Data
UnboxedInt32Policy<2> >::Data
{
private:
@ -8549,7 +8553,7 @@ class MRegExpTester
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>,
StringPolicy<1>,
IntPolicy<2> >::Data
UnboxedInt32Policy<2> >::Data
{
private:
@ -8696,7 +8700,7 @@ class MStringReplace
class MSubstr
: public MTernaryInstruction,
public MixPolicy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
public MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>::Data
{
private:
@ -9013,7 +9017,7 @@ class MConvertElementsToDoubles
// double. Else return the original value.
class MMaybeToDoubleElement
: public MBinaryInstruction,
public IntPolicy<1>::Data
public UnboxedInt32Policy<1>::Data
{
MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
: MBinaryInstruction(classOpcode, elements, value)
@ -9451,7 +9455,7 @@ class MNot
// (unsigned comparisons may be used).
class MBoundsCheck
: public MBinaryInstruction,
public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>::Data
{
// Range over which to perform the bounds check, may be modified by GVN.
int32_t minimum_;
@ -9516,7 +9520,7 @@ class MBoundsCheck
// Bailout if index < minimum.
class MBoundsCheckLower
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
int32_t minimum_;
bool fallible_;
@ -9551,7 +9555,7 @@ class MBoundsCheckLower
class MSpectreMaskIndex
: public MBinaryInstruction,
public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>::Data
{
MSpectreMaskIndex(MDefinition* index, MDefinition* length)
: MBinaryInstruction(classOpcode, index, length)
@ -10179,7 +10183,7 @@ class MArrayPush
// Array.prototype.slice on a dense array.
class MArraySlice
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>::Data
{
CompilerObject templateObj_;
gc::InitialHeap initialHeap_;
@ -12290,7 +12294,7 @@ class MCallSetElement
class MCallInitElementArray
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2> >::Data
{
MCallInitElementArray(MDefinition* obj, MDefinition* index, MDefinition* val)
: MTernaryInstruction(classOpcode, obj, index, val)
@ -12967,7 +12971,7 @@ class MArgumentsLength : public MNullaryInstruction
// This MIR instruction is used to get an argument from the actual arguments.
class MGetFrameArgument
: public MUnaryInstruction,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
bool scriptHasSetArg_;
@ -13069,7 +13073,7 @@ class MRestCommon
class MRest
: public MUnaryInstruction,
public MRestCommon,
public IntPolicy<0>::Data
public UnboxedInt32Policy<0>::Data
{
MRest(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* numActuals,
unsigned numFormals, ArrayObject* templateObject)
@ -13264,7 +13268,7 @@ class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Dat
// index, update the generational store buffer if the value is in the nursery
// and object is in the tenured heap.
class MPostWriteElementBarrier : public MTernaryInstruction
, public MixPolicy<ObjectPolicy<0>, IntPolicy<2>>::Data
, public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>::Data
{
MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, MDefinition* index)
: MTernaryInstruction(classOpcode, obj, value, index)
@ -13885,7 +13889,7 @@ public:
class MCompareExchangeTypedArrayElement
: public MQuaternaryInstruction,
public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
{
Scalar::Type arrayType_;
@ -13920,7 +13924,7 @@ class MCompareExchangeTypedArrayElement
class MAtomicExchangeTypedArrayElement
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, TruncateToInt32Policy<2>>::Data
{
Scalar::Type arrayType_;
@ -13952,7 +13956,7 @@ class MAtomicExchangeTypedArrayElement
class MAtomicTypedArrayElementBinop
: public MTernaryInstruction,
public MixPolicy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
public MixPolicy< ObjectPolicy<0>, UnboxedInt32Policy<1>, TruncateToInt32Policy<2> >::Data
{
private:
AtomicOp op_;
@ -14092,7 +14096,7 @@ class MDebugCheckSelfHosted
class MFinishBoundFunctionInit
: public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2>>::Data
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>::Data
{
MFinishBoundFunctionInit(MDefinition* bound, MDefinition* target, MDefinition* argCount)
: MTernaryInstruction(classOpcode, bound, target, argCount)

View File

@ -126,7 +126,7 @@ namespace jit {
_(AssertRange) \
_(ToDouble) \
_(ToFloat32) \
_(ToInt32) \
_(ToNumberInt32) \
_(TruncateToInt32) \
_(WrapInt64ToInt32) \
_(ExtendInt32ToInt64) \

View File

@ -2292,8 +2292,11 @@ class MacroAssembler : public MacroAssemblerSpecific
}
enum IntConversionBehavior {
// These two try to convert the input to an int32 using ToNumber and
// will fail if the resulting int32 isn't strictly equal to the input.
IntConversion_Normal,
IntConversion_NegativeZeroCheck,
// These two will convert the input to an int32 with loss of precision.
IntConversion_Truncate,
IntConversion_ClampToUint8,
};
@ -2335,9 +2338,8 @@ class MacroAssembler : public MacroAssemblerSpecific
void convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, Register output,
Label* fail, IntConversionBehavior behavior);
//
// Convenience functions for converting values to int32.
//
// This carries over the MToNumberInt32 operation on the ValueOperand
// input; see comment at the top of this class.
void convertValueToInt32(ValueOperand value, MDefinition* input,
FloatRegister temp, Register output, Label* fail,
bool negativeZeroCheck,
@ -2350,9 +2352,8 @@ class MacroAssembler : public MacroAssemblerSpecific
conversion);
}
//
// Convenience functions for truncating values to int32.
//
// This carries over the MTruncateToInt32 operation on the ValueOperand
// input; see the comment at the top of this class.
void truncateValueToInt32(ValueOperand value, MDefinition* input,
Label* handleStringEntry, Label* handleStringRejoin,
Label* truncateDoubleSlow,

View File

@ -599,8 +599,8 @@ Range::Range(const MDefinition* def)
// mimick a possible truncation.
switch (def->type()) {
case MIRType::Int32:
// MToInt32 cannot truncate. So we can safely clamp.
if (def->isToInt32())
// MToNumberInt32 cannot truncate. So we can safely clamp.
if (def->isToNumberInt32())
clampToInt32();
else
wrapAroundToInt32();
@ -1743,7 +1743,7 @@ MTruncateToInt32::computeRange(TempAllocator& alloc)
}
void
MToInt32::computeRange(TempAllocator& alloc)
MToNumberInt32::computeRange(TempAllocator& alloc)
{
// No clamping since this computes the range *before* bailouts.
setRange(new(alloc) Range(getOperand(0)));
@ -2861,7 +2861,7 @@ TruncateTest(TempAllocator& alloc, MTest* test)
if (!alloc.ensureBallast())
return false;
MBasicBlock* block = inner->block();
inner = MToInt32::New(alloc, inner);
inner = MToNumberInt32::New(alloc, inner);
block->insertBefore(block->lastIns(), inner->toInstruction());
}
MOZ_ASSERT(inner->type() == MIRType::Int32);
@ -3049,7 +3049,7 @@ RemoveTruncatesOnOutput(MDefinition* truncated)
for (MUseDefIterator use(truncated); use; use++) {
MDefinition* def = use.def();
if (!def->isTruncateToInt32() || !def->isToInt32())
if (!def->isTruncateToInt32() || !def->isToNumberInt32())
continue;
def->replaceAllUsesWith(truncated);
@ -3074,7 +3074,7 @@ AdjustTruncatedInputs(TempAllocator& alloc, MDefinition* truncated)
} else {
MInstruction* op;
if (kind == MDefinition::TruncateAfterBailouts)
op = MToInt32::New(alloc, truncated->getOperand(i));
op = MToNumberInt32::New(alloc, truncated->getOperand(i));
else
op = MTruncateToInt32::New(alloc, truncated->getOperand(i));
@ -3385,7 +3385,7 @@ MMod::collectRangeInfoPreTrunc()
}
void
MToInt32::collectRangeInfoPreTrunc()
MToNumberInt32::collectRangeInfoPreTrunc()
{
Range inputRange(input());
if (!inputRange.canBeNegativeZero())

View File

@ -865,8 +865,8 @@ IndexOf(MDefinition* ins, int32_t* res)
indexDef = indexDef->toSpectreMaskIndex()->index();
if (indexDef->isBoundsCheck())
indexDef = indexDef->toBoundsCheck()->index();
if (indexDef->isToInt32())
indexDef = indexDef->toToInt32()->getOperand(0);
if (indexDef->isToNumberInt32())
indexDef = indexDef->toToNumberInt32()->getOperand(0);
MConstant* indexDefConst = indexDef->maybeConstantValue();
if (!indexDefConst || indexDefConst->type() != MIRType::Int32)
return false;

View File

@ -86,7 +86,7 @@ ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
else if (ins->type() == MIRType::Float32)
replace = MToFloat32::New(alloc, in);
else
replace = MToInt32::New(alloc, in);
replace = MToNumberInt32::New(alloc, in);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(i, replace);
@ -242,7 +242,7 @@ ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
{
convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly;
}
replace = MToInt32::New(alloc, in, convert);
replace = MToNumberInt32::New(alloc, in, convert);
break;
}
case MIRType::Object:
@ -400,7 +400,7 @@ PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
// Power may be an int32 or a double. Integers receive a faster path.
if (specialization == MIRType::Double)
return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
return IntPolicy<1>::staticAdjustInputs(alloc, ins);
return UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
}
template <unsigned Op>
@ -463,7 +463,7 @@ template bool BooleanPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstru
template <unsigned Op>
bool
IntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
{
MDefinition* in = def->getOperand(Op);
if (in->type() == MIRType::Int32)
@ -476,10 +476,10 @@ IntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
return replace->typePolicy()->adjustInputs(alloc, replace);
}
template bool IntPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool IntPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool IntPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool IntPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
template <unsigned Op>
bool
@ -489,7 +489,7 @@ ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction*
if (in->type() == MIRType::Int32)
return true;
MToInt32* replace = MToInt32::New(alloc, in);
auto* replace = MToNumberInt32::New(alloc, in);
def->block()->insertBefore(def, replace);
def->replaceOperand(Op, replace);
@ -726,11 +726,11 @@ ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
bool
ToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
{
MOZ_ASSERT(ins->isToInt32() || ins->isTruncateToInt32());
MOZ_ASSERT(ins->isToNumberInt32() || ins->isTruncateToInt32());
MacroAssembler::IntConversionInputKind conversion = MacroAssembler::IntConversion_Any;
if (ins->isToInt32())
conversion = ins->toToInt32()->conversion();
if (ins->isToNumberInt32())
conversion = ins->toToNumberInt32()->conversion();
MDefinition* in = ins->getOperand(0);
switch (in->type()) {
@ -857,7 +857,7 @@ SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
if (in->type() == MIRType::Int32)
continue;
MInstruction* replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly);
auto* replace = MToNumberInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(s->numVectors() + i, replace);
if (!replace->typePolicy()->adjustInputs(alloc, replace))
@ -1218,67 +1218,67 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(ToStringPolicy) \
_(TypeBarrierPolicy)
#define TEMPLATE_TYPE_POLICY_LIST(_) \
_(BoxExceptPolicy<0, MIRType::Object>) \
_(BoxPolicy<0>) \
_(ConvertToInt32Policy<0>) \
_(ConvertToStringPolicy<0>) \
_(ConvertToStringPolicy<2>) \
_(DoublePolicy<0>) \
_(FloatingPointPolicy<0>) \
_(IntPolicy<0>) \
_(IntPolicy<1>) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >) \
_(MixPolicy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>) \
_(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, IntPolicy<2>>) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \
_(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
_(MixPolicy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \
_(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, CacheIdPolicy<2>>) \
_(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >) \
_(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >) \
_(MixPolicy<IntPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >) \
_(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
_(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >) \
_(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \
_(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \
_(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >) \
_(MixPolicy<StringPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \
_(NoFloatPolicy<0>) \
_(NoFloatPolicyAfter<0>) \
_(NoFloatPolicyAfter<1>) \
_(NoFloatPolicyAfter<2>) \
_(ObjectPolicy<0>) \
_(ObjectPolicy<1>) \
_(ObjectPolicy<3>) \
_(SimdPolicy<0>) \
_(SimdSameAsReturnedTypePolicy<0>) \
_(SimdScalarPolicy<0>) \
#define TEMPLATE_TYPE_POLICY_LIST(_) \
_(BoxExceptPolicy<0, MIRType::Object>) \
_(BoxPolicy<0>) \
_(ConvertToInt32Policy<0>) \
_(ConvertToStringPolicy<0>) \
_(ConvertToStringPolicy<2>) \
_(DoublePolicy<0>) \
_(FloatingPointPolicy<0>) \
_(UnboxedInt32Policy<0>) \
_(UnboxedInt32Policy<1>) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2> >) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, TruncateToInt32Policy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >) \
_(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
_(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, UnboxedInt32Policy<3>>) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \
_(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
_(MixPolicy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \
_(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, CacheIdPolicy<2>>) \
_(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >) \
_(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >) \
_(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >) \
_(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
_(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1> >) \
_(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >) \
_(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \
_(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \
_(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >) \
_(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \
_(NoFloatPolicy<0>) \
_(NoFloatPolicyAfter<0>) \
_(NoFloatPolicyAfter<1>) \
_(NoFloatPolicyAfter<2>) \
_(ObjectPolicy<0>) \
_(ObjectPolicy<1>) \
_(ObjectPolicy<3>) \
_(SimdPolicy<0>) \
_(SimdSameAsReturnedTypePolicy<0>) \
_(SimdScalarPolicy<0>) \
_(StringPolicy<0>)

View File

@ -182,9 +182,9 @@ class BooleanPolicy final : private TypePolicy
}
};
// Expect an Int for operand Op. If the input is a Value, it is unboxed.
// Expects either an Int32 or a boxed Int32 for operand Op; may unbox if needed.
template <unsigned Op>
class IntPolicy final : private TypePolicy
class UnboxedInt32Policy final : private TypePolicy
{
public:
EMPTY_DATA_;

View File

@ -4375,9 +4375,9 @@ class LValueToInt32 : public LInstructionHelper<1, BOX_PIECES, 2>
const LDefinition* temp() {
return getTemp(1);
}
MToInt32* mirNormal() const {
MToNumberInt32* mirNormal() const {
MOZ_ASSERT(mode_ == NORMAL);
return mir_->toToInt32();
return mir_->toToNumberInt32();
}
MTruncateToInt32* mirTruncate() const {
MOZ_ASSERT(mode_ == TRUNCATE);
@ -4401,8 +4401,8 @@ class LDoubleToInt32 : public LInstructionHelper<1, 1, 0>
setOperand(0, in);
}
MToInt32* mir() const {
return mir_->toToInt32();
MToNumberInt32* mir() const {
return mir_->toToNumberInt32();
}
};
@ -4419,8 +4419,8 @@ class LFloat32ToInt32 : public LInstructionHelper<1, 1, 0>
setOperand(0, in);
}
MToInt32* mir() const {
return mir_->toToInt32();
MToNumberInt32* mir() const {
return mir_->toToNumberInt32();
}
};

View File

@ -230,132 +230,209 @@ InstallCoverageSignalHandlers()
}
#endif
class OffThreadState {
// An off-thread parse or decode job.
class js::shell::OffThreadJob {
enum State {
IDLE, /* ready to work; no token, no source */
COMPILING, /* working; no token, have source */
DONE /* compilation done: have token and source */
RUNNING, // Working; no token.
DONE, // Finished; have token.
CANCELLED // Cancelled due to error.
};
public:
OffThreadState()
: monitor(mutexid::ShellOffThreadState),
state(IDLE),
runtime(nullptr),
token(),
source(nullptr)
{ }
using Source = mozilla::Variant<JS::UniqueTwoByteChars, JS::TranscodeBuffer>;
bool startIfIdle(JSContext* cx, ScriptKind kind, ScopedJSFreePtr<char16_t>& newSource);
bool startIfIdle(JSContext* cx, ScriptKind kind, JS::TranscodeBuffer&& newXdr);
void abandon(JSContext* cx);
OffThreadJob(ShellContext* sc, ScriptKind kind, Source&& source);
~OffThreadJob();
void cancel();
void markDone(void* newToken);
void* waitUntilDone(JSContext* cx);
void* waitUntilDone(JSContext* cx, ScriptKind kind);
char16_t* sourceChars() { return source.as<UniqueTwoByteChars>().get(); }
JS::TranscodeBuffer& xdrBuffer() { return source.as<JS::TranscodeBuffer>(); }
JS::TranscodeBuffer& xdrBuffer() { return xdr; }
public:
const int32_t id;
const ScriptKind kind;
private:
js::Monitor monitor;
ScriptKind scriptKind;
js::Monitor& monitor;
State state;
JSRuntime* runtime;
void* token;
char16_t* source;
JS::TranscodeBuffer xdr;
Source source;
};
static OffThreadState* gOffThreadState;
bool
OffThreadState::startIfIdle(JSContext* cx, ScriptKind kind, ScopedJSFreePtr<char16_t>& newSource)
static OffThreadJob*
NewOffThreadJob(JSContext* cx, ScriptKind kind, OffThreadJob::Source&& source)
{
AutoLockMonitor alm(monitor);
if (state != IDLE)
return false;
ShellContext* sc = GetShellContext(cx);
UniquePtr<OffThreadJob> job(cx->new_<OffThreadJob>(sc, kind, Move(source)));
if (!job)
return nullptr;
MOZ_ASSERT(!token);
if (!sc->offThreadJobs.append(job.get())) {
JS_ReportErrorASCII(cx, "OOM adding off-thread job");
return nullptr;
}
source = newSource.forget();
scriptKind = kind;
runtime = cx->runtime();
state = COMPILING;
return true;
return job.release();
}
bool
OffThreadState::startIfIdle(JSContext* cx, ScriptKind kind, JS::TranscodeBuffer&& newXdr)
static OffThreadJob*
GetSingleOffThreadJob(JSContext* cx, ScriptKind kind)
{
AutoLockMonitor alm(monitor);
if (state != IDLE)
return false;
ShellContext* sc = GetShellContext(cx);
const auto& jobs = sc->offThreadJobs;
if (jobs.empty()) {
JS_ReportErrorASCII(cx, "No off-thread jobs are pending");
return nullptr;
}
MOZ_ASSERT(!token);
if (jobs.length() > 1) {
JS_ReportErrorASCII(cx, "Multiple off-thread jobs are pending: must specify job ID");
return nullptr;
}
xdr = mozilla::Move(newXdr);
OffThreadJob* job = jobs[0];
if (job->kind != kind) {
JS_ReportErrorASCII(cx, "Off-thread job is the wrong kind");
return nullptr;
}
scriptKind = kind;
runtime = cx->runtime();
state = COMPILING;
return true;
return job;
}
static OffThreadJob*
LookupOffThreadJobByID(JSContext* cx, ScriptKind kind, int32_t id)
{
if (id <= 0) {
JS_ReportErrorASCII(cx, "Bad off-thread job ID");
return nullptr;
}
ShellContext* sc = GetShellContext(cx);
const auto& jobs = sc->offThreadJobs;
if (jobs.empty()) {
JS_ReportErrorASCII(cx, "No off-thread jobs are pending");
return nullptr;
}
OffThreadJob* job = nullptr;
for (auto someJob : jobs) {
if (someJob->id == id) {
job = someJob;
break;
}
}
if (!job) {
JS_ReportErrorASCII(cx, "Off-thread job not found");
return nullptr;
}
if (job->kind != kind) {
JS_ReportErrorASCII(cx, "Off-thread job is the wrong kind");
return nullptr;
}
return job;
}
static OffThreadJob*
LookupOffThreadJobForArgs(JSContext* cx, ScriptKind kind, const CallArgs& args, size_t arg)
{
// If the optional ID argument isn't present, get the single pending job.
if (args.length() <= arg)
return GetSingleOffThreadJob(cx, kind);
// Lookup the job using the specified ID.
int32_t id = 0;
RootedValue value(cx, args[arg]);
if (!ToInt32(cx, value, &id))
return nullptr;
return LookupOffThreadJobByID(cx, kind, id);
}
static void
DeleteOffThreadJob(JSContext* cx, OffThreadJob* job)
{
ShellContext* sc = GetShellContext(cx);
for (size_t i = 0; i < sc->offThreadJobs.length(); i++) {
if (sc->offThreadJobs[i] == job) {
sc->offThreadJobs.erase(&sc->offThreadJobs[i]);
js_delete(job);
return;
}
}
MOZ_CRASH("Off-thread job not found");
}
static void
CancelAllOffThreadJobs(JSContext* cx)
{
// Parse jobs may be blocked waiting on GC.
gc::FinishGC(cx);
CancelOffThreadParses(cx->runtime());
ShellContext* sc = GetShellContext(cx);
while (!sc->offThreadJobs.empty())
js_delete(sc->offThreadJobs.popCopy());
}
mozilla::Atomic<int32_t> gOffThreadJobSerial(1);
OffThreadJob::OffThreadJob(ShellContext* sc, ScriptKind kind, Source&& source)
: id(gOffThreadJobSerial++),
kind(kind),
monitor(sc->offThreadMonitor),
state(RUNNING),
token(nullptr),
source(Move(source))
{
MOZ_RELEASE_ASSERT(id > 0, "Off-thread job IDs exhausted");
}
OffThreadJob::~OffThreadJob()
{
MOZ_ASSERT(state != RUNNING);
}
void
OffThreadState::abandon(JSContext* cx)
OffThreadJob::cancel()
{
AutoLockMonitor alm(monitor);
MOZ_ASSERT(state == COMPILING);
MOZ_ASSERT(state == RUNNING);
MOZ_ASSERT(!token);
MOZ_ASSERT(source || !xdr.empty());
if (source)
js_free(source);
source = nullptr;
xdr.clearAndFree();
state = IDLE;
state = CANCELLED;
}
void
OffThreadState::markDone(void* newToken)
OffThreadJob::markDone(void* newToken)
{
AutoLockMonitor alm(monitor);
MOZ_ASSERT(state == COMPILING);
MOZ_ASSERT(state == RUNNING);
MOZ_ASSERT(!token);
MOZ_ASSERT(source || !xdr.empty());
MOZ_ASSERT(newToken);
token = newToken;
state = DONE;
alm.notify();
alm.notifyAll();
}
void*
OffThreadState::waitUntilDone(JSContext* cx, ScriptKind kind)
OffThreadJob::waitUntilDone(JSContext* cx)
{
AutoLockMonitor alm(monitor);
if (state == IDLE || cx->runtime() != runtime || scriptKind != kind)
return nullptr;
MOZ_ASSERT(state != CANCELLED);
if (state == COMPILING) {
while (state != DONE)
alm.wait();
}
MOZ_ASSERT(source || !xdr.empty());
if (source)
js_free(source);
source = nullptr;
xdr.clearAndFree();
while (state != DONE)
alm.wait();
MOZ_ASSERT(token);
void* holdToken = token;
token = nullptr;
state = IDLE;
return holdToken;
return token;
}
struct ShellCompartmentPrivate {
@ -505,9 +582,15 @@ ShellContext::ShellContext(JSContext* cx)
quitting(false),
readLineBufPos(0),
errFilePtr(nullptr),
outFilePtr(nullptr)
outFilePtr(nullptr),
offThreadMonitor(mutexid::ShellOffThreadState)
{}
ShellContext::~ShellContext()
{
MOZ_ASSERT(offThreadJobs.empty());
}
ShellContext*
js::shell::GetShellContext(JSContext* cx)
{
@ -3597,6 +3680,7 @@ WorkerMain(void* arg)
return;
auto guard = mozilla::MakeScopeExit([&] {
CancelAllOffThreadJobs(cx);
JS_DestroyContext(cx);
js_delete(sc);
if (input->siblingContext) {
@ -4564,7 +4648,8 @@ SyntaxParse(JSContext* cx, unsigned argc, Value* vp)
static void
OffThreadCompileScriptCallback(void* token, void* callbackData)
{
gOffThreadState->markDone(token);
auto job = static_cast<OffThreadJob*>(callbackData);
job->markDone(token);
}
static bool
@ -4619,21 +4704,19 @@ OffThreadCompileScript(JSContext* cx, unsigned argc, Value* vp)
return false;
size_t length = scriptContents->length();
const char16_t* chars = stableChars.twoByteRange().begin().get();
const char16_t* chars = stableChars.twoByteChars();
// Make sure we own the string's chars, so that they are not freed before
// the compilation is finished.
ScopedJSFreePtr<char16_t> ownedChars;
UniqueTwoByteChars ownedChars;
if (stableChars.maybeGiveOwnershipToCaller()) {
ownedChars = const_cast<char16_t*>(chars);
ownedChars.reset(const_cast<char16_t*>(chars));
} else {
char16_t* copy = cx->pod_malloc<char16_t>(length);
if (!copy)
ownedChars.reset(cx->pod_malloc<char16_t>(length));
if (!ownedChars)
return false;
mozilla::PodCopy(copy, chars, length);
ownedChars = copy;
chars = copy;
mozilla::PodCopy(ownedChars.get(), chars, length);
}
if (!JS::CanCompileOffThread(cx, options, length)) {
@ -4641,20 +4724,20 @@ OffThreadCompileScript(JSContext* cx, unsigned argc, Value* vp)
return false;
}
if (!gOffThreadState->startIfIdle(cx, ScriptKind::Script, ownedChars)) {
JS_ReportErrorASCII(cx, "called offThreadCompileScript without calling runOffThreadScript"
" to receive prior off-thread compilation");
OffThreadJob* job = NewOffThreadJob(cx, ScriptKind::Script,
OffThreadJob::Source(Move(ownedChars)));
if (!job)
return false;
}
if (!JS::CompileOffThread(cx, options, chars, length,
OffThreadCompileScriptCallback, nullptr))
if (!JS::CompileOffThread(cx, options, job->sourceChars(), length,
OffThreadCompileScriptCallback, job))
{
gOffThreadState->abandon(cx);
job->cancel();
DeleteOffThreadJob(cx, job);
return false;
}
args.rval().setUndefined();
args.rval().setInt32(job->id);
return true;
}
@ -4666,11 +4749,14 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp)
if (OffThreadParsingMustWaitForGC(cx->runtime()))
gc::FinishGC(cx);
void* token = gOffThreadState->waitUntilDone(cx, ScriptKind::Script);
if (!token) {
JS_ReportErrorASCII(cx, "called runOffThreadScript when no compilation is pending");
OffThreadJob* job = LookupOffThreadJobForArgs(cx, ScriptKind::Script, args, 0);
if (!job)
return false;
}
void* token = job->waitUntilDone(cx);
MOZ_ASSERT(token);
DeleteOffThreadJob(cx, job);
RootedScript script(cx, JS::FinishOffThreadScript(cx, token));
if (!script)
@ -4704,21 +4790,19 @@ OffThreadCompileModule(JSContext* cx, unsigned argc, Value* vp)
return false;
size_t length = scriptContents->length();
const char16_t* chars = stableChars.twoByteRange().begin().get();
const char16_t* chars = stableChars.twoByteChars();
// Make sure we own the string's chars, so that they are not freed before
// the compilation is finished.
ScopedJSFreePtr<char16_t> ownedChars;
UniqueTwoByteChars ownedChars;
if (stableChars.maybeGiveOwnershipToCaller()) {
ownedChars = const_cast<char16_t*>(chars);
ownedChars.reset(const_cast<char16_t*>(chars));
} else {
char16_t* copy = cx->pod_malloc<char16_t>(length);
if (!copy)
ownedChars.reset(cx->pod_malloc<char16_t>(length));
if (!ownedChars)
return false;
mozilla::PodCopy(copy, chars, length);
ownedChars = copy;
chars = copy;
mozilla::PodCopy(ownedChars.get(), chars, length);
}
if (!JS::CanCompileOffThread(cx, options, length)) {
@ -4726,20 +4810,20 @@ OffThreadCompileModule(JSContext* cx, unsigned argc, Value* vp)
return false;
}
if (!gOffThreadState->startIfIdle(cx, ScriptKind::Module, ownedChars)) {
JS_ReportErrorASCII(cx, "called offThreadCompileModule without receiving prior off-thread "
"compilation");
OffThreadJob* job = NewOffThreadJob(cx, ScriptKind::Module,
OffThreadJob::Source(Move(ownedChars)));
if (!job)
return false;
}
if (!JS::CompileOffThreadModule(cx, options, chars, length,
OffThreadCompileScriptCallback, nullptr))
if (!JS::CompileOffThreadModule(cx, options, job->sourceChars(), length,
OffThreadCompileScriptCallback, job))
{
gOffThreadState->abandon(cx);
job->cancel();
DeleteOffThreadJob(cx, job);
return false;
}
args.rval().setUndefined();
args.rval().setInt32(job->id);
return true;
}
@ -4751,11 +4835,14 @@ FinishOffThreadModule(JSContext* cx, unsigned argc, Value* vp)
if (OffThreadParsingMustWaitForGC(cx->runtime()))
gc::FinishGC(cx);
void* token = gOffThreadState->waitUntilDone(cx, ScriptKind::Module);
if (!token) {
JS_ReportErrorASCII(cx, "called finishOffThreadModule when no compilation is pending");
OffThreadJob* job = LookupOffThreadJobForArgs(cx, ScriptKind::Module, args, 0);
if (!job)
return false;
}
void* token = job->waitUntilDone(cx);
MOZ_ASSERT(token);
DeleteOffThreadJob(cx, job);
RootedObject module(cx, JS::FinishOffThreadModule(cx, token));
if (!module)
@ -4828,20 +4915,20 @@ OffThreadDecodeScript(JSContext* cx, unsigned argc, Value* vp)
return false;
}
if (!gOffThreadState->startIfIdle(cx, ScriptKind::DecodeScript, mozilla::Move(loadBuffer))) {
JS_ReportErrorASCII(cx, "called offThreadDecodeScript without calling "
"runOffThreadDecodedScript to receive prior off-thread compilation");
OffThreadJob* job = NewOffThreadJob(cx, ScriptKind::DecodeScript,
OffThreadJob::Source(Move(loadBuffer)));
if (!job)
return false;
}
if (!JS::DecodeOffThreadScript(cx, options, gOffThreadState->xdrBuffer(), 0,
OffThreadCompileScriptCallback, nullptr))
if (!JS::DecodeOffThreadScript(cx, options, job->xdrBuffer(), 0,
OffThreadCompileScriptCallback, job))
{
gOffThreadState->abandon(cx);
job->cancel();
DeleteOffThreadJob(cx, job);
return false;
}
args.rval().setUndefined();
args.rval().setInt32(job->id);
return true;
}
@ -4853,11 +4940,14 @@ runOffThreadDecodedScript(JSContext* cx, unsigned argc, Value* vp)
if (OffThreadParsingMustWaitForGC(cx->runtime()))
gc::FinishGC(cx);
void* token = gOffThreadState->waitUntilDone(cx, ScriptKind::DecodeScript);
if (!token) {
JS_ReportErrorASCII(cx, "called runOffThreadDecodedScript when no compilation is pending");
OffThreadJob* job = LookupOffThreadJobForArgs(cx, ScriptKind::DecodeScript, args, 0);
if (!job)
return false;
}
void* token = job->waitUntilDone(cx);
MOZ_ASSERT(token);
DeleteOffThreadJob(cx, job);
RootedScript script(cx, JS::FinishOffThreadScriptDecoder(cx, token));
if (!script)
@ -6858,8 +6948,9 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
JS_FN_HELP("offThreadCompileScript", OffThreadCompileScript, 1, 0,
"offThreadCompileScript(code[, options])",
" Compile |code| on a helper thread. To wait for the compilation to finish\n"
" and run the code, call |runOffThreadScript|. If present, |options| may\n"
" Compile |code| on a helper thread, returning a job ID.\n"
" To wait for the compilation to finish and run the code, call\n"
" |runOffThreadScript| passing the job ID. If present, |options| may\n"
" have properties saying how the code should be compiled:\n"
" noScriptRval: use the no-script-rval compiler option (default: false)\n"
" fileName: filename for error messages and debug info\n"
@ -6871,36 +6962,39 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
" any DOM element.\n"
" elementAttributeName: if present and not undefined, the name of\n"
" property of 'element' that holds this code. This is what\n"
" Debugger.Source.prototype.elementAttributeName returns.\n"),
" Debugger.Source.prototype.elementAttributeName returns."),
JS_FN_HELP("runOffThreadScript", runOffThreadScript, 0, 0,
"runOffThreadScript()",
" Wait for off-thread compilation to complete. If an error occurred,\n"
"runOffThreadScript([jobID])",
" Wait for an off-thread compilation job to complete. The job ID can be\n"
" ommitted if there is only one job pending. If an error occurred,\n"
" throw the appropriate exception; otherwise, run the script and return\n"
" its value."),
JS_FN_HELP("offThreadCompileModule", OffThreadCompileModule, 1, 0,
"offThreadCompileModule(code)",
" Compile |code| on a helper thread. To wait for the compilation to finish\n"
" and get the module object, call |finishOffThreadModule|."),
" Compile |code| on a helper thread, returning a job ID. To wait for the\n"
" compilation to finish and and get the module record object call\n"
" |finishOffThreadModule| passing the job ID."),
JS_FN_HELP("finishOffThreadModule", FinishOffThreadModule, 0, 0,
"finishOffThreadModule()",
" Wait for off-thread compilation to complete. If an error occurred,\n"
" throw the appropriate exception; otherwise, return the module object"),
"finishOffThreadModule([jobID])",
" Wait for an off-thread compilation job to complete. The job ID can be\n"
" ommitted if there is only one job pending. If an error occurred,\n"
" throw the appropriate exception; otherwise, return the module record object."),
JS_FN_HELP("offThreadDecodeScript", OffThreadDecodeScript, 1, 0,
"offThreadDecodeScript(cacheEntry[, options])",
" Decode |code| on a helper thread. To wait for the compilation to finish\n"
" and run the code, call |runOffThreadScript|. If present, |options| may\n"
" have properties saying how the code should be compiled.\n"
" (see also offThreadCompileScript)\n"),
" Decode |code| on a helper thread, returning a job ID. To wait for the\n"
" decoding to finish and run the code, call |runOffThreadDecodeScript| passing\n"
" the job ID. If present, |options| may have properties saying how the code\n"
" should be compiled (see also offThreadCompileScript)."),
JS_FN_HELP("runOffThreadDecodedScript", runOffThreadDecodedScript, 0, 0,
"runOffThreadDecodedScript()",
" Wait for off-thread decoding to complete. If an error occurred,\n"
" throw the appropriate exception; otherwise, run the script and return\n"
" its value."),
"runOffThreadDecodedScript([jobID])",
" Wait for off-thread decoding to complete. The job ID can be ommitted if there\n"
" is only one job pending. If an error occurred, throw the appropriate\n"
" exception; otherwise, run the script and return its value."),
JS_FN_HELP("timeout", Timeout, 1, 0,
"timeout([seconds], [func])",
@ -9121,13 +9215,6 @@ main(int argc, char** argv, char** envp)
});
JS::InitConsumeStreamCallback(cx, ConsumeBufferSource);
gOffThreadState = js_new<OffThreadState>();
if (!gOffThreadState)
return 1;
auto deleteOffThreadState = MakeScopeExit([] {
js_delete(gOffThreadState);
});
JS_SetNativeStackQuota(cx, gMaxStackSize);
JS::dbg::SetDebuggerMallocSizeOf(cx, moz_malloc_size_of);
@ -9180,6 +9267,8 @@ main(int argc, char** argv, char** envp)
DestructSharedArrayBufferMailbox();
CancelAllOffThreadJobs(cx);
JS_DestroyContext(cx);
return result;
}

View File

@ -10,6 +10,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Variant.h"
#include "jsapi.h"
@ -131,10 +132,13 @@ using MarkBitObservers = JS::WeakCache<NonshrinkingGCObjectVector>;
using StackChars = Vector<char16_t, 0, SystemAllocPolicy>;
#endif
class OffThreadJob;
// Per-context shell state.
struct ShellContext
{
explicit ShellContext(JSContext* cx);
~ShellContext();
bool isWorker;
double timeoutInterval;
@ -172,6 +176,11 @@ struct ShellContext
JS::UniqueChars moduleLoadPath;
UniquePtr<MarkBitObservers> markObservers;
// Off-thread parse state.
js::Monitor offThreadMonitor;
Vector<OffThreadJob*, 0, SystemAllocPolicy> offThreadJobs;
};
extern ShellContext*

View File

@ -1192,12 +1192,7 @@ GlobalHelperThreadState::maxParseThreads() const
{
if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_PARSE))
return 1;
// Don't allow simultaneous off thread parses, to reduce contention on the
// atoms table. Note that wasm compilation depends on this to avoid
// stalling the helper thread, as off thread parse tasks can trigger and
// block on other off thread wasm compilation tasks.
return 1;
return cpuCount;
}
size_t

View File

@ -1862,8 +1862,8 @@ nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
return 0;
}
int32_t index1 = parent->IndexOf(content1Ancestor);
int32_t index2 = parent->IndexOf(content2Ancestor);
int32_t index1 = parent->ComputeIndexOf(content1Ancestor);
int32_t index2 = parent->ComputeIndexOf(content2Ancestor);
if (index1 < 0 || index2 < 0) {
// one of them must be anonymous; we can't determine the order
return 0;

View File

@ -222,7 +222,7 @@ nsIFrame::ContentOffsets BRFrame::CalcContentOffsetsFromFramePoint(const nsPoint
ContentOffsets offsets;
offsets.content = mContent->GetParent();
if (offsets.content) {
offsets.offset = offsets.content->IndexOf(mContent);
offsets.offset = offsets.content->ComputeIndexOf(mContent);
offsets.secondaryOffset = offsets.offset;
offsets.associate = CARET_ASSOCIATE_AFTER;
}

View File

@ -2265,7 +2265,7 @@ nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
int32_t offset = 0;
if (newContent) {
// XXXbz there has GOT to be a better way of determining this!
offset = newContent->IndexOf(mContent);
offset = newContent->ComputeIndexOf(mContent);
}
//look up to see what selection(s) are on this frame
@ -4004,7 +4004,7 @@ nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
if (!parentContent) return NS_ERROR_FAILURE;
int32_t offset = parentContent->IndexOf(tableOrCellContent);
int32_t offset = parentContent->ComputeIndexOf(tableOrCellContent);
// Not likely?
if (offset < 0) return NS_ERROR_FAILURE;
@ -4739,7 +4739,7 @@ static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
}
if (type == LayoutFrameType::Br) {
parent = content->GetParent();
int32_t beginOffset = parent->IndexOf(content);
int32_t beginOffset = parent->ComputeIndexOf(content);
return FrameContentRange(parent, beginOffset, beginOffset);
}
// Loop to deal with anonymous content, which has no index; this loop
@ -4747,7 +4747,7 @@ static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
do {
parent = content->GetParent();
if (parent) {
int32_t beginOffset = parent->IndexOf(content);
int32_t beginOffset = parent->ComputeIndexOf(content);
if (beginOffset >= 0)
return FrameContentRange(parent, beginOffset, beginOffset + 1);
content = parent;
@ -7621,7 +7621,7 @@ int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
if (content) {
nsIContent* parentContent = content->GetParent();
if (parentContent) {
result = parentContent->IndexOf(content);
result = parentContent->ComputeIndexOf(content);
}
}
@ -7965,7 +7965,7 @@ nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
{
nsIContent* newContent = mContent->GetParent();
if (newContent){
int32_t newOffset = newContent->IndexOf(mContent);
int32_t newOffset = newContent->ComputeIndexOf(mContent);
// Find the direction of the frame from the EmbeddingLevelProperty,
// which is the resolved bidi level set in
@ -8174,7 +8174,7 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
if (parent)
{
aPos->mResultContent = parent;
aPos->mContentOffset = parent->IndexOf(content);
aPos->mContentOffset = parent->ComputeIndexOf(content);
aPos->mAttach = CARET_ASSOCIATE_BEFORE;
if ((point.x - offset.x+ tempRect.x)>tempRect.width)
{
@ -8325,7 +8325,7 @@ FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
// to avoid crashing here.
NS_ASSERTION(result.mContent, "Unexpected orphan content");
if (result.mContent)
result.mOffset = result.mContent->IndexOf(content) +
result.mOffset = result.mContent->ComputeIndexOf(content) +
(aDirection == eDirPrevious ? 1 : 0);
return result;
}

View File

@ -624,7 +624,7 @@ ParentOffset(nsINode *aNode, int32_t *aChildOffset)
nsIContent* parent = aNode->GetParent();
if (parent)
{
*aChildOffset = parent->IndexOf(aNode);
*aChildOffset = parent->ComputeIndexOf(aNode);
return parent;
}
@ -2791,7 +2791,7 @@ nsFrameSelection::SelectCellElement(nsIContent *aCellElement)
nsIContent *parent = aCellElement->GetParent();
// Get child offset
int32_t offset = parent->IndexOf(aCellElement);
int32_t offset = parent->ComputeIndexOf(aCellElement);
return CreateAndAddRange(parent, offset);
}

View File

@ -1922,7 +1922,7 @@ nsImageFrame::ShouldDisplaySelection()
nsCOMPtr<nsIContent> parentContent = mContent->GetParent();
if (parentContent)
{
int32_t thisOffset = parentContent->IndexOf(mContent);
int32_t thisOffset = parentContent->ComputeIndexOf(mContent);
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(parentContent);
nsCOMPtr<nsIDOMNode> rangeNode;
uint32_t rangeOffset;

View File

@ -7,7 +7,6 @@
XPIDL_SOURCES += [
'nsIPrintProgress.idl',
'nsIPrintProgressParams.idl',
'nsIPrintStatusFeedback.idl',
]
EXPORTS.mozilla.layout += [

View File

@ -1,23 +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 "nsISupports.idl"
interface nsIDocShell;
interface mozIDOMWindowProxy;
/**
* XXX This interface seems to be unimplemented and unused.
*/
[scriptable, uuid(8eb6ffc9-715c-487e-927c-c56139229548)]
interface nsIPrintStatusFeedback : nsISupports {
void showStatusString(in wstring status);
void startMeteors();
void stopMeteors();
void showProgress(in long percent);
[noscript] void setDocShell(in nsIDocShell shell, in mozIDOMWindowProxy window);
void closeWindow();
};

View File

@ -2529,7 +2529,7 @@ GetCorrespondingNodeInDocument(const nsINode* aNode, nsIDocument* aDoc)
nsTArray<int32_t> indexArray;
const nsINode* child = aNode;
while (const nsINode* parent = child->GetParentNode()) {
int32_t index = parent->IndexOf(child);
int32_t index = parent->ComputeIndexOf(child);
MOZ_ASSERT(index >= 0);
indexArray.AppendElement(index);
child = parent;

View File

@ -2683,7 +2683,7 @@ nsTableFrame::HomogenousInsertFrames(ChildListID aListID,
}
nsCOMPtr<nsIContent> container = content->GetParent();
if (MOZ_LIKELY(container)) { // XXX need this null-check, see bug 411823.
int32_t newIndex = container->IndexOf(content);
int32_t newIndex = container->ComputeIndexOf(content);
nsIFrame* kidFrame;
nsTableColGroupFrame* lastColGroup = nullptr;
if (isColGroup) {
@ -2707,7 +2707,7 @@ nsTableFrame::HomogenousInsertFrames(ChildListID aListID,
(content = pseudoFrame->GetContent()))) {
pseudoFrame = pseudoFrame->PrincipalChildList().FirstChild();
}
int32_t index = container->IndexOf(content);
int32_t index = container->ComputeIndexOf(content);
if (index > lastIndex && index < newIndex) {
lastIndex = index;
aPrevFrame = kidFrame;

View File

@ -1156,7 +1156,7 @@ nsListBoxBodyFrame::GetFirstItemBox(int32_t aOffset, bool* aCreated)
// We need to insert rows before the top frame
nsIContent* topContent = mTopFrame->GetContent();
nsIContent* topParent = topContent->GetParent();
int32_t contentIndex = topParent->IndexOf(topContent);
int32_t contentIndex = topParent->ComputeIndexOf(topContent);
contentIndex -= aOffset;
if (contentIndex < 0)
return nullptr;
@ -1217,7 +1217,7 @@ nsListBoxBodyFrame::GetNextItemBox(nsIFrame* aBox, int32_t aOffset,
nsIContent* prevContent = aBox->GetContent();
nsIContent* parentContent = prevContent->GetParent();
int32_t i = parentContent->IndexOf(prevContent);
int32_t i = parentContent->ComputeIndexOf(prevContent);
uint32_t childCount = parentContent->GetChildCount();
if (((uint32_t)i + aOffset + 1) < childCount) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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