This commit is contained in:
Wes Kocher 2014-01-21 17:36:55 -08:00
Родитель 9c5c042127 f0b5ead194
Коммит 8821f00cbd
121 изменённых файлов: 2472 добавлений и 1718 удалений

Просмотреть файл

@ -22,4 +22,5 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 953381 requires a clobber due to bug 961339.
CLOBBER due to recent changes to JS build files that were causing
"STOP! configure has changed and needs to be run in this build directory." bustage

Просмотреть файл

@ -999,7 +999,7 @@ let BookmarkingUI = {
if (widget.overflowed) {
// Don't open a popup in the overflow popup, rather just open the Library.
event.preventDefault();
widget.node.removeAttribute("noautoclose");
widget.node.removeAttribute("closemenu");
PlacesCommandHook.showPlacesOrganizer("BookmarksMenu");
return;
}
@ -1172,7 +1172,7 @@ let BookmarkingUI = {
let view = document.getElementById("PanelUI-bookmarks");
view.addEventListener("ViewShowing", this.onPanelMenuViewShowing);
view.addEventListener("ViewHiding", this.onPanelMenuViewHiding);
widget.node.setAttribute("noautoclose", "true");
widget.node.setAttribute("closemenu", "none");
PanelUI.showSubView("PanelUI-bookmarks", widget.node,
CustomizableUI.AREA_PANEL);
return;
@ -1181,9 +1181,9 @@ let BookmarkingUI = {
// Allow to close the panel if the page is already bookmarked, cause
// we are going to open the edit bookmark panel.
if (this._itemIds.length > 0)
widget.node.removeAttribute("noautoclose");
widget.node.removeAttribute("closemenu");
else
widget.node.setAttribute("noautoclose", "true");
widget.node.setAttribute("closemenu", "none");
}
// Ignore clicks on the star if we are updating its state.

Просмотреть файл

@ -1171,7 +1171,7 @@ SocialStatus = {
if (inMenuPanel) {
panel = document.getElementById("PanelUI-socialapi");
this._attachNotificatonPanel(panel, aToolbarButton, provider);
widget.node.setAttribute("noautoclose", "true");
widget.node.setAttribute("closemenu", "none");
showingEvent = "ViewShowing";
hidingEvent = "ViewHiding";
} else {

Просмотреть файл

@ -2530,8 +2530,7 @@ function getWebNavigation()
function BrowserReloadWithFlags(reloadFlags) {
let url = gBrowser.currentURI.spec;
if (gBrowser._updateBrowserRemoteness(gBrowser.selectedBrowser,
gBrowser._shouldBrowserBeRemote(url))) {
if (gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, url)) {
// If the remoteness has changed, the new browser doesn't have any
// information of what was loaded before, so we need to load the previous
// URL again.

Просмотреть файл

@ -23,7 +23,7 @@
let widget = widgetGroup.forWindow(window);
this.inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
if (this.inMenuPanel) {
widget.node.setAttribute("noautoclose", "true");
widget.node.setAttribute("closemenu", "none");
return document.getElementById("PanelUI-socialapi");
}
return document.getAnonymousElementByAttribute(this, "anonid", "panel");

Просмотреть файл

@ -266,7 +266,9 @@
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
this.getBrowserForTab(aTab).docShell.isAppTab = true;
// Bug 961867 - [e10s] Implement the logic for app tabs
if (!gMultiProcessBrowser)
this.getBrowserForTab(aTab).docShell.isAppTab = true;
if (aTab.selected)
this._setCloseKeyState(false);
@ -291,7 +293,9 @@
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
this.getBrowserForTab(aTab).docShell.isAppTab = false;
// Bug 961867 - [e10s] Implement the logic for app tabs
if (!gMultiProcessBrowser)
this.getBrowserForTab(aTab).docShell.isAppTab = false;
if (aTab.selected)
this._setCloseKeyState(true);
@ -1338,13 +1342,15 @@
</method>
#ifdef MAKE_E10S_WORK
<method name="_updateBrowserRemoteness">
<method name="updateBrowserRemoteness">
<parameter name="aBrowser"/>
<parameter name="aRemote"/>
<parameter name="aURL"/>
<body>
<![CDATA[
let shouldBeRemote = this._shouldBrowserBeRemote(aURL);
let isRemote = aBrowser.getAttribute("remote") == "true";
if (isRemote == aRemote)
if (isRemote == shouldBeRemote)
return false;
let wasActive = document.activeElement == aBrowser;
@ -1358,13 +1364,13 @@
// Change the "remote" attribute.
let parent = aBrowser.parentNode;
parent.removeChild(aBrowser);
aBrowser.setAttribute("remote", aRemote ? "true" : "false");
aBrowser.setAttribute("remote", shouldBeRemote ? "true" : "false");
parent.appendChild(aBrowser);
// Restore the progress listener.
aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
if (aRemote)
if (shouldBeRemote)
tab.setAttribute("remote", "true");
else
tab.removeAttribute("remote");
@ -2676,14 +2682,14 @@
<body>
<![CDATA[
#ifdef MAKE_E10S_WORK
this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(aURI));
this.updateBrowserRemoteness(this.mCurrentBrowser, aURI);
try {
#endif
return this.mCurrentBrowser.loadURI(aURI, aReferrerURI, aCharset);
#ifdef MAKE_E10S_WORK
} catch (e) {
let url = this.mCurrentBrowser.currentURI.spec;
this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(url));
this.updateBrowserRemoteness(this.mCurrentBrowser, url);
throw e;
}
#endif
@ -2701,14 +2707,14 @@
<body>
<![CDATA[
#ifdef MAKE_E10S_WORK
this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(aURI));
this.updateBrowserRemoteness(this.mCurrentBrowser, aURI);
try {
#endif
return this.mCurrentBrowser.loadURIWithFlags(aURI, aFlags, aReferrerURI, aCharset, aPostData);
#ifdef MAKE_E10S_WORK
} catch (e) {
let url = this.mCurrentBrowser.currentURI.spec;
this._updateBrowserRemoteness(this.mCurrentBrowser, this._shouldBrowserBeRemote(url));
this.updateBrowserRemoteness(this.mCurrentBrowser, url);
throw e;
}
#endif
@ -3220,7 +3226,7 @@
let uri = browser.currentURI;
let icon = browser.mIconURL;
this._updateBrowserRemoteness(browser, false);
this.updateBrowserRemoteness(browser, "about:tabcrashed");
browser.setAttribute("crashedPageTitle", title);
browser.docShell.displayLoadError(Cr.NS_ERROR_CONTENT_CRASHED, uri, null);

Просмотреть файл

@ -7,8 +7,17 @@
<label id="customization-header">
&customizeMode.menuAndToolbars.header;
</label>
<hbox id="customization-empty" hidden="true">
<label>&customizeMode.menuAndToolbars.empty;</label>
<label onclick="BrowserOpenAddonsMgr('addons://discovery/');"
onkeypress="BrowserOpenAddonsMgr('addons://discovery/');"
id="customization-more-tools"
class="text-link">
&customizeMode.menuAndToolbars.emptyLink;
</label>
</hbox>
<vbox id="customization-palette" flex="1"/>
<spacer flex="1"/>
<spacer id="customization-spacer" flex="1"/>
<hbox>
<button id="customization-toolbar-visibility-button" label="&customizeMode.toolbars;" class="customizationmode-button" type="menu">
<menupopup id="customization-toolbar-menu" onpopupshowing="onViewToolbarsPopupShowing(event)"/>

Просмотреть файл

@ -330,9 +330,15 @@ const PanelUI = {
* so that the panel knows if and when to close itself.
*/
onCommandHandler: function(aEvent) {
if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
PanelUI.hide();
let closemenu = aEvent.originalTarget.getAttribute("closemenu");
if (closemenu == "none") {
return;
}
if (closemenu == "single") {
this.showMainView();
return;
}
this.hide();
},
/**

Просмотреть файл

@ -1230,7 +1230,8 @@ let CustomizableUIInternal = {
}
// If the user hit enter/return, we don't check preventDefault - it makes sense
// that this was prevented, but we probably still want to close the panel.
// If consumers don't want this to happen, they should specify noautoclose.
// If consumers don't want this to happen, they should specify the closemenu
// attribute.
} else if (aEvent.type != "command") { // mouse events:
if (aEvent.defaultPrevented || aEvent.button != 0) {
@ -1243,7 +1244,7 @@ let CustomizableUIInternal = {
}
}
if (aEvent.target.getAttribute("noautoclose") == "true" ||
if (aEvent.target.getAttribute("closemenu") == "none" ||
aEvent.target.getAttribute("widget-type") == "view") {
return;
}

Просмотреть файл

@ -44,12 +44,12 @@ function setAttributes(aNode, aAttrs) {
}
}
function updateCombinedWidgetStyle(aNode, aArea, aModifyAutoclose) {
function updateCombinedWidgetStyle(aNode, aArea, aModifyCloseMenu) {
let inPanel = (aArea == CustomizableUI.AREA_PANEL);
let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
let attrs = {class: cls};
if (aModifyAutoclose) {
attrs.noautoclose = inPanel ? true : null;
if (aModifyCloseMenu) {
attrs.closemenu = inPanel ? "none" : null;
}
for (let i = 0, l = aNode.childNodes.length; i < l; ++i) {
if (aNode.childNodes[i].localName == "separator")
@ -311,7 +311,7 @@ const CustomizableWidgets = [{
let areaType = CustomizableUI.getAreaType(this.currentArea);
let inPanel = areaType == CustomizableUI.TYPE_MENU_PANEL;
let inToolbar = areaType == CustomizableUI.TYPE_TOOLBAR;
let noautoclose = inPanel ? "true" : null;
let closeMenu = inPanel ? "none" : null;
let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
if (!this.currentArea)
@ -319,20 +319,20 @@ const CustomizableWidgets = [{
let buttons = [{
id: "zoom-out-button",
noautoclose: noautoclose,
closemenu: closeMenu,
command: "cmd_fullZoomReduce",
class: cls,
label: true,
tooltiptext: true
}, {
id: "zoom-reset-button",
noautoclose: noautoclose,
closemenu: closeMenu,
command: "cmd_fullZoomReset",
class: cls,
tooltiptext: true
}, {
id: "zoom-in-button",
noautoclose: noautoclose,
closemenu: closeMenu,
command: "cmd_fullZoomEnlarge",
class: cls,
label: true,

Просмотреть файл

@ -48,6 +48,8 @@ function CustomizeMode(aWindow) {
// user. Then there's the visible palette, which gets populated and displayed
// to the user when in customizing mode.
this.visiblePalette = this.document.getElementById(kPaletteId);
this.paletteEmptyNotice = this.document.getElementById("customization-empty");
this.paletteSpacer = this.document.getElementById("customization-spacer");
};
CustomizeMode.prototype = {
@ -228,6 +230,8 @@ CustomizeMode.prototype = {
// Show the palette now that the transition has finished.
this.visiblePalette.hidden = false;
this.paletteSpacer.hidden = true;
this._updateEmptyPaletteNotice();
this._handler.isEnteringCustomizeMode = false;
this.dispatchToolboxEvent("customizationready");
@ -273,7 +277,9 @@ CustomizeMode.prototype = {
let documentElement = document.documentElement;
// Hide the palette before starting the transition for increased perf.
this.paletteSpacer.hidden = false;
this.visiblePalette.hidden = true;
this.paletteEmptyNotice.hidden = true;
this._transitioning = true;
@ -913,9 +919,15 @@ CustomizeMode.prototype = {
_onUIChange: function() {
this._changed = true;
this._updateResetButton();
this._updateEmptyPaletteNotice();
this.dispatchToolboxEvent("customizationchange");
},
_updateEmptyPaletteNotice: function() {
let paletteItems = this.visiblePalette.getElementsByTagName("toolbarpaletteitem");
this.paletteEmptyNotice.hidden = !!paletteItems.length;
},
_updateResetButton: function() {
let btn = this.document.getElementById("customization-reset-button");
btn.disabled = CustomizableUI.inDefaultState;

Просмотреть файл

@ -37,6 +37,7 @@ skip-if = true
[browser_918049_skipintoolbarset_dnd.js]
[browser_923857_customize_mode_event_wrapping_during_reset.js]
[browser_927717_customize_drag_empty_toolbar.js]
[browser_932928_show_notice_when_palette_empty.js]
[browser_934113_menubar_removable.js]
# Because this test is about the menubar, it can't be run on mac

Просмотреть файл

@ -0,0 +1,35 @@
/* 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";
// There should be an advert to get more addons when the palette is empty.
add_task(function() {
yield startCustomizing();
let visiblePalette = document.getElementById("customization-palette");
let emptyPaletteNotice = document.getElementById("customization-empty");
is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette.");
while (visiblePalette.childElementCount) {
gCustomizeMode.addToToolbar(visiblePalette.children[0]);
}
is(visiblePalette.childElementCount, 0, "There shouldn't be any items remaining in the visible palette.");
is(emptyPaletteNotice.hidden, false, "The empty palette notice should be shown when there are no items in the palette.");
yield endCustomizing();
yield startCustomizing();
visiblePalette = document.getElementById("customization-palette");
emptyPaletteNotice = document.getElementById("customization-empty");
is(emptyPaletteNotice.hidden, false,
"The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered.");
gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button"));
is(emptyPaletteNotice.hidden, true,
"The empty palette notice should not be shown when there is at least one item in the palette.");
});
add_task(function asyncCleanup() {
yield endCustomizing();
yield resetCustomization();
});

Просмотреть файл

@ -607,6 +607,11 @@ let SessionStoreInternal = {
receiveMessage: function ssi_receiveMessage(aMessage) {
var browser = aMessage.target;
var win = browser.ownerDocument.defaultView;
let tab = this._getTabForBrowser(browser);
if (!tab) {
// Ignore messages from <browser> elements that are not tabs.
return;
}
switch (aMessage.name) {
case "SessionStore:pageshow":
@ -630,7 +635,6 @@ let SessionStoreInternal = {
case "SessionStore:restoreHistoryComplete":
if (this.isCurrentEpoch(browser, aMessage.data.epoch)) {
// Notify the tabbrowser that the tab chrome has been restored.
let tab = this._getTabForBrowser(browser);
let tabData = browser.__SS_data;
// wall-paper fix for bug 439675: make sure that the URL to be loaded
@ -681,7 +685,6 @@ let SessionStoreInternal = {
Services.obs.notifyObservers(browser, NOTIFY_TAB_RESTORED, null);
}
let tab = this._getTabForBrowser(browser);
if (tab) {
SessionStoreInternal._resetLocalTabRestoringState(tab);
SessionStoreInternal.restoreNextTab();
@ -703,7 +706,6 @@ let SessionStoreInternal = {
break;
case "SessionStore:reloadPendingTab":
if (this.isCurrentEpoch(browser, aMessage.data.epoch)) {
let tab = this._getTabForBrowser(browser);
if (tab && browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
this.restoreTabContent(tab);
}
@ -819,6 +821,12 @@ let SessionStoreInternal = {
// internal data about the window.
aWindow.__SSi = this._generateWindowID();
let mm = aWindow.messageManager;
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
// Load the frame script after registering listeners.
mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
// and create its data object
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
@ -1343,12 +1351,6 @@ let SessionStoreInternal = {
let browser = aTab.linkedBrowser;
BROWSER_EVENTS.forEach(msg => browser.addEventListener(msg, this, true));
let mm = browser.messageManager;
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
// Load the frame script after registering listeners.
mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", false);
if (!aNoNotification) {
this.saveStateDelayed(aWindow);
}
@ -2753,6 +2755,12 @@ let SessionStoreInternal = {
pageStyle: tabData.pageStyle || null
});
// In electrolysis, we may need to change the browser's remote
// attribute so that it runs in a content process.
let activePageData = tabData.entries[activeIndex] || null;
let uri = activePageData ? activePageData.url || null : null;
tabbrowser.updateBrowserRemoteness(browser, uri);
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory",
{tabData: tabData, epoch: epoch});

Просмотреть файл

@ -3,6 +3,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/* Bug 661762 */
function test()
{
waitForExplicitFinish();
@ -25,22 +26,15 @@ function test()
openScratchpad(function () {
let sw = gScratchpadWindow;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
openScratchpad(function () {
function onWebConsoleOpen(subj) {
Services.obs.removeObserver(onWebConsoleOpen,
"web-console-created");
subj.QueryInterface(Ci.nsISupportsString);
let hud = HUDService.getHudReferenceById(subj.data);
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "webconsole").then((toolbox) => {
let hud = toolbox.getCurrentPanel().hud;
hud.jsterm.clearOutput(true);
executeSoon(testFocus.bind(null, sw, hud));
}
Services.obs.
addObserver(onWebConsoleOpen, "web-console-created", false);
HUDService.toggleWebConsole();
testFocus(sw, hud);
});
});
});
}, true);

Просмотреть файл

@ -142,24 +142,6 @@ HUD_SERVICE.prototype =
return this.consoles.get(aId);
},
/**
* Toggle the Web Console for the current tab.
*
* @return object
* A promise for either the opening of the toolbox that holds the Web
* Console, or a Promise for the closing of the toolbox.
*/
toggleWebConsole: function HS_toggleWebConsole()
{
let window = this.currentContext();
let target = devtools.TargetFactory.forTab(window.gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
return toolbox && toolbox.currentToolId == "webconsole" ?
toolbox.destroy() :
gDevTools.showToolbox(target, "webconsole");
},
/**
* Find if there is a Web Console open for the current tab and return the
* instance.
@ -744,7 +726,7 @@ BrowserConsole.prototype = Heritage.extend(WebConsole.prototype,
const HUDService = new HUD_SERVICE();
(() => {
let methods = ["openWebConsole", "openBrowserConsole", "toggleWebConsole",
let methods = ["openWebConsole", "openBrowserConsole",
"toggleBrowserConsole", "getOpenWebConsole",
"getBrowserConsole", "getHudByWindow", "getHudReferenceById"];
for (let method of methods) {

Просмотреть файл

@ -115,6 +115,7 @@ support-files =
[browser_console.js]
[browser_console_addonsdk_loader_exception.js]
[browser_console_clear_on_reload.js]
[browser_console_click_focus.js]
[browser_console_consolejsm_output.js]
[browser_console_dead_objects.js]
[browser_console_error_source_click.js]

Просмотреть файл

@ -0,0 +1,39 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
// Tests that the input field is focused when the console is opened.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
function test() {
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testInputFocus, false);
}
function testInputFocus() {
browser.removeEventListener("DOMContentLoaded", testInputFocus, false);
openConsole().then((hud) => {
let inputNode = hud.jsterm.inputNode;
ok(inputNode.getAttribute("focused"), "input node is focused");
let lostFocus = () => {
inputNode.removeEventListener("blur", lostFocus);
info("input node lost focus");
}
inputNode.addEventListener("blur", lostFocus);
browser.ownerDocument.getElementById("urlbar").click();
ok(!inputNode.getAttribute("focused"), "input node is not focused");
hud.outputNode.click();
ok(inputNode.getAttribute("focused"), "input node is focused");
finishTest();
});
}

Просмотреть файл

@ -569,6 +569,19 @@ WebConsoleFrame.prototype = {
toolbox.on("webconsole-selected", this._onPanelSelected);
}
/*
* Focus input line whenever the output area is clicked.
* Only focus when the target node (or parent, as in source links) is
* not an anchor.
*/
this.outputNode.addEventListener("click", (e) => {
if ((e.button == 0) &&
(e.target.nodeName.toLowerCase() != "a") &&
(e.target.parentNode.nodeName.toLowerCase() != "a")) {
this.jsterm.inputNode.focus();
}
});
// Toggle the timestamp on preference change
gDevTools.on("pref-changed", this._onToolboxPrefChanged);
this._onToolboxPrefChanged("pref-changed", {

Просмотреть файл

@ -677,6 +677,8 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
<!ENTITY customizeMode.menuAndToolbars.label "Menu and toolbars">
<!ENTITY customizeMode.menuAndToolbars.header "More Tools to Add to the Menu and Toolbar">
<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
<!ENTITY customizeMode.restoreDefaults "Restore Defaults">
<!ENTITY customizeMode.toolbars "Show / Hide Toolbars">

Просмотреть файл

@ -83,19 +83,25 @@ let Util = {
aElement instanceof Ci.nsIDOMHTMLTextAreaElement);
},
/**
* Checks whether aElement's content can be edited either if it(or any of its
* parents) has "contenteditable" attribute set to "true" or aElement's
* ownerDocument is in design mode.
*/
isEditableContent: function isEditableContent(aElement) {
if (!aElement)
return false;
if (aElement.isContentEditable || aElement.designMode == "on")
return true;
return false;
return !!aElement && (aElement.isContentEditable ||
this.isOwnerDocumentInDesignMode(aElement));
},
isEditable: function isEditable(aElement) {
if (!aElement)
if (!aElement) {
return false;
if (this.isTextInput(aElement) || this.isEditableContent(aElement))
}
if (this.isTextInput(aElement) || this.isEditableContent(aElement)) {
return true;
}
// If a body element is editable and the body is the child of an
// iframe or div we can assume this is an advanced HTML editor
@ -106,7 +112,15 @@ let Util = {
return true;
}
return aElement.ownerDocument && aElement.ownerDocument.designMode == "on";
return false;
},
/**
* Checks whether aElement's owner document has design mode turned on.
*/
isOwnerDocumentInDesignMode: function(aElement) {
return !!aElement && !!aElement.ownerDocument &&
aElement.ownerDocument.designMode == "on";
},
isMultilineInput: function isMultilineInput(aElement) {

Просмотреть файл

@ -105,6 +105,8 @@ var ContextMenuHandler = {
if (Util.isTextInput(this._target)) {
// select all text in the input control
this._target.select();
} else if (Util.isEditableContent(this._target)) {
this._target.ownerDocument.execCommand("selectAll", false);
} else {
// select the entire document
content.getSelection().selectAllChildren(content.document);
@ -121,7 +123,7 @@ var ContextMenuHandler = {
} else {
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
}
} else if (this._target.isContentEditable) {
} else if (Util.isEditableContent(this._target)) {
try {
this._target.ownerDocument.execCommand("paste",
false,
@ -145,7 +147,7 @@ var ContextMenuHandler = {
} else {
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
}
} else if (this._target.isContentEditable) {
} else if (Util.isEditableContent(this._target)) {
try {
this._target.ownerDocument.execCommand("cut", false);
} catch (ex) {
@ -259,7 +261,9 @@ var ContextMenuHandler = {
break;
}
// is the target contentEditable (not just inheriting contentEditable)
else if (elem.contentEditable == "true") {
// or the entire document in designer mode.
else if (elem.contentEditable == "true" ||
Util.isOwnerDocumentInDesignMode(elem)) {
this._target = elem;
isEditableText = true;
isText = true;

Просмотреть файл

@ -709,6 +709,84 @@ gTests.push({
run: getReopenTest(sendContextMenuClickToElement, sendTap)
});
gTests.push({
desc: "Bug 947505 - Right-click in a designMode document should display a " +
"context menu",
run: function test() {
info(chromeRoot + "browser_context_menu_tests_02.html");
yield addTab(chromeRoot + "browser_context_menu_tests_02.html");
purgeEventQueue();
emptyClipboard();
ContextUI.dismiss();
yield waitForCondition(() => !ContextUI.navbarVisible);
let tabWindow = Browser.selectedTab.browser.contentWindow;
let testSpan = tabWindow.document.getElementById("text1");
// Case #1: Document isn't in design mode and nothing is selected.
tabWindow.document.designMode = "off";
// Simulate right mouse click to reproduce the same step as noted in the
// appropriate bug. It's valid for non-touch case only.
synthesizeNativeMouseRDown(Browser.selectedTab.browser, 10, 10);
synthesizeNativeMouseRUp(Browser.selectedTab.browser, 10, 10);
yield waitForCondition(() => ContextUI.navbarVisible);
ok(ContextUI.navbarVisible, "Navbar is visible on context menu action.");
ok(ContextUI.tabbarVisible, "Tabbar is visible on context menu action.");
ContextUI.dismiss();
yield waitForCondition(() => !ContextUI.navbarVisible);
// Case #2: Document isn't in design mode and text is selected.
tabWindow.getSelection().selectAllChildren(testSpan);
let promise = waitForEvent(tabWindow.document, "popupshown");
sendContextMenuClickToSelection(tabWindow);
yield promise;
checkContextUIMenuItemVisibility(["context-copy", "context-search"]);
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
// Case #3: Document is in design mode and nothing is selected.
tabWindow.document.designMode = "on";
tabWindow.getSelection().removeAllRanges();
promise = waitForEvent(tabWindow.document, "popupshown");
sendContextMenuClickToElement(tabWindow, testSpan);
yield promise;
checkContextUIMenuItemVisibility(["context-select-all", "context-select"]);
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
// Case #4: Document is in design mode and text is selected.
tabWindow.getSelection().selectAllChildren(testSpan);
promise = waitForEvent(tabWindow.document, "popupshown");
sendContextMenuClickToSelection(tabWindow);
yield promise;
checkContextUIMenuItemVisibility(["context-cut", "context-copy",
"context-select-all", "context-select",
"context-search"]);
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
Browser.closeTab(Browser.selectedTab, { forceClose: true });
}
});
function test() {
setDevPixelEqualToPx();
runTests();

Просмотреть файл

@ -3960,7 +3960,7 @@ window > chatbox {
%include ../shared/customizableui/customizeMode.inc.css
#main-window[customizing] #titlebar {
#main-window[customize-entered] #titlebar {
padding-top: 0;
}

Просмотреть файл

@ -1145,3 +1145,4 @@ unicode/ustring.h
unicode/utypes.h
#endif
libutil.h
unwind.h

Просмотреть файл

@ -971,11 +971,15 @@ if test -n "$CROSS_COMPILE"; then
OS_RELEASE=
case "${target_os}" in
linux*) OS_ARCH=Linux OS_TARGET=Linux ;;
kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;;
kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU/kFreeBSD ;;
gnu*) OS_ARCH=GNU ;;
solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;;
mingw*) OS_ARCH=WINNT OS_TARGET=WINNT ;;
darwin*) OS_ARCH=Darwin OS_TARGET=Darwin ;;
dragonfly*) OS_ARCH=DragonFly OS_TARGET=DragonFly ;;
freebsd*) OS_ARCH=FreeBSD OS_TARGET=FreeBSD ;;
netbsd*) OS_ARCH=NetBSD OS_TARGET=NetBSD ;;
openbsd*) OS_ARCH=OpenBSD OS_TARGET=OpenBSD ;;
esac
case "${target}" in
*-android*|*-linuxandroid*) OS_ARCH=Linux OS_TARGET=Android ;;
@ -7451,7 +7455,10 @@ dnl ========================================================
dnl = Support for gcc stack unwinding (from gcc 3.3)
dnl ========================================================
if test -z "$SKIP_LIBRARY_CHECKS"; then
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
MOZ_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace))
AC_LANG_RESTORE
fi
dnl ========================================================

Просмотреть файл

@ -201,9 +201,7 @@ VideoGraphicBuffer::VideoGraphicBuffer(const android::wp<android::OmxDecoder> aO
VideoGraphicBuffer::~VideoGraphicBuffer()
{
if (mMediaBuffer) {
mMediaBuffer->release();
}
MOZ_ASSERT(!mMediaBuffer);
}
void

Просмотреть файл

@ -32,6 +32,8 @@ class VideoGraphicBuffer : public GraphicBufferLocked {
android::MediaBuffer *aBuffer,
SurfaceDescriptor& aDescriptor);
~VideoGraphicBuffer();
protected:
void Unlock();
};

Просмотреть файл

@ -152,10 +152,7 @@ static const char* GetOmxLibraryName()
return nullptr;
#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
/*
if (version >= 19) {
*/
if (version >= 16) {
return "libomxpluginkk.so";
}
else if (version == 13 || version == 12 || version == 11) {

Просмотреть файл

@ -2402,7 +2402,7 @@ nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
mgr->StopFrameTimeRecording(startIndex, tmpFrameIntervals);
*frameCount = tmpFrameIntervals.Length();
*frameIntervals = (float*)nsMemory::Alloc(*frameCount * sizeof(float*));
*frameIntervals = (float*)nsMemory::Alloc(*frameCount * sizeof(float));
/* copy over the frame intervals and paint times into the arrays we just allocated */
for (uint32_t i = 0; i < *frameCount; i++) {

Просмотреть файл

@ -5,9 +5,7 @@
"use strict";
let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Geometry.jsm");
function debug(msg) {
//dump("BrowserElementChild - " + msg + "\n");

Просмотреть файл

@ -101,6 +101,14 @@ function getErrorClass(errorCode) {
return null;
}
const OBSERVED_EVENTS = [
'fullscreen-origin-change',
'ask-parent-to-exit-fullscreen',
'ask-parent-to-rollback-fullscreen',
'xpcom-shutdown',
'activity-done'
];
/**
* The BrowserElementChild implements one half of <iframe mozbrowser>.
* (The other half is, unsurprisingly, BrowserElementParent.)
@ -253,25 +261,9 @@ BrowserElementChild.prototype = {
this._scrollEventHandler.bind(this),
/* useCapture = */ false);
Services.obs.addObserver(this,
"fullscreen-origin-change",
/* ownsWeak = */ true);
Services.obs.addObserver(this,
'ask-parent-to-exit-fullscreen',
/* ownsWeak = */ true);
Services.obs.addObserver(this,
'ask-parent-to-rollback-fullscreen',
/* ownsWeak = */ true);
Services.obs.addObserver(this,
'xpcom-shutdown',
/* ownsWeak = */ true);
Services.obs.addObserver(this,
'activity-done',
/* ownsWeak = */ true);
OBSERVED_EVENTS.forEach((aTopic) => {
Services.obs.addObserver(this, aTopic, false);
});
},
observe: function(subject, topic, data) {
@ -306,6 +298,9 @@ BrowserElementChild.prototype = {
*/
_unloadHandler: function() {
this._shuttingDown = true;
OBSERVED_EVENTS.forEach((aTopic) => {
Services.obs.removeObserver(this, aTopic);
});
},
_tryGetInnerWindowID: function(win) {

Просмотреть файл

@ -9,7 +9,6 @@
dump("############################### browserElementPanning.js loaded\n");
let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Geometry.jsm");

Просмотреть файл

@ -114,9 +114,6 @@ BrowserElementParentFactory.prototype = {
case 'in-process-browser-or-app-frame-shown':
this._observeInProcessBrowserFrameShown(subject);
break;
case 'content-document-global-created':
this._observeContentGlobalCreated(subject);
break;
}
},
};

Просмотреть файл

@ -1684,9 +1684,7 @@ GonkFrameBuilder(Image* aImage, void* aBuffer, uint32_t aWidth, uint32_t aHeight
void
ReceiveFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer)
{
if (!gc->ReceiveFrame(aBuffer, ImageFormat::GRALLOC_PLANAR_YCBCR, GonkFrameBuilder)) {
aBuffer->Unlock();
}
gc->ReceiveFrame(aBuffer, ImageFormat::GRALLOC_PLANAR_YCBCR, GonkFrameBuilder);
}
void

Просмотреть файл

@ -938,15 +938,23 @@ nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args,
/*
* This function is called during minor GCs for each key in the sJSObjWrappers
* table that has been moved.
*
* Note that the wrapper may be dead at this point, and even the table may have
* been finalized if all wrappers have died.
*/
static void
JSObjWrapperKeyMarkCallback(JSTracer *trc, void *key, void *data) {
JSObject *obj = static_cast<JSObject*>(key);
nsJSObjWrapper* wrapper = static_cast<nsJSObjWrapper*>(data);
JSObjWrapperKeyMarkCallback(JSTracer *trc, JSObject *obj, void *data) {
NPP npp = static_cast<NPP>(data);
if (!sJSObjWrappers.initialized())
return;
JSObject *prior = obj;
JS_CallObjectTracer(trc, &obj, "sJSObjWrappers key object");
NPP npp = wrapper->mNpp;
nsJSObjWrapperKey oldKey(prior, npp);
JSObjWrapperTable::Ptr p = sJSObjWrappers.lookup(oldKey);
if (!p)
return;
JS_CallObjectTracer(trc, &obj, "sJSObjWrappers key object");
nsJSObjWrapperKey newKey(obj, npp);
sJSObjWrappers.rekeyIfMoved(oldKey, newKey);
}
@ -1048,7 +1056,7 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
}
// Add postbarrier for the hashtable key
JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper);
JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper->mNpp);
return wrapper;
}

Просмотреть файл

@ -48,7 +48,7 @@ struct GraphicBufferAutoUnlock {
GrallocImage::GrallocImage()
: PlanarYCbCrImage(nullptr),
mBufferAllocated(false),
mGraphicBuffer(nullptr),
mGraphicBufferLocked(nullptr),
mTextureClient(nullptr)
{
mFormat = GRALLOC_PLANAR_YCBCR;
@ -58,11 +58,15 @@ GrallocImage::~GrallocImage()
{
// If we have a texture client, the latter takes over the responsibility to
// unlock the GraphicBufferLocked.
if (mGraphicBuffer.get() && !mTextureClient) {
mGraphicBuffer->Unlock();
if (mGraphicBufferLocked.get() && !mTextureClient) {
// mBufferAllocated is set when gralloc buffer is allocated
// in the GrallocImage.
// XXX the way of handling gralloc buffer in GrallocImage is inconsistent
// between gralloc buffer allocation in GrallocImage and
// gralloc buffer allocation outside of GrallocImage
if (mBufferAllocated) {
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->DeallocSurfaceDescriptorGralloc(mGraphicBuffer->GetSurfaceDescriptor());
ibc->DeallocSurfaceDescriptorGralloc(mGraphicBufferLocked->GetSurfaceDescriptor());
mBufferAllocated = false;
}
}
@ -78,7 +82,7 @@ GrallocImage::SetData(const Data& aData)
mData = aData;
mSize = aData.mPicSize;
if (!mGraphicBuffer.get()) {
if (!mGraphicBufferLocked.get()) {
SurfaceDescriptor desc;
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
@ -89,12 +93,12 @@ GrallocImage::SetData(const Data& aData)
GraphicBuffer::USAGE_HW_TEXTURE,
&desc);
mBufferAllocated = true;
mGraphicBuffer = new GraphicBufferLocked(desc);
mGraphicBufferLocked = new GraphicBufferLocked(desc);
}
sp<GraphicBuffer> graphicBuffer =
GrallocBufferActor::GetFrom(
mGraphicBuffer->GetSurfaceDescriptor().get_SurfaceDescriptorGralloc());
mGraphicBufferLocked->GetSurfaceDescriptor().get_SurfaceDescriptorGralloc());
if (!graphicBuffer.get()) {
return;
}
@ -151,7 +155,7 @@ GrallocImage::SetData(const Data& aData)
void GrallocImage::SetData(const GrallocData& aData)
{
mGraphicBuffer = aData.mGraphicBuffer;
mGraphicBufferLocked = aData.mGraphicBuffer;
mSize = aData.mPicSize;
}
@ -295,7 +299,7 @@ GrallocImage::GetTextureClient()
}
GrallocBufferActor* actor = static_cast<GrallocBufferActor*>(desc.bufferChild());
mTextureClient = new GrallocTextureClientOGL(actor, mSize, flags);
mTextureClient->SetGraphicBufferLocked(mGraphicBuffer);
mTextureClient->SetGraphicBufferLocked(mGraphicBufferLocked);
}
return mTextureClient;
}

Просмотреть файл

@ -8,6 +8,7 @@
#ifdef MOZ_WIDGET_GONK
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/gfx/Point.h"
#include "ImageLayers.h"
@ -29,8 +30,9 @@ class GrallocTextureClientOGL;
* called. Each producer must maintain their own buffer queue and
* implement the GraphicBufferLocked::Unlock() interface.
*/
class GraphicBufferLocked {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GraphicBufferLocked)
class GraphicBufferLocked
: public AtomicRefCountedWithFinalize<GraphicBufferLocked>
{
public:
GraphicBufferLocked(SurfaceDescriptor aGraphicBuffer)
@ -39,13 +41,28 @@ public:
virtual ~GraphicBufferLocked() {}
virtual void Unlock() {}
SurfaceDescriptor GetSurfaceDescriptor()
{
return mSurfaceDescriptor;
}
protected:
virtual void Unlock() {}
private:
/**
* Called once, just before the destructor.
*
* Here goes the shut-down code that uses virtual methods.
* Must only be called by Release().
*/
void Finalize()
{
Unlock();
}
friend class AtomicRefCountedWithFinalize<GraphicBufferLocked>;
protected:
SurfaceDescriptor mSurfaceDescriptor;
};
@ -123,8 +140,8 @@ public:
virtual bool IsValid() { return GetSurfaceDescriptor().type() != SurfaceDescriptor::T__None; }
SurfaceDescriptor GetSurfaceDescriptor() {
if (mGraphicBuffer.get()) {
return mGraphicBuffer->GetSurfaceDescriptor();
if (mGraphicBufferLocked.get()) {
return mGraphicBufferLocked->GetSurfaceDescriptor();
}
return SurfaceDescriptor();
}
@ -140,7 +157,7 @@ public:
private:
bool mBufferAllocated;
nsRefPtr<GraphicBufferLocked> mGraphicBuffer;
nsRefPtr<GraphicBufferLocked> mGraphicBufferLocked;
RefPtr<GrallocTextureClientOGL> mTextureClient;
};

Просмотреть файл

@ -635,8 +635,8 @@ PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
already_AddRefed<gfxASurface>
PlanarYCbCrImage::DeprecatedGetAsSurface()
{
if (mSurface) {
nsRefPtr<gfxASurface> result = mSurface.get();
if (mDeprecatedSurface) {
nsRefPtr<gfxASurface> result = mDeprecatedSurface.get();
return result.forget();
}
@ -654,11 +654,36 @@ PlanarYCbCrImage::DeprecatedGetAsSurface()
gfx::ConvertYCbCrToRGB(mData, format, mSize, imageSurface->Data(), imageSurface->Stride());
mSurface = imageSurface;
mDeprecatedSurface = imageSurface;
return imageSurface.forget();
}
TemporaryRef<gfx::SourceSurface>
PlanarYCbCrImage::GetAsSourceSurface()
{
if (mSourceSurface) {
return mSourceSurface.get();
}
gfx::IntSize size(mSize);
gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
mSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return nullptr;
}
RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride());
mSourceSurface = surface;
return surface.forget();
}
already_AddRefed<gfxASurface>
RemoteBitmapImage::DeprecatedGetAsSurface()
{

Просмотреть файл

@ -902,6 +902,7 @@ protected:
virtual uint8_t* AllocateBuffer(uint32_t aSize);
already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
gfxImageFormat GetOffscreenFormat();
@ -911,7 +912,8 @@ protected:
Data mData;
gfx::IntSize mSize;
gfxImageFormat mOffscreenFormat;
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
nsCountedRef<nsMainThreadSurfaceRef> mDeprecatedSurface;
nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
nsRefPtr<BufferRecycleBin> mRecycleBin;
};

Просмотреть файл

@ -53,6 +53,7 @@ public:
virtual void SetDelayedConversion(bool aDelayed) { mDelayedConversion = aDelayed; }
already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
private:
nsAutoArrayPtr<uint8_t> mDecodedBuffer;
@ -137,8 +138,8 @@ BasicPlanarYCbCrImage::DeprecatedGetAsSurface()
{
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
if (mSurface) {
nsRefPtr<gfxASurface> result = mSurface.get();
if (mDeprecatedSurface) {
nsRefPtr<gfxASurface> result = mDeprecatedSurface.get();
return result.forget();
}
@ -166,11 +167,50 @@ BasicPlanarYCbCrImage::DeprecatedGetAsSurface()
}
#endif
mSurface = result;
mDeprecatedSurface = result;
return result.forget();
}
TemporaryRef<gfx::SourceSurface>
BasicPlanarYCbCrImage::GetAsSourceSurface()
{
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
if (mSourceSurface) {
return mSourceSurface.get();
}
if (!mDecodedBuffer) {
return PlanarYCbCrImage::GetAsSourceSurface();
}
gfxImageFormat format = GetOffscreenFormat();
RefPtr<gfx::SourceSurface> surface;
{
// Create a DrawTarget so that we can own the data inside mDecodeBuffer.
// We create the target out of mDecodedBuffer, and get a snapshot from it.
// The draw target is destroyed on scope exit and the surface owns the data.
RefPtr<gfx::DrawTarget> drawTarget
= gfxPlatform::GetPlatform()->CreateDrawTargetForData(mDecodedBuffer,
mSize,
mStride,
gfx::ImageFormatToSurfaceFormat(format));
if (!drawTarget) {
return nullptr;
}
surface = drawTarget->Snapshot();
}
mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
mSourceSurface = surface;
return mSourceSurface.get();
}
ImageFactory*
BasicLayerManager::GetImageFactory()
{

Просмотреть файл

@ -18,13 +18,13 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
#include "mozilla/ipc/Shmem.h" // for Shmem
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/mozalloc.h" // for operator delete
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
class gfxReusableSurfaceWrapper;
class gfxASurface;

Просмотреть файл

@ -84,6 +84,16 @@ SharedPlanarYCbCrImage::DeprecatedGetAsSurface()
return PlanarYCbCrImage::DeprecatedGetAsSurface();
}
TemporaryRef<gfx::SourceSurface>
SharedPlanarYCbCrImage::GetAsSourceSurface()
{
if (!mTextureClient->IsAllocated()) {
NS_WARNING("Can't get as surface");
return nullptr;
}
return PlanarYCbCrImage::GetAsSourceSurface();
}
void
SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
{

Просмотреть файл

@ -101,6 +101,7 @@ public:
virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface() MOZ_OVERRIDE;
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
virtual void SetData(const PlanarYCbCrData& aData) MOZ_OVERRIDE;
virtual void SetDataNoCopy(const Data &aData) MOZ_OVERRIDE;

Просмотреть файл

@ -35,7 +35,6 @@ public:
virtual void DeallocateSharedData(ISurfaceAllocator*) MOZ_OVERRIDE
{
mBufferLocked->Unlock();
mBufferLocked = nullptr;
}
@ -129,9 +128,7 @@ GrallocTextureClientOGL::~GrallocTextureClientOGL()
if (ShouldDeallocateInDestructor()) {
// If the buffer has never been shared we must deallocate it or it would
// leak.
if (mBufferLocked) {
mBufferLocked->Unlock();
} else {
if (!mBufferLocked) {
// We just need to wrap the actor in a SurfaceDescriptor because that's what
// ISurfaceAllocator uses as input, we don't care about the other parameters.
SurfaceDescriptor sd = SurfaceDescriptorGralloc(nullptr, mGrallocActor,

Просмотреть файл

@ -34,19 +34,23 @@
typedef uint32_t be32;
typedef uint16_t be16;
#if 0
not used yet
/* __builtin_bswap isn't available in older gccs
* so open code it for now */
static be32 cpu_to_be32(int32_t v)
static be32 cpu_to_be32(uint32_t v)
{
#ifdef IS_LITTLE_ENDIAN
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
//return __builtin_bswap32(v);
#else
return v;
#endif
}
static be16 cpu_to_be16(uint16_t v)
{
#ifdef IS_LITTLE_ENDIAN
return ((v & 0xff) << 8) | ((v & 0xff00) >> 8);
#else
return v;
#endif
}
static uint32_t be32_to_cpu(be32 v)
{
@ -135,6 +139,16 @@ static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset)
return read_u16(mem, offset);
}
static void write_u32(void *mem, size_t offset, uint32_t value)
{
*((uint32_t *)((unsigned char*)mem + offset)) = cpu_to_be32(value);
}
static void write_u16(void *mem, size_t offset, uint16_t value)
{
*((uint16_t *)((unsigned char*)mem + offset)) = cpu_to_be16(value);
}
#define BAD_VALUE_PROFILE NULL
#define INVALID_PROFILE NULL
#define NO_MEM_PROFILE NULL
@ -848,11 +862,10 @@ static struct curveType *curve_from_gamma(float gamma)
return NULL;
curve->count = num_entries;
curve->data[0] = float_to_u8Fixed8Number(gamma);
curve->type = CURVE_TYPE;
curve->type = CURVE_TYPE;
return curve;
}
//XXX: it would be nice if we had a way of ensuring
// everything in a profile was initialized regardless of how it was created
@ -1152,25 +1165,27 @@ void qcms_profile_release(qcms_profile *profile)
#include <stdio.h>
qcms_profile* qcms_profile_from_file(FILE *file)
static void qcms_data_from_file(FILE *file, void **mem, size_t *size)
{
uint32_t length, remaining_length;
qcms_profile *profile;
size_t read_length;
be32 length_be;
void *data;
*mem = NULL;
*size = 0;
if (fread(&length_be, 1, sizeof(length_be), file) != sizeof(length_be))
return BAD_VALUE_PROFILE;
return;
length = be32_to_cpu(length_be);
if (length > MAX_PROFILE_SIZE || length < sizeof(length_be))
return BAD_VALUE_PROFILE;
return;
/* allocate room for the entire profile */
data = malloc(length);
if (!data)
return NO_MEM_PROFILE;
return;
/* copy in length to the front so that the buffer will contain the entire profile */
*((be32*)data) = length_be;
@ -1180,9 +1195,24 @@ qcms_profile* qcms_profile_from_file(FILE *file)
read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file);
if (read_length != remaining_length) {
free(data);
return INVALID_PROFILE;
return;
}
/* successfully get the profile.*/
*mem = data;
*size = length;
}
qcms_profile* qcms_profile_from_file(FILE *file)
{
uint32_t length;
qcms_profile *profile;
void *data;
qcms_data_from_file(file, &data, &length);
if ((data == NULL) || (length == 0))
return INVALID_PROFILE;
profile = qcms_profile_from_memory(data, length);
free(data);
return profile;
@ -1199,6 +1229,19 @@ qcms_profile* qcms_profile_from_path(const char *path)
return profile;
}
void qcms_data_from_path(const char *path, void **mem, size_t *size)
{
FILE *file = NULL;
*mem = NULL;
*size = 0;
file = fopen(path, "rb");
if (file) {
qcms_data_from_file(file, mem, size);
fclose(file);
}
}
#ifdef _WIN32
/* Unicode path version */
qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path)
@ -1211,4 +1254,128 @@ qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path)
}
return profile;
}
void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size)
{
FILE *file = NULL;
*mem = NULL;
*size = 0;
file = _wfopen(path, L"rb");
if (file) {
qcms_data_from_file(file, mem, size);
fclose(file);
}
}
#endif
/*
* This function constructs an ICC profile memory with given header and tag data,
* which can be read via qcms_profile_from_memory(). that means, we must satisfy
* the profiler header type check (which seems not complete till now) and proper
* information to read data from the tag table and tag data elements memory.
*
* To construct a valid ICC profile, its divided into three steps :
* (1) construct the r/g/bXYZ part
* (2) construct the r/g/bTRC part
* (3) construct the profile header
* this is a hardcode step just for "create_rgb_with_gamma", it is the only
* requirement till now, maybe we can make this method more general in future,
*
* NOTE : some of the parameters below are hardcode, please refer to the ICC documentation.
*/
#define ICC_PROFILE_HEADER_LENGTH 128
void qcms_data_create_rgb_with_gamma(qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries, float gamma, void **mem, size_t *size)
{
uint32_t length, offset, index, xyz_count, trc_count;
size_t tag_table_offset, tag_data_offset;
void *data;
struct matrix colorants;
uint32_t TAG_XYZ[3] = {TAG_rXYZ, TAG_gXYZ, TAG_bXYZ};
uint32_t TAG_TRC[3] = {TAG_rTRC, TAG_gTRC, TAG_bTRC};
if ((mem == NULL) || (size == NULL))
return;
*mem = NULL;
*size = 0;
/*
* total length = icc profile header(128) + tag count(4) +
* (tag table item (12) * total tag (6 = 3 rTRC + 3 rXYZ)) + rTRC elements data (3 * 20)
* + rXYZ elements data (3*16), and all tag data elements must start at the 4-byte boundary.
*/
xyz_count = 3; // rXYZ, gXYZ, bXYZ
trc_count = 3; // rTRC, gTRC, bTRC
length = ICC_PROFILE_HEADER_LENGTH + 4 + (12 * (xyz_count + trc_count)) + (xyz_count * 20) + (trc_count * 16);
// reserve the total memory.
data = malloc(length);
if (!data)
return;
memset(data, 0, length);
// Part1 : write rXYZ, gXYZ and bXYZ
if (!get_rgb_colorants(&colorants, white_point, primaries)) {
free(data);
return;
}
// the position of first tag's signature in tag table
tag_table_offset = ICC_PROFILE_HEADER_LENGTH + 4;
tag_data_offset = ICC_PROFILE_HEADER_LENGTH + 4 +
(12 * (xyz_count + trc_count)); // the start of tag data elements.
for (index = 0; index < xyz_count; ++index) {
// tag table
write_u32(data, tag_table_offset, TAG_XYZ[index]);
write_u32(data, tag_table_offset+4, tag_data_offset);
write_u32(data, tag_table_offset+8, 20); // 20 bytes per TAG_(r/g/b)XYZ tag element
// tag data element
write_u32(data, tag_data_offset, XYZ_TYPE);
// reserved 4 bytes.
write_u32(data, tag_data_offset+8, double_to_s15Fixed16Number(colorants.m[0][index]));
write_u32(data, tag_data_offset+12, double_to_s15Fixed16Number(colorants.m[1][index]));
write_u32(data, tag_data_offset+16, double_to_s15Fixed16Number(colorants.m[2][index]));
tag_table_offset += 12;
tag_data_offset += 20;
}
// Part2 : write rTRC, gTRC and bTRC
for (index = 0; index < trc_count; ++index) {
// tag table
write_u32(data, tag_table_offset, TAG_TRC[index]);
write_u32(data, tag_table_offset+4, tag_data_offset);
write_u32(data, tag_table_offset+8, 14); // 14 bytes per TAG_(r/g/b)TRC element
// tag data element
write_u32(data, tag_data_offset, CURVE_TYPE);
// reserved 4 bytes.
write_u32(data, tag_data_offset+8, 1); // count
write_u16(data, tag_data_offset+12, float_to_u8Fixed8Number(gamma));
tag_table_offset += 12;
tag_data_offset += 16;
}
/* Part3 : write profile header
*
* Important header fields are left empty. This generates a profile for internal use only.
* We should be generating: Profile version (04300000h), Profile signature (acsp),
* PCS illumiant field. Likewise mandatory profile tags are omitted.
*/
write_u32(data, 0, length); // the total length of this memory
write_u32(data, 12, DISPLAY_DEVICE_PROFILE); // profile->class
write_u32(data, 16, RGB_SIGNATURE); // profile->color_space
write_u32(data, 20, XYZ_SIGNATURE); // profile->pcs
write_u32(data, 64, QCMS_INTENT_PERCEPTUAL); // profile->rendering_intent
write_u32(data, ICC_PROFILE_HEADER_LENGTH, 6); // total tag count
// prepare the result
*mem = data;
*size = length;
}

Просмотреть файл

@ -130,16 +130,27 @@ typedef struct
} qcms_CIE_xyYTRIPLE;
qcms_profile* qcms_profile_create_rgb_with_gamma(
qcms_CIE_xyY white_point,
qcms_CIE_xyYTRIPLE primaries,
float gamma);
qcms_CIE_xyY white_point,
qcms_CIE_xyYTRIPLE primaries,
float gamma);
void qcms_data_create_rgb_with_gamma(
qcms_CIE_xyY white_point,
qcms_CIE_xyYTRIPLE primaries,
float gamma,
void **mem,
size_t *size);
qcms_profile* qcms_profile_from_memory(const void *mem, size_t size);
qcms_profile* qcms_profile_from_file(FILE *file);
qcms_profile* qcms_profile_from_path(const char *path);
void qcms_data_from_path(const char *path, void **mem, size_t *size);
#ifdef _WIN32
qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path);
void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size);
#endif
qcms_profile* qcms_profile_sRGB(void);
void qcms_profile_release(qcms_profile *profile);

Просмотреть файл

@ -255,6 +255,7 @@ static inline float uInt16Number_to_float(uInt16Number a)
void precache_release(struct precache_output *p);
qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries);
qcms_bool get_rgb_colorants(struct matrix *colorants, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries);
void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
unsigned char *src,

Просмотреть файл

@ -306,6 +306,14 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
return true;
}
qcms_bool get_rgb_colorants(struct matrix *colorants, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries)
{
*colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
*colorants = adapt_matrix_to_D50(*colorants, white_point);
return (colorants->invalid ? true : false);
}
#if 0
static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
{

Просмотреть файл

@ -83,6 +83,12 @@ struct NS_GFX nsFont {
// constants; see gfxFontConstants.h).
int16_t stretch;
// Kerning
uint8_t kerning;
// Synthesis setting, controls use of fake bolding/italics
uint8_t synthesis;
// The logical size of the font, in nscoord units
nscoord size;
@ -106,12 +112,6 @@ struct NS_GFX nsFont {
// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
nsString languageOverride;
// Kerning
uint8_t kerning;
// Synthesis setting, controls use of fake bolding/italics
uint8_t synthesis;
// Initialize the font struct with an ASCII name
nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,

Просмотреть файл

@ -1707,10 +1707,23 @@ gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *tra
out = in;
}
qcms_profile *
gfxPlatform::GetPlatformCMSOutputProfile()
void
gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
{
return nullptr;
mem = nullptr;
size = 0;
}
void
gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
{
nsAdoptingCString fname = Preferences::GetCString("gfx.color_management.display_profile");
if (!fname.IsEmpty()) {
qcms_data_from_path(fname, &mem, &size);
}
else {
gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
}
}
void
@ -1729,15 +1742,14 @@ gfxPlatform::CreateCMSOutputProfile()
}
if (!gCMSOutputProfile) {
nsAdoptingCString fname = Preferences::GetCString(GFX_PREF_CMS_DISPLAY_PROFILE);
if (!fname.IsEmpty()) {
gCMSOutputProfile = qcms_profile_from_path(fname);
}
}
void* mem = nullptr;
size_t size = 0;
if (!gCMSOutputProfile) {
gCMSOutputProfile =
gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile();
GetCMSOutputProfileData(mem, size);
if ((mem != nullptr) && (size > 0)) {
gCMSOutputProfile = qcms_profile_from_memory(mem, size);
free(mem);
}
}
/* Determine if the profile looks bogus. If so, close the profile

Просмотреть файл

@ -712,9 +712,11 @@ private:
static void CreateCMSOutputProfile();
static void GetCMSOutputProfileData(void *&mem, size_t &size);
friend void RecordingPrefChanged(const char *aPrefName, void *aClosure);
virtual qcms_profile* GetPlatformCMSOutputProfile();
virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
virtual bool SupportsOffMainThreadCompositing() { return true; }

Просмотреть файл

@ -278,9 +278,12 @@ gfxPlatformGtk::SupportsOffMainThreadCompositing()
#endif
}
qcms_profile *
gfxPlatformGtk::GetPlatformCMSOutputProfile()
void
gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
{
mem = nullptr;
size = 0;
#ifdef MOZ_X11
const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
@ -289,11 +292,10 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
// In xpcshell tests, we never initialize X and hence don't have a Display.
// In this case, there's no output colour management to be done, so we just
// return nullptr.
if (!dpy) {
return nullptr;
}
// return with nullptr.
if (!dpy)
return;
Window root = gdk_x11_get_default_root_xwindow();
Atom retAtom;
@ -309,20 +311,24 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
False, AnyPropertyType,
&retAtom, &retFormat, &retLength,
&retAfter, &retProperty)) {
qcms_profile* profile = nullptr;
if (retLength > 0)
profile = qcms_profile_from_memory(retProperty, retLength);
if (retLength > 0) {
void *buffer = malloc(retLength);
if (buffer) {
memcpy(buffer, retProperty, retLength);
mem = buffer;
size = retLength;
}
}
XFree(retProperty);
if (profile) {
if (size > 0) {
#ifdef DEBUG_tor
fprintf(stderr,
"ICM profile read from %s successfully\n",
ICC_PROFILE_ATOM_NAME);
#endif
return profile;
return;
}
}
}
@ -341,7 +347,7 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
#ifdef DEBUG_tor
fprintf(stderr, "Short EDID data\n");
#endif
return nullptr;
return;
}
// Format documented in "VESA E-EDID Implementation Guide"
@ -383,23 +389,18 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile()
primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
#endif
qcms_profile* profile =
qcms_profile_create_rgb_with_gamma(whitePoint, primaries, gamma);
qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
#ifdef DEBUG_tor
if (profile) {
if (size > 0) {
fprintf(stderr,
"ICM profile read from %s successfully\n",
EDID1_ATOM_NAME);
}
#endif
return profile;
}
}
#endif
return nullptr;
}

Просмотреть файл

@ -99,7 +99,7 @@ protected:
static gfxFontconfigUtils *sFontconfigUtils;
private:
virtual qcms_profile *GetPlatformCMSOutputProfile();
virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
virtual bool SupportsOffMainThreadCompositing();
#ifdef MOZ_X11

Просмотреть файл

@ -425,15 +425,18 @@ gfxPlatformMac::SupportsOffMainThreadCompositing()
return true;
}
qcms_profile *
gfxPlatformMac::GetPlatformCMSOutputProfile()
void
gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
{
mem = nullptr;
size = 0;
CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
if (!cspace) {
cspace = ::CGColorSpaceCreateDeviceRGB();
}
if (!cspace) {
return nullptr;
return;
}
CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace);
@ -441,12 +444,20 @@ gfxPlatformMac::GetPlatformCMSOutputProfile()
::CFRelease(cspace);
if (!iccp) {
return nullptr;
return;
}
qcms_profile* profile = qcms_profile_from_memory(::CFDataGetBytePtr(iccp), static_cast<size_t>(::CFDataGetLength(iccp)));
// copy to external buffer
size = static_cast<size_t>(::CFDataGetLength(iccp));
if (size > 0) {
void *data = malloc(size);
if (data) {
memcpy(data, ::CFDataGetBytePtr(iccp), size);
mem = data;
} else {
size = 0;
}
}
::CFRelease(iccp);
return profile;
}

Просмотреть файл

@ -82,7 +82,7 @@ public:
virtual already_AddRefed<gfxASurface>
CreateThebesSurfaceAliasForDrawTarget_hack(mozilla::gfx::DrawTarget *aTarget);
private:
virtual qcms_profile* GetPlatformCMSOutputProfile();
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
virtual bool SupportsOffMainThreadCompositing();

Просмотреть файл

@ -64,6 +64,7 @@
#include <winternl.h>
#include "d3dkmtQueryStatistics.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
@ -1051,16 +1052,19 @@ gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aF
return ff->FindFontForStyle(aFontStyle, aNeedsBold);
}
qcms_profile*
gfxWindowsPlatform::GetPlatformCMSOutputProfile()
void
gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size)
{
WCHAR str[MAX_PATH];
DWORD size = MAX_PATH;
BOOL res;
mem = nullptr;
mem_size = 0;
HDC dc = GetDC(nullptr);
if (!dc)
return nullptr;
return;
#if _MSC_VER
__try {
@ -1074,16 +1078,18 @@ gfxWindowsPlatform::GetPlatformCMSOutputProfile()
ReleaseDC(nullptr, dc);
if (!res)
return nullptr;
return;
#ifdef _WIN32
qcms_data_from_unicode_path(str, &mem, &mem_size);
qcms_profile* profile = qcms_profile_from_unicode_path(str);
#ifdef DEBUG_tor
if (profile)
if (mem_size > 0)
fprintf(stderr,
"ICM profile read from %s successfully\n",
NS_ConvertUTF16toUTF8(str).get());
#endif
return profile;
#endif // DEBUG_tor
#endif // _WIN32
}
bool

Просмотреть файл

@ -294,7 +294,7 @@ private:
mozilla::RefPtr<ID3D11Device> mD3D11Device;
bool mD3D11DeviceInitialized;
virtual qcms_profile* GetPlatformCMSOutputProfile();
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
// TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;

Просмотреть файл

@ -111,9 +111,8 @@ ObjectIdCache::add(JSContext *cx, JSObject *obj, ObjectId id)
* been moved.
*/
/* static */ void
ObjectIdCache::keyMarkCallback(JSTracer *trc, void *keyArg, void *dataArg) {
JSObject *key = static_cast<JSObject*>(keyArg);
ObjectIdTable* table = static_cast<ObjectIdTable*>(dataArg);
ObjectIdCache::keyMarkCallback(JSTracer *trc, JSObject *key, void *data) {
ObjectIdTable* table = static_cast<ObjectIdTable*>(data);
JSObject *prior = key;
JS_CallObjectTracer(trc, &key, "ObjectIdCache::table_ key");
table->rekeyIfMoved(prior, key);

Просмотреть файл

@ -75,7 +75,7 @@ class ObjectIdCache
void remove(JSObject *obj);
private:
static void keyMarkCallback(JSTracer *trc, void *key, void *data);
static void keyMarkCallback(JSTracer *trc, JSObject *key, void *data);
ObjectIdTable *table_;
};

Просмотреть файл

@ -119,25 +119,6 @@ endif
ifdef ENABLE_INTL_API
ifndef MOZ_NATIVE_ICU
ifdef _MSC_VER
ifdef MOZ_SHARED_ICU
OS_LIBS += $(call EXPAND_LIBNAME,delayimp)
ifdef MOZ_DEBUG
EXTRA_DSO_LDOPTS += \
-DELAYLOAD:icudtd$(MOZ_ICU_VERSION).dll \
-DELAYLOAD:icuind$(MOZ_ICU_VERSION).dll \
-DELAYLOAD:icuucd$(MOZ_ICU_VERSION).dll \
$(NULL)
else
EXTRA_DSO_LDOPTS += \
-DELAYLOAD:icudt$(MOZ_ICU_VERSION).dll \
-DELAYLOAD:icuin$(MOZ_ICU_VERSION).dll \
-DELAYLOAD:icuuc$(MOZ_ICU_VERSION).dll \
$(NULL)
endif
endif
endif
endif
endif

Просмотреть файл

@ -781,11 +781,15 @@ if test -n "$CROSS_COMPILE"; then
OS_RELEASE=
case "${target_os}" in
linux*) OS_ARCH=Linux OS_TARGET=Linux ;;
kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;;
kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU/kFreeBSD ;;
gnu*) OS_ARCH=GNU ;;
solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;;
mingw*) OS_ARCH=WINNT OS_TARGET=WINNT ;;
darwin*) OS_ARCH=Darwin OS_TARGET=Darwin ;;
dragonfly*) OS_ARCH=DragonFly OS_TARGET=DragonFly ;;
freebsd*) OS_ARCH=FreeBSD OS_TARGET=FreeBSD ;;
netbsd*) OS_ARCH=NetBSD OS_TARGET=NetBSD ;;
openbsd*) OS_ARCH=OpenBSD OS_TARGET=OpenBSD ;;
esac
case "${target}" in
*-android*|*-linuxandroid*) OS_ARCH=Linux OS_TARGET=Android ;;

Просмотреть файл

@ -4761,16 +4761,15 @@ StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
}
static void
PostBarrierCallback(JSTracer *trc, void *k, void *d)
PostBarrierCallback(JSTracer *trc, JSString *key, void *data)
{
typedef HashMap<JSFlatString*,
UnbarrieredFieldInfo,
FieldHashPolicy,
SystemAllocPolicy> UnbarrieredFieldInfoHash;
JSString *prior = static_cast<JSString*>(k);
UnbarrieredFieldInfoHash *table = reinterpret_cast<UnbarrieredFieldInfoHash*>(d);
JSString *key = prior;
UnbarrieredFieldInfoHash *table = reinterpret_cast<UnbarrieredFieldInfoHash*>(data);
JSString *prior = key;
JS_CallStringTracer(trc, &key, "CType fieldName");
table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
}

Просмотреть файл

@ -331,12 +331,13 @@ class StoreBuffer
void mark(JSTracer *trc);
};
template <typename Key>
class CallbackRef : public BufferableRef
{
public:
typedef void (*MarkCallback)(JSTracer *trc, void *key, void *data);
typedef void (*MarkCallback)(JSTracer *trc, Key *key, void *data);
CallbackRef(MarkCallback cb, void *k, void *d) : callback(cb), key(k), data(d) {}
CallbackRef(MarkCallback cb, Key *k, void *d) : callback(cb), key(k), data(d) {}
virtual void mark(JSTracer *trc) {
callback(trc, key, data);
@ -344,7 +345,7 @@ class StoreBuffer
private:
MarkCallback callback;
void *key;
Key *key;
void *data;
};
@ -441,8 +442,9 @@ class StoreBuffer
void putGeneric(const T &t) { put(bufferGeneric, t);}
/* Insert or update a callback entry. */
void putCallback(CallbackRef::MarkCallback callback, Cell *key, void *data) {
put(bufferGeneric, CallbackRef(callback, key, data));
template <typename Key>
void putCallback(void (*callback)(JSTracer *trc, Key *key, void *data), Key *key, void *data) {
put(bufferGeneric, CallbackRef<Key>(callback, key, data));
}
/* Mark the source of all edges in the store buffer. */

Просмотреть файл

@ -0,0 +1,2 @@
(()=>{ var x,y,z; ()=>{x++;y++;z++} })();
(()=>{ var x,y; if (true) { function z() { x++;y++ } } })();

Просмотреть файл

@ -19,6 +19,7 @@
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsopcodeinlines.h"
using namespace js;
using namespace js::jit;
@ -1522,7 +1523,7 @@ jit::ExtractLinearInequality(MTest *test, BranchDirection direction,
JSOp jsop = compare->jsop();
if (direction == FALSE_BRANCH)
jsop = analyze::NegateCompareOp(jsop);
jsop = NegateCompareOp(jsop);
SimpleLinearSum lsum = ExtractLinearSum(lhs);
SimpleLinearSum rsum = ExtractLinearSum(rhs);

Просмотреть файл

@ -28,6 +28,7 @@
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsopcodeinlines.h"
#include "jsscriptinlines.h"
#include "jit/CompileInfo-inl.h"

Просмотреть файл

@ -453,10 +453,8 @@ class InlineFrameIteratorMaybeGC
// scopeChain
Value v = s.read();
if (v.isObject()) {
JS_ASSERT_IF(script()->hasAnalysis(), script()->analysis()->usesScopeChain());
if (v.isObject())
return &v.toObject();
}
return callee()->environment();
}

Просмотреть файл

@ -17,6 +17,7 @@
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsopcodeinlines.h"
#include "jit/shared/Lowering-shared-inl.h"
@ -592,7 +593,7 @@ ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp)
if (lhs->isConstant()) {
*rhsp = lhs;
*lhsp = rhs;
return js::analyze::ReverseCompareOp(op);
return ReverseCompareOp(op);
}
return op;
}

Просмотреть файл

@ -18,6 +18,8 @@
#include "jit/MIRGraph.h"
#include "vm/NumericConversions.h"
#include "jsopcodeinlines.h"
using namespace js;
using namespace js::jit;
@ -167,7 +169,7 @@ RangeAnalysis::addBetaNodes()
JSOp jsop = compare->jsop();
if (branch_dir == FALSE_BRANCH) {
jsop = analyze::NegateCompareOp(jsop);
jsop = NegateCompareOp(jsop);
conservativeLower = GenericNaN();
conservativeUpper = GenericNaN();
}
@ -175,7 +177,7 @@ RangeAnalysis::addBetaNodes()
if (left->isConstant() && left->toConstant()->value().isNumber()) {
bound = left->toConstant()->value().toNumber();
val = right;
jsop = analyze::ReverseCompareOp(jsop);
jsop = ReverseCompareOp(jsop);
} else if (right->isConstant() && right->toConstant()->value().isNumber()) {
bound = right->toConstant()->value().toNumber();
val = left;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -14,210 +14,15 @@
namespace js {
namespace analyze {
class LoopAnalysis;
class Bytecode;
struct LifetimeVariable;
class SlotValue;
class SSAValue;
struct SSAValueInfo;
class SSAUseChain;
/*
* There are three analyses we can perform on a JSScript, outlined below.
* The results of all three are stored in ScriptAnalysis, but the analyses
* themselves can be performed separately. Along with type inference results,
* per-script analysis results are tied to the per-compartment analysis pool
* and are freed on every garbage collection.
*
* - Basic bytecode analysis. For each bytecode, determine the stack depth at
* that point and control flow information needed for compilation. Also does
* a defined-variables analysis to look for local variables which have uses
* before definitions.
*
* - Lifetime analysis. Makes a backwards pass over the script to approximate
* the regions where each variable is live, avoiding a full fixpointing
* live-variables pass. This is based on the algorithm described in:
*
* "Quality and Speed in Linear-scan Register Allocation"
* Traub et. al.
* PLDI, 1998
*
* - SSA analysis of the script's variables and stack values. For each stack
* value popped and non-escaping local variable or argument read, determines
* which push(es) or write(s) produced that value.
*
* Intermediate type inference results are additionally stored here. The above
* analyses are independent from type inference.
*/
/* Information about a bytecode instruction. */
class Bytecode
{
friend class ScriptAnalysis;
public:
Bytecode() { mozilla::PodZero(this); }
/* --------- Bytecode analysis --------- */
/* Whether there are any incoming jumps to this instruction. */
bool jumpTarget : 1;
/* Whether there is fallthrough to this instruction from a non-branching instruction. */
bool fallthrough : 1;
/* Whether this instruction is the fall through point of a conditional jump. */
bool jumpFallthrough : 1;
/*
* Whether this instruction must always execute, unless the script throws
* an exception which it does not later catch.
*/
bool unconditional : 1;
/* Whether this instruction has been analyzed to get its output defines and stack. */
bool analyzed : 1;
/* Whether this is a catch/finally entry point. */
bool exceptionEntry : 1;
/* Stack depth before this opcode. */
uint32_t stackDepth;
private:
/* If this is a JSOP_LOOPHEAD or JSOP_LOOPENTRY, information about the loop. */
LoopAnalysis *loop;
/* --------- SSA analysis --------- */
/* Generated location of each value popped by this bytecode. */
SSAValue *poppedValues;
/* Points where values pushed or written by this bytecode are popped. */
SSAUseChain **pushedUses;
union {
/*
* If this is a join point (implies jumpTarget), any slots at this
* point which can have a different values than at the immediate
* predecessor in the bytecode. Array is terminated by an entry with
* a zero slot.
*/
SlotValue *newValues;
/*
* Vector used during SSA analysis to store values in need of merging
* at this point. If this has incoming forward jumps and we have not
* yet reached this point, stores values for entries on the stack and
* for variables which have changed since the branch. If this is a loop
* head and we haven't reached the back edge yet, stores loop phi nodes
* for variables and entries live at the head of the loop.
*/
Vector<SlotValue> *pendingValues;
};
};
/*
* For opcodes which assign to a local variable or argument, track an extra def
* during SSA analysis for the value's use chain and assigned type.
*/
static inline bool
ExtendedDef(jsbytecode *pc)
{
switch ((JSOp)*pc) {
case JSOP_SETARG:
case JSOP_SETLOCAL:
return true;
default:
return false;
}
}
/*
* For opcodes which access local variables or arguments, we track an extra
* use during SSA analysis for the value of the variable before/after the op.
*/
static inline bool
ExtendedUse(jsbytecode *pc)
{
if (ExtendedDef(pc))
return true;
switch ((JSOp)*pc) {
case JSOP_GETARG:
case JSOP_CALLARG:
case JSOP_GETLOCAL:
case JSOP_CALLLOCAL:
return true;
default:
return false;
}
}
static inline JSOp
ReverseCompareOp(JSOp op)
{
switch (op) {
case JSOP_GT:
return JSOP_LT;
case JSOP_GE:
return JSOP_LE;
case JSOP_LT:
return JSOP_GT;
case JSOP_LE:
return JSOP_GE;
case JSOP_EQ:
case JSOP_NE:
case JSOP_STRICTEQ:
case JSOP_STRICTNE:
return op;
default:
MOZ_ASSUME_UNREACHABLE("unrecognized op");
}
}
static inline JSOp
NegateCompareOp(JSOp op)
{
switch (op) {
case JSOP_GT:
return JSOP_LE;
case JSOP_GE:
return JSOP_LT;
case JSOP_LT:
return JSOP_GE;
case JSOP_LE:
return JSOP_GT;
case JSOP_EQ:
return JSOP_NE;
case JSOP_NE:
return JSOP_EQ;
case JSOP_STRICTNE:
return JSOP_STRICTEQ;
case JSOP_STRICTEQ:
return JSOP_STRICTNE;
default:
MOZ_ASSUME_UNREACHABLE("unrecognized op");
}
}
static inline unsigned
FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
{
/*
* Get the target offset of a branch. For GOTO opcodes implementing
* 'continue' statements, short circuit any artificial backwards jump
* inserted by the emitter.
*/
jsbytecode *pc = script->offsetToPC(offset);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
if (targetOffset < offset) {
jsbytecode *target = script->offsetToPC(targetOffset);
JSOp nop = JSOp(*target);
if (nop == JSOP_GOTO)
return targetOffset + GET_JUMP_OFFSET(target);
}
return targetOffset;
}
/* Common representation of slots throughout analyses and the compiler. */
// Common representation of slots between ScriptAnalysis, TypeScript, and in the
// case of TotalSlots, Ion.
static inline uint32_t ThisSlot() {
return 0;
}
@ -232,371 +37,10 @@ static inline uint32_t TotalSlots(JSScript *script) {
return LocalSlot(script, 0) + script->nfixed();
}
static inline uint32_t StackSlot(JSScript *script, uint32_t index) {
return TotalSlots(script) + index;
}
static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc)
{
switch (JSOp(*pc)) {
case JSOP_GETARG:
case JSOP_CALLARG:
case JSOP_SETARG:
return ArgSlot(GET_ARGNO(pc));
case JSOP_GETLOCAL:
case JSOP_CALLLOCAL:
case JSOP_SETLOCAL:
return LocalSlot(script, GET_LOCALNO(pc));
case JSOP_THIS:
return ThisSlot();
default:
MOZ_ASSUME_UNREACHABLE("Bad slot opcode");
}
}
/*
* Information about the lifetime of a local or argument. These form a linked
* list describing successive intervals in the program where the variable's
* value may be live. At points in the script not in one of these segments
* (points in a 'lifetime hole'), the variable is dead and registers containing
* its type/payload can be discarded without needing to be synced.
*/
struct Lifetime
{
/*
* Start and end offsets of this lifetime. The variable is live at the
* beginning of every bytecode in this (inclusive) range.
*/
uint32_t start;
uint32_t end;
/*
* In a loop body, endpoint to extend this lifetime with if the variable is
* live in the next iteration.
*/
uint32_t savedEnd;
/*
* The start of this lifetime is a bytecode writing the variable. Each
* write to a variable is associated with a lifetime.
*/
bool write;
/* Next lifetime. The variable is dead from this->end to next->start. */
Lifetime *next;
Lifetime(uint32_t offset, uint32_t savedEnd, Lifetime *next)
: start(offset), end(offset), savedEnd(savedEnd),
write(false), next(next)
{}
};
/* Basic information for a loop. */
class LoopAnalysis
{
public:
/* Any loop this one is nested in. */
LoopAnalysis *parent;
/* Offset of the head of the loop. */
uint32_t head;
/*
* Offset of the unique jump going to the head of the loop. The code
* between the head and the backedge forms the loop body.
*/
uint32_t backedge;
};
/* Current lifetime information for a variable. */
struct LifetimeVariable
{
/* If the variable is currently live, the lifetime segment. */
Lifetime *lifetime;
/* If the variable is currently dead, the next live segment. */
Lifetime *saved;
/* Jump preceding the basic block which killed this variable. */
uint32_t savedEnd : 31;
/* If the variable needs to be kept alive until lifetime->start. */
bool ensured : 1;
/* Whether this variable is live at offset. */
Lifetime * live(uint32_t offset) const {
if (lifetime && lifetime->end >= offset)
return lifetime;
Lifetime *segment = lifetime ? lifetime : saved;
while (segment && segment->start <= offset) {
if (segment->end >= offset)
return segment;
segment = segment->next;
}
return nullptr;
}
/*
* Get the offset of the first write to the variable in an inclusive range,
* UINT32_MAX if the variable is not written in the range.
*/
uint32_t firstWrite(uint32_t start, uint32_t end) const {
Lifetime *segment = lifetime ? lifetime : saved;
while (segment && segment->start <= end) {
if (segment->start >= start && segment->write)
return segment->start;
segment = segment->next;
}
return UINT32_MAX;
}
uint32_t firstWrite(LoopAnalysis *loop) const {
return firstWrite(loop->head, loop->backedge);
}
/*
* If the variable is only written once in the body of a loop, offset of
* that write. UINT32_MAX otherwise.
*/
uint32_t onlyWrite(LoopAnalysis *loop) const {
uint32_t offset = UINT32_MAX;
Lifetime *segment = lifetime ? lifetime : saved;
while (segment && segment->start <= loop->backedge) {
if (segment->start >= loop->head && segment->write) {
if (offset != UINT32_MAX)
return UINT32_MAX;
offset = segment->start;
}
segment = segment->next;
}
return offset;
}
#ifdef DEBUG
void print() const;
#endif
};
struct SSAPhiNode;
/*
* Representation of values on stack or in slots at each point in the script.
* Values are independent from the bytecode position, and mean the same thing
* everywhere in the script. SSA values are immutable, except for contents of
* the values and types in an SSAPhiNode.
*/
class SSAValue
{
friend class ScriptAnalysis;
public:
enum Kind {
EMPTY = 0, /* Invalid entry. */
PUSHED = 1, /* Value pushed by some bytecode. */
VAR = 2, /* Initial or written value to some argument or local. */
PHI = 3 /* Selector for one of several values. */
};
Kind kind() const {
JS_ASSERT(u.pushed.kind == u.var.kind && u.pushed.kind == u.phi.kind);
/* Use a bitmask because MSVC wants to use -1 for PHI nodes. */
return (Kind) (u.pushed.kind & 0x3);
}
bool operator==(const SSAValue &o) const {
return !memcmp(this, &o, sizeof(SSAValue));
}
/* Accessors for values pushed by a bytecode within this script. */
uint32_t pushedOffset() const {
JS_ASSERT(kind() == PUSHED);
return u.pushed.offset;
}
uint32_t pushedIndex() const {
JS_ASSERT(kind() == PUSHED);
return u.pushed.index;
}
/* Accessors for initial and written values of arguments and (undefined) locals. */
bool varInitial() const {
JS_ASSERT(kind() == VAR);
return u.var.initial;
}
uint32_t varSlot() const {
JS_ASSERT(kind() == VAR);
return u.var.slot;
}
uint32_t varOffset() const {
JS_ASSERT(!varInitial());
return u.var.offset;
}
/* Accessors for phi nodes. */
uint32_t phiSlot() const;
uint32_t phiLength() const;
const SSAValue &phiValue(uint32_t i) const;
/* Offset at which this phi node was created. */
uint32_t phiOffset() const {
JS_ASSERT(kind() == PHI);
return u.phi.offset;
}
SSAPhiNode *phiNode() const {
JS_ASSERT(kind() == PHI);
return u.phi.node;
}
/* Other accessors. */
#ifdef DEBUG
void print() const;
#endif
void clear() {
mozilla::PodZero(this);
JS_ASSERT(kind() == EMPTY);
}
void initPushed(uint32_t offset, uint32_t index) {
clear();
u.pushed.kind = PUSHED;
u.pushed.offset = offset;
u.pushed.index = index;
}
static SSAValue PushedValue(uint32_t offset, uint32_t index) {
SSAValue v;
v.initPushed(offset, index);
return v;
}
void initInitial(uint32_t slot) {
clear();
u.var.kind = VAR;
u.var.initial = true;
u.var.slot = slot;
}
void initWritten(uint32_t slot, uint32_t offset) {
clear();
u.var.kind = VAR;
u.var.initial = false;
u.var.slot = slot;
u.var.offset = offset;
}
static SSAValue WrittenVar(uint32_t slot, uint32_t offset) {
SSAValue v;
v.initWritten(slot, offset);
return v;
}
void initPhi(uint32_t offset, SSAPhiNode *node) {
clear();
u.phi.kind = PHI;
u.phi.offset = offset;
u.phi.node = node;
}
static SSAValue PhiValue(uint32_t offset, SSAPhiNode *node) {
SSAValue v;
v.initPhi(offset, node);
return v;
}
private:
union {
struct {
Kind kind : 2;
uint32_t offset : 30;
uint32_t index;
} pushed;
struct {
Kind kind : 2;
bool initial : 1;
uint32_t slot : 29;
uint32_t offset;
} var;
struct {
Kind kind : 2;
uint32_t offset : 30;
SSAPhiNode *node;
} phi;
} u;
};
/*
* Mutable component of a phi node, with the possible values of the phi
* and the possible types of the node as determined by type inference.
* When phi nodes are copied around, any updates to the original will
* be seen by all copies made.
*/
struct SSAPhiNode
{
uint32_t slot;
uint32_t length;
SSAValue *options;
SSAUseChain *uses;
SSAPhiNode() { mozilla::PodZero(this); }
};
inline uint32_t
SSAValue::phiSlot() const
{
return u.phi.node->slot;
}
inline uint32_t
SSAValue::phiLength() const
{
JS_ASSERT(kind() == PHI);
return u.phi.node->length;
}
inline const SSAValue &
SSAValue::phiValue(uint32_t i) const
{
JS_ASSERT(kind() == PHI && i < phiLength());
return u.phi.node->options[i];
}
class SSAUseChain
{
public:
bool popped : 1;
uint32_t offset : 31;
/* FIXME: Assert that only the proper arm of this union is accessed. */
union {
uint32_t which;
SSAPhiNode *phi;
} u;
SSAUseChain *next;
SSAUseChain() { mozilla::PodZero(this); }
};
class SlotValue
{
public:
uint32_t slot;
SSAValue value;
SlotValue(uint32_t slot, const SSAValue &value) : slot(slot), value(value) {}
};
struct NeedsArgsObjState;
/* Analysis information about a script. */
// Analysis information about a script. FIXME: At this point, the entire
// purpose of this class is to compute JSScript::needsArgsObj, and to support
// isReachable() in order for jsinfer.cpp:FindPreviousInnerInitializer to get
// the previous opcode. For that purpose, it is completely overkill.
class ScriptAnalysis
{
friend class Bytecode;
@ -606,18 +50,9 @@ class ScriptAnalysis
Bytecode **codeArray;
uint32_t numSlots;
uint32_t numPropertyReads_;
bool outOfMemory;
bool hadFailure;
bool *escapedSlots;
/* Which analyses have been performed. */
bool ranBytecode_;
bool ranSSA_;
bool ranLifetimes_;
#ifdef DEBUG
/* Whether the compartment was in debug mode when we performed the analysis. */
bool originalDebugMode_: 1;
@ -625,21 +60,15 @@ class ScriptAnalysis
/* --------- Bytecode analysis --------- */
bool usesScopeChain_:1;
bool localsAliasStack_:1;
bool canTrackVars:1;
bool hasLoops_:1;
bool hasTryFinally_:1;
bool argumentsContentsObserved_:1;
uint32_t numReturnSites_;
/* --------- Lifetime analysis --------- */
LifetimeVariable *lifetimes;
public:
ScriptAnalysis(JSScript *script) {
mozilla::PodZero(this);
this->script_ = script;
@ -648,29 +77,8 @@ class ScriptAnalysis
#endif
}
bool ranBytecode() { return ranBytecode_; }
bool ranSSA() { return ranSSA_; }
bool ranLifetimes() { return ranLifetimes_; }
void analyzeBytecode(JSContext *cx);
void analyzeSSA(JSContext *cx);
void analyzeLifetimes(JSContext *cx);
bool OOM() const { return outOfMemory; }
bool failed() const { return hadFailure; }
/* Whether the script has a |finally| block. */
bool hasTryFinally() const { return hasTryFinally_; }
/* Number of property read opcodes in the script. */
uint32_t numPropertyReads() const { return numPropertyReads_; }
/* Whether there are NAME bytecodes which can access the frame's scope chain. */
bool usesScopeChain() const { return usesScopeChain_; }
uint32_t numReturnSites() const { return numReturnSites_; }
bool hasLoops() const { return hasLoops_; }
JS_WARN_UNUSED_RESULT
bool analyzeBytecode(JSContext *cx);
/*
* True if there are any LOCAL opcodes aliasing values on the stack (above
@ -678,8 +86,15 @@ class ScriptAnalysis
*/
bool localsAliasStack() { return localsAliasStack_; }
/* Accessors for bytecode information. */
bool isReachable(const jsbytecode *pc) { return maybeCode(pc); }
private:
JS_WARN_UNUSED_RESULT
bool analyzeSSA(JSContext *cx);
JS_WARN_UNUSED_RESULT
bool analyzeLifetimes(JSContext *cx);
/* Accessors for bytecode information. */
Bytecode& getCode(uint32_t offset) {
JS_ASSERT(offset < script_->length());
JS_ASSERT(codeArray[offset]);
@ -693,32 +108,16 @@ class ScriptAnalysis
}
Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(script_->pcToOffset(pc)); }
bool jumpTarget(uint32_t offset) {
JS_ASSERT(offset < script_->length());
return codeArray[offset] && codeArray[offset]->jumpTarget;
}
bool jumpTarget(const jsbytecode *pc) { return jumpTarget(script_->pcToOffset(pc)); }
bool popGuaranteed(jsbytecode *pc) {
jsbytecode *next = pc + GetBytecodeLength(pc);
return JSOp(*next) == JSOP_POP && !jumpTarget(next);
}
inline bool jumpTarget(uint32_t offset);
inline bool jumpTarget(const jsbytecode *pc);
inline const SSAValue &poppedValue(uint32_t offset, uint32_t which);
inline const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which);
const SlotValue *newValues(uint32_t offset) {
JS_ASSERT(offset < script_->length());
return getCode(offset).newValues;
}
const SlotValue *newValues(const jsbytecode *pc) { return newValues(script_->pcToOffset(pc)); }
inline const SlotValue *newValues(uint32_t offset);
inline const SlotValue *newValues(const jsbytecode *pc);
bool trackUseChain(const SSAValue &v) {
JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
return v.kind() != SSAValue::EMPTY &&
(v.kind() != SSAValue::VAR || !v.varInitial());
}
inline bool trackUseChain(const SSAValue &v);
/*
* Get the use chain for an SSA value. May be invalid for some opcodes in
@ -739,12 +138,7 @@ class ScriptAnalysis
* mode, and slots which are aliased by NAME or similar opcodes in the
* containing script (which does not imply the variable is closed).
*/
bool slotEscapes(uint32_t slot) {
JS_ASSERT(script_->compartment()->activeAnalysis);
if (slot >= numSlots)
return true;
return escapedSlots[slot];
}
inline bool slotEscapes(uint32_t slot);
/*
* Whether we distinguish different writes of this variable while doing
@ -752,68 +146,58 @@ class ScriptAnalysis
* presence of NAME opcodes which could alias local variables or arguments
* keeps us from tracking variable values at each point.
*/
bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars && slot < 1000; }
inline bool trackSlot(uint32_t slot);
const LifetimeVariable & liveness(uint32_t slot) {
JS_ASSERT(script_->compartment()->activeAnalysis);
JS_ASSERT(!slotEscapes(slot));
return lifetimes[slot];
}
inline const LifetimeVariable & liveness(uint32_t slot);
void printSSA(JSContext *cx);
void printTypes(JSContext *cx);
private:
void setOOM(JSContext *cx) {
if (!outOfMemory)
js_ReportOutOfMemory(cx);
outOfMemory = true;
hadFailure = true;
}
/* Bytecode helpers */
JS_WARN_UNUSED_RESULT
inline bool addJump(JSContext *cx, unsigned offset,
unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
unsigned stackDepth);
/* Lifetime helpers */
inline void addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
JS_WARN_UNUSED_RESULT
inline bool addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
LifetimeVariable **&saved, unsigned &savedCount);
inline void killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
JS_WARN_UNUSED_RESULT
inline bool killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
LifetimeVariable **&saved, unsigned &savedCount);
inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
JS_WARN_UNUSED_RESULT
inline bool extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
inline void ensureVariable(LifetimeVariable &var, unsigned until);
/* Current value for a variable or stack value, as tracked during SSA. */
struct SSAValueInfo
{
SSAValue v;
/*
* Sizes of branchTargets the last time this slot was written. Branches less
* than this threshold do not need to be inspected if the slot is written
* again, as they will already reflect the slot's value at the branch.
*/
int32_t branchSize;
};
/* SSA helpers */
JS_WARN_UNUSED_RESULT
bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv);
void insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
void mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv);
void checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
JS_WARN_UNUSED_RESULT
bool insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
JS_WARN_UNUSED_RESULT
bool mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv);
JS_WARN_UNUSED_RESULT
bool checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
Vector<SlotValue> *pending);
void checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
JS_WARN_UNUSED_RESULT
bool checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
SSAValueInfo *values, uint32_t stackDepth);
void checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
JS_WARN_UNUSED_RESULT
bool checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
Vector<uint32_t> &exceptionTargets);
void mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
JS_WARN_UNUSED_RESULT
bool mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
const Vector<uint32_t> &branchTargets, uint32_t currentOffset);
void mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
JS_WARN_UNUSED_RESULT
bool mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
const Vector<uint32_t> &exceptionTargets);
void mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
JS_WARN_UNUSED_RESULT
bool mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
const Vector<uint32_t> &exceptionTargets);
void freezeNewValues(JSContext *cx, uint32_t offset);
JS_WARN_UNUSED_RESULT
bool freezeNewValues(JSContext *cx, uint32_t offset);
typedef Vector<SSAValue, 16> SeenVector;
bool needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v);
@ -823,8 +207,10 @@ class ScriptAnalysis
public:
#ifdef DEBUG
void assertMatchingDebugMode();
void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth);
#else
void assertMatchingDebugMode() { }
void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth) { }
#endif
};
@ -835,14 +221,4 @@ void PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc);
} /* namespace analyze */
} /* namespace js */
namespace mozilla {
template <> struct IsPod<js::analyze::LifetimeVariable> : TrueType {};
template <> struct IsPod<js::analyze::LoopAnalysis> : TrueType {};
template <> struct IsPod<js::analyze::SlotValue> : TrueType {};
template <> struct IsPod<js::analyze::SSAValue> : TrueType {};
template <> struct IsPod<js::analyze::SSAUseChain> : TrueType {};
} /* namespace mozilla */
#endif /* jsanalyze_h */

Просмотреть файл

@ -1,54 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jsanalyzeinlines_h
#define jsanalyzeinlines_h
#include "jsanalyze.h"
#include "jsopcodeinlines.h"
namespace js {
namespace analyze {
inline const SSAValue &
ScriptAnalysis::poppedValue(uint32_t offset, uint32_t which)
{
JS_ASSERT(which < GetUseCount(script_, offset) +
(ExtendedUse(script_->offsetToPC(offset)) ? 1 : 0));
return getCode(offset).poppedValues[which];
}
inline const SSAValue &
ScriptAnalysis::poppedValue(const jsbytecode *pc, uint32_t which)
{
return poppedValue(script_->pcToOffset(pc), which);
}
inline SSAUseChain *&
ScriptAnalysis::useChain(const SSAValue &v)
{
JS_ASSERT(trackUseChain(v));
if (v.kind() == SSAValue::PUSHED)
return getCode(v.pushedOffset()).pushedUses[v.pushedIndex()];
if (v.kind() == SSAValue::VAR)
return getCode(v.varOffset()).pushedUses[GetDefCount(script_, v.varOffset())];
return v.phiNode()->uses;
}
inline jsbytecode *
ScriptAnalysis::getCallPC(jsbytecode *pc)
{
SSAUseChain *uses = useChain(SSAValue::PushedValue(script_->pcToOffset(pc), 0));
JS_ASSERT(uses && uses->popped);
JS_ASSERT(js_CodeSpec[script_->code()[uses->offset]].format & JOF_INVOKE);
return script_->offsetToPC(uses->offset);
}
} /* namespace analyze */
} /* namespace js */
#endif /* jsanalyzeinlines_h */

Просмотреть файл

@ -247,7 +247,7 @@ struct JSCompartment
js::types::TypeObjectWithNewScriptSet newTypeObjects;
js::types::TypeObjectWithNewScriptSet lazyTypeObjects;
void sweepNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet &table);
#if defined(JSGC_GENERATIONAL) and defined(JS_GC_ZEAL)
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
void checkNewTypeObjectTableAfterMovingGC();
void checkInitialShapesTableAfterMovingGC();
void checkWrapperMapAfterMovingGC();

Просмотреть файл

@ -1227,17 +1227,21 @@ js::IsInRequest(JSContext *cx)
#ifdef JSGC_GENERATIONAL
JS_FRIEND_API(void)
JS_StoreObjectPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSObject *key, void *data),
JSObject *key, void *data)
{
cx->runtime()->gcStoreBuffer.putCallback(callback, key, data);
JSRuntime *rt = cx->runtime();
if (IsInsideNursery(rt, key))
rt->gcStoreBuffer.putCallback(callback, key, data);
}
extern JS_FRIEND_API(void)
JS_StoreStringPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSString *key, void *data),
JSString *key, void *data)
{
cx->runtime()->gcStoreBuffer.putCallback(callback, key, data);
JSRuntime *rt = cx->runtime();
if (IsInsideNursery(rt, key))
rt->gcStoreBuffer.putCallback(callback, key, data);
}
#endif /* JSGC_GENERATIONAL */

Просмотреть файл

@ -1478,6 +1478,13 @@ struct JSJitInfo {
ArgTypeListEnd = (1 << 31)
};
static_assert(Any & String, "Any must include String.");
static_assert(Any & Integer, "Any must include Integer.");
static_assert(Any & Double, "Any must include Double.");
static_assert(Any & Boolean, "Any must include Boolean.");
static_assert(Any & Object, "Any must include Object.");
static_assert(Any & Null, "Any must include Null.");
enum AliasSet {
// An enum that describes what this getter/setter/method aliases. This
// determines what things can be hoisted past this call, and if this
@ -1585,17 +1592,6 @@ struct JSJitInfo {
JSTypedMethodJitInfo. */
uint32_t slotIndex : 12; /* If isInSlot is true, the index of the slot to
get the value from. Otherwise 0. */
private:
static void staticAsserts()
{
JS_STATIC_ASSERT(Any & String);
JS_STATIC_ASSERT(Any & Integer);
JS_STATIC_ASSERT(Any & Double);
JS_STATIC_ASSERT(Any & Boolean);
JS_STATIC_ASSERT(Any & Object);
JS_STATIC_ASSERT(Any & Null);
}
};
static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)),
@ -1892,22 +1888,22 @@ js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v);
#ifdef JSGC_GENERATIONAL
extern JS_FRIEND_API(void)
JS_StoreObjectPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSObject *key, void *data),
JSObject *key, void *data);
extern JS_FRIEND_API(void)
JS_StoreStringPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSString *key, void *data),
JSString *key, void *data);
#else
inline void
JS_StoreObjectPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSObject *key, void *data),
JSObject *key, void *data) {}
inline void
JS_StoreStringPostBarrierCallback(JSContext* cx,
void (*callback)(JSTracer *trc, void *key, void *data),
void (*callback)(JSTracer *trc, JSString *key, void *data),
JSString *key, void *data) {}
#endif /* JSGC_GENERATIONAL */

Просмотреть файл

@ -1874,13 +1874,13 @@ static inline jsbytecode *
PreviousOpcode(HandleScript script, jsbytecode *pc)
{
ScriptAnalysis *analysis = script->analysis();
JS_ASSERT(analysis->maybeCode(pc));
JS_ASSERT(analysis->isReachable(pc));
if (pc == script->code())
return nullptr;
for (pc--;; pc--) {
if (analysis->maybeCode(pc))
if (analysis->isReachable(pc))
break;
}
@ -1897,7 +1897,7 @@ FindPreviousInnerInitializer(HandleScript script, jsbytecode *initpc)
if (!script->hasAnalysis())
return nullptr;
if (!script->analysis()->maybeCode(initpc))
if (!script->analysis()->isReachable(initpc))
return nullptr;
/*
@ -3728,9 +3728,7 @@ JSScript::makeAnalysis(JSContext *cx)
RootedScript self(cx, this);
self->types->analysis->analyzeBytecode(cx);
if (self->types->analysis->OOM()) {
if (!self->types->analysis->analyzeBytecode(cx)) {
self->types->analysis = nullptr;
return false;
}
@ -4073,7 +4071,7 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
return type;
}
#if defined(JSGC_GENERATIONAL) and defined(JS_GC_ZEAL)
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
void
JSCompartment::checkNewTypeObjectTableAfterMovingGC()
{

Просмотреть файл

@ -22,7 +22,6 @@
#include "vm/StringObject.h"
#include "vm/TypedArrayObject.h"
#include "jsanalyzeinlines.h"
#include "jscntxtinlines.h"
namespace js {
@ -1428,7 +1427,7 @@ JSScript::ensureRanAnalysis(JSContext *cx)
return false;
if (!hasAnalysis() && !makeAnalysis(cx))
return false;
JS_ASSERT(analysis()->ranBytecode());
JS_ASSERT(hasAnalysis());
return true;
}

Просмотреть файл

@ -1137,7 +1137,7 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
if (!JSID_IS_EMPTY(child.propid) && it == FREEZE)
MarkTypePropertyNonWritable(cx, obj, child.propid);
last = cx->compartment()->propertyTree.getChild(cx, last, obj->numFixedSlots(), child);
last = cx->compartment()->propertyTree.getChild(cx, last, child);
if (!last)
return false;
}

Просмотреть файл

@ -304,8 +304,8 @@ AssertStackDepth(JSScript *script, uint32_t offset, uint32_t stackDepth) {
*
* call js_DumpScriptDepth(cx, script, pc)
*/
JS_ASSERT_IF(script->hasAnalysis() && script->analysis()->maybeCode(offset),
script->analysis()->getCode(offset).stackDepth == stackDepth);
if (script->hasAnalysis())
script->analysis()->assertMatchingStackDepthAtOffset(offset, stackDepth);
}
namespace {

Просмотреть файл

@ -51,6 +51,53 @@ GetUseCount(JSScript *script, unsigned offset)
return js_CodeSpec[*pc].nuses;
}
static inline JSOp
ReverseCompareOp(JSOp op)
{
switch (op) {
case JSOP_GT:
return JSOP_LT;
case JSOP_GE:
return JSOP_LE;
case JSOP_LT:
return JSOP_GT;
case JSOP_LE:
return JSOP_GE;
case JSOP_EQ:
case JSOP_NE:
case JSOP_STRICTEQ:
case JSOP_STRICTNE:
return op;
default:
MOZ_ASSUME_UNREACHABLE("unrecognized op");
}
}
static inline JSOp
NegateCompareOp(JSOp op)
{
switch (op) {
case JSOP_GT:
return JSOP_LE;
case JSOP_GE:
return JSOP_LT;
case JSOP_LT:
return JSOP_GE;
case JSOP_LE:
return JSOP_GT;
case JSOP_EQ:
return JSOP_NE;
case JSOP_NE:
return JSOP_EQ;
case JSOP_STRICTNE:
return JSOP_STRICTEQ;
case JSOP_STRICTEQ:
return JSOP_STRICTNE;
default:
MOZ_ASSUME_UNREACHABLE("unrecognized op");
}
}
class BytecodeRange {
public:
BytecodeRange(JSContext *cx, JSScript *script)

Просмотреть файл

@ -126,7 +126,7 @@ Shape::removeChild(Shape *child)
}
Shape *
PropertyTree::getChild(ExclusiveContext *cx, Shape *parent_, uint32_t nfixed, const StackShape &child)
PropertyTree::getChild(ExclusiveContext *cx, Shape *parent_, const StackShape &child)
{
{
Shape *shape = nullptr;
@ -189,7 +189,7 @@ PropertyTree::getChild(ExclusiveContext *cx, Shape *parent_, uint32_t nfixed, co
if (!shape)
return nullptr;
new (shape) Shape(child, nfixed);
new (shape) Shape(child, child.numFixedSlots());
if (!insertChild(cx, parent, shape))
return nullptr;

Просмотреть файл

@ -97,7 +97,7 @@ class PropertyTree
JSCompartment *compartment() { return compartment_; }
Shape *newShape(ExclusiveContext *cx);
Shape *getChild(ExclusiveContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child);
Shape *getChild(ExclusiveContext *cx, Shape *parent, const StackShape &child);
Shape *lookupChild(ThreadSafeContext *cx, Shape *parent, const StackShape &child);
};

Просмотреть файл

@ -128,16 +128,21 @@ Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle
return false;
RootedId id(cx, NameToId(bi->name()));
uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(slot + 1));
unsigned attrs = JSPROP_PERMANENT | JSPROP_ENUMERATE |
(bi->kind() == CONSTANT ? JSPROP_READONLY : 0);
StackShape child(nbase, id, slot++, 0, attrs, 0, 0);
Shape *shape = self->callObjShape_->getChildBinding(cx, child);
StackShape child(nbase, id, slot, nfixed, attrs, 0, 0);
Shape *shape = cx->compartment()->propertyTree.getChild(cx, self->callObjShape_, child);
if (!shape)
return false;
self->callObjShape_ = shape;
slot++;
}
JS_ASSERT(!self->callObjShape_->inDictionary());
JS_ASSERT(!bi);
return true;

Просмотреть файл

@ -2605,7 +2605,10 @@ class Debugger::ScriptQuery {
* condition occurred.
*/
void consider(JSScript *script) {
if (oom || script->selfHosted())
// We check for presence of script->code() because it is possible that
// the script was created and thus exposed to GC, but *not* fully
// initialized from fullyInit{FromEmitter,Trivial} due to errors.
if (oom || script->selfHosted() || !script->code())
return;
JSCompartment *compartment = script->compartment();
if (!compartments.has(compartment))

Просмотреть файл

@ -685,7 +685,7 @@ GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
StackShape child(base, id, slot, holder->numFixedSlots(), 0, 0, 0);
RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, holder->numFixedSlots(), child));
RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, child));
if (!shape)
return false;

Просмотреть файл

@ -1694,7 +1694,7 @@ DebugScopes::sweep(JSRuntime *rt)
}
}
#if defined(JSGC_GENERATIONAL) and defined(JS_GC_ZEAL)
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
void
DebugScopes::checkHashTablesAfterMovingGC(JSRuntime *runtime)
{

Просмотреть файл

@ -305,19 +305,6 @@ ShapeTable::grow(ThreadSafeContext *cx)
return true;
}
Shape *
Shape::getChildBinding(ExclusiveContext *cx, const StackShape &child)
{
JS_ASSERT(!inDictionary());
/* Try to allocate all slots inline. */
uint32_t slots = child.slotSpan();
gc::AllocKind kind = gc::GetGCObjectKind(slots);
uint32_t nfixed = gc::GetGCKindSlots(kind);
return cx->compartment()->propertyTree.getChild(cx, this, nfixed, child);
}
/* static */ Shape *
Shape::replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base,
TaggedProto proto, HandleShape shape)
@ -339,8 +326,7 @@ Shape::replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base,
StackShape child(shape);
child.base = nbase;
return cx->compartment()->propertyTree.getChild(cx, shape->parent,
shape->numFixedSlots(), child);
return cx->compartment()->propertyTree.getChild(cx, shape->parent, child);
}
/*
@ -399,7 +385,7 @@ JSObject::getChildProperty(ExclusiveContext *cx,
RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, child));
if (!obj->inDictionaryMode()) {
shape = cx->compartment()->propertyTree.getChild(cx, parent, obj->numFixedSlots(), child);
shape = cx->compartment()->propertyTree.getChild(cx, parent, child);
if (!shape)
return nullptr;
//JS_ASSERT(shape->parent == parent);
@ -719,7 +705,7 @@ js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
}
StackShape child(nbase, id, i, res->numFixedSlots(), JSPROP_ENUMERATE, 0, 0);
newShape = cx->compartment()->propertyTree.getChild(cx, newShape, res->numFixedSlots(), child);
newShape = cx->compartment()->propertyTree.getChild(cx, newShape, child);
if (!newShape)
return nullptr;
if (!JSObject::setLastProperty(cx, res, newShape))
@ -854,7 +840,7 @@ JSObject::putProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType c
* Now that we've possibly preserved slot, check whether all members match.
* If so, this is a redundant "put" and we can return without more work.
*/
if (shape->matchesParamsAfterId(nbase, slot, attrs, flags, shortid))
if (shape->matchesParamsAfterId(nbase, slot, obj->numFixedSlots(), attrs, flags, shortid))
return shape;
/*

Просмотреть файл

@ -960,8 +960,6 @@ class Shape : public gc::BarrieredCell<Shape>
insertIntoDictionary(dictp);
}
Shape *getChildBinding(ExclusiveContext *cx, const StackShape &child);
/* Replace the base shape of the last shape in a non-dictionary lineage with base. */
static Shape *replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base,
TaggedProto proto, HandleShape shape);
@ -1148,17 +1146,18 @@ class Shape : public gc::BarrieredCell<Shape>
bool matches(const Shape *other) const {
return propid_.get() == other->propid_.get() &&
matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
other->flags, other->shortid_);
matchesParamsAfterId(other->base(), other->maybeSlot(), other->numFixedSlots(),
other->attrs, other->flags, other->shortid_);
}
inline bool matches(const StackShape &other) const;
bool matchesParamsAfterId(BaseShape *base, uint32_t aslot, unsigned aattrs, unsigned aflags,
int ashortid) const
bool matchesParamsAfterId(BaseShape *base, uint32_t aslot, uint32_t afixed, unsigned aattrs,
unsigned aflags, int ashortid) const
{
return base->unowned() == this->base()->unowned() &&
maybeSlot() == aslot &&
numFixedSlots() == afixed &&
attrs == aattrs &&
((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
shortid_ == ashortid;
@ -1503,6 +1502,7 @@ struct StackShape
UnownedBaseShape *base;
jsid propid;
uint32_t slot_;
uint32_t nfixed_;
uint8_t attrs;
uint8_t flags;
int16_t shortid;
@ -1512,6 +1512,7 @@ struct StackShape
: base(base),
propid(propid),
slot_(slot),
nfixed_(nfixed),
attrs(uint8_t(attrs)),
flags(uint8_t(flags)),
shortid(int16_t(shortid))
@ -1524,7 +1525,8 @@ struct StackShape
StackShape(Shape *shape)
: base(shape->base()->unowned()),
propid(shape->propidRef()),
slot_(shape->slotInfo & Shape::SLOT_MASK),
slot_(shape->maybeSlot()),
nfixed_(shape->numFixedSlots()),
attrs(shape->attrs),
flags(shape->flags),
shortid(shape->shortid_)
@ -1546,6 +1548,10 @@ struct StackShape
slot_ = slot;
}
uint32_t numFixedSlots() const {
return nfixed_;
}
HashNumber hash() const {
HashNumber hash = uintptr_t(base);
@ -1554,6 +1560,7 @@ struct StackShape
hash = mozilla::RotateLeft(hash, 4) ^ attrs;
hash = mozilla::RotateLeft(hash, 4) ^ shortid;
hash = mozilla::RotateLeft(hash, 4) ^ slot_;
hash = mozilla::RotateLeft(hash, 4) ^ nfixed_;
hash = mozilla::RotateLeft(hash, 4) ^ JSID_BITS(propid);
return hash;
}
@ -1703,7 +1710,8 @@ inline bool
Shape::matches(const StackShape &other) const
{
return propid_.get() == other.propid &&
matchesParamsAfterId(other.base, other.slot_, other.attrs, other.flags, other.shortid);
matchesParamsAfterId(other.base, other.slot_, other.nfixed_, other.attrs, other.flags,
other.shortid);
}
template<> struct RootKind<Shape *> : SpecificRootKind<Shape *, THING_ROOT_SHAPE> {};

Просмотреть файл

@ -85,9 +85,8 @@ private:
* This function is called during minor GCs for each key in the HashMap that
* has been moved.
*/
static void KeyMarkCallback(JSTracer *trc, void *k, void *d) {
JSObject *key = static_cast<JSObject*>(k);
JSObject2WrappedJSMap* self = static_cast<JSObject2WrappedJSMap*>(d);
static void KeyMarkCallback(JSTracer *trc, JSObject *key, void *data) {
JSObject2WrappedJSMap* self = static_cast<JSObject2WrappedJSMap*>(data);
JSObject *prior = key;
JS_CallObjectTracer(trc, &key, "XPCJSRuntime::mWrappedJSMap key");
self->mTable.rekeyIfMoved(prior, key);
@ -694,7 +693,7 @@ private:
* This function is called during minor GCs for each key in the HashMap that
* has been moved.
*/
static void KeyMarkCallback(JSTracer *trc, void *k, void *d) {
static void KeyMarkCallback(JSTracer *trc, JSObject *key, void *data) {
/*
* To stop the barriers on the values of mTable firing while we are
* marking the store buffer, we cast the table to one that is
@ -702,10 +701,9 @@ private:
*/
typedef js::HashMap<JSObject *, JSObject *, js::PointerHasher<JSObject *, 3>,
js::SystemAllocPolicy> UnbarrieredMap;
JSObject2JSObjectMap *self = static_cast<JSObject2JSObjectMap *>(d);
JSObject2JSObjectMap *self = static_cast<JSObject2JSObjectMap *>(data);
UnbarrieredMap &table = reinterpret_cast<UnbarrieredMap &>(self->mTable);
JSObject *key = static_cast<JSObject*>(k);
JSObject *prior = key;
JS_CallObjectTracer(trc, &key, "XPCWrappedNativeScope::mWaiverWrapperMap key");
table.rekeyIfMoved(prior, key);

Просмотреть файл

@ -28,15 +28,6 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace JS;
bool
xpc_OkToHandOutWrapper(nsWrapperCache *cache)
{
MOZ_ASSERT(cache->GetWrapper(), "Must have wrapper");
MOZ_ASSERT(IS_WN_REFLECTOR(cache->GetWrapper()),
"Must have XPCWrappedNative wrapper");
return !XPCWrappedNative::Get(cache->GetWrapper())->NeedsSOW();
}
/***************************************************************************/
NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
@ -362,8 +353,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
RootedObject parent(cx, Scope->GetGlobalJSObject());
RootedValue newParentVal(cx, NullValue());
bool needsSOW = false;
bool needsCOW = false;
mozilla::Maybe<JSAutoCompartment> ac;
@ -376,9 +365,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
parent, parent.address());
if (NS_FAILED(rv))
return rv;
if (rv == NS_SUCCESS_CHROME_ACCESS_ONLY)
needsSOW = true;
rv = NS_OK;
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
@ -416,15 +402,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
}
} else {
ac.construct(static_cast<JSContext*>(cx), parent);
nsISupports *Object = helper.Object();
if (nsXPCWrappedJSClass::IsWrappedJS(Object)) {
nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrappedjs->GetJSObject())) &&
!xpc::AccessCheck::isChrome(js::GetObjectCompartment(Scope->GetGlobalJSObject()))) {
needsCOW = true;
}
}
}
AutoMarkingWrappedNativeProtoPtr proto(cx);
@ -473,11 +450,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
return rv;
}
if (needsSOW)
wrapper->SetNeedsSOW();
if (needsCOW)
wrapper->SetNeedsCOW();
return FinishCreate(Scope, Interface, cache, wrapper, resultWrapper);
}
@ -667,21 +639,6 @@ XPCWrappedNative::Destroy()
}
}
/*
* The only time GetRuntime() will be nullptr is if Destroy is called a
* second time on a wrapped native. Since we already unregistered the
* pointer the first time, there's no need to unregister again.
* Unregistration is safe the first time because mWrapper isn't used
* afterwards.
*/
if (XPCJSRuntime *rt = GetRuntime()) {
if (IsIncrementalBarrierNeeded(rt->Runtime()))
IncrementalObjectBarrier(GetWrapperPreserveColor());
mWrapper.setToCrashOnTouch();
} else {
MOZ_ASSERT(mWrapper.isSetToCrashOnTouch());
}
mMaybeScope = nullptr;
}
@ -1226,15 +1183,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
JS_SetPrivate(flat, nullptr);
}
// Before proceeding, eagerly create any same-compartment security wrappers
// that the object might have. This forces us to take the 'WithWrapper' path
// while transplanting that handles this stuff correctly.
{
JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject());
if (!wrapper->GetSameCompartmentSecurityWrapper(cx))
return NS_ERROR_FAILURE;
}
// Update scope maps. This section modifies global state, so from
// here on out we crash if anything fails.
Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
@ -1271,20 +1219,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
if (!newMap->Add(wrapper))
MOZ_CRASH();
RootedObject ww(cx, wrapper->GetWrapper());
if (ww) {
RootedObject newwrapper(cx);
MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper");
// Oops. We don't support transplanting objects with SOWs anymore.
flat = xpc::TransplantObject(cx, flat, newobj);
if (!flat)
MOZ_CRASH();
} else {
flat = xpc::TransplantObject(cx, flat, newobj);
if (!flat)
MOZ_CRASH();
}
MOZ_ASSERT(flat);
wrapper->mFlatJSObject = flat;
wrapper->mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
@ -1309,11 +1247,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
if (aNewParent) {
if (!JS_SetParent(cx, flat, aNewParent))
MOZ_CRASH();
JSObject *nw = wrapper->GetWrapper();
if (nw && !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) {
MOZ_CRASH();
}
}
return NS_OK;
@ -1359,29 +1292,6 @@ RescueOrphans(HandleObject obj)
// PreCreate may touch dead compartments.
js::AutoMaybeTouchDeadZones agc(parentObj);
bool isWN = IS_WN_REFLECTOR(obj);
// There's one little nasty twist here. For reasons described in bug 752764,
// we nuke SOW-ed objects after transplanting them. This means that nodes
// parented to an element (such as XUL elements), can end up with a nuked proxy
// in the parent chain, depending on the order of fixup. Because the proxy is
// nuked, we can't follow it anywhere. But we _can_ find the new wrapper for
// the underlying native parent.
if (MOZ_UNLIKELY(JS_IsDeadWrapper(parentObj))) {
if (isWN) {
XPCWrappedNative *wn =
static_cast<XPCWrappedNative*>(js::GetObjectPrivate(obj));
rv = wn->GetScriptableInfo()->GetCallback()->PreCreate(wn->GetIdentityObject(), cx,
wn->GetScope()->GetGlobalJSObject(),
parentObj.address());
NS_ENSURE_SUCCESS(rv, rv);
} else {
MOZ_ASSERT(IsDOMObject(obj));
const DOMClass* domClass = GetDOMClass(obj);
parentObj = domClass->mGetParent(cx, obj);
}
}
// Recursively fix up orphans on the parent chain.
rv = RescueOrphans(parentObj);
NS_ENSURE_SUCCESS(rv, rv);
@ -1392,7 +1302,7 @@ RescueOrphans(HandleObject obj)
return NS_OK;
// We've been orphaned. Find where our parent went, and follow it.
if (isWN) {
if (IS_WN_REFLECTOR(obj)) {
RootedObject realParent(cx, js::UncheckedUnwrap(parentObj));
XPCWrappedNative *wn =
static_cast<XPCWrappedNative*>(js::GetObjectPrivate(obj));
@ -1673,47 +1583,6 @@ XPCWrappedNative::InitTearOffJSObject(XPCWrappedNativeTearOff* to)
return true;
}
JSObject*
XPCWrappedNative::GetSameCompartmentSecurityWrapper(JSContext *cx)
{
// Grab the current state of affairs.
RootedObject flat(cx, GetFlatJSObject());
RootedObject wrapper(cx, GetWrapper());
// If we already have a wrapper, it must be what we want.
if (wrapper)
return wrapper;
// Chrome callers don't need same-compartment security wrappers.
JSCompartment *cxCompartment = js::GetContextCompartment(cx);
MOZ_ASSERT(cxCompartment == js::GetObjectCompartment(flat));
if (xpc::AccessCheck::isChrome(cxCompartment)) {
MOZ_ASSERT(wrapper == nullptr);
return flat;
}
// Check the possibilities. Note that we need to check for null in each
// case in order to distinguish between the 'no need for wrapper' and
// 'wrapping failed' cases.
//
// NB: We don't make SOWs for remote XUL domains where XBL scopes are
// disallowed.
if (NeedsSOW() && xpc::AllowXBLScope(js::GetContextCompartment(cx))) {
wrapper = xpc::WrapperFactory::WrapSOWObject(cx, flat);
if (!wrapper)
return nullptr;
}
// If we made a wrapper, cache it and return it.
if (wrapper) {
SetWrapper(wrapper);
return wrapper;
}
// Otherwise, just return the bare JS reflection.
return flat;
}
/***************************************************************************/
static bool Throw(nsresult errNum, XPCCallContext& ccx)
@ -1727,6 +1596,10 @@ static bool Throw(nsresult errNum, XPCCallContext& ccx)
class CallMethodHelper
{
XPCCallContext& mCallContext;
// We wait to call SetLastResult(mInvokeResult) until ~CallMethodHelper(),
// so that XPCWN-implemented functions like XPCComponents::GetLastResult()
// can still access the previous result.
nsresult mInvokeResult;
nsIInterfaceInfo* const mIFaceInfo;
const nsXPTMethodInfo* mMethodInfo;
nsISupports* const mCallee;
@ -1755,7 +1628,7 @@ class CallMethodHelper
GatherAndConvertResults();
JS_ALWAYS_INLINE bool
QueryInterfaceFastPath() const;
QueryInterfaceFastPath();
nsXPTCVariant*
GetDispatchParam(uint8_t paramIndex)
@ -1790,6 +1663,7 @@ public:
CallMethodHelper(XPCCallContext& ccx)
: mCallContext(ccx)
, mInvokeResult(NS_ERROR_UNEXPECTED)
, mIFaceInfo(ccx.GetInterface()->GetInterfaceInfo())
, mMethodInfo(nullptr)
, mCallee(ccx.GetTearOff()->GetNative())
@ -1862,7 +1736,6 @@ CallMethodHelper::Call()
mCallContext.SetRetVal(JSVAL_VOID);
XPCJSRuntime::Get()->SetPendingException(nullptr);
mCallContext.GetXPCContext()->SetLastResult(NS_ERROR_UNEXPECTED);
if (mVTableIndex == 0) {
return QueryInterfaceFastPath();
@ -1887,16 +1760,14 @@ CallMethodHelper::Call()
if (foundDependentParam && !ConvertDependentParams())
return false;
nsresult invokeResult = Invoke();
mCallContext.GetXPCContext()->SetLastResult(invokeResult);
mInvokeResult = Invoke();
if (JS_IsExceptionPending(mCallContext)) {
return false;
}
if (NS_FAILED(invokeResult)) {
ThrowBadResult(invokeResult, mCallContext);
if (NS_FAILED(mInvokeResult)) {
ThrowBadResult(mInvokeResult, mCallContext);
return false;
}
@ -1950,6 +1821,7 @@ CallMethodHelper::~CallMethodHelper()
}
}
mCallContext.GetXPCContext()->SetLastResult(mInvokeResult);
}
bool
@ -2115,7 +1987,7 @@ CallMethodHelper::GatherAndConvertResults()
}
bool
CallMethodHelper::QueryInterfaceFastPath() const
CallMethodHelper::QueryInterfaceFastPath()
{
MOZ_ASSERT(mVTableIndex == 0,
"Using the QI fast-path for a method other than QueryInterface");
@ -2136,14 +2008,11 @@ CallMethodHelper::QueryInterfaceFastPath() const
return false;
}
nsresult invokeResult;
nsISupports* qiresult = nullptr;
invokeResult = mCallee->QueryInterface(*iid, (void**) &qiresult);
mInvokeResult = mCallee->QueryInterface(*iid, (void**) &qiresult);
mCallContext.GetXPCContext()->SetLastResult(invokeResult);
if (NS_FAILED(invokeResult)) {
ThrowBadResult(invokeResult, mCallContext);
if (NS_FAILED(mInvokeResult)) {
ThrowBadResult(mInvokeResult, mCallContext);
return false;
}

Просмотреть файл

@ -1029,26 +1029,6 @@ static inline bool IS_PROTO_CLASS(const js::Class *clazz)
clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
}
/***************************************************************************/
namespace XPCWrapper {
enum WrapperType {
UNKNOWN = 0,
NONE = 0,
XPCNW_IMPLICIT = 1 << 0,
XPCNW_EXPLICIT = 1 << 1,
XPCNW = (XPCNW_IMPLICIT | XPCNW_EXPLICIT),
SJOW = 1 << 2,
// SJOW must be the last wrapper type that can be returned to chrome.
XOW = 1 << 3,
COW = 1 << 4,
SOW = 1 << 5
};
}
/***************************************************************************/
// XPCWrappedNativeScope is one-to-one with a JS global object.
@ -2189,7 +2169,6 @@ public:
GetProto()->TraceSelf(trc);
else
GetScope()->TraceSelf(trc);
TraceWrapper(trc);
if (mFlatJSObject && JS_IsGlobalObject(mFlatJSObject))
{
TraceXPCGlobal(trc, mFlatJSObject);
@ -2232,41 +2211,6 @@ public:
bool HasExternalReference() const {return mRefCnt > 1;}
bool NeedsSOW() { return mWrapper.hasFlag(WRAPPER_NEEDS_SOW); }
void SetNeedsSOW() { mWrapper.setFlags(WRAPPER_NEEDS_SOW); }
bool NeedsCOW() { return mWrapper.hasFlag(WRAPPER_NEEDS_COW); }
void SetNeedsCOW() { mWrapper.setFlags(WRAPPER_NEEDS_COW); }
JSObject* GetWrapperPreserveColor() const { return mWrapper.getPtr(); }
JSObject* GetWrapper()
{
JSObject* wrapper = GetWrapperPreserveColor();
if (wrapper) {
JS::ExposeObjectToActiveJS(wrapper);
// Call this to unmark mFlatJSObject.
GetFlatJSObject();
}
return wrapper;
}
void SetWrapper(JSObject *obj)
{
JS::IncrementalObjectBarrier(GetWrapperPreserveColor());
mWrapper.setPtr(obj);
}
void TraceWrapper(JSTracer *trc)
{
JS_CallTenuredObjectTracer(trc, &mWrapper, "XPCWrappedNative::mWrapper");
}
// Returns the relevant same-compartment security if applicable, or
// mFlatJSObject otherwise.
//
// This takes care of checking mWrapper to see if we already have such
// a wrapper.
JSObject *GetSameCompartmentSecurityWrapper(JSContext *cx);
void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
// Make ctor and dtor protected (rather than private) to placate nsCOMPtr.
@ -2289,10 +2233,6 @@ protected:
private:
enum {
// Flags bits for mWrapper:
WRAPPER_NEEDS_SOW = JS_BIT(0),
WRAPPER_NEEDS_COW = JS_BIT(1),
// Flags bits for mFlatJSObject:
FLAT_JS_OBJECT_VALID = JS_BIT(0)
};
@ -2326,7 +2266,6 @@ private:
JS::TenuredHeap<JSObject*> mFlatJSObject;
XPCNativeScriptableInfo* mScriptableInfo;
XPCWrappedNativeTearOffChunk mFirstChunk;
JS::TenuredHeap<JSObject*> mWrapper;
};
/***************************************************************************

Просмотреть файл

@ -119,9 +119,6 @@ struct RuntimeStats;
#define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0)
extern bool
xpc_OkToHandOutWrapper(nsWrapperCache *cache);
inline JSObject*
xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, JS::MutableHandleValue vp)
{
@ -129,8 +126,8 @@ xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, JS::MutableHand
JSObject* wrapper = cache->GetWrapper();
if (wrapper &&
js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) &&
(cache->IsDOMBinding() ? !cache->HasSystemOnlyWrapper() :
xpc_OkToHandOutWrapper(cache))) {
!(cache->IsDOMBinding() && cache->HasSystemOnlyWrapper()))
{
vp.setObject(*wrapper);
return wrapper;
}

Просмотреть файл

@ -0,0 +1,3 @@
function run_test() {
do_check_eq(Components.lastResult, Components.results.NS_OK);
}

Просмотреть файл

@ -39,6 +39,7 @@ support-files =
[test_bug867486.js]
[test_bug872772.js]
[test_bug885800.js]
[test_bug961054.js]
[test_bug_442086.js]
[test_file.js]
[test_blob.js]

Просмотреть файл

@ -263,12 +263,7 @@ AccessCheck::needsSystemOnlyWrapper(JSObject *obj)
JSObject* wrapper = obj;
if (dom::GetSameCompartmentWrapperForDOMBinding(wrapper))
return wrapper != obj;
if (!IS_WN_REFLECTOR(obj))
return false;
XPCWrappedNative *wn = XPCWrappedNative::Get(obj);
return wn->NeedsSOW();
return false;
}
enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };

Просмотреть файл

@ -494,22 +494,9 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, HandleObject objArg)
obj = JS_ObjectToOuterObject(cx, obj);
NS_ENSURE_TRUE(obj, nullptr);
if (dom::GetSameCompartmentWrapperForDOMBinding(*obj.address())) {
return obj;
}
MOZ_ASSERT(!dom::IsDOMObject(obj));
if (!IS_WN_REFLECTOR(obj))
return obj;
// Extract the WN. It should exist.
XPCWrappedNative *wn = XPCWrappedNative::Get(obj);
MOZ_ASSERT(wn, "Trying to wrap a dead WN!");
// The WN knows what to do.
RootedObject wrapper(cx, wn->GetSameCompartmentSecurityWrapper(cx));
return wrapper;
// The method below is a no-op for non-DOM objects.
dom::GetSameCompartmentWrapperForDOMBinding(*obj.address());
return obj;
}
// Call WaiveXrayAndWrap when you have a JS object that you don't want to be

Просмотреть файл

@ -1,7 +1,6 @@
<html class="reftest-wait">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
</head>
<body onload="start()">
<iframe src="data:text/html,<body contenteditable>foo bar"></iframe>
@ -12,7 +11,7 @@
var doc = iframe.contentDocument;
setTimeout(function() {
synthesizeMouse(iframe, 10, 10, {});
doc.body.focus();
// Now try to set the caret without moving it
win.getSelection().collapse(doc.body.firstChild, 1);

Просмотреть файл

@ -39,7 +39,7 @@ function callbackTestCanvas(canvas)
reference.parentNode.removeChild(reference);
}
canvases = [];
nextTest();
SimpleTest.waitForFocus(nextTest);
}
function doSnapShot(iframe) {

Просмотреть файл

@ -257,6 +257,8 @@ jpeg_abort_decompress
jpeg_read_raw_data
#endif
qcms_enable_iccv4
qcms_data_from_unicode_path
qcms_data_from_path
qcms_profile_create_rgb_with_gamma
qcms_profile_from_memory
qcms_profile_from_path

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше