mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound
This commit is contained in:
commit
763daa65ec
2
CLOBBER
2
CLOBBER
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -3681,7 +3681,11 @@ OverflowableToolbar.prototype = {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
this._moveItemsBackToTheirOrigin();
|
||||
if (this._target.scrollLeftMax > 0) {
|
||||
this.onOverflow();
|
||||
} else {
|
||||
this._moveItemsBackToTheirOrigin();
|
||||
}
|
||||
},
|
||||
|
||||
_disable: function() {
|
||||
|
@ -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]
|
||||
|
@ -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");
|
||||
});
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)),
|
||||
|
BIN
browser/themes/shared/customizableui/whimsy-bw.png
Normal file
BIN
browser/themes/shared/customizableui/whimsy-bw.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
browser/themes/shared/customizableui/whimsy-bw@2x.png
Normal file
BIN
browser/themes/shared/customizableui/whimsy-bw@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
browser/themes/shared/customizableui/whimsy.png
Normal file
BIN
browser/themes/shared/customizableui/whimsy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
browser/themes/shared/customizableui/whimsy@2x.png
Normal file
BIN
browser/themes/shared/customizableui/whimsy@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -1516,8 +1516,6 @@ nsContentUtils::Shutdown()
|
||||
sModifierSeparator = nullptr;
|
||||
|
||||
NS_IF_RELEASE(sSameOriginChecker);
|
||||
|
||||
nsTextEditorState::ShutDown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,6 +287,7 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
if (!IsExtensionEnabled(extension) || (extension == WEBGL_lose_context))
|
||||
continue;
|
||||
|
||||
mExtensions[extension]->MarkLost();
|
||||
mExtensions[extension] = nullptr;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
64
content/canvas/src/WebGLFramebufferAttachable.cpp
Normal file
64
content/canvas/src/WebGLFramebufferAttachable.cpp
Normal 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();
|
||||
}
|
43
content/canvas/src/WebGLFramebufferAttachable.h
Normal file
43
content/canvas/src/WebGLFramebufferAttachable.h
Normal 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_
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -147,6 +147,9 @@ WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
|
||||
if (aLevel > 0)
|
||||
SetCustomMipmap();
|
||||
|
||||
// Invalidate framebuffer status cache
|
||||
NotifyFBsStatusChanged();
|
||||
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>>&);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
},
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -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 () {},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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 = [];
|
||||
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
@ -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");
|
||||
|
@ -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 () {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
};
|
||||
|
21
dom/webidl/NativeOSFileInternals.webidl
Normal file
21
dom/webidl/NativeOSFileInternals.webidl
Normal 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;
|
||||
};
|
@ -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 {
|
||||
|
@ -245,6 +245,7 @@ WEBIDL_FILES = [
|
||||
'MozWakeLock.webidl',
|
||||
'MutationEvent.webidl',
|
||||
'MutationObserver.webidl',
|
||||
'NativeOSFileInternals.webidl',
|
||||
'NetDashboard.webidl',
|
||||
'NetworkOptions.webidl',
|
||||
'Node.webidl',
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -59,8 +59,6 @@ public:
|
||||
|
||||
void SpellCheckIfNeeded();
|
||||
|
||||
static NS_HIDDEN_(void) ShutDown();
|
||||
|
||||
protected:
|
||||
nsresult InstallToEditor();
|
||||
void UninstallFromEditor();
|
||||
|
@ -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>
|
||||
|
@ -203,7 +203,7 @@ SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
|
||||
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
|
||||
tiles, mRetainedWidth, mRetainedHeight,
|
||||
mResolution);
|
||||
mResolution, mFrameResolution.scale);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -608,7 +608,7 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
}
|
||||
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
|
||||
tiles, mRetainedWidth, mRetainedHeight,
|
||||
mResolution);
|
||||
mResolution, mFrameResolution.scale);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -286,6 +286,7 @@ struct SurfaceDescriptorTiles {
|
||||
int retainedWidth;
|
||||
int retainedHeight;
|
||||
float resolution;
|
||||
float frameResolution;
|
||||
};
|
||||
|
||||
struct OpUseTiledLayerBuffer {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
20
js/src/jit-test/tests/ion/bug953164.js
Normal file
20
js/src/jit-test/tests/ion/bug953164.js
Normal 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)
|
63
js/src/jit-test/tests/parallel/bug977853-convert-doubles.js
Normal file
63
js/src/jit-test/tests/parallel/bug977853-convert-doubles.js
Normal 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();
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user