Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2014-03-14 23:18:26 -07:00
commit 763daa65ec
344 changed files with 8350 additions and 3836 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Intermittent Android startup crashes leading to test bustage.
Bug 983185 requires a clobber. This may not affect all platforms.

View File

@ -397,6 +397,7 @@ XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx,
if (!treeColumns)
return;
bool nameChanged = false;
for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) {
nsCOMPtr<nsITreeColumn> column;
treeColumns->GetColumnAt(colIdx, getter_AddRefs(column));
@ -405,18 +406,14 @@ XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx,
if (cellAccessible) {
nsRefPtr<XULTreeGridCellAccessible> cellAcc = do_QueryObject(cellAccessible);
cellAcc->CellInvalidated();
nameChanged |= cellAcc->CellInvalidated();
}
}
}
nsAutoString name;
Name(name);
if (name != mCachedName) {
if (nameChanged)
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
mCachedName = name;
}
}
////////////////////////////////////////////////////////////////////////////////
@ -763,7 +760,7 @@ XULTreeGridCellAccessible::RelationByType(RelationType aType)
////////////////////////////////////////////////////////////////////////////////
// XULTreeGridCellAccessible: public implementation
void
bool
XULTreeGridCellAccessible::CellInvalidated()
{
@ -780,16 +777,20 @@ XULTreeGridCellAccessible::CellInvalidated()
nsEventShell::FireEvent(accEvent);
mCachedTextEquiv = textEquiv;
return true;
}
return;
return false;
}
mTreeView->GetCellText(mRow, mColumn, textEquiv);
if (mCachedTextEquiv != textEquiv) {
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
mCachedTextEquiv = textEquiv;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -106,7 +106,6 @@ protected:
// XULTreeItemAccessibleBase
mutable AccessibleHashtable mAccessibleCache;
nsString mCachedName;
};
@ -180,8 +179,9 @@ public:
/**
* Fire name or state change event if the accessible text or value has been
* changed.
* @return true if name has changed
*/
void CellInvalidated();
bool CellInvalidated();
protected:
// Accessible

View File

@ -879,9 +879,9 @@ pref("osfile.reset_worker_delay", 5000);
pref("apz.asyncscroll.throttle", 40);
pref("apz.pan_repaint_interval", 16);
// Maximum fling velocity in px/ms. Slower devices may need to reduce this
// Maximum fling velocity in inches/ms. Slower devices may need to reduce this
// to avoid checkerboarding. Note, float value must be set as a string.
pref("apz.max_velocity_pixels_per_ms", "6.0");
pref("apz.max_velocity_inches_per_ms", "0.0375");
// Tweak default displayport values to reduce the risk of running out of
// memory when zooming in

View File

@ -297,6 +297,7 @@
@BINPATH@/components/storage.xpt
@BINPATH@/components/telemetry.xpt
@BINPATH@/components/toolkit_finalizationwitness.xpt
@BINPATH@/components/toolkit_osfile.xpt
@BINPATH@/components/toolkitprofile.xpt
#ifdef MOZ_ENABLE_XREMOTE
@BINPATH@/components/toolkitremote.xpt

View File

@ -11,6 +11,8 @@ Cu.import("resource://gre/modules/NotificationDB.jsm");
Cu.import("resource:///modules/RecentWindow.jsm");
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
@ -4840,13 +4842,11 @@ function getBrowserSelection(aCharLen) {
// selections of more than 150 characters aren't useful
const kMaxSelectionLen = 150;
const charLen = Math.min(aCharLen || kMaxSelectionLen, kMaxSelectionLen);
let commandDispatcher = document.commandDispatcher;
var focusedWindow = commandDispatcher.focusedWindow;
let [element, focusedWindow] = BrowserUtils.getFocusSync(document);
var selection = focusedWindow.getSelection().toString();
// try getting a selected text in text input.
if (!selection) {
let element = commandDispatcher.focusedElement;
var isOnTextInput = function isOnTextInput(elem) {
// we avoid to return a value if a selection is in password field.
// ref. bug 565717

View File

@ -8,6 +8,7 @@ let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContentLinkHandler",
"resource:///modules/ContentLinkHandler.jsm");

View File

@ -80,8 +80,7 @@ nsContextMenu.prototype = {
// isn't actually linked.
if (this.isTextSelected && !this.onLink) {
// Ok, we have some text, let's figure out if it looks like a URL.
let selection = document.commandDispatcher.focusedWindow
.getSelection();
let selection = this.focusedWindow.getSelection();
let linkText = selection.toString().trim();
let uri;
if (/^(?:https?|ftp):/i.test(linkText)) {
@ -549,6 +548,10 @@ nsContextMenu.prototype = {
// Remember the node that was clicked.
this.target = aNode;
let [elt, win] = BrowserUtils.getFocusSync(document);
this.focusedWindow = win;
this.focusedElement = elt;
// If this is a remote context menu event, use the information from
// gContextMenuContentData instead.
if (this.isRemote) {
@ -1252,7 +1255,7 @@ nsContextMenu.prototype = {
var linkText;
// If selected text is found to match valid URL pattern.
if (this.onPlainTextLink)
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
linkText = this.focusedWindow.getSelection().toString().trim();
else
linkText = this.linkText();
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
@ -1449,7 +1452,7 @@ nsContextMenu.prototype = {
// Returns true if anything is selected.
isContentSelection: function() {
return !document.commandDispatcher.focusedWindow.getSelection().isCollapsed;
return !this.focusedWindow.getSelection().isCollapsed;
},
toString: function () {
@ -1551,7 +1554,7 @@ nsContextMenu.prototype = {
var linkText;
// If selected text is found to match valid URL pattern.
if (this.onPlainTextLink)
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
linkText = this.focusedWindow.getSelection().toString().trim();
else
linkText = this.linkText();
window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId, this.linkURL,

View File

@ -4,39 +4,43 @@
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
let tempScope = {};
Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
let NetUtil = tempScope.NetUtil;
// Trigger a save of a link in public mode, then trigger an identical save
// in private mode and ensure that the second request is differentiated from
// the first by checking that cookies set by the first response are not sent
// during the second request.
function triggerSave(aWindow, aCallback) {
info("started triggerSave");
var fileName;
let testBrowser = aWindow.gBrowser.selectedBrowser;
// This page sets a cookie if and only if a cookie does not exist yet
let testURI = "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html";
testBrowser.loadURI(testURI);
testBrowser.addEventListener("pageshow", function pageShown(event) {
info("got pageshow with " + event.target.location);
if (event.target.location != testURI) {
info("try again!");
testBrowser.loadURI(testURI);
return;
}
info("found our page!");
testBrowser.removeEventListener("pageshow", pageShown, false);
executeSoon(function () {
aWindow.document.addEventListener("popupshown", function(e) contextMenuOpened(aWindow, e), false);
waitForFocus(function () {
info("register to handle popupshown");
aWindow.document.addEventListener("popupshown", contextMenuOpened, false);
var link = testBrowser.contentDocument.getElementById("fff");
info("link: " + link);
EventUtils.synthesizeMouseAtCenter(link,
{ type: "contextmenu", button: 2 },
testBrowser.contentWindow);
});
info("right clicked!");
}, testBrowser.contentWindow);
}, false);
function contextMenuOpened(aWindow, event) {
event.currentTarget.removeEventListener("popupshown", contextMenuOpened, false);
function contextMenuOpened(event) {
info("contextMenuOpened");
aWindow.document.removeEventListener("popupshown", contextMenuOpened);
// Create the folder the link will be saved into.
var destDir = createTemporarySaveDirectory();
@ -44,50 +48,62 @@ function triggerSave(aWindow, aCallback) {
MockFilePicker.displayDirectory = destDir;
MockFilePicker.showCallback = function(fp) {
info("showCallback");
fileName = fp.defaultString;
info("fileName: " + fileName);
destFile.append (fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
info("done showCallback");
};
mockTransferCallback = function(downloadSuccess) {
info("mockTransferCallback");
onTransferComplete(aWindow, downloadSuccess, destDir);
destDir.remove(true);
ok(!destDir.exists(), "Destination dir should be removed");
ok(!destFile.exists(), "Destination file should be removed");
mockTransferCallback = function(){};
mockTransferCallback = null;
info("done mockTransferCallback");
}
// Select "Save Link As" option from context menu
var saveLinkCommand = aWindow.document.getElementById("context-savelink");
info("saveLinkCommand: " + saveLinkCommand);
saveLinkCommand.doCommand();
event.target.hidePopup();
info("popup hidden");
}
function onTransferComplete(aWindow, downloadSuccess, destDir) {
ok(downloadSuccess, "Link should have been downloaded successfully");
aWindow.gBrowser.removeCurrentTab();
aWindow.close();
executeSoon(function() aCallback());
}
}
function test() {
info("Start the test");
waitForExplicitFinish();
var windowsToClose = [];
var gNumSet = 0;
function testOnWindow(options, callback) {
info("testOnWindow(" + options + ")");
var win = OpenBrowserWindow(options);
info("got " + win);
whenDelayedStartupFinished(win, () => callback(win));
}
function whenDelayedStartupFinished(aWindow, aCallback) {
info("whenDelayedStartupFinished");
Services.obs.addObserver(function observer(aSubject, aTopic) {
info("whenDelayedStartupFinished, got topic: " + aTopic + ", got subject: " + aSubject + ", waiting for " + aWindow);
if (aWindow == aSubject) {
Services.obs.removeObserver(observer, aTopic);
executeSoon(aCallback);
info("whenDelayedStartupFinished found our window");
}
}, "browser-delayed-startup-finished", false);
}
@ -95,16 +111,16 @@ function test() {
mockTransferRegisterer.register();
registerCleanupFunction(function () {
info("Running the cleanup code");
mockTransferRegisterer.unregister();
MockFilePicker.cleanup();
windowsToClose.forEach(function(win) {
win.close();
});
Services.obs.removeObserver(observer, "http-on-modify-request");
Services.obs.removeObserver(observer, "http-on-examine-response");
info("Finished running the cleanup code");
});
function observer(subject, topic, state) {
info("observer called with " + topic);
if (topic == "http-on-modify-request") {
onModifyRequest(subject);
} else if (topic == "http-on-examine-response") {
@ -114,7 +130,9 @@ function test() {
function onExamineResponse(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
info("onExamineResponse with " + channel.URI.spec);
if (channel.URI.spec != "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs") {
info("returning");
return;
}
try {
@ -123,21 +141,32 @@ function test() {
// header with foopy=1 when there are no cookies for that domain.
is(cookies, "foopy=1", "Cookie should be foopy=1");
gNumSet += 1;
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
info("gNumSet = " + gNumSet);
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) {
info("onExamineResponse caught NOTAVAIL" + ex);
} catch (ex) {
info("ionExamineResponse caught " + ex);
}
}
function onModifyRequest(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
info("onModifyRequest with " + channel.URI.spec);
if (channel.URI.spec != "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs") {
return;
}
try {
let cookies = channel.getRequestHeader("cookie");
info("cookies: " + cookies);
// From browser/base/content/test/general/bug792715.sjs, we should never send a
// cookie because we are making only 2 requests: one in public mode, and
// one in private mode.
throw "We should never send a cookie in this test";
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) {
info("onModifyRequest caught NOTAVAIL" + ex);
} catch (ex) {
info("ionModifyRequest caught " + ex);
}
}
Services.obs.addObserver(observer, "http-on-modify-request", false);
@ -169,7 +198,10 @@ function createTemporarySaveDirectory() {
.getService(Ci.nsIProperties)
.get("TmpD", Ci.nsIFile);
saveDir.append("testsavedir");
if (!saveDir.exists())
if (!saveDir.exists()) {
info("create testsavedir!");
saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
}
info("return from createTempSaveDir: " + saveDir.path);
return saveDir;
}

View File

@ -460,6 +460,7 @@ const PanelUI = {
* @return the selected locale or "en-US" if none is selected
*/
function getLocale() {
const PREF_SELECTED_LOCALE = "general.useragent.locale";
try {
let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE,
Ci.nsIPrefLocalizedString);

View File

@ -3681,7 +3681,11 @@ OverflowableToolbar.prototype = {
if (!this._enabled)
return;
this._moveItemsBackToTheirOrigin();
if (this._target.scrollLeftMax > 0) {
this.onOverflow();
} else {
this._moveItemsBackToTheirOrigin();
}
},
_disable: function() {

View File

@ -65,6 +65,7 @@ skip-if = os == "linux"
[browser_948985_non_removable_defaultArea.js]
[browser_952963_areaType_getter_no_area.js]
[browser_956602_remove_special_widget.js]
[browser_963639_customizing_attribute_non_customizable_toolbar.js]
[browser_968447_bookmarks_toolbar_items_in_panel.js]
[browser_968565_insert_before_hidden_items.js]
[browser_969427_recreate_destroyed_widget_after_reset.js]

View File

@ -0,0 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const kToolbar = "test-toolbar-963639-non-customizable-customizing-attribute";
add_task(function() {
info("Test for Bug 963639 - CustomizeMode _onToolbarVisibilityChange sets @customizing on non-customizable toolbars");
let toolbar = document.createElement("toolbar");
toolbar.id = kToolbar;
gNavToolbox.appendChild(toolbar);
let testToolbar = document.getElementById(kToolbar)
ok(testToolbar, "Toolbar was created.");
is(gNavToolbox.getElementsByAttribute("id", kToolbar).length, 1,
"Toolbar was added to the navigator toolbox");
toolbar.setAttribute("toolbarname", "NonCustomizableToolbarCustomizingAttribute");
toolbar.setAttribute("collapsed", "true");
yield startCustomizing();
window.setToolbarVisibility(toolbar, "true");
isnot(toolbar.getAttribute("customizing"), "true",
"Toolbar doesn't have the customizing attribute");
yield endCustomizing();
gNavToolbox.removeChild(toolbar);
is(gNavToolbox.getElementsByAttribute("id", kToolbar).length, 0,
"Toolbar was removed from the navigator toolbox");
});

View File

@ -23,7 +23,7 @@ function test() {
Task.spawn(function* () {
try {
yield waitForSourceShown(gPanel, CODE_URL);
yield ensureSourceIs(gPanel, CODE_URL, true);
// Pause and set our breakpoints.
yield doInterrupt();

View File

@ -10,6 +10,9 @@ function test() {
initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
// It seems that this test may be slow on Ubuntu builds running on ec2.
requestLongerTimeout(2);
let { $, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;

View File

@ -310,6 +310,7 @@
@BINPATH@/components/spellchecker.xpt
@BINPATH@/components/storage.xpt
@BINPATH@/components/toolkit_finalizationwitness.xpt
@BINPATH@/components/toolkit_osfile.xpt
@BINPATH@/components/toolkitprofile.xpt
#ifdef MOZ_ENABLE_XREMOTE
@BINPATH@/components/toolkitremote.xpt

View File

@ -68,10 +68,6 @@
<field name="contentWindowId">null</field>
<property name="messageManager"
onget="return this._frameLoader.messageManager;"
readonly="true"/>
<field name="_contentTitle">null</field>
<field name="_ios">

View File

@ -84,6 +84,10 @@ browser.jar:
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
skin/classic/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
skin/classic/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
skin/classic/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
skin/classic/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)

View File

@ -141,6 +141,10 @@ browser.jar:
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl@2x.png (../shared/customizableui/subView-arrow-back-inverted-rtl@2x.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
skin/classic/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
skin/classic/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
skin/classic/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/buttons@2x.png (downloads/buttons@2x.png)

View File

@ -19,6 +19,44 @@
%include ../browser.inc
#PanelUI-popup #PanelUI-contents:empty {
height: 128px;
}
#PanelUI-popup #PanelUI-contents:empty::before {
content: "";
background-image: url(chrome://browser/skin/customizableui/whimsy-bw.png);
display: block;
width: 64px;
height: 64px;
position: absolute;
animation: moveX 3.05s linear 0s infinite alternate,
moveY 3.4s linear 0s infinite alternate;
}
#PanelUI-popup #PanelUI-contents:empty:hover::before {
background-image: url(chrome://browser/skin/customizableui/whimsy.png);
}
@media (min-resolution: 2dppx) {
#PanelUI-popup #PanelUI-contents:empty::before {
background-image: url(chrome://browser/skin/customizableui/whimsy-bw@2x.png);
background-size: 64px 64px;
}
#PanelUI-popup #PanelUI-contents:empty:hover::before {
background-image: url(chrome://browser/skin/customizableui/whimsy@2x.png);
}
}
@keyframes moveX {
/* These values are adjusted for the padding on the panel. */
from { margin-left: -15px; } to { margin-left: calc(100% - 49px); }
}
@keyframes moveY {
/* These values are adjusted for the padding and height of the panel. */
from { margin-top: -6px; } to { margin-top: 58px; }
}
#PanelUI-button {
background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, hsla(0,0%,100%,0)),
linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.3) 30%, hsla(210,54%,20%,.3) 70%, hsla(210,54%,20%,0)),

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -103,6 +103,10 @@ browser.jar:
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
skin/classic/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
skin/classic/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
skin/classic/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
skin/classic/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
* skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@ -431,6 +435,10 @@ browser.jar:
* skin/classic/aero/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay-aero.css)
skin/classic/aero/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/aero/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
skin/classic/aero/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
skin/classic/aero/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
skin/classic/aero/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
skin/classic/aero/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
* skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
skin/classic/aero/browser/downloads/buttons.png (downloads/buttons-aero.png)
skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)

View File

@ -17,6 +17,7 @@ import shutil
import tempfile
from datetime import datetime
from mozbuild.base import MozbuildObject
from buildconfig import substs
PORT = 8888
@ -54,6 +55,14 @@ if __name__ == '__main__':
env = os.environ.copy()
env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
env["XPCOM_DEBUG_BREAK"] = "warn"
# For VC12, make sure we can find the right bitness of pgort120.dll
if "VS120COMNTOOLS" in env and not substs["HAVE_64BIT_OS"]:
vc12dir = os.path.abspath(os.path.join(env["VS120COMNTOOLS"],
"../../VC/bin"))
if os.path.exists(vc12dir):
env["PATH"] = vc12dir + ";" + env["PATH"]
jarlog = os.getenv("JARLOG_FILE")
if jarlog:
env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)

View File

@ -1516,8 +1516,6 @@ nsContentUtils::Shutdown()
sModifierSeparator = nullptr;
NS_IF_RELEASE(sSameOriginChecker);
nsTextEditorState::ShutDown();
}
/**

View File

@ -287,6 +287,7 @@ WebGLContext::DestroyResourcesAndContext()
if (!IsExtensionEnabled(extension) || (extension == WEBGL_lose_context))
continue;
mExtensions[extension]->MarkLost();
mExtensions[extension] = nullptr;
}

View File

@ -720,6 +720,9 @@ WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer *rbuf)
if (mBoundFramebuffer)
mBoundFramebuffer->DetachRenderbuffer(rbuf);
// Invalidate framebuffer status cache
rbuf->NotifyFBsStatusChanged();
if (mBoundRenderbuffer == rbuf)
BindRenderbuffer(LOCAL_GL_RENDERBUFFER,
static_cast<WebGLRenderbuffer*>(nullptr));
@ -742,6 +745,9 @@ WebGLContext::DeleteTexture(WebGLTexture *tex)
if (mBoundFramebuffer)
mBoundFramebuffer->DetachTexture(tex);
// Invalidate framebuffer status cache
tex->NotifyFBsStatusChanged();
GLuint activeTexture = mActiveTexture;
for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
@ -2662,6 +2668,8 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
height != mBoundRenderbuffer->Height() ||
internalformat != mBoundRenderbuffer->InternalFormat();
if (sizeChanges) {
// Invalidate framebuffer status cache
mBoundRenderbuffer->NotifyFBsStatusChanged();
GetAndFlushUnderlyingGLErrors();
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
GLenum error = GetAndFlushUnderlyingGLErrors();

View File

@ -1173,6 +1173,7 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTex
case LOCAL_GL_LUMINANCE_ALPHA:
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
type == LOCAL_GL_HALF_FLOAT ||
type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
@ -1181,6 +1182,7 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTex
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
type == LOCAL_GL_HALF_FLOAT ||
type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
@ -1190,6 +1192,7 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTex
type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
type == LOCAL_GL_HALF_FLOAT ||
type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
@ -1252,8 +1255,11 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
break;
// TODO: WebGL spec doesn't allow half floats to specified as UInt16.
// case LOCAL_GL_HALF_FLOAT:
// case LOCAL_GL_HALF_FLOAT_OES:
case LOCAL_GL_HALF_FLOAT:
case LOCAL_GL_HALF_FLOAT_OES:
validInput = (jsArrayType == -1);
break;
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:

View File

@ -10,6 +10,7 @@ using namespace mozilla;
WebGLExtensionBase::WebGLExtensionBase(WebGLContext* context)
: WebGLContextBoundObject(context)
, mIsLost(false)
{
SetIsDOMBinding();
}
@ -18,6 +19,12 @@ WebGLExtensionBase::~WebGLExtensionBase()
{
}
void
WebGLExtensionBase::MarkLost()
{
mIsLost = true;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLExtensionBase)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLExtensionBase, AddRef)

View File

@ -26,6 +26,11 @@ void
WebGLExtensionDebugShaders::GetTranslatedShaderSource(WebGLShader* shader,
nsAString& retval)
{
if (mIsLost) {
return mContext->ErrorInvalidOperation("getTranslatedShaderSource: "
"Extension is lost.");
}
mContext->GetShaderTranslatedSource(shader, retval);
if (retval.IsVoid()) {

View File

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
@ -49,6 +50,9 @@ WebGLExtensionDrawBuffers::~WebGLExtensionDrawBuffers()
void WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost.");
mContext->DrawBuffers(buffers);
}

View File

@ -25,6 +25,9 @@ void
WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode, GLint first,
GLsizei count, GLsizei primcount)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("drawArraysInstancedANGLE: Extension is lost.");
mContext->DrawArraysInstanced(mode, first, count, primcount);
}
@ -33,12 +36,18 @@ WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode, GLsizei c
GLenum type, WebGLintptr offset,
GLsizei primcount)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("drawElementsInstancedANGLE: Extension is lost.");
mContext->DrawElementsInstanced(mode, count, type, offset, primcount);
}
void
WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index, GLuint divisor)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("vertexAttribDivisorANGLE: Extension is lost.");
mContext->VertexAttribDivisor(index, divisor);
}

View File

@ -25,21 +25,37 @@ WebGLExtensionVertexArray::~WebGLExtensionVertexArray()
already_AddRefed<WebGLVertexArray> WebGLExtensionVertexArray::CreateVertexArrayOES()
{
if (mIsLost) {
mContext->ErrorInvalidOperation("createVertexArrayOES: Extension is lost. Returning NULL.");
return nullptr;
}
return mContext->CreateVertexArray();
}
void WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("deleteVertexArrayOES: Extension is lost.");
mContext->DeleteVertexArray(array);
}
bool WebGLExtensionVertexArray::IsVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost) {
mContext->ErrorInvalidOperation("isVertexArrayOES: Extension is lost. Returning false.");
return false;
}
return mContext->IsVertexArray(array);
}
void WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost)
return mContext->ErrorInvalidOperation("bindVertexArrayOES: Extension is lost.");
mContext->BindVertexArray(array);
}

View File

@ -30,8 +30,13 @@ public:
return Context();
}
void MarkLost();
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLExtensionBase)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLExtensionBase)
protected:
bool mIsLost;
};
#define DECL_WEBGL_EXTENSION_GOOP \

View File

@ -25,6 +25,7 @@ WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
: WebGLContextBoundObject(context)
, mStatus(0)
, mHasEverBeenBound(false)
, mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
, mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
@ -391,6 +392,7 @@ WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
WebGLRenderbuffer* wrb)
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
return;
@ -400,27 +402,32 @@ WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
if (rbtarget != LOCAL_GL_RENDERBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
mDepthAttachment.SetRenderbuffer(wrb);
break;
case LOCAL_GL_STENCIL_ATTACHMENT:
mStencilAttachment.SetRenderbuffer(wrb);
break;
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
mDepthStencilAttachment.SetRenderbuffer(wrb);
break;
default:
// finish checking that the 'attachment' parameter is among the allowed values
if (!CheckColorAttachmentNumber(attachment, "framebufferRenderbuffer")){
return;
}
/* Get the requested attachment. If result is NULL, attachment is
* invalid and an error is generated.
*
* Don't use GetAttachment(...) here because it opt builds it
* returns mColorAttachment[0] for invalid attachment, which we
* really don't want to mess with.
*/
Attachment* a = GetAttachmentOrNull(attachment);
if (!a)
return; // Error generated internally to GetAttachmentOrNull.
size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
EnsureColorAttachments(colorAttachmentId);
mColorAttachments[colorAttachmentId].SetRenderbuffer(wrb);
break;
}
/* Invalidate cached framebuffer status and inform texture of it's
* new attachment
*/
mStatus = 0;
// Detach current
if (a->Texture())
a->Texture()->DetachFrom(this, attachment);
else if (a->Renderbuffer())
a->Renderbuffer()->DetachFrom(this, attachment);
// Attach new
if (wrb)
wrb->AttachTo(this, attachment);
a->SetRenderbuffer(wrb);
}
void
@ -431,11 +438,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target,
GLint level)
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture",
wtex))
{
if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
return;
}
if (target != LOCAL_GL_FRAMEBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
@ -458,25 +463,53 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target,
if (level != 0)
return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
mDepthAttachment.SetTexImage(wtex, textarget, level);
break;
case LOCAL_GL_STENCIL_ATTACHMENT:
mStencilAttachment.SetTexImage(wtex, textarget, level);
break;
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
mDepthStencilAttachment.SetTexImage(wtex, textarget, level);
break;
default:
if (!CheckColorAttachmentNumber(attachment, "framebufferTexture2D"))
return;
/* Get the requested attachment. If result is NULL, attachment is
* invalid and an error is generated.
*
* Don't use GetAttachment(...) here because it opt builds it
* returns mColorAttachment[0] for invalid attachment, which we
* really don't want to mess with.
*/
Attachment* a = GetAttachmentOrNull(attachment);
if (!a)
return; // Error generated internally to GetAttachmentOrNull.
size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
EnsureColorAttachments(colorAttachmentId);
mColorAttachments[colorAttachmentId].SetTexImage(wtex, textarget, level);
break;
}
/* Invalidate cached framebuffer status and inform texture of it's
* new attachment
*/
mStatus = 0;
// Detach current
if (a->Texture())
a->Texture()->DetachFrom(this, attachment);
else if (a->Renderbuffer())
a->Renderbuffer()->DetachFrom(this, attachment);
// Attach new
if (wtex)
wtex->AttachTo(this, attachment);
a->SetTexImage(wtex, textarget, level);
}
WebGLFramebuffer::Attachment*
WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment)
{
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
return &mDepthStencilAttachment;
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
return &mDepthAttachment;
if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
return &mStencilAttachment;
if (!CheckColorAttachmentNumber(attachment, "getAttachmentOrNull"))
return nullptr;
size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
EnsureColorAttachments(colorAttachmentId);
return &mColorAttachments[colorAttachmentId];
}
const WebGLFramebuffer::Attachment&
@ -676,9 +709,12 @@ WebGLFramebuffer::PrecheckFramebufferStatus() const
GLenum
WebGLFramebuffer::CheckFramebufferStatus() const
{
GLenum precheckStatus = PrecheckFramebufferStatus();
if (precheckStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return precheckStatus;
if (mStatus != 0)
return mStatus;
mStatus = PrecheckFramebufferStatus();
if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return mStatus;
// Looks good on our end. Let's ask the driver.
mContext->MakeContextCurrent();
@ -686,7 +722,8 @@ WebGLFramebuffer::CheckFramebufferStatus() const
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
FinalizeAttachments();
return mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
return mStatus;
}
bool
@ -831,6 +868,13 @@ void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
}
}
void
WebGLFramebuffer::NotifyAttachableChanged() const
{
// Attachment has changed, so invalidate cached status
mStatus = 0;
}
static void
FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
{

View File

@ -14,6 +14,7 @@
namespace mozilla {
class WebGLFramebufferAttachable;
class WebGLTexture;
class WebGLRenderbuffer;
namespace gl {
@ -114,6 +115,7 @@ public:
private:
const WebGLRectangleObject& GetAnyRectObject() const;
Attachment* GetAttachmentOrNull(GLenum attachment);
public:
bool HasDefinedAttachments() const;
@ -174,11 +176,17 @@ public:
bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const;
void EnsureColorAttachments(size_t colorAttachmentId);
Attachment* AttachmentFor(GLenum attachment);
void NotifyAttachableChanged() const;
private:
mutable GLenum mStatus;
GLuint mGLName;
bool mHasEverBeenBound;
void EnsureColorAttachments(size_t colorAttachmentId);
// we only store pointers to attached renderbuffers, not to attached textures, because
// we will only need to initialize renderbuffers. Textures are already initialized.
nsTArray<Attachment> mColorAttachments;

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "WebGLContext.h"
#include "WebGLFramebufferAttachable.h"
#include "WebGLFramebuffer.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
using namespace mozilla;
WebGLFramebufferAttachable::AttachmentPoint*
WebGLFramebufferAttachable::Contains(const WebGLFramebuffer* fb, GLenum attachment)
{
AttachmentPoint* first = mAttachmentPoints.begin();
AttachmentPoint* last = mAttachmentPoints.end();
for (; first != last; ++first) {
if (first->mFB == fb && first->mAttachment == attachment)
return first;
}
return nullptr;
}
void
WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, GLenum attachment)
{
MOZ_ASSERT(fb);
if (!fb)
return;
if (Contains(fb, attachment))
return; // Already attached. Ignore.
mAttachmentPoints.append(AttachmentPoint(fb, attachment));
}
void
WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, GLenum attachment)
{
MOZ_ASSERT(fb);
if (!fb)
return;
AttachmentPoint* point = Contains(fb, attachment);
if (!point) {
MOZ_ASSERT(false, "Is not attached to FB");
return;
}
mAttachmentPoints.erase(point);
}
void
WebGLFramebufferAttachable::NotifyFBsStatusChanged()
{
AttachmentPoint* first = mAttachmentPoints.begin();
AttachmentPoint* last = mAttachmentPoints.end();
for ( ; first != last; ++first)
first->mFB->NotifyAttachableChanged();
}

View File

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGLFRAMEBUFFERATTACHABLE_H_
#define WEBGLFRAMEBUFFERATTACHABLE_H_
#include "GLDefs.h"
#include "mozilla/Vector.h"
namespace mozilla {
class WebGLFramebuffer;
class WebGLFramebufferAttachable
{
struct AttachmentPoint
{
AttachmentPoint(const WebGLFramebuffer* fb, GLenum attachment)
: mFB(fb)
, mAttachment(attachment)
{}
const WebGLFramebuffer* mFB;
GLenum mAttachment;
};
Vector<AttachmentPoint> mAttachmentPoints;
AttachmentPoint* Contains(const WebGLFramebuffer* fb, GLenum attachment);
public:
// Track FBO/Attachment combinations
void AttachTo(WebGLFramebuffer* fb, GLenum attachment);
void DetachFrom(WebGLFramebuffer* fb, GLenum attachment);
void NotifyFBsStatusChanged();
};
} // namespace mozilla
#endif // !WEBGLFRAMEBUFFERATTACHABLE_H_

View File

@ -305,7 +305,7 @@ public:
}
bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
return Width() == other.Width() && Height() == other.Height();
return Width() == other.Width() && Height() == other.Height();
}
protected:

View File

@ -7,6 +7,7 @@
#define WEBGLRENDERBUFFER_H_
#include "WebGLObjectModel.h"
#include "WebGLFramebufferAttachable.h"
#include "nsWrapperCache.h"
@ -20,6 +21,7 @@ class WebGLRenderbuffer MOZ_FINAL
, public LinkedListElement<WebGLRenderbuffer>
, public WebGLRectangleObject
, public WebGLContextBoundObject
, public WebGLFramebufferAttachable
{
public:
WebGLRenderbuffer(WebGLContext *context);

View File

@ -147,6 +147,9 @@ WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
if (aLevel > 0)
SetCustomMipmap();
// Invalidate framebuffer status cache
NotifyFBsStatusChanged();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}

View File

@ -7,6 +7,7 @@
#define WEBGLTEXTURE_H_
#include "WebGLObjectModel.h"
#include "WebGLFramebufferAttachable.h"
#include "nsWrapperCache.h"
@ -37,6 +38,7 @@ class WebGLTexture MOZ_FINAL
, public WebGLRefCountedObject<WebGLTexture>
, public LinkedListElement<WebGLTexture>
, public WebGLContextBoundObject
, public WebGLFramebufferAttachable
{
public:
WebGLTexture(WebGLContext *context);

View File

@ -67,6 +67,7 @@ if CONFIG['MOZ_WEBGL']:
'WebGLExtensionTextureHalfFloatLinear.cpp',
'WebGLExtensionVertexArray.cpp',
'WebGLFramebuffer.cpp',
'WebGLFramebufferAttachable.cpp',
'WebGLObjectModel.cpp',
'WebGLProgram.cpp',
'WebGLQuery.cpp',
@ -104,4 +105,3 @@ LOCAL_INCLUDES += [
'/layout/style',
'/layout/xul',
]

View File

@ -148,12 +148,15 @@ random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=1
fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0 wrapper.html?half-colors.png
# Test premult:
fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha wrapper.html?colors-half-alpha.png
# random-if(B2G) from bug 983650
fuzzy(1,65536) random-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha wrapper.html?colors-half-alpha.png
fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) fails-if(cocoaWidget||Android) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha wrapper.html?half-colors-half-alpha.png
fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
# random-if(B2G) from bug 983650
fuzzy(1,65536) random-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
# Test over-bright premult:
fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
# random-if(B2G) from bug 983650
fuzzy(1,65536) random-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
# Check for hanging framebuffer bindings:

View File

@ -28,7 +28,7 @@
#include "nsGenericHTMLElement.h"
#include "nsIDOMEventListener.h"
#include "nsIEditorObserver.h"
#include "nsINativeKeyBindings.h"
#include "nsIWidget.h"
#include "nsIDocumentEncoder.h"
#include "nsISelectionPrivate.h"
#include "nsPIDOMWindow.h"
@ -49,9 +49,6 @@ using namespace mozilla::dom;
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
static nsINativeKeyBindings *sNativeInputBindings = nullptr;
static nsINativeKeyBindings *sNativeTextAreaBindings = nullptr;
class MOZ_STACK_CLASS ValueSetter
{
public:
@ -679,8 +676,6 @@ protected:
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
protected:
nsIFrame* mFrame;
@ -798,7 +793,7 @@ nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection*
// END nsIDOMSelectionListener
static void
DoCommandCallback(const char *aCommand, void *aData)
DoCommandCallback(Command aCommand, void* aData)
{
nsTextControlFrame *frame = static_cast<nsTextControlFrame*>(aData);
nsIContent *content = frame->GetContent();
@ -821,17 +816,19 @@ DoCommandCallback(const char *aCommand, void *aData)
return;
}
const char* commandStr = WidgetKeyboardEvent::GetCommandStr(aCommand);
nsCOMPtr<nsIController> controller;
controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
controllers->GetControllerForCommand(commandStr, getter_AddRefs(controller));
if (!controller) {
return;
}
bool commandEnabled;
nsresult rv = controller->IsCommandEnabled(aCommand, &commandEnabled);
nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
NS_ENSURE_SUCCESS_VOID(rv);
if (commandEnabled) {
controller->DoCommand(aCommand);
controller->DoCommand(commandStr);
}
}
@ -858,27 +855,25 @@ nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent)
return NS_ERROR_UNEXPECTED;
}
nsINativeKeyBindings *bindings = GetKeyBindings();
if (bindings) {
bool handled = false;
switch (keyEvent->message) {
case NS_KEY_DOWN:
handled = bindings->KeyDown(*keyEvent, DoCommandCallback, mFrame);
break;
case NS_KEY_UP:
handled = bindings->KeyUp(*keyEvent, DoCommandCallback, mFrame);
break;
case NS_KEY_PRESS:
handled = bindings->KeyPress(*keyEvent, DoCommandCallback, mFrame);
break;
default:
MOZ_CRASH("Unknown key message");
}
if (handled) {
aEvent->PreventDefault();
}
if (keyEvent->message != NS_KEY_PRESS) {
return NS_OK;
}
nsIWidget::NativeKeyBindingsType nativeKeyBindingsType =
mTxtCtrlElement->IsTextArea() ?
nsIWidget::NativeKeyBindingsForMultiLineEditor :
nsIWidget::NativeKeyBindingsForSingleLineEditor;
nsIWidget* widget = keyEvent->widget;
// If the event is created by chrome script, the widget is nullptr.
if (!widget) {
widget = mFrame->GetNearestWidget();
NS_ENSURE_TRUE(widget, NS_OK);
}
if (widget->ExecuteNativeKeyBinding(nativeKeyBindingsType,
*keyEvent, DoCommandCallback, mFrame)) {
aEvent->PreventDefault();
}
return NS_OK;
}
@ -947,37 +942,6 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
return domWindow->UpdateCommands(commandsToUpdate);
}
nsINativeKeyBindings*
nsTextInputListener::GetKeyBindings()
{
if (mTxtCtrlElement->IsTextArea()) {
static bool sNoTextAreaBindings = false;
if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
&sNativeTextAreaBindings);
if (!sNativeTextAreaBindings) {
sNoTextAreaBindings = true;
}
}
return sNativeTextAreaBindings;
}
static bool sNoInputBindings = false;
if (!sNativeInputBindings && !sNoInputBindings) {
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
&sNativeInputBindings);
if (!sNativeInputBindings) {
sNoInputBindings = true;
}
}
return sNativeInputBindings;
}
// END nsTextInputListener
// nsTextEditorState
@ -1982,13 +1946,6 @@ nsTextEditorState::InitializeKeyboardEventListeners()
mSelCon->SetScrollableFrame(do_QueryFrame(mBoundFrame->GetFirstPrincipalChild()));
}
/* static */ void
nsTextEditorState::ShutDown()
{
NS_IF_RELEASE(sNativeTextAreaBindings);
NS_IF_RELEASE(sNativeInputBindings);
}
void
nsTextEditorState::ValueWasChanged(bool aNotify)
{

View File

@ -188,9 +188,6 @@ public:
*/
bool GetMaxLength(int32_t* aMaxLength);
/* called to free up native keybinding services */
static NS_HIDDEN_(void) ShutDown();
void ClearValueCache() { mCachedValue.Truncate(); }
void HideSelectionIfBlurred();

View File

@ -47,6 +47,12 @@ protected:
struct AllTypedArraysBase {
};
// Struct that serves as a base class for all owning unions.
// Particularly useful so we can use IsBaseOf to detect owning union
// template arguments.
struct AllOwningUnionBase {
};
struct EnumEntry {
const char* value;

View File

@ -1657,7 +1657,8 @@ public:
// sequence types.
template<typename T,
bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value>
bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
class SequenceTracer
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1665,7 +1666,7 @@ class SequenceTracer
// sequence<object> or sequence<object?>
template<>
class SequenceTracer<JSObject*, false, false>
class SequenceTracer<JSObject*, false, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1679,7 +1680,7 @@ public:
// sequence<any>
template<>
class SequenceTracer<JS::Value, false, false>
class SequenceTracer<JS::Value, false, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1693,7 +1694,7 @@ public:
// sequence<sequence<T>>
template<typename T>
class SequenceTracer<Sequence<T>, false, false>
class SequenceTracer<Sequence<T>, false, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1707,7 +1708,7 @@ public:
// sequence<sequence<T>> as return value
template<typename T>
class SequenceTracer<nsTArray<T>, false, false>
class SequenceTracer<nsTArray<T>, false, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1721,7 +1722,7 @@ public:
// sequence<someDictionary>
template<typename T>
class SequenceTracer<T, true, false>
class SequenceTracer<T, true, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1735,7 +1736,7 @@ public:
// sequence<SomeTypedArray>
template<typename T>
class SequenceTracer<T, false, true>
class SequenceTracer<T, false, true, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
@ -1747,9 +1748,23 @@ public:
}
};
// sequence<SomeOwningUnion>
template<typename T>
class SequenceTracer<T, false, false, true>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
for (; arrayp != end; ++arrayp) {
arrayp->TraceUnion(trc);
}
}
};
// sequence<T?> with T? being a Nullable<T>
template<typename T>
class SequenceTracer<Nullable<T>, false, false>
class SequenceTracer<Nullable<T>, false, false, false>
{
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated

View File

@ -912,8 +912,14 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
typeDesc = p.getDescriptor(f.inner.identifier.name)
except NoSuchDescriptorError:
continue
declarations.add((typeDesc.nativeType, False))
implheaders.add(typeDesc.headerFile)
if typeDesc.interface.isCallback():
# Callback interfaces always use strong refs, so
# we need to include the right header to be able
# to Release() in our inlined code.
headers.add(typeDesc.headerFile)
else:
declarations.add((typeDesc.nativeType, False))
implheaders.add(typeDesc.headerFile)
elif f.isDictionary():
# For a dictionary, we need to see its declaration in
# UnionTypes.h so we have its sizeof and know how big to
@ -926,6 +932,11 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
# Need to see the actual definition of the enum,
# unfortunately.
headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isCallback():
# Callbacks always use strong refs, so we need to include
# the right header to be able to Release() in our inlined
# code.
headers.add(CGHeaders.getDeclarationFilename(f))
map(addInfoForType, getAllTypes(descriptors, dictionaries, callbacks))
@ -3276,7 +3287,10 @@ while (true) {
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
if len(objectMemberTypes) > 0:
assert len(objectMemberTypes) == 1
object = CGGeneric("%s.SetToObject(cx, argObj);\n"
# Very important to NOT construct a temporary Rooted here, since the
# SetToObject call can call a Rooted constructor and we need to keep
# stack discipline for Rooted.
object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n"
"done = true;" % unionArgumentObj)
names.append(objectMemberTypes[0].name)
else:
@ -3303,7 +3317,7 @@ while (true) {
else:
templateBody = CGList([templateBody, object], "\n")
if any([arrayObject, dateObject, callbackObject, object]):
if dateObject:
templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());"))
templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
else:
@ -7187,7 +7201,9 @@ class CGUnionStruct(CGThing):
disallowCopyConstruction = True
friend=" friend class %sArgument;\n" % str(self.type) if not self.ownsMembers else ""
bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else []
return CGClass(selfName,
bases=bases,
members=members,
constructors=constructors,
methods=methods,

View File

@ -524,6 +524,7 @@ public:
void PassUnion12(const EventInitOrLong& arg);
void PassUnion13(JSContext*, const ObjectOrLongOrNull& arg);
void PassUnion14(JSContext*, const ObjectOrLongOrNull& arg);
void PassUnionWithCallback(const EventHandlerNonNullOrNullOrLong& arg);
#endif
void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
@ -566,6 +567,7 @@ public:
void PassNullableUnionWithDefaultValue12(const Nullable<UnrestrictedFloatOrString>& arg);
void PassSequenceOfUnions(const Sequence<OwningCanvasPatternOrCanvasGradient>&);
void PassSequenceOfUnions2(JSContext*, const Sequence<OwningObjectOrLong>&);
void PassVariadicUnion(const Sequence<OwningCanvasPatternOrCanvasGradient>&);
void PassSequenceOfNullableUnions(const Sequence<Nullable<OwningCanvasPatternOrCanvasGradient>>&);

View File

@ -475,6 +475,7 @@ interface TestInterface {
void passUnion12(optional (EventInit or long) arg = 5);
void passUnion13(optional (object or long?) arg = null);
void passUnion14(optional (object or long?) arg = 5);
void passUnionWithCallback((EventHandler or long) arg);
#endif
void passUnionWithNullable((object? or long) arg);
void passNullableUnion((object or long)? arg);
@ -521,6 +522,7 @@ interface TestInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
void passSequenceOfUnions2(sequence<(object or long)> arg);
void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);

View File

@ -368,6 +368,7 @@ interface TestExampleInterface {
void passUnion12(optional (EventInit or long) arg = 5);
void passUnion13(optional (object or long?) arg = null);
void passUnion14(optional (object or long?) arg = 5);
void passUnionWithCallback((EventHandler or long) arg);
#endif
void passUnionWithNullable((object? or long) arg);
void passNullableUnion((object or long)? arg);
@ -414,6 +415,7 @@ interface TestExampleInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
void passSequenceOfUnions2(sequence<(object or long)> arg);
void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);

View File

@ -389,6 +389,7 @@ interface TestJSImplInterface {
void passUnion12(optional (EventInit or long) arg = 5);
void passUnion13(optional (object or long?) arg = null);
void passUnion14(optional (object or long?) arg = 5);
void passUnionWithCallback((EventHandler or long) arg);
#endif
void passUnionWithNullable((object? or long) arg);
void passNullableUnion((object or long)? arg);
@ -435,6 +436,7 @@ interface TestJSImplInterface {
void passNullableUnionWithDefaultValue12(optional (unrestricted float or DOMString)? arg = null);
void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
void passSequenceOfUnions2(sequence<(object or long)> arg);
void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);

View File

@ -335,6 +335,7 @@ this.DOMIdentity = {
},
_unwatch: function DOMIdentity_unwatch(message, targetMM) {
log("DOMIDentity__unwatch: " + message.id);
this.getService(message).RP.unwatch(message.id, targetMM);
},

View File

@ -670,7 +670,7 @@ nsDOMIdentity.prototype = {
},
uninit: function DOMIdentity_uninit() {
this._log("nsDOMIdentity uninit()");
this._log("nsDOMIdentity uninit() " + this._id);
this._identityInternal._mm.sendAsyncMessage(
"Identity:RP:Unwatch",
{ id: this._id }

View File

@ -41,7 +41,11 @@
onready: onready,
onlogin: onlogin,
onerror: onerror,
onlogout: function() {},
// onlogout will actually be called every time watch() is invoked,
// because fxa will find no signed-in user and so trigger logout.
// For this test, though, we don't care and just ignore logout.
onlogout: function () {},
});
};

View File

@ -34,7 +34,13 @@ is("appStatus" in document.nodePrincipal, true,
function MockFXAManager() {}
MockFXAManager.prototype = {
getAssertion: function(audience) {
getAssertion: function(audience, options) {
// Always reject a request for a silent assertion, simulating the
// scenario in which there is no signed-in user to begin with.
if (options.silent) {
return Promise.resolve(null);
}
let deferred = Promise.defer();
jwcrypto.generateKeyPair("DS160", (err, kp) => {
if (err) {
@ -137,7 +143,7 @@ function receiveMessage(event) {
let expected = app.expected;
is(result.success, expected.success,
"Assertion request " + (expected.success ? "succeeds" : "fails"));
"Assertion request succeeds");
if (expected.success) {
// Confirm that the assertion audience and origin are as expected
@ -180,7 +186,6 @@ window.addEventListener("message", receiveMessage, false, true);
function runTest() {
for (let app of apps) {
dump("** Testing " + app.title + "\n");
// Set up state for message handler
expectedErrors = 0;
receivedErrors = [];

View File

@ -31,7 +31,10 @@ Components.utils.import("resource://gre/modules/identity/FirefoxAccounts.jsm");
// plumbing.
function MockFXAManager() {}
MockFXAManager.prototype = {
getAssertion: function() {
getAssertion: function(audience, options) {
if (options.silent) {
return Promise.resolve(null);
}
return Promise.resolve("here~you.go.dude");
}
};

View File

@ -1594,8 +1594,8 @@ PeerConnectionWrapper.prototype = {
var res = stats[key];
// validate stats
ok(res.id == key, "Coherent stats id");
var nowish = Date.now() + 10000; // TODO: severe drift observed
var minimum = this.whenCreated - 10000; // on Windows XP (Bug 979649)
var nowish = Date.now() + 1000; // TODO: clock drift observed
var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
ok(res.timestamp >= minimum,
"Valid " + (res.isRemote? "rtcp" : "rtp") + " timestamp " +
res.timestamp + " >= " + minimum + " (" +
@ -1631,12 +1631,10 @@ PeerConnectionWrapper.prototype = {
if(res.type == "outboundrtp") {
ok(rem.type == "inboundrtp", "Rtcp is inbound");
ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived");
// TODO: Re-enable once Bug 980497 is fixed
// ok(rem.packetsReceived <= res.packetsSent, "No more than sent");
ok(rem.packetsReceived <= res.packetsSent, "No more than sent");
ok(rem.packetsLost !== undefined, "Rtcp packetsLost");
ok(rem.bytesReceived >= rem.packetsReceived * 8, "Rtcp bytesReceived");
// TODO: Re-enable once Bug 980497 is fixed
// ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
ok(rem.jitter !== undefined, "Rtcp jitter");
} else {
ok(rem.type == "outboundrtp", "Rtcp is outbound");

View File

@ -41,6 +41,10 @@ const NETWORK_STATUS_AWAY = 2;
// The maximum traffic amount can be saved in the |cachedStats|.
const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
const QUEUE_TYPE_UPDATE_STATS = 0;
const QUEUE_TYPE_UPDATE_CACHE = 1;
const QUEUE_TYPE_WRITE_CACHE = 2;
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
@ -398,7 +402,6 @@ this.NetworkStatsService = {
* it retrieve them from database and return to the manager.
*/
getSamples: function getSamples(mm, msg) {
let self = this;
let network = msg.network;
let netId = this.getNetworkId(network.id, network.type);
@ -420,6 +423,13 @@ this.NetworkStatsService = {
let start = new Date(msg.start);
let end = new Date(msg.end);
let callback = (function (aError, aResult) {
this._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
}).bind(this);
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
@ -429,27 +439,28 @@ this.NetworkStatsService = {
// If network is currently active we need to update the cached stats first before
// retrieving stats from the DB.
if (self._networks[aNetId].status == NETWORK_STATUS_READY) {
self.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
if (this._networks[aNetId].status == NETWORK_STATUS_READY) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
debug("serviceType: " + serviceType);
self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
});
if (appId || serviceType) {
this.updateCachedStats(callback);
return;
}
this.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
this.updateCachedStats(callback);
}.bind(this));
return;
}
// Network not active, so no need to update
self._db.find(function onStatsFound(aError, aResult) {
this._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
}.bind(this));
},
clearInterfaceStats: function clearInterfaceStats(mm, msg) {
@ -515,11 +526,11 @@ this.NetworkStatsService = {
},
updateAllStats: function updateAllStats(aCallback) {
// Update |cachedStats|.
this.updateCachedStats();
let elements = [];
let lastElement = null;
let callback = (function (success, message) {
this.updateCachedStats(aCallback);
}).bind(this);
// For each connectionType create an object containning the type
// and the 'queueIndex', the 'queueIndex' is an integer representing
@ -533,10 +544,12 @@ this.NetworkStatsService = {
}
lastElement = { netId: netId,
queueIndex: this.updateQueueIndex(netId)};
queueIndex: this.updateQueueIndex(netId) };
if (lastElement.queueIndex == -1) {
elements.push({ netId: lastElement.netId, callbacks: [] });
elements.push({ netId: lastElement.netId,
callbacks: [],
queueType: QUEUE_TYPE_UPDATE_STATS });
}
}
@ -552,7 +565,7 @@ this.NetworkStatsService = {
if (elements.length > 0) {
// If length of elements is greater than 0, callback is set to
// the last element.
elements[elements.length - 1].callbacks.push(aCallback);
elements[elements.length - 1].callbacks.push(callback);
this.updateQueue = this.updateQueue.concat(elements);
} else {
// Else, it means that all connection types are already in the queue to
@ -567,7 +580,7 @@ this.NetworkStatsService = {
return;
}
this.updateQueue[lastElement.queueIndex].callbacks.push(aCallback);
this.updateQueue[lastElement.queueIndex].callbacks.push(callback);
}
// Call the function that process the elements of the queue.
@ -583,7 +596,9 @@ this.NetworkStatsService = {
// if it is not being processed or add a callback if it is.
let index = this.updateQueueIndex(aNetId);
if (index == -1) {
this.updateQueue.push({netId: aNetId, callbacks: [aCallback]});
this.updateQueue.push({ netId: aNetId,
callbacks: [aCallback],
queueType: QUEUE_TYPE_UPDATE_STATS });
} else {
this.updateQueue[index].callbacks.push(aCallback);
return;
@ -611,7 +626,7 @@ this.NetworkStatsService = {
if (aResult != undefined) {
let item = this.updateQueue.shift();
for (let callback of item.callbacks) {
if(callback) {
if (callback) {
callback(aResult, aMessage);
}
}
@ -620,9 +635,7 @@ this.NetworkStatsService = {
// if isQueueRunning is false it means there is no processing currently
// being done, so start.
if (this.isQueueRunning) {
if(this.updateQueue.length > 1) {
return;
}
return;
} else {
this.isQueueRunning = true;
}
@ -635,7 +648,17 @@ this.NetworkStatsService = {
}
// Call the update function for the next element.
this.update(this.updateQueue[0].netId, this.processQueue.bind(this));
switch (this.updateQueue[0].queueType) {
case QUEUE_TYPE_UPDATE_STATS:
this.update(this.updateQueue[0].netId, this.processQueue.bind(this));
break;
case QUEUE_TYPE_UPDATE_CACHE:
this.updateCache(this.processQueue.bind(this));
break;
case QUEUE_TYPE_WRITE_CACHE:
this.writeCache(this.updateQueue[0].stats, this.processQueue.bind(this));
break;
}
},
update: function update(aNetId, aCallback) {
@ -708,14 +731,11 @@ this.NetworkStatsService = {
let netId = this.convertNetworkInterface(aNetwork);
if (!netId) {
if (aCallback) {
aCallback.notify(false, "Invalid network type");
aCallback(false, "Invalid network type");
}
return;
}
debug("saveStats: " + aAppId + " " + aServiceType + " " + netId + " " +
aTimeStamp + " " + aRxBytes + " " + aTxBytes);
// Check if |aConnectionType|, |aAppId| and |aServiceType| are valid.
// There are two invalid cases for the combination of |aAppId| and
// |aServiceType|:
@ -736,33 +756,41 @@ this.NetworkStatsService = {
txBytes: aTxBytes,
isAccumulative: aIsAccumulative };
this.updateQueue.push({ stats: stats,
callbacks: [aCallback],
queueType: QUEUE_TYPE_WRITE_CACHE });
this.processQueue();
},
/*
*
*/
writeCache: function writeCache(aStats, aCallback) {
debug("saveStats: " + aStats.appId + " " + aStats.serviceType + " " +
aStats.networkId + " " + aStats.networkType + " " + aStats.date + " "
+ aStats.date + " " + aStats.rxBytes + " " + aStats.txBytes);
// Generate an unique key from |appId|, |serviceType| and |netId|,
// which is used to retrieve data in |cachedStats|.
let key = stats.appId + "" + stats.serviceType + "" + netId;
let netId = this.getNetworkId(aStats.networkId, aStats.networkType);
let key = aStats.appId + "" + aStats.serviceType + "" + netId;
// |cachedStats| only keeps the data with the same date.
// If the incoming date is different from |cachedStatsDate|,
// both |cachedStats| and |cachedStatsDate| will get updated.
let diff = (this._db.normalizeDate(stats.date) -
let diff = (this._db.normalizeDate(aStats.date) -
this._db.normalizeDate(this.cachedStatsDate)) /
this._db.sampleRate;
if (diff != 0) {
this.updateCachedStats(function onUpdated(success, message) {
this.cachedStatsDate = stats.date;
this.cachedStats[key] = stats;
this.updateCache(function onUpdated(success, message) {
this.cachedStatsDate = aStats.date;
this.cachedStats[key] = aStats;
if (!aCallback) {
return;
if (aCallback) {
aCallback(true, "ok");
}
if (!success) {
aCallback.notify(false, message);
return;
}
aCallback.notify(true, "ok");
}.bind(this));
return;
}
@ -770,30 +798,46 @@ this.NetworkStatsService = {
// If not found, save the incoming data into the cached.
let cachedStats = this.cachedStats[key];
if (!cachedStats) {
this.cachedStats[key] = stats;
this.cachedStats[key] = aStats;
if (aCallback) {
aCallback(true, "ok");
}
return;
}
// Find matched row, accumulate the traffic amount.
cachedStats.rxBytes += stats.rxBytes;
cachedStats.txBytes += stats.txBytes;
cachedStats.rxBytes += aStats.rxBytes;
cachedStats.txBytes += aStats.txBytes;
// If new rxBytes or txBytes exceeds MAX_CACHED_TRAFFIC
// the corresponding row will be saved to indexedDB.
// Then, the row will be removed from the cached.
if (cachedStats.rxBytes > MAX_CACHED_TRAFFIC ||
cachedStats.txBytes > MAX_CACHED_TRAFFIC) {
this._db.saveStats(cachedStats,
function (error, result) {
debug("Application stats inserted in indexedDB");
this._db.saveStats(cachedStats, function (error, result) {
debug("Application stats inserted in indexedDB");
if (aCallback) {
aCallback(true, "ok");
}
);
});
delete this.cachedStats[key];
return;
}
if (aCallback) {
aCallback(true, "ok");
}
},
updateCachedStats: function updateCachedStats(aCallback) {
debug("updateCachedStats: " + this.cachedStatsDate);
this.updateQueue.push({ callbacks: [aCallback],
queueType: QUEUE_TYPE_UPDATE_CACHE });
this.processQueue();
},
updateCache: function updateCache(aCallback) {
debug("updateCache: " + this.cachedStatsDate);
let stats = Object.keys(this.cachedStats);
if (stats.length == 0) {
@ -801,39 +845,29 @@ this.NetworkStatsService = {
if (aCallback) {
aCallback(true, "no need to update");
}
return;
}
let index = 0;
this._db.saveStats(this.cachedStats[stats[index]],
function onSavedStats(error, result) {
if (DEBUG) {
debug("Application stats inserted in indexedDB");
}
function onSavedStats(error, result) {
debug("Application stats inserted in indexedDB");
// Clean up the |cachedStats| after updating.
if (index == stats.length - 1) {
this.cachedStats = Object.create(null);
if (!aCallback) {
return;
}
if (error) {
aCallback(false, error);
return;
}
// Clean up the |cachedStats| after updating.
if (index == stats.length - 1) {
this.cachedStats = Object.create(null);
if (aCallback) {
aCallback(true, "ok");
return;
}
return;
}
// Update is not finished, keep updating.
index += 1;
this._db.saveStats(this.cachedStats[stats[index]],
onSavedStats.bind(this, error, result));
}.bind(this));
// Update is not finished, keep updating.
index += 1;
this._db.saveStats(this.cachedStats[stats[index]],
onSavedStats.bind(this, error, result));
}.bind(this));
},
get maxCachedTraffic () {

View File

@ -44,6 +44,10 @@ NetworkStatsServiceProxy.prototype = {
" " + aRxBytes + " " + aTxBytes + " " + aIsAccumulative);
}
if (aCallback) {
aCallback = aCallback.notify;
}
NetworkStatsService.saveStats(aAppId, "", aNetwork, aTimeStamp,
aRxBytes, aTxBytes, aIsAccumulative,
aCallback);
@ -69,6 +73,10 @@ NetworkStatsServiceProxy.prototype = {
aIsAccumulative);
}
if (aCallback) {
aCallback = aCallback.notify;
}
NetworkStatsService.saveStats(0, aServiceType ,aNetwork, aTimeStamp,
aRxBytes, aTxBytes, aIsAccumulative,
aCallback);

View File

@ -7,6 +7,8 @@ const NETWORK_STATUS_READY = 0;
const NETWORK_STATUS_STANDBY = 1;
const NETWORK_STATUS_AWAY = 2;
const QUEUE_TYPE_UPDATE_STATS = 0;
var wifiId = '00';
function getNetworks(callback) {
@ -80,11 +82,11 @@ add_test(function test_update() {
});
add_test(function test_updateQueueIndex() {
NetworkStatsService.updateQueue = [{netId: 0, callbacks: null},
{netId: 1, callbacks: null},
{netId: 2, callbacks: null},
{netId: 3, callbacks: null},
{netId: 4, callbacks: null}];
NetworkStatsService.updateQueue = [{netId: 0, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
{netId: 1, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
{netId: 2, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
{netId: 3, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
{netId: 4, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS}];
var index = NetworkStatsService.updateQueueIndex(3);
do_check_eq(index, 3);
index = NetworkStatsService.updateQueueIndex(10);

View File

@ -36,7 +36,6 @@ function mokConvertNetworkInterface() {
add_test(function test_saveAppStats() {
var cachedStats = NetworkStatsService.cachedStats;
var timestamp = NetworkStatsService.cachedStatsDate.getTime();
var samples = 5;
// Create to fake nsINetworkInterfaces. As nsINetworkInterface can not
// be instantiated, these two vars will emulate it by filling the properties
@ -49,39 +48,39 @@ add_test(function test_saveAppStats() {
do_check_eq(Object.keys(cachedStats).length, 0);
for (var i = 0; i < samples; i++) {
nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false);
nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false,
function (success, message) {
do_check_eq(success, true);
nssProxy.saveAppStats(1, mobile, timestamp, 10, 20, false,
function (success, message) {
var key1 = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
var key2 = 1 + "" + mobileNetId + "";
nssProxy.saveAppStats(1, mobile, timestamp, 10, 20, false);
}
do_check_eq(Object.keys(cachedStats).length, 2);
do_check_eq(cachedStats[key1].appId, 1);
do_check_eq(cachedStats[key1].serviceType.length, 0);
do_check_eq(cachedStats[key1].networkId, wifi.id);
do_check_eq(cachedStats[key1].networkType, wifi.type);
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key1].rxBytes, 10);
do_check_eq(cachedStats[key1].txBytes, 20);
do_check_eq(cachedStats[key2].appId, 1);
do_check_eq(cachedStats[key1].serviceType.length, 0);
do_check_eq(cachedStats[key2].networkId, mobile.id);
do_check_eq(cachedStats[key2].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key2].rxBytes, 10);
do_check_eq(cachedStats[key2].txBytes, 20);
var key1 = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
var key2 = 1 + "" + mobileNetId + "";
do_check_eq(Object.keys(cachedStats).length, 2);
do_check_eq(cachedStats[key1].appId, 1);
do_check_eq(cachedStats[key1].serviceType.length, 0);
do_check_eq(cachedStats[key1].networkId, wifi.id);
do_check_eq(cachedStats[key1].networkType, wifi.type);
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key1].rxBytes, 50);
do_check_eq(cachedStats[key1].txBytes, 100);
do_check_eq(cachedStats[key2].appId, 1);
do_check_eq(cachedStats[key1].serviceType.length, 0);
do_check_eq(cachedStats[key2].networkId, mobile.id);
do_check_eq(cachedStats[key2].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key2].rxBytes, 50);
do_check_eq(cachedStats[key2].txBytes, 100);
run_next_test();
run_next_test();
});
});
});
add_test(function test_saveServiceStats() {
var timestamp = NetworkStatsService.cachedStatsDate.getTime();
var samples = 5;
// Create to fake nsINetworkInterfaces. As nsINetworkInterface can not
// be instantiated, these two vars will emulate it by filling the properties
@ -92,90 +91,80 @@ add_test(function test_saveServiceStats() {
// Insert fake mobile network interface in NetworkStatsService
var mobileNetId = NetworkStatsService.getNetworkId(mobile.id, mobile.type);
NetworkStatsService.updateCachedStats(
function (success, msg) {
NetworkStatsService.updateCachedStats(function (success, msg) {
do_check_eq(success, true);
var cachedStats = NetworkStatsService.cachedStats;
do_check_eq(Object.keys(cachedStats).length, 0);
var serviceType = 'FakeType';
nssProxy.saveServiceStats(serviceType, wifi, timestamp, 10, 20, false,
function (success, message) {
do_check_eq(success, true);
nssProxy.saveServiceStats(serviceType, mobile, timestamp, 10, 20, false,
function (success, message) {
do_check_eq(success, true);
var key1 = 0 + "" + serviceType +
NetworkStatsService.getNetworkId(wifi.id, wifi.type);
var key2 = 0 + "" + serviceType + mobileNetId + "";
var cachedStats = NetworkStatsService.cachedStats;
do_check_eq(Object.keys(cachedStats).length, 0);
do_check_eq(Object.keys(cachedStats).length, 2);
do_check_eq(cachedStats[key1].appId, 0);
do_check_eq(cachedStats[key1].serviceType, serviceType);
do_check_eq(cachedStats[key1].networkId, wifi.id);
do_check_eq(cachedStats[key1].networkType, wifi.type);
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key1].rxBytes, 10);
do_check_eq(cachedStats[key1].txBytes, 20);
do_check_eq(cachedStats[key2].appId, 0);
do_check_eq(cachedStats[key1].serviceType, serviceType);
do_check_eq(cachedStats[key2].networkId, mobile.id);
do_check_eq(cachedStats[key2].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key2].rxBytes, 10);
do_check_eq(cachedStats[key2].txBytes, 20);
var serviceType = 'FakeType';
for (var i = 0; i < samples; i++) {
nssProxy.saveServiceStats(serviceType, wifi, timestamp, 10, 20, false);
nssProxy.saveServiceStats(serviceType, mobile, timestamp, 10, 20, false);
}
var key1 = 0 + "" + serviceType +
NetworkStatsService.getNetworkId(wifi.id, wifi.type);
var key2 = 0 + "" + serviceType + mobileNetId + "";
do_check_eq(Object.keys(cachedStats).length, 2);
do_check_eq(cachedStats[key1].appId, 0);
do_check_eq(cachedStats[key1].serviceType, serviceType);
do_check_eq(cachedStats[key1].networkId, wifi.id);
do_check_eq(cachedStats[key1].networkType, wifi.type);
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key1].rxBytes, 50);
do_check_eq(cachedStats[key1].txBytes, 100);
do_check_eq(cachedStats[key2].appId, 0);
do_check_eq(cachedStats[key1].serviceType, serviceType);
do_check_eq(cachedStats[key2].networkId, mobile.id);
do_check_eq(cachedStats[key2].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
Math.floor(timestamp / 1000));
do_check_eq(cachedStats[key2].rxBytes, 50);
do_check_eq(cachedStats[key2].txBytes, 100);
run_next_test();
}
);
run_next_test();
});
});
});
});
add_test(function test_saveStatsWithDifferentDates() {
var today = NetworkStatsService.cachedStatsDate;
var tomorrow = new Date(today.getTime() + (24 * 60 * 60 * 1000));
var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
var mobile = {type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, id: "1234"};
var key = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
NetworkStatsService.updateCachedStats(function (success, message) {
do_check_eq(success, true);
NetworkStatsService.updateCachedStats(
function (success, msg) {
do_check_eq(Object.keys(NetworkStatsService.cachedStats).length, 0);
nssProxy.saveAppStats(1, mobile, today.getTime(), 10, 20, false,
function (success, message) {
do_check_eq(success, true);
do_check_eq(Object.keys(NetworkStatsService.cachedStats).length, 0);
nssProxy.saveAppStats(1, wifi, today.getTime(), 10, 20, false);
nssProxy.saveAppStats(1, mobile, today.getTime(), 10, 20, false);
var saveStatsCb = {
notify: function notify(success, message) {
do_check_eq(success, true);
var cachedStats = NetworkStatsService.cachedStats;
var key = 2 + "" +
NetworkStatsService.getNetworkId(mobile.id, mobile.type);
do_check_eq(Object.keys(cachedStats).length, 1);
do_check_eq(cachedStats[key].appId, 2);
do_check_eq(cachedStats[key].networkId, mobile.id);
do_check_eq(cachedStats[key].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key].date).getTime() / 1000,
Math.floor(tomorrow.getTime() / 1000));
do_check_eq(cachedStats[key].rxBytes, 30);
do_check_eq(cachedStats[key].txBytes, 40);
run_next_test();
}
};
nssProxy.saveAppStats(2, mobile, tomorrow.getTime(), 30, 40, false,
saveStatsCb);
}
);
function (success, message) {
do_check_eq(success, true);
var cachedStats = NetworkStatsService.cachedStats;
var key = 2 + "" +
NetworkStatsService.getNetworkId(mobile.id, mobile.type);
do_check_eq(Object.keys(cachedStats).length, 1);
do_check_eq(cachedStats[key].appId, 2);
do_check_eq(cachedStats[key].networkId, mobile.id);
do_check_eq(cachedStats[key].networkType, mobile.type);
do_check_eq(new Date(cachedStats[key].date).getTime() / 1000,
Math.floor(tomorrow.getTime() / 1000));
do_check_eq(cachedStats[key].rxBytes, 30);
do_check_eq(cachedStats[key].txBytes, 40);
run_next_test();
});
});
});
});
add_test(function test_saveStatsWithMaxCachedTraffic() {
@ -183,24 +172,24 @@ add_test(function test_saveStatsWithMaxCachedTraffic() {
var maxtraffic = NetworkStatsService.maxCachedTraffic;
var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
NetworkStatsService.updateCachedStats(
function (success, msg) {
NetworkStatsService.updateCachedStats(function (success, message) {
do_check_eq(success, true);
var cachedStats = NetworkStatsService.cachedStats;
do_check_eq(Object.keys(cachedStats).length, 0);
nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false,
function (success, message) {
do_check_eq(success, true);
var cachedStats = NetworkStatsService.cachedStats;
do_check_eq(Object.keys(cachedStats).length, 0);
nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false);
do_check_eq(Object.keys(cachedStats).length, 1);
nssProxy.saveAppStats(1, wifi, timestamp, maxtraffic, 20, false,
function (success, message) {
do_check_eq(success, true);
do_check_eq(Object.keys(cachedStats).length, 0);
nssProxy.saveAppStats(1, wifi, timestamp, maxtraffic, 20, false);
do_check_eq(Object.keys(cachedStats).length, 0);
run_next_test();
}
);
run_next_test();
});
});
});
});
function run_test() {

View File

@ -709,6 +709,8 @@ static const dom::ConstantSpec gWinProperties[] =
INT_CONSTANT(ERROR_FILE_NOT_FOUND),
INT_CONSTANT(ERROR_NO_MORE_FILES),
INT_CONSTANT(ERROR_PATH_NOT_FOUND),
INT_CONSTANT(ERROR_BAD_ARGUMENTS),
INT_CONSTANT(ERROR_NOT_SUPPORTED),
PROP_END
};

View File

@ -0,0 +1,21 @@
/* 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 obtaone at http://mozilla.org/MPL/2.0/. */
/**
* Options for nsINativeOSFileInternals::Read
*/
dictionary NativeOSFileReadOptions
{
/**
* If specified, convert the raw bytes to a String
* with the specified encoding. Otherwise, return
* the raw bytes as a TypedArray.
*/
DOMString? encoding;
/**
* If specified, limit the number of bytes to read.
*/
unsigned long long? bytes;
};

View File

@ -40,6 +40,7 @@ dictionary RTCInboundRTPStreamStats : RTCRTPStreamStats {
unsigned long packetsLost;
long mozAvSyncDelay;
long mozJitterBufferDelay;
long mozRtt;
};
dictionary RTCOutboundRTPStreamStats : RTCRTPStreamStats {
@ -58,7 +59,6 @@ dictionary RTCMediaStreamTrackStats : RTCStats {
unsigned long framesSent;
unsigned long framesReceived; // Only for remoteSource=true
unsigned long framesDecoded;
unsigned long first;
};
dictionary RTCMediaStreamStats : RTCStats {

View File

@ -245,6 +245,7 @@ WEBIDL_FILES = [
'MozWakeLock.webidl',
'MutationEvent.webidl',
'MutationObserver.webidl',
'NativeOSFileInternals.webidl',
'NetDashboard.webidl',
'NetworkOptions.webidl',
'Node.webidl',

View File

@ -39,7 +39,6 @@
#include "nsIFocusManager.h" // for nsIFocusManager
#include "nsIFormControl.h" // for nsIFormControl, etc
#include "nsIHTMLEditor.h" // for nsIHTMLEditor
#include "nsINativeKeyBindings.h" // for nsINativeKeyBindings
#include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
#include "nsIPresShell.h" // for nsIPresShell
@ -47,6 +46,7 @@
#include "nsISelectionController.h" // for nsISelectionController, etc
#include "nsISelectionPrivate.h" // for nsISelectionPrivate
#include "nsITransferable.h" // for kFileMime, kHTMLMime, etc
#include "nsIWidget.h" // for nsIWidget
#include "nsLiteralString.h" // for NS_LITERAL_STRING
#include "nsPIWindowRoot.h" // for nsPIWindowRoot
#include "nsServiceManagerUtils.h" // for do_GetService
@ -61,26 +61,8 @@ class nsPresContext;
using namespace mozilla;
using namespace mozilla::dom;
static nsINativeKeyBindings *sNativeEditorBindings = nullptr;
static nsINativeKeyBindings*
GetEditorKeyBindings()
{
static bool noBindings = false;
if (!sNativeEditorBindings && !noBindings) {
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor",
&sNativeEditorBindings);
if (!sNativeEditorBindings) {
noBindings = true;
}
}
return sNativeEditorBindings;
}
static void
DoCommandCallback(const char *aCommand, void *aData)
DoCommandCallback(Command aCommand, void* aData)
{
nsIDocument* doc = static_cast<nsIDocument*>(aData);
nsPIDOMWindow* win = doc->GetWindow();
@ -92,17 +74,19 @@ DoCommandCallback(const char *aCommand, void *aData)
return;
}
const char* commandStr = WidgetKeyboardEvent::GetCommandStr(aCommand);
nsCOMPtr<nsIController> controller;
root->GetControllerForCommand(aCommand, getter_AddRefs(controller));
root->GetControllerForCommand(commandStr, getter_AddRefs(controller));
if (!controller) {
return;
}
bool commandEnabled;
nsresult rv = controller->IsCommandEnabled(aCommand, &commandEnabled);
nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
NS_ENSURE_SUCCESS_VOID(rv);
if (commandEnabled) {
controller->DoCommand(aCommand);
controller->DoCommand(commandStr);
}
}
@ -125,12 +109,6 @@ nsEditorEventListener::~nsEditorEventListener()
}
}
/* static */ void
nsEditorEventListener::ShutDown()
{
NS_IF_RELEASE(sNativeEditorBindings);
}
nsresult
nsEditorEventListener::Connect(nsEditor* aEditor)
{
@ -526,19 +504,25 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
if (GetEditorKeyBindings() && ShouldHandleNativeKeyBindings(aKeyEvent)) {
if (ShouldHandleNativeKeyBindings(aKeyEvent)) {
// Now, ask the native key bindings to handle the event.
// XXX Note that we're not passing the keydown/keyup events to the native
// key bindings, which should be OK since those events are only handled on
// Windows for now, where we don't have native key bindings.
WidgetKeyboardEvent* keyEvent =
aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
MOZ_ASSERT(keyEvent,
"DOM key event's internal event must be WidgetKeyboardEvent");
nsIWidget* widget = keyEvent->widget;
// If the event is created by chrome script, the widget is always nullptr.
if (!widget) {
nsCOMPtr<nsIPresShell> ps = GetPresShell();
nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
widget = pc ? pc->GetNearestWidget() : nullptr;
NS_ENSURE_TRUE(widget, NS_OK);
}
nsCOMPtr<nsIDocument> doc = mEditor->GetDocument();
bool handled = sNativeEditorBindings->KeyPress(*keyEvent,
DoCommandCallback,
doc);
bool handled = widget->ExecuteNativeKeyBinding(
nsIWidget::NativeKeyBindingsForRichTextEditor,
*keyEvent, DoCommandCallback, doc);
if (handled) {
aKeyEvent->PreventDefault();
}

View File

@ -59,8 +59,6 @@ public:
void SpellCheckIfNeeded();
static NS_HIDDEN_(void) ShutDown();
protected:
nsresult InstallToEditor();
void UninstallFromEditor();

View File

@ -110,10 +110,12 @@ public:
Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; }
Log &operator <<(const char aStr[]) { mMessage << static_cast<const char*>(aStr); return *this; }
Log &operator <<(bool aBool) { mMessage << (aBool ? "true" : "false"); return *this; }
Log &operator <<(int32_t aInt) { mMessage << aInt; return *this; }
Log &operator <<(uint32_t aInt) { mMessage << aInt; return *this; }
Log &operator <<(int64_t aLong) { mMessage << aLong; return *this; }
Log &operator <<(uint64_t aLong) { mMessage << aLong; return *this; }
Log &operator <<(int aInt) { mMessage << aInt; return *this; }
Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; }
Log &operator <<(long aLong) { mMessage << aLong; return *this; }
Log &operator <<(unsigned long aLong) { mMessage << aLong; return *this; }
Log &operator <<(long long aLong) { mMessage << aLong; return *this; }
Log &operator <<(unsigned long long aLong) { mMessage << aLong; return *this; }
Log &operator <<(Float aFloat) { mMessage << aFloat; return *this; }
Log &operator <<(double aDouble) { mMessage << aDouble; return *this; }
template <typename T, typename Sub>

View File

@ -203,7 +203,7 @@ SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles()
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
tiles, mRetainedWidth, mRetainedHeight,
mResolution);
mResolution, mFrameResolution.scale);
}
bool

View File

@ -608,7 +608,7 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
}
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
tiles, mRetainedWidth, mRetainedHeight,
mResolution);
mResolution, mFrameResolution.scale);
}
void

View File

@ -34,7 +34,6 @@ TiledLayerBufferComposite::TiledLayerBufferComposite()
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
const nsIntRegion& aOldPaintedRegion)
: mFrameResolution(1.0)
{
mUninitialized = false;
mHasDoubleBufferedTiles = false;
@ -43,6 +42,7 @@ TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocat
mRetainedWidth = aDescriptor.retainedWidth();
mRetainedHeight = aDescriptor.retainedHeight();
mResolution = aDescriptor.resolution();
mFrameResolution = CSSToScreenScale(aDescriptor.frameResolution());
// Combine any valid content that wasn't already uploaded
nsIntRegion oldPaintedRegion(aOldPaintedRegion);

View File

@ -8,6 +8,7 @@
#include <math.h> // for fabsf, pow, powf
#include <algorithm> // for max
#include "AsyncPanZoomController.h" // for AsyncPanZoomController
#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
#include "FrameMetrics.h" // for FrameMetrics
#include "mozilla/Attributes.h" // for MOZ_FINAL
#include "mozilla/Preferences.h" // for Preferences
@ -65,9 +66,9 @@ namespace layers {
*/
/**
* "apz.max_velocity_pixels_per_ms"
* "apz.max_velocity_inches_per_ms"
*
* Maximum velocity in pixels per millisecond. Velocity will be capped at this
* Maximum velocity in inches per millisecond. Velocity will be capped at this
* value if a faster fling occurs. Negative values indicate unlimited velocity.
*
* The default value is -1.0f, set in gfxPrefs.h
@ -84,7 +85,7 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) {
float newVelocity = mAxisLocked ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds();
if (gfxPrefs::APZMaxVelocity() > 0.0f) {
newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity());
newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI());
}
mVelocity = newVelocity;

View File

@ -286,6 +286,7 @@ struct SurfaceDescriptorTiles {
int retainedWidth;
int retainedHeight;
float resolution;
float frameResolution;
};
struct OpUseTiledLayerBuffer {

View File

@ -53,27 +53,29 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
if (MOZ_UNLIKELY(!mFace)) {
// No face. This unfortunate situation might happen if the font
// file is (re)moved at the wrong time.
aMetrics->emHeight = mGfxFont->GetStyle()->size;
aMetrics->emAscent = 0.8 * aMetrics->emHeight;
aMetrics->emDescent = 0.2 * aMetrics->emHeight;
aMetrics->maxAscent = aMetrics->emAscent;
aMetrics->maxDescent = aMetrics->maxDescent;
aMetrics->maxHeight = aMetrics->emHeight;
const gfxFloat emHeight = mGfxFont->GetStyle()->size;
aMetrics->emHeight = emHeight;
aMetrics->maxAscent = aMetrics->emAscent = 0.8 * emHeight;
aMetrics->maxDescent = aMetrics->emDescent = 0.2 * emHeight;
aMetrics->maxHeight = emHeight;
aMetrics->internalLeading = 0.0;
aMetrics->externalLeading = 0.2 * aMetrics->emHeight;
aSpaceGlyph = 0;
aMetrics->spaceWidth = 0.5 * aMetrics->emHeight;
aMetrics->maxAdvance = aMetrics->spaceWidth;
aMetrics->aveCharWidth = aMetrics->spaceWidth;
aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth;
aMetrics->xHeight = 0.5 * aMetrics->emHeight;
aMetrics->underlineSize = aMetrics->emHeight / 14.0;
aMetrics->underlineOffset = -aMetrics->underlineSize;
aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight;
aMetrics->strikeoutSize = aMetrics->underlineSize;
aMetrics->superscriptOffset = aMetrics->xHeight;
aMetrics->subscriptOffset = aMetrics->xHeight;
aMetrics->externalLeading = 0.2 * emHeight;
const gfxFloat spaceWidth = 0.5 * emHeight;
aMetrics->spaceWidth = spaceWidth;
aMetrics->maxAdvance = spaceWidth;
aMetrics->aveCharWidth = spaceWidth;
aMetrics->zeroOrAveCharWidth = spaceWidth;
const gfxFloat xHeight = 0.5 * emHeight;
aMetrics->xHeight = xHeight;
aMetrics->superscriptOffset = xHeight;
aMetrics->subscriptOffset = xHeight;
const gfxFloat underlineSize = emHeight / 14.0;
aMetrics->underlineSize = underlineSize;
aMetrics->underlineOffset = -underlineSize;
aMetrics->strikeoutOffset = 0.25 * emHeight;
aMetrics->strikeoutSize = underlineSize;
*aSpaceGlyph = 0;
return;
}

View File

@ -106,7 +106,7 @@ private:
DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f);
DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);
DECL_GFX_PREF(Once, "apz.max_event_acceleration", APZMaxEventAcceleration, float, 999.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_pixels_per_ms", APZMaxVelocity, float, -1.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_inches_per_ms", APZMaxVelocity, float, -1.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5);
DECL_GFX_PREF(Once, "gfx.android.rgb16.force", AndroidRGB16Force, bool, false);

View File

@ -123,7 +123,6 @@ struct ObjectsExtraSizes
macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
@ -406,6 +405,7 @@ struct ZoneStats
macro(Other, IsLiveGCThing, typeObjectsGCHeap) \
macro(Other, NotLiveGCThing, typeObjectsMallocHeap) \
macro(Other, NotLiveGCThing, typePool) \
macro(Other, NotLiveGCThing, baselineStubsOptimized) \
ZoneStats()
: FOR_EACH_SIZE(ZERO_SIZE)
@ -501,7 +501,6 @@ struct CompartmentStats
macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
macro(Other, NotLiveGCThing, baselineData) \
macro(Other, NotLiveGCThing, baselineStubsFallback) \
macro(Other, NotLiveGCThing, baselineStubsOptimized) \
macro(Other, NotLiveGCThing, ionData) \
macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \
macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \

View File

@ -733,6 +733,15 @@ UnsizedArrayTypeDescr::dimension(JSContext *cx, unsigned int argc, jsval *vp)
return true;
}
bool
js::IsTypedObjectArray(JSObject &obj)
{
if (!obj.is<TypedObject>())
return false;
TypeDescr& d = obj.as<TypedObject>().typeDescr();
return d.is<SizedArrayTypeDescr>() || d.is<UnsizedArrayTypeDescr>();
}
/*********************************
* StructType class
*/

View File

@ -295,7 +295,8 @@ class X4TypeDescr : public SizedTypeDescr
macro_(X4TypeDescr::TYPE_INT32, int32_t, int32) \
macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
bool IsTypedObjectClass(const Class *clasp); // Defined in TypedArrayObject.h
bool IsTypedObjectClass(const Class *clasp); // Defined below
bool IsTypedObjectArray(JSObject& obj);
bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
HandleTypeDescr obj,

View File

@ -1510,7 +1510,7 @@ function MapTypedParImplDepth1(inArray, inArrayType, outArrayType, func) {
if (outGrainTypeIsComplex)
SetTypedObjectValue(outGrainType, outArray, outOffset, r);
else
outArray[i] = r;
UnsafePutElements(outArray, i, r);
}
inOffset += inGrainTypeSize;
outOffset += outGrainTypeSize;

View File

@ -107,21 +107,6 @@ gc::GetPageFaultCount()
return pmc.PageFaultCount;
}
void *
gc::AllocateMappedObject(int fd, int *new_fd, size_t offset, size_t length,
size_t alignment, size_t header)
{
// TODO: to be implemented.
return nullptr;
}
// Deallocate mapped memory for object.
void
gc::DeallocateMappedObject(int fd, void *p, size_t length)
{
// TODO: to be implemented.
}
#elif defined(SOLARIS)
#include <sys/mman.h>
@ -180,28 +165,10 @@ gc::GetPageFaultCount()
return 0;
}
void *
gc::AllocateMappedObject(int fd, int *new_fd, size_t offset, size_t length,
size_t alignment, size_t header)
{
// TODO: to be implemented.
return nullptr;
}
// Deallocate mapped memory for object.
void
gc::DeallocateMappedObject(int fd, void *p, size_t length)
{
// TODO: to be implemented.
}
#elif defined(XP_UNIX)
#include <algorithm>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void
@ -318,90 +285,6 @@ gc::GetPageFaultCount()
return usage.ru_majflt;
}
void *
gc::AllocateMappedObject(int fd, int *new_fd, size_t offset, size_t length,
size_t alignment, size_t header)
{
#define NEED_PAGE_ALIGNED 0
size_t pa_start; // Page aligned starting
size_t pa_end; // Page aligned ending
size_t pa_size; // Total page aligned size
size_t page_size = sysconf(_SC_PAGESIZE); // Page size
bool page_for_header = false; // Do we need an additional page for header?
struct stat st;
uint8_t *buf;
// Make sure file exists and do sanity check for offset and size.
if (fstat(fd, &st) < 0 || offset >= (size_t) st.st_size ||
length == 0 || length > (size_t) st.st_size - offset)
return nullptr;
// Check for minimal alignment requirement.
#if NEED_PAGE_ALIGNED
alignment = std::max(alignment, page_size);
#endif
if (offset & (alignment - 1))
return nullptr;
// Page aligned starting of the offset.
pa_start = offset & ~(page_size - 1);
// Calculate page aligned ending by adding one page to the page aligned
// starting of data end position(offset + length - 1).
pa_end = ((offset + length - 1) & ~(page_size - 1)) + page_size;
pa_size = pa_end - pa_start;
// Do we need one more page for header?
if (offset - pa_start < header) {
page_for_header = true;
pa_size += page_size;
}
// Ask for a continuous memory location.
buf = (uint8_t *) MapMemory(pa_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (buf == MAP_FAILED)
return nullptr;
// Duplicate a new fd for mapping, so each cloned object uses a different fd.
*new_fd = dup(fd);
// If there's an additional page for header, don't map that page to file.
if (page_for_header) {
buf = (uint8_t *) mmap(buf + page_size, pa_size - page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED, *new_fd, pa_start);
} else {
buf = (uint8_t *) mmap(buf, pa_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED, *new_fd, pa_start);
}
if (buf == MAP_FAILED) {
close(*new_fd);
return nullptr;
}
// Reset the data before target file, which we don't need to see.
memset(buf, 0, offset - pa_start);
// Reset the data after target file, which we don't need to see.
memset(buf + (offset - pa_start) + length, 0, pa_end - (offset + length));
return buf + (offset - pa_start) - header;
}
void
gc::DeallocateMappedObject(int fd, void *p, size_t length)
{
void *pa_start; // Page aligned starting
size_t page_size = sysconf(_SC_PAGESIZE); // Page size
size_t total_size; // Total allocated size
// The fd is not needed anymore.
close(fd);
pa_start = (void *)(uintptr_t(p) & ~(page_size - 1));
total_size = ((uintptr_t(p) + length) & ~(page_size - 1)) + page_size - uintptr_t(pa_start);
munmap(pa_start, total_size);
}
#else
#error "Memory mapping functions are not defined for your OS."
#endif

View File

@ -41,19 +41,6 @@ MarkPagesInUse(JSRuntime *rt, void *p, size_t size);
size_t
GetPageFaultCount();
// Allocate mapped memory for object from file descriptor, offset and length
// of the file.
// The new_fd is duplicated from original fd, for the purpose of cloned object.
// The offset must be aligned according to alignment requirement.
// An additional page might be allocated depending on offset and header size given.
void *
AllocateMappedObject(int fd, int *new_fd, size_t offset, size_t length,
size_t alignment, size_t header);
// Deallocate mapped memory of the object.
void
DeallocateMappedObject(int fd, void *p, size_t length);
} // namespace gc
} // namespace js

View File

@ -42,6 +42,9 @@ JS::Zone::Zone(JSRuntime *rt)
gcGrayRoots(),
data(nullptr),
types(this)
#ifdef JS_ION
, jitZone_(nullptr)
#endif
{
/* Ensure that there are no vtables to mess us up here. */
JS_ASSERT(reinterpret_cast<JS::shadow::Zone *>(this) ==
@ -54,6 +57,10 @@ Zone::~Zone()
{
if (this == runtimeFromMainThread()->systemZone)
runtimeFromMainThread()->systemZone = nullptr;
#ifdef JS_ION
js_delete(jitZone_);
#endif
}
bool
@ -169,6 +176,9 @@ void
Zone::discardJitCode(FreeOp *fop)
{
#ifdef JS_ION
if (!jitZone())
return;
if (isPreservingCode()) {
PurgeJITCaches(this);
} else {
@ -205,8 +215,7 @@ Zone::discardJitCode(FreeOp *fop)
script->resetUseCount();
}
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next())
jit::FinishDiscardJitCode(fop, comp);
jitZone()->optimizedStubSpace()->free();
}
#endif
}
@ -219,6 +228,20 @@ Zone::gcNumber()
return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gcNumber;
}
#ifdef JS_ION
js::jit::JitZone *
Zone::createJitZone(JSContext *cx)
{
MOZ_ASSERT(!jitZone_);
if (!cx->runtime()->getJitRuntime(cx))
return nullptr;
jitZone_ = cx->new_<js::jit::JitZone>();
return jitZone_;
}
#endif
JS::Zone *
js::ZoneOfObject(const JSObject &obj)
{

View File

@ -18,6 +18,10 @@
namespace js {
namespace jit {
class JitZone;
}
/*
* Encapsulates the data needed to perform allocation. Typically there is
* precisely one of these per zone (|cx->zone().allocator|). However, in
@ -280,7 +284,9 @@ struct Zone : public JS::shadow::Zone,
void discardJitCode(js::FreeOp *fop);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *typePool);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *typePool,
size_t *baselineStubsOptimized);
void setGCLastBytes(size_t lastBytes, js::JSGCInvocationKind gckind);
void reduceGCTriggerBytes(size_t amount);
@ -316,6 +322,19 @@ struct Zone : public JS::shadow::Zone,
private:
void sweepBreakpoints(js::FreeOp *fop);
#ifdef JS_ION
js::jit::JitZone *jitZone_;
js::jit::JitZone *createJitZone(JSContext *cx);
public:
js::jit::JitZone *getJitZone(JSContext *cx) {
return jitZone_ ? jitZone_ : createJitZone(cx);
}
js::jit::JitZone *jitZone() {
return jitZone_;
}
#endif
};
} /* namespace JS */

View File

@ -0,0 +1,20 @@
function test(a) {
var total = 0;
for (var i=0; i<100; i++) {
var j = 1;
var b = a.a
if (b) {
j += b.test;
}
total += j;
}
print(total)
}
var a1 = {"a": {"test":1}};
var a2 = {"a": undefined};
test(a1)
test(a2)
test(a1)
test(a2)

View File

@ -0,0 +1,63 @@
// Bug 977853 -- Pared down version of script exhibiting negative
// interaction with convert to doubles optimization. See bug for gory
// details.
if (!getBuildConfiguration().parallelJS)
quit();
load(libdir + "parallelarray-helpers.js")
var numIters = 5;
var golden_output;
function PJS_div4(v, s)
{
return [ v[0]/s, v[1]/s, v[2]/s, v[3]/s ];
}
function PJS_normalized(v)
{
var d = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
d = d > 0.0 ? d : 1.0;
var result = [ v[0]/d, v[1]/d, v[2]/d, 1.0 ];
return result;
}
// This is the elemental function passed to mapPar
function PJS_displace(p)
{
var position = [p[0], p[1], p[2], 1.0];
var normal = position;
var roughness = 0.025 / 0.35;
normal = PJS_normalized(PJS_div4(normal, roughness));
return null;
}
var NUM_VERTEX_COMPONENTS = 3;
var initPos, nVertices;
var userData = {
nVertices : 25, //2880,
initPos : [],
};
function setup() {
for(var k = 0; k < NUM_VERTEX_COMPONENTS*userData.nVertices; k++) {
userData.initPos[k] = k/1000;
}
nVertices = userData.nVertices;
initPos = new Array(nVertices);
for(var i=0, j=0; i<nVertices; i++, j+=NUM_VERTEX_COMPONENTS) {
initPos[i] = [userData.initPos[j],
userData.initPos[j+1],
userData.initPos[j+2]];
}
}
function SimulatePJS() {
var curPosAndNor;
// Measure Parallel Execution
assertParallelExecSucceeds(
function(m) { return initPos.mapPar(PJS_displace, m); },
function() { });
}
var start_time, elapsed_parallel = 0, elapsed_sequential = 0;
setup();
SimulatePJS();

View File

@ -3,15 +3,6 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() {
var a = range(0, 64);
function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10;
var k = 11;
var j = 12;
@ -34,11 +25,6 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h;
case 8: return i; case 9: return j;
case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
}
});
}

View File

@ -3,15 +3,6 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() {
var a = range(0, 64);
function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10;
var k = 11;
var j = 12;
@ -32,11 +23,6 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h;
case 8: return i; case 9: return j;
case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
}
};
};

View File

@ -463,24 +463,8 @@ HandleDynamicLinkFailure(JSContext *cx, CallArgs args, AsmJSModule &module, Hand
return false;
// Call the function we just recompiled.
unsigned argc = args.length();
InvokeArgs args2(cx);
if (!args2.init(argc))
return false;
args2.setCallee(ObjectValue(*fun));
args2.setThis(args.thisv());
for (unsigned i = 0; i < argc; i++)
args2[i].set(args[i]);
if (!Invoke(cx, args2))
return false;
args.rval().set(args2.rval());
return true;
args.setCallee(ObjectValue(*fun));
return Invoke(cx, args);
}
#ifdef MOZ_VTUNE

View File

@ -532,7 +532,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
// If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
// This may be wrong for the last frame of ArgumentCheck bailout, but
// that will be fixed later.
if (cx->runtime()->spsProfiler.enabled() && ionScript->hasSPSInstrumentation()) {
if (ionScript->hasSPSInstrumentation()) {
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on frame!");
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
}

View File

@ -1087,7 +1087,7 @@ class ICStubCompiler
ICStubSpace *getStubSpace(JSScript *script) {
if (ICStub::CanMakeCalls(kind))
return script->baselineScript()->fallbackStubSpace();
return script->compartment()->jitCompartment()->optimizedStubSpace();
return script->zone()->jitZone()->optimizedStubSpace();
}
};

View File

@ -972,8 +972,7 @@ CodeGenerator::visitLambda(LLambda *lir)
JS_ASSERT(!info.singletonType);
masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap);
masm.initGCThing(output, tempReg, info.fun);
masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
emitLambdaInit(output, scopeChain, info);
@ -3337,29 +3336,6 @@ CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
return callVM(CreateDerivedTypedObjInfo, lir);
}
bool
CodeGenerator::visitNewSlots(LNewSlots *lir)
{
Register temp1 = ToRegister(lir->temp1());
Register temp2 = ToRegister(lir->temp2());
Register temp3 = ToRegister(lir->temp3());
Register output = ToRegister(lir->output());
masm.mov(ImmPtr(GetIonContext()->runtime), temp1);
masm.mov(ImmWord(lir->mir()->nslots()), temp2);
masm.setupUnalignedABICall(2, temp3);
masm.passABIArg(temp1);
masm.passABIArg(temp2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
masm.testPtr(output, output);
if (!bailoutIf(Assembler::Zero, lir->snapshot()))
return false;
return true;
}
bool CodeGenerator::visitAtan2D(LAtan2D *lir)
{
Register temp = ToRegister(lir->temp());
@ -3408,8 +3384,7 @@ CodeGenerator::visitNewArray(LNewArray *lir)
if (!addOutOfLineCode(ool))
return false;
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.initGCThing(objReg, tempReg, templateObject);
masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
masm.bind(ool->rejoin());
return true;
@ -3495,8 +3470,7 @@ CodeGenerator::visitNewObject(LNewObject *lir)
if (!addOutOfLineCode(ool))
return false;
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.initGCThing(objReg, tempReg, templateObject);
masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
masm.bind(ool->rejoin());
return true;
@ -3531,14 +3505,13 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
if (!ool)
return false;
masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(objReg, tempReg, templateObj);
masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
masm.bind(ool->rejoin());
return true;
}
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
HandleTypeObject, HeapSlot *);
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape, HandleTypeObject);
static const VMFunction NewCallObjectInfo =
FunctionInfo<NewCallObjectFn>(NewCallObject);
@ -3551,22 +3524,11 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
JSObject *templateObj = lir->mir()->templateObject();
// If we have a template object, we can inline call object creation.
OutOfLineCode *ool;
if (lir->slots()->isRegister()) {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ToRegister(lir->slots())),
StoreRegisterTo(objReg));
} else {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ImmPtr(nullptr)),
StoreRegisterTo(objReg));
}
OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type())),
StoreRegisterTo(objReg));
if (!ool)
return false;
@ -3574,11 +3536,7 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
// Objects can only be given singleton types in VM calls.
masm.jump(ool->entry());
} else {
masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(objReg, tempReg, templateObj);
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
}
masm.bind(ool->rejoin());
@ -3595,17 +3553,6 @@ CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
JSObject *templateObj = lir->mir()->templateObj();
emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
// NB: !lir->slots()->isRegister() implies that there is no slots
// array at all, and the memory is already zeroed when copying
// from the template object
if (lir->slots()->isRegister()) {
Register slotsReg = ToRegister(lir->slots());
JS_ASSERT(slotsReg != resultReg);
masm.storePtr(slotsReg, Address(resultReg, JSObject::offsetOfSlots()));
}
return true;
}
@ -3664,8 +3611,7 @@ CodeGenerator::visitNewStringObject(LNewStringObject *lir)
if (!ool)
return false;
masm.newGCThing(output, temp, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(output, temp, templateObj);
masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
masm.loadStringLength(input, temp);
@ -3910,7 +3856,7 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
return false;
// Allocate. If the FreeList is empty, call to VM, which may GC.
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
// Initialize based on the templateObject.
masm.bind(ool->rejoin());
@ -4979,6 +4925,70 @@ JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
return code;
}
JitCode *
JitRuntime::generateMallocStub(JSContext *cx)
{
const Register regReturn = CallTempReg0;
const Register regNBytes = CallTempReg0;
const Register regRuntime = CallTempReg1;
const Register regTemp = CallTempReg1;
MacroAssembler masm(cx);
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(regNBytes);
masm.PushRegsInMask(regs);
masm.setupUnalignedABICall(2, regTemp);
masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
masm.passABIArg(regRuntime);
masm.passABIArg(regNBytes);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MallocWrapper));
masm.storeCallResult(regReturn);
masm.PopRegsInMask(regs);
masm.ret();
Linker linker(masm);
JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "MallocStub");
#endif
return code;
}
JitCode *
JitRuntime::generateFreeStub(JSContext *cx)
{
const Register regSlots = CallTempReg0;
const Register regTemp = CallTempReg1;
MacroAssembler masm(cx);
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(regSlots);
masm.PushRegsInMask(regs);
masm.setupUnalignedABICall(1, regTemp);
masm.passABIArg(regSlots);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js_free));
masm.PopRegsInMask(regs);
masm.ret();
Linker linker(masm);
JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "FreeStub");
#endif
return code;
}
typedef bool (*CharCodeAtFn)(JSContext *, HandleString, int32_t, uint32_t *);
static const VMFunction CharCodeAtInfo = FunctionInfo<CharCodeAtFn>(jit::CharCodeAt);
@ -5632,9 +5642,7 @@ CodeGenerator::visitArrayConcat(LArrayConcat *lir)
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
// Try to allocate an object.
JSObject *templateObj = lir->mir()->templateObj();
masm.newGCThing(temp1, temp2, templateObj, &fail, lir->mir()->initialHeap());
masm.initGCThing(temp1, temp2, templateObj);
masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
masm.jump(&call);
{
masm.bind(&fail);
@ -6005,8 +6013,7 @@ CodeGenerator::visitRest(LRest *lir)
JSObject *templateObject = lir->mir()->templateObject();
Label joinAlloc, failAlloc;
masm.newGCThing(temp2, temp0, templateObject, &failAlloc, gc::DefaultHeap);
masm.initGCThing(temp2, temp0, templateObject);
masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
masm.jump(&joinAlloc);
{
masm.bind(&failAlloc);

View File

@ -131,7 +131,6 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDirectEvalV(LCallDirectEvalV *lir);
bool visitDoubleToInt32(LDoubleToInt32 *lir);
bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
bool visitNewSlots(LNewSlots *lir);
bool visitNewArrayCallVM(LNewArray *lir);
bool visitNewArray(LNewArray *lir);
bool visitOutOfLineNewArray(OutOfLineNewArray *ool);

View File

@ -268,6 +268,16 @@ JitRuntime::initialize(JSContext *cx)
if (!shapePreBarrier_)
return false;
IonSpew(IonSpew_Codegen, "# Emitting malloc stub");
mallocStub_ = generateMallocStub(cx);
if (!mallocStub_)
return false;
IonSpew(IonSpew_Codegen, "# Emitting free stub");
freeStub_ = generateFreeStub(cx);
if (!freeStub_)
return false;
IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers");
for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
if (!generateVMWrapper(cx, *fun))
@ -455,9 +465,8 @@ jit::RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode)
}
}
JitCompartment::JitCompartment(JitRuntime *rt)
: rt(rt),
stubCodes_(nullptr),
JitCompartment::JitCompartment()
: stubCodes_(nullptr),
baselineCallReturnAddr_(nullptr),
baselineGetPropReturnAddr_(nullptr),
baselineSetPropReturnAddr_(nullptr),
@ -562,7 +571,7 @@ JitCompartment::mark(JSTracer *trc, JSCompartment *compartment)
FinishAllOffThreadCompilations(compartment);
// Free temporary OSR buffer.
rt->freeOsrTempData();
trc->runtime->jitRuntime()->freeOsrTempData();
}
void
@ -2701,14 +2710,6 @@ jit::FinishInvalidation(FreeOp *fop, JSScript *script)
FinishInvalidationOf(fop, script, script->parallelIonScript(), true);
}
void
jit::FinishDiscardJitCode(FreeOp *fop, JSCompartment *comp)
{
// Free optimized baseline stubs.
if (comp->jitCompartment())
comp->jitCompartment()->optimizedStubSpace()->free();
}
void
jit::MarkValueFromIon(JSRuntime *rt, Value *vp)
{
@ -2918,13 +2919,4 @@ AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
script->baselineScript()->resetActive();
}
}
if (comp_) {
FinishDiscardJitCode(fop, comp_);
} else {
for (CompartmentsInZoneIter comp(zone_); !comp.done(); comp.next()) {
if (comp->principals)
FinishDiscardJitCode(fop, comp);
}
}
}

View File

@ -1647,42 +1647,31 @@ TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool fi
input = inputUnbox->input();
}
if (test->getOperand(0) == input && direction == TRUE_BRANCH) {
*eliminated = true;
if (inputUnbox)
inputUnbox->makeInfallible();
barrier->replaceAllUsesWith(barrier->input());
return;
}
MDefinition *subject = nullptr;
bool removeUndefined;
bool removeNull;
test->filtersUndefinedOrNull(direction == TRUE_BRANCH, &subject, &removeUndefined, &removeNull);
if (!test->getOperand(0)->isCompare())
// The Test doesn't filter undefined nor null.
if (!subject)
return;
MCompare *compare = test->getOperand(0)->toCompare();
MCompare::CompareType compareType = compare->compareType();
if (compareType != MCompare::Compare_Undefined && compareType != MCompare::Compare_Null)
return;
if (compare->getOperand(0) != input)
// Make sure the subject equals the input to the TypeBarrier.
if (subject != input)
return;
JSOp op = compare->jsop();
JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
op == JSOP_NE || op == JSOP_STRICTNE);
if ((direction == TRUE_BRANCH) != (op == JSOP_NE || op == JSOP_STRICTNE))
// When the TypeBarrier filters undefined, the test must at least also do,
// this, before the TypeBarrier can get removed.
if (!removeUndefined && filtersUndefined)
return;
// A test 'if (x.f != null)' or 'if (x.f != undefined)' filters both null
// and undefined. If strict equality is used, only the specified rhs is
// tested for.
if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
if (compareType == MCompare::Compare_Undefined && !filtersUndefined)
return;
if (compareType == MCompare::Compare_Null && !filtersNull)
return;
}
// When the TypeBarrier filters null, the test must at least also do,
// this, before the TypeBarrier can get removed.
if (!removeNull && filtersNull)
return;
// Eliminate the TypeBarrier. The possible TypeBarrier unboxing is kept,
// but made infallible.
*eliminated = true;
if (inputUnbox)
inputUnbox->makeInfallible();

View File

@ -189,18 +189,21 @@ GetJumpOffset(jsbytecode *pc)
}
IonBuilder::CFGState
IonBuilder::CFGState::If(jsbytecode *join, MBasicBlock *ifFalse)
IonBuilder::CFGState::If(jsbytecode *join, MTest *test)
{
CFGState state;
state.state = IF_TRUE;
state.stopAt = join;
state.branch.ifFalse = ifFalse;
state.branch.ifFalse = test->ifFalse();
state.branch.test = test;
return state;
}
IonBuilder::CFGState
IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBlock *ifFalse)
IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test)
{
MBasicBlock *ifFalse = test->ifFalse();
CFGState state;
// If the end of the false path is the same as the start of the
// false path, then the "else" block is empty and we can devolve
@ -213,6 +216,7 @@ IonBuilder::CFGState::IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBl
state.stopAt = trueEnd;
state.branch.falseEnd = falseEnd;
state.branch.ifFalse = ifFalse;
state.branch.test = test;
return state;
}
@ -223,6 +227,7 @@ IonBuilder::CFGState::AndOr(jsbytecode *join, MBasicBlock *joinStart)
state.state = AND_OR;
state.stopAt = join;
state.branch.ifFalse = joinStart;
state.branch.test = nullptr;
return state;
}
@ -1885,6 +1890,10 @@ IonBuilder::processIfElseTrueEnd(CFGState &state)
pc = state.branch.ifFalse->pc();
setCurrentAndSpecializePhis(state.branch.ifFalse);
graph().moveBlockToEnd(current);
if (state.branch.test)
filterTypesAtTest(state.branch.test);
return ControlStatus_Jumped;
}
@ -3008,6 +3017,64 @@ IonBuilder::tableSwitch(JSOp op, jssrcnote *sn)
return ControlStatus_Jumped;
}
bool
IonBuilder::filterTypesAtTest(MTest *test)
{
JS_ASSERT(test->ifTrue() == current || test->ifFalse() == current);
bool trueBranch = test->ifTrue() == current;
MDefinition *subject = nullptr;
bool removeUndefined;
bool removeNull;
test->filtersUndefinedOrNull(trueBranch, &subject, &removeUndefined, &removeNull);
// The test filters no undefined or null.
if (!subject)
return true;
// There is no TypeSet that can get filtered.
if (!subject->resultTypeSet())
return true;
// Only do this optimization if the typeset does contains null or undefined.
if ((!(removeUndefined && subject->resultTypeSet()->hasType(types::Type::UndefinedType())) &&
!(removeNull && subject->resultTypeSet()->hasType(types::Type::NullType()))))
{
return true;
}
// Find all values on the stack that correspond to the subject
// and replace it with a MIR with filtered TypeSet information.
// Create the replacement MIR lazily upon first occurence.
MDefinition *replace = nullptr;
for (uint32_t i = 0; i < current->stackDepth(); i++) {
if (current->getSlot(i) != subject)
continue;
// Create replacement MIR with filtered TypesSet.
if (!replace) {
types::TemporaryTypeSet *type =
subject->resultTypeSet()->filter(alloc_->lifoAlloc(), removeUndefined,
removeNull);
if (!type)
return false;
replace = ensureDefiniteTypeSet(subject, type);
// Make sure we don't hoist it above the MTest, we can use the
// 'dependency' of an MInstruction. This is normally used by
// Alias Analysis, but won't get overwritten, since this
// instruction doesn't have an AliasSet.
replace->setDependency(test);
}
current->setSlot(i, replace);
}
return true;
}
bool
IonBuilder::jsop_label()
{
@ -3426,7 +3493,7 @@ IonBuilder::jsop_ifeq(JSOp op)
// IF case, the IFEQ offset is the join point.
switch (SN_TYPE(sn)) {
case SRC_IF:
if (!cfgStack_.append(CFGState::If(falseStart, ifFalse)))
if (!cfgStack_.append(CFGState::If(falseStart, test)))
return false;
break;
@ -3445,7 +3512,7 @@ IonBuilder::jsop_ifeq(JSOp op)
JS_ASSERT(falseEnd > trueEnd);
JS_ASSERT(falseEnd >= falseStart);
if (!cfgStack_.append(CFGState::IfElse(trueEnd, falseEnd, ifFalse)))
if (!cfgStack_.append(CFGState::IfElse(trueEnd, falseEnd, test)))
return false;
break;
}
@ -3458,6 +3525,9 @@ IonBuilder::jsop_ifeq(JSOp op)
// it's the next instruction.
setCurrentAndSpecializePhis(ifTrue);
// Filter the types in the true branch.
filterTypesAtTest(test);
return true;
}
@ -4597,23 +4667,9 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// creation.
CallObject *templateObj = inspector->templateCallObject();
// If the CallObject needs dynamic slots, allocate those now.
MInstruction *slots;
if (templateObj->hasDynamicSlots()) {
size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
templateObj->lastProperty()->slotSpan(templateObj->getClass()),
templateObj->getClass());
slots = MNewSlots::New(alloc(), nslots);
} else {
slots = MConstant::New(alloc(), NullValue());
}
current->add(slots);
// Allocate the actual object. It is important that no intervening
// instructions could potentially bailout, thus leaking the dynamic slots
// pointer. Run-once scripts need a singleton type, so always do a VM call
// in such cases.
MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce(), slots);
// Allocate the object. Run-once scripts need a singleton type, so always do
// a VM call in such cases.
MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce());
current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here,
@ -4622,14 +4678,20 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
// Initialize argument slots.
MSlots *slots = nullptr;
for (AliasedFormalIter i(script()); i; i++) {
unsigned slot = i.scopeSlot();
unsigned formal = i.frameIndex();
MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
if (slot >= templateObj->numFixedSlots())
if (slot >= templateObj->numFixedSlots()) {
if (!slots) {
slots = MSlots::New(alloc(), callObj);
current->add(slots);
}
current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
else
} else {
current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
}
}
return callObj;
@ -6242,6 +6304,26 @@ IonBuilder::ensureDefiniteType(MDefinition *def, JSValueType definiteType)
return replace;
}
MDefinition *
IonBuilder::ensureDefiniteTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
{
// We cannot arbitrarily add a typeset to a definition. It can be shared
// in another path. So we always need to create a new MIR.
// Use ensureDefiniteType to do unboxing. If that happened the type can
// be added on the newly created unbox operation.
MDefinition *replace = ensureDefiniteType(def, types->getKnownTypeTag());
if (replace != def) {
replace->setResultTypeSet(types);
return replace;
}
// Create a NOP mir instruction to filter the typeset.
MFilterTypeSet *filter = MFilterTypeSet::New(alloc(), def, types);
current->add(filter);
return filter;
}
static size_t
NumFixedSlots(JSObject *object)
{
@ -7159,6 +7241,36 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
JS_ASSERT(knownType == JSVAL_TYPE_UNKNOWN);
}
// If the array is being converted to doubles, but we've observed
// just int, substitute a type set of int+double into the observed
// type set. The reason for this is that, in the
// interpreter+baseline, such arrays may consist of mixed
// ints/doubles, but when we enter ion code, we will be coercing
// all inputs to doubles. Therefore, the type barrier checking for
// just int is highly likely (*almost* guaranteed) to fail sooner
// or later. Essentially, by eagerly coercing to double, ion is
// making the observed types outdated. To compensate for this, we
// substitute a broader observed type set consisting of both ints
// and doubles. There is perhaps a tradeoff here, so we limit this
// optimization to parallel code, where it is needed to prevent
// perpetual bailouts in some extreme cases. (Bug 977853)
//
// NB: we have not added a MConvertElementsToDoubles MIR, so we
// cannot *assume* the result is a double.
if (executionMode == ParallelExecution &&
barrier &&
types->getKnownTypeTag() == JSVAL_TYPE_INT32 &&
objTypes &&
objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
{
// Note: double implies int32 as well for typesets
types = alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::DoubleType());
if (!types)
return false;
barrier = false; // Don't need a barrier anymore
}
if (knownType != JSVAL_TYPE_UNKNOWN)
load->setResultType(MIRTypeFromValueType(knownType));
@ -7460,7 +7572,7 @@ IonBuilder::setElemTryScalarElemOfTypedObject(bool *emitted,
}
// Store the element
if (!storeScalarTypedObjectValue(obj, indexAsByteOffset, elemType, canBeNeutered, value))
if (!storeScalarTypedObjectValue(obj, indexAsByteOffset, elemType, canBeNeutered, false, value))
return false;
current->push(value);
@ -7492,6 +7604,10 @@ IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object,
return true;
TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>();
if (gc::IsInsideNursery(tarr->runtimeFromMainThread(), tarr->viewData()))
return true;
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
@ -7806,6 +7922,28 @@ IonBuilder::jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
return resumeAfter(ins);
}
bool
IonBuilder::jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType,
SetElemSafety safety,
bool racy,
MDefinition *object, MDefinition *index, MDefinition *value)
{
JS_ASSERT(safety == SetElem_Unsafe); // Can be fixed, but there's been no reason to as of yet
MInstruction *int_index = MToInt32::New(alloc(), index);
current->add(int_index);
size_t elemSize = ScalarTypeDescr::alignment(arrayType);
MMul *byteOffset = MMul::New(alloc(), int_index, constantInt(elemSize),
MIRType_Int32, MMul::Integer);
current->add(byteOffset);
if (!storeScalarTypedObjectValue(object, byteOffset, arrayType, false, racy, value))
return false;
return true;
}
bool
IonBuilder::jsop_length()
{
@ -8983,7 +9121,7 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
// OK! Perform the optimization.
if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, true, value))
if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, true, false, value))
return false;
current->push(value);
@ -9999,15 +10137,16 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
bool
IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
MDefinition *byteOffset,
ScalarTypeDescr::Type type,
bool canBeNeutered,
bool racy,
MDefinition *value)
{
// Find location within the owner object.
MDefinition *elements, *scaledOffset;
size_t alignment = ScalarTypeDescr::alignment(type);
loadTypedObjectElements(typedObj, offset, alignment, canBeNeutered,
loadTypedObjectElements(typedObj, byteOffset, alignment, canBeNeutered,
&elements, &scaledOffset);
// Clamp value to [0, 255] when type is Uint8Clamped
@ -10020,6 +10159,8 @@ IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj,
MStoreTypedArrayElement *store =
MStoreTypedArrayElement::New(alloc(), elements, scaledOffset, toWrite,
type);
if (racy)
store->setRacy();
current->add(store);
return true;

View File

@ -110,6 +110,7 @@ class IonBuilder : public MIRGenerator
MBasicBlock *ifFalse;
jsbytecode *falseEnd;
MBasicBlock *ifTrue; // Set when the end of the true path is reached.
MTest *test;
} branch;
struct {
// Common entry point.
@ -200,8 +201,8 @@ class IonBuilder : public MIRGenerator
}
}
static CFGState If(jsbytecode *join, MBasicBlock *ifFalse);
static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBlock *ifFalse);
static CFGState If(jsbytecode *join, MTest *test);
static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test);
static CFGState AndOr(jsbytecode *join, MBasicBlock *joinStart);
static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins);
static CFGState CondSwitch(IonBuilder *builder, jsbytecode *exitpc, jsbytecode *defaultTarget);
@ -337,6 +338,9 @@ class IonBuilder : public MIRGenerator
MConstant *constant(const Value &v);
MConstant *constantInt(int32_t i);
// Filter the type information at tests
bool filterTypesAtTest(MTest *test);
// Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier);
@ -352,6 +356,9 @@ class IonBuilder : public MIRGenerator
// added to |current| in this case.
MDefinition *ensureDefiniteType(MDefinition* def, JSValueType definiteType);
// Creates a MDefinition based on the given def improved with type as TypeSet.
MDefinition *ensureDefiniteTypeSet(MDefinition* def, types::TemporaryTypeSet *types);
JSObject *getSingletonPrototype(JSFunction *target);
MDefinition *createThisScripted(MDefinition *callee);
@ -459,6 +466,7 @@ class IonBuilder : public MIRGenerator
MDefinition *offset,
ScalarTypeDescr::Type type,
bool canBeNeutered,
bool racy,
MDefinition *value);
bool checkTypedObjectIndexInBounds(size_t elemSize,
MDefinition *obj,
@ -565,6 +573,9 @@ class IonBuilder : public MIRGenerator
bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
SetElemSafety safety,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType,
SetElemSafety safety, bool racy,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_length();
bool jsop_length_fastPath();
bool jsop_arguments();
@ -667,6 +678,8 @@ class IonBuilder : public MIRGenerator
bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base);
bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
bool inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
InliningStatus inlineNewDenseArray(CallInfo &callInfo);
InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo);
InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo);
@ -680,6 +693,8 @@ class IonBuilder : public MIRGenerator
// TypedObject intrinsics.
InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
ScalarTypeDescr::Type *arrayType);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);

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