зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound
This commit is contained in:
Коммит
8821f00cbd
3
CLOBBER
3
CLOBBER
|
@ -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;
|
||||
|
|
1056
js/src/jsanalyze.cpp
1056
js/src/jsanalyze.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче