diff --git a/.hgtags b/.hgtags index 5f3c68c841cf..bc4042041437 100644 --- a/.hgtags +++ b/.hgtags @@ -69,3 +69,4 @@ a95d426422816513477e5863add1b00ac7041dcb AURORA_BASE_20110412 5eb553dd2ceae5f88d80f27afc5ef3935c5d43b0 AURORA_BASE_20110705 41b84b87c816403e1b74963d8094cff0406c989e AURORA_BASE_20110816 c0983049bcaa9551e5f276d5a77ce154c151e0b0 AURORA_BASE_20110927 +462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R15 diff --git a/accessible/src/base/FocusManager.cpp b/accessible/src/base/FocusManager.cpp index 11439299c6fa..342239fff8ca 100644 --- a/accessible/src/base/FocusManager.cpp +++ b/accessible/src/base/FocusManager.cpp @@ -41,6 +41,7 @@ #include "nsAccUtils.h" #include "nsRootAccessible.h" +#include "nsEventStateManager.h" #include "nsFocusManager.h" namespace dom = mozilla::dom; @@ -352,18 +353,22 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent) } } -nsIContent* -FocusManager::FocusedDOMElm() const +nsINode* +FocusManager::FocusedDOMNode() const { nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager(); - return DOMFocusManager->GetFocusedContent(); -} + nsIContent* focusedElm = DOMFocusManager->GetFocusedContent(); -nsIDocument* -FocusManager::FocusedDOMDocument() const -{ - nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager(); + // No focus on remote target elements like xul:browser having DOM focus and + // residing in chrome process because it means an element in content process + // keeps the focus. + if (focusedElm) { + if (nsEventStateManager::IsRemoteTarget(focusedElm)) + return nsnull; + return focusedElm; + } + // Otherwise the focus can be on DOM document. nsCOMPtr focusedWnd; DOMFocusManager->GetFocusedWindow(getter_AddRefs(focusedWnd)); if (focusedWnd) { @@ -374,3 +379,10 @@ FocusManager::FocusedDOMDocument() const } return nsnull; } + +nsIDocument* +FocusManager::FocusedDOMDocument() const +{ + nsINode* focusedNode = FocusedDOMNode(); + return focusedNode ? focusedNode->OwnerDoc() : nsnull; +} diff --git a/accessible/src/base/FocusManager.h b/accessible/src/base/FocusManager.h index 5dbd34b99ee9..10caf0c9ac69 100644 --- a/accessible/src/base/FocusManager.h +++ b/accessible/src/base/FocusManager.h @@ -146,18 +146,7 @@ private: /** * Return DOM node having DOM focus. */ - inline nsINode* FocusedDOMNode() const - { - nsINode* focusedNode = FocusedDOMElm(); - if (focusedNode) - return focusedNode; - return FocusedDOMDocument(); - } - - /** - * Return DOM element having DOM focus. - */ - nsIContent* FocusedDOMElm() const; + nsINode* FocusedDOMNode() const; /** * Return DOM document having DOM focus. diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index 074cc8c0adcb..b709de366ff8 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -654,7 +654,7 @@ nsAccessible::IsVisible(bool* aIsOffscreen) } // The frame intersects the viewport, but we need to check the parent view chain :( - bool isVisible = nsCoreUtils::CheckVisibilityInParentChain(frame); + bool isVisible = frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY); if (isVisible && rectVisibility == nsRectVisibility_kVisible) { *aIsOffscreen = false; } diff --git a/accessible/src/base/nsCoreUtils.cpp b/accessible/src/base/nsCoreUtils.cpp index 370c1d31b447..cdf887d92038 100644 --- a/accessible/src/base/nsCoreUtils.cpp +++ b/accessible/src/base/nsCoreUtils.cpp @@ -758,31 +758,6 @@ nsCoreUtils::IsColumnHidden(nsITreeColumn *aColumn) nsGkAtoms::_true, eCaseMatters); } -bool -nsCoreUtils::CheckVisibilityInParentChain(nsIFrame* aFrame) -{ - nsIView* view = aFrame->GetClosestView(); - if (view && !view->IsEffectivelyVisible()) - return false; - - nsIPresShell* presShell = aFrame->PresContext()->GetPresShell(); - while (presShell) { - if (!presShell->IsActive()) { - return false; - } - - nsIFrame* rootFrame = presShell->GetRootFrame(); - presShell = nsnull; - if (rootFrame) { - nsIFrame* frame = nsLayoutUtils::GetCrossDocParentFrame(rootFrame); - if (frame) { - presShell = frame->PresContext()->GetPresShell(); - } - } - } - return true; -} - //////////////////////////////////////////////////////////////////////////////// // nsAccessibleDOMStringList //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/base/nsCoreUtils.h b/accessible/src/base/nsCoreUtils.h index 8008e10c0147..7321f4fdf7a4 100644 --- a/accessible/src/base/nsCoreUtils.h +++ b/accessible/src/base/nsCoreUtils.h @@ -370,11 +370,6 @@ public: aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scope); } - /** - * Check the visibility across both parent content and chrome. - */ - static bool CheckVisibilityInParentChain(nsIFrame* aFrame); - }; diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index c3429b54d19a..d80861e6ec14 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -311,7 +311,8 @@ nsDocAccessible::NativeState() state |= states::BUSY; nsIFrame* frame = GetFrame(); - if (!frame || !nsCoreUtils::CheckVisibilityInParentChain(frame)) { + if (!frame || + !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY)) { state |= states::INVISIBLE | states::OFFSCREEN; } diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 1bf374a6b7ec..780c869c7ff5 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -77,7 +77,7 @@ pref("extensions.update.autoUpdateDefault", true); // Disable add-ons installed into the shared user and shared system areas by // default. This does not include the application directory. See the SCOPE // constants in AddonManager.jsm for values to use here -pref("extensions.autoDisableScopes", 10); +pref("extensions.autoDisableScopes", 15); // Dictionary download preference pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/firefox/dictionaries/"); diff --git a/browser/base/Makefile.in b/browser/base/Makefile.in index df14dfeddfa0..3523ab62895b 100644 --- a/browser/base/Makefile.in +++ b/browser/base/Makefile.in @@ -83,6 +83,3 @@ endif ifneq (,$(filter windows gtk2, $(MOZ_WIDGET_TOOLKIT))) DEFINES += -DMENUBAR_CAN_AUTOHIDE=1 endif - -libs:: - $(NSINSTALL) $(srcdir)/content/tabview/modules/* $(FINAL_TARGET)/modules/tabview diff --git a/browser/base/content/aboutDialog.xul b/browser/base/content/aboutDialog.xul index de182166782e..f43559927fe9 100644 --- a/browser/base/content/aboutDialog.xul +++ b/browser/base/content/aboutDialog.xul @@ -67,7 +67,8 @@ #else title="&aboutDialog.title;" #endif - aria-describedby="version distribution distributionId" + role="dialog" + aria-describedby="version distribution distributionId communityDesc contributeDesc trademark" > - -

Text fields with changed text

- - - -

Text fields with unchanged text

- - - -

Changed field IDs

-
diff --git a/browser/components/sessionstore/test/browser/browser_500328.js b/browser/components/sessionstore/test/browser/browser_500328.js index 5fe32e28b1b6..5c7e793e68a4 100644 --- a/browser/components/sessionstore/test/browser/browser_500328.js +++ b/browser/components/sessionstore/test/browser/browser_500328.js @@ -116,13 +116,13 @@ function test() { // After these push/replaceState calls, the window should have three // history entries: - // testURL (state object: null) <-- oldest - // testURL (state object: {obj1:1}) - // page2 (state object: {obj3:/^a$/}) <-- newest + // testURL (state object: null) <-- oldest + // testURL (state object: {obj1:1}) + // testURL?page2 (state object: {obj3:/^a$/}) <-- newest let contentWindow = tab.linkedBrowser.contentWindow; let history = contentWindow.history; history.pushState({obj1:1}, "title-obj1"); - history.pushState({obj2:2}, "title-obj2", "page2"); + history.pushState({obj2:2}, "title-obj2", "?page2"); history.replaceState({obj3:/^a$/}, "title-obj3"); let state = ss.getTabState(tab); diff --git a/browser/components/sessionstore/test/browser/browser_607016.js b/browser/components/sessionstore/test/browser/browser_607016.js index 6c5bdb731e74..eb465294d2d2 100644 --- a/browser/components/sessionstore/test/browser/browser_607016.js +++ b/browser/components/sessionstore/test/browser/browser_607016.js @@ -84,14 +84,19 @@ function test() { let curState = JSON.parse(ss.getBrowserState()); for (let i = 0; i < curState.windows[0].tabs.length; i++) { - if (state.windows[0].tabs[i].extData) { - is(curState.windows[0].tabs[i].extData["uniq"], - state.windows[0].tabs[i].extData["uniq"], + let tabState = state.windows[0].tabs[i]; + let tabCurState = curState.windows[0].tabs[i]; + if (tabState.extData) { + is(tabCurState.extData["uniq"], tabState.extData["uniq"], "sanity check that tab has correct extData"); } - else - ok(!("extData" in curState.windows[0].tabs[i]), - "sanity check that tab doesn't have extData"); + else { + // We aren't expecting there to be any data on extData, but panorama + // may be setting something, so we need to make sure that if we do have + // data, we just don't have anything for "uniq". + ok(!("extData" in tabCurState) || !("uniq" in tabCurState.extData), + "sanity check that tab doesn't have extData or extData doesn't have 'uniq'"); + } } // Now we'll set a new unique value on 1 of the tabs diff --git a/browser/components/sessionstore/test/browser/browser_665702-state_session.js b/browser/components/sessionstore/test/browser/browser_665702-state_session.js new file mode 100644 index 000000000000..aee0f2554cd0 --- /dev/null +++ b/browser/components/sessionstore/test/browser/browser_665702-state_session.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function compareArray(a, b) { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +} + +function test() { + let currentState = JSON.parse(ss.getBrowserState()); + ok(currentState.session, "session data returned by getBrowserState"); + + let keys = Object.keys(currentState.session); + let expectedKeys = ["state", "lastUpdate", "startTime", "recentCrashes"]; + ok(compareArray(keys.sort(), expectedKeys.sort()), + "session object from getBrowserState has correct keys"); +} diff --git a/browser/components/sessionstore/test/browser/browser_694378.js b/browser/components/sessionstore/test/browser/browser_694378.js new file mode 100644 index 000000000000..d935e8f96291 --- /dev/null +++ b/browser/components/sessionstore/test/browser/browser_694378.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test Summary: +// 1. call ss.setWindowState with a broken state +// 1a. ensure that it doesn't throw. + +function test() { + waitForExplicitFinish(); + + let brokenState = { + windows: [ + { tabs: [{ entries: [{ url: "about:mozilla" }] }] } + //{ tabs: [{ entries: [{ url: "about:robots" }] }] }, + ], + selectedWindow: 2 + }; + let brokenStateString = JSON.stringify(brokenState); + + let gotError = false; + try { + ss.setWindowState(window, brokenStateString, true); + } + catch (ex) { + gotError = true; + info(ex); + } + + ok(!gotError, "ss.setWindowState did not throw an error"); + + // Make sure that we reset the state. Use a full state just in case things get crazy. + let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]}; + waitForBrowserState(blankState, finish); +} + diff --git a/browser/components/sessionstore/test/browser/browser_476161.js b/browser/components/sessionstore/test/browser/browser_form_restore_events.js similarity index 56% rename from browser/components/sessionstore/test/browser/browser_476161.js rename to browser/components/sessionstore/test/browser/browser_form_restore_events.js index a92c9737fdca..ab9897d7e6e6 100644 --- a/browser/components/sessionstore/test/browser/browser_476161.js +++ b/browser/components/sessionstore/test/browser/browser_form_restore_events.js @@ -35,33 +35,64 @@ * ***** END LICENSE BLOCK ***** */ function test() { - /** Test for Bug 476161 **/ - + /** Originally a test for Bug 476161, but then expanded to include all input types in bug 640136 **/ + waitForExplicitFinish(); - + + let file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + let testURL = "http://mochi.test:8888/browser/" + - "browser/components/sessionstore/test/browser/browser_476161_sample.html"; + "browser/components/sessionstore/test/browser/browser_form_restore_events_sample.html"; let tab = gBrowser.addTab(testURL); tab.linkedBrowser.addEventListener("load", function(aEvent) { tab.linkedBrowser.removeEventListener("load", arguments.callee, true); let doc = tab.linkedBrowser.contentDocument; - - doc.getElementById("modify1").value += Math.random(); - doc.getElementById("modify2").value += " " + Date.now(); - + + // text fields + doc.getElementById("modify01").value += Math.random(); + doc.getElementById("modify02").value += " " + Date.now(); + + // textareas + doc.getElementById("modify03").value += Math.random(); + doc.getElementById("modify04").value += " " + Date.now(); + + // file + doc.getElementById("modify05").value = file.path; + + // select + doc.getElementById("modify06").selectedIndex = 1; + var multipleChange = doc.getElementById("modify07"); + Array.forEach(multipleChange.options, function(option) option.selected = true); + + // checkbox + doc.getElementById("modify08").checked = true; + doc.getElementById("modify09").checked = false; + + // radio + // select one then another in the same group - only last one should get event on restore + doc.getElementById("modify10").checked = true; + doc.getElementById("modify11").checked = true; + + let tab2 = gBrowser.duplicateTab(tab); tab2.linkedBrowser.addEventListener("load", function(aEvent) { tab2.linkedBrowser.removeEventListener("load", arguments.callee, true); let doc = tab2.linkedBrowser.contentDocument; - let changed = doc.getElementById("changed").textContent.trim().split(); - - is(changed.sort().join(" "), "modify1 modify2", - "input events were only dispatched for modified text fields"); - + let inputFired = doc.getElementById("inputFired").textContent.trim().split(); + let changeFired = doc.getElementById("changeFired").textContent.trim().split(); + + is(inputFired.sort().join(" "), "modify01 modify02 modify03 modify04 modify05", + "input events were only dispatched for modified input, textarea fields"); + + is(changeFired.sort().join(" "), "modify06 unchanged06 modify07 modify08 modify09 modify11", + "change events were only dispatched for modified select, checkbox, radio fields"); + // clean up gBrowser.removeTab(tab2); gBrowser.removeTab(tab); - + finish(); }, true); }, true); diff --git a/browser/components/sessionstore/test/browser/browser_form_restore_events_sample.html b/browser/components/sessionstore/test/browser/browser_form_restore_events_sample.html new file mode 100644 index 000000000000..5e4b73b3c67c --- /dev/null +++ b/browser/components/sessionstore/test/browser/browser_form_restore_events_sample.html @@ -0,0 +1,98 @@ + +Test for form restore events (originally bug 476161) + + + + +

Text fields with changed text

+ + + + + +

Text fields with unchanged text

+ + + + + +

Textarea with changed text

+ + + +

Textarea with unchanged text

+ + + +

file field with changed value

+ + +

file field with unchanged value

+ + + + +

Select menu with changed selection

+ + +

Select menu with unchanged selection (change event still fires)

+ + +

Multiple Select menu with changed selection

+ + +

Select menu with unchanged selection

+ + +

checkbox with changed value

+ + + +

checkbox with unchanged value

+ + + +

radio with changed value

+Radio 1 +Radio 2 +Radio 3 + +

radio with unchanged value

+Radio 4 +Radio 5 +Radio 6 + +

Changed field IDs

+
+
+
diff --git a/browser/components/tabview/Makefile.in b/browser/components/tabview/Makefile.in new file mode 100644 index 000000000000..c86fb752212d --- /dev/null +++ b/browser/components/tabview/Makefile.in @@ -0,0 +1,53 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Places code +# +# The Initial Developer of the Original Code is +# Google Inc. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brett Wilson +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +ifdef ENABLE_TESTS + DIRS += test +endif + +include $(topsrcdir)/config/rules.mk + +libs:: + $(NSINSTALL) $(srcdir)/modules/* $(FINAL_TARGET)/modules/tabview diff --git a/browser/base/content/tabview/content.js b/browser/components/tabview/content.js similarity index 100% rename from browser/base/content/tabview/content.js rename to browser/components/tabview/content.js diff --git a/browser/base/content/tabview/drag.js b/browser/components/tabview/drag.js similarity index 100% rename from browser/base/content/tabview/drag.js rename to browser/components/tabview/drag.js diff --git a/browser/base/content/tabview/groupitems.js b/browser/components/tabview/groupitems.js similarity index 100% rename from browser/base/content/tabview/groupitems.js rename to browser/components/tabview/groupitems.js diff --git a/browser/base/content/tabview/iq.js b/browser/components/tabview/iq.js similarity index 100% rename from browser/base/content/tabview/iq.js rename to browser/components/tabview/iq.js diff --git a/browser/base/content/tabview/items.js b/browser/components/tabview/items.js similarity index 100% rename from browser/base/content/tabview/items.js rename to browser/components/tabview/items.js diff --git a/browser/components/tabview/jar.mn b/browser/components/tabview/jar.mn new file mode 100644 index 000000000000..7b54b18afd95 --- /dev/null +++ b/browser/components/tabview/jar.mn @@ -0,0 +1,5 @@ +browser.jar: + content/browser/tabview.css (tabview.css) +* content/browser/tabview.js (tabview.js) + content/browser/tabview.html (tabview.html) + content/browser/tabview-content.js (content.js) diff --git a/browser/base/content/tabview/modules/utils.jsm b/browser/components/tabview/modules/utils.jsm similarity index 100% rename from browser/base/content/tabview/modules/utils.jsm rename to browser/components/tabview/modules/utils.jsm diff --git a/browser/base/content/tabview/search.js b/browser/components/tabview/search.js similarity index 100% rename from browser/base/content/tabview/search.js rename to browser/components/tabview/search.js diff --git a/browser/base/content/tabview/storage.js b/browser/components/tabview/storage.js similarity index 100% rename from browser/base/content/tabview/storage.js rename to browser/components/tabview/storage.js diff --git a/browser/base/content/tabview/storagePolicy.js b/browser/components/tabview/storagePolicy.js similarity index 100% rename from browser/base/content/tabview/storagePolicy.js rename to browser/components/tabview/storagePolicy.js diff --git a/browser/base/content/tabview/tabitems.js b/browser/components/tabview/tabitems.js similarity index 100% rename from browser/base/content/tabview/tabitems.js rename to browser/components/tabview/tabitems.js diff --git a/browser/base/content/tabview/tabview.css b/browser/components/tabview/tabview.css similarity index 100% rename from browser/base/content/tabview/tabview.css rename to browser/components/tabview/tabview.css diff --git a/browser/base/content/tabview/tabview.html b/browser/components/tabview/tabview.html similarity index 100% rename from browser/base/content/tabview/tabview.html rename to browser/components/tabview/tabview.html diff --git a/browser/base/content/tabview/tabview.js b/browser/components/tabview/tabview.js similarity index 100% rename from browser/base/content/tabview/tabview.js rename to browser/components/tabview/tabview.js diff --git a/browser/base/content/test/tabview/Makefile.in b/browser/components/tabview/test/Makefile.in similarity index 99% rename from browser/base/content/test/tabview/Makefile.in rename to browser/components/tabview/test/Makefile.in index 03707d6f60b5..8796bffdf8ac 100644 --- a/browser/base/content/test/tabview/Makefile.in +++ b/browser/components/tabview/test/Makefile.in @@ -34,11 +34,11 @@ # # ***** END LICENSE BLOCK ***** -DEPTH = ../../../../.. +DEPTH = ../../../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ -relativesrcdir = browser/base/content/test/tabview +relativesrcdir = browser/components/tabview/test include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk diff --git a/browser/base/content/test/tabview/browser_tabview_alltabs.js b/browser/components/tabview/test/browser_tabview_alltabs.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_alltabs.js rename to browser/components/tabview/test/browser_tabview_alltabs.js diff --git a/browser/base/content/test/tabview/browser_tabview_apptabs.js b/browser/components/tabview/test/browser_tabview_apptabs.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_apptabs.js rename to browser/components/tabview/test/browser_tabview_apptabs.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug580412.js b/browser/components/tabview/test/browser_tabview_bug580412.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug580412.js rename to browser/components/tabview/test/browser_tabview_bug580412.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug586553.js b/browser/components/tabview/test/browser_tabview_bug586553.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug586553.js rename to browser/components/tabview/test/browser_tabview_bug586553.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587043.js b/browser/components/tabview/test/browser_tabview_bug587043.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587043.js rename to browser/components/tabview/test/browser_tabview_bug587043.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587231.js b/browser/components/tabview/test/browser_tabview_bug587231.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587231.js rename to browser/components/tabview/test/browser_tabview_bug587231.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587276.js b/browser/components/tabview/test/browser_tabview_bug587276.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587276.js rename to browser/components/tabview/test/browser_tabview_bug587276.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587351.js b/browser/components/tabview/test/browser_tabview_bug587351.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587351.js rename to browser/components/tabview/test/browser_tabview_bug587351.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587503.js b/browser/components/tabview/test/browser_tabview_bug587503.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587503.js rename to browser/components/tabview/test/browser_tabview_bug587503.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug587990.js b/browser/components/tabview/test/browser_tabview_bug587990.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug587990.js rename to browser/components/tabview/test/browser_tabview_bug587990.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug588265.js b/browser/components/tabview/test/browser_tabview_bug588265.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug588265.js rename to browser/components/tabview/test/browser_tabview_bug588265.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug589324.js b/browser/components/tabview/test/browser_tabview_bug589324.js similarity index 96% rename from browser/base/content/test/tabview/browser_tabview_bug589324.js rename to browser/components/tabview/test/browser_tabview_bug589324.js index a70dffdbc0fa..43d590bb6122 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug589324.js +++ b/browser/components/tabview/test/browser_tabview_bug589324.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html"; +const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html"; const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/"; let state = { diff --git a/browser/base/content/test/tabview/browser_tabview_bug590606.js b/browser/components/tabview/test/browser_tabview_bug590606.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug590606.js rename to browser/components/tabview/test/browser_tabview_bug590606.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug591706.js b/browser/components/tabview/test/browser_tabview_bug591706.js similarity index 89% rename from browser/base/content/test/tabview/browser_tabview_bug591706.js rename to browser/components/tabview/test/browser_tabview_bug591706.js index c659edbaeed7..ffd258e2cb7b 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug591706.js +++ b/browser/components/tabview/test/browser_tabview_bug591706.js @@ -38,14 +38,15 @@ function onTabViewWindowLoaded() { let secondTabItem = secondTab._tabViewTabItem; ok(group.getChildren().some(function(child) child == secondTabItem),"The second tab was made in our new group"); is(group.getChildren().length, 1, "Only one tab in the first group"); - isnot(firstTab.linkedBrowser.contentWindow.location, secondTab.linkedBrowser.contentWindow.location, "The two tabs must have different locations"); + isnot(firstTab.linkedBrowser.currentURI.spec, secondTab.linkedBrowser.currentURI.spec, "The two tabs must have different locations"); // Add the first tab to the group *programmatically*, without specifying a dropPos group.add(firstTabItem); is(group.getChildren().length, 2, "Two tabs in the group"); - is(group.getChildren()[0].tab.linkedBrowser.contentWindow.location, secondTab.linkedBrowser.contentWindow.location, "The second tab was there first"); - is(group.getChildren()[1].tab.linkedBrowser.contentWindow.location, firstTab.linkedBrowser.contentWindow.location, "The first tab was just added and went to the end of the line"); - + + is(group.getChildren()[0].tab.linkedBrowser.currentURI.spec, secondTab.linkedBrowser.currentURI.spec, "The second tab was there first"); + is(group.getChildren()[1].tab.linkedBrowser.currentURI.spec, firstTab.linkedBrowser.currentURI.spec, "The first tab was just added and went to the end of the line"); + group.addSubscriber("close", function onClose() { group.removeSubscriber("close", onClose); diff --git a/browser/base/content/test/tabview/browser_tabview_bug593283.js b/browser/components/tabview/test/browser_tabview_bug593283.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug593283.js rename to browser/components/tabview/test/browser_tabview_bug593283.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug594958.js b/browser/components/tabview/test/browser_tabview_bug594958.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug594958.js rename to browser/components/tabview/test/browser_tabview_bug594958.js diff --git a/browser/components/tabview/test/browser_tabview_bug595020.js b/browser/components/tabview/test/browser_tabview_bug595020.js new file mode 100644 index 000000000000..c3b5d4366583 --- /dev/null +++ b/browser/components/tabview/test/browser_tabview_bug595020.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); + +let stateStartup = {windows:[ + {tabs:[{entries:[{url:"about:home"}]}], extData:{"tabview-last-session-group-name":"title"}} +]}; + +function test() { + let assertWindowTitle = function (win, title) { + let browser = win.gBrowser.tabs[0].linkedBrowser; + let winTitle = win.gBrowser.getWindowTitleForBrowser(browser); + + info('window title is: "' + winTitle + '"'); + is(winTitle.indexOf(title), 0, "title starts with '" + title + "'"); + }; + + let testGroupNameChange = function (win) { + showTabView(function () { + let cw = win.TabView.getContentWindow(); + let groupItem = cw.GroupItems.groupItems[0]; + groupItem.setTitle("new-title"); + + hideTabView(function () { + assertWindowTitle(win, "new-title"); + finish(); + }, win); + }, win); + }; + + waitForExplicitFinish(); + + newWindowWithState(stateStartup, function (win) { + registerCleanupFunction(function () win.close()); + assertWindowTitle(win, "title"); + testGroupNameChange(win); + }); +} diff --git a/browser/base/content/test/tabview/browser_tabview_bug595191.js b/browser/components/tabview/test/browser_tabview_bug595191.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595191.js rename to browser/components/tabview/test/browser_tabview_bug595191.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595436.js b/browser/components/tabview/test/browser_tabview_bug595436.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595436.js rename to browser/components/tabview/test/browser_tabview_bug595436.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595518.js b/browser/components/tabview/test/browser_tabview_bug595518.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595518.js rename to browser/components/tabview/test/browser_tabview_bug595518.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595521.js b/browser/components/tabview/test/browser_tabview_bug595521.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595521.js rename to browser/components/tabview/test/browser_tabview_bug595521.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595560.js b/browser/components/tabview/test/browser_tabview_bug595560.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595560.js rename to browser/components/tabview/test/browser_tabview_bug595560.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595601.js b/browser/components/tabview/test/browser_tabview_bug595601.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595601.js rename to browser/components/tabview/test/browser_tabview_bug595601.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595804.js b/browser/components/tabview/test/browser_tabview_bug595804.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595804.js rename to browser/components/tabview/test/browser_tabview_bug595804.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595930.js b/browser/components/tabview/test/browser_tabview_bug595930.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595930.js rename to browser/components/tabview/test/browser_tabview_bug595930.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595943.js b/browser/components/tabview/test/browser_tabview_bug595943.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595943.js rename to browser/components/tabview/test/browser_tabview_bug595943.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug595965.js b/browser/components/tabview/test/browser_tabview_bug595965.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug595965.js rename to browser/components/tabview/test/browser_tabview_bug595965.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug596781.js b/browser/components/tabview/test/browser_tabview_bug596781.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug596781.js rename to browser/components/tabview/test/browser_tabview_bug596781.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug597248.js b/browser/components/tabview/test/browser_tabview_bug597248.js similarity index 95% rename from browser/base/content/test/tabview/browser_tabview_bug597248.js rename to browser/components/tabview/test/browser_tabview_bug597248.js index eeb8dfe0f55e..98490c1b29f6 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug597248.js +++ b/browser/components/tabview/test/browser_tabview_bug597248.js @@ -16,8 +16,8 @@ function test() { function setupOne(win) { win.TabView.firstUseExperienced = true; - win.gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/search1.html"); - win.gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html"); + win.gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/search1.html"); + win.gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html"); afterAllTabsLoaded(function () setupTwo(win), win); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug597360.js b/browser/components/tabview/test/browser_tabview_bug597360.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug597360.js rename to browser/components/tabview/test/browser_tabview_bug597360.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug597399.js b/browser/components/tabview/test/browser_tabview_bug597399.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug597399.js rename to browser/components/tabview/test/browser_tabview_bug597399.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug597980.js b/browser/components/tabview/test/browser_tabview_bug597980.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug597980.js rename to browser/components/tabview/test/browser_tabview_bug597980.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug598375.js b/browser/components/tabview/test/browser_tabview_bug598375.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug598375.js rename to browser/components/tabview/test/browser_tabview_bug598375.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug598600.js b/browser/components/tabview/test/browser_tabview_bug598600.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug598600.js rename to browser/components/tabview/test/browser_tabview_bug598600.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug599048.js b/browser/components/tabview/test/browser_tabview_bug599048.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug599048.js rename to browser/components/tabview/test/browser_tabview_bug599048.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug599626.js b/browser/components/tabview/test/browser_tabview_bug599626.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug599626.js rename to browser/components/tabview/test/browser_tabview_bug599626.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug600645.js b/browser/components/tabview/test/browser_tabview_bug600645.js similarity index 96% rename from browser/base/content/test/tabview/browser_tabview_bug600645.js rename to browser/components/tabview/test/browser_tabview_bug600645.js index 8ee342e38cee..f079af744636 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug600645.js +++ b/browser/components/tabview/test/browser_tabview_bug600645.js @@ -68,5 +68,5 @@ function onTabViewWindowLoaded() { newTab.addEventListener("error", errorHandler, false); newTab.linkedBrowser.loadURI( - "http://mochi.test:8888/browser/browser/base/content/test/tabview/test_bug600645.html"); + "http://mochi.test:8888/browser/browser/components/tabview/test/test_bug600645.html"); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug600812.js b/browser/components/tabview/test/browser_tabview_bug600812.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug600812.js rename to browser/components/tabview/test/browser_tabview_bug600812.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug602432.js b/browser/components/tabview/test/browser_tabview_bug602432.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug602432.js rename to browser/components/tabview/test/browser_tabview_bug602432.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug604098.js b/browser/components/tabview/test/browser_tabview_bug604098.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug604098.js rename to browser/components/tabview/test/browser_tabview_bug604098.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug606657.js b/browser/components/tabview/test/browser_tabview_bug606657.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug606657.js rename to browser/components/tabview/test/browser_tabview_bug606657.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug606905.js b/browser/components/tabview/test/browser_tabview_bug606905.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug606905.js rename to browser/components/tabview/test/browser_tabview_bug606905.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug607108.js b/browser/components/tabview/test/browser_tabview_bug607108.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug607108.js rename to browser/components/tabview/test/browser_tabview_bug607108.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug608037.js b/browser/components/tabview/test/browser_tabview_bug608037.js similarity index 96% rename from browser/base/content/test/tabview/browser_tabview_bug608037.js rename to browser/components/tabview/test/browser_tabview_bug608037.js index 37b2f5f9691a..8e02d611feda 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug608037.js +++ b/browser/components/tabview/test/browser_tabview_bug608037.js @@ -8,7 +8,7 @@ function test() { waitForExplicitFinish(); tabOne = gBrowser.addTab("http://mochi.test:8888/"); - tabTwo = gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html"); + tabTwo = gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html"); afterAllTabsLoaded(function () { // make sure the tab one is selected because undoCloseTab() would remove diff --git a/browser/base/content/test/tabview/browser_tabview_bug608158.js b/browser/components/tabview/test/browser_tabview_bug608158.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug608158.js rename to browser/components/tabview/test/browser_tabview_bug608158.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug608184.js b/browser/components/tabview/test/browser_tabview_bug608184.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug608184.js rename to browser/components/tabview/test/browser_tabview_bug608184.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug608405.js b/browser/components/tabview/test/browser_tabview_bug608405.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug608405.js rename to browser/components/tabview/test/browser_tabview_bug608405.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug610208.js b/browser/components/tabview/test/browser_tabview_bug610208.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug610208.js rename to browser/components/tabview/test/browser_tabview_bug610208.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug610242.js b/browser/components/tabview/test/browser_tabview_bug610242.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug610242.js rename to browser/components/tabview/test/browser_tabview_bug610242.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug612470.js b/browser/components/tabview/test/browser_tabview_bug612470.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug612470.js rename to browser/components/tabview/test/browser_tabview_bug612470.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug613541.js b/browser/components/tabview/test/browser_tabview_bug613541.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug613541.js rename to browser/components/tabview/test/browser_tabview_bug613541.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug616729.js b/browser/components/tabview/test/browser_tabview_bug616729.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug616729.js rename to browser/components/tabview/test/browser_tabview_bug616729.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug616967.js b/browser/components/tabview/test/browser_tabview_bug616967.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug616967.js rename to browser/components/tabview/test/browser_tabview_bug616967.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug618816.js b/browser/components/tabview/test/browser_tabview_bug618816.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug618816.js rename to browser/components/tabview/test/browser_tabview_bug618816.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug618828.js b/browser/components/tabview/test/browser_tabview_bug618828.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug618828.js rename to browser/components/tabview/test/browser_tabview_bug618828.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug619937.js b/browser/components/tabview/test/browser_tabview_bug619937.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug619937.js rename to browser/components/tabview/test/browser_tabview_bug619937.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug622835.js b/browser/components/tabview/test/browser_tabview_bug622835.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug622835.js rename to browser/components/tabview/test/browser_tabview_bug622835.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug623768.js b/browser/components/tabview/test/browser_tabview_bug623768.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug623768.js rename to browser/components/tabview/test/browser_tabview_bug623768.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624265.js b/browser/components/tabview/test/browser_tabview_bug624265.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624265.js rename to browser/components/tabview/test/browser_tabview_bug624265.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624692.js b/browser/components/tabview/test/browser_tabview_bug624692.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624692.js rename to browser/components/tabview/test/browser_tabview_bug624692.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624727.js b/browser/components/tabview/test/browser_tabview_bug624727.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624727.js rename to browser/components/tabview/test/browser_tabview_bug624727.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624847.js b/browser/components/tabview/test/browser_tabview_bug624847.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624847.js rename to browser/components/tabview/test/browser_tabview_bug624847.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624931.js b/browser/components/tabview/test/browser_tabview_bug624931.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624931.js rename to browser/components/tabview/test/browser_tabview_bug624931.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug624953.js b/browser/components/tabview/test/browser_tabview_bug624953.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug624953.js rename to browser/components/tabview/test/browser_tabview_bug624953.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug625195.js b/browser/components/tabview/test/browser_tabview_bug625195.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug625195.js rename to browser/components/tabview/test/browser_tabview_bug625195.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug625269.js b/browser/components/tabview/test/browser_tabview_bug625269.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug625269.js rename to browser/components/tabview/test/browser_tabview_bug625269.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug625424.js b/browser/components/tabview/test/browser_tabview_bug625424.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug625424.js rename to browser/components/tabview/test/browser_tabview_bug625424.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug625955.js b/browser/components/tabview/test/browser_tabview_bug625955.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug625955.js rename to browser/components/tabview/test/browser_tabview_bug625955.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug626368.js b/browser/components/tabview/test/browser_tabview_bug626368.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug626368.js rename to browser/components/tabview/test/browser_tabview_bug626368.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug626455.js b/browser/components/tabview/test/browser_tabview_bug626455.js similarity index 92% rename from browser/base/content/test/tabview/browser_tabview_bug626455.js rename to browser/components/tabview/test/browser_tabview_bug626455.js index 0b08374a7394..6b6334c20f24 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug626455.js +++ b/browser/components/tabview/test/browser_tabview_bug626455.js @@ -22,8 +22,7 @@ function test() { contentWindow = TabView.getContentWindow(); activeGroup = contentWindow.GroupItems.getActiveGroupItem(); - gBrowser.browsers[0].contentWindow.location = - "data:text/html,

test for bug 626455, tab1"; + gBrowser.browsers[0].loadURI("data:text/html,

test for bug 626455, tab1"); gBrowser.addTab(TEST_URL); afterAllTabsLoaded(testStayOnPage); @@ -40,7 +39,7 @@ function testStayOnPage() { is(gBrowser.tabs.length, 1, "The total number of tab is 1 when staying on the page"); - let location = gBrowser.browsers[0].contentWindow.location.toString(); + let location = gBrowser.browsers[0].currentURI.spec; isnot(location.indexOf("onbeforeunload"), -1, "The open tab is the expected one"); @@ -80,7 +79,7 @@ function finishTest() { is(contentWindow.TabItems.getItems().length, 1, "The total number of tab items is 1 after leaving the page"); - let location = gBrowser.browsers[0].contentWindow.location.toString(); + let location = gBrowser.browsers[0].currentURI.spec; is(location, "about:blank", "The open tab is the expected one"); isnot(contentWindow.GroupItems.getActiveGroupItem(), activeGroup, diff --git a/browser/base/content/test/tabview/browser_tabview_bug626525.js b/browser/components/tabview/test/browser_tabview_bug626525.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug626525.js rename to browser/components/tabview/test/browser_tabview_bug626525.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug626791.js b/browser/components/tabview/test/browser_tabview_bug626791.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug626791.js rename to browser/components/tabview/test/browser_tabview_bug626791.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug627288.js b/browser/components/tabview/test/browser_tabview_bug627288.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug627288.js rename to browser/components/tabview/test/browser_tabview_bug627288.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug627736.js b/browser/components/tabview/test/browser_tabview_bug627736.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug627736.js rename to browser/components/tabview/test/browser_tabview_bug627736.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug628061.js b/browser/components/tabview/test/browser_tabview_bug628061.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug628061.js rename to browser/components/tabview/test/browser_tabview_bug628061.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug628165.js b/browser/components/tabview/test/browser_tabview_bug628165.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug628165.js rename to browser/components/tabview/test/browser_tabview_bug628165.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug628270.js b/browser/components/tabview/test/browser_tabview_bug628270.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug628270.js rename to browser/components/tabview/test/browser_tabview_bug628270.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug628887.js b/browser/components/tabview/test/browser_tabview_bug628887.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug628887.js rename to browser/components/tabview/test/browser_tabview_bug628887.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug629189.js b/browser/components/tabview/test/browser_tabview_bug629189.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug629189.js rename to browser/components/tabview/test/browser_tabview_bug629189.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug629195.js b/browser/components/tabview/test/browser_tabview_bug629195.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug629195.js rename to browser/components/tabview/test/browser_tabview_bug629195.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug630102.js b/browser/components/tabview/test/browser_tabview_bug630102.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug630102.js rename to browser/components/tabview/test/browser_tabview_bug630102.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug630157.js b/browser/components/tabview/test/browser_tabview_bug630157.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug630157.js rename to browser/components/tabview/test/browser_tabview_bug630157.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug631662.js b/browser/components/tabview/test/browser_tabview_bug631662.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug631662.js rename to browser/components/tabview/test/browser_tabview_bug631662.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug631752.js b/browser/components/tabview/test/browser_tabview_bug631752.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug631752.js rename to browser/components/tabview/test/browser_tabview_bug631752.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug633190.js b/browser/components/tabview/test/browser_tabview_bug633190.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug633190.js rename to browser/components/tabview/test/browser_tabview_bug633190.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug633788.js b/browser/components/tabview/test/browser_tabview_bug633788.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug633788.js rename to browser/components/tabview/test/browser_tabview_bug633788.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug634077.js b/browser/components/tabview/test/browser_tabview_bug634077.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug634077.js rename to browser/components/tabview/test/browser_tabview_bug634077.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug634085.js b/browser/components/tabview/test/browser_tabview_bug634085.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug634085.js rename to browser/components/tabview/test/browser_tabview_bug634085.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug634672.js b/browser/components/tabview/test/browser_tabview_bug634672.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug634672.js rename to browser/components/tabview/test/browser_tabview_bug634672.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug635696.js b/browser/components/tabview/test/browser_tabview_bug635696.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug635696.js rename to browser/components/tabview/test/browser_tabview_bug635696.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug637840.js b/browser/components/tabview/test/browser_tabview_bug637840.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug637840.js rename to browser/components/tabview/test/browser_tabview_bug637840.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug640765.js b/browser/components/tabview/test/browser_tabview_bug640765.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug640765.js rename to browser/components/tabview/test/browser_tabview_bug640765.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug641802.js b/browser/components/tabview/test/browser_tabview_bug641802.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug641802.js rename to browser/components/tabview/test/browser_tabview_bug641802.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug642793.js b/browser/components/tabview/test/browser_tabview_bug642793.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug642793.js rename to browser/components/tabview/test/browser_tabview_bug642793.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug643392.js b/browser/components/tabview/test/browser_tabview_bug643392.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug643392.js rename to browser/components/tabview/test/browser_tabview_bug643392.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug644097.js b/browser/components/tabview/test/browser_tabview_bug644097.js similarity index 94% rename from browser/base/content/test/tabview/browser_tabview_bug644097.js rename to browser/components/tabview/test/browser_tabview_bug644097.js index 2d44da65ef3b..3d8fabb475f4 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug644097.js +++ b/browser/components/tabview/test/browser_tabview_bug644097.js @@ -12,7 +12,7 @@ function test() { // create some tabs with favIcons for (let i = 0; i < 3; i++) - win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/test_bug644097.html", {inBackground: true}); + win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/components/tabview/test/test_bug644097.html", {inBackground: true}); win.gBrowser.removeTab(win.gBrowser.tabs[0]); diff --git a/browser/base/content/test/tabview/browser_tabview_bug648882.js b/browser/components/tabview/test/browser_tabview_bug648882.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug648882.js rename to browser/components/tabview/test/browser_tabview_bug648882.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug649006.js b/browser/components/tabview/test/browser_tabview_bug649006.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug649006.js rename to browser/components/tabview/test/browser_tabview_bug649006.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug649307.js b/browser/components/tabview/test/browser_tabview_bug649307.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug649307.js rename to browser/components/tabview/test/browser_tabview_bug649307.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug649319.js b/browser/components/tabview/test/browser_tabview_bug649319.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug649319.js rename to browser/components/tabview/test/browser_tabview_bug649319.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug650280.js b/browser/components/tabview/test/browser_tabview_bug650280.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug650280.js rename to browser/components/tabview/test/browser_tabview_bug650280.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug650573.js b/browser/components/tabview/test/browser_tabview_bug650573.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug650573.js rename to browser/components/tabview/test/browser_tabview_bug650573.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug651311.js b/browser/components/tabview/test/browser_tabview_bug651311.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug651311.js rename to browser/components/tabview/test/browser_tabview_bug651311.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug654295.js b/browser/components/tabview/test/browser_tabview_bug654295.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug654295.js rename to browser/components/tabview/test/browser_tabview_bug654295.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug654721.js b/browser/components/tabview/test/browser_tabview_bug654721.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug654721.js rename to browser/components/tabview/test/browser_tabview_bug654721.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug654941.js b/browser/components/tabview/test/browser_tabview_bug654941.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug654941.js rename to browser/components/tabview/test/browser_tabview_bug654941.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug655269.js b/browser/components/tabview/test/browser_tabview_bug655269.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug655269.js rename to browser/components/tabview/test/browser_tabview_bug655269.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug656778.js b/browser/components/tabview/test/browser_tabview_bug656778.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug656778.js rename to browser/components/tabview/test/browser_tabview_bug656778.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug656913.js b/browser/components/tabview/test/browser_tabview_bug656913.js similarity index 93% rename from browser/base/content/test/tabview/browser_tabview_bug656913.js rename to browser/components/tabview/test/browser_tabview_bug656913.js index e45a3c64fc40..e20e4ae3821e 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug656913.js +++ b/browser/components/tabview/test/browser_tabview_bug656913.js @@ -5,7 +5,7 @@ function test() { waitForExplicitFinish(); - let urlBase = "http://mochi.test:8888/browser/browser/base/content/test/tabview/"; + let urlBase = "http://mochi.test:8888/browser/browser/components/tabview/test/"; let newTab = gBrowser.addTab(urlBase + "search1.html"); registerCleanupFunction(function() { diff --git a/browser/base/content/test/tabview/browser_tabview_bug662266.js b/browser/components/tabview/test/browser_tabview_bug662266.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug662266.js rename to browser/components/tabview/test/browser_tabview_bug662266.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug663421.js b/browser/components/tabview/test/browser_tabview_bug663421.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug663421.js rename to browser/components/tabview/test/browser_tabview_bug663421.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug665502.js b/browser/components/tabview/test/browser_tabview_bug665502.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug665502.js rename to browser/components/tabview/test/browser_tabview_bug665502.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug669694.js b/browser/components/tabview/test/browser_tabview_bug669694.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug669694.js rename to browser/components/tabview/test/browser_tabview_bug669694.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug673196.js b/browser/components/tabview/test/browser_tabview_bug673196.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug673196.js rename to browser/components/tabview/test/browser_tabview_bug673196.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug673729.js b/browser/components/tabview/test/browser_tabview_bug673729.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug673729.js rename to browser/components/tabview/test/browser_tabview_bug673729.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug677310.js b/browser/components/tabview/test/browser_tabview_bug677310.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug677310.js rename to browser/components/tabview/test/browser_tabview_bug677310.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug679853.js b/browser/components/tabview/test/browser_tabview_bug679853.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug679853.js rename to browser/components/tabview/test/browser_tabview_bug679853.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug681599.js b/browser/components/tabview/test/browser_tabview_bug681599.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug681599.js rename to browser/components/tabview/test/browser_tabview_bug681599.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug685476.js b/browser/components/tabview/test/browser_tabview_bug685476.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug685476.js rename to browser/components/tabview/test/browser_tabview_bug685476.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug685692.js b/browser/components/tabview/test/browser_tabview_bug685692.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug685692.js rename to browser/components/tabview/test/browser_tabview_bug685692.js diff --git a/browser/base/content/test/tabview/browser_tabview_bug686654.js b/browser/components/tabview/test/browser_tabview_bug686654.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_bug686654.js rename to browser/components/tabview/test/browser_tabview_bug686654.js diff --git a/browser/base/content/test/tabview/browser_tabview_click_group.js b/browser/components/tabview/test/browser_tabview_click_group.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_click_group.js rename to browser/components/tabview/test/browser_tabview_click_group.js diff --git a/browser/base/content/test/tabview/browser_tabview_dragdrop.js b/browser/components/tabview/test/browser_tabview_dragdrop.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_dragdrop.js rename to browser/components/tabview/test/browser_tabview_dragdrop.js diff --git a/browser/base/content/test/tabview/browser_tabview_exit_button.js b/browser/components/tabview/test/browser_tabview_exit_button.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_exit_button.js rename to browser/components/tabview/test/browser_tabview_exit_button.js diff --git a/browser/base/content/test/tabview/browser_tabview_expander.js b/browser/components/tabview/test/browser_tabview_expander.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_expander.js rename to browser/components/tabview/test/browser_tabview_expander.js diff --git a/browser/base/content/test/tabview/browser_tabview_firstrun_pref.js b/browser/components/tabview/test/browser_tabview_firstrun_pref.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_firstrun_pref.js rename to browser/components/tabview/test/browser_tabview_firstrun_pref.js diff --git a/browser/base/content/test/tabview/browser_tabview_group.js b/browser/components/tabview/test/browser_tabview_group.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_group.js rename to browser/components/tabview/test/browser_tabview_group.js diff --git a/browser/base/content/test/tabview/browser_tabview_launch.js b/browser/components/tabview/test/browser_tabview_launch.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_launch.js rename to browser/components/tabview/test/browser_tabview_launch.js diff --git a/browser/base/content/test/tabview/browser_tabview_layout.js b/browser/components/tabview/test/browser_tabview_layout.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_layout.js rename to browser/components/tabview/test/browser_tabview_layout.js diff --git a/browser/base/content/test/tabview/browser_tabview_multiwindow_search.js b/browser/components/tabview/test/browser_tabview_multiwindow_search.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_multiwindow_search.js rename to browser/components/tabview/test/browser_tabview_multiwindow_search.js diff --git a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js b/browser/components/tabview/test/browser_tabview_privatebrowsing.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_privatebrowsing.js rename to browser/components/tabview/test/browser_tabview_privatebrowsing.js diff --git a/browser/base/content/test/tabview/browser_tabview_rtl.js b/browser/components/tabview/test/browser_tabview_rtl.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_rtl.js rename to browser/components/tabview/test/browser_tabview_rtl.js diff --git a/browser/base/content/test/tabview/browser_tabview_search.js b/browser/components/tabview/test/browser_tabview_search.js similarity index 98% rename from browser/base/content/test/tabview/browser_tabview_search.js rename to browser/components/tabview/test/browser_tabview_search.js index 4096a14b2e59..29c8243670b8 100644 --- a/browser/base/content/test/tabview/browser_tabview_search.js +++ b/browser/components/tabview/test/browser_tabview_search.js @@ -8,7 +8,7 @@ function test() { waitForExplicitFinish(); // set up our tabs - let urlBase = "http://mochi.test:8888/browser/browser/base/content/test/tabview/"; + let urlBase = "http://mochi.test:8888/browser/browser/components/tabview/test/"; let tabOne = gBrowser.addTab(urlBase + "search1.html"); let tabTwo = gBrowser.addTab(urlBase + "search2.html"); newTabs = [ tabOne, tabTwo ]; diff --git a/browser/base/content/test/tabview/browser_tabview_snapping.js b/browser/components/tabview/test/browser_tabview_snapping.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_snapping.js rename to browser/components/tabview/test/browser_tabview_snapping.js diff --git a/browser/base/content/test/tabview/browser_tabview_startup_transitions.js b/browser/components/tabview/test/browser_tabview_startup_transitions.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_startup_transitions.js rename to browser/components/tabview/test/browser_tabview_startup_transitions.js diff --git a/browser/base/content/test/tabview/browser_tabview_storage_policy.js b/browser/components/tabview/test/browser_tabview_storage_policy.js similarity index 97% rename from browser/base/content/test/tabview/browser_tabview_storage_policy.js rename to browser/components/tabview/test/browser_tabview_storage_policy.js index 0d5347f3bdb9..df14a77f7bce 100644 --- a/browser/base/content/test/tabview/browser_tabview_storage_policy.js +++ b/browser/components/tabview/test/browser_tabview_storage_policy.js @@ -48,7 +48,7 @@ function test1() { HttpRequestObserver.cacheControlValue = null; }); - newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/base/content/test/tabview/dummy_page.html"); + newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/components/tabview/test/dummy_page.html"); } function test2() { @@ -73,7 +73,7 @@ function test3() { Services.prefs.setBoolPref(PREF_DISK_CACHE_SSL, true); - newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/dummy_page.html"); + newTab.linkedBrowser.loadURI("https://example.com/browser/browser/components/tabview/test/dummy_page.html"); afterAllTabsLoaded(function() { let tabItem = newTab._tabViewTabItem; @@ -91,7 +91,7 @@ function test4() { Services.prefs.setBoolPref(PREF_DISK_CACHE_SSL, false); - newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/"); + newTab.linkedBrowser.loadURI("https://example.com/browser/browser/components/tabview/test/"); afterAllTabsLoaded(function() { let tabItem = newTab._tabViewTabItem; diff --git a/browser/base/content/test/tabview/browser_tabview_thumbnail_storage.js b/browser/components/tabview/test/browser_tabview_thumbnail_storage.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_thumbnail_storage.js rename to browser/components/tabview/test/browser_tabview_thumbnail_storage.js diff --git a/browser/base/content/test/tabview/browser_tabview_undo_group.js b/browser/components/tabview/test/browser_tabview_undo_group.js similarity index 100% rename from browser/base/content/test/tabview/browser_tabview_undo_group.js rename to browser/components/tabview/test/browser_tabview_undo_group.js diff --git a/browser/base/content/test/tabview/dummy_page.html b/browser/components/tabview/test/dummy_page.html similarity index 100% rename from browser/base/content/test/tabview/dummy_page.html rename to browser/components/tabview/test/dummy_page.html diff --git a/browser/base/content/test/tabview/head.js b/browser/components/tabview/test/head.js similarity index 100% rename from browser/base/content/test/tabview/head.js rename to browser/components/tabview/test/head.js diff --git a/browser/base/content/test/tabview/search1.html b/browser/components/tabview/test/search1.html similarity index 100% rename from browser/base/content/test/tabview/search1.html rename to browser/components/tabview/test/search1.html diff --git a/browser/base/content/test/tabview/search2.html b/browser/components/tabview/test/search2.html similarity index 100% rename from browser/base/content/test/tabview/search2.html rename to browser/components/tabview/test/search2.html diff --git a/browser/base/content/test/tabview/test_bug600645.html b/browser/components/tabview/test/test_bug600645.html similarity index 100% rename from browser/base/content/test/tabview/test_bug600645.html rename to browser/components/tabview/test/test_bug600645.html diff --git a/browser/base/content/test/tabview/test_bug644097.html b/browser/components/tabview/test/test_bug644097.html similarity index 100% rename from browser/base/content/test/tabview/test_bug644097.html rename to browser/components/tabview/test/test_bug644097.html diff --git a/browser/base/content/tabview/thumbnailStorage.js b/browser/components/tabview/thumbnailStorage.js similarity index 100% rename from browser/base/content/tabview/thumbnailStorage.js rename to browser/components/tabview/thumbnailStorage.js diff --git a/browser/base/content/tabview/trench.js b/browser/components/tabview/trench.js similarity index 100% rename from browser/base/content/tabview/trench.js rename to browser/components/tabview/trench.js diff --git a/browser/base/content/tabview/ui.js b/browser/components/tabview/ui.js similarity index 100% rename from browser/base/content/tabview/ui.js rename to browser/components/tabview/ui.js diff --git a/browser/devtools/highlighter/TreePanel.jsm b/browser/devtools/highlighter/TreePanel.jsm index cd75fdab2516..1835bc87aaee 100644 --- a/browser/devtools/highlighter/TreePanel.jsm +++ b/browser/devtools/highlighter/TreePanel.jsm @@ -230,7 +230,14 @@ TreePanel.prototype = { treeBox.minHeight = 10; treeBox.flex = 1; toolbarParent.insertBefore(treeBox, toolbar); - this.createResizer(); + + let resizerTop = + this.IUI.browser.ownerDocument.getElementById("inspector-top-resizer"); + let resizerEnd = + this.IUI.browser.ownerDocument.getElementById("inspector-end-resizer"); + resizerTop.removeAttribute("disabled"); + resizerEnd.removeAttribute("disabled"); + treeBox.appendChild(this.treeIFrame); let boundLoadedInitializeTreePanel = function loadedInitializeTreePanel() @@ -251,28 +258,19 @@ TreePanel.prototype = { } }, - /** - * Lame resizer on the toolbar. - */ - createResizer: function TP_createResizer() - { - let resizer = this.document.createElement("resizer"); - resizer.id = "inspector-horizontal-splitter"; - resizer.setAttribute("dir", "top"); - resizer.flex = 1; - resizer.setAttribute("element", "inspector-tree-box"); - resizer.height = 24; - this.IUI.toolbar.appendChild(resizer); - this.resizer = resizer; - }, - /** * Close the TreePanel. */ close: function TP_close() { if (this.openInDock) { - this.IUI.toolbar.removeChild(this.resizer); + let resizerTop = + this.IUI.browser.ownerDocument.getElementById("inspector-top-resizer"); + let resizerEnd = + this.IUI.browser.ownerDocument.getElementById("inspector-end-resizer"); + resizerTop.setAttribute("disabled", "true"); + resizerEnd.setAttribute("disabled", "true"); + let treeBox = this.container; let treeBoxParent = treeBox.parentNode; treeBoxParent.removeChild(treeBox); @@ -679,8 +677,6 @@ TreePanel.prototype = { domplateUtils.setDOM(null); - delete this.resizer; - if (this.DOMHelpers) { this.DOMHelpers.destroy(); delete this.DOMHelpers; diff --git a/browser/devtools/highlighter/inspector.jsm b/browser/devtools/highlighter/inspector.jsm index 9dc18f7c299d..74403283bfe4 100644 --- a/browser/devtools/highlighter/inspector.jsm +++ b/browser/devtools/highlighter/inspector.jsm @@ -49,6 +49,7 @@ var EXPORTED_SYMBOLS = ["InspectorUI"]; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource:///modules/TreePanel.jsm"); const INSPECTOR_INVISIBLE_ELEMENTS = { "head": true, @@ -345,72 +346,72 @@ Highlighter.prototype = { */ highlight: function Highlighter_highlight(aScroll) { - // node is not set or node is not highlightable, bail - if (!this.node || !this.isNodeHighlightable(this.node)) { - return; - } + let rect = null; - if (aScroll) { - this.node.scrollIntoView(); - } + if (this.node && this.isNodeHighlightable(this.node)) { - let clientRect = this.node.getBoundingClientRect(); - - // Go up in the tree of frames to determine the correct rectangle. - // clientRect is read-only, we need to be able to change properties. - let rect = {top: clientRect.top, - left: clientRect.left, - width: clientRect.width, - height: clientRect.height}; - - let frameWin = this.node.ownerDocument.defaultView; - - // We iterate through all the parent windows. - while (true) { - - // Does the selection overflow on the right of its window? - let diffx = frameWin.innerWidth - (rect.left + rect.width); - if (diffx < 0) { - rect.width += diffx; + if (aScroll) { + this.node.scrollIntoView(); } - // Does the selection overflow on the bottom of its window? - let diffy = frameWin.innerHeight - (rect.top + rect.height); - if (diffy < 0) { - rect.height += diffy; + let clientRect = this.node.getBoundingClientRect(); + + // Go up in the tree of frames to determine the correct rectangle. + // clientRect is read-only, we need to be able to change properties. + rect = {top: clientRect.top, + left: clientRect.left, + width: clientRect.width, + height: clientRect.height}; + + let frameWin = this.node.ownerDocument.defaultView; + + // We iterate through all the parent windows. + while (true) { + + // Does the selection overflow on the right of its window? + let diffx = frameWin.innerWidth - (rect.left + rect.width); + if (diffx < 0) { + rect.width += diffx; + } + + // Does the selection overflow on the bottom of its window? + let diffy = frameWin.innerHeight - (rect.top + rect.height); + if (diffy < 0) { + rect.height += diffy; + } + + // Does the selection overflow on the left of its window? + if (rect.left < 0) { + rect.width += rect.left; + rect.left = 0; + } + + // Does the selection overflow on the top of its window? + if (rect.top < 0) { + rect.height += rect.top; + rect.top = 0; + } + + // Selection has been clipped to fit in its own window. + + // Are we in the top-level window? + if (frameWin.parent === frameWin || !frameWin.frameElement) { + break; + } + + // We are in an iframe. + // We take into account the parent iframe position and its + // offset (borders and padding). + let frameRect = frameWin.frameElement.getBoundingClientRect(); + + let [offsetTop, offsetLeft] = + this.IUI.getIframeContentOffset(frameWin.frameElement); + + rect.top += frameRect.top + offsetTop; + rect.left += frameRect.left + offsetLeft; + + frameWin = frameWin.parent; } - - // Does the selection overflow on the left of its window? - if (rect.left < 0) { - rect.width += rect.left; - rect.left = 0; - } - - // Does the selection overflow on the top of its window? - if (rect.top < 0) { - rect.height += rect.top; - rect.top = 0; - } - - // Selection has been clipped to fit in its own window. - - // Are we in the top-level window? - if (frameWin.parent === frameWin || !frameWin.frameElement) { - break; - } - - // We are in an iframe. - // We take into account the parent iframe position and its - // offset (borders and padding). - let frameRect = frameWin.frameElement.getBoundingClientRect(); - - let [offsetTop, offsetLeft] = - this.IUI.getIframeContentOffset(frameWin.frameElement); - - rect.top += frameRect.top + offsetTop; - rect.left += frameRect.left + offsetLeft; - - frameWin = frameWin.parent; } this.highlightRectangle(rect); @@ -448,6 +449,11 @@ Highlighter.prototype = { */ highlightRectangle: function Highlighter_highlightRectangle(aRect) { + if (!aRect) { + this.unhighlight(); + return; + } + let oldRect = this._contentRect; if (oldRect && aRect.top == oldRect.top && aRect.left == oldRect.left && @@ -469,6 +475,9 @@ Highlighter.prototype = { if (aRectScaled.left >= 0 && aRectScaled.top >= 0 && aRectScaled.width > 0 && aRectScaled.height > 0) { + + this.veilTransparentBox.style.visibility = "visible"; + // The bottom div and the right div are flexibles (flex=1). // We don't need to resize them. this.veilTopBox.style.height = aRectScaled.top + "px"; @@ -495,6 +504,7 @@ Highlighter.prototype = { this._highlighting = false; this.veilMiddleBox.style.height = 0; this.veilTransparentBox.style.width = 0; + this.veilTransparentBox.style.visibility = "hidden"; Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.UNHIGHLIGHTING, null); }, @@ -837,7 +847,7 @@ InspectorUI.prototype = { } // Observer used to inspect the specified element from content after the - // inspector UI has been opened. + // inspector UI has been opened (via the content context menu). function inspectObserver(aElement) { Services.obs.removeObserver(boundInspectObserver, INSPECTOR_NOTIFICATIONS.OPENED, @@ -865,14 +875,21 @@ InspectorUI.prototype = { this.initTools(); - if (!this.TreePanel && this.treePanelEnabled) { - Cu.import("resource:///modules/TreePanel.jsm", this); - this.treePanel = new this.TreePanel(this.chromeWin, this); + if (this.treePanelEnabled) { + this.treePanel = new TreePanel(this.chromeWin, this); + } + + if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") && + !this.toolRegistered("styleinspector")) { + this.stylePanel = new StyleInspector(this.chromeWin, this); } this.toolbar.hidden = false; this.inspectMenuitem.setAttribute("checked", true); + // initialize the HTML Breadcrumbs + this.breadcrumbs = new HTMLBreadcrumbs(this); + this.isDirty = false; this.progressListener = new InspectorProgressListener(this); @@ -886,26 +903,7 @@ InspectorUI.prototype = { */ initTools: function IUI_initTools() { - // Style inspector - if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") && - !this.toolRegistered("styleinspector")) { - let stylePanel = StyleInspector.createPanel(true); - this.registerTool({ - id: "styleinspector", - label: StyleInspector.l10n("style.highlighter.button.label"), - tooltiptext: StyleInspector.l10n("style.highlighter.button.tooltip"), - accesskey: StyleInspector.l10n("style.highlighter.accesskey"), - context: stylePanel, - get isOpen() stylePanel.isOpen(), - onSelect: stylePanel.selectNode, - show: stylePanel.showTool, - hide: stylePanel.hideTool, - dim: stylePanel.dimTool, - panel: stylePanel, - unregister: stylePanel.destroy, - }); - this.stylePanel = stylePanel; - } + // Extras go here. }, /** @@ -1004,6 +1002,11 @@ InspectorUI.prototype = { this.highlighter = null; } + if (this.breadcrumbs) { + this.breadcrumbs.destroy(); + this.breadcrumbs = null; + } + this.inspectMenuitem.setAttribute("checked", false); this.browser = this.win = null; // null out references to browser and window this.winID = null; @@ -1014,7 +1017,6 @@ InspectorUI.prototype = { delete this.treePanel; delete this.stylePanel; delete this.toolbar; - delete this.TreePanel; Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null); }, @@ -1098,6 +1100,8 @@ InspectorUI.prototype = { } } + this.breadcrumbs.update(); + this.toolsSelect(aScroll); }, @@ -1893,13 +1897,463 @@ InspectorProgressListener.prototype = { }, }; +/////////////////////////////////////////////////////////////////////////// +//// HTML Breadcrumbs + +/** + * Display the ancestors of the current node and its children. + * Only one "branch" of children are displayed (only one line). + * + * Mechanism: + * . If no nodes displayed yet: + * then display the ancestor of the selected node and the selected node; + * else select the node; + * . If the selected node is the last node displayed, append its first (if any). + * + * @param object aInspector + * The InspectorUI instance. + */ +function HTMLBreadcrumbs(aInspector) +{ + this.IUI = aInspector; + this.DOMHelpers = new DOMHelpers(this.IUI.win); + this._init(); +} + +HTMLBreadcrumbs.prototype = { + _init: function BC__init() + { + this.container = this.IUI.chromeDoc.getElementById("inspector-breadcrumbs"); + this.container.addEventListener("mousedown", this, true); + + // We will save a list of already displayed nodes in this array. + this.nodeHierarchy = []; + + // Last selected node in nodeHierarchy. + this.currentIndex = -1; + + // Siblings menu + this.menu = this.IUI.chromeDoc.createElement("menupopup"); + this.menu.id = "inspector-breadcrumbs-menu"; + + let popupSet = this.IUI.chromeDoc.getElementById("mainPopupSet"); + popupSet.appendChild(this.menu); + + this.menu.addEventListener("popuphiding", (function() { + while (this.menu.hasChildNodes()) { + this.menu.removeChild(this.menu.firstChild); + } + let button = this.container.querySelector("button[siblings-menu-open]"); + button.removeAttribute("siblings-menu-open"); + }).bind(this), false); + }, + + /** + * Build a string that represents the node: tagName#id.class1.class2. + * + * @param aNode The node to pretty-print + * @returns a string + */ + prettyPrintNodeAsText: function BC_prettyPrintNodeText(aNode) + { + let text = aNode.tagName.toLowerCase(); + if (aNode.id) { + text += "#" + aNode.id; + } + for (let i = 0; i < aNode.classList.length; i++) { + text += "." + aNode.classList[i]; + } + return text; + }, + + + /** + * Build

p>strong

+ + + diff --git a/browser/devtools/webconsole/test/browser/browser_gcli_inspect.js b/browser/devtools/webconsole/test/browser/browser_gcli_inspect.js new file mode 100644 index 000000000000..c5499105af0c --- /dev/null +++ b/browser/devtools/webconsole/test/browser/browser_gcli_inspect.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// For more information on GCLI see: +// - https://github.com/mozilla/gcli/blob/master/docs/index.md +// - https://wiki.mozilla.org/DevTools/Features/GCLI + +// Tests that the inspect command works as it should + +Components.utils.import("resource:///modules/gcli.jsm"); + +registerCleanupFunction(function() { + gcliterm = undefined; + requisition = undefined; + + Services.prefs.clearUserPref("devtools.gcli.enable"); +}); + +function test() { + Services.prefs.setBoolPref("devtools.gcli.enable", true); + addTab("http://example.com/browser/browser/devtools/webconsole/test/browser/browser_gcli_inspect.html"); + browser.addEventListener("DOMContentLoaded", onLoad, false); +} + +let gcliterm; +let requisition; + +function onLoad() { + browser.removeEventListener("DOMContentLoaded", onLoad, false); + + try { + openConsole(); + + let hud = HUDService.getHudByWindow(content); + gcliterm = hud.gcliterm; + requisition = gcliterm.opts.requisition; + + testSetup(); + testCreateCommands(); + } + catch (ex) { + ok(false, "Caught exception: " + ex) + gcli._internal.console.error("Test Failure", ex); + } + finally { + closeConsole(); + finishTest(); + } +} + +function testSetup() { + ok(gcliterm, "We have a GCLI term"); + ok(requisition, "We have a Requisition"); +} + +function testCreateCommands() { + type("inspec"); + is(gcliterm.completeNode.textContent, " inspect", "Completion for \"inspec\""); + is(requisition.getStatus().toString(), "ERROR", "inspec is ERROR"); + + type("inspect"); + is(requisition.getStatus().toString(), "ERROR", "inspect is ERROR"); + + type("inspect h1"); + is(requisition.getStatus().toString(), "ERROR", "inspect h1 is ERROR"); + + type("inspect span"); + is(requisition.getStatus().toString(), "ERROR", "inspect span is ERROR"); + + type("inspect div"); + is(requisition.getStatus().toString(), "VALID", "inspect div is VALID"); + + type("inspect .someclass"); + is(requisition.getStatus().toString(), "VALID", "inspect .someclass is VALID"); + + type("inspect #someid"); + is(requisition.getStatus().toString(), "VALID", "inspect #someid is VALID"); + + type("inspect button[disabled]"); + is(requisition.getStatus().toString(), "VALID", "inspect button[disabled] is VALID"); + + type("inspect p>strong"); + is(requisition.getStatus().toString(), "VALID", "inspect p>strong is VALID"); + + type("inspect :root"); + is(requisition.getStatus().toString(), "VALID", "inspect :root is VALID"); +} + +function type(command) { + gcliterm.inputNode.value = command.slice(0, -1); + gcliterm.inputNode.focus(); + EventUtils.synthesizeKey(command.slice(-1), {}); +} diff --git a/browser/devtools/webconsole/test/browser/browser_gcli_web.js b/browser/devtools/webconsole/test/browser/browser_gcli_web.js index 4900e63e4468..0b68f4bfcf93 100644 --- a/browser/devtools/webconsole/test/browser/browser_gcli_web.js +++ b/browser/devtools/webconsole/test/browser/browser_gcli_web.js @@ -54,7 +54,7 @@ var Node = Components.interfaces.nsIDOMNode; * http://opensource.org/licenses/BSD-3-Clause */ -define('gclitest/index', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testHistory', 'gclitest/testRequire'], function(require, exports, module) { +define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testHistory', 'gclitest/testRequire'], function(require, exports, module) { // We need to make sure GCLI is initialized before we begin testing it require('gcli/index'); @@ -65,7 +65,6 @@ define('gclitest/index', ['require', 'exports', 'module' , 'gcli/index', 'test/e examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit')); examiner.addSuite('gclitest/testCli', require('gclitest/testCli')); examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory')); - examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire')); examiner.run(); @@ -1373,7 +1372,7 @@ define('gclitest/requirable', ['require', 'exports', 'module' ], function(requir }); function undefine() { - delete define.modules['gclitest/index']; + delete define.modules['gclitest/suite']; delete define.modules['test/examiner']; delete define.modules['gclitest/testTokenize']; delete define.modules['test/assert']; @@ -1384,7 +1383,7 @@ function undefine() { delete define.modules['gclitest/testRequire']; delete define.modules['gclitest/requirable']; - delete define.globalDomain.modules['gclitest/index']; + delete define.globalDomain.modules['gclitest/suite']; delete define.globalDomain.modules['test/examiner']; delete define.globalDomain.modules['gclitest/testTokenize']; delete define.globalDomain.modules['test/assert']; diff --git a/browser/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh index a0aadd113a11..5208d8fc5824 100755 --- a/browser/installer/windows/nsis/shared.nsh +++ b/browser/installer/windows/nsis/shared.nsh @@ -289,7 +289,7 @@ ; An empty string is used for the 5th param because FirefoxHTML is not a ; protocol handler - ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \ + ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \ "${DDEApplication}" "$3" "WWW_OpenURL" ${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \ @@ -509,7 +509,7 @@ ${If} "$R9" == "true" ; An empty string is used for the 5th param because FirefoxHTML is not a ; protocol handler. - ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \ + ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \ "${DDEApplication}" "$3" "WWW_OpenURL" ${EndIf} diff --git a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties index 5563da808868..6940549ef169 100644 --- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties @@ -35,3 +35,25 @@ consoleManual=Filter, clear and close the web console # LOCALIZATION NOTE (consoleclearDesc) A very short string used to describe the # function of the 'console clear' command. consoleclearDesc=Clear the console + +# LOCALIZATION NOTE (inspectDesc) A very short description of the 'inspect' +# command. See inspectManual for a fuller description of what it does. This +# string is designed to be shown in a menu alongside the command name, which +# is why it should be as short as possible. +inspectDesc=Inspect a node + +# LOCALIZATION NOTE (inspectManual) A fuller description of the 'inspect' +# command, displayed when the user asks for help on what it does. +inspectManual=Investigate the dimensions and properties of an element using \ +a CSS selector to open the DOM highlighter + +# LOCALIZATION NOTE (inspectNodeDesc) A very short string to describe the +# 'node' parameter to the 'inspect' command, which is displayed in a dialog +# when the user is using this command. +inspectNodeDesc=CSS selector + +# LOCALIZATION NOTE (inspectNodeManual) A fuller description of the 'node' +# parameter to the 'inspect' command, displayed when the user asks for help +# on what it does. +inspectNodeManual=A CSS selector for use with Document.querySelector which \ +identifies a single element diff --git a/browser/locales/en-US/chrome/browser/inspector.properties b/browser/locales/en-US/chrome/browser/devtools/inspector.properties similarity index 97% rename from browser/locales/en-US/chrome/browser/inspector.properties rename to browser/locales/en-US/chrome/browser/devtools/inspector.properties index ae1529ff0a01..6f5bb87a9c82 100644 --- a/browser/locales/en-US/chrome/browser/inspector.properties +++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties @@ -7,6 +7,7 @@ confirmNavigationAway.buttonLeaveAccesskey=L confirmNavigationAway.buttonStay=Stay on Page confirmNavigationAway.buttonStayAccesskey=S +breadcrumbs.siblings=Siblings # LOCALIZATION NOTE (htmlPanel): Used in the Inspector tool's openInspectorUI # method when registering the HTML panel. diff --git a/browser/locales/en-US/chrome/browser/scratchpad.dtd b/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd similarity index 87% rename from browser/locales/en-US/chrome/browser/scratchpad.dtd rename to browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd index 7d1cf9ee1871..b20d4e8a02f7 100644 --- a/browser/locales/en-US/chrome/browser/scratchpad.dtd +++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd @@ -95,22 +95,23 @@ - - - + + - - - - - + - - + diff --git a/browser/locales/en-US/chrome/browser/scratchpad.properties b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties similarity index 88% rename from browser/locales/en-US/chrome/browser/scratchpad.properties rename to browser/locales/en-US/chrome/browser/devtools/scratchpad.properties index 36f71bc23428..8434dfc8f2c6 100644 --- a/browser/locales/en-US/chrome/browser/scratchpad.properties +++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties @@ -33,3 +33,7 @@ saveFile.failed=The file save operation failed. # how to use the Scratchpad. Note that this should be a valid JavaScript # comment inside /* and */. scratchpadIntro=/*\n * This is a JavaScript Scratchpad.\n *\n * Enter some JavaScript, then Right Click or choose from the Execute Menu:\n * 1. Run to evaluate the selected text,\n * 2. Inspect to bring up an Object Inspector on the result, or,\n * 3. Display to insert the result in a comment after the selection.\n */\n\n + +# LOCALIZATION NOTE (notification.browserContext): This is the message displayed +# over the top of the editor when the user has switched to browser context. +browserContext.notification=This scratchpad executes in the Browser context. diff --git a/browser/locales/en-US/chrome/browser/styleinspector.dtd b/browser/locales/en-US/chrome/browser/devtools/styleinspector.dtd similarity index 100% rename from browser/locales/en-US/chrome/browser/styleinspector.dtd rename to browser/locales/en-US/chrome/browser/devtools/styleinspector.dtd diff --git a/browser/locales/en-US/chrome/browser/styleinspector.properties b/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties similarity index 100% rename from browser/locales/en-US/chrome/browser/styleinspector.properties rename to browser/locales/en-US/chrome/browser/devtools/styleinspector.properties diff --git a/toolkit/locales/en-US/chrome/global/webConsole.dtd b/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd similarity index 100% rename from toolkit/locales/en-US/chrome/global/webConsole.dtd rename to browser/locales/en-US/chrome/browser/devtools/webConsole.dtd diff --git a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties new file mode 100644 index 000000000000..b78faef1b8c1 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties @@ -0,0 +1,174 @@ +typeError=Error: +typeWarning=Warning: +typeNetwork=Network: +typeException=Exception: +typeCssParser=CSS Parser: +typeStrict=Strict Warning: +msgCategory=Category: +errLine=Line: %S +btnHide=Hide +btnPrefs=Preferences +categoryPage=Page: +categoryConsole=Console: +btnMutation=DOM Mutation +tipMutation=Toggle DOM Mutation event logging +btnPageNet=Net +tipPageNet=Log network access +btnPageCSS=CSS +tipPageCSS=Log CSS parsing errors +btnPageJS=JS +tipPageJS=Log JavaScript exceptions +# LOCALIZATION NOTE (btnPageWebDeveloper): +# +# This is used as the text of the "Web Developer" button on the toolbar. It +# shows or hides messages that the web developer inserted on the page for +# debugging purposes, using calls such console.log() and console.error(). You +# may wish to localize this as "Page" if that is clearer in your locale. See +# bug 601667 for more information. +btnPageWebDeveloper=Web Developer +# LOCALIZATION NOTE (tipPageWebDeveloper): +# +# This is used as the text of the tool tip for the "Web Developer" button on +# the toolbar. +tipPageWebDeveloper=Log messages sent to the "console" object +btnConsoleErrors=Errors +tipConsoleErrors=Log calls to console.error() +btnConsoleInfo=Info +tipConsoleInfo=Log calls to console.info() +btnConsoleWarnings=Warnings +tipConsoleWarnings=Log calls to console.warn() +btnConsoleLog=Log +tipConsoleLog=Log calls to console.log() +btnGlobal=Global Messages +tipGlobal=Toggle Global Message logging +localConsole=Local Console +clearConsoleCmd.label=Clear Console +clearConsoleCmd.accesskey=e +# LOCALIZATION NOTE (btnClear): +# +# This is used as the text of the "Clear" button for the toolbar. It clears the +# contents of the console. +btnClear=Clear +stringFilter=Filter +close.button=Close +close.accesskey=C +update.button=Update +update.accesskey=U +# LOCALIZATION NOTE FOR `jsPropertyTitle` AND `jsPropertyInspectTitle`: +# +# The "PropertyPanel" is used to display a JS object to the user. +# If it is clear which object is being inspected (e.g., window, document object) +# the title of the panel is based on the `jsPropertyInspectTitle` string. +# If it isn't clear which object is being inspected, the `jsPropertyTitle` string +# gets used. This can be the case when the user logs an object to the WebConsole +# output using the console.log(aObjectToInspect) method. +# +# You can find a screenshot of the PropertyPanel here: +# https://bug585030.bugzilla.mozilla.org/attachment.cgi?id=464034 +jsPropertyTitle=Object Inspector +# LOCALIZATION NOTE (jsPropertyInspectTitle): +# +# The %S is replaced by the evaluated code the user clicked on in the console. +# +# Example: The user executed `window.document` in the WebConsole. The `document` +# object is written to the output. If the user clicks on the `document` output +# in the console, a PropertyPanel will show up. The title of the PropertyPanel +# is set to `Inspect: window.document` because the clicked `document` object was +# evaluated based on the `window.document` string. +jsPropertyInspectTitle=Inspect: %S +saveBodies.label=Log Request and Response Bodies +saveBodies.accesskey=L +copyCmd.label=Copy +copyCmd.accesskey=C +selectAllCmd.label=Select All +selectAllCmd.accesskey=A +# LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock), +# %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds. +timestampFormat=%02S:%02S:%02S.%03S + +helperFuncUnsupportedTypeError=Can't call pprint on this type of object. +NetworkPanel.label=Inspect Network Request +# LOCALIZATION NOTE (NetworkPanel.deltaDurationMS): +# +# This string is used to show the duration between two network events (e.g +# request and respones header or response header and response body). +NetworkPanel.durationMS=%Sms +# LOCALIZATION NOTE (NetworkPanel.imageSizeDeltaDurationMS): +# This string is used to show the duration between the response header and the +# response body event. It also shows the size of the received or cached image. +# +# The first %S is replace by the width of the inspected image. +# The second %S is replaced by the height of the inspected image. +# The third %S is replaced by the duration between the response header and the +# response body event. +NetworkPanel.imageSizeDeltaDurationMS=%Sx%Spx, Δ%Sms +# LOCALIZATION NOTE (NetworkPanel.responseBodyUnableToDisplay.content): +# +# This string is displayed within the response body section of the NetworkPanel +# if the content type of the network request can't be displayed in the +# NetworkPanel. E.g. any kind of text is easy to display, but some audio or +# flash data received from the server can't be displayed. +# +# The %S is replaced by the content type, that can't be displayed, examples are +# o application/x-shockwave-flash +# o music/crescendo +NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S" +ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page. + +# LOCALIZATION NOTE (inspectStyle.nullObjectPassed): +# This message is returned when a null object is passed in to inspectstyle() +inspectStyle.nullObjectPassed=Object is null + +# LOCALIZATION NOTE (inspectStyle.mustBeDomNode): +# This message is returned when a non-DOM node is passed in to inspectstyle() +inspectStyle.mustBeDomNode=Object must be a valid DOM node + +# LOCALIZATION NOTE (inspectStyle.nodeHasNoStyleProps): +# This message is returned when an unstyleable object is passed in to inspectstyle() +inspectStyle.nodeHasNoStyleProps=Object cannot be styled + +# LOCALIZATION NOTE (inspectStyle.styleInspectorNotEnabled): +# This message is returned when devtools.styleinspector.enabled is not set to +# true +inspectStyle.styleInspectorNotEnabled=The style inspector is not enabled. Please set the option devtools.styleinspector.enabled to true in about:config to use this command. + +# LOCALIZATION NOTE (webConsolePosition): The label shown for the menu which +# allows the user to toggle between the Web Console positioning types. +webConsolePosition=Position + +# LOCALIZATION NOTE (webConsolePositionTooltip): The tooltip shown when the user +# hovers the Position button in the Web Console toolbar. +webConsolePositionTooltip=Position the Web Console above or below the document + +# LOCALIZATION NOTE (webConsolePositionAbove): When this option is selected the +# Web Console interface is displayed above the web page. +webConsolePositionAbove=Above + +# LOCALIZATION NOTE (webConsolePositionBelow): When this option is selected the +# Web Console interface is displayed below the web page. +webConsolePositionBelow=Below + +# LOCALIZATION NOTE (webConsolePositionWindow): When this option is selected the +# Web Console interface is displayed in a floating panel. +webConsolePositionWindow=Window + +# LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating +# panel title, followed by the web page URL. +# For RTL languages you need to set the LRM in the string to give the URL +# the correct direction. +webConsoleWindowTitleAndURL=Web Console - %S + +# LOCALIZATION NOTE (Autocomplete.label): +# The autocomplete popup panel label/title. +Autocomplete.label=Autocomplete popup + +# LOCALIZATION NOTE (stacktrace.anonymousFunction): +# This string is used to display JavaScript functions that have no given name - +# they are said to be anonymous. See stacktrace.outputMessage. +stacktrace.anonymousFunction= + +# LOCALIZATION NOTE (stacktrace.outputMessage): +# This string is used in the Web Console output to identify a web developer call +# to console.trace(). The stack trace of JavaScript function calls is displayed. +# In this minimal message we only show the last call. +stacktrace.outputMessage=Stack trace from %S, function %S, line %S. diff --git a/browser/locales/en-US/chrome/browser/syncProgress.dtd b/browser/locales/en-US/chrome/browser/syncProgress.dtd new file mode 100644 index 000000000000..59da81a72af7 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/syncProgress.dtd @@ -0,0 +1,11 @@ + + %brandDTD; + + + + + + + + diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index 5320a52caaf5..c334e3f04ac8 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -9,18 +9,21 @@ locale/browser/aboutHome.dtd (%chrome/browser/aboutHome.dtd) locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd) #ifdef MOZ_SERVICES_SYNC + locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd) locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd) #endif * locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) - locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties) - locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties) - locale/browser/styleinspector.properties (%chrome/browser/styleinspector.properties) - locale/browser/styleinspector.dtd (%chrome/browser/styleinspector.dtd) - locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties) - locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd) - locale/browser/inspector.properties (%chrome/browser/inspector.properties) + locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties) + locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties) + locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties) + locale/browser/devtools/inspector.properties (%chrome/browser/devtools/inspector.properties) + locale/browser/devtools/scratchpad.properties (%chrome/browser/devtools/scratchpad.properties) + locale/browser/devtools/scratchpad.dtd (%chrome/browser/devtools/scratchpad.dtd) + locale/browser/devtools/styleinspector.properties (%chrome/browser/devtools/styleinspector.properties) + locale/browser/devtools/styleinspector.dtd (%chrome/browser/devtools/styleinspector.dtd) + locale/browser/devtools/webConsole.dtd (%chrome/browser/devtools/webConsole.dtd) locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd) locale/browser/openLocation.properties (%chrome/browser/openLocation.properties) * locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd) diff --git a/browser/themes/gnomestripe/browser/browser.css b/browser/themes/gnomestripe/browser/browser.css index 71c42f5aaaf0..97e1744863a0 100644 --- a/browser/themes/gnomestripe/browser/browser.css +++ b/browser/themes/gnomestripe/browser/browser.css @@ -1585,10 +1585,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- } /* Tab drag and drop */ -.tab-drag-label { - padding: 2px; -} - .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); margin-bottom: -11px; @@ -1954,15 +1950,83 @@ panel[dimmed="true"] { outline-color: white; } -/* - * need a "bumpy" background image for this! - */ -#inspector-horizontal-splitter { - background: none !important; +/* Highlighter toolbar */ + +#inspector-toolbar { + -moz-appearance: none; + padding: 0 3px 4px; + border-top: 1px solid hsla(210, 8%, 5%, .65); + box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset; + background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%)); +} + +#inspector-inspect-toolbutton, +#inspector-tools > toolbarbutton { + -moz-appearance: none; + min-width: 78px; + min-height: 22px; + color: hsl(210,30%,85%); + text-shadow: 0 -1px 0 hsla(210,8%,5%,.45); + border: 1px solid hsla(210,8%,5%,.45); + border-radius: 3px; + background: -moz-linear-gradient(hsla(212,7%,57%,.35), hsla(212,7%,57%,.1)) padding-box; + box-shadow: 0 1px 0 hsla(210,16%,76%,.15) inset, 0 0 0 1px hsla(210,16%,76%,.15) inset, 0 1px 0 hsla(210,16%,76%,.15); +} + +#inspector-inspect-toolbutton:not([checked]):hover:active, +#inspector-tools > toolbarbutton:not([checked]):hover:active { + border-color: hsla(210,8%,5%,.6); + background: -moz-linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3)); + box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15); +} + +#inspector-inspect-toolbutton[checked], +#inspector-tools > toolbarbutton[checked] { + color: hsl(208,100%,60%) !important; + border-color: hsla(210,8%,5%,.6) !important; + background: -moz-linear-gradient(hsla(220,6%,10%,.6), hsla(210,11%,18%,.45) 75%, hsla(210,11%,30%,.4)); + box-shadow: 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15); +} + +#inspector-inspect-toolbutton[checked]:hover, +#inspector-tools > toolbarbutton[checked]:hover { + background-color: transparent !important; +} + +#inspector-inspect-toolbutton[checked]:hover:active, +#inspector-tools > toolbarbutton[checked]:hover:active { + background-color: hsla(210,8%,5%,.2) !important; +} + +/* Highlighter - toolbar resizers */ + +.inspector-resizer { -moz-appearance: none; cursor: n-resize; } +.inspector-resizer[disabled] { + visibility: hidden; +} + +#inspector-top-resizer { + background: none; + height: 4px; +} + +#inspector-end-resizer { + width: 12px; + height: 8px; + background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px); + background-size: 10px 2px; + background-clip: padding-box; + background-repeat: repeat-y; + border-width: 1px 1px 0; + border-style: solid; + border-color: rgba(255, 255, 255, 0.05); + margin: 7px 7px 8px; +} + /* Highlighter - Node Infobar */ /* Highlighter - Node Infobar - text */ @@ -2022,3 +2086,161 @@ panel[dimmed="true"] { #highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar { margin: 7px 0; } + +/* Highlighter toolbar - breadcrumbs */ + +#inspector-breadcrumbs { + padding: 0 6px; + /* A fake 1px-shadow is included in the border-images of the + inspector-breadcrumbs-buttons, to match toolbar-buttons style. + This negative margin compensate the extra row of pixels created + by the shadow.*/ + margin-bottom: -1px; +} + +.inspector-breadcrumbs-button { + -moz-appearance: none; + background-color: transparent; + border-width: 1px 13px 2px 13px; + color: hsl(210,30%,85%); + max-width: 85px; + /* The content of the button can be larger than the button */ + overflow: hidden; + min-height: 25px; + + margin: 0 -11px 0 0; + padding: 0 9px; +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-tag { + color: hsl(208,100%,60%); +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-id { + color: hsl(205,100%,70%); +} + +.inspector-breadcrumbs-id, +.inspector-breadcrumbs-classes { + color: #8d99a6; +} + +/* Highlighter toolbar - breadcrumbs - LTR */ + +.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type { + margin-left: 0; +} + +.inspector-breadcrumbs-button { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]), +.inspector-breadcrumbs-button:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open], +.inspector-breadcrumbs-button[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked], +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked], +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 stretch; +} + +/* Highlighter toolbar - breadcrumbs - RTL */ + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type { + margin-right: 0; +} + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 stretch; +} diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-pressed.png new file mode 100644 index 000000000000..1b0fcf98659e Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png new file mode 100644 index 000000000000..c7c2f39ab2c4 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected.png new file mode 100644 index 000000000000..c7c2f39ab2c4 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end.png new file mode 100644 index 000000000000..2a65f402ad84 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-end.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png new file mode 100644 index 000000000000..1d2611ddaf0b Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png new file mode 100644 index 000000000000..d2b7f8dae062 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected.png new file mode 100644 index 000000000000..2311685f8642 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle.png new file mode 100644 index 000000000000..a99e9fabe969 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-middle.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-pressed.png new file mode 100644 index 000000000000..30c2c29463bd Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png new file mode 100644 index 000000000000..a5bc6124e552 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected.png new file mode 100644 index 000000000000..a08fb902db8b Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start.png new file mode 100644 index 000000000000..b8a43b58cd7a Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/ltr-start.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-pressed.png new file mode 100644 index 000000000000..4c57d76f18b5 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png new file mode 100644 index 000000000000..cd2f0a5e837f Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected.png new file mode 100644 index 000000000000..cd2f0a5e837f Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end.png new file mode 100644 index 000000000000..ea9bc32556ae Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-end.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png new file mode 100644 index 000000000000..d6a8a4385689 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png new file mode 100644 index 000000000000..61bbcb13419b Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected.png new file mode 100644 index 000000000000..066c34528030 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle.png new file mode 100644 index 000000000000..cb87d62b24b9 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-middle.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-pressed.png new file mode 100644 index 000000000000..155f6380bf22 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png new file mode 100644 index 000000000000..dab1153284f5 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected.png new file mode 100644 index 000000000000..a520e8088c78 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start-selected.png differ diff --git a/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start.png b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start.png new file mode 100644 index 000000000000..86912e0668d7 Binary files /dev/null and b/browser/themes/gnomestripe/browser/devtools/breadcrumbs/rtl-start.png differ diff --git a/browser/themes/gnomestripe/browser/jar.mn b/browser/themes/gnomestripe/browser/jar.mn index a1a569f2452d..377c6bc9f64d 100644 --- a/browser/themes/gnomestripe/browser/jar.mn +++ b/browser/themes/gnomestripe/browser/jar.mn @@ -87,16 +87,43 @@ browser.jar: skin/classic/browser/devtools/search.png (devtools/search.png) skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css) skin/classic/browser/devtools/gcli.css (devtools/gcli.css) + skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end.png (devtools/breadcrumbs/ltr-end.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png (devtools/breadcrumbs/ltr-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png (devtools/breadcrumbs/ltr-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected.png (devtools/breadcrumbs/ltr-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle.png (devtools/breadcrumbs/ltr-middle.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-pressed.png (devtools/breadcrumbs/ltr-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png (devtools/breadcrumbs/ltr-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start.png (devtools/breadcrumbs/ltr-start.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected.png (devtools/breadcrumbs/ltr-start-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-pressed.png (devtools/breadcrumbs/rtl-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png (devtools/breadcrumbs/rtl-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected.png (devtools/breadcrumbs/rtl-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end.png (devtools/breadcrumbs/rtl-end.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-pressed.png (devtools/breadcrumbs/rtl-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png (devtools/breadcrumbs/rtl-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected.png (devtools/breadcrumbs/rtl-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle.png (devtools/breadcrumbs/rtl-middle.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-pressed.png (devtools/breadcrumbs/rtl-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png (devtools/breadcrumbs/rtl-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start.png (devtools/breadcrumbs/rtl-start.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png) + #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-16-throbber.png skin/classic/browser/sync-16.png skin/classic/browser/sync-24-throbber.png skin/classic/browser/sync-32.png skin/classic/browser/sync-bg.png + skin/classic/browser/sync-128.png skin/classic/browser/sync-desktopIcon.png skin/classic/browser/sync-mobileIcon.png skin/classic/browser/sync-notification-24.png skin/classic/browser/syncSetup.css skin/classic/browser/syncCommon.css skin/classic/browser/syncQuota.css + skin/classic/browser/syncProgress.css #endif diff --git a/browser/themes/gnomestripe/browser/sync-128.png b/browser/themes/gnomestripe/browser/sync-128.png new file mode 100644 index 000000000000..1ea34818ceb9 Binary files /dev/null and b/browser/themes/gnomestripe/browser/sync-128.png differ diff --git a/widget/src/android/nsToolkit.h b/browser/themes/gnomestripe/browser/syncProgress.css similarity index 72% rename from widget/src/android/nsToolkit.h rename to browser/themes/gnomestripe/browser/syncProgress.css index 15b9e5791ea3..fd4eed0733b6 100644 --- a/widget/src/android/nsToolkit.h +++ b/browser/themes/gnomestripe/browser/syncProgress.css @@ -1,4 +1,3 @@ -/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -12,15 +11,15 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is mozilla.org code. + * The Original Code is Firefox Sync. * * The Initial Developer of the Original Code is - * Mozilla Foundation - * Portions created by the Initial Developer are Copyright (C) 2009-2010 + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Vladimir Vukicevic + * Allison Naaktgeboren * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,23 +34,46 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ +@import url(chrome://global/skin/inContentUI.css); -#ifndef nsToolkit_h__ -#define nsToolkit_h__ +:root { + height: 100%; + width: 100%; + padding: 0; +} -#include +body { + margin: 0; + padding: 0 2em; +} -class nsToolkit : - public nsIToolkit -{ -public: - NS_DECL_ISUPPORTS +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} - // nsIToolkit - NS_IMETHOD Init(PRThread *aThread); +#successLogo { + margin: 1em 2em; +} - nsToolkit(); - virtual ~nsToolkit(); -}; +#loadingText { + margin: 2em 6em; +} -#endif /* nsToolkit_h__ */ +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css index 249060b9b9bb..d0e284cc3b23 100644 --- a/browser/themes/pinstripe/browser/browser.css +++ b/browser/themes/pinstripe/browser/browser.css @@ -1563,7 +1563,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { height: 26px; } -.tab-drag-label, .tabbrowser-tab, .tabs-newtab-button { -moz-appearance: none; @@ -1842,19 +1841,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { * Tab Drag and Drop */ -.tab-drag-label { - background: -moz-linear-gradient(#eee, #ccc); - padding: 4px 8px; - border-radius: 4px; - box-shadow: inset 0 1px 0 rgba(255,255,255,.6); -} - -.tab-drag-panel:not([target]) > .tab-drag-label { - background: -moz-linear-gradient(#ddd, #bbb); - border-bottom: 1px solid #999; - border-radius: 3px 3px 0 0; -} - .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); margin-bottom: -8px; @@ -2563,8 +2549,7 @@ panel[dimmed="true"] { #inspector-toolbar { -moz-appearance: none; - height: 32px; - padding: 0 3px; + padding: 0 3px 4px; border-top: 1px solid hsla(210, 8%, 5%, .65); box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset; background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%)); @@ -2573,17 +2558,21 @@ panel[dimmed="true"] { #inspector-inspect-toolbutton, #inspector-tools > toolbarbutton { -moz-appearance: none; - width: 78px; - margin: 3px 5px; + min-width: 78px; + min-height: 22px; color: hsl(210,30%,85%); text-shadow: 0 -1px 0 hsla(210,8%,5%,.45); border: 1px solid hsla(210,8%,5%,.45); border-radius: @toolbarbuttonCornerRadius@; - background: -moz-linear-gradient(hsla(212,7%,57%,.35), hsla(212,7%,57%,.1)); - background-clip: padding-box; + background: -moz-linear-gradient(hsla(212,7%,57%,.35), hsla(212,7%,57%,.1)) padding-box; box-shadow: 0 1px 0 hsla(210,16%,76%,.15) inset, 0 0 0 1px hsla(210,16%,76%,.15) inset, 0 1px 0 hsla(210,16%,76%,.15); } +#inspector-inspect-toolbutton > .toolbarbutton-text , +#inspector-tools > toolbarbutton > .toolbarbutton-text { + margin: 1px 6px; +} + #inspector-inspect-toolbutton:not([checked]):hover:active, #inspector-tools > toolbarbutton:not([checked]):hover:active { border-color: hsla(210,8%,5%,.6); @@ -2604,15 +2593,35 @@ panel[dimmed="true"] { background-color: hsla(210,8%,5%,.2); } -/* - * need a "bumpy" background image for this! - */ -#inspector-horizontal-splitter { - background: none !important; +/* Highlighter - toolbar resizers */ + +.inspector-resizer { -moz-appearance: none; cursor: n-resize; } +.inspector-resizer[disabled] { + visibility: hidden; +} + +#inspector-top-resizer { + background: none; + height: 4px; +} + +#inspector-end-resizer { + width: 12px; + height: 8px; + background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px); + background-size: 10px 2px; + background-clip: padding-box; + background-repeat: repeat-y; + border-width: 1px 1px 0; + border-style: solid; + border-color: rgba(255, 255, 255, 0.05); + margin: 7px 7px 8px; +} + /* Highlighter - Node Infobar */ /* Highlighter - Node Infobar - text */ @@ -2672,3 +2681,160 @@ panel[dimmed="true"] { #highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar { margin: 7px 0; } + +/* Highlighter toolbar - breadcrumbs */ + +#inspector-breadcrumbs { + padding: 0 6px; + /* A fake 1px-shadow is included in the border-images of the + inspector-breadcrumbs-buttons, to match toolbar-buttons style. + This negative margin compensate the extra row of pixels created + by the shadow.*/ + margin-bottom: -1px; +} + +.inspector-breadcrumbs-button { + -moz-appearance: none; + border-width: 1px 13px 2px 13px; + color: hsl(210,30%,85%); + max-width: 85px; + /* The content of the button can be larger than the button */ + overflow: hidden; + min-height: 25px; + + margin: 0 -11px 0 0; + padding: 0 9px; +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-tag { + color: hsl(208,100%,60%); +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-id { + color: hsl(205,100%,70%); +} + +.inspector-breadcrumbs-id, +.inspector-breadcrumbs-classes { + color: #8d99a6; +} + +/* Highlighter toolbar - breadcrumbs - LTR */ + +.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type { + margin-left: 0; +} + +.inspector-breadcrumbs-button { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]), +.inspector-breadcrumbs-button:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open], +.inspector-breadcrumbs-button[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked], +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked], +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 stretch; +} + +/* Highlighter toolbar - breadcrumbs - RTL */ + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type { + margin-right: 0; +} + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 stretch; +} diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png new file mode 100644 index 000000000000..1b0fcf98659e Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png new file mode 100644 index 000000000000..c7c2f39ab2c4 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected.png new file mode 100644 index 000000000000..c7c2f39ab2c4 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end.png new file mode 100644 index 000000000000..2a65f402ad84 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-end.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png new file mode 100644 index 000000000000..1d2611ddaf0b Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png new file mode 100644 index 000000000000..d2b7f8dae062 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png new file mode 100644 index 000000000000..2311685f8642 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle.png new file mode 100644 index 000000000000..a99e9fabe969 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-middle.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png new file mode 100644 index 000000000000..30c2c29463bd Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png new file mode 100644 index 000000000000..a5bc6124e552 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected.png new file mode 100644 index 000000000000..a08fb902db8b Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start.png new file mode 100644 index 000000000000..b8a43b58cd7a Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/ltr-start.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png new file mode 100644 index 000000000000..4c57d76f18b5 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png new file mode 100644 index 000000000000..cd2f0a5e837f Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected.png new file mode 100644 index 000000000000..cd2f0a5e837f Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end.png new file mode 100644 index 000000000000..ea9bc32556ae Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-end.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png new file mode 100644 index 000000000000..d6a8a4385689 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png new file mode 100644 index 000000000000..61bbcb13419b Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png new file mode 100644 index 000000000000..066c34528030 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle.png new file mode 100644 index 000000000000..cb87d62b24b9 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-middle.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png new file mode 100644 index 000000000000..155f6380bf22 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png new file mode 100644 index 000000000000..dab1153284f5 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected.png new file mode 100644 index 000000000000..a520e8088c78 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start-selected.png differ diff --git a/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start.png b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start.png new file mode 100644 index 000000000000..86912e0668d7 Binary files /dev/null and b/browser/themes/pinstripe/browser/devtools/breadcrumbs/rtl-start.png differ diff --git a/browser/themes/pinstripe/browser/jar.mn b/browser/themes/pinstripe/browser/jar.mn index 2f93c25c5fa5..7854b5ebb55c 100644 --- a/browser/themes/pinstripe/browser/jar.mn +++ b/browser/themes/pinstripe/browser/jar.mn @@ -126,17 +126,44 @@ browser.jar: skin/classic/browser/devtools/search.png (devtools/search.png) skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css) skin/classic/browser/devtools/gcli.css (devtools/gcli.css) + skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end.png (devtools/breadcrumbs/ltr-end.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png (devtools/breadcrumbs/ltr-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png (devtools/breadcrumbs/ltr-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected.png (devtools/breadcrumbs/ltr-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle.png (devtools/breadcrumbs/ltr-middle.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-pressed.png (devtools/breadcrumbs/ltr-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png (devtools/breadcrumbs/ltr-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start.png (devtools/breadcrumbs/ltr-start.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected.png (devtools/breadcrumbs/ltr-start-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-pressed.png (devtools/breadcrumbs/rtl-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png (devtools/breadcrumbs/rtl-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected.png (devtools/breadcrumbs/rtl-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end.png (devtools/breadcrumbs/rtl-end.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-pressed.png (devtools/breadcrumbs/rtl-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png (devtools/breadcrumbs/rtl-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected.png (devtools/breadcrumbs/rtl-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle.png (devtools/breadcrumbs/rtl-middle.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-pressed.png (devtools/breadcrumbs/rtl-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png (devtools/breadcrumbs/rtl-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start.png (devtools/breadcrumbs/rtl-start.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png) + #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-throbber.png skin/classic/browser/sync-16.png skin/classic/browser/sync-32.png skin/classic/browser/sync-bg.png + skin/classic/browser/sync-128.png skin/classic/browser/sync-desktopIcon.png skin/classic/browser/sync-mobileIcon.png skin/classic/browser/sync-notification-24.png skin/classic/browser/syncSetup.css skin/classic/browser/syncCommon.css skin/classic/browser/syncQuota.css + skin/classic/browser/syncProgress.css #endif skin/classic/browser/lion/keyhole-circle.png (keyhole-circle-lion.png) skin/classic/browser/lion/Toolbar.png (Toolbar-lion.png) diff --git a/browser/themes/pinstripe/browser/sync-128.png b/browser/themes/pinstripe/browser/sync-128.png new file mode 100644 index 000000000000..1ea34818ceb9 Binary files /dev/null and b/browser/themes/pinstripe/browser/sync-128.png differ diff --git a/security/nss/lib/ssl/sslerrstrs.h b/browser/themes/pinstripe/browser/syncProgress.css similarity index 68% rename from security/nss/lib/ssl/sslerrstrs.h rename to browser/themes/pinstripe/browser/syncProgress.css index 69dbd8230e3e..fd4eed0733b6 100644 --- a/security/nss/lib/ssl/sslerrstrs.h +++ b/browser/themes/pinstripe/browser/syncProgress.css @@ -1,7 +1,4 @@ -/* - * This file contains prototypes for the public SSL functions. - * - * ***** BEGIN LICENSE BLOCK ***** +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -14,14 +11,15 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is the Netscape security libraries. + * The Original Code is Firefox Sync. * * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Allison Naaktgeboren * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,18 +34,46 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslerrstrs.h,v 1.1 2011/08/17 14:41:02 emaldona%redhat.com Exp $ */ +@import url(chrome://global/skin/inContentUI.css); -#ifndef __sslerrstrs_h_ -#define __sslerrstrs_h_ +:root { + height: 100%; + width: 100%; + padding: 0; +} -#include "prtypes.h" +body { + margin: 0; + padding: 0 2em; +} -SEC_BEGIN_PROTOS +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} -extern PRStatus -ssl_InitializePRErrorTable(void); +#successLogo { + margin: 1em 2em; +} -SEC_END_PROTOS +#loadingText { + margin: 2em 6em; +} -#endif /* __sslerrstrs_h_ */ +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/browser/themes/winstripe/browser/browser-aero.css b/browser/themes/winstripe/browser/browser-aero.css index c0a54d01dfe9..6b3d6f0cf185 100644 --- a/browser/themes/winstripe/browser/browser-aero.css +++ b/browser/themes/winstripe/browser/browser-aero.css @@ -11,7 +11,6 @@ margin-top: 1px; } - .tab-drag-preview::before, #appmenu-button { border-width: 2px; -moz-border-left-colors: @appMenuButtonBorderColor@; @@ -22,7 +21,6 @@ 0 0 2px 1px rgba(255,255,255,.25) inset; } - #main-window[privatebrowsingmode=temporary] .tab-drag-preview::before, #main-window[privatebrowsingmode=temporary] #appmenu-button { -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9); -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9); @@ -57,7 +55,6 @@ -moz-linear-gradient(@customToolbarColor@, @customToolbarColor@); } - .tab-drag-label, .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) { background-image: -moz-linear-gradient(white, @toolbarHighlight@ 50%), -moz-linear-gradient(@customToolbarColor@, @customToolbarColor@); @@ -289,31 +286,6 @@ -moz-linear-gradient(rgba(255,255,255,0), #CCD9EA 200px, #C7D5E7); background-attachment: fixed; } - - .tab-drag-panel { - -moz-appearance: -moz-win-borderless-glass; - } - .tab-drag-label { - padding: 4px; - background-color: -moz-dialog; - border-radius: 3px; - } - .tab-drag-preview { - margin: 15px 7px 7px; - } - .tab-drag-panel:not([target]) > .tab-drag-preview { - display: block; - } - .tab-drag-preview::before { /* miniature appmenu button */ - content: ""; - display: block; - margin-top: -15px; - -moz-margin-start: -2px; - padding: 0; - width: 32px; - height: 7px; - border-radius: 0 0 3px 3px; - } } @media not all and (-moz-windows-compositor) { diff --git a/browser/themes/winstripe/browser/browser.css b/browser/themes/winstripe/browser/browser.css index 45793a72fe6e..2843d92e46c9 100644 --- a/browser/themes/winstripe/browser/browser.css +++ b/browser/themes/winstripe/browser/browser.css @@ -184,7 +184,6 @@ } %ifdef MOZ_OFFICIAL_BRANDING -.tab-drag-preview::before, #appmenu-button { background-image: -moz-linear-gradient(rgb(247,182,82), rgb(215,98,10) 95%); border-color: rgba(83,42,6,.9); @@ -208,7 +207,6 @@ } %else %if MOZ_UPDATE_CHANNEL == aurora -.tab-drag-preview::before, #appmenu-button { background-image: -moz-linear-gradient(hsl(208,99%,37%), hsl(214,90%,23%) 95%); border-color: hsla(214,89%,21%,.9); @@ -231,7 +229,6 @@ 0 1px 1px rgba(0,0,0,.2) inset; } %else -.tab-drag-preview::before, #appmenu-button { background-image: -moz-linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%); border-color: hsla(210,59%,13%,.9); @@ -256,7 +253,6 @@ %endif %endif -#main-window[privatebrowsingmode=temporary] .tab-drag-preview::before, #main-window[privatebrowsingmode=temporary] #appmenu-button { background-image: -moz-linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%); border-color: rgba(43,8,65,.9); @@ -1926,25 +1922,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- outline: 1px dotted; } -/* Tab drag and drop */ -.tab-drag-panel { - border: 0 !important; -} - -.tab-drag-label { - margin: 0 !important; - padding: 5px; - border: 1px solid DimGray; -} - -.tab-drag-panel:not([target]) > .tab-drag-label { - display: none; -} - -.tab-drag-preview { - border: 1px solid rgba(0,0,0,.5); -} - +/* Tab DnD indicator */ .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); margin-bottom: -11px; @@ -2665,15 +2643,83 @@ panel[dimmed="true"] { outline-color: white; } -/* - * need a "bumpy" background image for this! - */ -#inspector-horizontal-splitter { - background: none !important; +/* Highlighter toolbar */ + +#inspector-toolbar { + -moz-appearance: none; + padding: 0 3px 4px; + border-top: 1px solid hsla(211,68%,6%,.65) !important; + box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset; + background-image: -moz-linear-gradient(top, hsl(209,18%,34%), hsl(210,24%,16%)); +} + +#inspector-inspect-toolbutton, +#inspector-tools > toolbarbutton { + -moz-appearance: none; + min-width: 78px; + min-height: 22px; + color: hsl(210,30%,85%); + text-shadow: 0 -1px 0 hsla(210,8%,5%,.45); + border: 1px solid hsla(211,68%,6%,.5); + border-radius: 3px; + background: -moz-linear-gradient(hsla(209,13%,54%,.35), hsla(209,13%,54%,.1) 85%, hsla(209,13%,54%,.2)) padding-box; + box-shadow: 0 1px 0 hsla(209,29%,72%,.15) inset, 0 0 0 1px hsla(209,29%,72%,.1) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1); +} + +#inspector-inspect-toolbutton > .toolbarbutton-icon, +#inspector-tools > toolbarbutton > .toolbarbutton-icon { + margin: 0; +} + +#inspector-inspect-toolbutton:not([checked]):hover:active, +#inspector-tools > toolbarbutton:not([checked]):hover:active { + background-color: hsla(210,18%,9%,.1); + background-image: -moz-linear-gradient(hsla(209,13%,54%,.35), hsla(209,13%,54%,.1) 85%, hsla(209,13%,54%,.2)); + box-shadow: 0 1px 3px hsla(211,68%,6%,.5) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1); +} + +#inspector-inspect-toolbutton[checked], +#inspector-tools > toolbarbutton[checked] { + border-color: hsla(211,68%,6%,.6); + background: -moz-linear-gradient(hsla(211,68%,6%,.1), hsla(211,68%,6%,.2)); + box-shadow: 0 1px 3px hsla(211,68%,6%,.5) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1); + color: hsl(200,100%,60%) !important; +} + +#inspector-inspect-toolbutton[checked]:hover:active, +#inspector-tools > toolbarbutton[checked]:hover:active { + background-color: hsla(211,68%,6%,.2); +} + +/* Highlighter - toolbar resizers */ + +.inspector-resizer { -moz-appearance: none; cursor: n-resize; } +.inspector-resizer[disabled] { + visibility: hidden; +} + +#inspector-top-resizer { + background: none; + height: 4px; +} + +#inspector-end-resizer { + width: 12px; + height: 8px; + background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px); + background-size: 10px 2px; + background-clip: padding-box; + background-repeat: repeat-y; + border-width: 1px 1px 0; + border-style: solid; + border-color: rgba(255, 255, 255, 0.05); + margin: 7px 7px 8px; +} + /* Highlighter - Node Infobar */ /* Highlighter - Node Infobar - text */ @@ -2733,3 +2779,162 @@ panel[dimmed="true"] { #highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar { margin: 7px 0; } + +/* Highlighter toolbar - breadcrumbs */ + +#inspector-breadcrumbs { + padding: 0 6px; + /* A fake 1px-shadow is included in the border-images of the + inspector-breadcrumbs-buttons, to match toolbar-buttons style. + This negative margin compensate the extra row of pixels created + by the shadow.*/ + margin: -1px 0; +} + +.inspector-breadcrumbs-button { + -moz-appearance: none; + background-color: transparent; + border-width: 2px 13px; + outline: none; + color: hsl(210,30%,85%); + max-width: 85px; + /* The content of the button can be larger than the button */ + overflow: hidden; + min-height: 25px; + + margin: 0 -11px 0 0; + padding: 0 9px; +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-tag { + color: hsl(200,100%,60%); +} + +.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-id { + color: hsl(200,100%,70%); +} + +.inspector-breadcrumbs-id, +.inspector-breadcrumbs-classes { + color: #8d99a6; +} + +/* Highlighter toolbar - breadcrumbs - LTR */ + +.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type { + margin-left: 0; +} + +.inspector-breadcrumbs-button { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]), +.inspector-breadcrumbs-button:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open], +.inspector-breadcrumbs-button[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked], +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked] { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked], +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 2 13 2 13 stretch; +} + +/* Highlighter toolbar - breadcrumbs - RTL */ + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type { + margin-right: 0; +} + +.inspector-breadcrumbs-button:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 2 13 2 13 stretch; +} + +.inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl), +.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) { + -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 2 13 2 13 stretch; +} diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png new file mode 100644 index 000000000000..80c1f3a26da4 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png new file mode 100644 index 000000000000..87808778c6e4 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected.png new file mode 100644 index 000000000000..dbb728411333 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end.png new file mode 100644 index 000000000000..ee96024f1a81 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-end.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png new file mode 100644 index 000000000000..57abb3ffbe78 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png new file mode 100644 index 000000000000..3898ba3ac10b Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png new file mode 100644 index 000000000000..c0d13e3efd4f Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle.png new file mode 100644 index 000000000000..eb65fffd55e0 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-middle.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png new file mode 100644 index 000000000000..c1a946525817 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png new file mode 100644 index 000000000000..77d63d1b1196 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected.png new file mode 100644 index 000000000000..6529b71abd92 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start.png new file mode 100644 index 000000000000..a4ca858603ef Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/ltr-start.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png new file mode 100644 index 000000000000..1077cfb7b7d6 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png new file mode 100644 index 000000000000..ab1040ba8cde Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected.png new file mode 100644 index 000000000000..8b0905d0f094 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end.png new file mode 100644 index 000000000000..88cc61b0bcf0 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-end.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png new file mode 100644 index 000000000000..f4a3a5beef55 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png new file mode 100644 index 000000000000..d66acb42eb2e Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png new file mode 100644 index 000000000000..9b77579e94d3 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle.png new file mode 100644 index 000000000000..63b620154179 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-middle.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png new file mode 100644 index 000000000000..bfff8e95d8f1 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png new file mode 100644 index 000000000000..2ce094819032 Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected.png new file mode 100644 index 000000000000..e7c848ac3cbc Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start-selected.png differ diff --git a/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start.png b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start.png new file mode 100644 index 000000000000..b8f67974c6ba Binary files /dev/null and b/browser/themes/winstripe/browser/devtools/breadcrumbs/rtl-start.png differ diff --git a/browser/themes/winstripe/browser/jar.mn b/browser/themes/winstripe/browser/jar.mn index 9d0a50884717..1d77ac079413 100644 --- a/browser/themes/winstripe/browser/jar.mn +++ b/browser/themes/winstripe/browser/jar.mn @@ -110,10 +110,36 @@ browser.jar: skin/classic/browser/devtools/search.png (devtools/search.png) skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css) skin/classic/browser/devtools/gcli.css (devtools/gcli.css) + skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-end.png (devtools/breadcrumbs/ltr-end.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png (devtools/breadcrumbs/ltr-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png (devtools/breadcrumbs/ltr-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected.png (devtools/breadcrumbs/ltr-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/ltr-middle.png (devtools/breadcrumbs/ltr-middle.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-pressed.png (devtools/breadcrumbs/ltr-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png (devtools/breadcrumbs/ltr-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start.png (devtools/breadcrumbs/ltr-start.png) + skin/classic/browser/devtools/breadcrumbs/ltr-start-selected.png (devtools/breadcrumbs/ltr-start-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-pressed.png (devtools/breadcrumbs/rtl-end-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png (devtools/breadcrumbs/rtl-end-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end-selected.png (devtools/breadcrumbs/rtl-end-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-end.png (devtools/breadcrumbs/rtl-end.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-pressed.png (devtools/breadcrumbs/rtl-middle-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png (devtools/breadcrumbs/rtl-middle-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle-selected.png (devtools/breadcrumbs/rtl-middle-selected.png) + skin/classic/browser/devtools/breadcrumbs/rtl-middle.png (devtools/breadcrumbs/rtl-middle.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-pressed.png (devtools/breadcrumbs/rtl-start-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png (devtools/breadcrumbs/rtl-start-selected-pressed.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start.png (devtools/breadcrumbs/rtl-start.png) + skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png) + #ifdef MOZ_SERVICES_SYNC skin/classic/browser/sync-throbber.png skin/classic/browser/sync-16.png skin/classic/browser/sync-32.png + skin/classic/browser/sync-128.png skin/classic/browser/sync-bg.png skin/classic/browser/sync-desktopIcon.png skin/classic/browser/sync-mobileIcon.png @@ -121,6 +147,7 @@ browser.jar: skin/classic/browser/syncSetup.css skin/classic/browser/syncCommon.css skin/classic/browser/syncQuota.css + skin/classic/browser/syncProgress.css #endif #ifdef XP_WIN @@ -234,10 +261,36 @@ browser.jar: skin/classic/aero/browser/devtools/search.png (devtools/search.png) skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css) skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-end.png (devtools/breadcrumbs/ltr-end.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-pressed.png (devtools/breadcrumbs/ltr-middle-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png (devtools/breadcrumbs/ltr-middle-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-selected.png (devtools/breadcrumbs/ltr-middle-selected.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle.png (devtools/breadcrumbs/ltr-middle.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-start-pressed.png (devtools/breadcrumbs/ltr-start-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-start-selected-pressed.png (devtools/breadcrumbs/ltr-start-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-start.png (devtools/breadcrumbs/ltr-start.png) + skin/classic/aero/browser/devtools/breadcrumbs/ltr-start-selected.png (devtools/breadcrumbs/ltr-start-selected.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-end-pressed.png (devtools/breadcrumbs/rtl-end-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-end-selected-pressed.png (devtools/breadcrumbs/rtl-end-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-end-selected.png (devtools/breadcrumbs/rtl-end-selected.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-end.png (devtools/breadcrumbs/rtl-end.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-middle-pressed.png (devtools/breadcrumbs/rtl-middle-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-middle-selected-pressed.png (devtools/breadcrumbs/rtl-middle-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-middle-selected.png (devtools/breadcrumbs/rtl-middle-selected.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-middle.png (devtools/breadcrumbs/rtl-middle.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-pressed.png (devtools/breadcrumbs/rtl-start-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png (devtools/breadcrumbs/rtl-start-selected-pressed.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-start.png (devtools/breadcrumbs/rtl-start.png) + skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png) + #ifdef MOZ_SERVICES_SYNC skin/classic/aero/browser/sync-throbber.png skin/classic/aero/browser/sync-16.png skin/classic/aero/browser/sync-32.png + skin/classic/aero/browser/sync-128.png skin/classic/aero/browser/sync-bg.png skin/classic/aero/browser/sync-desktopIcon.png skin/classic/aero/browser/sync-mobileIcon.png @@ -245,5 +298,6 @@ browser.jar: skin/classic/aero/browser/syncSetup.css skin/classic/aero/browser/syncCommon.css skin/classic/aero/browser/syncQuota.css + skin/classic/aero/browser/syncProgress.css #endif #endif diff --git a/browser/themes/winstripe/browser/places/organizer-aero.css b/browser/themes/winstripe/browser/places/organizer-aero.css index 34ff3b974352..0070f9094ce5 100644 --- a/browser/themes/winstripe/browser/places/organizer-aero.css +++ b/browser/themes/winstripe/browser/places/organizer-aero.css @@ -2,7 +2,6 @@ %filter substitution %define toolbarHighlight rgba(255,255,255,.5) -%define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32); %define customToolbarColor hsl(214,44%,87%) #placesView { @@ -71,21 +70,10 @@ #searchFilter { -moz-appearance: none; - background-color: rgba(255,255,255,.725); - color: black; padding: 2px; -moz-padding-start: 4px; background-clip: padding-box; - border: 1px solid ThreeDDarkShadow; + border: 1px solid rgba(0,0,0,.32); border-radius: 2.5px; - @navbarTextboxCustomBorder@ - } - - #searchFilter:hover { - background-color: rgba(255,255,255,.898); - } - - #searchFilter[focused] { - background-color: white; } } diff --git a/browser/themes/winstripe/browser/sync-128.png b/browser/themes/winstripe/browser/sync-128.png new file mode 100644 index 000000000000..1ea34818ceb9 Binary files /dev/null and b/browser/themes/winstripe/browser/sync-128.png differ diff --git a/security/nss/lib/ssl/sslutil.h b/browser/themes/winstripe/browser/syncProgress.css similarity index 68% rename from security/nss/lib/ssl/sslutil.h rename to browser/themes/winstripe/browser/syncProgress.css index 26603280881a..fd4eed0733b6 100644 --- a/security/nss/lib/ssl/sslutil.h +++ b/browser/themes/winstripe/browser/syncProgress.css @@ -1,7 +1,4 @@ -/* - * This file contains prototypes for the public SSL functions. - * - * ***** BEGIN LICENSE BLOCK ***** +/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -14,14 +11,15 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is the Netscape security libraries. + * The Original Code is Firefox Sync. * * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Allison Naaktgeboren * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,18 +34,46 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslutil.h,v 1.1 2011/08/17 14:41:20 emaldona%redhat.com Exp $ */ +@import url(chrome://global/skin/inContentUI.css); -#ifndef __sslutil_h_ -#define __sslutil_h_ +:root { + height: 100%; + width: 100%; + padding: 0; +} -#include "prtypes.h" +body { + margin: 0; + padding: 0 2em; +} -SEC_BEGIN_PROTOS +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} -extern PRStatus SSL_InitializePRErrorTable(void); -extern SECStatus ssl_Init(void); +#successLogo { + margin: 1em 2em; +} -SEC_END_PROTOS +#loadingText { + margin: 2em 6em; +} -#endif /* __sslutil_h_ */ +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/build/automation.py.in b/build/automation.py.in index ae4a7574abcf..c8e4dab77b56 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -418,10 +418,6 @@ user_pref("javascript.options.showInConsole", true); user_pref("devtools.errorconsole.enabled", true); user_pref("layout.debug.enable_data_xbl", true); user_pref("browser.EULA.override", true); -user_pref("javascript.options.tracejit.content", true); -user_pref("javascript.options.methodjit.content", true); -user_pref("javascript.options.jitprofiling.content", true); -user_pref("javascript.options.methodjit_always", false); user_pref("gfx.color_management.force_srgb", true); user_pref("network.manage-offline-status", false); user_pref("test.mousescroll", true); @@ -1025,9 +1021,9 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t installRDFFilename = "install.rdf" - extensionsRootDir = os.path.join(profileDir, "extensions") + extensionsRootDir = os.path.join(profileDir, "extensions", "staged") if not os.path.isdir(extensionsRootDir): - os.mkdir(extensionsRootDir) + os.makedirs(extensionsRootDir) if os.path.isfile(extensionSource): reader = ZipFileReader(extensionSource) diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index ad98f4852c37..600bf6fcac54 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -312,7 +312,6 @@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ -MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@ PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ diff --git a/config/rules.mk b/config/rules.mk index e9d9414aa49f..bdeb86d599ca 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -362,9 +362,6 @@ endif endif # !GNU_CC -ifdef ENABLE_CXX_EXCEPTIONS -CXXFLAGS += $(MOZ_EXCEPTIONS_FLAGS_ON) -DMOZ_CPP_EXCEPTIONS=1 -endif # ENABLE_CXX_EXCEPTIONS endif # WINNT ifeq ($(SOLARIS_SUNPRO_CXX),1) diff --git a/configure.in b/configure.in index 556407aefc61..f50e1b0feb9a 100644 --- a/configure.in +++ b/configure.in @@ -755,8 +755,6 @@ case "$target" in _MOZ_RTTI_FLAGS_ON='-GR' _MOZ_RTTI_FLAGS_OFF='-GR-' - _MOZ_EXCEPTIONS_FLAGS_ON='-EHsc' - _MOZ_EXCEPTIONS_FLAGS_OFF='' AC_DEFINE(HAVE_SEH_EXCEPTIONS) if test -n "$WIN32_REDIST_DIR"; then @@ -1545,8 +1543,6 @@ if test "$GNU_CC"; then ASFLAGS="$ASFLAGS -fPIC" _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti - _MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions' - _MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions' # Turn on GNU specific features # -Wall - turn on all warnings @@ -1604,7 +1600,7 @@ fi if test "$GNU_CXX"; then # FIXME: Let us build with strict aliasing. bug 414641. - CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" + CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing" # Turn on GNU specific features _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor" if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then @@ -2490,9 +2486,7 @@ ia64*-hpux*) LIBS="-lCrun -lCstd -lc $LIBS" AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" - CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" - _MOZ_EXCEPTIONS_FLAGS_ON='-features=except' - _MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except' + CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions,no%except -norunpath -D__FUNCTION__=__func__ -template=no%extdef" LDFLAGS="-xildoff $LDFLAGS" if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then _SAVE_LDFLAGS=$LDFLAGS @@ -7747,24 +7741,6 @@ if test "$ac_nscap_nonconst_opeq_bug" = "yes" ; then fi fi # ! SKIP_COMPILER_CHECKS -dnl ======================================================== -dnl C++ exceptions (g++/VC/Sun only - for now) -dnl Should be smarter and check that the compiler does indeed have exceptions -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(cpp-exceptions, -[ --enable-cpp-exceptions Enable C++ exceptions ], -[ _MOZ_CPP_EXCEPTIONS=1 ], -[ _MOZ_CPP_EXCEPTIONS= ]) - -if test "$_MOZ_CPP_EXCEPTIONS"; then - _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON - AC_DEFINE(MOZ_CPP_EXCEPTIONS) -else - _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF -fi - -AC_SUBST(_MOZ_EXCEPTIONS_FLAGS_ON) - AC_DEFINE(CPP_THROW_NEW, [throw()]) AC_LANG_C @@ -8421,7 +8397,6 @@ CFLAGS=`echo \ CXXFLAGS=`echo \ $_MOZ_RTTI_FLAGS \ - $_MOZ_EXCEPTIONS_FLAGS \ $_WARNINGS_CXXFLAGS \ $CXXFLAGS` diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 0863bece35f0..b886f619aa0c 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1716,6 +1716,22 @@ public: */ static bool IsFullScreenKeyInputRestricted(); + /** + * Returns true if the doctree rooted at aDoc contains any plugins which + * we don't control event dispatch for, i.e. do any plugins in this doc tree + * receive key events outside of our control? This always returns false + * on MacOSX. + */ + static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc); + + /** + * Returns true if the content is in a document and contains a plugin + * which we don't control event dispatch for, i.e. do any plugins in this + * doc tree receive key events outside of our control? This always returns + * false on MacOSX. + */ + static bool HasPluginWithUncontrolledEventDispatch(nsIContent* aContent); + /** * Returns the time limit on handling user input before * nsEventStateManager::IsHandlingUserInput() stops returning true. diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 38d5bc0e3ea3..f20d48390b38 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -69,6 +69,7 @@ #include "nsIAnimationFrameListener.h" #include "nsEventStates.h" #include "nsIStructuredCloneContainer.h" +#include "nsIBFCacheEntry.h" #include "nsDOMMemoryReporter.h" class nsIContent; @@ -125,8 +126,8 @@ class Element; } // namespace mozilla #define NS_IDOCUMENT_IID \ -{ 0x4114a7c7, 0xb2f4, 0x4dea, \ - { 0xac, 0x78, 0x20, 0xab, 0xda, 0x6f, 0xb2, 0xaf } } +{ 0x448c396a, 0x013c, 0x47b8, \ + { 0x95, 0xf4, 0x56, 0x68, 0x0f, 0x5f, 0x12, 0xf8 } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -479,11 +480,15 @@ public: return GetBFCacheEntry() ? nsnull : mPresShell; } - void SetBFCacheEntry(nsISHEntry* aSHEntry) { - mSHEntry = aSHEntry; + void SetBFCacheEntry(nsIBFCacheEntry* aEntry) + { + mBFCacheEntry = aEntry; } - nsISHEntry* GetBFCacheEntry() const { return mSHEntry; } + nsIBFCacheEntry* GetBFCacheEntry() const + { + return mBFCacheEntry; + } /** * Return the parent document of this document. Will return null @@ -1786,9 +1791,9 @@ protected: AnimationListenerList mAnimationFrameListeners; - // The session history entry in which we're currently bf-cached. Non-null - // if and only if we're currently in the bfcache. - nsISHEntry* mSHEntry; + // This object allows us to evict ourself from the back/forward cache. The + // pointer is non-null iff we're currently in the bfcache. + nsIBFCacheEntry *mBFCacheEntry; // Our base target. nsString mBaseTarget; diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 57af2cadedf2..5ab72c827b0c 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -203,8 +203,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsDOMTouchEvent.h" #include "nsIScriptElement.h" #include "nsIContentViewer.h" - -#include "prdtoa.h" +#include "nsIObjectLoadingContent.h" #include "mozilla/Preferences.h" @@ -5815,6 +5814,70 @@ nsContentUtils::IsFullScreenKeyInputRestricted() return sFullScreenKeyInputRestricted; } +static void +CheckForWindowedPlugins(nsIContent* aContent, void* aResult) +{ + if (!aContent->IsInDoc()) { + return; + } + nsCOMPtr olc(do_QueryInterface(aContent)); + if (!olc) { + return; + } + nsRefPtr plugin; + olc->GetPluginInstance(getter_AddRefs(plugin)); + if (!plugin) { + return; + } + bool isWindowless = false; + nsresult res = plugin->IsWindowless(&isWindowless); + if (NS_SUCCEEDED(res) && !isWindowless) { + *static_cast(aResult) = true; + } +} + +static bool +DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult) +{ + if (!nsContentUtils::IsChromeDoc(aDoc)) { + aDoc->EnumerateFreezableElements(CheckForWindowedPlugins, aResult); + } + if (*static_cast(aResult)) { + // Return false to stop iteration, we found a windowed plugin. + return false; + } + aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult); + // Return false to stop iteration if we found a windowed plugin in + // the sub documents. + return !*static_cast(aResult); +} + +/* static */ +bool +nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc) +{ +#ifdef XP_MACOSX + // We control dispatch to all mac plugins. + return false; +#endif + bool result = false; + DocTreeContainsWindowedPlugins(aDoc, &result); + return result; +} + +/* static */ +bool +nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) +{ +#ifdef XP_MACOSX + // We control dispatch to all mac plugins. + return false; +#endif + bool result = false; + CheckForWindowedPlugins(aContent, &result); + return result; +} + // static void nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder, diff --git a/content/base/src/nsDOMBlobBuilder.cpp b/content/base/src/nsDOMBlobBuilder.cpp index b2c4c4d0a879..c0b99c59de52 100644 --- a/content/base/src/nsDOMBlobBuilder.cpp +++ b/content/base/src/nsDOMBlobBuilder.cpp @@ -372,7 +372,10 @@ nsDOMBlobBuilder::Append(const jsval& aData, JSContext* aCx) // Is it an object? if (JSVAL_IS_OBJECT(aData)) { JSObject* obj = JSVAL_TO_OBJECT(aData); - NS_ASSERTION(obj, "Er, what?"); + if (!obj) { + // We got passed null. Just do nothing. + return NS_OK; + } // Is it a Blob? nsCOMPtr blob = do_QueryInterface( diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a921b0820668..7a648231c032 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -8578,13 +8578,11 @@ nsDocument::GetMozFullScreenEnabled(bool *aFullScreen) NS_ENSURE_ARG_POINTER(aFullScreen); *aFullScreen = false; - if (!nsContentUtils::IsFullScreenApiEnabled()) { + if (!nsContentUtils::IsFullScreenApiEnabled() || + nsContentUtils::HasPluginWithUncontrolledEventDispatch(this)) { return NS_OK; } - // todo: Bug 684618 - Deny requests for DOM full-screen when windowed - // plugins are present. - // Ensure that all ancestor + + + + + diff --git a/content/html/content/test/test_fullscreen-api.html b/content/html/content/test/test_fullscreen-api.html index 35de6bdec41f..8069f8150d2c 100644 --- a/content/html/content/test/test_fullscreen-api.html +++ b/content/html/content/test/test_fullscreen-api.html @@ -86,6 +86,11 @@ function apiTestFinished() { } function keysTestFinished() { + testWindow.close(); + testWindow = window.open("file_fullscreen-plugins.html", "", "width=500,height=500"); +} + +function pluginTestFinished() { testWindow.close(); SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled); SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted); diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 365a037ac98a..88345f848bb3 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2699,17 +2699,15 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, } static void -NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument, - bool aEditable) +NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument) { for (nsIContent* child = aNode->GetFirstChild(); child; child = child->GetNextSibling()) { - if (child->HasFlag(NODE_IS_EDITABLE) != aEditable && - child->IsElement()) { + if (child->IsElement()) { child->AsElement()->UpdateState(true); } - NotifyEditableStateChange(child, aDocument, aEditable); + NotifyEditableStateChange(child, aDocument); } } @@ -2802,6 +2800,8 @@ nsHTMLDocument::EditingStateChanged() if (newState == eOff) { // Editing is being turned off. + nsAutoScriptBlocker scriptBlocker; + NotifyEditableStateChange(this, this); return TurnEditingOff(); } @@ -2958,7 +2958,7 @@ nsHTMLDocument::EditingStateChanged() if (updateState) { nsAutoScriptBlocker scriptBlocker; - NotifyEditableStateChange(this, this, designMode); + NotifyEditableStateChange(this, this); } // Resync the editor's spellcheck state. diff --git a/content/media/VideoUtils.h b/content/media/VideoUtils.h index 9791cb3330b7..1b6f41738338 100644 --- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -166,4 +166,10 @@ void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio); #define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE #endif +// Android's audio backend is not available in content processes, so audio must +// be remoted to the parent chrome process. +#if defined(ANDROID) +#define REMOTE_AUDIO 1 +#endif + #endif diff --git a/content/media/nsAudioStream.cpp b/content/media/nsAudioStream.cpp index 2f3e2c204aed..3ee4bf248f16 100644 --- a/content/media/nsAudioStream.cpp +++ b/content/media/nsAudioStream.cpp @@ -66,12 +66,6 @@ using namespace mozilla; #define SA_PER_STREAM_VOLUME 1 #endif -// Android's audio backend is not available in content processes, so audio must -// be remoted to the parent chrome process. -#if defined(ANDROID) -#define REMOTE_AUDIO 1 -#endif - using mozilla::TimeStamp; #ifdef PR_LOGGING @@ -80,6 +74,9 @@ PRLogModuleInfo* gAudioStreamLog = nsnull; static const PRUint32 FAKE_BUFFER_SIZE = 176400; +// Number of milliseconds per second. +static const PRInt64 MS_PER_S = 1000; + class nsNativeAudioStream : public nsAudioStream { public: @@ -752,9 +749,9 @@ nsRemotedAudioStream::GetPositionInFrames() return 0; PRInt64 time = mAudioChild->GetLastKnownPositionTimestamp(); - PRInt64 result = position + (mRate * (PR_IntervalNow() - time) / USECS_PER_S); + PRInt64 dt = PR_IntervalToMilliseconds(PR_IntervalNow() - time); - return result; + return position + (mRate * dt / MS_PER_S); } bool diff --git a/content/media/nsBuiltinDecoderReader.h b/content/media/nsBuiltinDecoderReader.h index 00a002ee0264..f846cec95180 100644 --- a/content/media/nsBuiltinDecoderReader.h +++ b/content/media/nsBuiltinDecoderReader.h @@ -385,7 +385,7 @@ private: }; // Encapsulates the decoding and reading of media data. Reading can only be -// done on the decode thread thread. Never hold the decoder monitor when +// done on the decode thread. Never hold the decoder monitor when // calling into this class. Unless otherwise specified, methods and fields of // this class can only be accessed on the decode thread. class nsBuiltinDecoderReader : public nsRunnable { diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp index aef55f61e196..3e0cec3710a4 100644 --- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -635,6 +635,29 @@ void nsBuiltinDecoderStateMachine::AudioLoop() NS_WARNING("Int overflow calculating audio end time"); break; } + +// The remoted audio stream does not block writes when the other end's buffers +// are full, so this sleep is necessary to stop the audio thread spinning its +// wheels. When bug 695612 is fixed, this block of code can be removed. +#if defined(REMOTE_AUDIO) + PRInt64 audioAhead = mAudioEndTime - GetMediaTime(); + if (audioAhead > AMPLE_AUDIO_USECS && + framesWritten > minWriteFrames) + { + // We've pushed enough audio onto the hardware that we've queued up a + // significant amount ahead of the playback position. The decode + // thread will be going to sleep, so we won't get any new audio + // anyway, so sleep until we need to push to the hardware again. + Wait(AMPLE_AUDIO_USECS / 2); + // Kick the decode thread; since above we only do a NotifyAll when + // we pop an audio chunk of the queue, the decoder won't wake up if + // we've got no more decoded chunks to push to the hardware. We can + // hit this condition if the last frame in the stream doesn't have + // it's EOS flag set, and the decode thread sleeps just after decoding + // that packet, but before realising there's no more packets. + mon.NotifyAll(); + } +#endif } } if (mReader->mAudioQueue.AtEndOfStream() && diff --git a/content/svg/content/src/SVGPathSegListSMILType.cpp b/content/svg/content/src/SVGPathSegListSMILType.cpp index f7e015f27d90..d0414c7d7fde 100644 --- a/content/svg/content/src/SVGPathSegListSMILType.cpp +++ b/content/svg/content/src/SVGPathSegListSMILType.cpp @@ -95,21 +95,6 @@ SVGPathSegListSMILType::IsEqual(const nsSMILValue& aLeft, *static_cast(aRight.mU.mPtr); } -static bool -ArcFlagsDiffer(SVGPathDataAndOwner::const_iterator aPathData1, - SVGPathDataAndOwner::const_iterator aPathData2) -{ - NS_ABORT_IF_FALSE - (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData1[0])), - "ArcFlagsDiffer called with non-arc segment"); - NS_ABORT_IF_FALSE - (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData2[0])), - "ArcFlagsDiffer called with non-arc segment"); - - return aPathData1[LARGE_ARC_FLAG_IDX] != aPathData2[LARGE_ARC_FLAG_IDX] || - aPathData1[SWEEP_FLAG_IDX] != aPathData2[SWEEP_FLAG_IDX]; -} - enum PathInterpolationResult { eCannotInterpolate, eRequiresConversion, @@ -139,12 +124,6 @@ CanInterpolate(const SVGPathDataAndOwner& aStart, PRUint32 startType = SVGPathSegUtils::DecodeType(*pStart); PRUint32 endType = SVGPathSegUtils::DecodeType(*pEnd); - if (SVGPathSegUtils::IsArcType(startType) && - SVGPathSegUtils::IsArcType(endType) && - ArcFlagsDiffer(pStart, pEnd)) { - return eCannotInterpolate; - } - if (startType != endType) { if (!SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType)) { return eCannotInterpolate; @@ -215,25 +194,22 @@ AddWeightedPathSegs(double aCoeff1, NS_ABORT_IF_FALSE(!aSeg1 || SVGPathSegUtils::DecodeType(*aSeg1) == segType, "unexpected segment type"); - // FIRST: Directly copy the arguments that don't make sense to add. aResultSeg[0] = aSeg2[0]; // encoded segment type - bool isArcType = SVGPathSegUtils::IsArcType(segType); - if (isArcType) { - // Copy boolean arc flags. - NS_ABORT_IF_FALSE(!aSeg1 || !ArcFlagsDiffer(aSeg1, aSeg2), - "Expecting arc flags to match"); - aResultSeg[LARGE_ARC_FLAG_IDX] = aSeg2[LARGE_ARC_FLAG_IDX]; - aResultSeg[SWEEP_FLAG_IDX] = aSeg2[SWEEP_FLAG_IDX]; - } - - // SECOND: Add the arguments that are supposed to be added. + // FIRST: Add all the arguments. // (The 1's below are to account for segment type) PRUint32 numArgs = SVGPathSegUtils::ArgCountForType(segType); for (PRUint32 i = 1; i < 1 + numArgs; ++i) { - // Need to skip arc flags for arc-type segments. (already handled them) - if (!(isArcType && (i == LARGE_ARC_FLAG_IDX || i == SWEEP_FLAG_IDX))) { - aResultSeg[i] = (aSeg1 ? aCoeff1 * aSeg1[i] : 0.0) + aCoeff2 * aSeg2[i]; + aResultSeg[i] = (aSeg1 ? aCoeff1 * aSeg1[i] : 0.0) + aCoeff2 * aSeg2[i]; + } + + // SECOND: ensure non-zero flags become 1. + if (SVGPathSegUtils::IsArcType(segType)) { + if (aResultSeg[LARGE_ARC_FLAG_IDX] != 0.0f) { + aResultSeg[LARGE_ARC_FLAG_IDX] = 1.0f; + } + if (aResultSeg[SWEEP_FLAG_IDX] != 0.0f) { + aResultSeg[SWEEP_FLAG_IDX] = 1.0f; } } diff --git a/content/svg/content/src/nsSVGFilters.cpp b/content/svg/content/src/nsSVGFilters.cpp index a83a895cd772..2a111a69ee63 100644 --- a/content/svg/content/src/nsSVGFilters.cpp +++ b/content/svg/content/src/nsSVGFilters.cpp @@ -169,8 +169,7 @@ nsSVGFE::SetupScalingFilter(nsSVGFilterInstance *aInstance, return result; gfxRect r(aDataRect.x, aDataRect.y, aDataRect.width, aDataRect.height); - r.Scale(gfxFloat(scaledSize.width)/aTarget->mImage->Width(), - gfxFloat(scaledSize.height)/aTarget->mImage->Height()); + r.Scale(1 / kernelX, 1 / kernelY); r.RoundOut(); if (!gfxUtils::GfxRectToIntRect(r, &result.mDataRect)) return result; diff --git a/content/svg/content/src/nsSVGImageElement.cpp b/content/svg/content/src/nsSVGImageElement.cpp index 9fefc872c709..b097bdeb722d 100644 --- a/content/svg/content/src/nsSVGImageElement.cpp +++ b/content/svg/content/src/nsSVGImageElement.cpp @@ -45,7 +45,6 @@ #include "imgIContainer.h" #include "imgIDecoderObserver.h" #include "gfxContext.h" -#include "mozilla/Preferences.h" using namespace mozilla; @@ -168,28 +167,6 @@ nsSVGImageElement::LoadSVGImage(bool aForce, bool aNotify) //---------------------------------------------------------------------- // nsIContent methods: -nsresult -nsSVGImageElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, - const nsAString* aValue, bool aNotify) -{ - if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) { - // If caller is not chrome and dom.disable_image_src_set is true, - // prevent setting image.src by exiting early - if (Preferences::GetBool("dom.disable_image_src_set") && - !nsContentUtils::IsCallerChrome()) { - return NS_OK; - } - - if (aValue) { - LoadSVGImage(true, aNotify); - } else { - CancelImageRequests(aNotify); - } - } - return nsSVGImageElementBase::AfterSetAttr(aNamespaceID, aName, - aValue, aNotify); -} - void nsSVGImageElement::MaybeLoadSVGImage() { @@ -281,17 +258,6 @@ nsSVGImageElement::GetStringInfo() ArrayLength(sStringInfo)); } -void -nsSVGImageElement::DidAnimateString(PRUint8 aAttrEnum) -{ - if (aAttrEnum == HREF) { - LoadSVGImage(true, false); - return; - } - - nsSVGImageElementBase::DidAnimateString(aAttrEnum); -} - nsresult nsSVGImageElement::CopyInnerTo(nsGenericElement* aDest) const { diff --git a/content/svg/content/src/nsSVGImageElement.h b/content/svg/content/src/nsSVGImageElement.h index 3e59da4949c3..8893bf519650 100644 --- a/content/svg/content/src/nsSVGImageElement.h +++ b/content/svg/content/src/nsSVGImageElement.h @@ -77,8 +77,6 @@ public: NS_FORWARD_NSIDOMSVGELEMENT(nsSVGImageElementBase::) // nsIContent interface - virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, - const nsAString* aValue, bool aNotify); virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, bool aCompileEventHandlers); @@ -103,7 +101,6 @@ protected: virtual LengthAttributesInfo GetLengthInfo(); virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio(); virtual StringAttributesInfo GetStringInfo(); - virtual void DidAnimateString(PRUint8 aAttrEnum); enum { X, Y, WIDTH, HEIGHT }; nsSVGLength2 mLengthAttributes[4]; diff --git a/content/svg/content/src/nsSVGMpathElement.cpp b/content/svg/content/src/nsSVGMpathElement.cpp index 17054ea75368..1546bcd3654a 100644 --- a/content/svg/content/src/nsSVGMpathElement.cpp +++ b/content/svg/content/src/nsSVGMpathElement.cpp @@ -229,6 +229,7 @@ nsSVGMpathElement::GetReferencedPath() nsIContent* genericTarget = mHrefTarget.get(); if (genericTarget && + genericTarget->GetNameSpaceID() == kNameSpaceID_SVG && genericTarget->Tag() == nsGkAtoms::path) { return static_cast(genericTarget); } diff --git a/content/svg/content/test/test_pathAnimInterpolation.xhtml b/content/svg/content/test/test_pathAnimInterpolation.xhtml index 66b89f09f1c9..36f8e4de5ebc 100644 --- a/content/svg/content/test/test_pathAnimInterpolation.xhtml +++ b/content/svg/content/test/test_pathAnimInterpolation.xhtml @@ -138,10 +138,10 @@ var gSuffixes = { [40, 50, 60, 70, 80, 90], [50, 70, 90, 110, 130, 150]], QQ: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]], qq: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]], - AA: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100], - [35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]], - aa: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100], - [35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]], + AA: [[10, 20, 30, 1, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100], + [35, 45, 55, 1, 0, 65, 75], [45, 65, 85, 1, 0, 105, 125]], + aa: [[10, 20, 30, 0, 1, 40, 50], [60, 70, 80, 0, 0, 90, 100], + [35, 45, 55, 0, 1, 65, 75], [45, 65, 85, 0, 1, 105, 125]], HH: [[10], [20], [15], [25]], hh: [[10], [20], [15], [25]], VV: [[10], [20], [15], [25]], @@ -286,17 +286,6 @@ function run() } } - // Test that differences in arc flag parameters cause the - // interpolation/addition not to occur. - addTest(1, "M100,100", - "A", [10, 20, 30, 0, 0, 40, 50], - "a", [60, 70, 80, 0, 1, 90, 100], - "a", [60, 70, 80, 0, 1, 90, 100], additive); - addTest(1, "M100,100", - "A", [10, 20, 30, 0, 0, 40, 50], - "a", [60, 70, 80, 1, 0, 90, 100], - "a", [60, 70, 80, 1, 0, 90, 100], additive); - // Test all pairs of segment types that cannot be interpolated between. for each (let fromType in gTypes) { let fromArguments = generatePathSegmentArguments(fromType, 0); diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index b2a6b9d250f7..8125595466c9 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -656,14 +656,7 @@ nsXULElement::PerformAccesskey(bool aKeyCausesActivation, } nsIFrame* frame = content->GetPrimaryFrame(); - if (!frame) - return; - - const nsStyleVisibility* vis = frame->GetStyleVisibility(); - - if (vis->mVisible == NS_STYLE_VISIBILITY_COLLAPSE || - vis->mVisible == NS_STYLE_VISIBILITY_HIDDEN || - !frame->AreAncestorViewsVisible()) + if (!frame || !frame->IsVisibleConsideringAncestors()) return; nsXULElement* elm = FromContent(content); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 9916a6de0b2f..6b3e4f48a5aa 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4126,10 +4126,10 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, mFailedLoadType = mLoadType; if (mLSHE) { - // If we don't give mLSHE a new doc identifier here, when we go back or - // forward to another SHEntry with the same doc identifier, the error - // page will persist. - mLSHE->SetUniqueDocIdentifier(); + // Abandon mLSHE's BFCache entry and create a new one. This way, if + // we go back or forward to another SHEntry with the same doc + // identifier, the error page won't persist. + mLSHE->AbandonBFCacheEntry(); } nsCAutoString url; @@ -4402,10 +4402,10 @@ nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType) nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry)); NS_ENSURE_SUCCESS(rv, rv); - // Give our cloned shEntry a new document identifier so this load is - // independent of all other loads. (This is important, in particular, - // for bugs 582795 and 585298.) - rv = shEntry->SetUniqueDocIdentifier(); + // Give our cloned shEntry a new bfcache entry so this load is independent + // of all other loads. (This is important, in particular, for bugs 582795 + // and 585298.) + rv = shEntry->AbandonBFCacheEntry(); NS_ENSURE_SUCCESS(rv, rv); // @@ -4821,8 +4821,11 @@ nsDocShell::GetVisibility(bool * aVisibility) nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nsnull; bool isDocShellOffScreen = false; docShell->GetIsOffScreenBrowser(&isDocShellOffScreen); - if (frame && !frame->AreAncestorViewsVisible() && !isDocShellOffScreen) + if (frame && + !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) && + !isDocShellOffScreen) { return NS_OK; + } treeItem = parentItem; treeItem->GetParent(getter_AddRefs(parentItem)); @@ -8280,17 +8283,15 @@ nsDocShell::InternalLoad(nsIURI * aURI, NS_SUCCEEDED(splitRv2) && curBeforeHash.Equals(newBeforeHash); - bool sameDocIdent = false; + // XXX rename + bool sameDocument = false; if (mOSHE && aSHEntry) { // We're doing a history load. - PRUint64 ourDocIdent, otherDocIdent; - mOSHE->GetDocIdentifier(&ourDocIdent); - aSHEntry->GetDocIdentifier(&otherDocIdent); - sameDocIdent = (ourDocIdent == otherDocIdent); + mOSHE->SharesDocumentWith(aSHEntry, &sameDocument); #ifdef DEBUG - if (sameDocIdent) { + if (sameDocument) { nsCOMPtr currentPostData; mOSHE->GetPostData(getter_AddRefs(currentPostData)); NS_ASSERTION(currentPostData == aPostData, @@ -8313,7 +8314,7 @@ nsDocShell::InternalLoad(nsIURI * aURI, // The restriction tha the SHEntries in (a) must be different ensures // that history.go(0) and the like trigger full refreshes, rather than // short-circuited loads. - bool doShortCircuitedLoad = (sameDocIdent && mOSHE != aSHEntry) || + bool doShortCircuitedLoad = (sameDocument && mOSHE != aSHEntry) || (!aSHEntry && aPostData == nsnull && sameExceptHashes && !newHash.IsEmpty()); @@ -8364,7 +8365,6 @@ nsDocShell::InternalLoad(nsIURI * aURI, OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true); nsCOMPtr postData; - PRUint64 docIdent = PRUint64(-1); nsCOMPtr cacheKey; if (mOSHE) { @@ -8378,8 +8378,13 @@ nsDocShell::InternalLoad(nsIURI * aURI, // wouldn't want here. if (aLoadType & LOAD_CMD_NORMAL) { mOSHE->GetPostData(getter_AddRefs(postData)); - mOSHE->GetDocIdentifier(&docIdent); mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); + + // Link our new SHEntry to the old SHEntry's back/forward + // cache data, since the two SHEntries correspond to the + // same document. + if (mLSHE) + mLSHE->AdoptBFCacheEntry(mOSHE); } } @@ -8399,11 +8404,6 @@ nsDocShell::InternalLoad(nsIURI * aURI, // cache first if (cacheKey) mOSHE->SetCacheKey(cacheKey); - - // Propagate our document identifier to the new mOSHE so that - // we'll know it's related by an anchor navigation or pushState. - if (docIdent != PRUint64(-1)) - mOSHE->SetDocIdentifier(docIdent); } /* restore previous position of scroller(s), if we're moving @@ -8447,7 +8447,7 @@ nsDocShell::InternalLoad(nsIURI * aURI, } } - if (sameDocIdent) { + if (sameDocument) { // Set the doc's URI according to the new history entry's URI nsCOMPtr newURI; mOSHE->GetURI(getter_AddRefs(newURI)); @@ -8464,10 +8464,10 @@ nsDocShell::InternalLoad(nsIURI * aURI, // Dispatch the popstate and hashchange events, as appropriate. nsCOMPtr window = do_QueryInterface(mScriptGlobal); if (window) { - // Need the doHashchange check here since sameDocIdent is + // Need the doHashchange check here since sameDocument is // false if we're navigating to a new shentry (i.e. a aSHEntry // is null), such as when clicking a . - if (sameDocIdent || doHashchange) { + if (sameDocument || doHashchange) { window->DispatchSyncPopState(); } @@ -9250,11 +9250,11 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, } // If the response status indicates an error, unlink this session - // history entry from any entries sharing its doc ident. + // history entry from any entries sharing its document. PRUint32 responseStatus; nsresult rv = httpChannel->GetResponseStatus(&responseStatus); if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) { - mLSHE->SetUniqueDocIdentifier(); + mLSHE->AbandonBFCacheEntry(); } } } @@ -9483,9 +9483,9 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, // It's important that this function not run arbitrary scripts after step 1 // and before completing step 5. For example, if a script called // history.back() before we completed step 5, bfcache might destroy an - // active content viewer. Since EvictContentViewers at the end of step 5 - // might run script, we can't just put a script blocker around the critical - // section. + // active content viewer. Since EvictOutOfRangeContentViewers at the end of + // step 5 might run script, we can't just put a script blocker around the + // critical section. // // Note that we completely ignore the aTitle parameter. @@ -9665,11 +9665,9 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE); - // Set the new SHEntry's document identifier, if we can. - PRUint64 ourDocIdent; - NS_ENSURE_SUCCESS(oldOSHE->GetDocIdentifier(&ourDocIdent), - NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(newSHEntry->SetDocIdentifier(ourDocIdent), + // Link the new SHEntry to the old SHEntry's BFCache entry, since the + // two entries correspond to the same document. + NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE); // Set the new SHEntry's title (bug 655273). @@ -9715,7 +9713,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, PRInt32 curIndex = -1; rv = rootSH->GetIndex(&curIndex); if (NS_SUCCEEDED(rv) && curIndex > -1) { - internalSH->EvictContentViewers(curIndex - 1, curIndex); + internalSH->EvictOutOfRangeContentViewers(curIndex); } } diff --git a/docshell/build/nsDocShellModule.cpp b/docshell/build/nsDocShellModule.cpp index dbd26a6a22c7..89030e8c4507 100644 --- a/docshell/build/nsDocShellModule.cpp +++ b/docshell/build/nsDocShellModule.cpp @@ -66,6 +66,7 @@ // session history #include "nsSHEntry.h" +#include "nsSHEntryShared.h" #include "nsSHistory.h" #include "nsSHTransaction.h" @@ -87,15 +88,15 @@ Initialize() nsresult rv = nsSHistory::Startup(); NS_ENSURE_SUCCESS(rv, rv); - rv = nsSHEntry::Startup(); - return rv; + nsSHEntryShared::Startup(); + return NS_OK; } static void Shutdown() { nsSHistory::Shutdown(); - nsSHEntry::Shutdown(); + nsSHEntryShared::Shutdown(); gInitialized = false; } diff --git a/docshell/shistory/public/Makefile.in b/docshell/shistory/public/Makefile.in index 434b098b1c90..36e14517ada2 100644 --- a/docshell/shistory/public/Makefile.in +++ b/docshell/shistory/public/Makefile.in @@ -56,6 +56,7 @@ XPIDLSRCS = \ nsISHContainer.idl \ nsISHTransaction.idl \ nsISHistoryInternal.idl \ + nsIBFCacheEntry.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/docshell/shistory/public/nsIBFCacheEntry.idl b/docshell/shistory/public/nsIBFCacheEntry.idl new file mode 100644 index 000000000000..99d1e371f6f7 --- /dev/null +++ b/docshell/shistory/public/nsIBFCacheEntry.idl @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * This interface lets you evict a document from the back/forward cache. + */ +[scriptable, uuid(a576060e-c7df-4d81-aa8c-5b52bd6ad25d)] +interface nsIBFCacheEntry : nsISupports +{ + void RemoveFromBFCacheSync(); + void RemoveFromBFCacheAsync(); + + readonly attribute unsigned long long ID; +}; diff --git a/docshell/shistory/public/nsISHEntry.idl b/docshell/shistory/public/nsISHEntry.idl index 155ae63e2f29..3daa1f1a0306 100644 --- a/docshell/shistory/public/nsISHEntry.idl +++ b/docshell/shistory/public/nsISHEntry.idl @@ -51,15 +51,18 @@ interface nsIInputStream; interface nsIDocShellTreeItem; interface nsISupportsArray; interface nsIStructuredCloneContainer; +interface nsIBFCacheEntry; + %{C++ struct nsIntRect; class nsDocShellEditorData; +class nsSHEntryShared; %} [ref] native nsIntRect(nsIntRect); [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData); +[ptr] native nsSHEntryShared(nsSHEntryShared); - -[scriptable, uuid(b92d403e-f5ec-4b81-b0e3-6e6c241cef2d)] +[scriptable, uuid(6443FD72-A50F-4B8B-BB82-BB1FA04CB15D)] interface nsISHEntry : nsIHistoryEntry { /** URI for the document */ @@ -140,21 +143,6 @@ interface nsISHEntry : nsIHistoryEntry */ attribute unsigned long ID; - /** - * docIdentifier is an integer that should be the same for two entries - * attached to the same docshell if and only if the two entries are entries - * for the same document. In practice, two entries A and B will have the - * same docIdentifier if we arrived at B by clicking an anchor link in A or - * if B was created by A's calling history.pushState(). - */ - attribute unsigned long long docIdentifier; - - /** - * Changes this entry's doc identifier to a new value which is unique - * among those of all other entries. - */ - void setUniqueDocIdentifier(); - /** attribute to set and get the cache key for the entry */ attribute nsISupports cacheKey; @@ -252,6 +240,36 @@ interface nsISHEntry : nsIHistoryEntry * The history ID of the docshell. */ attribute unsigned long long docshellID; + + readonly attribute nsIBFCacheEntry BFCacheEntry; + + /** + * Does this SHEntry point to the given BFCache entry? If so, evicting + * the BFCache entry will evict the SHEntry, since the two entries + * correspond to the same document. + */ + [notxpcom, noscript] + boolean hasBFCacheEntry(in nsIBFCacheEntry aEntry); + + /** + * Adopt aEntry's BFCacheEntry, so now both this and aEntry point to + * aEntry's BFCacheEntry. + */ + void adoptBFCacheEntry(in nsISHEntry aEntry); + + /** + * Create a new BFCache entry and drop our reference to our old one. This + * call unlinks this SHEntry from any other SHEntries for its document. + */ + void abandonBFCacheEntry(); + + /** + * Does this SHEntry correspond to the same document as aEntry? This is + * true iff the two SHEntries have the same BFCacheEntry. So in + * particular, sharesDocumentWith(aEntry) is guaranteed to return true if + * it's preceeded by a call to adoptBFCacheEntry(aEntry). + */ + boolean sharesDocumentWith(in nsISHEntry aEntry); }; [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)] @@ -264,6 +282,17 @@ interface nsISHEntryInternal : nsISupports * A number that is assigned by the sHistory when the entry is activated */ attribute unsigned long lastTouched; + + /** + * Some state, particularly that related to the back/forward cache, is + * shared between SHEntries which correspond to the same document. This + * method gets a pointer to that shared state. + * + * This shared state is the SHEntry's BFCacheEntry. So + * hasBFCacheEntry(getSharedState()) is guaranteed to return true. + */ + [noscript, notxpcom] + nsSHEntryShared getSharedState(); }; %{ C++ diff --git a/docshell/shistory/public/nsISHistoryInternal.idl b/docshell/shistory/public/nsISHistoryInternal.idl index 338acec23468..1f5b0b683659 100644 --- a/docshell/shistory/public/nsISHistoryInternal.idl +++ b/docshell/shistory/public/nsISHistoryInternal.idl @@ -57,7 +57,7 @@ struct nsTArrayDefaultAllocator; [ref] native nsDocshellIDArray(nsTArray); -[scriptable, uuid(2dede933-25e1-47a3-8f61-0127c785ea01)] +[scriptable, uuid(e27cf38e-c19f-4294-bd31-d7e0916e7fa2)] interface nsISHistoryInternal: nsISupports { /** @@ -96,20 +96,25 @@ interface nsISHistoryInternal: nsISupports */ readonly attribute nsISHistoryListener listener; - /** - * Evict content viewers until the number of content viewers per tab - * is no more than gHistoryMaxViewers. Also, count - * total number of content viewers globally and evict one if we are over - * our total max. This is always called in Show(), after we destroy - * the previous viewer. - */ - void evictContentViewers(in long previousIndex, in long index); + /** + * Evict content viewers which don't lie in the "safe" range around aIndex. + * In practice, this should leave us with no more than gHistoryMaxViewers + * viewers associated with this SHistory object. + * + * Also make sure that the total number of content viewers in all windows is + * not greater than our global max; if it is, evict viewers as appropriate. + * + * @param aIndex - The index around which the "safe" range is centered. In + * general, if you just navigated the history, aIndex should be the index + * history was navigated to. + */ + void evictOutOfRangeContentViewers(in long aIndex); /** - * Evict the content viewer associated with a session history entry + * Evict the content viewer associated with a bfcache entry * that has timed out. */ - void evictExpiredContentViewerForEntry(in nsISHEntry aEntry); + void evictExpiredContentViewerForEntry(in nsIBFCacheEntry aEntry); /** * Evict all the content viewers in this session history diff --git a/docshell/shistory/src/Makefile.in b/docshell/shistory/src/Makefile.in index e1debfbd983c..7d8eedde7983 100644 --- a/docshell/shistory/src/Makefile.in +++ b/docshell/shistory/src/Makefile.in @@ -48,10 +48,13 @@ LIBRARY_NAME = shistory_s FORCE_STATIC_LIB = 1 LIBXUL_LIBRARY = 1 +EXPORTS = nsSHEntryShared.h \ + $(NULL) CPPSRCS = nsSHEntry.cpp \ nsSHTransaction.cpp \ nsSHistory.cpp \ + nsSHEntryShared.cpp \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/docshell/shistory/src/nsSHEntry.cpp b/docshell/shistory/src/nsSHEntry.cpp index baab34a27e04..c3ce68d4c81a 100644 --- a/docshell/shistory/src/nsSHEntry.cpp +++ b/docshell/shistory/src/nsSHEntry.cpp @@ -36,10 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -#ifdef DEBUG_bryner -#define DEBUG_PAGE_CACHE -#endif - // Local Includes #include "nsSHEntry.h" #include "nsXPIDLString.h" @@ -48,103 +44,44 @@ #include "nsIDocShellTreeItem.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" -#include "nsAutoPtr.h" -#include "nsThreadUtils.h" -#include "nsIWebNavigation.h" #include "nsISHistory.h" #include "nsISHistoryInternal.h" #include "nsDocShellEditorData.h" -#include "nsIDocShell.h" +#include "nsSHEntryShared.h" +#include "nsILayoutHistoryState.h" +#include "nsIContentViewer.h" +#include "nsISupportsArray.h" namespace dom = mozilla::dom; -// Hardcode this to time out unused content viewers after 30 minutes -#define CONTENT_VIEWER_TIMEOUT_SECONDS 30*60 - -typedef nsExpirationTracker HistoryTrackerBase; -class HistoryTracker : public HistoryTrackerBase { -public: - // Expire cached contentviewers after 20-30 minutes in the cache. - HistoryTracker() : HistoryTrackerBase((CONTENT_VIEWER_TIMEOUT_SECONDS/2)*1000) {} - -protected: - virtual void NotifyExpired(nsSHEntry* aObj) { - RemoveObject(aObj); - aObj->Expire(); - } -}; - -static HistoryTracker *gHistoryTracker = nsnull; static PRUint32 gEntryID = 0; -static PRUint64 gEntryDocIdentifier = 0; - -nsresult nsSHEntry::Startup() -{ - gHistoryTracker = new HistoryTracker(); - return gHistoryTracker ? NS_OK : NS_ERROR_OUT_OF_MEMORY; -} - -void nsSHEntry::Shutdown() -{ - delete gHistoryTracker; - gHistoryTracker = nsnull; -} - -static void StopTrackingEntry(nsSHEntry *aEntry) -{ - if (aEntry->GetExpirationState()->IsTracked()) { - gHistoryTracker->RemoveObject(aEntry); - } -} //***************************************************************************** //*** nsSHEntry: Object Management //***************************************************************************** -nsSHEntry::nsSHEntry() +nsSHEntry::nsSHEntry() : mLoadType(0) , mID(gEntryID++) - , mDocIdentifier(gEntryDocIdentifier++) , mScrollPositionX(0) , mScrollPositionY(0) , mURIWasModified(false) - , mIsFrameNavigation(false) - , mSaveLayoutState(true) - , mExpired(false) - , mSticky(true) - , mDynamicallyCreated(false) - , mParent(nsnull) - , mViewerBounds(0, 0, 0, 0) - , mDocShellID(0) - , mLastTouched(0) { + mShared = new nsSHEntryShared(); } nsSHEntry::nsSHEntry(const nsSHEntry &other) - : mURI(other.mURI) + : mShared(other.mShared) + , mURI(other.mURI) , mReferrerURI(other.mReferrerURI) - // XXX why not copy mDocument? , mTitle(other.mTitle) , mPostData(other.mPostData) - , mLayoutHistoryState(other.mLayoutHistoryState) , mLoadType(0) // XXX why not copy? , mID(other.mID) - , mDocIdentifier(other.mDocIdentifier) , mScrollPositionX(0) // XXX why not copy? , mScrollPositionY(0) // XXX why not copy? , mURIWasModified(other.mURIWasModified) - , mIsFrameNavigation(other.mIsFrameNavigation) - , mSaveLayoutState(other.mSaveLayoutState) - , mExpired(other.mExpired) - , mSticky(true) - , mDynamicallyCreated(other.mDynamicallyCreated) - // XXX why not copy mContentType? - , mCacheKey(other.mCacheKey) - , mParent(other.mParent) - , mViewerBounds(0, 0, 0, 0) - , mOwner(other.mOwner) - , mDocShellID(other.mDocShellID) , mStateData(other.mStateData) { } @@ -160,37 +97,16 @@ ClearParentPtr(nsISHEntry* aEntry, void* /* aData */) nsSHEntry::~nsSHEntry() { - StopTrackingEntry(this); - - // Since we never really remove kids from SHEntrys, we need to null - // out the mParent pointers on all our kids. + // Null out the mParent pointers on all our kids. mChildren.EnumerateForwards(ClearParentPtr, nsnull); - mChildren.Clear(); - - if (mContentViewer) { - // RemoveFromBFCacheSync is virtual, so call the nsSHEntry version - // explicitly - nsSHEntry::RemoveFromBFCacheSync(); - } - - mEditorData = nsnull; - -#ifdef DEBUG - // This is not happening as far as I can tell from breakpad as of early November 2007 - nsExpirationTracker::Iterator iterator(gHistoryTracker); - nsSHEntry* elem; - while ((elem = iterator.Next()) != nsnull) { - NS_ASSERTION(elem != this, "Found dead entry still in the tracker!"); - } -#endif } //***************************************************************************** // nsSHEntry: nsISupports //***************************************************************************** -NS_IMPL_ISUPPORTS5(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry, - nsIMutationObserver, nsISHEntryInternal) +NS_IMPL_ISUPPORTS4(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry, + nsISHEntryInternal) //***************************************************************************** // nsSHEntry: nsISHEntry @@ -251,35 +167,13 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI) NS_IMETHODIMP nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) { - NS_PRECONDITION(!aViewer || !mContentViewer, "SHEntry already contains viewer"); - - if (mContentViewer || !aViewer) { - DropPresentationState(); - } - - mContentViewer = aViewer; - - if (mContentViewer) { - gHistoryTracker->AddObject(this); - - nsCOMPtr domDoc; - mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); - // Store observed document in strong pointer in case it is removed from - // the contentviewer - mDocument = do_QueryInterface(domDoc); - if (mDocument) { - mDocument->SetBFCacheEntry(this); - mDocument->AddMutationObserver(this); - } - } - - return NS_OK; + return mShared->SetContentViewer(aViewer); } NS_IMETHODIMP nsSHEntry::GetContentViewer(nsIContentViewer **aResult) { - *aResult = mContentViewer; + *aResult = mShared->mContentViewer; NS_IF_ADDREF(*aResult); return NS_OK; } @@ -319,14 +213,14 @@ nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry, NS_IMETHODIMP nsSHEntry::SetSticky(bool aSticky) { - mSticky = aSticky; + mShared->mSticky = aSticky; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetSticky(bool *aSticky) { - *aSticky = mSticky; + *aSticky = mShared->mSticky; return NS_OK; } @@ -365,16 +259,18 @@ NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData) NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) { - *aResult = mLayoutHistoryState; + *aResult = mShared->mLayoutHistoryState; NS_IF_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) { - mLayoutHistoryState = aState; - if (mLayoutHistoryState) - mLayoutHistoryState->SetScrollPositionOnly(!mSaveLayoutState); + mShared->mLayoutHistoryState = aState; + if (mShared->mLayoutHistoryState) { + mShared->mLayoutHistoryState-> + SetScrollPositionOnly(!mShared->mSaveLayoutState); + } return NS_OK; } @@ -403,91 +299,73 @@ NS_IMETHODIMP nsSHEntry::SetID(PRUint32 aID) return NS_OK; } -NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult) +nsSHEntryShared* nsSHEntry::GetSharedState() { - *aResult = mDocIdentifier; - return NS_OK; -} - -NS_IMETHODIMP nsSHEntry::SetDocIdentifier(PRUint64 aDocIdentifier) -{ - // This ensures that after a session restore, gEntryDocIdentifier is greater - // than all SHEntries' docIdentifiers, which ensures that we'll never repeat - // a doc identifier. - if (aDocIdentifier >= gEntryDocIdentifier) - gEntryDocIdentifier = aDocIdentifier + 1; - - mDocIdentifier = aDocIdentifier; - return NS_OK; -} - -NS_IMETHODIMP nsSHEntry::SetUniqueDocIdentifier() -{ - mDocIdentifier = gEntryDocIdentifier++; - return NS_OK; + return mShared; } NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag) { - *aFlag = mIsFrameNavigation; + *aFlag = mShared->mIsFrameNavigation; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool aFlag) { - mIsFrameNavigation = aFlag; + mShared->mIsFrameNavigation = aFlag; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult) { - *aResult = mCacheKey; + *aResult = mShared->mCacheKey; NS_IF_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey) { - mCacheKey = aCacheKey; + mShared->mCacheKey = aCacheKey; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag) { - *aFlag = mSaveLayoutState; + *aFlag = mShared->mSaveLayoutState; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) { - mSaveLayoutState = aFlag; - if (mLayoutHistoryState) - mLayoutHistoryState->SetScrollPositionOnly(!aFlag); + mShared->mSaveLayoutState = aFlag; + if (mShared->mLayoutHistoryState) { + mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag); + } return NS_OK; } NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag) { - *aFlag = mExpired; + *aFlag = mShared->mExpired; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool aFlag) { - mExpired = aFlag; + mShared->mExpired = aFlag; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType) { - aContentType = mContentType; + aContentType = mShared->mContentType; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType) { - mContentType = aContentType; + mShared->mContentType = aContentType; return NS_OK; } @@ -502,26 +380,27 @@ nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle, mURI = aURI; mTitle = aTitle; mPostData = aInputStream; - mCacheKey = aCacheKey; - mContentType = aContentType; - mOwner = aOwner; - mDocShellID = aDocShellID; - mDynamicallyCreated = aDynamicCreation; // Set the LoadType by default to loadHistory during creation mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory; + mShared->mCacheKey = aCacheKey; + mShared->mContentType = aContentType; + mShared->mOwner = aOwner; + mShared->mDocShellID = aDocShellID; + mShared->mDynamicallyCreated = aDynamicCreation; + // By default all entries are set false for subframe flag. // nsDocShell::CloneAndReplace() which creates entries for // all subframe navigations, sets the flag to true. - mIsFrameNavigation = false; + mShared->mIsFrameNavigation = false; // By default we save LayoutHistoryState - mSaveLayoutState = true; - mLayoutHistoryState = aLayoutHistoryState; + mShared->mSaveLayoutState = true; + mShared->mLayoutHistoryState = aLayoutHistoryState; //By default the page is not expired - mExpired = false; + mShared->mExpired = false; return NS_OK; } @@ -530,8 +409,6 @@ NS_IMETHODIMP nsSHEntry::Clone(nsISHEntry ** aResult) { *aResult = new nsSHEntry(*this); - if (!*aResult) - return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aResult); return NS_OK; } @@ -540,7 +417,7 @@ NS_IMETHODIMP nsSHEntry::GetParent(nsISHEntry ** aResult) { NS_ENSURE_ARG_POINTER(aResult); - *aResult = mParent; + *aResult = mShared->mParent; NS_IF_ADDREF(*aResult); return NS_OK; } @@ -553,49 +430,95 @@ nsSHEntry::SetParent(nsISHEntry * aParent) * * XXX this method should not be scriptable if this is the case!! */ - mParent = aParent; + mShared->mParent = aParent; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetWindowState(nsISupports *aState) { - mWindowState = aState; + mShared->mWindowState = aState; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetWindowState(nsISupports **aState) { - NS_IF_ADDREF(*aState = mWindowState); + NS_IF_ADDREF(*aState = mShared->mWindowState); return NS_OK; } NS_IMETHODIMP nsSHEntry::SetViewerBounds(const nsIntRect &aBounds) { - mViewerBounds = aBounds; + mShared->mViewerBounds = aBounds; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetViewerBounds(nsIntRect &aBounds) { - aBounds = mViewerBounds; + aBounds = mShared->mViewerBounds; return NS_OK; } NS_IMETHODIMP nsSHEntry::GetOwner(nsISupports **aOwner) { - NS_IF_ADDREF(*aOwner = mOwner); + NS_IF_ADDREF(*aOwner = mShared->mOwner); return NS_OK; } NS_IMETHODIMP nsSHEntry::SetOwner(nsISupports *aOwner) { - mOwner = aOwner; + mShared->mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry **aEntry) +{ + NS_ENSURE_ARG_POINTER(aEntry); + NS_IF_ADDREF(*aEntry = mShared); + return NS_OK; +} + +bool +nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry *aEntry) +{ + return static_cast(mShared) == aEntry; +} + +NS_IMETHODIMP +nsSHEntry::AdoptBFCacheEntry(nsISHEntry *aEntry) +{ + nsCOMPtr shEntry = do_QueryInterface(aEntry); + NS_ENSURE_STATE(shEntry); + + nsSHEntryShared *shared = shEntry->GetSharedState(); + NS_ENSURE_STATE(shared); + + mShared = shared; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SharesDocumentWith(nsISHEntry *aEntry, bool *aOut) +{ + NS_ENSURE_ARG_POINTER(aOut); + + nsCOMPtr internal = do_QueryInterface(aEntry); + NS_ENSURE_STATE(internal); + + *aOut = mShared == internal->GetSharedState(); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::AbandonBFCacheEntry() +{ + mShared = nsSHEntryShared::Duplicate(mShared); return NS_OK; } @@ -753,256 +676,77 @@ NS_IMETHODIMP nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell) { NS_ASSERTION(aShell, "Null child shell added to history entry"); - mChildShells.AppendObject(aShell); + mShared->mChildShells.AppendObject(aShell); return NS_OK; } NS_IMETHODIMP nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell) { - NS_IF_ADDREF(*aShell = mChildShells.SafeObjectAt(aIndex)); + NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex)); return NS_OK; } NS_IMETHODIMP nsSHEntry::ClearChildShells() { - mChildShells.Clear(); + mShared->mChildShells.Clear(); return NS_OK; } NS_IMETHODIMP nsSHEntry::GetRefreshURIList(nsISupportsArray **aList) { - NS_IF_ADDREF(*aList = mRefreshURIList); + NS_IF_ADDREF(*aList = mShared->mRefreshURIList); return NS_OK; } NS_IMETHODIMP nsSHEntry::SetRefreshURIList(nsISupportsArray *aList) { - mRefreshURIList = aList; + mShared->mRefreshURIList = aList; return NS_OK; } NS_IMETHODIMP nsSHEntry::SyncPresentationState() { - if (mContentViewer && mWindowState) { - // If we have a content viewer and a window state, we should be ok. - return NS_OK; - } - - DropPresentationState(); - - return NS_OK; + return mShared->SyncPresentationState(); } -void -nsSHEntry::DropPresentationState() -{ - nsRefPtr kungFuDeathGrip = this; - - if (mDocument) { - mDocument->SetBFCacheEntry(nsnull); - mDocument->RemoveMutationObserver(this); - mDocument = nsnull; - } - if (mContentViewer) - mContentViewer->ClearHistoryEntry(); - - StopTrackingEntry(this); - mContentViewer = nsnull; - mSticky = true; - mWindowState = nsnull; - mViewerBounds.SetRect(0, 0, 0, 0); - mChildShells.Clear(); - mRefreshURIList = nsnull; - mEditorData = nsnull; -} - -void -nsSHEntry::Expire() -{ - // This entry has timed out. If we still have a content viewer, we need to - // get it evicted. - if (!mContentViewer) - return; - nsCOMPtr container; - mContentViewer->GetContainer(getter_AddRefs(container)); - nsCOMPtr treeItem = do_QueryInterface(container); - if (!treeItem) - return; - // We need to find the root DocShell since only that object has an - // SHistory and we need the SHistory to evict content viewers - nsCOMPtr root; - treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root)); - nsCOMPtr webNav = do_QueryInterface(root); - nsCOMPtr history; - webNav->GetSessionHistory(getter_AddRefs(history)); - nsCOMPtr historyInt = do_QueryInterface(history); - if (!historyInt) - return; - historyInt->EvictExpiredContentViewerForEntry(this); -} - -//***************************************************************************** -// nsSHEntry: nsIMutationObserver -//***************************************************************************** - -void -nsSHEntry::NodeWillBeDestroyed(const nsINode* aNode) -{ - NS_NOTREACHED("Document destroyed while we're holding a strong ref to it"); -} - -void -nsSHEntry::CharacterDataWillChange(nsIDocument* aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) -{ -} - -void -nsSHEntry::CharacterDataChanged(nsIDocument* aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) -{ - RemoveFromBFCacheAsync(); -} - -void -nsSHEntry::AttributeWillChange(nsIDocument* aDocument, - dom::Element* aContent, - PRInt32 aNameSpaceID, - nsIAtom* aAttribute, - PRInt32 aModType) -{ -} - -void -nsSHEntry::AttributeChanged(nsIDocument* aDocument, - dom::Element* aElement, - PRInt32 aNameSpaceID, - nsIAtom* aAttribute, - PRInt32 aModType) -{ - RemoveFromBFCacheAsync(); -} - -void -nsSHEntry::ContentAppended(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aFirstNewContent, - PRInt32 /* unused */) -{ - RemoveFromBFCacheAsync(); -} - -void -nsSHEntry::ContentInserted(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 /* unused */) -{ - RemoveFromBFCacheAsync(); -} - -void -nsSHEntry::ContentRemoved(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInContainer, - nsIContent* aPreviousSibling) -{ - RemoveFromBFCacheAsync(); -} - -void -nsSHEntry::ParentChainChanged(nsIContent *aContent) -{ -} - -class DestroyViewerEvent : public nsRunnable -{ -public: - DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument) - : mViewer(aViewer), - mDocument(aDocument) - {} - - NS_IMETHOD Run() - { - if (mViewer) - mViewer->Destroy(); - return NS_OK; - } - - nsCOMPtr mViewer; - nsCOMPtr mDocument; -}; - void nsSHEntry::RemoveFromBFCacheSync() { - NS_ASSERTION(mContentViewer && mDocument, - "we're not in the bfcache!"); - - nsCOMPtr viewer = mContentViewer; - DropPresentationState(); - - // Warning! The call to DropPresentationState could have dropped the last - // reference to this nsSHEntry, so no accessing members beyond here. - - if (viewer) { - viewer->Destroy(); - } + mShared->RemoveFromBFCacheSync(); } void nsSHEntry::RemoveFromBFCacheAsync() { - NS_ASSERTION(mContentViewer && mDocument, - "we're not in the bfcache!"); - - // Release the reference to the contentviewer asynchronously so that the - // document doesn't get nuked mid-mutation. - - nsCOMPtr evt = - new DestroyViewerEvent(mContentViewer, mDocument); - nsresult rv = NS_DispatchToCurrentThread(evt); - if (NS_FAILED(rv)) { - NS_WARNING("failed to dispatch DestroyViewerEvent"); - } - else { - // Drop presentation. Also ensures that we don't post more then one - // PLEvent. Only do this if we succeeded in posting the event since - // otherwise the document could be torn down mid mutation causing crashes. - DropPresentationState(); - } - // Warning! The call to DropPresentationState could have dropped the last - // reference to this nsSHEntry, so no accessing members beyond here. + mShared->RemoveFromBFCacheAsync(); } nsDocShellEditorData* nsSHEntry::ForgetEditorData() { - return mEditorData.forget(); + // XXX jlebar Check how this is used. + return mShared->mEditorData.forget(); } void nsSHEntry::SetEditorData(nsDocShellEditorData* aData) { - NS_ASSERTION(!(aData && mEditorData), + NS_ASSERTION(!(aData && mShared->mEditorData), "We're going to overwrite an owning ref!"); - if (mEditorData != aData) - mEditorData = aData; + if (mShared->mEditorData != aData) { + mShared->mEditorData = aData; + } } bool nsSHEntry::HasDetachedEditor() { - return mEditorData != nsnull; + return mShared->mEditorData != nsnull; } NS_IMETHODIMP @@ -1023,7 +767,7 @@ nsSHEntry::SetStateData(nsIStructuredCloneContainer *aContainer) NS_IMETHODIMP nsSHEntry::IsDynamicallyAdded(bool* aAdded) { - *aAdded = mDynamicallyCreated; + *aAdded = mShared->mDynamicallyCreated; return NS_OK; } @@ -1046,14 +790,14 @@ nsSHEntry::HasDynamicallyAddedChild(bool* aAdded) NS_IMETHODIMP nsSHEntry::GetDocshellID(PRUint64* aID) { - *aID = mDocShellID; + *aID = mShared->mDocShellID; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetDocshellID(PRUint64 aID) { - mDocShellID = aID; + mShared->mDocShellID = aID; return NS_OK; } @@ -1061,14 +805,13 @@ nsSHEntry::SetDocshellID(PRUint64 aID) NS_IMETHODIMP nsSHEntry::GetLastTouched(PRUint32 *aLastTouched) { - *aLastTouched = mLastTouched; + *aLastTouched = mShared->mLastTouched; return NS_OK; } NS_IMETHODIMP nsSHEntry::SetLastTouched(PRUint32 aLastTouched) { - mLastTouched = aLastTouched; + mShared->mLastTouched = aLastTouched; return NS_OK; } - diff --git a/docshell/shistory/src/nsSHEntry.h b/docshell/shistory/src/nsSHEntry.h index cd44eb0d8e3c..4e3eeee29cd0 100644 --- a/docshell/shistory/src/nsSHEntry.h +++ b/docshell/shistory/src/nsSHEntry.h @@ -42,28 +42,21 @@ // Helper Classes #include "nsCOMPtr.h" +#include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsString.h" -#include "nsAutoPtr.h" // Interfaces needed -#include "nsIContentViewer.h" #include "nsIInputStream.h" -#include "nsILayoutHistoryState.h" #include "nsISHEntry.h" #include "nsISHContainer.h" #include "nsIURI.h" -#include "nsIEnumerator.h" #include "nsIHistoryEntry.h" -#include "nsRect.h" -#include "nsISupportsArray.h" -#include "nsIMutationObserver.h" -#include "nsExpirationTracker.h" -#include "nsDocShellEditorData.h" + +class nsSHEntryShared; class nsSHEntry : public nsISHEntry, public nsISHContainer, - public nsIMutationObserver, public nsISHEntryInternal { public: @@ -75,51 +68,30 @@ public: NS_DECL_NSISHENTRY NS_DECL_NSISHENTRYINTERNAL NS_DECL_NSISHCONTAINER - NS_DECL_NSIMUTATIONOBSERVER void DropPresentationState(); - void Expire(); - - nsExpirationState *GetExpirationState() { return &mExpirationState; } - static nsresult Startup(); static void Shutdown(); private: ~nsSHEntry(); - nsCOMPtr mURI; - nsCOMPtr mReferrerURI; - nsCOMPtr mContentViewer; - nsCOMPtr mDocument; // document currently being observed - nsString mTitle; - nsCOMPtr mPostData; - nsCOMPtr mLayoutHistoryState; - nsCOMArray mChildren; - PRUint32 mLoadType; - PRUint32 mID; - PRInt64 mDocIdentifier; - PRInt32 mScrollPositionX; - PRInt32 mScrollPositionY; - PRPackedBool mURIWasModified; - PRPackedBool mIsFrameNavigation; - PRPackedBool mSaveLayoutState; - PRPackedBool mExpired; - PRPackedBool mSticky; - PRPackedBool mDynamicallyCreated; - nsCString mContentType; - nsCOMPtr mCacheKey; - nsISHEntry * mParent; // weak reference - nsCOMPtr mWindowState; - nsIntRect mViewerBounds; - nsCOMArray mChildShells; - nsCOMPtr mRefreshURIList; - nsCOMPtr mOwner; - nsExpirationState mExpirationState; - nsAutoPtr mEditorData; - PRUint64 mDocShellID; - PRUint32 mLastTouched; + // We share the state in here with other SHEntries which correspond to the + // same document. + nsRefPtr mShared; + + // See nsSHEntry.idl for comments on these members. + nsCOMPtr mURI; + nsCOMPtr mReferrerURI; + nsString mTitle; + nsCOMPtr mPostData; + PRUint32 mLoadType; + PRUint32 mID; + PRInt32 mScrollPositionX; + PRInt32 mScrollPositionY; + nsCOMArray mChildren; + bool mURIWasModified; nsCOMPtr mStateData; }; diff --git a/docshell/shistory/src/nsSHEntryShared.cpp b/docshell/shistory/src/nsSHEntryShared.cpp new file mode 100644 index 000000000000..ba8089d4e6dc --- /dev/null +++ b/docshell/shistory/src/nsSHEntryShared.cpp @@ -0,0 +1,400 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Justin Lebar + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsSHEntryShared.h" +#include "nsISHistory.h" +#include "nsISHistoryInternal.h" +#include "nsIDocument.h" +#include "nsIWebNavigation.h" +#include "nsIContentViewer.h" +#include "nsIDocShellTreeItem.h" +#include "nsISupportsArray.h" +#include "nsDocShellEditorData.h" +#include "nsThreadUtils.h" +#include "nsILayoutHistoryState.h" +#include "prprf.h" + +namespace dom = mozilla::dom; + +namespace { + +PRUint64 gSHEntrySharedID = 0; + +} // anonymous namespace + +// Hardcode this to time out unused content viewers after 30 minutes +// XXX jlebar shouldn't this be a pref? +#define CONTENT_VIEWER_TIMEOUT_SECONDS (30*60) + +typedef nsExpirationTracker HistoryTrackerBase; +class HistoryTracker : public HistoryTrackerBase { +public: + // Expire cached contentviewers after 20-30 minutes in the cache. + HistoryTracker() + : HistoryTrackerBase(1000 * CONTENT_VIEWER_TIMEOUT_SECONDS / 2) + { + } + +protected: + virtual void NotifyExpired(nsSHEntryShared *aObj) { + RemoveObject(aObj); + aObj->Expire(); + } +}; + +static HistoryTracker *gHistoryTracker = nsnull; + +void +nsSHEntryShared::Startup() +{ + gHistoryTracker = new HistoryTracker(); +} + +void +nsSHEntryShared::Shutdown() +{ + delete gHistoryTracker; + gHistoryTracker = nsnull; +} + +nsSHEntryShared::nsSHEntryShared() + : mDocShellID(0) + , mParent(nsnull) + , mIsFrameNavigation(false) + , mSaveLayoutState(true) + , mSticky(true) + , mDynamicallyCreated(false) + , mLastTouched(0) + , mID(gSHEntrySharedID++) + , mExpired(false) + , mViewerBounds(0, 0, 0, 0) +{ +} + +nsSHEntryShared::~nsSHEntryShared() +{ + RemoveFromExpirationTracker(); + +#ifdef DEBUG + // Check that we're not still on track to expire. We shouldn't be, because + // we just removed ourselves! + nsExpirationTracker::Iterator + iterator(gHistoryTracker); + + nsSHEntryShared *elem; + while ((elem = iterator.Next()) != nsnull) { + NS_ASSERTION(elem != this, "Found dead entry still in the tracker!"); + } +#endif + + if (mContentViewer) { + RemoveFromBFCacheSync(); + } +} + +NS_IMPL_ISUPPORTS2(nsSHEntryShared, nsIBFCacheEntry, nsIMutationObserver) + +already_AddRefed +nsSHEntryShared::Duplicate(nsSHEntryShared *aEntry) +{ + nsRefPtr newEntry = new nsSHEntryShared(); + + newEntry->mDocShellID = aEntry->mDocShellID; + newEntry->mChildShells.AppendObjects(aEntry->mChildShells); + newEntry->mOwner = aEntry->mOwner; + newEntry->mParent = aEntry->mParent; + newEntry->mContentType.Assign(aEntry->mContentType); + newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation; + newEntry->mSaveLayoutState = aEntry->mSaveLayoutState; + newEntry->mSticky = aEntry->mSticky; + newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated; + newEntry->mCacheKey = aEntry->mCacheKey; + newEntry->mLastTouched = aEntry->mLastTouched; + + return newEntry.forget(); +} + +void nsSHEntryShared::RemoveFromExpirationTracker() +{ + if (GetExpirationState()->IsTracked()) { + gHistoryTracker->RemoveObject(this); + } +} + +nsresult +nsSHEntryShared::SyncPresentationState() +{ + if (mContentViewer && mWindowState) { + // If we have a content viewer and a window state, we should be ok. + return NS_OK; + } + + DropPresentationState(); + + return NS_OK; +} + +void +nsSHEntryShared::DropPresentationState() +{ + nsRefPtr kungFuDeathGrip = this; + + if (mDocument) { + mDocument->SetBFCacheEntry(nsnull); + mDocument->RemoveMutationObserver(this); + mDocument = nsnull; + } + if (mContentViewer) { + mContentViewer->ClearHistoryEntry(); + } + + RemoveFromExpirationTracker(); + mContentViewer = nsnull; + mSticky = true; + mWindowState = nsnull; + mViewerBounds.SetRect(0, 0, 0, 0); + mChildShells.Clear(); + mRefreshURIList = nsnull; + mEditorData = nsnull; +} + +void +nsSHEntryShared::Expire() +{ + // This entry has timed out. If we still have a content viewer, we need to + // evict it. + if (!mContentViewer) { + return; + } + nsCOMPtr container; + mContentViewer->GetContainer(getter_AddRefs(container)); + nsCOMPtr treeItem = do_QueryInterface(container); + if (!treeItem) { + return; + } + // We need to find the root DocShell since only that object has an + // SHistory and we need the SHistory to evict content viewers + nsCOMPtr root; + treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root)); + nsCOMPtr webNav = do_QueryInterface(root); + nsCOMPtr history; + webNav->GetSessionHistory(getter_AddRefs(history)); + nsCOMPtr historyInt = do_QueryInterface(history); + if (!historyInt) { + return; + } + historyInt->EvictExpiredContentViewerForEntry(this); +} + +nsresult +nsSHEntryShared::SetContentViewer(nsIContentViewer *aViewer) +{ + NS_PRECONDITION(!aViewer || !mContentViewer, + "SHEntryShared already contains viewer"); + + if (mContentViewer || !aViewer) { + DropPresentationState(); + } + + mContentViewer = aViewer; + + if (mContentViewer) { + gHistoryTracker->AddObject(this); + + nsCOMPtr domDoc; + mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); + // Store observed document in strong pointer in case it is removed from + // the contentviewer + mDocument = do_QueryInterface(domDoc); + if (mDocument) { + mDocument->SetBFCacheEntry(this); + mDocument->AddMutationObserver(this); + } + } + + return NS_OK; +} + +nsresult +nsSHEntryShared::RemoveFromBFCacheSync() +{ + NS_ASSERTION(mContentViewer && mDocument, + "we're not in the bfcache!"); + + nsCOMPtr viewer = mContentViewer; + DropPresentationState(); + + // Warning! The call to DropPresentationState could have dropped the last + // reference to this object, so don't access members beyond here. + + if (viewer) { + viewer->Destroy(); + } + + return NS_OK; +} + +class DestroyViewerEvent : public nsRunnable +{ +public: + DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument) + : mViewer(aViewer), + mDocument(aDocument) + {} + + NS_IMETHOD Run() + { + if (mViewer) { + mViewer->Destroy(); + } + return NS_OK; + } + + nsCOMPtr mViewer; + nsCOMPtr mDocument; +}; + +nsresult +nsSHEntryShared::RemoveFromBFCacheAsync() +{ + NS_ASSERTION(mContentViewer && mDocument, + "we're not in the bfcache!"); + + // Release the reference to the contentviewer asynchronously so that the + // document doesn't get nuked mid-mutation. + + nsCOMPtr evt = + new DestroyViewerEvent(mContentViewer, mDocument); + nsresult rv = NS_DispatchToCurrentThread(evt); + if (NS_FAILED(rv)) { + NS_WARNING("failed to dispatch DestroyViewerEvent"); + } else { + // Drop presentation. Only do this if we succeeded in posting the event + // since otherwise the document could be torn down mid-mutation, causing + // crashes. + DropPresentationState(); + } + + // Careful! The call to DropPresentationState could have dropped the last + // reference to this nsSHEntryShared, so don't access members beyond here. + + return NS_OK; +} + +nsresult +nsSHEntryShared::GetID(PRUint64 *aID) +{ + *aID = mID; + return NS_OK; +} + +//***************************************************************************** +// nsSHEntryShared: nsIMutationObserver +//***************************************************************************** + +void +nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode) +{ + NS_NOTREACHED("Document destroyed while we're holding a strong ref to it"); +} + +void +nsSHEntryShared::CharacterDataWillChange(nsIDocument* aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) +{ +} + +void +nsSHEntryShared::CharacterDataChanged(nsIDocument* aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) +{ + RemoveFromBFCacheAsync(); +} + +void +nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument, + dom::Element* aContent, + PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) +{ +} + +void +nsSHEntryShared::AttributeChanged(nsIDocument* aDocument, + dom::Element* aElement, + PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) +{ + RemoveFromBFCacheAsync(); +} + +void +nsSHEntryShared::ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aFirstNewContent, + PRInt32 /* unused */) +{ + RemoveFromBFCacheAsync(); +} + +void +nsSHEntryShared::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 /* unused */) +{ + RemoveFromBFCacheAsync(); +} + +void +nsSHEntryShared::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer, + nsIContent* aPreviousSibling) +{ + RemoveFromBFCacheAsync(); +} + +void +nsSHEntryShared::ParentChainChanged(nsIContent *aContent) +{ +} diff --git a/docshell/shistory/src/nsSHEntryShared.h b/docshell/shistory/src/nsSHEntryShared.h new file mode 100644 index 000000000000..792b7cabfc20 --- /dev/null +++ b/docshell/shistory/src/nsSHEntryShared.h @@ -0,0 +1,124 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Justin Lebar + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSHEntryShared_h__ +#define nsSHEntryShared_h__ + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nsCOMArray.h" +#include "nsIBFCacheEntry.h" +#include "nsIMutationObserver.h" +#include "nsExpirationTracker.h" +#include "nsRect.h" + +class nsSHEntry; +class nsISHEntry; +class nsIDocument; +class nsIContentViewer; +class nsIDocShellTreeItem; +class nsILayoutHistoryState; +class nsISupportsArray; +class nsDocShellEditorData; + +// A document may have multiple SHEntries, either due to hash navigations or +// calls to history.pushState. SHEntries corresponding to the same document +// share many members; in particular, they share state related to the +// back/forward cache. +// +// nsSHEntryShared is the vehicle for this sharing. +class nsSHEntryShared : public nsIBFCacheEntry, + public nsIMutationObserver +{ + public: + static void Startup(); + static void Shutdown(); + + nsSHEntryShared(); + ~nsSHEntryShared(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIMUTATIONOBSERVER + NS_DECL_NSIBFCACHEENTRY + + private: + friend class nsSHEntry; + + friend class HistoryTracker; + friend class nsExpirationTracker; + nsExpirationState *GetExpirationState() { return &mExpirationState; } + + static already_AddRefed Duplicate(nsSHEntryShared *aEntry); + + void RemoveFromExpirationTracker(); + void Expire(); + nsresult SyncPresentationState(); + void DropPresentationState(); + + nsresult SetContentViewer(nsIContentViewer *aViewer); + + // See nsISHEntry.idl for an explanation of these members. + + // These members are copied by nsSHEntryShared::Duplicate(). If you add a + // member here, be sure to update the Duplicate() implementation. + PRUint64 mDocShellID; + nsCOMArray mChildShells; + nsCOMPtr mOwner; + nsISHEntry* mParent; + nsCString mContentType; + bool mIsFrameNavigation; + bool mSaveLayoutState; + bool mSticky; + bool mDynamicallyCreated; + nsCOMPtr mCacheKey; + PRUint32 mLastTouched; + + // These members aren't copied by nsSHEntryShared::Duplicate() because + // they're specific to a particular content viewer. + PRUint64 mID; + nsCOMPtr mContentViewer; + nsCOMPtr mDocument; + nsCOMPtr mLayoutHistoryState; + bool mExpired; + nsCOMPtr mWindowState; + nsIntRect mViewerBounds; + nsCOMPtr mRefreshURIList; + nsExpirationState mExpirationState; + nsAutoPtr mEditorData; +}; + +#endif diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp index 4200307da8da..c211dbdf2e55 100644 --- a/docshell/shistory/src/nsSHistory.cpp +++ b/docshell/shistory/src/nsSHistory.cpp @@ -72,12 +72,10 @@ using namespace mozilla; #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" #define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers" -#define PREF_SHISTORY_OPTIMIZE_EVICTION "browser.sessionhistory.optimize_eviction" static const char* kObservedPrefs[] = { PREF_SHISTORY_SIZE, PREF_SHISTORY_MAX_TOTAL_VIEWERS, - PREF_SHISTORY_OPTIMIZE_EVICTION, nsnull }; @@ -90,16 +88,46 @@ static PRCList gSHistoryList; // means we will calculate how many viewers to cache based on total memory PRInt32 nsSHistory::sHistoryMaxTotalViewers = -1; -// Whether we should optimize the search for which entry to evict, -// by evicting older entries first. See entryLastTouched in -// nsSHistory::EvictGlobalContentViewer(). -// NB: After 4.0, we should remove this option and the corresponding -// pref - optimization should always be used -static bool gOptimizeEviction = false; // A counter that is used to be able to know the order in which // entries were touched, so that we can evict older entries first. static PRUint32 gTouchCounter = 0; +static PRLogModuleInfo* gLogModule = PR_LOG_DEFINE("nsSHistory"); +#define LOG(format) PR_LOG(gLogModule, PR_LOG_DEBUG, format) + +// This macro makes it easier to print a log message which includes a URI's +// spec. Example use: +// +// nsIURI *uri = [...]; +// LOG_SPEC(("The URI is %s.", _spec), uri); +// +#define LOG_SPEC(format, uri) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(gLogModule, PR_LOG_DEBUG)) { \ + nsCAutoString _specStr(NS_LITERAL_CSTRING("(null)"));\ + if (uri) { \ + uri->GetSpec(_specStr); \ + } \ + const char* _spec = _specStr.get(); \ + LOG(format); \ + } \ + PR_END_MACRO + +// This macro makes it easy to log a message including an SHEntry's URI. +// For example: +// +// nsCOMPtr shentry = [...]; +// LOG_SHENTRY_SPEC(("shentry %p has uri %s.", shentry.get(), _spec), shentry); +// +#define LOG_SHENTRY_SPEC(format, shentry) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(gLogModule, PR_LOG_DEBUG)) { \ + nsCOMPtr uri; \ + shentry->GetURI(getter_AddRefs(uri)); \ + LOG_SPEC(format, uri); \ + } \ + PR_END_MACRO + enum HistCmd{ HIST_CMD_BACK, HIST_CMD_FORWARD, @@ -134,15 +162,60 @@ nsSHistoryObserver::Observe(nsISupports *aSubject, const char *aTopic, { if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { nsSHistory::UpdatePrefs(); - nsSHistory::EvictGlobalContentViewer(); + nsSHistory::GloballyEvictContentViewers(); } else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) || !strcmp(aTopic, "memory-pressure")) { - nsSHistory::EvictAllContentViewersGlobally(); + nsSHistory::GloballyEvictAllContentViewers(); } return NS_OK; } +namespace { + +already_AddRefed +GetContentViewerForTransaction(nsISHTransaction *aTrans) +{ + nsCOMPtr entry; + aTrans->GetSHEntry(getter_AddRefs(entry)); + if (!entry) { + return nsnull; + } + + nsCOMPtr ownerEntry; + nsCOMPtr viewer; + entry->GetAnyContentViewer(getter_AddRefs(ownerEntry), + getter_AddRefs(viewer)); + return viewer.forget(); +} + +void +EvictContentViewerForTransaction(nsISHTransaction *aTrans) +{ + nsCOMPtr entry; + aTrans->GetSHEntry(getter_AddRefs(entry)); + nsCOMPtr viewer; + nsCOMPtr ownerEntry; + entry->GetAnyContentViewer(getter_AddRefs(ownerEntry), + getter_AddRefs(viewer)); + if (viewer) { + NS_ASSERTION(ownerEntry, + "Content viewer exists but its SHEntry is null"); + + LOG_SHENTRY_SPEC(("Evicting content viewer 0x%p for " + "owning SHEntry 0x%p at %s.", + viewer.get(), ownerEntry.get(), _spec), ownerEntry); + + // Drop the presentation state before destroying the viewer, so that + // document teardown is able to correctly persist the state. + ownerEntry->SetContentViewer(nsnull); + ownerEntry->SyncPresentationState(); + viewer->Destroy(); + } +} + +} // anonymous namespace + //***************************************************************************** //*** nsSHistory: Object Management //***************************************************************************** @@ -240,7 +313,6 @@ nsSHistory::UpdatePrefs() Preferences::GetInt(PREF_SHISTORY_SIZE, &gHistoryMaxSize); Preferences::GetInt(PREF_SHISTORY_MAX_TOTAL_VIEWERS, &sHistoryMaxTotalViewers); - Preferences::GetBool(PREF_SHISTORY_OPTIMIZE_EVICTION, &gOptimizeEviction); // If the pref is negative, that means we calculate how many viewers // we think we should cache, based on total memory if (sHistoryMaxTotalViewers < 0) { @@ -689,12 +761,12 @@ nsSHistory::GetListener(nsISHistoryListener ** aListener) } NS_IMETHODIMP -nsSHistory::EvictContentViewers(PRInt32 aPreviousIndex, PRInt32 aIndex) +nsSHistory::EvictOutOfRangeContentViewers(PRInt32 aIndex) { // Check our per SHistory object limit in the currently navigated SHistory - EvictWindowContentViewers(aPreviousIndex, aIndex); + EvictOutOfRangeWindowContentViewers(aIndex); // Check our total limit across all SHistory objects - EvictGlobalContentViewer(); + GloballyEvictContentViewers(); return NS_OK; } @@ -703,7 +775,14 @@ nsSHistory::EvictAllContentViewers() { // XXXbz we don't actually do a good job of evicting things as we should, so // we might have viewers quite far from mIndex. So just evict everything. - EvictContentViewersInRange(0, mLength); + nsCOMPtr trans = mListRoot; + while (trans) { + EvictContentViewerForTransaction(trans); + + nsISHTransaction *temp = trans; + temp->GetNext(getter_AddRefs(trans)); + } + return NS_OK; } @@ -835,103 +914,78 @@ nsSHistory::ReloadCurrentEntry() } void -nsSHistory::EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex) +nsSHistory::EvictOutOfRangeWindowContentViewers(PRInt32 aIndex) { - // To enforce the per SHistory object limit on cached content viewers, we - // need to release all of the content viewers that are no longer in the - // "window" that now ends/begins at aToIndex. Existing content viewers - // should be in the window from - // aFromIndex - gHistoryMaxViewers to aFromIndex + gHistoryMaxViewers + // XXX rename method to EvictContentViewersExceptAroundIndex, or something. + + // We need to release all content viewers that are no longer in the range // - // We make the assumption that entries outside this range have no viewers so - // that we don't have to walk the whole entire session history checking for - // content viewers. + // aIndex - gHistoryMaxViewers to aIndex + gHistoryMaxViewers + // + // to ensure that this SHistory object isn't responsible for more than + // gHistoryMaxViewers content viewers. But our job is complicated by the + // fact that two transactions which are related by either hash navigations or + // history.pushState will have the same content viewer. + // + // To illustrate the issue, suppose gHistoryMaxViewers = 3 and we have four + // linked transactions in our history. Suppose we then add a new content + // viewer and call into this function. So the history looks like: + // + // A A A A B + // + * + // + // where the letters are content viewers and + and * denote the beginning and + // end of the range aIndex +/- gHistoryMaxViewers. + // + // Although one copy of the content viewer A exists outside the range, we + // don't want to evict A, because it has other copies in range! + // + // We therefore adjust our eviction strategy to read: + // + // Evict each content viewer outside the range aIndex -/+ + // gHistoryMaxViewers, unless that content viewer also appears within the + // range. + // + // (Note that it's entirely legal to have two copies of one content viewer + // separated by a different content viewer -- call pushState twice, go back + // once, and refresh -- so we can't rely on identical viewers only appearing + // adjacent to one another.) - // This can happen on the first load of a page in a particular window - if (aFromIndex < 0 || aToIndex < 0) { + if (aIndex < 0) { return; } - NS_ASSERTION(aFromIndex < mLength, "aFromIndex is out of range"); - NS_ASSERTION(aToIndex < mLength, "aToIndex is out of range"); - if (aFromIndex >= mLength || aToIndex >= mLength) { + NS_ASSERTION(aIndex < mLength, "aIndex is out of range"); + if (aIndex >= mLength) { return; } - // These indices give the range of SHEntries whose content viewers will be - // evicted - PRInt32 startIndex, endIndex; - if (aToIndex > aFromIndex) { // going forward - endIndex = aToIndex - gHistoryMaxViewers; - if (endIndex <= 0) { - return; - } - startIndex = NS_MAX(0, aFromIndex - gHistoryMaxViewers); - } else { // going backward - startIndex = aToIndex + gHistoryMaxViewers + 1; - if (startIndex >= mLength) { - return; - } - endIndex = NS_MIN(mLength, aFromIndex + gHistoryMaxViewers + 1); - } + // Calculate the range that's safe from eviction. + PRInt32 startSafeIndex = PR_MAX(0, aIndex - gHistoryMaxViewers); + PRInt32 endSafeIndex = PR_MIN(mLength, aIndex + gHistoryMaxViewers); -#ifdef DEBUG + LOG(("EvictOutOfRangeWindowContentViewers(index=%d), " + "mLength=%d. Safe range [%d, %d]", + aIndex, mLength, startSafeIndex, endSafeIndex)); + + // The content viewers in range aIndex -/+ gHistoryMaxViewers will not be + // evicted. Collect a set of them so we don't accidentally evict one of them + // if it appears outside this range. + nsCOMArray safeViewers; nsCOMPtr trans; + GetTransactionAtIndex(startSafeIndex, getter_AddRefs(trans)); + for (PRUint32 i = startSafeIndex; trans && i <= endSafeIndex; i++) { + nsCOMPtr viewer = GetContentViewerForTransaction(trans); + safeViewers.AppendObject(viewer); + nsISHTransaction *temp = trans; + temp->GetNext(getter_AddRefs(trans)); + } + + // Walk the SHistory list and evict any content viewers that aren't safe. GetTransactionAtIndex(0, getter_AddRefs(trans)); - - // Walk the full session history and check that entries outside the window - // around aFromIndex have no content viewers - for (PRInt32 i = 0; trans && i < mLength; ++i) { - if (i < aFromIndex - gHistoryMaxViewers || - i > aFromIndex + gHistoryMaxViewers) { - nsCOMPtr entry; - trans->GetSHEntry(getter_AddRefs(entry)); - nsCOMPtr viewer; - nsCOMPtr ownerEntry; - entry->GetAnyContentViewer(getter_AddRefs(ownerEntry), - getter_AddRefs(viewer)); - NS_WARN_IF_FALSE(!viewer, - "ContentViewer exists outside gHistoryMaxViewer range"); - } - - nsISHTransaction *temp = trans; - temp->GetNext(getter_AddRefs(trans)); - } -#endif - - EvictContentViewersInRange(startIndex, endIndex); -} - -void -nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd) -{ - nsCOMPtr trans; - GetTransactionAtIndex(aStart, getter_AddRefs(trans)); - - for (PRInt32 i = aStart; trans && i < aEnd; ++i) { - nsCOMPtr entry; - trans->GetSHEntry(getter_AddRefs(entry)); - nsCOMPtr viewer; - nsCOMPtr ownerEntry; - entry->GetAnyContentViewer(getter_AddRefs(ownerEntry), - getter_AddRefs(viewer)); - if (viewer) { - NS_ASSERTION(ownerEntry, - "ContentViewer exists but its SHEntry is null"); -#ifdef DEBUG_PAGE_CACHE - nsCOMPtr uri; - ownerEntry->GetURI(getter_AddRefs(uri)); - nsCAutoString spec; - if (uri) - uri->GetSpec(spec); - - printf("per SHistory limit: evicting content viewer: %s\n", spec.get()); -#endif - - // Drop the presentation state before destroying the viewer, so that - // document teardown is able to correctly persist the state. - ownerEntry->SetContentViewer(nsnull); - ownerEntry->SyncPresentationState(); - viewer->Destroy(); + while (trans) { + nsCOMPtr viewer = GetContentViewerForTransaction(trans); + if (safeViewers.IndexOf(viewer) == -1) { + EvictContentViewerForTransaction(trans); } nsISHTransaction *temp = trans; @@ -939,138 +993,153 @@ nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd) } } -// static -void -nsSHistory::EvictGlobalContentViewer() +namespace { + +class TransactionAndDistance { - // true until the total number of content viewers is <= total max - // The usual case is that we only need to evict one content viewer. - // However, if somebody resets the pref value, we might occasionally - // need to evict more than one. - bool shouldTryEviction = true; - while (shouldTryEviction) { - // Walk through our list of SHistory objects, looking for content - // viewers in the possible active window of all of the SHEntry objects. - // Keep track of the SHEntry object that has a ContentViewer and is - // farthest from the current focus in any SHistory object. The - // ContentViewer associated with that SHEntry will be evicted - PRInt32 distanceFromFocus = 0; - PRUint32 candidateLastTouched = 0; - nsCOMPtr evictFromSHE; - nsCOMPtr evictViewer; - PRInt32 totalContentViewers = 0; - nsSHistory* shist = static_cast - (PR_LIST_HEAD(&gSHistoryList)); - while (shist != &gSHistoryList) { - // Calculate the window of SHEntries that could possibly have a content - // viewer. There could be up to gHistoryMaxViewers content viewers, - // but we don't know whether they are before or after the mIndex position - // in the SHEntry list. Just check both sides, to be safe. - PRInt32 startIndex = NS_MAX(0, shist->mIndex - gHistoryMaxViewers); - PRInt32 endIndex = NS_MIN(shist->mLength - 1, - shist->mIndex + gHistoryMaxViewers); - nsCOMPtr trans; - shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans)); +public: + TransactionAndDistance(nsISHTransaction *aTrans, PRUint32 aDist) + : mTransaction(aTrans) + , mDistance(aDist) + { + mViewer = GetContentViewerForTransaction(aTrans); + NS_ASSERTION(mViewer, "Transaction should have a content viewer"); - for (PRInt32 i = startIndex; trans && i <= endIndex; ++i) { - nsCOMPtr entry; - trans->GetSHEntry(getter_AddRefs(entry)); - nsCOMPtr viewer; - nsCOMPtr ownerEntry; - entry->GetAnyContentViewer(getter_AddRefs(ownerEntry), - getter_AddRefs(viewer)); + nsCOMPtr shentry; + mTransaction->GetSHEntry(getter_AddRefs(shentry)); - PRUint32 entryLastTouched = 0; - if (gOptimizeEviction) { - nsCOMPtr entryInternal = do_QueryInterface(entry); - if (entryInternal) { - // Find when this entry was last activated - entryInternal->GetLastTouched(&entryLastTouched); - } - } - -#ifdef DEBUG_PAGE_CACHE - nsCOMPtr uri; - if (ownerEntry) { - ownerEntry->GetURI(getter_AddRefs(uri)); - } else { - entry->GetURI(getter_AddRefs(uri)); - } - nsCAutoString spec; - if (uri) { - uri->GetSpec(spec); - printf("Considering for eviction: %s\n", spec.get()); - } -#endif - - // This SHEntry has a ContentViewer, so check how far away it is from - // the currently used SHEntry within this SHistory object - if (viewer) { - PRInt32 distance = NS_ABS(shist->mIndex - i); - -#ifdef DEBUG_PAGE_CACHE - printf("Has a cached content viewer: %s\n", spec.get()); - printf("mIndex: %d i: %d\n", shist->mIndex, i); -#endif - totalContentViewers++; - - // If this entry is further away from focus than any previously found - // or at the same distance but it is longer time since it was activated - // then take this entry as the new candiate for eviction - if (distance > distanceFromFocus || (distance == distanceFromFocus && candidateLastTouched > entryLastTouched)) { - -#ifdef DEBUG_PAGE_CACHE - printf("Choosing as new eviction candidate: %s\n", spec.get()); -#endif - candidateLastTouched = entryLastTouched; - distanceFromFocus = distance; - evictFromSHE = ownerEntry; - evictViewer = viewer; - } - } - nsISHTransaction* temp = trans; - temp->GetNext(getter_AddRefs(trans)); - } - shist = static_cast(PR_NEXT_LINK(shist)); - } - -#ifdef DEBUG_PAGE_CACHE - printf("Distance from focus: %d\n", distanceFromFocus); - printf("Total max viewers: %d\n", sHistoryMaxTotalViewers); - printf("Total number of viewers: %d\n", totalContentViewers); -#endif - - if (totalContentViewers > sHistoryMaxTotalViewers && evictViewer) { -#ifdef DEBUG_PAGE_CACHE - nsCOMPtr uri; - evictFromSHE->GetURI(getter_AddRefs(uri)); - nsCAutoString spec; - if (uri) { - uri->GetSpec(spec); - printf("Evicting content viewer: %s\n", spec.get()); - } -#endif - - // Drop the presentation state before destroying the viewer, so that - // document teardown is able to correctly persist the state. - evictFromSHE->SetContentViewer(nsnull); - evictFromSHE->SyncPresentationState(); - evictViewer->Destroy(); - - // If we only needed to evict one content viewer, then we are done. - // Otherwise, continue evicting until we reach the max total limit. - if (totalContentViewers - sHistoryMaxTotalViewers == 1) { - shouldTryEviction = false; - } + nsCOMPtr shentryInternal = do_QueryInterface(shentry); + if (shentryInternal) { + shentryInternal->GetLastTouched(&mLastTouched); } else { - // couldn't find a content viewer to evict, so we are done - shouldTryEviction = false; + NS_WARNING("Can't cast to nsISHEntryInternal?"); + mLastTouched = 0; } - } // while shouldTryEviction + } + + bool operator<(const TransactionAndDistance &aOther) const + { + // Compare distances first, and fall back to last-accessed times. + if (aOther.mDistance != this->mDistance) { + return this->mDistance < aOther.mDistance; + } + + return this->mLastTouched < aOther.mLastTouched; + } + + bool operator==(const TransactionAndDistance &aOther) const + { + // This is a little silly; we need == so the default comaprator can be + // instantiated, but this function is never actually called when we sort + // the list of TransactionAndDistance objects. + return aOther.mDistance == this->mDistance && + aOther.mLastTouched == this->mLastTouched; + } + + nsCOMPtr mTransaction; + nsCOMPtr mViewer; + PRUint32 mLastTouched; + PRInt32 mDistance; +}; + +} // anonymous namespace + +//static +void +nsSHistory::GloballyEvictContentViewers() +{ + // First, collect from each SHistory object the transactions which have a + // cached content viewer. Associate with each transaction its distance from + // its SHistory's current index. + + nsTArray transactions; + + nsSHistory *shist = static_cast(PR_LIST_HEAD(&gSHistoryList)); + while (shist != &gSHistoryList) { + + // Maintain a list of the transactions which have viewers and belong to + // this particular shist object. We'll add this list to the global list, + // |transactions|, eventually. + nsTArray shTransactions; + + // Content viewers are likely to exist only within shist->mIndex -/+ + // gHistoryMaxViewers, so only search within that range. + // + // A content viewer might exist outside that range due to either: + // + // * history.pushState or hash navigations, in which case a copy of the + // content viewer should exist within the range, or + // + // * bugs which cause us not to call nsSHistory::EvictContentViewers() + // often enough. Once we do call EvictContentViewers() for the + // SHistory object in question, we'll do a full search of its history + // and evict the out-of-range content viewers, so we don't bother here. + // + PRInt32 startIndex = NS_MAX(0, shist->mIndex - gHistoryMaxViewers); + PRInt32 endIndex = NS_MIN(shist->mLength - 1, + shist->mIndex + gHistoryMaxViewers); + nsCOMPtr trans; + shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans)); + for (PRInt32 i = startIndex; trans && i <= endIndex; i++) { + nsCOMPtr contentViewer = + GetContentViewerForTransaction(trans); + + if (contentViewer) { + // Because one content viewer might belong to multiple SHEntries, we + // have to search through shTransactions to see if we already know + // about this content viewer. If we find the viewer, update its + // distance from the SHistory's index and continue. + bool found = false; + for (PRUint32 j = 0; j < shTransactions.Length(); j++) { + TransactionAndDistance &container = shTransactions[j]; + if (container.mViewer == contentViewer) { + container.mDistance = PR_MIN(container.mDistance, + PR_ABS(i - shist->mIndex)); + found = true; + break; + } + } + + // If we didn't find a TransactionAndDistance for this content viewer, make a new + // one. + if (!found) { + TransactionAndDistance container(trans, PR_ABS(i - shist->mIndex)); + shTransactions.AppendElement(container); + } + } + + nsISHTransaction *temp = trans; + temp->GetNext(getter_AddRefs(trans)); + } + + // We've found all the transactions belonging to shist which have viewers. + // Add those transactions to our global list and move on. + transactions.AppendElements(shTransactions); + shist = static_cast(PR_NEXT_LINK(shist)); + } + + // We now have collected all cached content viewers. First check that we + // have enough that we actually need to evict some. + if ((PRInt32)transactions.Length() <= sHistoryMaxTotalViewers) { + return; + } + + // If we need to evict, sort our list of transactions and evict the largest + // ones. (We could of course get better algorithmic complexity here by using + // a heap or something more clever. But sHistoryMaxTotalViewers isn't large, + // so let's not worry about it.) + transactions.Sort(); + + for (PRInt32 i = transactions.Length() - 1; + i >= sHistoryMaxTotalViewers; --i) { + + EvictContentViewerForTransaction(transactions[i].mTransaction); + + } } -NS_IMETHODIMP -nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry) +nsresult +nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry *aEntry) { PRInt32 startIndex = NS_MAX(0, mIndex - gHistoryMaxViewers); PRInt32 endIndex = NS_MIN(mLength - 1, @@ -1082,8 +1151,11 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry) for (i = startIndex; trans && i <= endIndex; ++i) { nsCOMPtr entry; trans->GetSHEntry(getter_AddRefs(entry)); - if (entry == aEntry) + + // Does entry have the same BFCacheEntry as the argument to this method? + if (entry->HasBFCacheEntry(aEntry)) { break; + } nsISHTransaction *temp = trans; temp->GetNext(getter_AddRefs(trans)); @@ -1091,21 +1163,13 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry) if (i > endIndex) return NS_OK; - NS_ASSERTION(i != mIndex, "How did the current session entry expire?"); - if (i == mIndex) + if (i == mIndex) { + NS_WARNING("How did the current SHEntry expire?"); return NS_OK; - - // We evict content viewers for the expired entry and any other entries that - // we would have to go through the expired entry to get to (i.e. the entries - // that have the expired entry between them and the current entry). Those - // other entries should have timed out already, actually, but this is just - // to be on the safe side. - if (i < mIndex) { - EvictContentViewersInRange(startIndex, i + 1); - } else { - EvictContentViewersInRange(i, endIndex + 1); } - + + EvictContentViewerForTransaction(trans); + return NS_OK; } @@ -1116,11 +1180,11 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry) //static void -nsSHistory::EvictAllContentViewersGlobally() +nsSHistory::GloballyEvictAllContentViewers() { PRInt32 maxViewers = sHistoryMaxTotalViewers; sHistoryMaxTotalViewers = 0; - EvictGlobalContentViewer(); + GloballyEvictContentViewers(); sHistoryMaxTotalViewers = maxViewers; } diff --git a/docshell/shistory/src/nsSHistory.h b/docshell/shistory/src/nsSHistory.h index 1efeb8cfa209..7bf6d69c0455 100644 --- a/docshell/shistory/src/nsSHistory.h +++ b/docshell/shistory/src/nsSHistory.h @@ -101,12 +101,11 @@ protected: nsresult PrintHistory(); #endif - // Evict the viewers at indices between aStartIndex and aEndIndex, - // including aStartIndex but not aEndIndex. - void EvictContentViewersInRange(PRInt32 aStartIndex, PRInt32 aEndIndex); - void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex); - static void EvictGlobalContentViewer(); - static void EvictAllContentViewersGlobally(); + // Evict content viewers in this window which don't lie in the "safe" range + // around aIndex. + void EvictOutOfRangeWindowContentViewers(PRInt32 aIndex); + static void GloballyEvictContentViewers(); + static void GloballyEvictAllContentViewers(); // Calculates a max number of total // content viewers to cache, based on amount of total memory diff --git a/docshell/test/Makefile.in b/docshell/test/Makefile.in index 272973d9dd3f..e8ce5c3e5abc 100644 --- a/docshell/test/Makefile.in +++ b/docshell/test/Makefile.in @@ -119,6 +119,7 @@ _TEST_FILES = \ test_bug669671.html \ file_bug669671.sjs \ test_bug675587.html \ + test_bfcache_plus_hash.html \ test_bug680257.html \ file_bug680257.html \ $(NULL) diff --git a/docshell/test/chrome/bug396519_window.xul b/docshell/test/chrome/bug396519_window.xul index d45e07cd90c7..179e094633c0 100644 --- a/docshell/test/chrome/bug396519_window.xul +++ b/docshell/test/chrome/bug396519_window.xul @@ -50,6 +50,9 @@ const LISTEN_EVENTS = ["pageshow"]; + const Cc = Components.classes; + const Ci = Components.interfaces; + var gBrowser; var gTestCount = 0; var gTestsIterator; @@ -96,6 +99,23 @@ QueryInterface(Components.interfaces.nsISHEntry); is(!!shEntry.contentViewer, gExpected[i], "content viewer "+i+", test "+gTestCount); } + + // Make sure none of the SHEntries share bfcache entries with one + // another. + for (var i = 0; i < history.count; i++) { + for (var j = 0; j < history.count; j++) { + if (j == i) + continue; + + let shentry1 = history.getEntryAtIndex(i, false) + .QueryInterface(Ci.nsISHEntry); + let shentry2 = history.getEntryAtIndex(j, false) + .QueryInterface(Ci.nsISHEntry); + ok(!shentry1.sharesDocumentWith(shentry2), + 'Test ' + gTestCount + ': shentry[' + i + "] shouldn't " + + "share document with shentry[" + j + ']'); + } + } } else { is(history.count, gExpected.length, "Wrong history length in test "+gTestCount); diff --git a/docshell/test/chrome/docshell_helpers.js b/docshell/test/chrome/docshell_helpers.js index 0c078efa6871..29ac35fce897 100755 --- a/docshell/test/chrome/docshell_helpers.js +++ b/docshell/test/chrome/docshell_helpers.js @@ -342,7 +342,6 @@ function finish() { // If the test changed the value of max_total_viewers via a call to // enableBFCache(), then restore it now. if (typeof(gOrigMaxTotalViewers) != "undefined") { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); prefs.setIntPref("browser.sessionhistory.max_total_viewers", @@ -425,7 +424,6 @@ function waitForTrue(fn, onWaitComplete, timeout) { * to 0 (disabled), if a number, set it to that specific number */ function enableBFCache(enable) { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); diff --git a/docshell/test/test_bfcache_plus_hash.html b/docshell/test/test_bfcache_plus_hash.html new file mode 100644 index 000000000000..c8f3765135bd --- /dev/null +++ b/docshell/test/test_bfcache_plus_hash.html @@ -0,0 +1,120 @@ + + + + + Test for Bug 646641 + + + + + +Mozilla Bug 646641 +

+ +
+
+
+ + diff --git a/dom/base/ConsoleAPI.js b/dom/base/ConsoleAPI.js index 6ae372668d23..03eeaca0dcdb 100644 --- a/dom/base/ConsoleAPI.js +++ b/dom/base/ConsoleAPI.js @@ -201,6 +201,9 @@ ConsoleAPI.prototype = { } let args = Array.prototype.slice.call(aArguments); let format = args.shift(); + if (typeof format != "string") { + return aArguments; + } // Format specification regular expression. let pattern = /%(\d*).?(\d*)[a-zA-Z]/g; let processed = format.replace(pattern, function CA_PA_substitute(spec) { diff --git a/dom/base/domerr.msg b/dom/base/domerr.msg index b9d6231de0af..450e7d459585 100644 --- a/dom/base/domerr.msg +++ b/dom/base/domerr.msg @@ -95,9 +95,11 @@ DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR, "A mutation operation was at DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR, "A request was placed against a transaction which is currently not active, or which is finished.") DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, "A request was aborted, for example through a call to IDBTransaction.abort.") DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR, "A mutation operation was attempted in a READ_ONLY transaction.") -DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.") -DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR, "The operation failed because of some temporary problems. The failed operation might be able to succeed when the operation is retried without any intervention by application-level functionality.") DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR, "A lock for the transaction could not be obtained in a reasonable time.") +DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR, "The current transaction exceeded its quota limitations.") +DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_VERSION_ERR, "The operation failed because the stored database is a higher version than the version requested.") + +DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.") DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR, "The current transaction was automatically rolled back by the database because of deadlock or other transaction serialization failures.") /* DOM error codes defined by us */ diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index df67fd021651..48e196b027c4 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1450,6 +1450,8 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(WebGLExtensionStandardDerivatives, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -1505,7 +1507,7 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeRequest, nsDOMGenericSH, + NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(IDBDatabaseException, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -3986,6 +3988,10 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext) + DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest) DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest) DOM_CLASSINFO_MAP_END @@ -4087,8 +4093,8 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeRequest, nsIIDBVersionChangeRequest) - DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeRequest) + DOM_CLASSINFO_MAP_BEGIN(IDBOpenDBRequest, nsIIDBOpenDBRequest) + DOM_CLASSINFO_MAP_ENTRY(nsIIDBOpenDBRequest) DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_END @@ -7980,6 +7986,31 @@ nsNamedNodeMapSH::GetNamedItem(nsISupports *aNative, const nsAString& aName, // HTMLCollection helper +nsresult +nsHTMLCollectionSH::PreCreate(nsISupports *nativeObj, JSContext *cx, + JSObject *globalObj, JSObject **parentObj) +{ + nsIHTMLCollection* list = static_cast(nativeObj); +#ifdef DEBUG + { + nsCOMPtr list_qi = do_QueryInterface(nativeObj); + + // If this assertion fires the QI implementation for the object in + // question doesn't use the nsIHTMLCollection pointer as the nsISupports + // pointer. That must be fixed, or we'll crash... + NS_ASSERTION(list_qi == list, "Uh, fix QI!"); + } +#endif + + nsINode* native_parent = list->GetParentObject(); + + nsresult rv = + WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_SUCCESS_ALLOW_SLIM_WRAPPERS; +} + nsresult nsHTMLCollectionSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 *length) diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 15974b5e5be2..43ecee501d42 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -732,6 +732,9 @@ protected: nsresult *aResult); public: + NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, + JSObject *globalObj, JSObject **parentObj); + static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsHTMLCollectionSH(aData); diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 5f532ea5884c..6c79490b18c9 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -472,6 +472,7 @@ DOMCI_CLASS(WebGLUniformLocation) DOMCI_CLASS(WebGLActiveInfo) DOMCI_CLASS(WebGLExtension) DOMCI_CLASS(WebGLExtensionStandardDerivatives) +DOMCI_CLASS(WebGLExtensionLoseContext) DOMCI_CLASS(PaintRequest) DOMCI_CLASS(PaintRequestList) @@ -506,7 +507,7 @@ DOMCI_CLASS(IDBCursorWithValue) DOMCI_CLASS(IDBKeyRange) DOMCI_CLASS(IDBIndex) DOMCI_CLASS(IDBVersionChangeEvent) -DOMCI_CLASS(IDBVersionChangeRequest) +DOMCI_CLASS(IDBOpenDBRequest) DOMCI_CLASS(IDBDatabaseException) DOMCI_CLASS(Touch) diff --git a/dom/base/nsDOMError.h b/dom/base/nsDOMError.h index 2b0ba1351a07..2715b70dd4bb 100644 --- a/dom/base/nsDOMError.h +++ b/dom/base/nsDOMError.h @@ -100,10 +100,12 @@ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,7) #define NS_ERROR_DOM_INDEXEDDB_ABORT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,8) #define NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,9) -#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10) -#define NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11) -#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12) -#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,13) +#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10) +#define NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11) +#define NS_ERROR_DOM_INDEXEDDB_VERSION_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12) + +#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1001) +#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1002) /* DOM error codes defined by us */ diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 2d95dd6c660a..a6a2d676e5d4 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1941,3 +1941,25 @@ nsDOMWindowUtils::GetMayHaveTouchEventListeners(bool* aResult) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResult) +{ + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsresult rv; + nsCOMPtr content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* frame = content->GetPrimaryFrame(); + + if (!frame) { + *aResult = false; + return NS_OK; + } + + *aResult = frame->CheckAndClearPaintedState(); + return NS_OK; +} + diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 49f1205e8d4b..21674d577cc9 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1442,8 +1442,7 @@ nsFocusManager::CheckIfFocusable(nsIContent* aContent, PRUint32 aFlags) // HTML areas do not have their own frame, and the img frame we get from // GetPrimaryFrame() is not relevant as to whether it is focusable or // not, so we have to do all the relevant checks manually for them. - return frame->AreAncestorViewsVisible() && - frame->GetStyleVisibility()->IsVisible() && + return frame->IsVisibleConsideringAncestors() && aContent->IsFocusable() ? aContent : nsnull; } @@ -2980,7 +2979,8 @@ nsFocusManager::GetRootForFocus(nsPIDOMWindow* aWindow, TabParent* nsFocusManager::GetRemoteForContent(nsIContent* aContent) { if (!aContent || - aContent->Tag() != nsGkAtoms::browser || + (aContent->Tag() != nsGkAtoms::browser && + aContent->Tag() != nsGkAtoms::iframe) || !aContent->IsXUL() || !aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote, nsGkAtoms::_true, eIgnoreCase)) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 15e1fcaace1b..e560081dd8df 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1817,6 +1817,34 @@ WindowStateHolder::~WindowStateHolder() NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) + +struct ReparentWaiverClosure +{ + JSContext *mCx; + JSObject *mNewInner; +}; + +static JSDHashOperator +ReparentWaiverWrappers(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + ReparentWaiverClosure *closure = static_cast(arg); + JSObject *value = static_cast(hdr)->value; + + // We reparent wrappers that have as their parent an inner window whose + // outer has the new inner window as its current inner. + JSObject *parent = JS_GetParent(closure->mCx, value); + JSObject *outer = JS_ObjectToOuterObject(closure->mCx, parent); + if (outer) { + JSObject *inner = JS_ObjectToInnerObject(closure->mCx, outer); + if (inner == closure->mNewInner && inner != parent) + JS_SetParent(closure->mCx, value, closure->mNewInner); + } else { + JS_ClearPendingException(closure->mCx); + } + return JS_DHASH_NEXT; +} + nsresult nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsISupports* aState, @@ -2163,6 +2191,19 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject); mContext->SetOuterObject(mJSObject); + + JSCompartment *compartment = js::GetObjectCompartment(mJSObject); + xpc::CompartmentPrivate *priv = + static_cast(JS_GetCompartmentPrivate(cx, compartment)); + if (priv && priv->waiverWrapperMap) { + NS_ASSERTION(!JS_IsExceptionPending(cx), + "We might overwrite a pending exception!"); + ReparentWaiverClosure closure = { + cx, + newInnerWindow->mJSObject + }; + priv->waiverWrapperMap->Enumerate(ReparentWaiverWrappers, &closure); + } } } @@ -7421,9 +7462,18 @@ nsGlobalWindow::GetListenerManager(bool aCreateIfNotFound) nsIScriptContext* nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv) { - nsIScriptContext* scx = GetContext(); - *aRv = scx ? NS_OK : NS_ERROR_UNEXPECTED; - return scx; + *aRv = NS_ERROR_UNEXPECTED; + if (IsInnerWindow()) { + nsPIDOMWindow* outer = GetOuterWindow(); + NS_ENSURE_TRUE(outer && outer->GetCurrentInnerWindow() == this, nsnull); + } + + nsIScriptContext* scx; + if ((scx = GetContext())) { + *aRv = NS_OK; + return scx; + } + return nsnull; } //***************************************************************************** diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index a86c6356ef75..d420f1b89500 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1643,7 +1643,7 @@ nsJSContext::ExecuteScript(void *aScriptObject, nsCOMPtr principal; rv = sSecurityManager->GetObjectPrincipal(mContext, - JS_GetObjectFromScript(script), + JS_GetGlobalFromScript(script), getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index d97e70a54d6d..e330f2fe3b44 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -158,7 +158,15 @@ public: void SetIsProxy() { - mWrapperPtrBits |= WRAPPER_IS_PROXY; + NS_ASSERTION(!mWrapperPtrBits, + "This flag should be set before creating any wrappers."); + mWrapperPtrBits = WRAPPER_IS_PROXY; + } + void ClearIsProxy() + { + NS_ASSERTION(!mWrapperPtrBits || mWrapperPtrBits == WRAPPER_IS_PROXY, + "This flag should be cleared before creating any wrappers."); + mWrapperPtrBits = 0; } bool IsProxy() const diff --git a/dom/indexedDB/AsyncConnectionHelper.cpp b/dom/indexedDB/AsyncConnectionHelper.cpp index 7b9acfa2f551..df2b7b340d43 100644 --- a/dom/indexedDB/AsyncConnectionHelper.cpp +++ b/dom/indexedDB/AsyncConnectionHelper.cpp @@ -120,10 +120,57 @@ ConvertCloneBuffersToArrayInternal( } // anonymous namespace +HelperBase::~HelperBase() +{ + if (!NS_IsMainThread()) { + IDBRequest* request; + mRequest.forget(&request); + + if (request) { + nsCOMPtr mainThread; + NS_GetMainThread(getter_AddRefs(mainThread)); + NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!"); + + if (mainThread) { + NS_ProxyRelease(mainThread, static_cast(request)); + } + } + } +} + +nsresult +HelperBase::WrapNative(JSContext* aCx, + nsISupports* aNative, + jsval* aResult) +{ + NS_ASSERTION(aCx, "Null context!"); + NS_ASSERTION(aNative, "Null pointer!"); + NS_ASSERTION(aResult, "Null pointer!"); + NS_ASSERTION(mRequest, "Null request!"); + + JSObject* global = + static_cast(mRequest->ScriptContext()->GetNativeGlobal()); + NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsresult rv = + nsContentUtils::WrapNative(aCx, global, aNative, aResult); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + return NS_OK; +} + +void +HelperBase::ReleaseMainThreadObjects() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + mRequest = nsnull; +} + AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase, IDBRequest* aRequest) -: mDatabase(aDatabase), - mRequest(aRequest), +: HelperBase(aRequest), + mDatabase(aDatabase), mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)), mResultCode(NS_OK), mDispatched(false) @@ -133,9 +180,9 @@ AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase, AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction, IDBRequest* aRequest) -: mDatabase(aTransaction->mDatabase), +: HelperBase(aRequest), + mDatabase(aTransaction->mDatabase), mTransaction(aTransaction), - mRequest(aRequest), mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)), mResultCode(NS_OK), mDispatched(false) @@ -152,9 +199,6 @@ AsyncConnectionHelper::~AsyncConnectionHelper() IDBTransaction* transaction; mTransaction.forget(&transaction); - IDBRequest* request; - mRequest.forget(&request); - nsCOMPtr mainThread; NS_GetMainThread(getter_AddRefs(mainThread)); NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!"); @@ -167,9 +211,6 @@ AsyncConnectionHelper::~AsyncConnectionHelper() NS_ProxyRelease(mainThread, static_cast(transaction)); } - if (request) { - NS_ProxyRelease(mainThread, static_cast(request)); - } } } @@ -195,7 +236,7 @@ AsyncConnectionHelper::Run() gCurrentTransaction = mTransaction; if (mRequest) { - nsresult rv = mRequest->SetDone(this); + nsresult rv = mRequest->NotifyHelperCompleted(this); if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { mResultCode = rv; } @@ -379,14 +420,19 @@ AsyncConnectionHelper::Init() return NS_OK; } +already_AddRefed +AsyncConnectionHelper::CreateSuccessEvent() +{ + return CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR)); +} + nsresult AsyncConnectionHelper::OnSuccess() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(mRequest, "Null request!"); - nsRefPtr event = - CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR)); + nsRefPtr event = CreateSuccessEvent(); if (!event) { NS_ERROR("Failed to create event!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; @@ -465,28 +511,8 @@ AsyncConnectionHelper::ReleaseMainThreadObjects() mDatabase = nsnull; mTransaction = nsnull; - mRequest = nsnull; -} -nsresult -AsyncConnectionHelper::WrapNative(JSContext* aCx, - nsISupports* aNative, - jsval* aResult) -{ - NS_ASSERTION(aCx, "Null context!"); - NS_ASSERTION(aNative, "Null pointer!"); - NS_ASSERTION(aResult, "Null pointer!"); - NS_ASSERTION(mRequest, "Null request!"); - - JSObject* global = - static_cast(mRequest->ScriptContext()->GetNativeGlobal()); - NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - nsresult rv = - nsContentUtils::WrapNative(aCx, global, aNative, aResult); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - return NS_OK; + HelperBase::ReleaseMainThreadObjects(); } // static @@ -534,8 +560,8 @@ TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable, NS_ASSERTION(aRunnable, "Null pointer!"); NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!"); - TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); - NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE); + TransactionThreadPool* pool = TransactionThreadPool::Get(); + NS_ASSERTION(pool, "This should never be null!"); return pool->Dispatch(mTransaction, aRunnable, false, nsnull); } diff --git a/dom/indexedDB/AsyncConnectionHelper.h b/dom/indexedDB/AsyncConnectionHelper.h index 5b5361e14868..6f72a567f4aa 100644 --- a/dom/indexedDB/AsyncConnectionHelper.h +++ b/dom/indexedDB/AsyncConnectionHelper.h @@ -49,6 +49,8 @@ #include "nsIRunnable.h" #include "nsIThread.h" +#include "nsDOMEvent.h" + #include "mozilla/TimeStamp.h" class mozIStorageConnection; @@ -57,6 +59,42 @@ BEGIN_INDEXEDDB_NAMESPACE class IDBTransaction; +// A common base class for AsyncConnectionHelper and OpenDatabaseHelper that +// IDBRequest can use. +class HelperBase : public nsIRunnable +{ + friend class IDBRequest; +public: + virtual nsresult GetResultCode() = 0; + + virtual nsresult GetSuccessResult(JSContext* aCx, + jsval* aVal) = 0; + +protected: + HelperBase(IDBRequest* aRequest) + : mRequest(aRequest) + { } + + virtual ~HelperBase(); + + /** + * Helper to wrap a native into a jsval. Uses the global object of the request + * to parent the native. + */ + nsresult WrapNative(JSContext* aCx, + nsISupports* aNative, + jsval* aResult); + + /** + * Gives the subclass a chance to release any objects that must be released + * on the main thread, regardless of success or failure. Subclasses that + * implement this method *MUST* call the base class implementation as well. + */ + virtual void ReleaseMainThreadObjects(); + + nsRefPtr mRequest; +}; + /** * Must be subclassed. The subclass must implement DoDatabaseWork. It may then * choose to implement OnSuccess and OnError depending on the needs of the @@ -66,11 +104,9 @@ class IDBTransaction; * and Dispatched from the main thread only. Target thread may not be the main * thread. */ -class AsyncConnectionHelper : public nsIRunnable, +class AsyncConnectionHelper : public HelperBase, public mozIStorageProgressHandler { - friend class IDBRequest; - public: NS_DECL_ISUPPORTS NS_DECL_NSIRUNNABLE @@ -89,6 +125,11 @@ public: static IDBTransaction* GetCurrentTransaction(); + bool HasTransaction() + { + return mTransaction; + } + nsISupports* GetSource() { return mRequest ? mRequest->Source() : nsnull; @@ -128,6 +169,13 @@ protected: */ virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) = 0; + /** + * This function returns the event to be dispatched at the request when + * OnSuccess is called. A subclass can override this to fire an event other + * than "success" at the request. + */ + virtual already_AddRefed CreateSuccessEvent(); + /** * This callback is run on the main thread if DoDatabaseWork returned NS_OK. * The default implementation fires a "success" DOM event with its target set @@ -157,14 +205,6 @@ protected: */ virtual void ReleaseMainThreadObjects(); - /** - * Helper to wrap a native into a jsval. Uses the global object of the request - * to parent the native. - */ - nsresult WrapNative(JSContext* aCx, - nsISupports* aNative, - jsval* aResult); - /** * Helper to make a JS array object out of an array of clone buffers. */ @@ -176,7 +216,6 @@ protected: protected: nsRefPtr mDatabase; nsRefPtr mTransaction; - nsRefPtr mRequest; private: nsCOMPtr mOldProgressHandler; diff --git a/dom/indexedDB/CheckPermissionsHelper.cpp b/dom/indexedDB/CheckPermissionsHelper.cpp index e3564c32ec02..db79222f0e7c 100644 --- a/dom/indexedDB/CheckPermissionsHelper.cpp +++ b/dom/indexedDB/CheckPermissionsHelper.cpp @@ -150,7 +150,7 @@ CheckPermissionsHelper::Run() return NS_OK; } - nsRefPtr helper; + nsRefPtr helper; helper.swap(mHelper); nsCOMPtr window; @@ -168,7 +168,8 @@ CheckPermissionsHelper::Run() "Unknown permission!"); helper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); - return helper->Run(); + + return helper->RunImmediately(); } NS_IMETHODIMP diff --git a/dom/indexedDB/CheckPermissionsHelper.h b/dom/indexedDB/CheckPermissionsHelper.h index 60b56197307a..ef0ec219e69d 100644 --- a/dom/indexedDB/CheckPermissionsHelper.h +++ b/dom/indexedDB/CheckPermissionsHelper.h @@ -41,7 +41,7 @@ #define mozilla_dom_indexeddb_checkpermissionshelper_h__ // Only meant to be included in IndexedDB source files, not exported. -#include "AsyncConnectionHelper.h" +#include "OpenDatabaseHelper.h" #include "nsIInterfaceRequestor.h" #include "nsIObserver.h" @@ -62,7 +62,7 @@ public: NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIOBSERVER - CheckPermissionsHelper(AsyncConnectionHelper* aHelper, + CheckPermissionsHelper(OpenDatabaseHelper* aHelper, nsIDOMWindow* aWindow, const nsAString& aName, const nsACString& aASCIIOrigin) @@ -80,7 +80,7 @@ public: } private: - nsRefPtr mHelper; + nsRefPtr mHelper; nsCOMPtr mWindow; nsString mName; nsCString mASCIIOrigin; diff --git a/dom/indexedDB/DatabaseInfo.cpp b/dom/indexedDB/DatabaseInfo.cpp index f7ed1136285a..0433aa75da84 100644 --- a/dom/indexedDB/DatabaseInfo.cpp +++ b/dom/indexedDB/DatabaseInfo.cpp @@ -85,7 +85,8 @@ EnumerateObjectStoreNames(const nsAString& aKey, DatabaseInfo::DatabaseInfo() : id(0), nextObjectStoreId(1), - nextIndexId(1) + nextIndexId(1), + runningVersionChange(false) { MOZ_COUNT_CTOR(DatabaseInfo); } diff --git a/dom/indexedDB/DatabaseInfo.h b/dom/indexedDB/DatabaseInfo.h index 50a715b325fd..1f2ff398e0ac 100644 --- a/dom/indexedDB/DatabaseInfo.h +++ b/dom/indexedDB/DatabaseInfo.h @@ -54,7 +54,8 @@ struct DatabaseInfo ~DatabaseInfo(); #else DatabaseInfo() - : id(0), nextObjectStoreId(1), nextIndexId(1) { } + : id(0), nextObjectStoreId(1), nextIndexId(1), runningVersionChange(false) + { } #endif static bool Get(PRUint32 aId, @@ -68,11 +69,12 @@ struct DatabaseInfo bool ContainsStoreName(const nsAString& aName); nsString name; - nsString version; + PRUint64 version; PRUint32 id; nsString filePath; PRInt64 nextObjectStoreId; PRInt64 nextIndexId; + bool runningVersionChange; nsAutoRefCnt referenceCount; }; diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index ffe516ba2221..a87a325c75b9 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -72,24 +72,6 @@ mozilla::Mutex* gPromptHelpersMutex = nsnull; // Protected by gPromptHelpersMutex. nsTArray >* gPromptHelpers = nsnull; -class SetVersionHelper : public AsyncConnectionHelper -{ -public: - SetVersionHelper(IDBTransaction* aTransaction, - IDBRequest* aRequest, - const nsAString& aVersion) - : AsyncConnectionHelper(aTransaction, aRequest), mVersion(aVersion) - { } - - nsresult DoDatabaseWork(mozIStorageConnection* aConnection); - nsresult GetSuccessResult(JSContext* aCx, - jsval* aVal); - -private: - // In-params - nsString mVersion; -}; - class CreateObjectStoreHelper : public AsyncConnectionHelper { public: @@ -446,6 +428,34 @@ IDBDatabase::IsClosed() return mClosed; } +void +IDBDatabase::EnterSetVersionTransaction() +{ + DatabaseInfo* dbInfo; + if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) { + NS_ERROR("This should never fail!"); + } + + NS_ASSERTION(!dbInfo->runningVersionChange, "How did that happen?"); + dbInfo->runningVersionChange = true; +} + +void +IDBDatabase::ExitSetVersionTransaction() +{ + DatabaseInfo* dbInfo; + if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) { + NS_ERROR("This should never fail!"); + } + + NS_ASSERTION(dbInfo->runningVersionChange, "How did that happen?"); + dbInfo->runningVersionChange = false; + + IndexedDatabaseManager* manager = IndexedDatabaseManager::Get(); + NS_ASSERTION(manager, "We should always have a manager here"); + manager->UnblockSetVersionRunnable(this); +} + void IDBDatabase::OnUnlink() { @@ -502,14 +512,14 @@ IDBDatabase::GetName(nsAString& aName) } NS_IMETHODIMP -IDBDatabase::GetVersion(nsAString& aVersion) +IDBDatabase::GetVersion(PRUint64* aVersion) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); DatabaseInfo* info; if (!DatabaseInfo::Get(mDatabaseId, &info)) { NS_ERROR("This should never fail!"); } - aVersion.Assign(info->version); + *aVersion = info->version; return NS_OK; } @@ -687,48 +697,6 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName) return NS_OK; } -NS_IMETHODIMP -IDBDatabase::SetVersion(const nsAString& aVersion, - JSContext* aCx, - nsIIDBRequest** _retval) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (mClosed) { - // XXX Update spec for a real error code here. - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - - DatabaseInfo* info; - if (!DatabaseInfo::Get(mDatabaseId, &info)) { - NS_ERROR("This should never fail!"); - } - - // Lock the whole database. - nsTArray storesToOpen; - nsRefPtr transaction = - IDBTransaction::Create(this, storesToOpen, IDBTransaction::VERSION_CHANGE, - kDefaultDatabaseTimeoutSeconds, true); - NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - nsRefPtr request = - IDBVersionChangeRequest::Create(static_cast(this), - ScriptContext(), Owner(), transaction); - NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - nsRefPtr helper = - new SetVersionHelper(transaction, request, aVersion); - - IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); - NS_ASSERTION(mgr, "This should never be null!"); - - nsresult rv = mgr->SetDatabaseVersion(this, request, aVersion, helper); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - request.forget(_retval); - return NS_OK; -} - NS_IMETHODIMP IDBDatabase::Transaction(nsIVariant* aStoreNames, PRUint16 aMode, @@ -770,6 +738,10 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames, NS_ERROR("This should never fail!"); } + if (info->runningVersionChange) { + return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; + } + nsTArray storesToOpen; switch (type) { @@ -933,47 +905,6 @@ IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor) return NS_OK; } -nsresult -SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection) -{ - NS_PRECONDITION(aConnection, "Passing a null connection!"); - - nsCOMPtr stmt; - nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( - "UPDATE database " - "SET version = :version" - ), getter_AddRefs(stmt)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = stmt->BindStringByName(NS_LITERAL_CSTRING("version"), mVersion); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (NS_FAILED(stmt->Execute())) { - return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; - } - - return NS_OK; -} - -nsresult -SetVersionHelper::GetSuccessResult(JSContext* aCx, - jsval* aVal) -{ - DatabaseInfo* info; - if (!DatabaseInfo::Get(mDatabase->Id(), &info)) { - NS_ERROR("This should never fail!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - info->version = mVersion; - - nsresult rv = WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, - mTransaction), - aVal); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - nsresult CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { diff --git a/dom/indexedDB/IDBDatabase.h b/dom/indexedDB/IDBDatabase.h index 5a2ab7f582ec..9df3cb4f3c26 100644 --- a/dom/indexedDB/IDBDatabase.h +++ b/dom/indexedDB/IDBDatabase.h @@ -135,6 +135,9 @@ public: // Whether or not the database has had Close called on it. bool IsClosed(); + void EnterSetVersionTransaction(); + void ExitSetVersionTransaction(); + private: IDBDatabase(); ~IDBDatabase(); diff --git a/dom/indexedDB/IDBEvents.cpp b/dom/indexedDB/IDBEvents.cpp index 349d43b95979..55f6f7da1701 100644 --- a/dom/indexedDB/IDBEvents.cpp +++ b/dom/indexedDB/IDBEvents.cpp @@ -103,9 +103,10 @@ mozilla::dom::indexedDB::CreateGenericEventRunnable(const nsAString& aType, } // static -already_AddRefed +already_AddRefed IDBVersionChangeEvent::CreateInternal(const nsAString& aType, - const nsAString& aVersion) + PRUint64 aOldVersion, + PRUint64 aNewVersion) { nsRefPtr event(new IDBVersionChangeEvent()); @@ -115,7 +116,8 @@ IDBVersionChangeEvent::CreateInternal(const nsAString& aType, rv = event->SetTrusted(true); NS_ENSURE_SUCCESS(rv, nsnull); - event->mVersion = aVersion; + event->mOldVersion = aOldVersion; + event->mNewVersion = aNewVersion; nsDOMEvent* result; event.forget(&result); @@ -125,10 +127,12 @@ IDBVersionChangeEvent::CreateInternal(const nsAString& aType, // static already_AddRefed IDBVersionChangeEvent::CreateRunnableInternal(const nsAString& aType, - const nsAString& aVersion, + PRUint64 aOldVersion, + PRUint64 aNewVersion, nsIDOMEventTarget* aTarget) { - nsCOMPtr event = CreateInternal(aType, aVersion); + nsRefPtr event = + CreateInternal(aType, aOldVersion, aNewVersion); NS_ENSURE_TRUE(event, nsnull); nsCOMPtr runnable(new EventFiringRunnable(aTarget, event)); @@ -146,8 +150,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) DOMCI_DATA(IDBVersionChangeEvent, IDBVersionChangeEvent) NS_IMETHODIMP -IDBVersionChangeEvent::GetVersion(nsAString& aVersion) +IDBVersionChangeEvent::GetOldVersion(PRUint64* aOldVersion) { - aVersion.Assign(mVersion); + NS_ENSURE_ARG_POINTER(aOldVersion); + *aOldVersion = mOldVersion; + return NS_OK; +} + +NS_IMETHODIMP +IDBVersionChangeEvent::GetNewVersion(PRUint64* aNewVersion) +{ + NS_ENSURE_ARG_POINTER(aNewVersion); + *aNewVersion = mNewVersion; return NS_OK; } diff --git a/dom/indexedDB/IDBEvents.h b/dom/indexedDB/IDBEvents.h index 87f003045561..150c7911e743 100644 --- a/dom/indexedDB/IDBEvents.h +++ b/dom/indexedDB/IDBEvents.h @@ -56,6 +56,7 @@ #define TIMEOUT_EVT_STR "timeout" #define VERSIONCHANGE_EVT_STR "versionchange" #define BLOCKED_EVT_STR "blocked" +#define UPGRADENEEDED_EVT_STR "upgradeneeded" BEGIN_INDEXEDDB_NAMESPACE @@ -75,48 +76,65 @@ public: NS_FORWARD_TO_NSDOMEVENT NS_DECL_NSIIDBVERSIONCHANGEEVENT - inline static already_AddRefed - Create(const nsAString& aVersion) + inline static already_AddRefed + Create(PRInt64 aOldVersion, + PRInt64 aNewVersion) { - return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR), aVersion); + return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR), + aOldVersion, aNewVersion); } - inline static already_AddRefed - CreateBlocked(const nsAString& aVersion) + inline static already_AddRefed + CreateBlocked(PRUint64 aOldVersion, + PRUint64 aNewVersion) { - return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion); + return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), + aOldVersion, aNewVersion); + } + + inline static already_AddRefed + CreateUpgradeNeeded(PRUint64 aOldVersion, + PRUint64 aNewVersion) + { + return CreateInternal(NS_LITERAL_STRING(UPGRADENEEDED_EVT_STR), + aOldVersion, aNewVersion); } inline static already_AddRefed - CreateRunnable(const nsAString& aVersion, + CreateRunnable(PRUint64 aOldVersion, + PRUint64 aNewVersion, nsIDOMEventTarget* aTarget) { return CreateRunnableInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR), - aVersion, aTarget); + aOldVersion, aNewVersion, aTarget); } static already_AddRefed - CreateBlockedRunnable(const nsAString& aVersion, + CreateBlockedRunnable(PRUint64 aOldVersion, + PRUint64 aNewVersion, nsIDOMEventTarget* aTarget) { - return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion, - aTarget); + return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), + aOldVersion, aNewVersion, aTarget); } protected: IDBVersionChangeEvent() : nsDOMEvent(nsnull, nsnull) { } virtual ~IDBVersionChangeEvent() { } - static already_AddRefed + static already_AddRefed CreateInternal(const nsAString& aType, - const nsAString& aVersion); + PRUint64 aOldVersion, + PRUint64 aNewVersion); static already_AddRefed CreateRunnableInternal(const nsAString& aType, - const nsAString& aVersion, + PRUint64 aOldVersion, + PRUint64 aNewVersion, nsIDOMEventTarget* aTarget); - nsString mVersion; + PRUint64 mOldVersion; + PRUint64 mNewVersion; }; END_INDEXEDDB_NAMESPACE diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index c3a82f8844a9..be7eb62c773e 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -53,7 +53,6 @@ #include "nsDirectoryServiceUtils.h" #include "nsDOMClassInfoID.h" #include "nsIPrincipal.h" -#include "nsEscape.h" #include "nsHashKeys.h" #include "nsPIDOMWindow.h" #include "nsServiceManagerUtils.h" @@ -65,6 +64,7 @@ #include "CheckPermissionsHelper.h" #include "DatabaseInfo.h" #include "IDBDatabase.h" +#include "IDBEvents.h" #include "IDBKeyRange.h" #include "IndexedDatabaseManager.h" #include "LazyIdleThread.h" @@ -72,8 +72,6 @@ using namespace mozilla; -#define DB_SCHEMA_VERSION 4 - USING_INDEXEDDB_NAMESPACE namespace { @@ -89,360 +87,6 @@ struct ObjectStoreInfoMap ObjectStoreInfo* info; }; -class OpenDatabaseHelper : public AsyncConnectionHelper -{ -public: - OpenDatabaseHelper(IDBRequest* aRequest, - const nsAString& aName, - const nsACString& aASCIIOrigin) - : AsyncConnectionHelper(static_cast(nsnull), aRequest), - mName(aName), mASCIIOrigin(aASCIIOrigin), mDatabaseId(0), - mLastObjectStoreId(0), mLastIndexId(0) - { } - - nsresult DoDatabaseWork(mozIStorageConnection* aConnection); - nsresult GetSuccessResult(JSContext* aCx, - jsval* aVal); - -private: - // In-params. - nsString mName; - nsCString mASCIIOrigin; - - // Out-params. - nsTArray > mObjectStores; - nsString mVersion; - PRUint32 mDataVersion; - nsString mDatabaseFilePath; - PRUint32 mDatabaseId; - PRInt64 mLastObjectStoreId; - PRInt64 mLastIndexId; -}; - -nsresult -CreateTables(mozIStorageConnection* aDBConn) -{ - NS_PRECONDITION(!NS_IsMainThread(), - "Creating tables on the main thread!"); - NS_PRECONDITION(aDBConn, "Passing a null database connection!"); - - // Table `database` - nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE database (" - "name TEXT NOT NULL, " - "version TEXT DEFAULT NULL, " - "dataVersion INTEGER NOT NULL" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `object_store` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE object_store (" - "id INTEGER, " - "name TEXT NOT NULL, " - "key_path TEXT NOT NULL, " - "auto_increment INTEGER NOT NULL DEFAULT 0, " - "PRIMARY KEY (id), " - "UNIQUE (name)" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `object_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE object_data (" - "id INTEGER, " - "object_store_id INTEGER NOT NULL, " - "data BLOB NOT NULL, " - "key_value DEFAULT NULL, " // NONE affinity - "PRIMARY KEY (id), " - "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE UNIQUE INDEX key_index " - "ON object_data (key_value, object_store_id);" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `ai_object_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE ai_object_data (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "object_store_id INTEGER NOT NULL, " - "data BLOB NOT NULL, " - "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE UNIQUE INDEX ai_key_index " - "ON ai_object_data (id, object_store_id);" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `index` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE object_store_index (" - "id INTEGER, " - "object_store_id INTEGER NOT NULL, " - "name TEXT NOT NULL, " - "key_path TEXT NOT NULL, " - "unique_index INTEGER NOT NULL, " - "object_store_autoincrement INTERGER NOT NULL, " - "PRIMARY KEY (id), " - "UNIQUE (object_store_id, name), " - "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `index_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE index_data (" - "id INTEGER, " - "index_id INTEGER NOT NULL, " - "object_data_id INTEGER NOT NULL, " - "object_data_key NOT NULL, " // NONE affinity - "value NOT NULL, " - "PRIMARY KEY (id), " - "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " - "CASCADE, " - "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE INDEX value_index " - "ON index_data (index_id, value);" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `unique_index_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE unique_index_data (" - "id INTEGER, " - "index_id INTEGER NOT NULL, " - "object_data_id INTEGER NOT NULL, " - "object_data_key NOT NULL, " // NONE affinity - "value NOT NULL, " - "PRIMARY KEY (id), " - "UNIQUE (index_id, value), " - "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " - "CASCADE " - "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `ai_index_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE ai_index_data (" - "id INTEGER, " - "index_id INTEGER NOT NULL, " - "ai_object_data_id INTEGER NOT NULL, " - "value NOT NULL, " - "PRIMARY KEY (id), " - "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " - "CASCADE, " - "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE INDEX ai_value_index " - "ON ai_index_data (index_id, value);" - )); - NS_ENSURE_SUCCESS(rv, rv); - - // Table `ai_unique_index_data` - rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE ai_unique_index_data (" - "id INTEGER, " - "index_id INTEGER NOT NULL, " - "ai_object_data_id INTEGER NOT NULL, " - "value NOT NULL, " - "PRIMARY KEY (id), " - "UNIQUE (index_id, value), " - "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " - "CASCADE, " - "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE " - "CASCADE" - ");" - )); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -CreateMetaData(mozIStorageConnection* aConnection, - const nsAString& aName) -{ - NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!"); - NS_PRECONDITION(aConnection, "Null database!"); - - nsCOMPtr stmt; - nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( - "INSERT OR REPLACE INTO database (name, dataVersion) " - "VALUES (:name, :dataVersion)" - ), getter_AddRefs(stmt)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName); - NS_ENSURE_SUCCESS(rv, rv); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"), - JS_STRUCTURED_CLONE_VERSION); - NS_ENSURE_SUCCESS(rv, rv); - - return stmt->Execute(); -} - -nsresult -GetDatabaseFile(const nsACString& aASCIIOrigin, - const nsAString& aName, - nsIFile** aDatabaseFile) -{ - NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!"); - - nsCOMPtr dbFile; - nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile)); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin); - originSanitized.ReplaceChar(":/", '+'); - - rv = dbFile->Append(originSanitized); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString filename; - filename.AppendInt(HashString(aName)); - - nsCString escapedName; - if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) { - NS_WARNING("Can't escape database name!"); - return NS_ERROR_UNEXPECTED; - } - - const char* forwardIter = escapedName.BeginReading(); - const char* backwardIter = escapedName.EndReading() - 1; - - nsCString substring; - while (forwardIter <= backwardIter && substring.Length() < 21) { - if (substring.Length() % 2) { - substring.Append(*backwardIter--); - } - else { - substring.Append(*forwardIter++); - } - } - - filename.Append(NS_ConvertASCIItoUTF16(substring)); - filename.AppendLiteral(".sqlite"); - - rv = dbFile->Append(filename); - NS_ENSURE_SUCCESS(rv, rv); - - dbFile.forget(aDatabaseFile); - return NS_OK; -} - -nsresult -CreateDatabaseConnection(const nsAString& aName, - nsIFile* aDBFile, - mozIStorageConnection** aConnection) -{ - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - - nsCOMPtr dbDirectory; - nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory)); - NS_ENSURE_SUCCESS(rv, rv); - - bool exists; - rv = aDBFile->Exists(&exists); - NS_ENSURE_SUCCESS(rv, rv); - - NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota"); - - nsCOMPtr ss = - do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); - NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); - - nsCOMPtr connection; - rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, - getter_AddRefs(connection)); - if (rv == NS_ERROR_FILE_CORRUPTED) { - // Nuke the database file. The web services can recreate their data. - rv = aDBFile->Remove(false); - NS_ENSURE_SUCCESS(rv, rv); - - exists = false; - - rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, - getter_AddRefs(connection)); - } - NS_ENSURE_SUCCESS(rv, rv); - - // Check to make sure that the database schema is correct. - PRInt32 schemaVersion; - rv = connection->GetSchemaVersion(&schemaVersion); - NS_ENSURE_SUCCESS(rv, rv); - - if (schemaVersion != DB_SCHEMA_VERSION) { - if (exists) { - // If the connection is not at the right schema version, nuke it. - rv = aDBFile->Remove(false); - NS_ENSURE_SUCCESS(rv, rv); - - rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, - getter_AddRefs(connection)); - NS_ENSURE_SUCCESS(rv, rv); - } - - mozStorageTransaction transaction(connection, false, - mozIStorageConnection::TRANSACTION_IMMEDIATE); - - rv = CreateTables(connection); - NS_ENSURE_SUCCESS(rv, rv); - - rv = CreateMetaData(connection, aName); - NS_ENSURE_SUCCESS(rv, rv); - - rv = transaction.Commit(); - NS_ENSURE_SUCCESS(rv, rv); - } - - // Check to make sure that the database schema is correct again. - NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) && - schemaVersion == DB_SCHEMA_VERSION, - "CreateTables failed!"); - - // Turn on foreign key constraints. - rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "PRAGMA foreign_keys = ON;" - )); - NS_ENSURE_SUCCESS(rv, rv); - - connection.forget(aConnection); - return NS_OK; -} - } // anonymous namespace IDBFactory::IDBFactory() @@ -571,13 +215,12 @@ IDBFactory::GetDirectoryForOrigin(const nsACString& aASCIIOrigin, nsresult IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, PRUint32 aDatabaseId, - nsAString& aVersion, + PRUint64* aVersion, ObjectStoreInfoArray& aObjectStores) { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aConnection, "Null pointer!"); - aVersion.Truncate(); aObjectStores.Clear(); // Load object store names and ids. @@ -672,21 +315,18 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, return NS_ERROR_UNEXPECTED; } - nsString version; - rv = stmt->GetString(0, version); - NS_ENSURE_SUCCESS(rv, rv); + PRInt64 version = 0; + rv = stmt->GetInt64(0, &version); - if (version.IsVoid()) { - version.SetIsVoid(false); - } - aVersion = version; - return NS_OK; + *aVersion = NS_MAX(version, 0); + + return rv; } // static nsresult IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo, - const nsAString& aVersion, + PRUint64 aVersion, ObjectStoreInfoArray& aObjectStores) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -739,11 +379,16 @@ DOMCI_DATA(IDBFactory, IDBFactory) NS_IMETHODIMP IDBFactory::Open(const nsAString& aName, + PRInt64 aVersion, JSContext* aCx, - nsIIDBRequest** _retval) + nsIIDBOpenDBRequest** _retval) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + if (aVersion < 1) { + return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR; + } + if (XRE_GetProcessType() == GeckoProcessType_Content) { // Force ContentChild to cache the path from the parent, so that // we do not end up in a side thread that asks for the path (which @@ -784,12 +429,12 @@ IDBFactory::Open(const nsAString& aName, } } - nsRefPtr request = IDBRequest::Create(this, context, window, - nsnull); + nsRefPtr request = + IDBOpenDBRequest::Create(context, window); NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); nsRefPtr openHelper = - new OpenDatabaseHelper(request, aName, origin); + new OpenDatabaseHelper(request, aName, origin, aVersion); nsRefPtr permissionHelper = new CheckPermissionsHelper(openHelper, window, aName, origin); @@ -803,200 +448,3 @@ IDBFactory::Open(const nsAString& aName, request.forget(_retval); return NS_OK; } - -nsresult -OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) -{ -#ifdef DEBUG - { - bool correctThread; - NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()-> - IsOnCurrentThread(&correctThread)) && - correctThread, - "Running on the wrong thread!"); - } -#endif - NS_ASSERTION(!aConnection, "Huh?!"); - - if (IndexedDatabaseManager::IsShuttingDown()) { - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - nsCOMPtr dbFile; - nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = dbFile->GetPath(mDatabaseFilePath); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - nsCOMPtr dbDirectory; - rv = dbFile->GetParent(getter_AddRefs(dbDirectory)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - bool exists; - rv = dbDirectory->Exists(&exists); - NS_ENSURE_SUCCESS(rv, rv); - - if (exists) { - bool isDirectory; - rv = dbDirectory->IsDirectory(&isDirectory); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - } - else { - rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - } - - IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); - NS_ASSERTION(mgr, "This should never be null!"); - - rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - nsCOMPtr connection; - rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - // Get the data version. - nsCOMPtr stmt; - rv = connection->CreateStatement(NS_LITERAL_CSTRING( - "SELECT dataVersion " - "FROM database" - ), getter_AddRefs(stmt)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - bool hasResult; - rv = stmt->ExecuteStep(&hasResult); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (!hasResult) { - NS_ERROR("Database has no dataVersion!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - PRInt64 dataVersion; - rv = stmt->GetInt64(0, &dataVersion); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (dataVersion > JS_STRUCTURED_CLONE_VERSION) { - NS_ERROR("Bad data version!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - if (dataVersion < JS_STRUCTURED_CLONE_VERSION) { - // Need to upgrade the database, here, before returning to the main thread. - NS_NOTYETIMPLEMENTED("Implement me!"); - } - - mDatabaseId = HashString(mDatabaseFilePath); - NS_ASSERTION(mDatabaseId, "HashString gave us 0?!"); - - rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, mVersion, - mObjectStores); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - for (PRUint32 i = 0; i < mObjectStores.Length(); i++) { - nsAutoPtr& objectStoreInfo = mObjectStores[i]; - for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) { - IndexInfo& indexInfo = objectStoreInfo->indexes[j]; - mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId); - } - mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId); - } - - return NS_OK; -} - -nsresult -OpenDatabaseHelper::GetSuccessResult(JSContext* aCx, - jsval *aVal) -{ - DatabaseInfo* dbInfo; - if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) { - NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!"); - ++dbInfo->referenceCount; - -#ifdef DEBUG - { - NS_ASSERTION(dbInfo->name == mName && - dbInfo->version == mVersion && - dbInfo->id == mDatabaseId && - dbInfo->filePath == mDatabaseFilePath, - "Metadata mismatch!"); - - PRUint32 objectStoreCount = mObjectStores.Length(); - for (PRUint32 index = 0; index < objectStoreCount; index++) { - nsAutoPtr& info = mObjectStores[index]; - NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!"); - - ObjectStoreInfo* otherInfo; - NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &otherInfo), - "ObjectStore not known!"); - - NS_ASSERTION(info->name == otherInfo->name && - info->id == otherInfo->id && - info->keyPath == otherInfo->keyPath && - info->autoIncrement == otherInfo->autoIncrement && - info->databaseId == otherInfo->databaseId, - "Metadata mismatch!"); - NS_ASSERTION(dbInfo->ContainsStoreName(info->name), - "Object store names out of date!"); - NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(), - "Bad index length!"); - - PRUint32 indexCount = info->indexes.Length(); - for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) { - const IndexInfo& indexInfo = info->indexes[indexIndex]; - const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex]; - NS_ASSERTION(indexInfo.id == otherIndexInfo.id, - "Bad index id!"); - NS_ASSERTION(indexInfo.name == otherIndexInfo.name, - "Bad index name!"); - NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath, - "Bad index keyPath!"); - NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique, - "Bad index unique value!"); - NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement, - "Bad index autoIncrement value!"); - } - } - } -#endif - - } - else { - nsAutoPtr newInfo(new DatabaseInfo()); - - newInfo->name = mName; - newInfo->id = mDatabaseId; - newInfo->filePath = mDatabaseFilePath; - newInfo->referenceCount = 1; - - if (!DatabaseInfo::Put(newInfo)) { - NS_ERROR("Failed to add to hash!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - dbInfo = newInfo.forget(); - - nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mVersion, - mObjectStores); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!"); - } - - dbInfo->nextObjectStoreId = mLastObjectStoreId + 1; - dbInfo->nextIndexId = mLastIndexId + 1; - - nsRefPtr database = - IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo, - mASCIIOrigin); - if (!database) { - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, database), - aVal); -} diff --git a/dom/indexedDB/IDBFactory.h b/dom/indexedDB/IDBFactory.h index 3c0d46b1daf7..786c621a1783 100644 --- a/dom/indexedDB/IDBFactory.h +++ b/dom/indexedDB/IDBFactory.h @@ -85,12 +85,12 @@ public: static nsresult LoadDatabaseInformation(mozIStorageConnection* aConnection, PRUint32 aDatabaseId, - nsAString& aVersion, + PRUint64* aVersion, ObjectStoreInfoArray& aObjectStores); static nsresult UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo, - const nsAString& aVersion, + PRUint64 aVersion, ObjectStoreInfoArray& aObjectStores); private: diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp index dce02a60e76a..04d1f883f0ee 100644 --- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -121,7 +121,7 @@ IDBRequest::Reset() } nsresult -IDBRequest::SetDone(AsyncConnectionHelper* aHelper) +IDBRequest::NotifyHelperCompleted(HelperBase* aHelper) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!"); @@ -203,12 +203,10 @@ IDBRequest::GetReadyState(PRUint16* aReadyState) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - if (mHaveResultOrErrorCode) { - *aReadyState = nsIIDBRequest::DONE; - } - else { - *aReadyState = nsIIDBRequest::LOADING; - } + *aReadyState = mHaveResultOrErrorCode ? + nsIIDBRequest::DONE : + nsIIDBRequest::LOADING; + return NS_OK; } @@ -345,7 +343,7 @@ IDBRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor) return NS_OK; } -IDBVersionChangeRequest::~IDBVersionChangeRequest() +IDBOpenDBRequest::~IDBOpenDBRequest() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -355,11 +353,9 @@ IDBVersionChangeRequest::~IDBVersionChangeRequest() } // static -already_AddRefed -IDBVersionChangeRequest::Create(nsISupports* aSource, - nsIScriptContext* aScriptContext, - nsPIDOMWindow* aOwner, - IDBTransaction* aTransaction) +already_AddRefed +IDBOpenDBRequest::Create(nsIScriptContext* aScriptContext, + nsPIDOMWindow* aOwner) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -368,10 +364,8 @@ IDBVersionChangeRequest::Create(nsISupports* aSource, return nsnull; } - nsRefPtr request(new IDBVersionChangeRequest()); + nsRefPtr request(new IDBOpenDBRequest()); - request->mSource = aSource; - request->mTransaction = aTransaction; request->mScriptContext = aScriptContext; request->mOwner = aOwner; @@ -379,52 +373,50 @@ IDBVersionChangeRequest::Create(nsISupports* aSource, } void -IDBVersionChangeRequest::RootResultVal() +IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction) +{ + mTransaction = aTransaction; +} + +void +IDBOpenDBRequest::RootResultVal() { NS_ASSERTION(!mResultValRooted, "This should be false!"); - NS_HOLD_JS_OBJECTS(this, IDBVersionChangeRequest); + NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest); mResultValRooted = true; } void -IDBVersionChangeRequest::UnrootResultVal() +IDBOpenDBRequest::UnrootResultVal() { NS_ASSERTION(mResultValRooted, "This should be true!"); - NS_DROP_JS_OBJECTS(this, IDBVersionChangeRequest); + NS_DROP_JS_OBJECTS(this, IDBOpenDBRequest); mResultValRooted = false; } -NS_IMETHODIMP -IDBVersionChangeRequest::SetOnblocked(nsIDOMEventListener* aBlockedListener) -{ - return RemoveAddEventListener(NS_LITERAL_STRING(BLOCKED_EVT_STR), - mOnBlockedListener, aBlockedListener); -} +NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked) +NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded) -NS_IMETHODIMP -IDBVersionChangeRequest::GetOnblocked(nsIDOMEventListener** aBlockedListener) -{ - return GetInnerEventListener(mOnBlockedListener, aBlockedListener); -} +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest) -NS_IMPL_CYCLE_COLLECTION_CLASS(IDBVersionChangeRequest) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBVersionChangeRequest, +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnBlockedListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnupgradeneededListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnblockedListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBVersionChangeRequest, +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest) - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnBlockedListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnupgradeneededListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnblockedListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBVersionChangeRequest) - NS_INTERFACE_MAP_ENTRY(nsIIDBVersionChangeRequest) - NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBVersionChangeRequest) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest) + NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest) NS_INTERFACE_MAP_END_INHERITING(IDBRequest) -NS_IMPL_ADDREF_INHERITED(IDBVersionChangeRequest, IDBRequest) -NS_IMPL_RELEASE_INHERITED(IDBVersionChangeRequest, IDBRequest) +NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest) +NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest) -DOMCI_DATA(IDBVersionChangeRequest, IDBVersionChangeRequest) +DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest) diff --git a/dom/indexedDB/IDBRequest.h b/dom/indexedDB/IDBRequest.h index 5bd0a3543702..1cf91f5f4134 100644 --- a/dom/indexedDB/IDBRequest.h +++ b/dom/indexedDB/IDBRequest.h @@ -44,9 +44,9 @@ #include "mozilla/dom/indexedDB/IndexedDatabase.h" #include "nsIIDBRequest.h" -#include "nsIIDBVersionChangeRequest.h" +#include "nsIIDBOpenDBRequest.h" -#include "nsDOMEventTargetHelper.h" +#include "nsDOMEventTargetWrapperCache.h" #include "nsCycleCollectionParticipant.h" class nsIScriptContext; @@ -54,7 +54,7 @@ class nsPIDOMWindow; BEGIN_INDEXEDDB_NAMESPACE -class AsyncConnectionHelper; +class HelperBase; class IDBTransaction; class IDBRequest : public nsDOMEventTargetHelper, @@ -82,7 +82,15 @@ public: void Reset(); - nsresult SetDone(AsyncConnectionHelper* aHelper); + nsresult NotifyHelperCompleted(HelperBase* aHelper); + + void SetError(nsresult rv) + { + NS_ASSERTION(NS_FAILED(rv), "Er, what?"); + NS_ASSERTION(mErrorCode == NS_OK, "Already have an error?"); + + mErrorCode = rv; + } nsIScriptContext* ScriptContext() { @@ -116,30 +124,31 @@ protected: bool mHaveResultOrErrorCode; }; -class IDBVersionChangeRequest : public IDBRequest, - public nsIIDBVersionChangeRequest +class IDBOpenDBRequest : public IDBRequest, + public nsIIDBOpenDBRequest { public: NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIIDBREQUEST(IDBRequest::) - NS_DECL_NSIIDBVERSIONCHANGEREQUEST - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBVersionChangeRequest, + NS_DECL_NSIIDBOPENDBREQUEST + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest, IDBRequest) - ~IDBVersionChangeRequest(); - static - already_AddRefed - Create(nsISupports* aSource, - nsIScriptContext* aScriptContext, - nsPIDOMWindow* aOwner, - IDBTransaction* aTransaction); + already_AddRefed + Create(nsIScriptContext* aScriptContext, + nsPIDOMWindow* aOwner); + + void SetTransaction(IDBTransaction* aTransaction); virtual void RootResultVal(); virtual void UnrootResultVal(); protected: - nsRefPtr mOnBlockedListener; + ~IDBOpenDBRequest(); + + nsRefPtr mOnblockedListener; + nsRefPtr mOnupgradeneededListener; }; END_INDEXEDDB_NAMESPACE diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp index 3e4dc5901528..f44037397a3d 100644 --- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -182,6 +182,14 @@ IDBTransaction::OnRequestFinished() } } +void +IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ASSERTION(!mListener, "Shouldn't already have a listener!"); + mListener = aListener; +} + nsresult IDBTransaction::CommitOrRollback() { @@ -190,7 +198,7 @@ IDBTransaction::CommitOrRollback() TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); NS_ENSURE_STATE(pool); - nsRefPtr helper(new CommitHelper(this)); + nsRefPtr helper(new CommitHelper(this, mListener)); mCachedStatements.Enumerate(DoomCachedStatements, helper); NS_ASSERTION(!mCachedStatements.Count(), "Statements left!"); @@ -775,8 +783,13 @@ IDBTransaction::Abort() mAborted = true; mReadyState = nsIIDBTransaction::DONE; + if (Mode() == nsIIDBTransaction::VERSION_CHANGE) { + // If a version change transaction is aborted, the db must be closed + mDatabase->Close(); + } + // Fire the abort event if there are no outstanding requests. Otherwise the - // abort event will be fired when all outdtanding requests finish. + // abort event will be fired when all outstanding requests finish. if (needToCommitOrRollback) { return CommitOrRollback(); } @@ -908,8 +921,10 @@ IDBTransaction::AfterProcessNextEvent(nsIThreadInternal* aThread, return NS_OK; } -CommitHelper::CommitHelper(IDBTransaction* aTransaction) +CommitHelper::CommitHelper(IDBTransaction* aTransaction, + IDBTransactionListener* aListener) : mTransaction(aTransaction), + mListener(aListener), mAborted(!!aTransaction->mAborted), mHaveMetadata(false) { @@ -965,7 +980,14 @@ CommitHelper::Run() #ifdef DEBUG mTransaction->mFiredCompleteOrAbort = true; #endif + + // Tell the listener (if we have one) that we're done + if (mListener) { + mListener->NotifyTransactionComplete(mTransaction); + } + mTransaction = nsnull; + return NS_OK; } @@ -994,7 +1016,7 @@ CommitHelper::Run() nsresult rv = IDBFactory::LoadDatabaseInformation(mConnection, mTransaction->Database()->Id(), - mOldVersion, mOldObjectStores); + &mOldVersion, mOldObjectStores); if (NS_SUCCEEDED(rv)) { mHaveMetadata = true; } diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h index ff59ca1615d9..d9e998a8c0d4 100644 --- a/dom/indexedDB/IDBTransaction.h +++ b/dom/indexedDB/IDBTransaction.h @@ -65,6 +65,15 @@ class CommitHelper; struct ObjectStoreInfo; class TransactionThreadPool; +class IDBTransactionListener +{ +public: + NS_IMETHOD_(nsrefcnt) AddRef() = 0; + NS_IMETHOD_(nsrefcnt) Release() = 0; + + virtual nsresult NotifyTransactionComplete(IDBTransaction* aTransaction) = 0; +}; + class IDBTransaction : public nsDOMEventTargetHelper, public nsIIDBTransaction, public nsIThreadObserver @@ -95,6 +104,8 @@ public: void OnNewRequest(); void OnRequestFinished(); + void SetTransactionListener(IDBTransactionListener* aListener); + bool StartSavepoint(); nsresult ReleaseSavepoint(); void RollbackSavepoint(); @@ -189,6 +200,8 @@ private: nsInterfaceHashtable mCachedStatements; + nsRefPtr mListener; + // Only touched on the database thread. nsCOMPtr mConnection; @@ -211,7 +224,8 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIRUNNABLE - CommitHelper(IDBTransaction* aTransaction); + CommitHelper(IDBTransaction* aTransaction, + IDBTransactionListener* aListener); ~CommitHelper(); template @@ -229,10 +243,11 @@ public: private: nsRefPtr mTransaction; + nsRefPtr mListener; nsCOMPtr mConnection; nsAutoTArray, 10> mDoomedObjects; - nsString mOldVersion; + PRUint64 mOldVersion; nsTArray > mOldObjectStores; bool mAborted; diff --git a/dom/indexedDB/IndexedDatabase.h b/dom/indexedDB/IndexedDatabase.h index 59f1eaf50582..db956429a156 100644 --- a/dom/indexedDB/IndexedDatabase.h +++ b/dom/indexedDB/IndexedDatabase.h @@ -51,6 +51,8 @@ #include "nsStringGlue.h" #include "nsTArray.h" +#define DB_SCHEMA_VERSION 5 + #define BEGIN_INDEXEDDB_NAMESPACE \ namespace mozilla { namespace dom { namespace indexedDB { diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index e5d75092a490..baa3784f00a9 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -149,14 +149,20 @@ class DelayedSetVersion : public nsRunnable { public: DelayedSetVersion(IDBDatabase* aDatabase, - IDBVersionChangeRequest* aRequest, - const nsAString& aVersion, + IDBOpenDBRequest* aRequest, + PRInt64 aOldVersion, + PRInt64 aNewVersion, AsyncConnectionHelper* aHelper) : mDatabase(aDatabase), mRequest(aRequest), - mVersion(aVersion), + mOldVersion(aOldVersion), + mNewVersion(aNewVersion), mHelper(aHelper) - { } + { + NS_ASSERTION(aDatabase, "Null database!"); + NS_ASSERTION(aRequest, "Null request!"); + NS_ASSERTION(aHelper, "Null helper!"); + } NS_IMETHOD Run() { @@ -165,7 +171,8 @@ public: IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); NS_ASSERTION(mgr, "This should never be null!"); - nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest, mVersion, + nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest, + mOldVersion, mNewVersion, mHelper); NS_ENSURE_SUCCESS(rv, rv); @@ -174,8 +181,9 @@ public: private: nsRefPtr mDatabase; - nsRefPtr mRequest; - nsString mVersion; + nsRefPtr mRequest; + PRInt64 mOldVersion; + PRInt64 mNewVersion; nsRefPtr mHelper; }; @@ -187,12 +195,14 @@ class VersionChangeEventsRunnable : public nsRunnable public: VersionChangeEventsRunnable( IDBDatabase* aRequestingDatabase, - IDBVersionChangeRequest* aRequest, + IDBOpenDBRequest* aRequest, nsTArray >& aWaitingDatabases, - const nsAString& aVersion) + PRInt64 aOldVersion, + PRInt64 aNewVersion) : mRequestingDatabase(aRequestingDatabase), mRequest(aRequest), - mVersion(aVersion) + mOldVersion(aOldVersion), + mNewVersion(aNewVersion) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aRequestingDatabase, "Null pointer!"); @@ -218,19 +228,17 @@ public: // First check if the document the IDBDatabase is part of is bfcached nsCOMPtr ownerDoc = database->GetOwnerDocument(); - nsISHEntry* shEntry; - if (ownerDoc && (shEntry = ownerDoc->GetBFCacheEntry())) { - nsCOMPtr sheInternal = do_QueryInterface(shEntry); - if (sheInternal) { - sheInternal->RemoveFromBFCacheSync(); - } + nsIBFCacheEntry* bfCacheEntry; + if (ownerDoc && (bfCacheEntry = ownerDoc->GetBFCacheEntry())) { + bfCacheEntry->RemoveFromBFCacheSync(); NS_ASSERTION(database->IsClosed(), "Kicking doc out of bfcache should have closed database"); continue; } // Otherwise fire a versionchange event. - nsCOMPtr event(IDBVersionChangeEvent::Create(mVersion)); + nsRefPtr event = + IDBVersionChangeEvent::Create(mOldVersion, mNewVersion); NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); bool dummy; @@ -241,8 +249,8 @@ public: // then fire the blocked event. for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) { if (!mWaitingDatabases[index]->IsClosed()) { - nsCOMPtr event = - IDBVersionChangeEvent::CreateBlocked(mVersion); + nsRefPtr event = + IDBVersionChangeEvent::CreateBlocked(mOldVersion, mNewVersion); NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); bool dummy; @@ -257,9 +265,10 @@ public: private: nsRefPtr mRequestingDatabase; - nsRefPtr mRequest; + nsRefPtr mRequest; nsTArray > mWaitingDatabases; - nsString mVersion; + PRInt64 mOldVersion; + PRInt64 mNewVersion; }; } // anonymous namespace @@ -512,8 +521,9 @@ IndexedDatabaseManager::IsShuttingDown() nsresult IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase, - IDBVersionChangeRequest* aRequest, - const nsAString& aVersion, + IDBOpenDBRequest* aRequest, + PRInt64 aOldVersion, + PRInt64 aNewVersion, AsyncConnectionHelper* aHelper) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -530,7 +540,8 @@ IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase, // Same database, just queue this call to run after the current // SetVersion transaction completes. nsRefPtr delayed = - new DelayedSetVersion(aDatabase, aRequest, aVersion, aHelper); + new DelayedSetVersion(aDatabase, aRequest, aOldVersion, aNewVersion, + aHelper); if (!runnable->mDelayedRunnables.AppendElement(delayed)) { NS_WARNING("Out of memory!"); return NS_ERROR_OUT_OF_MEMORY; @@ -600,7 +611,7 @@ IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase, nsRefPtr eventsRunnable = new VersionChangeEventsRunnable(aDatabase, aRequest, waitingDatabases, - aVersion); + aOldVersion, aNewVersion); rv = NS_DispatchToCurrentThread(eventsRunnable); NS_ENSURE_SUCCESS(rv, rv); @@ -682,19 +693,15 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase) // Now run the helper if there are no more live databases. if (runnable->mHelper && runnable->mDatabases.IsEmpty()) { - // Don't hold the callback alive longer than necessary. - nsRefPtr helper; - helper.swap(runnable->mHelper); + // At this point, all databases are closed, so no new transactions can + // be started. There may, however, still be outstanding transactions + // that have not completed. We need to wait for those before we + // dispatch the helper. - if (NS_FAILED(helper->DispatchToTransactionPool())) { - NS_WARNING("Failed to dispatch to thread pool!"); - } + TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); - // Now wait for the transaction to complete. Completing the transaction - // will be our cue to remove the SetVersionRunnable from our list and - // therefore allow other SetVersion requests to begin. - TransactionThreadPool* pool = TransactionThreadPool::Get(); - NS_ASSERTION(pool, "This should never be null!"); + nsRefPtr waitRunnable = + new WaitForTransactionsToFinishRunnable(runnable); // All other databases should be closed, so we only need to wait on this // one. @@ -703,8 +710,8 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase) NS_ERROR("This should never fail!"); } - // Use the SetVersionRunnable as the callback. - if (!pool->WaitForAllDatabasesToComplete(array, runnable)) { + // Use the WaitForTransactionsToFinishRunnable as the callback. + if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) { NS_WARNING("Failed to wait for transaction to complete!"); } } @@ -713,6 +720,27 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase) } } +void +IndexedDatabaseManager::UnblockSetVersionRunnable(IDBDatabase* aDatabase) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ASSERTION(aDatabase, "Null pointer!"); + + // Check through the list of SetVersionRunnables to find the one we're seeking. + for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) { + nsRefPtr& runnable = mSetVersionRunnables[index]; + + if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) { + NS_ASSERTION(!runnable->mHelper, + "Why are we unblocking a runnable if the helper didn't run?"); + NS_DispatchToCurrentThread(runnable); + return; + } + } + + NS_NOTREACHED("How did we get here!"); +} + // static bool IndexedDatabaseManager::SetCurrentDatabase(IDBDatabase* aDatabase) @@ -1272,3 +1300,39 @@ IndexedDatabaseManager::SetVersionRunnable::Run() return NS_OK; } + +NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::WaitForTransactionsToFinishRunnable, + nsIRunnable) + +NS_IMETHODIMP +IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + // Don't hold the callback alive longer than necessary. + nsRefPtr helper; + helper.swap(mRunnable->mHelper); + + nsRefPtr runnable; + runnable.swap(mRunnable); + + // If the helper has a transaction, dispatch it to the transaction + // threadpool. + if (helper->HasTransaction()) { + if (NS_FAILED(helper->DispatchToTransactionPool())) { + NS_WARNING("Failed to dispatch to thread pool!"); + } + } + // Otherwise, dispatch it to the IO thread. + else { + IndexedDatabaseManager* manager = IndexedDatabaseManager::Get(); + NS_ASSERTION(manager, "We should definitely have a manager here"); + + helper->Dispatch(manager->IOThread()); + } + + // The helper is responsible for calling + // IndexedDatabaseManager::UnblockSetVersionRunnable. + + return NS_OK; +} diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h index c8d63fd7601e..7287394d233f 100644 --- a/dom/indexedDB/IndexedDatabaseManager.h +++ b/dom/indexedDB/IndexedDatabaseManager.h @@ -97,8 +97,9 @@ public: // Begins the process of setting a database version. nsresult SetDatabaseVersion(IDBDatabase* aDatabase, - IDBVersionChangeRequest* aRequest, - const nsAString& aVersion, + IDBOpenDBRequest* aRequest, + PRInt64 aOldVersion, + PRInt64 aNewVersion, AsyncConnectionHelper* aHelper); // Called when a window is being purged from the bfcache or the user leaves @@ -203,6 +204,8 @@ private: // Called when AsyncUsageRunnable has finished its Run() method. inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable); + void UnblockSetVersionRunnable(IDBDatabase* aDatabase); + // Responsible for waiting until all databases have been closed before running // the version change transaction. Created when // IndexedDatabaseManager::SetDatabaseVersion is called. Runs only once on the @@ -226,6 +229,26 @@ private: // Called when SetVersionRunnable has finished its Run() method. inline void OnSetVersionRunnableComplete(SetVersionRunnable* aRunnable); + + // A callback runnable used by the TransactionPool when it's safe to proceed + // with a SetVersion/DeleteDatabase/etc. + class WaitForTransactionsToFinishRunnable : public nsIRunnable + { + public: + WaitForTransactionsToFinishRunnable(SetVersionRunnable* aRunnable) + : mRunnable(aRunnable) + { + NS_ASSERTION(mRunnable, "Why don't we have a runnable?"); + NS_ASSERTION(mRunnable->mDatabases.IsEmpty(), "We're here too early!"); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + private: + nsRefPtr mRunnable; + }; + // Maintains a list of live databases per origin. nsClassHashtable > mLiveDatabases; diff --git a/dom/indexedDB/Makefile.in b/dom/indexedDB/Makefile.in index 6b93bd27b7fe..2401e7c853a6 100644 --- a/dom/indexedDB/Makefile.in +++ b/dom/indexedDB/Makefile.in @@ -67,6 +67,7 @@ CPPSRCS = \ IDBFactory.cpp \ IndexedDatabaseManager.cpp \ LazyIdleThread.cpp \ + OpenDatabaseHelper.cpp \ TransactionThreadPool.cpp \ $(NULL) @@ -110,7 +111,7 @@ XPIDLSRCS = \ nsIIDBRequest.idl \ nsIIDBTransaction.idl \ nsIIDBVersionChangeEvent.idl \ - nsIIDBVersionChangeRequest.idl \ + nsIIDBOpenDBRequest.idl \ nsIIndexedDatabaseManager.idl \ $(NULL) diff --git a/dom/indexedDB/OpenDatabaseHelper.cpp b/dom/indexedDB/OpenDatabaseHelper.cpp new file mode 100644 index 000000000000..ffe82ba4cbc7 --- /dev/null +++ b/dom/indexedDB/OpenDatabaseHelper.cpp @@ -0,0 +1,1025 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Indexed Database. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ben Turner + * Kyle Huey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "OpenDatabaseHelper.h" +#include "IDBEvents.h" +#include "IDBFactory.h" +#include "IndexedDatabaseManager.h" + +#include "mozilla/storage.h" +#include "nsIFile.h" + +#include "nsContentUtils.h" +#include "nsEscape.h" +#include "nsThreadUtils.h" + +USING_INDEXEDDB_NAMESPACE + +const extern PRUint32 kDefaultDatabaseTimeoutSeconds = 30; + +namespace { + +nsresult +GetDatabaseFile(const nsACString& aASCIIOrigin, + const nsAString& aName, + nsIFile** aDatabaseFile) +{ + NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!"); + + nsCOMPtr dbFile; + nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin); + originSanitized.ReplaceChar(":/", '+'); + + rv = dbFile->Append(originSanitized); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString filename; + filename.AppendInt(HashString(aName)); + + nsCString escapedName; + if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) { + NS_WARNING("Can't escape database name!"); + return NS_ERROR_UNEXPECTED; + } + + const char* forwardIter = escapedName.BeginReading(); + const char* backwardIter = escapedName.EndReading() - 1; + + nsCString substring; + while (forwardIter <= backwardIter && substring.Length() < 21) { + if (substring.Length() % 2) { + substring.Append(*backwardIter--); + } + else { + substring.Append(*forwardIter++); + } + } + + filename.Append(NS_ConvertASCIItoUTF16(substring)); + filename.AppendLiteral(".sqlite"); + + rv = dbFile->Append(filename); + NS_ENSURE_SUCCESS(rv, rv); + + dbFile.forget(aDatabaseFile); + return NS_OK; +} + +nsresult +CreateTables(mozIStorageConnection* aDBConn) +{ + NS_PRECONDITION(!NS_IsMainThread(), + "Creating tables on the main thread!"); + NS_PRECONDITION(aDBConn, "Passing a null database connection!"); + + // Table `database` + nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE database (" + "name TEXT NOT NULL, " + "version INTEGER NOT NULL DEFAULT 0, " + "dataVersion INTEGER NOT NULL" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `object_store` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE object_store (" + "id INTEGER, " + "name TEXT NOT NULL, " + "key_path TEXT NOT NULL, " + "auto_increment INTEGER NOT NULL DEFAULT 0, " + "PRIMARY KEY (id), " + "UNIQUE (name)" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `object_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE object_data (" + "id INTEGER, " + "object_store_id INTEGER NOT NULL, " + "data BLOB NOT NULL, " + "key_value DEFAULT NULL, " // NONE affinity + "PRIMARY KEY (id), " + "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE UNIQUE INDEX key_index " + "ON object_data (key_value, object_store_id);" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `ai_object_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE ai_object_data (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "object_store_id INTEGER NOT NULL, " + "data BLOB NOT NULL, " + "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE UNIQUE INDEX ai_key_index " + "ON ai_object_data (id, object_store_id);" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `index` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE object_store_index (" + "id INTEGER, " + "object_store_id INTEGER NOT NULL, " + "name TEXT NOT NULL, " + "key_path TEXT NOT NULL, " + "unique_index INTEGER NOT NULL, " + "object_store_autoincrement INTERGER NOT NULL, " + "PRIMARY KEY (id), " + "UNIQUE (object_store_id, name), " + "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `index_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE index_data (" + "id INTEGER, " + "index_id INTEGER NOT NULL, " + "object_data_id INTEGER NOT NULL, " + "object_data_key NOT NULL, " // NONE affinity + "value NOT NULL, " + "PRIMARY KEY (id), " + "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " + "CASCADE, " + "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE INDEX value_index " + "ON index_data (index_id, value);" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `unique_index_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE unique_index_data (" + "id INTEGER, " + "index_id INTEGER NOT NULL, " + "object_data_id INTEGER NOT NULL, " + "object_data_key NOT NULL, " // NONE affinity + "value NOT NULL, " + "PRIMARY KEY (id), " + "UNIQUE (index_id, value), " + "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " + "CASCADE " + "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `ai_index_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE ai_index_data (" + "id INTEGER, " + "index_id INTEGER NOT NULL, " + "ai_object_data_id INTEGER NOT NULL, " + "value NOT NULL, " + "PRIMARY KEY (id), " + "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " + "CASCADE, " + "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE INDEX ai_value_index " + "ON ai_index_data (index_id, value);" + )); + NS_ENSURE_SUCCESS(rv, rv); + + // Table `ai_unique_index_data` + rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE ai_unique_index_data (" + "id INTEGER, " + "index_id INTEGER NOT NULL, " + "ai_object_data_id INTEGER NOT NULL, " + "value NOT NULL, " + "PRIMARY KEY (id), " + "UNIQUE (index_id, value), " + "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE " + "CASCADE, " + "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE " + "CASCADE" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult +CreateMetaData(mozIStorageConnection* aConnection, + const nsAString& aName) +{ + NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!"); + NS_PRECONDITION(aConnection, "Null database!"); + + nsCOMPtr stmt; + nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( + "INSERT OR REPLACE INTO database (name, dataVersion) " + "VALUES (:name, :dataVersion)" + ), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"), + JS_STRUCTURED_CLONE_VERSION); + NS_ENSURE_SUCCESS(rv, rv); + + return stmt->Execute(); +} + +nsresult +UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection) +{ + nsresult rv; + + mozStorageTransaction transaction(aConnection, false, + mozIStorageConnection::TRANSACTION_IMMEDIATE); + + // All we changed is the type of the version column, so lets try to + // convert that to an integer, and if we fail, set it to 0. + nsCOMPtr stmt; + rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( + "SELECT name, version, dataVersion " + "FROM database" + ), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + nsString name; + PRInt32 intVersion; + PRInt64 dataVersion; + + { + mozStorageStatementScoper scoper(stmt); + + bool hasResults; + rv = stmt->ExecuteStep(&hasResults); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(hasResults, NS_ERROR_FAILURE); + + nsString version; + rv = stmt->GetString(1, version); + NS_ENSURE_SUCCESS(rv, rv); + + intVersion = version.ToInteger(&rv, 10); + if (NS_FAILED(rv)) { + intVersion = 0; + } + + rv = stmt->GetString(0, name); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->GetInt64(2, &dataVersion); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "DROP TABLE database" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE database (" + "name TEXT NOT NULL, " + "version INTEGER NOT NULL DEFAULT 0, " + "dataVersion INTEGER NOT NULL" + ");" + )); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( + "INSERT INTO database (name, version, dataVersion) " + "VALUES (:name, :version, :dataVersion)" + ), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, rv); + + { + mozStorageStatementScoper scoper(stmt); + + rv = stmt->BindStringParameter(0, name); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->BindInt32Parameter(1, intVersion); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->BindInt64Parameter(2, dataVersion); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = aConnection->SetSchemaVersion(DB_SCHEMA_VERSION); + NS_ENSURE_SUCCESS(rv, rv); + + rv = transaction.Commit(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult +CreateDatabaseConnection(const nsAString& aName, + nsIFile* aDBFile, + mozIStorageConnection** aConnection) +{ + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + + nsCOMPtr dbDirectory; + nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory)); + NS_ENSURE_SUCCESS(rv, rv); + + bool exists; + rv = aDBFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota"); + + nsCOMPtr ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); + + nsCOMPtr connection; + rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, + getter_AddRefs(connection)); + if (rv == NS_ERROR_FILE_CORRUPTED) { + // Nuke the database file. The web services can recreate their data. + rv = aDBFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + + exists = false; + + rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, + getter_AddRefs(connection)); + } + NS_ENSURE_SUCCESS(rv, rv); + + // Check to make sure that the database schema is correct. + PRInt32 schemaVersion; + rv = connection->GetSchemaVersion(&schemaVersion); + NS_ENSURE_SUCCESS(rv, rv); + + if (schemaVersion != DB_SCHEMA_VERSION) { + // This logic needs to change next time we change the schema! + PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 5); + if (schemaVersion == 4) { + rv = UpgradeSchemaFrom4To5(connection); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + // Nuke it from orbit, it's the only way to be sure. + if (exists) { + // If the connection is not at the right schema version, nuke it. + rv = aDBFile->Remove(false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, + getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, rv); + } + + mozStorageTransaction transaction(connection, false, + mozIStorageConnection::TRANSACTION_IMMEDIATE); + rv = CreateTables(connection); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CreateMetaData(connection, aName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = transaction.Commit(); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + // Check to make sure that the database schema is correct again. + NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) && + schemaVersion == DB_SCHEMA_VERSION, + "CreateTables failed!"); + + // Turn on foreign key constraints. + rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "PRAGMA foreign_keys = ON;" + )); + NS_ENSURE_SUCCESS(rv, rv); + + connection.forget(aConnection); + return NS_OK; +} + +class SetVersionHelper : public AsyncConnectionHelper, + public IDBTransactionListener +{ +public: + SetVersionHelper(IDBTransaction* aTransaction, + IDBOpenDBRequest* aRequest, + OpenDatabaseHelper* aHelper, + PRUint64 aRequestedVersion, + PRUint64 aCurrentVersion) + : AsyncConnectionHelper(aTransaction, aRequest), + mOpenRequest(aRequest), mOpenHelper(aHelper), + mRequestedVersion(aRequestedVersion), + mCurrentVersion(aCurrentVersion) + { + mTransaction->SetTransactionListener(this); + } + + NS_DECL_ISUPPORTS_INHERITED + + nsresult GetSuccessResult(JSContext* aCx, + jsval* aVal); + +protected: + nsresult DoDatabaseWork(mozIStorageConnection* aConnection); + nsresult Init(); + + // SetVersionHelper never fires an error event at the request. It hands that + // responsibility back to the OpenDatabaseHelper + void OnError() { } + + // Need an upgradeneeded event here. + already_AddRefed CreateSuccessEvent(); + + nsresult NotifyTransactionComplete(IDBTransaction* aTransaction); + +private: + // In-params + nsRefPtr mOpenHelper; + nsRefPtr mOpenRequest; + PRUint64 mRequestedVersion; + PRUint64 mCurrentVersion; +}; + +} // anonymous namespace + +NS_IMPL_THREADSAFE_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable); + +nsresult +OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget) +{ + NS_ASSERTION(mState == eCreated, "We've already been dispatched?"); + mState = eDBWork; + + return aTarget->Dispatch(this, NS_DISPATCH_NORMAL); +} + +nsresult +OpenDatabaseHelper::RunImmediately() +{ + NS_ASSERTION(mState == eCreated, "We've already been dispatched?"); + NS_ASSERTION(NS_FAILED(mResultCode), + "Should only be short-circuiting if we failed!"); + NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!"); + + mState = eFiringEvents; + return this->Run(); +} + +nsresult +OpenDatabaseHelper::DoDatabaseWork() +{ +#ifdef DEBUG + { + bool correctThread; + NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()-> + IsOnCurrentThread(&correctThread)) && + correctThread, + "Running on the wrong thread!"); + } +#endif + + mState = eFiringEvents; // In case we fail somewhere along the line. + + if (IndexedDatabaseManager::IsShuttingDown()) { + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + + nsCOMPtr dbFile; + nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + rv = dbFile->GetPath(mDatabaseFilePath); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsCOMPtr dbDirectory; + rv = dbFile->GetParent(getter_AddRefs(dbDirectory)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + bool exists; + rv = dbDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (exists) { + bool isDirectory; + rv = dbDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + else { + rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never be null!"); + + rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsCOMPtr connection; + rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + // Get the data version. + nsCOMPtr stmt; + rv = connection->CreateStatement(NS_LITERAL_CSTRING( + "SELECT dataVersion " + "FROM database" + ), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + bool hasResult; + rv = stmt->ExecuteStep(&hasResult); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (!hasResult) { + NS_ERROR("Database has no dataVersion!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + + PRInt64 dataVersion; + rv = stmt->GetInt64(0, &dataVersion); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (dataVersion > JS_STRUCTURED_CLONE_VERSION) { + NS_ERROR("Bad data version!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + + if (dataVersion < JS_STRUCTURED_CLONE_VERSION) { + // Need to upgrade the database, here, before returning to the main thread. + NS_NOTYETIMPLEMENTED("Implement me!"); + } + + mDatabaseId = HashString(mDatabaseFilePath); + NS_ASSERTION(mDatabaseId, "HashString gave us 0?!"); + + rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, &mCurrentVersion, + mObjectStores); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + for (PRUint32 i = 0; i < mObjectStores.Length(); i++) { + nsAutoPtr& objectStoreInfo = mObjectStores[i]; + for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) { + IndexInfo& indexInfo = objectStoreInfo->indexes[j]; + mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId); + } + mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId); + } + + // See if we need to do a VERSION_CHANGE transaction + if (mCurrentVersion > mRequestedVersion) { + return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR; + } + + if (mCurrentVersion != mRequestedVersion) { + mState = eSetVersionPending; + } + + return NS_OK; +} + +nsresult +OpenDatabaseHelper::StartSetVersion() +{ + NS_ASSERTION(mState == eSetVersionPending, "Why are we here?"); + + // In case we fail, fire error events + mState = eFiringEvents; + + nsresult rv = EnsureSuccessResult(); + NS_ENSURE_SUCCESS(rv, rv); + + nsTArray storesToOpen; + nsRefPtr transaction = + IDBTransaction::Create(mDatabase, storesToOpen, + IDBTransaction::VERSION_CHANGE, + kDefaultDatabaseTimeoutSeconds, true); + NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsRefPtr helper = + new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion, + mCurrentVersion); + + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never be null!"); + + rv = mgr->SetDatabaseVersion(mDatabase, mOpenDBRequest, mCurrentVersion, + mRequestedVersion, helper); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + // The SetVersionHelper is responsible for dispatching us back to the + // main thread again and changing the state to eSetVersionCompleted. + mState = eSetVersionPending; + + return NS_OK; +} + +NS_IMETHODIMP +OpenDatabaseHelper::Run() +{ + NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?"); + + if (NS_IsMainThread()) { + // If we need to queue up a SetVersionHelper, do that here. + if (mState == eSetVersionPending) { + nsresult rv = StartSetVersion(); + + if (NS_SUCCEEDED(rv)) { + return rv; + } + + SetError(rv); + // fall through and run the default error processing + } + + // We've done whatever work we need to do on the DB thread, and any + // SetVersion stuff is done by now. + NS_ASSERTION(mState == eFiringEvents || + mState == eSetVersionCompleted, "Why are we here?"); + + if (mState == eSetVersionCompleted) { + // Allow transaction creation/other version change transactions to proceed + // before we fire events. Other version changes will be postd to the end + // of the event loop, and will be behind whatever the page does in + // its error/success event handlers. + mDatabase->ExitSetVersionTransaction(); + + mState = eFiringEvents; + } else { + // Notify the request that we're done, but only if we didn't just finish + // a SetVersionHelper. In the SetVersionHelper case, that helper tells + // the request that it is done, and we avoid calling NotifyHandlerCompleted + // twice. + + nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this); + if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { + mResultCode = rv; + } + } + + NS_ASSERTION(mState == eFiringEvents, "Why are we here?"); + + if (NS_FAILED(mResultCode)) { + DispatchErrorEvent(); + } else { + DispatchSuccessEvent(); + } + + ReleaseMainThreadObjects(); + + return NS_OK; + } + + // If we're on the DB thread, do that + NS_ASSERTION(mState == eDBWork, "Why are we here?"); + mResultCode = DoDatabaseWork(); + NS_ASSERTION(mState != eDBWork, "We should be doing something else now."); + + return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); +} + +nsresult +OpenDatabaseHelper::EnsureSuccessResult() +{ + DatabaseInfo* dbInfo; + if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) { + NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!"); + ++dbInfo->referenceCount; + +#ifdef DEBUG + { + NS_ASSERTION(dbInfo->name == mName && + dbInfo->version == mCurrentVersion && + dbInfo->id == mDatabaseId && + dbInfo->filePath == mDatabaseFilePath, + "Metadata mismatch!"); + + PRUint32 objectStoreCount = mObjectStores.Length(); + for (PRUint32 index = 0; index < objectStoreCount; index++) { + nsAutoPtr& info = mObjectStores[index]; + NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!"); + + ObjectStoreInfo* otherInfo; + NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &otherInfo), + "ObjectStore not known!"); + + NS_ASSERTION(info->name == otherInfo->name && + info->id == otherInfo->id && + info->keyPath == otherInfo->keyPath && + info->autoIncrement == otherInfo->autoIncrement && + info->databaseId == otherInfo->databaseId, + "Metadata mismatch!"); + NS_ASSERTION(dbInfo->ContainsStoreName(info->name), + "Object store names out of date!"); + NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(), + "Bad index length!"); + + PRUint32 indexCount = info->indexes.Length(); + for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) { + const IndexInfo& indexInfo = info->indexes[indexIndex]; + const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex]; + NS_ASSERTION(indexInfo.id == otherIndexInfo.id, + "Bad index id!"); + NS_ASSERTION(indexInfo.name == otherIndexInfo.name, + "Bad index name!"); + NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath, + "Bad index keyPath!"); + NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique, + "Bad index unique value!"); + NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement, + "Bad index autoIncrement value!"); + } + } + } +#endif + + } + else { + nsAutoPtr newInfo(new DatabaseInfo()); + + newInfo->name = mName; + newInfo->id = mDatabaseId; + newInfo->filePath = mDatabaseFilePath; + newInfo->referenceCount = 1; + + if (!DatabaseInfo::Put(newInfo)) { + NS_ERROR("Failed to add to hash!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + + dbInfo = newInfo.forget(); + + nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion, + mObjectStores); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!"); + } + + dbInfo->nextObjectStoreId = mLastObjectStoreId + 1; + dbInfo->nextIndexId = mLastIndexId + 1; + + nsRefPtr database = + IDBDatabase::Create(mOpenDBRequest->ScriptContext(), + mOpenDBRequest->Owner(), dbInfo, mASCIIOrigin); + if (!database) { + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + + NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!"); + mDatabase.swap(database); + + return NS_OK; +} + +nsresult +OpenDatabaseHelper::GetSuccessResult(JSContext* aCx, + jsval* aVal) +{ + // Be careful not to load the database twice. + if (!mDatabase) { + nsresult rv = EnsureSuccessResult(); + NS_ENSURE_SUCCESS(rv, rv); + } + + return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase), + aVal); +} + +nsresult +OpenDatabaseHelper::NotifySetVersionFinished() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread"); + NS_ASSERTION(mState = eSetVersionPending, "How did we get here?"); + + mState = eSetVersionCompleted; + + // Dispatch ourself back to the main thread + return NS_DispatchToCurrentThread(this); +} + +void +OpenDatabaseHelper::BlockDatabase() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ASSERTION(mDatabase, "This is going bad fast."); + + mDatabase->EnterSetVersionTransaction(); +} + +void +OpenDatabaseHelper::DispatchSuccessEvent() +{ + NS_ASSERTION(mDatabase, "Doesn't seem very successful to me."); + + nsRefPtr event = + CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR)); + if (!event) { + NS_ERROR("Failed to create event!"); + return; + } + + bool dummy; + mOpenDBRequest->DispatchEvent(event, &dummy); +} + +void +OpenDatabaseHelper::DispatchErrorEvent() +{ + nsRefPtr event = + CreateGenericEvent(NS_LITERAL_STRING(ERROR_EVT_STR)); + if (!event) { + NS_ERROR("Failed to create event!"); + return; + } + + PRUint16 errorCode = 0; + DebugOnly rv = + mOpenDBRequest->GetErrorCode(&errorCode); + NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't be failing at this point!"); + if (!errorCode) { + mOpenDBRequest->SetError(mResultCode); + } + + bool dummy; + mOpenDBRequest->DispatchEvent(event, &dummy); +} + +void +OpenDatabaseHelper::ReleaseMainThreadObjects() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + mOpenDBRequest = nsnull; + mDatabase = nsnull; + + HelperBase::ReleaseMainThreadObjects(); +} + +NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper); + +nsresult +SetVersionHelper::Init() +{ + // Block transaction creation until we are done. + mOpenHelper->BlockDatabase(); + + return NS_OK; +} + +nsresult +SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection) +{ + NS_ASSERTION(aConnection, "Passing a null connection!"); + + nsCOMPtr stmt; + nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( + "UPDATE database " + "SET version = :version" + ), getter_AddRefs(stmt)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"), + mRequestedVersion); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (NS_FAILED(stmt->Execute())) { + return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; + } + + return NS_OK; +} + +nsresult +SetVersionHelper::GetSuccessResult(JSContext* aCx, + jsval* aVal) +{ + DatabaseInfo* info; + if (!DatabaseInfo::Get(mDatabase->Id(), &info)) { + NS_ERROR("This should never fail!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + info->version = mRequestedVersion; + + NS_ASSERTION(mTransaction, "Better have a transaction!"); + + mOpenRequest->SetTransaction(mTransaction); + + return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase), + aVal); +} + +already_AddRefed +SetVersionHelper::CreateSuccessEvent() +{ + NS_ASSERTION(mCurrentVersion < mRequestedVersion, "Huh?"); + + return IDBVersionChangeEvent::CreateUpgradeNeeded(mCurrentVersion, + mRequestedVersion); +} + +nsresult +SetVersionHelper::NotifyTransactionComplete(IDBTransaction* aTransaction) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ASSERTION(aTransaction, "This is unexpected."); + NS_ASSERTION(mOpenRequest, "Why don't we have a request?"); + + // If we hit an error, the OpenDatabaseHelper needs to get that error too. + nsresult rv = GetResultCode(); + if (NS_FAILED(rv)) { + mOpenHelper->SetError(rv); + } + + // If the transaction was aborted, we should throw an error message. + if (aTransaction->IsAborted()) { + mOpenHelper->SetError(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR); + } + + mOpenRequest->SetTransaction(nsnull); + + rv = mOpenHelper->NotifySetVersionFinished(); + mOpenHelper = nsnull; + + return rv; +} diff --git a/dom/indexedDB/OpenDatabaseHelper.h b/dom/indexedDB/OpenDatabaseHelper.h new file mode 100644 index 000000000000..53334867ab32 --- /dev/null +++ b/dom/indexedDB/OpenDatabaseHelper.h @@ -0,0 +1,131 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Indexed Database. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ben Turner + * Kyle Huey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef mozilla_dom_indexeddb_opendatabasehelper_h__ +#define mozilla_dom_indexeddb_opendatabasehelper_h__ + +#include "AsyncConnectionHelper.h" +#include "DatabaseInfo.h" +#include "IDBDatabase.h" +#include "IDBRequest.h" + +#include "nsIRunnable.h" + +class mozIStorageConnection; + +BEGIN_INDEXEDDB_NAMESPACE + +class OpenDatabaseHelper : public HelperBase +{ +public: + OpenDatabaseHelper(IDBOpenDBRequest* aRequest, + const nsAString& aName, + const nsACString& aASCIIOrigin, + PRUint64 aRequestedVersion) + : HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName), + mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion), + mCurrentVersion(0), mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0), + mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated), + mResultCode(NS_OK) + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + nsresult Dispatch(nsIEventTarget* aDatabaseThread); + nsresult RunImmediately(); + + void SetError(nsresult rv) + { + NS_ASSERTION(NS_FAILED(rv), "Why are you telling me?"); + mResultCode = rv; + } + + nsresult GetResultCode() + { + return mResultCode; + } + + nsresult NotifySetVersionFinished(); + void BlockDatabase(); + +protected: + // Methods only called on the main thread + nsresult EnsureSuccessResult(); + nsresult StartSetVersion(); + nsresult GetSuccessResult(JSContext* aCx, + jsval* aVal); + void DispatchSuccessEvent(); + void DispatchErrorEvent(); + void ReleaseMainThreadObjects(); + + // Methods only called on the DB thread + nsresult DoDatabaseWork(); + +private: + // In-params. + nsRefPtr mOpenDBRequest; + nsString mName; + nsCString mASCIIOrigin; + PRUint64 mRequestedVersion; + + // Out-params. + nsTArray > mObjectStores; + PRUint64 mCurrentVersion; + PRUint32 mDataVersion; + nsString mDatabaseFilePath; + PRUint32 mDatabaseId; + PRInt64 mLastObjectStoreId; + PRInt64 mLastIndexId; + nsRefPtr mDatabase; + + // State variables + enum OpenDatabaseState { + eCreated = 0, // Not yet dispatched to the DB thread + eDBWork, // Waiting to do/doing work on the DB thread + eFiringEvents, // Waiting to fire/firing events on the main thread + eSetVersionPending, // Waiting on a SetVersionHelper + eSetVersionCompleted, // SetVersionHelper is done + }; + OpenDatabaseState mState; + nsresult mResultCode; +}; + +END_INDEXEDDB_NAMESPACE + +#endif // mozilla_dom_indexeddb_opendatabasehelper_h__ diff --git a/dom/indexedDB/TransactionThreadPool.cpp b/dom/indexedDB/TransactionThreadPool.cpp index 2bb66132b486..c78ba97ef90d 100644 --- a/dom/indexedDB/TransactionThreadPool.cpp +++ b/dom/indexedDB/TransactionThreadPool.cpp @@ -238,7 +238,6 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction) #ifdef DEBUG if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) { - NS_ASSERTION(dbTransactionInfo->locked, "Should be locked!"); NS_ASSERTION(transactionCount == 1, "More transactions running than should be!"); } @@ -344,10 +343,6 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction, PRUint32 transactionCount = transactionsInProgress.Length(); NS_ASSERTION(transactionCount, "Should never be 0!"); - if (mode == IDBTransaction::VERSION_CHANGE) { - dbTransactionInfo->lockPending = true; - } - for (PRUint32 index = 0; index < transactionCount; index++) { // See if this transaction is in out list of current transactions. const TransactionInfo& info = transactionsInProgress[index]; @@ -358,11 +353,7 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction, } } - if (dbTransactionInfo->locked || dbTransactionInfo->lockPending) { - *aCanRun = false; - *aExistingQueue = nsnull; - return NS_OK; - } + NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?"); bool writeOverlap; nsresult rv = @@ -448,11 +439,6 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction, dbTransactionInfo = autoDBTransactionInfo; } - if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) { - NS_ASSERTION(!dbTransactionInfo->locked, "Already locked?!"); - dbTransactionInfo->locked = true; - } - const nsTArray& objectStoreNames = aTransaction->mObjectStoreNames; nsTArray& storesInUse = diff --git a/dom/indexedDB/TransactionThreadPool.h b/dom/indexedDB/TransactionThreadPool.h index 97d15c469170..4fdd152c4b04 100644 --- a/dom/indexedDB/TransactionThreadPool.h +++ b/dom/indexedDB/TransactionThreadPool.h @@ -123,12 +123,6 @@ protected: struct DatabaseTransactionInfo { - DatabaseTransactionInfo() - : locked(false), lockPending(false) - { } - - bool locked; - bool lockPending; nsTArray transactions; nsTArray storesReading; nsTArray storesWriting; diff --git a/dom/indexedDB/nsIIDBDatabase.idl b/dom/indexedDB/nsIIDBDatabase.idl index 5f550fb13ee4..83d23700196d 100644 --- a/dom/indexedDB/nsIIDBDatabase.idl +++ b/dom/indexedDB/nsIIDBDatabase.idl @@ -51,12 +51,12 @@ interface nsIDOMEventListener; * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase * for more information. */ -[scriptable, uuid(42b38d02-1a29-45f0-99ef-04fd5b441270)] +[scriptable, uuid(ac14faa5-261c-4a84-9616-a700fd606f83)] interface nsIIDBDatabase : nsISupports { readonly attribute DOMString name; - readonly attribute DOMString version; + readonly attribute unsigned long long version; readonly attribute nsIDOMDOMStringList objectStoreNames; @@ -76,10 +76,6 @@ interface nsIIDBDatabase : nsISupports void deleteObjectStore(in AString name); - [implicit_jscontext] - nsIIDBRequest - setVersion(in AString version); - [optional_argc, implicit_jscontext] nsIIDBTransaction transaction(in nsIVariant storeNames, // js array of strings diff --git a/dom/indexedDB/nsIIDBFactory.idl b/dom/indexedDB/nsIIDBFactory.idl index fcd3c06be487..8ed0fe18af16 100644 --- a/dom/indexedDB/nsIIDBFactory.idl +++ b/dom/indexedDB/nsIIDBFactory.idl @@ -41,7 +41,7 @@ #include "nsISupports.idl" interface nsIIDBKeyRange; -interface nsIIDBRequest; +interface nsIIDBOpenDBRequest; interface nsIVariant; /** @@ -49,10 +49,10 @@ interface nsIVariant; * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory * for more information. */ -[scriptable, uuid(137d17a5-fac5-4788-87b5-bc3806d7cfaf)] +[scriptable, uuid(4b23254a-ce6d-4442-8c90-9d8744d3c633)] interface nsIIDBFactory : nsISupports { [implicit_jscontext] - nsIIDBRequest - open(in AString name); + nsIIDBOpenDBRequest + open(in AString name, in long long version); }; diff --git a/dom/indexedDB/nsIIDBVersionChangeRequest.idl b/dom/indexedDB/nsIIDBOpenDBRequest.idl similarity index 87% rename from dom/indexedDB/nsIIDBVersionChangeRequest.idl rename to dom/indexedDB/nsIIDBOpenDBRequest.idl index e35508d6c0e7..19b26344b8de 100644 --- a/dom/indexedDB/nsIIDBVersionChangeRequest.idl +++ b/dom/indexedDB/nsIIDBOpenDBRequest.idl @@ -43,12 +43,13 @@ interface nsIDOMEventListener; /** - * IDBReqeust interface. See - * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more - * information. + * IDBOpenDBRequest interface. See + * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest + * for more information. */ -[scriptable, uuid(aeaabb0d-594a-4c58-ac5e-68ef3bff927d)] -interface nsIIDBVersionChangeRequest : nsISupports +[scriptable, uuid(91010fbe-1dfb-435d-852e-288d2804c0a7)] +interface nsIIDBOpenDBRequest : nsISupports { attribute nsIDOMEventListener onblocked; + attribute nsIDOMEventListener onupgradeneeded; }; diff --git a/dom/indexedDB/nsIIDBVersionChangeEvent.idl b/dom/indexedDB/nsIIDBVersionChangeEvent.idl index 41d45068d1ac..0710ac385b37 100644 --- a/dom/indexedDB/nsIIDBVersionChangeEvent.idl +++ b/dom/indexedDB/nsIIDBVersionChangeEvent.idl @@ -39,8 +39,9 @@ #include "nsIDOMEvent.idl" -[scriptable, uuid(6a232c30-1bc4-4d5b-9ce0-6e7c08934755)] +[scriptable, uuid(2c5159dc-7d71-4fc6-a3b3-884ed7586456)] interface nsIIDBVersionChangeEvent : nsIDOMEvent { - readonly attribute AString version; + readonly attribute unsigned long long oldVersion; + readonly attribute unsigned long long newVersion; }; diff --git a/dom/indexedDB/test/Makefile.in b/dom/indexedDB/test/Makefile.in index 555fbeaf93fd..9d7d00f15f6d 100644 --- a/dom/indexedDB/test/Makefile.in +++ b/dom/indexedDB/test/Makefile.in @@ -98,6 +98,7 @@ TEST_FILES = \ test_setVersion.html \ test_setVersion_abort.html \ test_setVersion_events.html \ + test_setVersion_exclusion.html \ test_writer_starvation.html \ third_party_iframe1.html \ third_party_iframe2.html \ diff --git a/dom/indexedDB/test/bfcache_iframe1.html b/dom/indexedDB/test/bfcache_iframe1.html index e8c3a3ee80e2..dc4e37dc0eb4 100644 --- a/dom/indexedDB/test/bfcache_iframe1.html +++ b/dom/indexedDB/test/bfcache_iframe1.html @@ -2,14 +2,14 @@ diff --git a/dom/indexedDB/test/bfcache_iframe2.html b/dom/indexedDB/test/bfcache_iframe2.html index 1b7f35767b48..0f596fdf5d2b 100644 --- a/dom/indexedDB/test/bfcache_iframe2.html +++ b/dom/indexedDB/test/bfcache_iframe2.html @@ -2,26 +2,24 @@ diff --git a/dom/indexedDB/test/browser_forgetThisSite.js b/dom/indexedDB/test/browser_forgetThisSite.js index 7085da699eba..8478369d0ac7 100644 --- a/dom/indexedDB/test/browser_forgetThisSite.js +++ b/dom/indexedDB/test/browser_forgetThisSite.js @@ -33,7 +33,7 @@ function test1() gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); setFinishedCallback(function(result, exception) { - ok(result == "11", "Set version on database in " + testPageURL1); + ok(result == 11, "Set version on database in " + testPageURL1); ok(!exception, "No exception"); gBrowser.removeCurrentTab(); @@ -51,7 +51,7 @@ function test2() gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); setFinishedCallback(function(result, exception) { - ok(result == "11", "Set version on database in " + testPageURL2); + ok(result == 11, "Set version on database in " + testPageURL2); ok(!exception, "No exception"); gBrowser.removeCurrentTab(); @@ -79,7 +79,7 @@ function test4() gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); setFinishedCallback(function(result, exception) { - ok(result == "11", "Got correct version on database in " + testPageURL3); + ok(result == 11, "Got correct version on database in " + testPageURL3); ok(!exception, "No exception"); gBrowser.removeCurrentTab(); @@ -97,7 +97,9 @@ function test5() gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); setFinishedCallback(function(result, exception) { - ok(result == "", "Got correct version on database in " + testPageURL4); + // XXXkhuey this isn't really testing anything until we get the default + // version behavior implemented ... + ok(result == 11, "Got correct version on database in " + testPageURL4); ok(!exception, "No exception"); gBrowser.removeCurrentTab(); diff --git a/dom/indexedDB/test/browser_forgetThisSiteAdd.html b/dom/indexedDB/test/browser_forgetThisSiteAdd.html index 5b698aadf727..2a7525d4ec64 100644 --- a/dom/indexedDB/test/browser_forgetThisSiteAdd.html +++ b/dom/indexedDB/test/browser_forgetThisSiteAdd.html @@ -9,9 +9,9 @@ + + + + + + + + + + diff --git a/dom/indexedDB/test/test_success_events_after_abort.html b/dom/indexedDB/test/test_success_events_after_abort.html index 1d03ec9ac5df..31a29d59d563 100644 --- a/dom/indexedDB/test/test_success_events_after_abort.html +++ b/dom/indexedDB/test/test_success_events_after_abort.html @@ -12,19 +12,14 @@ - + diff --git a/dom/tests/browser/browser_ConsoleAPITests.js b/dom/tests/browser/browser_ConsoleAPITests.js index 0729aa720042..eee1f4672701 100644 --- a/dom/tests/browser/browser_ConsoleAPITests.js +++ b/dom/tests/browser/browser_ConsoleAPITests.js @@ -220,10 +220,15 @@ function observeConsoleTest() { expect("log", "2, a, %l", 3); win.console.log("%d, %s, %l", 2, "a", 3); - // bug #692550 handle null and undefined + // Bug #692550 handle null and undefined. expect("log", "null, undefined"); win.console.log("%s, %s", null, undefined); + // Bug #696288 handle object as first argument. + let obj = { a: 1 }; + expect("log", obj, "a"); + win.console.log(obj, "a"); + expect("dir", win.toString()); win.console.dir(win); diff --git a/dom/tests/mochitest/bugs/Makefile.in b/dom/tests/mochitest/bugs/Makefile.in index 0a987e909e06..62bbd1b1c2a8 100644 --- a/dom/tests/mochitest/bugs/Makefile.in +++ b/dom/tests/mochitest/bugs/Makefile.in @@ -52,6 +52,8 @@ _TEST_FILES = \ test_bug159849.html \ test_bug265203.html \ test_bug291377.html \ + file_bug291653.html \ + test_bug291653.html \ test_bug308856.html \ test_bug317448.html \ test_bug327891.html \ diff --git a/dom/tests/mochitest/bugs/file_bug291653.html b/dom/tests/mochitest/bugs/file_bug291653.html new file mode 100644 index 000000000000..4bfc8337e8d7 --- /dev/null +++ b/dom/tests/mochitest/bugs/file_bug291653.html @@ -0,0 +1,28 @@ + + + + + + Test for bug 291653 + + diff --git a/dom/tests/mochitest/bugs/test_bug291653.html b/dom/tests/mochitest/bugs/test_bug291653.html new file mode 100644 index 000000000000..024a60d71e12 --- /dev/null +++ b/dom/tests/mochitest/bugs/test_bug291653.html @@ -0,0 +1,46 @@ + + + + + Test for Bug 291653 + + + + +Mozilla Bug 291653 +

+ +
+
+
+ + diff --git a/dom/tests/mochitest/bugs/test_bug633133.html b/dom/tests/mochitest/bugs/test_bug633133.html index 66efc5ecee25..2d5f11661462 100644 --- a/dom/tests/mochitest/bugs/test_bug633133.html +++ b/dom/tests/mochitest/bugs/test_bug633133.html @@ -28,7 +28,7 @@ var divCollection = document.getElementsByTagName('div'); ok("foo" in divCollection, "'foo' should be in the div collection"); ok("bar" in divCollection, "'bar' should be in the div collection"); -ok("" in divCollection, "empty string should be in the div collection"); +ok(!("" in divCollection), "empty string shouldn't be in the div collection"); ok(!("foobar" in divCollection), "'foobar' shouldn't be in the div collection"); var select = $('select'); diff --git a/dom/workers/Events.cpp b/dom/workers/Events.cpp index 6b8d00122eec..d2884a88ad34 100644 --- a/dom/workers/Events.cpp +++ b/dom/workers/Events.cpp @@ -37,6 +37,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/Util.h" + #include "Events.h" #include "jsapi.h" @@ -57,6 +59,7 @@ #define CONSTANT_FLAGS \ JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY +using namespace mozilla; USING_WORKERS_NAMESPACE namespace { @@ -1126,7 +1129,7 @@ DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent, if (hasProperty) { jsval argv[] = { OBJECT_TO_JSVAL(aEvent) }; jsval rval = JSVAL_VOID; - if (!JS_CallFunctionName(aCx, aTarget, kFunctionName, JS_ARRAY_LENGTH(argv), + if (!JS_CallFunctionName(aCx, aTarget, kFunctionName, ArrayLength(argv), argv, &rval) || !JS_ValueToBoolean(aCx, rval, &preventDefaultCalled)) { return false; diff --git a/dom/workers/Exceptions.cpp b/dom/workers/Exceptions.cpp index 04fd886cb6ab..d2eaf6a26852 100644 --- a/dom/workers/Exceptions.cpp +++ b/dom/workers/Exceptions.cpp @@ -37,6 +37,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/Util.h" + #include "Exceptions.h" #include "jsapi.h" @@ -54,6 +56,7 @@ #define CONSTANT_FLAGS \ JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY +using namespace mozilla; USING_WORKERS_NAMESPACE namespace { @@ -247,9 +250,7 @@ DOMException::Create(JSContext* aCx, intN aCode) } size_t foundIndex = size_t(-1); - for (size_t index = 0; - index < JS_ARRAY_LENGTH(sStaticProperties) - 1; - index++) { + for (size_t index = 0; index < ArrayLength(sStaticProperties) - 1; index++) { if (sStaticProperties[index].tinyid == aCode) { foundIndex = index; break; @@ -397,9 +398,7 @@ FileException::Create(JSContext* aCx, intN aCode) } size_t foundIndex = size_t(-1); - for (size_t index = 0; - index < JS_ARRAY_LENGTH(sStaticProperties) - 1; - index++) { + for (size_t index = 0; index < ArrayLength(sStaticProperties) - 1; index++) { if (sStaticProperties[index].tinyid == aCode) { foundIndex = index; break; diff --git a/dom/workers/ListenerManager.cpp b/dom/workers/ListenerManager.cpp index 9383cef27e96..3f7da2bb5736 100644 --- a/dom/workers/ListenerManager.cpp +++ b/dom/workers/ListenerManager.cpp @@ -36,6 +36,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/Util.h" + #include "ListenerManager.h" #include "jsapi.h" @@ -44,7 +46,8 @@ #include "Events.h" -using mozilla::dom::workers::events::ListenerManager; +using namespace mozilla; +using dom::workers::events::ListenerManager; namespace { @@ -426,7 +429,7 @@ ListenerManager::DispatchEvent(JSContext* aCx, JSObject* aTarget, jsval argv[] = { OBJECT_TO_JSVAL(aEvent) }; jsval rval = JSVAL_VOID; - if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, JS_ARRAY_LENGTH(argv), + if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, ArrayLength(argv), argv, &rval)) { if (!JS_ReportPendingException(aCx)) { return false; diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 7eae4c58d683..a2210474250e 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -37,6 +37,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/Util.h" + #include "WorkerScope.h" #include "jsapi.h" @@ -68,6 +70,7 @@ #define FUNCTION_FLAGS \ JSPROP_ENUMERATE +using namespace mozilla; USING_WORKERS_NAMESPACE namespace { @@ -287,7 +290,7 @@ private: jsval rval = JSVAL_VOID; if (!JS_CallFunctionValue(aCx, JSVAL_TO_OBJECT(scope), listener, - JS_ARRAY_LENGTH(argv), argv, &rval)) { + ArrayLength(argv), argv, &rval)) { JS_ReportPendingException(aCx); return false; } diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index dab15390c782..c54c4d655562 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -1355,10 +1355,7 @@ public class GeckoAppShell (int)y); if (GeckoApp.mainLayout.indexOfChild(view) == -1) { - view.setWillNotDraw(false); - if(view instanceof SurfaceView) - ((SurfaceView)view).setZOrderOnTop(true); - + view.setWillNotDraw(true); GeckoApp.mainLayout.addView(view, lp); } else @@ -1412,16 +1409,9 @@ public class GeckoAppShell return null; } - static HashMap sSufaceMap = new HashMap(); - - public static void lockSurfaceANP() + public static SurfaceInfo getSurfaceInfo(SurfaceView sview) { - Log.i("GeckoAppShell", "other lockSurfaceANP"); - } - - public static org.mozilla.gecko.SurfaceLockInfo lockSurfaceANP(android.view.SurfaceView sview, int top, int left, int bottom, int right) - { - Log.i("GeckoAppShell", "real lockSurfaceANP " + sview + ", " + top + ", " + left + ", " + bottom + ", " + right); + Log.i("GeckoAppShell", "getSurfaceInfo " + sview); if (sview == null) return null; @@ -1435,80 +1425,28 @@ public class GeckoAppShell } int n = 0; - if (format == PixelFormat.RGB_565) + if (format == PixelFormat.RGB_565) { n = 2; - else if (format == PixelFormat.RGBA_8888) + } else if (format == PixelFormat.RGBA_8888) { n = 4; - - if (n == 0) + } else { + Log.i("GeckoAppShell", "Unknown pixel format: " + format); return null; - - SurfaceLockInfo info = sSufaceMap.get(sview); - if (info == null) { - info = new SurfaceLockInfo(); - sSufaceMap.put(sview, info); } - Rect r = new Rect(left, top, right, bottom); - - info.canvas = sview.getHolder().lockCanvas(r); - int bufSizeRequired = info.canvas.getWidth() * info.canvas.getHeight() * n; - Log.i("GeckoAppShell", "lockSurfaceANP - bufSizeRequired: " + n + " " + info.canvas.getHeight() + " " + info.canvas.getWidth()); - - if (info.width != info.canvas.getWidth() || info.height != info.canvas.getHeight() || info.buffer == null || info.buffer.capacity() < bufSizeRequired) { - info.width = info.canvas.getWidth(); - info.height = info.canvas.getHeight(); - - // XXX Bitmaps instead of ByteBuffer - info.buffer = ByteBuffer.allocateDirect(bufSizeRequired); //leak - Log.i("GeckoAppShell", "!!!!!!!!!!! lockSurfaceANP - Allocating buffer! " + bufSizeRequired); - - } - - info.canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR); + SurfaceInfo info = new SurfaceInfo(); + Rect r = sview.getHolder().getSurfaceFrame(); + info.width = r.right; + info.height = r.bottom; info.format = format; - info.dirtyTop = top; - info.dirtyBottom = bottom; - info.dirtyLeft = left; - info.dirtyRight = right; return info; } - public static void unlockSurfaceANP(SurfaceView sview) { - SurfaceLockInfo info = sSufaceMap.get(sview); - - int n = 0; - Bitmap.Config config; - if (info.format == PixelFormat.RGB_565) { - n = 2; - config = Bitmap.Config.RGB_565; - } else { - n = 4; - config = Bitmap.Config.ARGB_8888; - } - - Log.i("GeckoAppShell", "unlockSurfaceANP: " + (info.width * info.height * n)); - - Bitmap bm = Bitmap.createBitmap(info.width, info.height, config); - bm.copyPixelsFromBuffer(info.buffer); - info.canvas.drawBitmap(bm, 0, 0, null); - sview.getHolder().unlockCanvasAndPost(info.canvas); - } - - public static Class getSurfaceLockInfoClass() { - Log.i("GeckoAppShell", "class name: " + SurfaceLockInfo.class.getName()); - return SurfaceLockInfo.class; - } - - public static Method getSurfaceLockMethod() { - Method[] m = GeckoAppShell.class.getMethods(); - for (int i = 0; i < m.length; i++) { - if (m[i].getName().equals("lockSurfaceANP")) - return m[i]; - } - return null; + public static Class getSurfaceInfoClass() { + Log.i("GeckoAppShell", "class name: " + SurfaceInfo.class.getName()); + return SurfaceInfo.class; } static native void executeNextRunnable(); diff --git a/embedding/android/Makefile.in b/embedding/android/Makefile.in index 92abf3875d2b..0aec2533e4c9 100644 --- a/embedding/android/Makefile.in +++ b/embedding/android/Makefile.in @@ -53,7 +53,7 @@ JAVAFILES = \ GeckoSurfaceView.java \ GeckoInputConnection.java \ AlertNotification.java \ - SurfaceLockInfo.java \ + SurfaceInfo.java \ $(NULL) PROCESSEDJAVAFILES = \ diff --git a/embedding/android/SurfaceInfo.java b/embedding/android/SurfaceInfo.java new file mode 100644 index 000000000000..f823926a2821 --- /dev/null +++ b/embedding/android/SurfaceInfo.java @@ -0,0 +1,7 @@ +package org.mozilla.gecko; + +public class SurfaceInfo { + public int format; + public int width; + public int height; +} diff --git a/embedding/android/SurfaceLockInfo.java b/embedding/android/SurfaceLockInfo.java deleted file mode 100644 index 4dcb7dc2b6a3..000000000000 --- a/embedding/android/SurfaceLockInfo.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.mozilla.gecko; - -import android.graphics.Canvas; -import java.nio.Buffer; - -public class SurfaceLockInfo { - public int dirtyTop; - public int dirtyLeft; - public int dirtyRight; - public int dirtyBottom; - - public int bpr; - public int format; - public int width; - public int height; - public Buffer buffer; - public Canvas canvas; -} diff --git a/embedding/browser/webBrowser/nsWebBrowser.cpp b/embedding/browser/webBrowser/nsWebBrowser.cpp index 4424ae71d840..ac2c84850349 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.cpp +++ b/embedding/browser/webBrowser/nsWebBrowser.cpp @@ -1156,7 +1156,7 @@ NS_IMETHODIMP nsWebBrowser::Create() mInternalWidget->SetClientData(static_cast(this)); mInternalWidget->Create(nsnull, mParentNativeWindow, bounds, nsWebBrowser::HandleEvent, - nsnull, nsnull, &widgetInit); + nsnull, &widgetInit); } nsCOMPtr docShell(do_CreateInstance("@mozilla.org/docshell;1", &rv)); diff --git a/gfx/angle/CONTRIBUTORS b/gfx/angle/CONTRIBUTORS index 51221b1290ed..6f9946a1f681 100644 --- a/gfx/angle/CONTRIBUTORS +++ b/gfx/angle/CONTRIBUTORS @@ -28,6 +28,7 @@ Google Inc. Adrienne Walker Mozilla Corp. + Ehsan Akhgari Benoit Jacob Makoto Kato Vladimir Vukicevic @@ -40,3 +41,5 @@ Jim Hauxwell ddefrostt timeless Yore Apex +Mark Callow + diff --git a/gfx/angle/DEPS b/gfx/angle/DEPS index 072737b6667b..b50d4e3aa592 100644 --- a/gfx/angle/DEPS +++ b/gfx/angle/DEPS @@ -1,6 +1,6 @@ deps = { "trunk/third_party/gyp": - "http://gyp.googlecode.com/svn/trunk@800", + "http://gyp.googlecode.com/svn/trunk@1080", } hooks = [ diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla index 346138ee418f..b588b7ef3b84 100644 --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -1,16 +1,14 @@ This is the ANGLE project, from http://code.google.com/p/angleproject/ -Current revision: r774 +Current revision: r802 == Applied local patches == In this order: - angle-nspr-misc.patch - don't bother with ANGLE_OS detection with NSPR - angle-renaming.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles - angle-instrinsic-msvc2005.patch - work around a MSVC 2005 compile error + angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles + angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error angle-limit-identifiers-to-250-chars.patch - see bug 675625 angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands. - angle-mCurrentValueOffsets-size_t.patch - ANGLE bug 220 - compile fix on win64 In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE. diff --git a/gfx/angle/angle-instrinsic-msvc2005.patch b/gfx/angle/angle-intrinsic-msvc2005.patch similarity index 100% rename from gfx/angle/angle-instrinsic-msvc2005.patch rename to gfx/angle/angle-intrinsic-msvc2005.patch diff --git a/gfx/angle/angle-mCurrentValueOffsets-size_t.patch b/gfx/angle/angle-mCurrentValueOffsets-size_t.patch deleted file mode 100644 index fcc778cf6dac..000000000000 --- a/gfx/angle/angle-mCurrentValueOffsets-size_t.patch +++ /dev/null @@ -1,24 +0,0 @@ -# HG changeset patch -# Parent 693fb23429fdbf40e272e1c48887479cc597e0bc -diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.h b/gfx/angle/src/libGLESv2/VertexDataManager.h ---- a/gfx/angle/src/libGLESv2/VertexDataManager.h -+++ b/gfx/angle/src/libGLESv2/VertexDataManager.h -@@ -127,17 +127,17 @@ class VertexDataManager - - Context *const mContext; - IDirect3DDevice9 *const mDevice; - - StreamingVertexBuffer *mStreamingBuffer; - - bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS]; - StreamingVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS]; -- UINT mCurrentValueOffsets[MAX_VERTEX_ATTRIBS]; -+ std::size_t mCurrentValueOffsets[MAX_VERTEX_ATTRIBS]; - - // Attribute format conversion - struct FormatConverter - { - bool identity; - std::size_t outputElementSize; - void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); - D3DDECLTYPE d3dDeclType; diff --git a/gfx/angle/angle-nspr-misc.patch b/gfx/angle/angle-nspr-misc.patch deleted file mode 100644 index c7412df00bec..000000000000 --- a/gfx/angle/angle-nspr-misc.patch +++ /dev/null @@ -1,2 +0,0 @@ -# HG changeset patch -# Parent 6a9ec71ad85de76c551a5398b1427d9f76430b1f diff --git a/gfx/angle/angle-use-xmalloc.patch b/gfx/angle/angle-use-xmalloc.patch index 2a09fef7f795..f70cf4cfb004 100644 --- a/gfx/angle/angle-use-xmalloc.patch +++ b/gfx/angle/angle-use-xmalloc.patch @@ -1,17 +1,18 @@ # HG changeset patch -# Parent 74f1894d664435118be4fdefd53cabfdaa9985bc +# Parent fecc64a6df53a9056b21958affad38c80ca38496 + diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in -@@ -123,16 +123,18 @@ CSRCS = \ - memory.c \ - scanner.c \ - symbols.c \ - tokens.c \ +@@ -127,16 +127,18 @@ CSRCS = \ $(NULL) DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD + #these defines are from ANGLE's build_angle.gyp + DEFINES += -DANGLE_DISABLE_TRACE + DEFINES += -DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0 + +EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB) + ifdef MOZ_ANGLE @@ -25,14 +26,14 @@ diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla -@@ -4,16 +4,17 @@ Current revision: r740 +@@ -3,16 +3,17 @@ This is the ANGLE project, from http://c + Current revision: r774 == Applied local patches == In this order: - angle-nspr-misc.patch - don't bother with ANGLE_OS detection with NSPR angle-renaming.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles - angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error + angle-instrinsic-msvc2005.patch - work around a MSVC 2005 compile error angle-limit-identifiers-to-250-chars.patch - see bug 675625 + angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands. @@ -118,7 +119,7 @@ diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in --- a/gfx/angle/src/libEGL/Makefile.in +++ b/gfx/angle/src/libEGL/Makefile.in -@@ -150,8 +150,10 @@ RCFILE = $(srcdir)/libEGL.rc +@@ -153,8 +153,10 @@ RCFILE = $(srcdir)/libEGL.rc include $(topsrcdir)/config/rules.mk EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \ @@ -132,7 +133,7 @@ diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in --- a/gfx/angle/src/libGLESv2/Makefile.in +++ b/gfx/angle/src/libGLESv2/Makefile.in -@@ -159,8 +159,10 @@ CPPSRCS += \ +@@ -162,8 +162,10 @@ CPPSRCS += \ DEFFILE = $(srcdir)/libGLESv2.def RCFILE = $(srcdir)/libGLESv2.rc diff --git a/gfx/angle/build/common.gypi b/gfx/angle/build/common.gypi index 8682410ebb2d..65125e228d3d 100644 --- a/gfx/angle/build/common.gypi +++ b/gfx/angle/build/common.gypi @@ -4,7 +4,7 @@ { 'variables': { - 'library%': 'shared_library', + 'component%': 'static_library', }, 'target_defaults': { 'default_configuration': 'Debug', @@ -81,6 +81,11 @@ }, }, # Release }, # configurations + 'conditions': [ + ['component=="shared_library"', { + 'defines': ['COMPONENT_BUILD'], + }], + ], }, # target_defaults 'conditions': [ ['OS=="win"', { diff --git a/gfx/angle/extensions/ANGLE_translated_shader_source.txt b/gfx/angle/extensions/ANGLE_translated_shader_source.txt new file mode 100644 index 000000000000..a5234ebe961a --- /dev/null +++ b/gfx/angle/extensions/ANGLE_translated_shader_source.txt @@ -0,0 +1,118 @@ +Name + + ANGLE_translated_shader_source + +Name Strings + + GL_ANGLE_translated_shader_source + +Contributors + + Daniel Koch, TransGaming Inc. + Gregg Tavares, Google Inc. + Kenneth Russell, Google Inc. + Zhenyao Mo, Google Inc. + +Contact + + Zhenyao Mo, Google Inc. (zmo 'at' google 'dot' com) + +Status + + Implemented in ANGLE ES2 + +Version + + Last Modified Date: October 5, 2011 + Author Revision: 2 + +Number + + OpenGL ES Extension #?? + +Dependencies + + OpenGL ES 2.0 is required. + + The extension is written against the OpenGL ES 2.0 specification. + +Overview + + WebGL uses the GLSL ES 2.0 spec on all platforms, and translates these + shaders to the host platform's native language (HLSL, GLSL, and even GLSL + ES). For debugging purposes, it is useful to be able to examine the shader + after translation. + + This extension addes a new function to query the translated shader source, + and adds a new enum for GetShaderiv's parameter to query the + translated shader source length. + +IP Status + + No known IP claims. + +New Types + + None + +New Procedures and Functions + + void GetTranslatedShaderSourceANGLE(uint shader, sizei bufsize, + sizei* length, char* source); + +New Tokens + + Accepted by the parameter of GetShaderiv: + + TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 + +Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State +Requests) + + Append in the end of the fourth paragraph of section 6.1.8 (Shader and + Program Queries): + + " If is TRANSLATED_SHADER_LENGTH_ANGLE, the length of the translated + source string, including a null terminator, is returned. If no source has + been defined, CompileShader has not been called, or the translation has + failed for , zero is returned." + + Append after the last paragraph of section 6.1.8 (Shader and Program + Queries): + + "The command + + void GetTranslatedShaderSourceANGLE( uint shader, sizei bufSize, + sizei *length, char *source ); + + returns in the string making up the translated source code for + the shader object . The string will be null terminated. + The actual number of characters written into , excluding the null + terminator, is returned in . If is NULL, no length is + returned. The maximum number of characters that may be written into + , including the null terminator, is specified by . The + string is the translated string of a concatenation of the strings + passed to the GL using ShaderSource. The length of this translated string + is given by TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, which can be queried + with GetShaderiv. + + If no source has been defined, CompileShader has not been called, or the + translation has failed for , zero is returned for , and + an empty string is returned for . + + If the value of SHADER_COMPILER is not TRUE, then the error INVALID_- + OPERATION is generated." + +Issues + + 1) What enum value should be used for TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE? + + RESOLVED: The first draft used a temporary enum value. This been replaced + with a enum allocated from the ANGLE range of GL enums. + +Revision History + + Revision 1, 2011/09/29, zmo + - first draft + Revision 2, 2011/10/05, dgkoch + - assigned enum diff --git a/gfx/angle/extensions/EGL_ANGLE_software_display.txt b/gfx/angle/extensions/EGL_ANGLE_software_display.txt index c584817fc7c3..556e1bee505f 100644 --- a/gfx/angle/extensions/EGL_ANGLE_software_display.txt +++ b/gfx/angle/extensions/EGL_ANGLE_software_display.txt @@ -21,7 +21,7 @@ Status Version - Version 1, July 12, 2011 + Version 2, October 19, 2011 Number @@ -46,7 +46,7 @@ New Procedures and Functions New Tokens - None + EGL_SOFTWARE_DISPLAY_ANGLE (EGLNativeDisplayType)-1 Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) @@ -61,3 +61,5 @@ Issues Revision History Version 1, 2011/07/12 - first draft. + Version 2, 2011/10/18 - add token definition + diff --git a/gfx/angle/include/GLES2/gl2ext.h b/gfx/angle/include/GLES2/gl2ext.h index 9371ad7d8f82..b95a58df101f 100644 --- a/gfx/angle/include/GLES2/gl2ext.h +++ b/gfx/angle/include/GLES2/gl2ext.h @@ -217,6 +217,11 @@ typedef void* GLeglImageOES; #define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 #endif +/* GL_ANGLE_translated_shader_source */ +#ifndef GL_ANGLE_translated_shader_source +#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 +#endif + /*------------------------------------------------------------------------* * APPLE extension tokens *------------------------------------------------------------------------*/ @@ -810,6 +815,15 @@ typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum #define GL_ANGLE_texture_compression_dxt5 1 #endif +/* GL_ANGLE_translated_shader_source */ +#ifndef GL_ANGLE_translated_shader_source +#define GL_ANGLE_translated_shader_source 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +#endif +typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +#endif + /*------------------------------------------------------------------------* * APPLE extension functions *------------------------------------------------------------------------*/ diff --git a/gfx/angle/include/GLSLANG/ShaderLang.h b/gfx/angle/include/GLSLANG/ShaderLang.h index 91af12af7e83..bbe3a126fb6e 100644 --- a/gfx/angle/include/GLSLANG/ShaderLang.h +++ b/gfx/angle/include/GLSLANG/ShaderLang.h @@ -6,6 +6,23 @@ #ifndef _COMPILER_INTERFACE_INCLUDED_ #define _COMPILER_INTERFACE_INCLUDED_ +#if defined(COMPONENT_BUILD) +#if defined(_WIN32) || defined(_WIN64) + +#if defined(COMPILER_IMPLEMENTATION) +#define COMPILER_EXPORT __declspec(dllexport) +#else +#define COMPILER_EXPORT __declspec(dllimport) +#endif // defined(COMPILER_IMPLEMENTATION) + +#else // defined(WIN32) +#define COMPILER_EXPORT __attribute__((visibility("default"))) +#endif + +#else // defined(COMPONENT_BUILD) +#define COMPILER_EXPORT +#endif + // // This is the platform independent interface between an OGL driver // and the shading language compiler. @@ -93,12 +110,12 @@ typedef enum { // compiler operations. // If the function succeeds, the return value is nonzero, else zero. // -int ShInitialize(); +COMPILER_EXPORT int ShInitialize(); // // Driver should call this at shutdown. // If the function succeeds, the return value is nonzero, else zero. // -int ShFinalize(); +COMPILER_EXPORT int ShFinalize(); // // Implementation dependent built-in resources (constants and extensions). @@ -125,7 +142,7 @@ typedef struct // // Initialize built-in resources with minimum expected values. // -void ShInitBuiltInResources(ShBuiltInResources* resources); +COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources); // // ShHandle held by but opaque to the driver. It is allocated, @@ -148,10 +165,12 @@ typedef void* ShHandle; // output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT, // or SH_HLSL_OUTPUT. // resources: Specifies the built-in resources. -ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, - ShShaderOutput output, - const ShBuiltInResources* resources); -void ShDestruct(ShHandle handle); +COMPILER_EXPORT ShHandle ShConstructCompiler( + ShShaderType type, + ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources* resources); +COMPILER_EXPORT void ShDestruct(ShHandle handle); // // Compiles the given shader source. @@ -178,7 +197,7 @@ void ShDestruct(ShHandle handle); // Can be queried by calling ShGetActiveAttrib() and // ShGetActiveUniform(). // -int ShCompile( +COMPILER_EXPORT int ShCompile( const ShHandle handle, const char* const shaderStrings[], const int numStrings, @@ -206,7 +225,9 @@ int ShCompile( // the null termination character. // // params: Requested parameter -void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params); +COMPILER_EXPORT void ShGetInfo(const ShHandle handle, + ShShaderInfo pname, + int* params); // Returns nul-terminated information log for a compiled shader. // Parameters: @@ -216,7 +237,7 @@ void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params); // to accomodate the information log. The size of the buffer required // to store the returned information log can be obtained by calling // ShGetInfo with SH_INFO_LOG_LENGTH. -void ShGetInfoLog(const ShHandle handle, char* infoLog); +COMPILER_EXPORT void ShGetInfoLog(const ShHandle handle, char* infoLog); // Returns null-terminated object code for a compiled shader. // Parameters: @@ -226,7 +247,7 @@ void ShGetInfoLog(const ShHandle handle, char* infoLog); // accomodate the object code. The size of the buffer required to // store the returned object code can be obtained by calling // ShGetInfo with SH_OBJECT_CODE_LENGTH. -void ShGetObjectCode(const ShHandle handle, char* objCode); +COMPILER_EXPORT void ShGetObjectCode(const ShHandle handle, char* objCode); // Returns information about an active attribute variable. // Parameters: @@ -247,13 +268,13 @@ void ShGetObjectCode(const ShHandle handle, char* objCode); // memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care // about the mapped name. If the name is not mapped, then name and // mappedName are the same. -void ShGetActiveAttrib(const ShHandle handle, - int index, - int* length, - int* size, - ShDataType* type, - char* name, - char* mappedName); +COMPILER_EXPORT void ShGetActiveAttrib(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName); // Returns information about an active uniform variable. // Parameters: @@ -274,13 +295,13 @@ void ShGetActiveAttrib(const ShHandle handle, // memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care // about the mapped name. If the name is not mapped, then name and // mappedName are the same. -void ShGetActiveUniform(const ShHandle handle, - int index, - int* length, - int* size, - ShDataType* type, - char* name, - char* mappedName); +COMPILER_EXPORT void ShGetActiveUniform(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName); #ifdef __cplusplus } diff --git a/gfx/angle/samples/build_samples.gyp b/gfx/angle/samples/build_samples.gyp index 313b7451043e..7cbb90701a1e 100644 --- a/gfx/angle/samples/build_samples.gyp +++ b/gfx/angle/samples/build_samples.gyp @@ -25,10 +25,18 @@ ], 'include_dirs': [ '../include', + '../src', ], 'sources': [ 'translator/translator.cpp', + '../src/common/debug.cpp', ], + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalLibraryDirectories': ['$(DXSDK_DIR)/lib/x86'], + 'AdditionalDependencies': ['d3d9.lib'], + } + } }, ], 'conditions': [ diff --git a/gfx/angle/samples/translator/translator.cpp b/gfx/angle/samples/translator/translator.cpp index a4bf6c2b1292..421316fe1b71 100644 --- a/gfx/angle/samples/translator/translator.cpp +++ b/gfx/angle/samples/translator/translator.cpp @@ -149,12 +149,12 @@ int main(int argc, char* argv[]) } if (compiled && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) { LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); - PrintActiveVariables(compiler, SH_ACTIVE_ATTRIBUTES, compileOptions & SH_MAP_LONG_VARIABLE_NAMES); + PrintActiveVariables(compiler, SH_ACTIVE_ATTRIBUTES, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0); LogMsg("END", "COMPILER", numCompiles, "ACTIVE ATTRIBS"); printf("\n\n"); LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); - PrintActiveVariables(compiler, SH_ACTIVE_UNIFORMS, compileOptions & SH_MAP_LONG_VARIABLE_NAMES); + PrintActiveVariables(compiler, SH_ACTIVE_UNIFORMS, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0); LogMsg("END", "COMPILER", numCompiles, "ACTIVE UNIFORMS"); printf("\n\n"); } diff --git a/gfx/angle/src/common/debug.cpp b/gfx/angle/src/common/debug.cpp index 4dd7327e7966..9fd95c1e6567 100644 --- a/gfx/angle/src/common/debug.cpp +++ b/gfx/angle/src/common/debug.cpp @@ -63,7 +63,11 @@ void trace(bool traceFileDebugOnly, const char *format, ...) { va_list vararg; va_start(vararg, format); +#if defined(ANGLE_DISABLE_PERF) + output(traceFileDebugOnly, NULL, format, vararg); +#else output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg); +#endif va_end(vararg); } @@ -79,10 +83,12 @@ bool perfActive() ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) { +#if !defined(ANGLE_DISABLE_PERF) va_list vararg; va_start(vararg, format); output(true, reinterpret_cast(D3DPERF_BeginEvent), format, vararg); va_end(vararg); +#endif } ScopedPerfEventHelper::~ScopedPerfEventHelper() diff --git a/gfx/angle/src/common/version.h b/gfx/angle/src/common/version.h index 2827ea22e1d0..90abab28696e 100644 --- a/gfx/angle/src/common/version.h +++ b/gfx/angle/src/common/version.h @@ -1,7 +1,7 @@ #define MAJOR_VERSION 0 #define MINOR_VERSION 0 #define BUILD_VERSION 0 -#define BUILD_REVISION 774 +#define BUILD_REVISION 802 #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) diff --git a/gfx/angle/src/compiler/OutputHLSL.cpp b/gfx/angle/src/compiler/OutputHLSL.cpp index 8e804d6ce3c0..231728b7a510 100644 --- a/gfx/angle/src/compiler/OutputHLSL.cpp +++ b/gfx/angle/src/compiler/OutputHLSL.cpp @@ -1503,7 +1503,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) if (node->usesTernaryOperator()) { - out << "t" << mUnfoldSelect->getTemporaryIndex(); + out << "s" << mUnfoldSelect->getNextTemporaryIndex(); } else // if/else statement { @@ -1567,21 +1567,6 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) } else { - if (node->getInit()) - { - mUnfoldSelect->traverse(node->getInit()); - } - - if (node->getCondition()) - { - mUnfoldSelect->traverse(node->getCondition()); - } - - if (node->getExpression()) - { - mUnfoldSelect->traverse(node->getExpression()); - } - out << "for("; if (node->getInit()) diff --git a/gfx/angle/src/compiler/PoolAlloc.h b/gfx/angle/src/compiler/PoolAlloc.h index 55e09dbc4055..a8a59c69acd9 100644 --- a/gfx/angle/src/compiler/PoolAlloc.h +++ b/gfx/angle/src/compiler/PoolAlloc.h @@ -253,12 +253,18 @@ public: pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } - pool_allocator() : allocator(GlobalPoolAllocator) { } - pool_allocator(TPoolAllocator& a) : allocator(a) { } + pool_allocator() : allocator(&GlobalPoolAllocator) { } + pool_allocator(TPoolAllocator& a) : allocator(&a) { } pool_allocator(const pool_allocator& p) : allocator(p.allocator) { } + template + pool_allocator& operator=(const pool_allocator& p) { + allocator = p.allocator; + return *this; + } + template - pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } + pool_allocator(const pool_allocator& p) : allocator(&p.getAllocator()) { } #if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR) // libCStd on some platforms have a different allocate/deallocate interface. @@ -290,11 +296,11 @@ public: size_type max_size() const { return static_cast(-1) / sizeof(T); } size_type max_size(int size) const { return static_cast(-1) / size; } - void setAllocator(TPoolAllocator* a) { allocator = *a; } - TPoolAllocator& getAllocator() const { return allocator; } + void setAllocator(TPoolAllocator* a) { allocator = a; } + TPoolAllocator& getAllocator() const { return *allocator; } protected: - TPoolAllocator& allocator; + TPoolAllocator* allocator; }; #endif // _POOLALLOC_INCLUDED_ diff --git a/gfx/angle/src/compiler/UnfoldSelect.cpp b/gfx/angle/src/compiler/UnfoldSelect.cpp index a36c3931ec01..d3985e68b9f6 100644 --- a/gfx/angle/src/compiler/UnfoldSelect.cpp +++ b/gfx/angle/src/compiler/UnfoldSelect.cpp @@ -20,8 +20,9 @@ UnfoldSelect::UnfoldSelect(TParseContext &context, OutputHLSL *outputHLSL) : mCo void UnfoldSelect::traverse(TIntermNode *node) { - mTemporaryIndex++; + int rewindIndex = mTemporaryIndex; node->traverse(this); + mTemporaryIndex = rewindIndex; } bool UnfoldSelect::visitSelection(Visit visit, TIntermSelection *node) @@ -30,36 +31,66 @@ bool UnfoldSelect::visitSelection(Visit visit, TIntermSelection *node) if (node->usesTernaryOperator()) { - int i = mTemporaryIndex++; + int i = mTemporaryIndex; - out << mOutputHLSL->typeString(node->getType()) << " t" << i << ";\n"; + out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; + mTemporaryIndex = i + 1; node->getCondition()->traverse(this); out << "if("; + mTemporaryIndex = i + 1; node->getCondition()->traverse(mOutputHLSL); out << ")\n" "{\n"; + mTemporaryIndex = i + 1; node->getTrueBlock()->traverse(this); - out << " t" << i << " = "; + out << " s" << i << " = "; + mTemporaryIndex = i + 1; node->getTrueBlock()->traverse(mOutputHLSL); out << ";\n" "}\n" "else\n" "{\n"; + mTemporaryIndex = i + 1; node->getFalseBlock()->traverse(this); - out << " t" << i << " = "; + out << " s" << i << " = "; + mTemporaryIndex = i + 1; node->getFalseBlock()->traverse(mOutputHLSL); out << ";\n" "}\n"; - mTemporaryIndex--; + mTemporaryIndex = i + 1; } return false; } -int UnfoldSelect::getTemporaryIndex() +bool UnfoldSelect::visitLoop(Visit visit, TIntermLoop *node) { - return mTemporaryIndex; + int rewindIndex = mTemporaryIndex; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + mTemporaryIndex = rewindIndex; + + return false; +} + +int UnfoldSelect::getNextTemporaryIndex() +{ + return mTemporaryIndex++; } } diff --git a/gfx/angle/src/compiler/UnfoldSelect.h b/gfx/angle/src/compiler/UnfoldSelect.h index de296e4428da..4a3ba5f86ed0 100644 --- a/gfx/angle/src/compiler/UnfoldSelect.h +++ b/gfx/angle/src/compiler/UnfoldSelect.h @@ -23,8 +23,9 @@ class UnfoldSelect : public TIntermTraverser void traverse(TIntermNode *node); bool visitSelection(Visit visit, TIntermSelection *node); + bool visitLoop(Visit visit, TIntermLoop *node); - int getTemporaryIndex(); + int getNextTemporaryIndex(); protected: TParseContext &mContext; diff --git a/gfx/angle/src/compiler/intermOut.cpp b/gfx/angle/src/compiler/intermOut.cpp index 798a69af7eb6..e83c7b72f2a3 100644 --- a/gfx/angle/src/compiler/intermOut.cpp +++ b/gfx/angle/src/compiler/intermOut.cpp @@ -261,6 +261,8 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) case EOpRefract: out << "refract"; break; case EOpMul: out << "component-wise multiply"; break; + case EOpDeclaration: out << "Declaration: "; break; + default: out.message(EPrefixError, "Bad aggregation op"); } diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp index e5e05d582546..77d0e91e8b32 100644 --- a/gfx/angle/src/libGLESv2/Context.cpp +++ b/gfx/angle/src/libGLESv2/Context.cpp @@ -381,6 +381,8 @@ void Context::markAllStateDirty() mSampleStateDirty = true; mDitherStateDirty = true; mFrontFaceDirty = true; + mDxUniformsDirty = true; + mCachedCurrentProgram = NULL; } void Context::setClearColor(float red, float green, float blue, float alpha) @@ -893,6 +895,7 @@ void Context::deleteShader(GLuint shader) void Context::deleteProgram(GLuint program) { mResourceManager->deleteProgram(program); + mCachedCurrentProgram = NULL; } void Context::deleteTexture(GLuint texture) @@ -973,7 +976,7 @@ Framebuffer *Context::getReadFramebuffer() Framebuffer *Context::getDrawFramebuffer() { - return getFramebuffer(mState.drawFramebuffer); + return mBoundDrawFramebuffer; } void Context::bindArrayBuffer(unsigned int buffer) @@ -1022,6 +1025,8 @@ void Context::bindDrawFramebuffer(GLuint framebuffer) } mState.drawFramebuffer = framebuffer; + + mBoundDrawFramebuffer = getFramebuffer(framebuffer); } void Context::bindRenderbuffer(GLuint renderbuffer) @@ -1040,6 +1045,8 @@ void Context::useProgram(GLuint program) { Program *newProgram = mResourceManager->getProgram(program); Program *oldProgram = mResourceManager->getProgram(priorProgram); + mCachedCurrentProgram = NULL; + mDxUniformsDirty = true; if (newProgram) { @@ -1057,6 +1064,10 @@ void Context::setFramebufferZero(Framebuffer *buffer) { delete mFramebufferMap[0]; mFramebufferMap[0] = buffer; + if (mState.drawFramebuffer == 0) + { + mBoundDrawFramebuffer = buffer; + } } void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer) @@ -1105,7 +1116,11 @@ Buffer *Context::getElementArrayBuffer() Program *Context::getCurrentProgram() { - return mResourceManager->getProgram(mState.currentProgram); + if (!mCachedCurrentProgram) + { + mCachedCurrentProgram = mResourceManager->getProgram(mState.currentProgram); + } + return mCachedCurrentProgram; } Texture2D *Context::getTexture2D() @@ -1614,19 +1629,19 @@ bool Context::applyRenderTarget(bool ignoreViewport) return error(GL_INVALID_FRAMEBUFFER_OPERATION, false); } - IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); - - if (!renderTarget) - { - return false; // Context must be lost - } - + IDirect3DSurface9 *renderTarget = NULL; IDirect3DSurface9 *depthStencil = NULL; bool renderTargetChanged = false; unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { + renderTarget = framebufferObject->getRenderTarget(); + + if (!renderTarget) + { + return false; // Context must be lost + } device->SetRenderTarget(0, renderTarget); mAppliedRenderTargetSerial = renderTargetSerial; mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets. @@ -1670,6 +1685,15 @@ bool Context::applyRenderTarget(bool ignoreViewport) if (!mRenderTargetDescInitialized || renderTargetChanged) { + if (!renderTarget) + { + renderTarget = framebufferObject->getRenderTarget(); + + if (!renderTarget) + { + return false; // Context must be lost + } + } renderTarget->GetDesc(&mRenderTargetDesc); mRenderTargetDescInitialized = true; } @@ -1709,6 +1733,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) device->SetViewport(&viewport); mSetViewport = viewport; mViewportInitialized = true; + mDxUniformsDirty = true; } if (mScissorStateDirty) @@ -1731,7 +1756,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) mScissorStateDirty = false; } - if (mState.currentProgram) + if (mState.currentProgram && mDxUniformsDirty) { Program *programObject = getCurrentProgram(); @@ -1752,6 +1777,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) GLint depthRange = programObject->getDxDepthRangeLocation(); GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear}; programObject->setUniform3fv(depthRange, 1, nearFarDiff); + mDxUniformsDirty = false; } return true; @@ -2089,12 +2115,14 @@ void Context::applyTextures(SamplerType type) Program *programObject = getCurrentProgram(); int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; // Range of Direct3D 9 samplers of given sampler type + unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS; + int d3dSamplerOffset = (type == SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int samplerRange = programObject->getUsedSamplerRange(type); - for (int samplerIndex = 0; samplerIndex < samplerCount; samplerIndex++) + for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) { int textureUnit = programObject->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index - int d3dSampler = (type == SAMPLER_PIXEL) ? samplerIndex : D3DVERTEXTEXTURESAMPLER0 + samplerIndex; - unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS; + int d3dSampler = samplerIndex + d3dSamplerOffset; if (textureUnit != -1) { @@ -2148,6 +2176,15 @@ void Context::applyTextures(SamplerType type) } } } + + for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + if (appliedTextureSerial[samplerIndex] != 0) + { + device->SetTexture(samplerIndex + d3dSamplerOffset, NULL); + appliedTextureSerial[samplerIndex] = 0; + } + } } void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) @@ -3434,6 +3471,7 @@ void Context::initExtensionString() { mExtensionString += "GL_ANGLE_texture_compression_dxt5 "; } + mExtensionString += "GL_ANGLE_translated_shader_source "; // Other vendor-specific extensions if (supportsEventQueries()) diff --git a/gfx/angle/src/libGLESv2/Context.h b/gfx/angle/src/libGLESv2/Context.h index 583c52437f5c..6e99762ae74e 100644 --- a/gfx/angle/src/libGLESv2/Context.h +++ b/gfx/angle/src/libGLESv2/Context.h @@ -544,6 +544,9 @@ class Context D3DVIEWPORT9 mSetViewport; bool mRenderTargetDescInitialized; D3DSURFACE_DESC mRenderTargetDesc; + bool mDxUniformsDirty; + Program *mCachedCurrentProgram; + Framebuffer *mBoundDrawFramebuffer; bool mSupportsShaderModel3; bool mSupportsVertexTexture; diff --git a/gfx/angle/src/libGLESv2/Framebuffer.cpp b/gfx/angle/src/libGLESv2/Framebuffer.cpp index 0f7ec20f8801..3858e2694f05 100644 --- a/gfx/angle/src/libGLESv2/Framebuffer.cpp +++ b/gfx/angle/src/libGLESv2/Framebuffer.cpp @@ -58,19 +58,19 @@ Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) { - mColorbufferType = type; + mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); } void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) { - mDepthbufferType = type; + mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); } void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) { - mStencilbufferType = type; + mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); } diff --git a/gfx/angle/src/libGLESv2/Program.cpp b/gfx/angle/src/libGLESv2/Program.cpp index fd79e46689f1..e5ffd25785f9 100644 --- a/gfx/angle/src/libGLESv2/Program.cpp +++ b/gfx/angle/src/libGLESv2/Program.cpp @@ -40,7 +40,6 @@ Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) data = new unsigned char[bytes]; memset(data, 0, bytes); dirty = true; - handlesSet = false; } Uniform::~Uniform() @@ -144,8 +143,6 @@ bool Program::detachShader(Shader *shader) } else UNREACHABLE(); - unlink(); - return true; } @@ -200,11 +197,26 @@ int Program::getSemanticIndex(int attributeIndex) return mSemanticIndex[attributeIndex]; } +// Returns one more than the highest sampler index used. +GLint Program::getUsedSamplerRange(SamplerType type) +{ + switch (type) + { + case SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + // Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler // index (0-15 for the pixel shader and 0-3 for the vertex shader). GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex) { - GLuint logicalTextureUnit = -1; + GLint logicalTextureUnit = -1; switch (type) { @@ -227,7 +239,7 @@ GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex) default: UNREACHABLE(); } - if (logicalTextureUnit >= 0 && logicalTextureUnit < getContext()->getMaximumCombinedTextureImageUnits()) + if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits()) { return logicalTextureUnit; } @@ -300,8 +312,17 @@ bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat), - v, sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = 0; + target[2] = 0; + target[3] = 0; + target += 4; + v += 1; + } } else if (targetUniform->type == GL_BOOL) { @@ -357,8 +378,17 @@ bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2, - v, 2 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = 0; + target[3] = 0; + target += 4; + v += 2; + } } else if (targetUniform->type == GL_BOOL_VEC2) { @@ -415,8 +445,17 @@ bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3, - v, 3 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = v[2]; + target[3] = 0; + target += 4; + v += 3; + } } else if (targetUniform->type == GL_BOOL_VEC3) { @@ -510,6 +549,37 @@ bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) return true; } +template +void transposeMatrix(T *target, const GLfloat *value) +{ + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + target[x * targetWidth + y] = value[y * srcWidth + x]; + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = srcWidth; x < targetWidth; x++) + { + target[y * targetWidth + x] = 0; + } + } + // clear unfilled bottom. + for (int y = srcHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + target[y * targetWidth + x] = 0; + } + } +} + bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) { if (location < 0 || location >= (int)mUniformIndex.size()) @@ -532,8 +602,13 @@ bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4, - value, 4 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 8; + value += 4; + } return true; } @@ -560,12 +635,18 @@ bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9, - value, 9 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 12; + value += 9; + } return true; } + bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) { if (location < 0 || location >= (int)mUniformIndex.size()) @@ -588,8 +669,13 @@ bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat * count = std::min(arraySize - (int)mUniformIndex[location].element, count); - memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16, - value, 16 * sizeof(GLfloat) * count); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 16; + value += 16; + } return true; } @@ -833,35 +919,51 @@ bool Program::getUniformfv(GLint location, GLfloat *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - unsigned int count = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + switch (targetUniform->type) { - case GL_BOOL: + case GL_FLOAT_MAT2: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); + break; + case GL_FLOAT_MAT3: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); + break; + case GL_FLOAT_MAT4: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + break; + default: { - GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count; + unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); - for (unsigned int i = 0; i < count; ++i) + switch (UniformComponentType(targetUniform->type)) { - params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; + case GL_BOOL: + { + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; + } + } + break; + case GL_FLOAT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat), + count * sizeof(GLfloat)); + break; + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (float)intParams[i]; + } + } + break; + default: UNREACHABLE(); } } - break; - case GL_FLOAT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat), - count * sizeof(GLfloat)); - break; - case GL_INT: - { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count; - - for (unsigned int i = 0; i < count; ++i) - { - params[i] = (float)intParams[i]; - } - } - break; - default: UNREACHABLE(); } return true; @@ -876,35 +978,57 @@ bool Program::getUniformiv(GLint location, GLint *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - unsigned int count = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + switch (targetUniform->type) { - case GL_BOOL: + case GL_FLOAT_MAT2: { - GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count; - - for (unsigned int i = 0; i < count; ++i) - { - params[i] = (GLint)boolParams[i]; - } + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); } break; - case GL_FLOAT: + case GL_FLOAT_MAT3: { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count; - - for (unsigned int i = 0; i < count; ++i) - { - params[i] = (GLint)floatParams[i]; - } + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); } break; - case GL_INT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint), - count * sizeof(GLint)); + case GL_FLOAT_MAT4: + { + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + } break; - default: UNREACHABLE(); + default: + { + unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); + + switch (UniformComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)boolParams[i]; + } + } + break; + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)floatParams[i]; + } + } + break; + case GL_INT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint), + count * sizeof(GLint)); + break; + default: UNREACHABLE(); + } + } } return true; @@ -922,15 +1046,8 @@ void Program::dirtyAllUniforms() // Applies all the uniforms set for this program object to the Direct3D 9 device void Program::applyUniforms() { - unsigned int numUniforms = mUniformIndex.size(); - for (unsigned int location = 0; location < numUniforms; location++) - { - if (mUniformIndex[location].element != 0) - { - continue; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + for (std::vector::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) { + Uniform *targetUniform = *ub; if (targetUniform->dirty) { @@ -941,23 +1058,23 @@ void Program::applyUniforms() switch (targetUniform->type) { - case GL_BOOL: applyUniform1bv(location, arraySize, b); break; - case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break; - case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break; - case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break; - case GL_FLOAT: applyUniform1fv(location, arraySize, f); break; - case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break; - case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break; - case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break; - case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break; - case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break; - case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break; + case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break; + case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break; + case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break; + case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break; case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: - case GL_INT: applyUniform1iv(location, arraySize, i); break; - case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break; - case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break; - case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break; + case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break; + case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break; + case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break; + case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break; default: UNREACHABLE(); } @@ -1726,6 +1843,7 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT mSamplersPS[samplerIndex].active = true; mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; mSamplersPS[samplerIndex].logicalTextureUnit = 0; + mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); } else { @@ -1741,6 +1859,7 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT mSamplersVS[samplerIndex].active = true; mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; mSamplersVS[samplerIndex].logicalTextureUnit = 0; + mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); } else { @@ -1816,6 +1935,9 @@ bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::s } } + initializeConstantHandles(uniform, &uniform->ps, mConstantTablePS); + initializeConstantHandles(uniform, &uniform->vs, mConstantTableVS); + mUniforms.push_back(uniform); unsigned int uniformIndex = mUniforms.size() - 1; @@ -1927,382 +2049,107 @@ std::string Program::undecorateUniform(const std::string &_name) return _name; } -bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v) +void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v) { - BOOL *vector = new BOOL[count]; - for (int i = 0; i < count; i++) - { - if (v[i] == GL_FALSE) - vector[i] = 0; - else - vector[i] = 1; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - if (constantPS) + float *vector = NULL; + BOOL *boolVector = NULL; + + if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_FLOAT4 || + targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_FLOAT4) { - mConstantTablePS->SetBoolArray(device, constantPS, vector, count); - } + vector = new float[4 * count]; - if (constantVS) - { - mConstantTableVS->SetBoolArray(device, constantVS, vector, count); - } - - delete [] vector; - - return true; -} - -bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0); - - v += 2; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), - (v[2] == GL_FALSE ? 0.0f : 1.0f), 0); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f), - (v[1] == GL_FALSE ? 0.0f : 1.0f), - (v[2] == GL_FALSE ? 0.0f : 1.0f), - (v[3] == GL_FALSE ? 0.0f : 1.0f)); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete [] vector; - - return true; -} - -bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetFloatArray(device, constantPS, v, count); - } - - if (constantVS) - { - mConstantTableVS->SetFloatArray(device, constantVS, v, count); - } - - return true; -} - -bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0); - - v += 2; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v) -{ - D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; - - for (int i = 0; i < count; i++) - { - vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0); - - v += 3; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } - - delete[] vector; - - return true; -} - -bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count); - } - - return true; -} - -bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) -{ - D3DXMATRIX *matrix = new D3DXMATRIX[count]; - - for (int i = 0; i < count; i++) - { - matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0, - value[1], value[3], 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - - value += 4; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); - } - - if (constantVS) - { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); - } - - delete[] matrix; - - return true; -} - -bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) -{ - D3DXMATRIX *matrix = new D3DXMATRIX[count]; - - for (int i = 0; i < count; i++) - { - matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0, - value[1], value[4], value[7], 0, - value[2], value[5], value[8], 0, - 0, 0, 0, 1); - - value += 9; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); - } - - if (constantVS) - { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); - } - - delete[] matrix; - - return true; -} - -bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) -{ - D3DXMATRIX *matrix = new D3DXMATRIX[count]; - - for (int i = 0; i < count; i++) - { - matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12], - value[1], value[5], value[9], value[13], - value[2], value[6], value[10], value[14], - value[3], value[7], value[11], value[15]); - - value += 16; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count); - } - - if (constantVS) - { - mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count); - } - - delete[] matrix; - - return true; -} - -bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) -{ - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - D3DXCONSTANT_DESC constantDescription; - UINT descriptionCount = 1; - HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount); - ASSERT(SUCCEEDED(result)); - - if (constantDescription.RegisterSet == D3DXRS_SAMPLER) + for (int i = 0; i < count; i++) { - unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS); + for (int j = 0; j < 4; j++) + { + if (j < width) + { + vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f; + } + else + { + vector[i * 4 + j] = 0.0f; + } + } + } + } + + if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_BOOL || + targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_BOOL) + { + boolVector = new BOOL[count * width]; + for (int i = 0; i < count * width; i++) + { + boolVector[i] = v[i] != GL_FALSE; + } + } + + if (targetUniform->ps.registerCount) + { + if (targetUniform->ps.registerSet == D3DXRS_FLOAT4) + { + device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, vector, targetUniform->ps.registerCount); + } + else if (targetUniform->ps.registerSet == D3DXRS_BOOL) + { + device->SetPixelShaderConstantB(targetUniform->ps.registerIndex, boolVector, targetUniform->ps.registerCount); + } + else UNREACHABLE(); + } + + if (targetUniform->vs.registerCount) + { + if (targetUniform->vs.registerSet == D3DXRS_FLOAT4) + { + device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, vector, targetUniform->vs.registerCount); + } + else if (targetUniform->vs.registerSet == D3DXRS_BOOL) + { + device->SetVertexShaderConstantB(targetUniform->vs.registerIndex, boolVector, targetUniform->vs.registerCount); + } + else UNREACHABLE(); + } + + delete [] vector; + delete [] boolVector; +} + +bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v) +{ + IDirect3DDevice9 *device = getDevice(); + + if (targetUniform->ps.registerCount) + { + device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, v, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, v, targetUniform->vs.registerCount); + } + + return true; +} + +bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + + for (int i = 0; i < count; i++) + { + vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0); + } + + IDirect3DDevice9 *device = getDevice(); + + if (targetUniform->ps.registerCount) + { + if (targetUniform->ps.registerSet == D3DXRS_SAMPLER) + { + unsigned int firstIndex = targetUniform->ps.registerIndex; for (int i = 0; i < count; i++) { @@ -2317,20 +2164,16 @@ bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) } else { - mConstantTablePS->SetIntArray(device, constantPS, v, count); + ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4); + device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float*)vector, targetUniform->ps.registerCount); } } - if (constantVS) + if (targetUniform->vs.registerCount) { - D3DXCONSTANT_DESC constantDescription; - UINT descriptionCount = 1; - HRESULT result = mConstantTableVS->GetConstantDesc(constantVS, &constantDescription, &descriptionCount); - ASSERT(SUCCEEDED(result)); - - if (constantDescription.RegisterSet == D3DXRS_SAMPLER) + if (targetUniform->vs.registerSet == D3DXRS_SAMPLER) { - unsigned int firstIndex = mConstantTableVS->GetSamplerIndex(constantVS); + unsigned int firstIndex = targetUniform->vs.registerIndex; for (int i = 0; i < count; i++) { @@ -2345,14 +2188,17 @@ bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) } else { - mConstantTableVS->SetIntArray(device, constantVS, v, count); + ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4); + device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount); } } + delete [] vector; + return true; } -bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v) { D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; @@ -2363,29 +2209,14 @@ bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v) v += 2; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } + applyUniformniv(targetUniform, count, vector); delete[] vector; return true; } -bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v) { D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; @@ -2396,29 +2227,14 @@ bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v) v += 3; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } + applyUniformniv(targetUniform, count, vector); delete[] vector; return true; } -bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v) +bool Program::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v) { D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; @@ -2429,28 +2245,29 @@ bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v) v += 4; } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - D3DXHANDLE constantPS; - D3DXHANDLE constantVS; - getConstantHandles(targetUniform, &constantPS, &constantVS); - IDirect3DDevice9 *device = getDevice(); - - if (constantPS) - { - mConstantTablePS->SetVectorArray(device, constantPS, vector, count); - } - - if (constantVS) - { - mConstantTableVS->SetVectorArray(device, constantVS, vector, count); - } + applyUniformniv(targetUniform, count, vector); delete [] vector; return true; } +void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector) +{ + IDirect3DDevice9 *device = getDevice(); + + if (targetUniform->ps.registerCount) + { + ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4); + device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float *)vector, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4); + device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount); + } +} // append a santized message to the program info log. // The D3D compiler includes a fake file path in some of the warning or error @@ -2515,7 +2332,7 @@ void Program::resetInfoLog() } } -// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction +// Returns the program object to an unlinked state, before re-linking, or at destruction void Program::unlink(bool destroy) { if (destroy) // Object being destructed @@ -2573,6 +2390,9 @@ void Program::unlink(bool destroy) mSamplersVS[index].active = false; } + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + while (!mUniforms.empty()) { delete mUniforms.back(); @@ -2900,7 +2720,7 @@ bool Program::validateSamplers(bool logErrors) textureUnitType[i] = TEXTURE_UNKNOWN; } - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) { if (mSamplersPS[i].active) { @@ -2935,7 +2755,7 @@ bool Program::validateSamplers(bool logErrors) } } - for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i) + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) { if (mSamplersVS[i].active) { @@ -2973,17 +2793,23 @@ bool Program::validateSamplers(bool logErrors) return true; } -void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS) +void Program::initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *ri, ID3DXConstantTable *constantTable) { - if (!targetUniform->handlesSet) + D3DXHANDLE handle = constantTable->GetConstantByName(0, targetUniform->_name.c_str()); + if (handle) { - targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->_name.c_str()); - targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->_name.c_str()); - targetUniform->handlesSet = true; + UINT descriptionCount = 1; + D3DXCONSTANT_DESC constantDescription; + HRESULT result = constantTable->GetConstantDesc(handle, &constantDescription, &descriptionCount); + ASSERT(SUCCEEDED(result)); + ri->registerIndex = constantDescription.RegisterIndex; + ri->registerCount = constantDescription.RegisterCount; + ri->registerSet = constantDescription.RegisterSet; + } + else + { + ri->registerCount = 0; } - - *constantPS = targetUniform->psHandle; - *constantVS = targetUniform->vsHandle; } GLint Program::getDxDepthRangeLocation() const diff --git a/gfx/angle/src/libGLESv2/Program.h b/gfx/angle/src/libGLESv2/Program.h index 4bf344fcf182..23be162ddc38 100644 --- a/gfx/angle/src/libGLESv2/Program.h +++ b/gfx/angle/src/libGLESv2/Program.h @@ -42,9 +42,15 @@ struct Uniform unsigned char *data; bool dirty; - D3DXHANDLE vsHandle; - D3DXHANDLE psHandle; - bool handlesSet; + struct RegisterInfo + { + int registerSet; + int registerIndex; + int registerCount; + }; + + RegisterInfo ps; + RegisterInfo vs; }; // Struct used for correlating uniforms/elements of uniform arrays to handles @@ -77,6 +83,7 @@ class Program GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex); TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); GLint getUniformLocation(std::string name); bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v); @@ -149,23 +156,15 @@ class Program bool defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = ""); bool defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name); Uniform *createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name); - bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform4bv(GLint location, GLsizei count, const GLboolean *v); - bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v); - bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); - bool applyUniform1iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform2iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform3iv(GLint location, GLsizei count, const GLint *v); - bool applyUniform4iv(GLint location, GLsizei count, const GLint *v); + bool applyUniformnfv(Uniform *targetUniform, const GLfloat *v); + bool applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v); + void applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector); + void applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v); - void getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS); + void initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *rs, ID3DXConstantTable *constantTable); void appendToInfoLogSanitized(const char *message); void appendToInfoLog(const char *info, ...); @@ -197,6 +196,8 @@ class Program Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS]; Sampler mSamplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; typedef std::vector UniformArray; UniformArray mUniforms; diff --git a/gfx/angle/src/libGLESv2/Shader.cpp b/gfx/angle/src/libGLESv2/Shader.cpp index f66b2c52ab7a..58eed0784065 100644 --- a/gfx/angle/src/libGLESv2/Shader.cpp +++ b/gfx/angle/src/libGLESv2/Shader.cpp @@ -157,22 +157,34 @@ int Shader::getSourceLength() const } } -void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) +int Shader::getTranslatedSourceLength() const +{ + if (!mHlsl) + { + return 0; + } + else + { + return strlen(mHlsl) + 1; + } +} + +void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer) { int index = 0; - if (mSource) + if (source) { - while (index < bufSize - 1 && index < (int)strlen(mSource)) + while (index < bufSize - 1 && index < (int)strlen(source)) { - source[index] = mSource[index]; + buffer[index] = source[index]; index++; } } if (bufSize) { - source[index] = '\0'; + buffer[index] = '\0'; } if (length) @@ -181,6 +193,16 @@ void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source) } } +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mHlsl, bufSize, length, buffer); +} + bool Shader::isCompiled() { return mHlsl != NULL; diff --git a/gfx/angle/src/libGLESv2/Shader.h b/gfx/angle/src/libGLESv2/Shader.h index 535b42d8c6a0..22fc6376c8e4 100644 --- a/gfx/angle/src/libGLESv2/Shader.h +++ b/gfx/angle/src/libGLESv2/Shader.h @@ -57,7 +57,9 @@ class Shader int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); int getSourceLength() const; - void getSource(GLsizei bufSize, GLsizei *length, char *source); + void getSource(GLsizei bufSize, GLsizei *length, char *buffer); + int getTranslatedSourceLength() const; + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer); virtual void compile() = 0; bool isCompiled(); @@ -78,6 +80,8 @@ class Shader void compileToHLSL(void *compiler); + void getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer); + static GLenum parseType(const std::string &type); static bool compareVarying(const Varying &x, const Varying &y); diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp index 5a816d4df727..745b8fb8c26e 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -1987,7 +1987,7 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu try { if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) - || renderbuffertarget != GL_RENDERBUFFER) + || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) { return error(GL_INVALID_ENUM); } @@ -2003,13 +2003,13 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu framebuffer = context->getReadFramebuffer(); framebufferHandle = context->getReadFramebufferHandle(); } - else + else { framebuffer = context->getDrawFramebuffer(); framebufferHandle = context->getDrawFramebufferHandle(); } - if (framebufferHandle == 0 || !framebuffer) + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) { return error(GL_INVALID_OPERATION); } @@ -3089,6 +3089,9 @@ void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) case GL_SHADER_SOURCE_LENGTH: *params = shaderObject->getSourceLength(); return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shaderObject->getTranslatedSourceLength(); + return; default: return error(GL_INVALID_ENUM); } @@ -3209,6 +3212,38 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length } } +void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", + shader, bufsize, length, source); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_OPERATION); + } + + shaderObject->getTranslatedSource(bufsize, length, source); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + const GLubyte* __stdcall glGetString(GLenum name) { EVENT("(GLenum name = 0x%X)", name); @@ -5769,6 +5804,7 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV}, {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV}, {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV}, + {"glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)glGetTranslatedShaderSourceANGLE}, }; for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) diff --git a/gfx/angle/src/libGLESv2/libGLESv2.def b/gfx/angle/src/libGLESv2/libGLESv2.def index b91217199bf2..4793f75fbb14 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.def +++ b/gfx/angle/src/libGLESv2/libGLESv2.def @@ -154,6 +154,7 @@ EXPORTS glIsFenceNV @155 glSetFenceNV @156 glTestFenceNV @157 + glGetTranslatedShaderSourceANGLE @159 ; EGL dependencies glCreateContext @144 NONAME diff --git a/gfx/angle/src/libGLESv2/utilities.cpp b/gfx/angle/src/libGLESv2/utilities.cpp index 01cca3c05f71..3dba89987d32 100644 --- a/gfx/angle/src/libGLESv2/utilities.cpp +++ b/gfx/angle/src/libGLESv2/utilities.cpp @@ -54,6 +54,42 @@ int UniformComponentCount(GLenum type) return 0; } +// This is how much data we actually store for a uniform +int UniformInternalComponentCount(GLenum type) +{ + switch (type) + { + case GL_BOOL: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + case GL_BOOL_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + return 4; + case GL_FLOAT_MAT2: + return 8; + case GL_FLOAT_MAT3: + return 12; + case GL_FLOAT_MAT4: + return 16; + default: + UNREACHABLE(); + } + + return 0; +} + GLenum UniformComponentType(GLenum type) { switch(type) @@ -85,16 +121,22 @@ GLenum UniformComponentType(GLenum type) return GL_NONE; } -size_t UniformTypeSize(GLenum type) +size_t UniformComponentSize(GLenum type) { switch(type) { case GL_BOOL: return sizeof(GLboolean); case GL_FLOAT: return sizeof(GLfloat); case GL_INT: return sizeof(GLint); + default: UNREACHABLE(); } - return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(type); + return 0; +} + +size_t UniformTypeSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformInternalComponentCount(type); } int VariableRowCount(GLenum type) diff --git a/gfx/angle/src/libGLESv2/utilities.h b/gfx/angle/src/libGLESv2/utilities.h index bf7f4f93482b..f6b964c45565 100644 --- a/gfx/angle/src/libGLESv2/utilities.h +++ b/gfx/angle/src/libGLESv2/utilities.h @@ -22,6 +22,7 @@ namespace gl struct Color; int UniformComponentCount(GLenum type); +int UniformInternalComponentCount(GLenum type); GLenum UniformComponentType(GLenum type); size_t UniformTypeSize(GLenum type); int VariableRowCount(GLenum type); diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 647686612b2c..dc2d1c049c7b 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -889,7 +889,7 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext, nsRefPtr image = mContainer->GetCurrentImage(); nsRefPtr surface = mContainer->GetCurrentAsSurface(&mSize); - if (!surface) { + if (!surface || surface->CairoStatus()) { return nsnull; } @@ -1868,6 +1868,14 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, untransformedSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::CONTENT_COLOR_ALPHA); + if (!untransformedSurface) { + if (pushedTargetOpaqueRect) { + currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0)); + } + NS_ASSERTION(needsSaveRestore, "Should always need to restore with 3d transforms!"); + aTarget->Restore(); + return; + } untransformedSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y)); groupTarget = new gfxContext(untransformedSurface); } else if (needsGroup) { @@ -2389,7 +2397,8 @@ class BasicShadowableImageLayer : public BasicImageLayer, { public: BasicShadowableImageLayer(BasicShadowLayerManager* aManager) : - BasicImageLayer(aManager) + BasicImageLayer(aManager), + mBufferIsOpaque(false) { MOZ_COUNT_CTOR(BasicShadowableImageLayer); } @@ -2451,6 +2460,7 @@ private: // For YUV Images these are the 3 planes (Y, Cb and Cr), // for RGB images only mBackSurface is used. SurfaceDescriptor mBackBuffer; + bool mBufferIsOpaque; nsRefPtr mBackBufferY; nsRefPtr mBackBufferU; nsRefPtr mBackBufferV; @@ -2460,6 +2470,11 @@ private: void BasicShadowableImageLayer::Paint(gfxContext* aContext) { + if (!HasShadow()) { + BasicImageLayer::Paint(aContext); + return; + } + if (!mContainer) { return; } @@ -2518,12 +2533,16 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext) if (!pat || !HasShadow()) return; - if (oldSize != mSize || !IsSurfaceDescriptorValid(mBackBuffer)) { + bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE); + if (oldSize != mSize || + !IsSurfaceDescriptorValid(mBackBuffer) || + isOpaque != mBufferIsOpaque) { DestroyBackBuffer(); + mBufferIsOpaque = isOpaque; if (!BasicManager()->AllocBuffer( mSize, - (GetContentFlags() & CONTENT_OPAQUE) ? + isOpaque ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA, &mBackBuffer)) NS_RUNTIMEABORT("creating ImageLayer 'front buffer' failed!"); @@ -2575,7 +2594,8 @@ class BasicShadowableCanvasLayer : public BasicCanvasLayer, { public: BasicShadowableCanvasLayer(BasicShadowLayerManager* aManager) : - BasicCanvasLayer(aManager) + BasicCanvasLayer(aManager), + mBufferIsOpaque(false) { MOZ_COUNT_CTOR(BasicShadowableCanvasLayer); } @@ -2622,6 +2642,7 @@ private: } SurfaceDescriptor mBackBuffer; + bool mBufferIsOpaque; }; void @@ -2651,10 +2672,14 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext) return; } - if (!IsSurfaceDescriptorValid(mBackBuffer)) { + bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE); + if (!IsSurfaceDescriptorValid(mBackBuffer) || + isOpaque != mBufferIsOpaque) { + DestroyBackBuffer(); + mBufferIsOpaque = isOpaque; if (!BasicManager()->AllocBuffer( gfxIntSize(mBounds.width, mBounds.height), - (GetContentFlags() & CONTENT_OPAQUE) ? + isOpaque ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA, &mBackBuffer)) NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!"); @@ -2943,7 +2968,13 @@ BasicShadowImageLayer::Swap(const SharedImage& aNewFront, nsRefPtr surface = BasicManager()->OpenDescriptor(aNewFront); // Destroy mFrontBuffer if size different - if (surface->GetSize() != mSize) { + bool needDrop = false; + if (IsSurfaceDescriptorValid(mFrontBuffer)) { + nsRefPtr front = BasicManager()->OpenDescriptor(mFrontBuffer); + needDrop = surface->GetSize() != mSize || + surface->GetContentType() != front->GetContentType(); + } + if (needDrop) { DestroyFrontBuffer(); mSize = surface->GetSize(); } @@ -3059,7 +3090,13 @@ BasicShadowCanvasLayer::Swap(const CanvasSurface& aNewFront, bool needYFlip, BasicManager()->OpenDescriptor(aNewFront); // Destroy mFrontBuffer if size different gfxIntSize sz = surface->GetSize(); - if (sz != gfxIntSize(mBounds.width, mBounds.height)) { + bool needDrop = false; + if (IsSurfaceDescriptorValid(mFrontSurface)) { + nsRefPtr front = BasicManager()->OpenDescriptor(mFrontSurface); + needDrop = sz != gfxIntSize(mBounds.width, mBounds.height) || + surface->GetContentType() != front->GetContentType(); + } + if (needDrop) { DestroyFrontBuffer(); mBounds.SetRect(0, 0, sz.width, sz.height); } diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index c298c0846897..77cad933cb9a 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -172,6 +172,10 @@ CanvasLayerOGL::UpdateSurface() } #endif + if (mCanvasGLContext) { + mCanvasGLContext->MakeCurrent(); + mCanvasGLContext->fFinish(); + } mOGLManager->MakeCurrent(); if (mCanvasGLContext && @@ -320,7 +324,8 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront, if (!mDestroyed) { nsRefPtr surf = ShadowLayerForwarder::OpenDescriptor(aNewFront); gfxIntSize sz = surf->GetSize(); - if (!mTexImage || mTexImage->GetSize() != sz) { + if (!mTexImage || mTexImage->GetSize() != sz || + mTexImage->GetContentType() != surf->GetContentType()) { Init(aNewFront, needYFlip); } nsIntRegion updateRegion(nsIntRect(0, 0, sz.width, sz.height)); diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index 0bfe44eb5067..8681ac13fcc2 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -885,7 +885,8 @@ ShadowImageLayerOGL::Swap(const SharedImage& aNewFront, nsRefPtr surf = ShadowLayerForwarder::OpenDescriptor(aNewFront.get_SurfaceDescriptor()); gfxIntSize size = surf->GetSize(); - if (mSize != size || !mTexImage) { + if (mSize != size || !mTexImage || + mTexImage->GetContentType() != surf->GetContentType()) { Init(aNewFront); } // XXX this is always just ridiculously slow diff --git a/gfx/thebes/GLContext.cpp b/gfx/thebes/GLContext.cpp index fa6e67090ca6..ece01b1c8bd8 100644 --- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -174,6 +174,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return true; } + mHasRobustness = IsExtensionSupported(ARB_robustness); + SymLoadStruct symbols[] = { { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } }, { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } }, @@ -325,6 +327,9 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) { mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fUnmapBuffer, { mIsGLES2 ? NULL : "UnmapBuffer", NULL } }, + { mHasRobustness ? (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus : (PRFuncPtr*) NULL, + { mHasRobustness ? "GetGraphicsResetStatusARB" : NULL, NULL } }, + { NULL, { NULL } }, }; @@ -377,6 +382,33 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer), "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!"); + // Check for aux symbols based on extensions + if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) || + IsExtensionSupported(GLContext::EXT_framebuffer_blit)) { + SymLoadStruct auxSymbols[] = { + { (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebuffer", "BlitFramebufferEXT", "BlitFramebufferANGLE", NULL } }, + { NULL, { NULL } }, + }; + if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) { + NS_RUNTIMEABORT("GL supports framebuffer_blit without supplying glBlitFramebuffer"); + mInitialized = false; + } + } + + if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) || + IsExtensionSupported(GLContext::EXT_framebuffer_multisample)) { + SymLoadStruct auxSymbols[] = { + { (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", NULL } }, + { NULL, { NULL } }, + }; + if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) { + NS_RUNTIMEABORT("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample"); + mInitialized = false; + } + } + } + + if (mInitialized) { GLint v[4]; fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v); @@ -438,6 +470,12 @@ static const char *sExtensionNames[] = { "GL_ARB_texture_float", "GL_EXT_unpack_subimage", "GL_OES_standard_derivatives", + "GL_EXT_framebuffer_blit", + "GL_ANGLE_framebuffer_blit", + "GL_EXT_framebuffer_multisample", + "GL_ANGLE_framebuffer_multisample", + "GL_OES_rgb8_rgba8", + "GL_ARB_robustness", NULL }; @@ -986,107 +1024,155 @@ PRUint32 TiledTextureImage::GetTileCount() } bool -GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize) +GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA) { if (!IsOffscreenSizeAllowed(aSize)) return false; MakeCurrent(); - bool alpha = mCreationFormat.alpha > 0; - int depth = mCreationFormat.depth; - int stencil = mCreationFormat.stencil; + const bool alpha = mCreationFormat.alpha > 0; + const int depth = mCreationFormat.depth; + const int stencil = mCreationFormat.stencil; + int samples = mCreationFormat.samples; - bool firstTime = (mOffscreenFBO == 0); + if (!SupportsFramebufferMultisample() || aDisableAA) + samples = 0; - GLuint curBoundTexture = 0; + const bool useDrawMSFBO = (samples > 0); + + if (!useDrawMSFBO && !aUseReadFBO) + return true; + + const bool firstTime = (mOffscreenDrawFBO == 0 && mOffscreenReadFBO == 0); + + GLuint curBoundFramebufferDraw = 0; + GLuint curBoundFramebufferRead = 0; GLuint curBoundRenderbuffer = 0; - GLuint curBoundFramebuffer = 0; + GLuint curBoundTexture = 0; GLint viewport[4]; - bool useDepthStencil = - !mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil); + const bool useDepthStencil = + !mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil); // save a few things for later restoring - fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture); - fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer); + curBoundFramebufferDraw = GetBoundDrawFBO(); + curBoundFramebufferRead = GetBoundReadFBO(); fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*) &curBoundRenderbuffer); + fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture); fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); - // the context format of what we're defining; - // for some reason, UpdateActualFormat isn't working with a bound FBO. - ContextFormat cf; + // the context format of what we're defining + // This becomes mActualFormat on success + ContextFormat cf(mCreationFormat); - // If this is the first time we're going through this, we need - // to create the objects we'll use. Otherwise, just bind them. - if (firstTime) { - fGenTextures(1, &mOffscreenTexture); - fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + // Create everything we need for the resize, so if it fails, we haven't broken anything + // If successful, these new resized objects will replace their associated member vars in GLContext + GLuint newOffscreenDrawFBO = 0; + GLuint newOffscreenReadFBO = 0; + GLuint newOffscreenTexture = 0; + GLuint newOffscreenColorRB = 0; + GLuint newOffscreenDepthRB = 0; + GLuint newOffscreenStencilRB = 0; - fGenFramebuffers(1, &mOffscreenFBO); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO); - - if (depth && stencil && useDepthStencil) { - fGenRenderbuffers(1, &mOffscreenDepthRB); - } else { - if (depth) { - fGenRenderbuffers(1, &mOffscreenDepthRB); - } - - if (stencil) { - fGenRenderbuffers(1, &mOffscreenStencilRB); - } - } - } else { - fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO); + // Create the buffers and texture + if (aUseReadFBO) { + fGenFramebuffers(1, &newOffscreenReadFBO); + fGenTextures(1, &newOffscreenTexture); } - // resize the FBO components - if (alpha) { - fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - aSize.width, aSize.height, - 0, - LOCAL_GL_RGBA, - LOCAL_GL_UNSIGNED_BYTE, - NULL); - - cf.red = cf.green = cf.blue = cf.alpha = 8; + if (useDrawMSFBO) { + fGenFramebuffers(1, &newOffscreenDrawFBO); + fGenRenderbuffers(1, &newOffscreenColorRB); } else { - fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGB, - aSize.width, aSize.height, - 0, - LOCAL_GL_RGB, -#ifdef XP_WIN - LOCAL_GL_UNSIGNED_BYTE, -#else - mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5 - : LOCAL_GL_UNSIGNED_BYTE, -#endif - NULL); - -#ifdef XP_WIN - cf.red = cf.green = cf.blue = 8; -#else - cf.red = 5; - cf.green = 6; - cf.blue = 5; -#endif - cf.alpha = 0; + newOffscreenDrawFBO = newOffscreenReadFBO; } if (depth && stencil && useDepthStencil) { - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB); - fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, - LOCAL_GL_DEPTH24_STENCIL8, - aSize.width, aSize.height); + fGenRenderbuffers(1, &newOffscreenDepthRB); + } else { + if (depth) { + fGenRenderbuffers(1, &newOffscreenDepthRB); + } + + if (stencil) { + fGenRenderbuffers(1, &newOffscreenStencilRB); + } + } + + // Allocate texture + if (aUseReadFBO) { + fBindTexture(LOCAL_GL_TEXTURE_2D, newOffscreenTexture); + fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + + if (alpha) { + fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + LOCAL_GL_RGBA, + aSize.width, aSize.height, + 0, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + NULL); + + cf.red = cf.green = cf.blue = cf.alpha = 8; + } else { + fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + LOCAL_GL_RGB, + aSize.width, aSize.height, + 0, + LOCAL_GL_RGB, +#ifdef XP_WIN + LOCAL_GL_UNSIGNED_BYTE, +#else + mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5 + : LOCAL_GL_UNSIGNED_BYTE, +#endif + NULL); + +#ifdef XP_WIN + cf.red = cf.green = cf.blue = 8; +#else + cf.red = 5; + cf.green = 6; + cf.blue = 5; +#endif + cf.alpha = 0; + } + } + cf.samples = samples; + + // Allocate color buffer + if (useDrawMSFBO) { + GLenum colorFormat; + if (!mIsGLES2 || IsExtensionSupported(OES_rgb8_rgba8)) + colorFormat = alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8; + else + colorFormat = alpha ? LOCAL_GL_RGBA4 : LOCAL_GL_RGB565; + + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenColorRB); + fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, + samples, + colorFormat, + aSize.width, aSize.height); + } + + // Allocate depth and stencil buffers + if (depth && stencil && useDepthStencil) { + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB); + if (useDrawMSFBO) { + fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, + samples, + LOCAL_GL_DEPTH24_STENCIL8, + aSize.width, aSize.height); + } else { + fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, + LOCAL_GL_DEPTH24_STENCIL8, + aSize.width, aSize.height); + } cf.depth = 24; cf.stencil = 8; } else { @@ -1108,77 +1194,167 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize) cf.depth = 24; } - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB); - fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, depthType, - aSize.width, aSize.height); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB); + if (useDrawMSFBO) { + fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, + samples, + depthType, + aSize.width, aSize.height); + } else { + fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, + depthType, + aSize.width, aSize.height); + } } if (stencil) { - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenStencilRB); - fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, - LOCAL_GL_STENCIL_INDEX8, - aSize.width, aSize.height); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenStencilRB); + if (useDrawMSFBO) { + fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, + samples, + LOCAL_GL_STENCIL_INDEX8, + aSize.width, aSize.height); + } else { + fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, + LOCAL_GL_STENCIL_INDEX8, + aSize.width, aSize.height); + } cf.stencil = 8; } } - // Now assemble the FBO, if we're creating one - // for the first time. - if (firstTime) { - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - mOffscreenTexture, - 0); + // Now assemble the FBO + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenDrawFBO); // If we're not using a separate draw FBO, this will be the read FBO + if (useDrawMSFBO) { + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, + newOffscreenColorRB); + } - if (depth && stencil && useDepthStencil) { + if (depth && stencil && useDepthStencil) { + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_DEPTH_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, + newOffscreenDepthRB); + fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, + newOffscreenDepthRB); + } else { + if (depth) { fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, - mOffscreenDepthRB); + newOffscreenDepthRB); + } + + if (stencil) { fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, - mOffscreenDepthRB); - } else { - if (depth) { - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - mOffscreenDepthRB); - } - - if (stencil) { - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - mOffscreenStencilRB); - } + newOffscreenStencilRB); } } + if (aUseReadFBO) { + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenReadFBO); + fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_TEXTURE_2D, + newOffscreenTexture, + 0); + } + // We should be all resized. Check for framebuffer completeness. - GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + GLenum status; + bool framebuffersComplete = true; + + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenDrawFBO); + status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { - NS_WARNING("Error resizing offscreen framebuffer -- framebuffer not complete"); + NS_WARNING("DrawFBO: Incomplete"); +#ifdef DEBUG + printf_stderr("Framebuffer status: %X\n", status); +#endif + framebuffersComplete = false; + } + + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenReadFBO); + status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { + NS_WARNING("ReadFBO: Incomplete"); +#ifdef DEBUG + printf_stderr("Framebuffer status: %X\n", status); +#endif + framebuffersComplete = false; + } + + if (!framebuffersComplete) { + NS_WARNING("Error resizing offscreen framebuffer -- framebuffer(s) not complete"); + + // Clean up the mess + fDeleteFramebuffers(1, &newOffscreenDrawFBO); + fDeleteFramebuffers(1, &newOffscreenReadFBO); + fDeleteTextures(1, &newOffscreenTexture); + fDeleteRenderbuffers(1, &newOffscreenColorRB); + fDeleteRenderbuffers(1, &newOffscreenDepthRB); + fDeleteRenderbuffers(1, &newOffscreenStencilRB); + + BindReadFBO(curBoundFramebufferRead); + BindDrawFBO(curBoundFramebufferDraw); + fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer); + fViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + return false; } + // Success, so delete the old and busted + fDeleteFramebuffers(1, &mOffscreenDrawFBO); + fDeleteFramebuffers(1, &mOffscreenReadFBO); + fDeleteTextures(1, &mOffscreenTexture); + fDeleteRenderbuffers(1, &mOffscreenColorRB); + fDeleteRenderbuffers(1, &mOffscreenDepthRB); + fDeleteRenderbuffers(1, &mOffscreenStencilRB); + + // Update currently bound references if we're changing what they were point to + // This way we don't rebind to old buffers when we're done here + if (curBoundFramebufferDraw == mOffscreenDrawFBO) + curBoundFramebufferDraw = newOffscreenDrawFBO; + if (curBoundFramebufferRead == mOffscreenReadFBO) + curBoundFramebufferRead = newOffscreenReadFBO; + if (curBoundTexture == mOffscreenTexture) + curBoundTexture = newOffscreenTexture; + if (curBoundRenderbuffer == mOffscreenColorRB) + curBoundRenderbuffer = newOffscreenColorRB; + else if (curBoundRenderbuffer == mOffscreenDepthRB) + curBoundRenderbuffer = newOffscreenDepthRB; + else if (curBoundRenderbuffer == mOffscreenStencilRB) + curBoundRenderbuffer = newOffscreenStencilRB; + + // Replace with the new hotness + mOffscreenDrawFBO = newOffscreenDrawFBO; + mOffscreenReadFBO = newOffscreenReadFBO; + mOffscreenTexture = newOffscreenTexture; + mOffscreenColorRB = newOffscreenColorRB; + mOffscreenDepthRB = newOffscreenDepthRB; + mOffscreenStencilRB = newOffscreenStencilRB; + mOffscreenSize = aSize; mOffscreenActualSize = aSize; - if (firstTime) { - // UpdateActualFormat() doesn't work for some reason, with a - // FBO bound, even though it should. - //UpdateActualFormat(); - mActualFormat = cf; + mActualFormat = cf; #ifdef DEBUG - printf_stderr("Created offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d\n", + if (mDebugMode) { + printf_stderr("%s %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n", + firstTime ? "Created" : "Resized", + mOffscreenActualSize.width, mOffscreenActualSize.height, mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha, - mActualFormat.depth, mActualFormat.stencil); -#endif + mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples); } +#endif // We're good, and the framebuffer is already attached, so let's // clear out our new framebuffer; otherwise we'll end up displaying @@ -1186,13 +1362,18 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize) // can restore them. fViewport(0, 0, aSize.width, aSize.height); + // Make sure we know that the buffers are new and thus dirty: + ForceDirtyFBOs(); + // Clear the new framebuffer with the full viewport + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, GetOffscreenFBO()); ClearSafely(); // Ok, now restore the GL state back to what it was before the resize took place. + BindDrawFBO(curBoundFramebufferDraw); + BindReadFBO(curBoundFramebufferRead); fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture); fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, curBoundFramebuffer); // -don't- restore the viewport the first time through this, since // the previous one isn't valid. @@ -1205,13 +1386,17 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize) void GLContext::DeleteOffscreenFBO() { - fDeleteFramebuffers(1, &mOffscreenFBO); + fDeleteFramebuffers(1, &mOffscreenDrawFBO); + fDeleteFramebuffers(1, &mOffscreenReadFBO); fDeleteTextures(1, &mOffscreenTexture); + fDeleteRenderbuffers(1, &mOffscreenColorRB); fDeleteRenderbuffers(1, &mOffscreenDepthRB); fDeleteRenderbuffers(1, &mOffscreenStencilRB); - mOffscreenFBO = 0; + mOffscreenDrawFBO = 0; + mOffscreenReadFBO = 0; mOffscreenTexture = 0; + mOffscreenColorRB = 0; mOffscreenDepthRB = 0; mOffscreenStencilRB = 0; } diff --git a/gfx/thebes/GLContext.h b/gfx/thebes/GLContext.h index 0f9032f3fa2c..7fc219aaa81f 100644 --- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -476,11 +476,11 @@ struct THEBES_API ContextFormat }; ContextFormat() { - memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(ContextFormat)); } ContextFormat(const StandardContextFormat cf) { - memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(ContextFormat)); switch (cf) { case BasicRGBA32: red = green = blue = alpha = 8; @@ -519,6 +519,7 @@ struct THEBES_API ContextFormat int green, minGreen; int blue, minBlue; int alpha, minAlpha; + int samples; int colorBits() const { return red + green + blue; } }; @@ -531,7 +532,8 @@ public: GLContext(const ContextFormat& aFormat, bool aIsOffscreen = false, GLContext *aSharedContext = nsnull) - : mInitialized(false), + : mOffscreenFBOsDirty(false), + mInitialized(false), mIsOffscreen(aIsOffscreen), #ifdef USE_GLES2 mIsGLES2(true), @@ -547,7 +549,9 @@ public: mFlipped(false), mBlitProgram(0), mBlitFramebuffer(0), - mOffscreenFBO(0), + mOffscreenDrawFBO(0), + mOffscreenReadFBO(0), + mOffscreenColorRB(0), mOffscreenDepthRB(0), mOffscreenStencilRB(0) #ifdef DEBUG @@ -719,7 +723,7 @@ public: return false; } - if (!aOffscreen->mOffscreenFBO) { + if (!aOffscreen->mOffscreenDrawFBO && !aOffscreen->mOffscreenReadFBO) { return false; } @@ -749,8 +753,8 @@ public: * Only valid if IsOffscreen() returns true. */ virtual bool ResizeOffscreen(const gfxIntSize& aNewSize) { - if (mOffscreenFBO) - return ResizeOffscreenFBO(aNewSize); + if (mOffscreenDrawFBO || mOffscreenReadFBO) + return ResizeOffscreenFBO(aNewSize, mOffscreenReadFBO != 0); return false; } @@ -781,12 +785,232 @@ public: * Only valid if IsOffscreen() returns true. */ GLuint GetOffscreenFBO() { - return mOffscreenFBO; + // 0 is interpreted as (off)screen, whether for read or draw operations + return 0; } + GLuint GetOffscreenTexture() { return mOffscreenTexture; } + virtual bool SupportsFramebufferMultisample() { + return IsExtensionSupported(EXT_framebuffer_multisample) || IsExtensionSupported(ANGLE_framebuffer_multisample); + } + + virtual bool SupportsOffscreenSplit() { + return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit); + } + + GLuint GetBoundDrawFBO() { + GLint ret = 0; + if (SupportsOffscreenSplit()) + fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret); + else + fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); + return ret; + } + + GLuint GetBoundReadFBO() { + GLint ret = 0; + if (SupportsOffscreenSplit()) + fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, &ret); + else + fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); + return ret; + } + + void BindDrawFBO(GLuint name) { + if (SupportsOffscreenSplit()) + fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name); + else + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); + } + + void BindReadFBO(GLuint name) { + if (SupportsOffscreenSplit()) + fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name); + else + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); + } + + GLuint SwapBoundDrawFBO(GLuint name) { + GLuint prev = GetBoundDrawFBO(); + BindDrawFBO(name); + return prev; + } + + GLuint SwapBoundReadFBO(GLuint name) { + GLuint prev = GetBoundReadFBO(); + BindReadFBO(name); + return prev; + } + + void BindOffscreenDrawBuffer() { + BindDrawFBO(mOffscreenDrawFBO); + } + + void BindOffscreenReadBuffer() { + BindReadFBO(mOffscreenReadFBO); + } + + void BindOffscreenBuffers() { + BindOffscreenDrawBuffer(); + BindOffscreenReadBuffer(); + } + +private: + GLuint mPrevDrawFBOBinding; + GLuint mPrevReadFBOBinding; + bool mOffscreenFBOsDirty; + + void BeforeGLDrawCall() { + // Record and rebind if necessary + mPrevDrawFBOBinding = GetBoundDrawFBO(); + if (mPrevDrawFBOBinding == 0) { + BindDrawFBO(mOffscreenDrawFBO); + } else if (mPrevDrawFBOBinding != mOffscreenDrawFBO) + return; + + // Must be after binding the proper FBO + if (mOffscreenDrawFBO == mOffscreenReadFBO) + return; + + // If we're already dirty, no need to set it again + if (mOffscreenFBOsDirty) + return; + + mOffscreenFBOsDirty = true; + } + + void AfterGLDrawCall() { + if (mPrevDrawFBOBinding == 0) { + BindDrawFBO(0); + } + } + + void BeforeGLReadCall() { + // Record and rebind if necessary + mPrevReadFBOBinding = GetBoundReadFBO(); + if (mPrevReadFBOBinding == 0) { + BindReadFBO(mOffscreenReadFBO); + } else if (mPrevReadFBOBinding != mOffscreenReadFBO) + return; + + // Must be after binding the proper FBO + if (mOffscreenDrawFBO == mOffscreenReadFBO) + return; + + // If we're not dirty, there's no need to blit + if (!mOffscreenFBOsDirty) + return; + + const bool scissor = fIsEnabled(LOCAL_GL_SCISSOR_TEST); + if (scissor) + fDisable(LOCAL_GL_SCISSOR_TEST); + + // flip read/draw for blitting + GLuint prevDraw = SwapBoundDrawFBO(mOffscreenReadFBO); + BindReadFBO(mOffscreenDrawFBO); // We know that Read must already be mOffscreenRead, so no need to write that down + + GLint width = mOffscreenActualSize.width; + GLint height = mOffscreenActualSize.height; + raw_fBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + LOCAL_GL_COLOR_BUFFER_BIT, + LOCAL_GL_NEAREST); + + BindDrawFBO(prevDraw); + BindReadFBO(mOffscreenReadFBO); + + if (scissor) + fEnable(LOCAL_GL_SCISSOR_TEST); + + mOffscreenFBOsDirty = false; + } + + void AfterGLReadCall() { + if (mPrevReadFBOBinding == 0) { + BindReadFBO(0); + } + } + +public: + // Draw call hooks: + void fClear(GLbitfield mask) { + BeforeGLDrawCall(); + raw_fClear(mask); + AfterGLDrawCall(); + } + + void fDrawArrays(GLenum mode, GLint first, GLsizei count) { + BeforeGLDrawCall(); + raw_fDrawArrays(mode, first, count); + AfterGLDrawCall(); + } + + void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { + BeforeGLDrawCall(); + raw_fDrawElements(mode, count, type, indices); + AfterGLDrawCall(); + } + + // Read call hooks: + void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { + BeforeGLReadCall(); + raw_fReadPixels(x, y, width, height, format, type, pixels); + AfterGLReadCall(); + } + + void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + BeforeGLReadCall(); + raw_fCopyTexImage2D(target, level, internalformat, + x, y, width, height, border); + AfterGLReadCall(); + } + + void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + BeforeGLReadCall(); + raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, + x, y, width, height); + AfterGLReadCall(); + } + + void ForceDirtyFBOs() { + GLuint draw = SwapBoundReadFBO(mOffscreenDrawFBO); + + BeforeGLDrawCall(); + // no-op; just pretend we did something + AfterGLDrawCall(); + + BindDrawFBO(draw); + } + + void BlitDirtyFBOs() { + GLuint read = SwapBoundReadFBO(mOffscreenReadFBO); + + BeforeGLReadCall(); + // no-op; we just want to make sure the Read FBO is updated if it needs to be + AfterGLReadCall(); + + BindReadFBO(read); + } + + // Before reads from offscreen texture + void fFinish() { + BeforeGLReadCall(); + raw_fFinish(); + AfterGLReadCall(); + } + + // Draw/Read + void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + BeforeGLDrawCall(); + BeforeGLReadCall(); + raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + AfterGLReadCall(); + AfterGLDrawCall(); + } + #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) virtual gfxASurface* GetOffscreenPixmapSurface() { @@ -1013,6 +1237,12 @@ public: ARB_texture_float, EXT_unpack_subimage, OES_standard_derivatives, + EXT_framebuffer_blit, + ANGLE_framebuffer_blit, + EXT_framebuffer_multisample, + ANGLE_framebuffer_multisample, + OES_rgb8_rgba8, + ARB_robustness, Extensions_Max }; @@ -1049,11 +1279,24 @@ public: bool values[setlen]; }; + /** + * Context reset constants. + * These are used to determine who is guilty when a context reset + * happens. + */ + enum ContextResetARB { + CONTEXT_NO_ERROR = 0, + CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253, + CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254, + CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255, + }; + protected: bool mInitialized; bool mIsOffscreen; bool mIsGLES2; bool mIsGlobalSharedContext; + bool mHasRobustness; PRInt32 mVendor; @@ -1092,9 +1335,24 @@ protected: // helper to create/resize an offscreen FBO, // for offscreen implementations that use FBOs. - bool ResizeOffscreenFBO(const gfxIntSize& aSize); + bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA); + bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO) { + if (ResizeOffscreenFBO(aSize, aUseReadFBO, false)) + return true; + + if (!mCreationFormat.samples) + return false; + + if (mDebugMode) { + printf_stderr("Requested level of multisampling is unavailable, continuing without multisampling\n"); + } + + return ResizeOffscreenFBO(aSize, aUseReadFBO, true); + } void DeleteOffscreenFBO(); - GLuint mOffscreenFBO; + GLuint mOffscreenDrawFBO; + GLuint mOffscreenReadFBO; + GLuint mOffscreenColorRB; GLuint mOffscreenDepthRB; GLuint mOffscreenStencilRB; @@ -1454,7 +1712,7 @@ public: AFTER_GL_CALL; } - void fClear(GLbitfield mask) { + void raw_fClear(GLbitfield mask) { BEFORE_GL_CALL; mSymbols.fClear(mask); AFTER_GL_CALL; @@ -1514,13 +1772,13 @@ public: AFTER_GL_CALL; } - void fDrawArrays(GLenum mode, GLint first, GLsizei count) { + void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) { BEFORE_GL_CALL; mSymbols.fDrawArrays(mode, first, count); AFTER_GL_CALL; } - void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { + void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { BEFORE_GL_CALL; mSymbols.fDrawElements(mode, count, type, indices); AFTER_GL_CALL; @@ -1538,7 +1796,7 @@ public: AFTER_GL_CALL; } - void fFinish() { + void raw_fFinish() { BEFORE_GL_CALL; mSymbols.fFinish(); AFTER_GL_CALL; @@ -1756,7 +2014,7 @@ public: AFTER_GL_CALL; } - void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { + void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { BEFORE_GL_CALL; mSymbols.fReadPixels(x, y, width, height, format, type, pixels); AFTER_GL_CALL; @@ -2002,7 +2260,7 @@ public: AFTER_GL_CALL; } - void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { BEFORE_GL_CALL; mSymbols.fCopyTexImage2D(target, level, internalformat, x, FixYValue(y, height), @@ -2010,7 +2268,7 @@ public: AFTER_GL_CALL; } - void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { BEFORE_GL_CALL; mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, FixYValue(y, height), @@ -2092,6 +2350,12 @@ public: return retval; } + void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + BEFORE_GL_CALL; + mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + AFTER_GL_CALL; + } + realGLboolean fIsRenderbuffer (GLuint renderbuffer) { BEFORE_GL_CALL; realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer); @@ -2105,6 +2369,12 @@ public: AFTER_GL_CALL; } + void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) { + BEFORE_GL_CALL; + mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height); + AFTER_GL_CALL; + } + void fDepthRange(GLclampf a, GLclampf b) { BEFORE_GL_CALL; if (mIsGLES2) { @@ -2242,6 +2512,14 @@ public: AFTER_GL_CALL; TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names)); } + + GLenum GLAPIENTRY fGetGraphicsResetStatus() { + BEFORE_GL_CALL; + GLenum ret = mHasRobustness ? mSymbols.fGetGraphicsResetStatus() : 0; + AFTER_GL_CALL; + return ret; + } + #ifdef DEBUG void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName); void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName); diff --git a/gfx/thebes/GLContextProviderCGL.mm b/gfx/thebes/GLContextProviderCGL.mm index cda582aa955d..dabb014bdb67 100644 --- a/gfx/thebes/GLContextProviderCGL.mm +++ b/gfx/thebes/GLContextProviderCGL.mm @@ -46,6 +46,7 @@ #include "gfxPlatform.h" #include "gfxFailure.h" #include "prenv.h" +#include "mozilla/Preferences.h" namespace mozilla { namespace gl { @@ -263,6 +264,9 @@ GLContextCGL::UnbindTex2DOffscreen(GLContext *aOffscreen) bool GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) { + if (!IsOffscreenSizeAllowed(aNewSize)) + return false; + if (mPBuffer) { NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:LOCAL_GL_TEXTURE_2D @@ -274,6 +278,10 @@ GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) return false; } + if (!ResizeOffscreenFBO(aNewSize, false)) { + return false; + } + [mPBuffer release]; mPBuffer = pb; @@ -289,7 +297,7 @@ GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) return true; } - return ResizeOffscreenFBO(aNewSize); + return ResizeOffscreenFBO(aNewSize, true); } class TextureImageCGL : public BasicTextureImage @@ -528,8 +536,7 @@ CreateOffscreenPBufferContext(const gfxIntSize& aSize, } static already_AddRefed -CreateOffscreenFBOContext(const gfxIntSize& aSize, - const ContextFormat& aFormat, +CreateOffscreenFBOContext(const ContextFormat& aFormat, bool aShare = true) { if (!sCGLLibrary.EnsureInitialized()) { @@ -557,23 +564,32 @@ already_AddRefed GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize, const ContextFormat& aFormat) { + ContextFormat actualFormat(aFormat); + actualFormat.samples = 0; + nsRefPtr glContext; - - glContext = CreateOffscreenPBufferContext(aSize, aFormat); - if (glContext && - glContext->Init()) + + NS_ENSURE_TRUE(Preferences::GetRootBranch(), nsnull); + const bool preferFBOs = Preferences::GetBool("cgl.prefer-fbo", false); + if (!preferFBOs) { - glContext->mOffscreenSize = aSize; - glContext->mOffscreenActualSize = aSize; + glContext = CreateOffscreenPBufferContext(aSize, actualFormat); + if (glContext && + glContext->Init() && + glContext->ResizeOffscreenFBO(aSize, false)) + { + glContext->mOffscreenSize = aSize; + glContext->mOffscreenActualSize = aSize; - return glContext.forget(); + return glContext.forget(); + } } // try a FBO as second choice - glContext = CreateOffscreenFBOContext(aSize, aFormat); + glContext = CreateOffscreenFBOContext(actualFormat); if (glContext && glContext->Init() && - glContext->ResizeOffscreenFBO(aSize)) + glContext->ResizeOffscreenFBO(aSize, true)) { return glContext.forget(); } @@ -602,8 +618,7 @@ GLContextProviderCGL::GetGlobalContext() // than 16x16 in size; also 16x16 is POT so that we can do // a FBO with it on older video cards. A FBO context for // sharing is preferred since it has no associated target. - gGlobalContext = CreateOffscreenFBOContext(gfxIntSize(16, 16), - ContextFormat(ContextFormat::BasicRGB24), + gGlobalContext = CreateOffscreenFBOContext(ContextFormat(ContextFormat::BasicRGB24), false); if (!gGlobalContext || !static_cast(gGlobalContext.get())->Init()) { NS_WARNING("Couldn't init gGlobalContext."); diff --git a/gfx/thebes/GLContextProviderEGL.cpp b/gfx/thebes/GLContextProviderEGL.cpp index 7d9a095db7be..83320c99e869 100644 --- a/gfx/thebes/GLContextProviderEGL.cpp +++ b/gfx/thebes/GLContextProviderEGL.cpp @@ -1054,6 +1054,9 @@ GLContextEGL::UnbindTex2DOffscreen(GLContext *aOffscreen) bool GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) { + if (!IsOffscreenSizeAllowed(aNewSize)) + return false; + if (mIsPBuffer) { gfxIntSize pbsize(aNewSize); @@ -1067,9 +1070,12 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) pbsize); if (!surface) { NS_WARNING("Failed to resize pbuffer"); - return nsnull; + return false; } + if (!ResizeOffscreenFBO(pbsize, false)) + return false; + SetOffscreenSize(aNewSize, pbsize); if (mSurface && !mPlatformContext) { @@ -1114,6 +1120,9 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) if (!config) { return false; } + if (!ResizeOffscreenFBO(aNewSize, true)) + return false; + mThebesSurface = xsurface; return true; @@ -1121,10 +1130,13 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) #endif #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) - return ResizeOffscreenPixmapSurface(aNewSize); + if (ResizeOffscreenPixmapSurface(aNewSize)) { + if (ResizeOffscreenFBO(aNewSize, true)) + return true; + } #endif - return ResizeOffscreenFBO(aNewSize); + return ResizeOffscreenFBO(aNewSize, true); } @@ -1999,13 +2011,15 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize, nsTArray attribs(32); int attribAttempt = 0; + int tryDepthSize = (aFormat.depth > 0) ? 24 : 0; + TRY_ATTRIBS_AGAIN: switch (attribAttempt) { case 0: - FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, 24); + FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, tryDepthSize); break; case 1: - FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, 24); + FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, tryDepthSize); break; case 2: FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, -1); @@ -2239,9 +2253,27 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize, } #if defined(ANDROID) || defined(XP_WIN) - return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat); + nsRefPtr glContext = + GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat); + + if (!glContext) + return nsnull; + + if (!glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), false)) + return nsnull; + + return glContext.forget(); #elif defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) - return GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, aFormat); + nsRefPtr glContext = + GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, aFormat); + + if (!glContext) + return nsnull; + + if (!glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true)) + return nsnull; + + return glContext.forget(); #elif defined(MOZ_X11) nsRefPtr glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat, true); @@ -2254,7 +2286,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize, // render from this return nsnull; } - if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(aSize)) { + if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true)) { // we weren't able to create the initial // offscreen FBO, so this is dead return nsnull; diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/thebes/GLContextProviderGLX.cpp index 41b575702dc5..c4e8d52b7329 100644 --- a/gfx/thebes/GLContextProviderGLX.cpp +++ b/gfx/thebes/GLContextProviderGLX.cpp @@ -102,7 +102,11 @@ GLXLibrary::EnsureInitialized() // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 +#ifdef __OpenBSD__ + const char *libGLfilename = "libGL.so"; +#else const char *libGLfilename = "libGL.so.1"; +#endif ScopedGfxFeatureReporter reporter(libGLfilename); mOGLLibrary = PR_LoadLibrary(libGLfilename); if (!mOGLLibrary) { @@ -179,6 +183,11 @@ GLXLibrary::EnsureInitialized() { NULL, { NULL } } }; + LibrarySymbolLoader::SymLoadStruct symbols_robustness[] = { + { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", NULL } }, + { NULL, { NULL } } + }; + if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) { NS_WARNING("Couldn't find required entry point in OpenGL shared library"); return false; @@ -247,6 +256,17 @@ GLXLibrary::EnsureInitialized() NS_WARNING("Texture from pixmap disabled"); } + if (HasExtension(extensionsStr, "GL_ARB_robustness")) { + if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { + // We have no easy way of checking whether or not this extension + // exists, so it's best to just try to load it and accept that it + // might fail. + //NS_WARNING("Couldn't load ARB_robustness symbols"); + } else { + mHasRobustness = true; + } + } + gIsATI = serverVendor && DoesVendorStringMatch(serverVendor, "ATI"); gIsChromium = (serverVendor && DoesVendorStringMatch(serverVendor, "Chromium")) || @@ -629,6 +649,23 @@ GLXLibrary::xWaitX() AFTER_GLX_CALL; } +GLXContext +GLXLibrary::xCreateContextAttribs(Display* display, + GLXFBConfig config, + GLXContext share_list, + Bool direct, + const int* attrib_list) +{ + BEFORE_GLX_CALL; + GLXContext result = xCreateContextAttribsInternal(display, + config, + share_list, + direct, + attrib_list); + AFTER_GLX_CALL; + return result; +} + GLXLibrary sGLXLibrary; class GLContextGLX : public GLContext @@ -663,11 +700,25 @@ TRY_AGAIN_NO_SHARING: error = false; - context = sGLXLibrary.xCreateNewContext(display, - cfg, - GLX_RGBA_TYPE, - shareContext ? shareContext->mContext : NULL, - True); + if (sGLXLibrary.HasRobustness()) { + int attrib_list[] = { + LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB, + LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB, + 0, + }; + + context = sGLXLibrary.xCreateContextAttribs(display, + cfg, + shareContext ? shareContext->mContext : NULL, + True, + attrib_list); + } else { + context = sGLXLibrary.xCreateNewContext(display, + cfg, + GLX_RGBA_TYPE, + shareContext ? shareContext->mContext : NULL, + True); + } if (context) { glContext = new GLContextGLX(format, @@ -1237,7 +1288,6 @@ already_AddRefed GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize, const ContextFormat& aFormat) { - nsRefPtr glContext = CreateOffscreenPixmapContext(aSize, aFormat, true); @@ -1251,7 +1301,7 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize, return nsnull; } - if (!glContext->ResizeOffscreenFBO(aSize)) { + if (!glContext->ResizeOffscreenFBO(aSize, true)) { // we weren't able to create the initial // offscreen FBO, so this is dead return nsnull; diff --git a/gfx/thebes/GLContextProviderOSMesa.cpp b/gfx/thebes/GLContextProviderOSMesa.cpp index da07beac91bd..4290c8ba7367 100644 --- a/gfx/thebes/GLContextProviderOSMesa.cpp +++ b/gfx/thebes/GLContextProviderOSMesa.cpp @@ -259,7 +259,10 @@ GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize, return nsnull; } - nsRefPtr glContext = new GLContextOSMesa(aFormat); + ContextFormat actualFormat(aFormat); + actualFormat.samples = 0; + + nsRefPtr glContext = new GLContextOSMesa(actualFormat); if (!glContext->Init(aSize)) { diff --git a/gfx/thebes/GLContextProviderWGL.cpp b/gfx/thebes/GLContextProviderWGL.cpp index 69ae5f1256a9..928f9b733e5b 100644 --- a/gfx/thebes/GLContextProviderWGL.cpp +++ b/gfx/thebes/GLContextProviderWGL.cpp @@ -48,6 +48,8 @@ #include "prenv.h" +#include "mozilla/Preferences.h" + namespace mozilla { namespace gl { @@ -398,10 +400,44 @@ GLContextWGL::UnbindTex2DOffscreen(GLContext *aOffscreen) } } + +static bool +GetMaxSize(HDC hDC, int format, gfxIntSize& size) +{ + int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB}; + int result[2]; + + // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues) + if (!sWGLLibrary.fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result)) + return false; + + size.width = result[0]; + size.height = result[1]; + return true; +} + +static bool +IsValidSizeForFormat(HDC hDC, int format, const gfxIntSize& requested) +{ + gfxIntSize max; + if (!GetMaxSize(hDC, format, max)) + return true; + + if (requested.width > max.width) + return false; + if (requested.height > max.height) + return false; + + return true; +} + bool GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) { if (mPBuffer) { + if (!IsValidSizeForFormat(gSharedWindowDC, mPixelFormat, aNewSize)) + return false; + int pbattrs[] = { LOCAL_WGL_TEXTURE_FORMAT_ARB, mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB @@ -433,10 +469,10 @@ GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) MakeCurrent(); ClearSafely(); - return true; + return ResizeOffscreenFBO(aNewSize, false); } - return ResizeOffscreenFBO(aNewSize); + return ResizeOffscreenFBO(aNewSize, true); } static GLContextWGL * @@ -543,6 +579,9 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize, // XXX add back the priority choosing code here int chosenFormat = formats[0]; + if (!IsValidSizeForFormat(gSharedWindowDC, chosenFormat, aSize)) + return nsnull; + HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, chosenFormat, aSize.width, aSize.height, pbattrs.Elements()); @@ -570,8 +609,7 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize, } static already_AddRefed -CreateWindowOffscreenContext(const gfxIntSize& aSize, - const ContextFormat& aFormat) +CreateWindowOffscreenContext(const ContextFormat& aFormat) { // CreateWindowOffscreenContext must return a global-shared context GLContextWGL *shareContext = GetGlobalContextWGL(); @@ -616,7 +654,10 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize, // Always try to create a pbuffer context first, because we // want the context isolation. - if (sWGLLibrary.fCreatePbuffer && + NS_ENSURE_TRUE(Preferences::GetRootBranch(), nsnull); + const bool preferFBOs = Preferences::GetBool("wgl.prefer-fbo", false); + if (!preferFBOs && + sWGLLibrary.fCreatePbuffer && sWGLLibrary.fChoosePixelFormat) { glContext = CreatePBufferOffscreenContext(aSize, aFormat); @@ -624,7 +665,7 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize, // If it failed, then create a window context and use a FBO. if (!glContext) { - glContext = CreateWindowOffscreenContext(aSize, aFormat); + glContext = CreateWindowOffscreenContext(aFormat); } if (!glContext || @@ -633,15 +674,12 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize, return nsnull; } + if (!glContext->ResizeOffscreenFBO(aSize, !glContext->mPBuffer)) + return nsnull; + glContext->mOffscreenSize = aSize; glContext->mOffscreenActualSize = aSize; - if (!glContext->mPBuffer && - !glContext->ResizeOffscreenFBO(aSize)) - { - return nsnull; - } - return glContext.forget(); } diff --git a/gfx/thebes/GLContextSymbols.h b/gfx/thebes/GLContextSymbols.h index d53855d372f7..38aac71f7f9b 100644 --- a/gfx/thebes/GLContextSymbols.h +++ b/gfx/thebes/GLContextSymbols.h @@ -307,6 +307,11 @@ struct GLContextSymbols typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height); PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage; + typedef void (GLAPIENTRY * PFNGLBLITFRAMEBUFFER) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + PFNGLBLITFRAMEBUFFER fBlitFramebuffer; + typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLE) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height); + PFNGLRENDERBUFFERSTORAGEMULTISAMPLE fRenderbufferStorageMultisample; + /* These are different between GLES2 and desktop GL; we hide those differences, use the GL * names, but the most limited data type. @@ -368,6 +373,8 @@ struct GLContextSymbols typedef realGLboolean (GLAPIENTRY * PFNGLUNMAPBUFFER) (GLenum target); PFNGLUNMAPBUFFER fUnmapBuffer; + typedef GLenum (GLAPIENTRY * PFNGLGETGRAPHICSRESETSTATUS) (void); + PFNGLGETGRAPHICSRESETSTATUS fGetGraphicsResetStatus; }; } diff --git a/gfx/thebes/GLDefs.h b/gfx/thebes/GLDefs.h index 87c48ccb02b0..99fe58b970e6 100644 --- a/gfx/thebes/GLDefs.h +++ b/gfx/thebes/GLDefs.h @@ -178,6 +178,7 @@ typedef ptrdiff_t GLintptr; #define LOCAL_GL_STACK_OVERFLOW 0x0503 #define LOCAL_GL_STACK_UNDERFLOW 0x0504 #define LOCAL_GL_OUT_OF_MEMORY 0x0505 +#define LOCAL_GL_CONTEXT_LOST 0x9242 #define LOCAL_GL_2D 0x0600 #define LOCAL_GL_3D 0x0601 #define LOCAL_GL_3D_COLOR 0x0602 @@ -3039,6 +3040,49 @@ typedef ptrdiff_t GLintptr; #define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define LOCAL_GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 + +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 + +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 + +#define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 + +#define LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 + +#define LOCAL_GL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_GL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_GL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_GL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define LOCAL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define LOCAL_WGL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define LOCAL_GL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define LOCAL_GL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define LOCAL_WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define LOCAL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + +#define LOCAL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + #define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001 #define LOCAL_WGL_DRAW_TO_BITMAP_ARB 0x2002 diff --git a/gfx/thebes/GLXLibrary.h b/gfx/thebes/GLXLibrary.h index 3029bfd2c5d3..000b98fabdd5 100644 --- a/gfx/thebes/GLXLibrary.h +++ b/gfx/thebes/GLXLibrary.h @@ -50,7 +50,7 @@ class GLXLibrary public: GLXLibrary() : mInitialized(false), mTriedInitializing(false), mHasTextureFromPixmap(false), mDebug(false), - mOGLLibrary(nsnull) {} + mHasRobustness(false), mOGLLibrary(nsnull) {} void xDestroyContext(Display* display, GLXContext context); Bool xMakeCurrent(Display* display, @@ -108,6 +108,12 @@ public: void xWaitGL(); void xWaitX(); + GLXContext xCreateContextAttribs(Display* display, + GLXFBConfig config, + GLXContext share_list, + Bool direct, + const int* attrib_list); + bool EnsureInitialized(); GLXPixmap CreatePixmap(gfxASurface* aSurface); @@ -116,6 +122,7 @@ public: void ReleaseTexImage(GLXPixmap aPixmap); bool HasTextureFromPixmap() { return mHasTextureFromPixmap; } + bool HasRobustness() { return mHasRobustness; } bool SupportsTextureFromPixmap(gfxASurface* aSurface); private: @@ -209,6 +216,13 @@ private: typedef void (GLAPIENTRY * PFNGLXWAITX) (); PFNGLXWAITGL xWaitXInternal; + typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXTATTRIBS) (Display *, + GLXFBConfig, + GLXContext, + Bool, + const int *); + PFNGLXCREATECONTEXTATTRIBS xCreateContextAttribsInternal; + #ifdef DEBUG void BeforeGLXCall(); void AfterGLXCall(); @@ -218,6 +232,7 @@ private: bool mTriedInitializing; bool mHasTextureFromPixmap; bool mDebug; + bool mHasRobustness; PRLibrary *mOGLLibrary; }; diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index bad007b825e0..1372441df9bb 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -85,6 +85,7 @@ #include "nsIConsoleService.h" #include "nsServiceManagerUtils.h" #include "nsStringGlue.h" +#include "nsIClipboardHelper.h" using mozilla::CheckedInt; @@ -711,43 +712,69 @@ gfxASurface::RecordMemoryFreed() } } +#ifdef DEBUG void -gfxASurface::DumpAsDataURL() +gfxASurface::WriteAsPNG(const char* aFile) { - gfxIntSize size = GetSize(); - if (size.width == -1 && size.height == -1) { - printf("Could not determine surface size\n"); - return; - } + FILE *file = fopen(aFile, "wb"); + if (file) { + WriteAsPNG_internal(file, true); + fclose(file); + } else { + NS_WARNING("Failed to create file!\n"); + } +} + +void +gfxASurface::DumpAsDataURL() +{ + WriteAsPNG_internal(stdout, false); +} - nsAutoArrayPtr imageBuffer(new (std::nothrow) PRUint8[size.width * - size.height * - 4]); - if (!imageBuffer) { - printf("Could not allocate image buffer\n"); - return; - } - - nsRefPtr imgsurf = - new gfxImageSurface(imageBuffer.get(), - gfxIntSize(size.width, size.height), - size.width * 4, - gfxASurface::ImageFormatARGB32); +void +gfxASurface::CopyAsDataURL() +{ + WriteAsPNG_internal(nsnull, false); +} - if (!imgsurf || imgsurf->CairoStatus()) { - printf("Could not allocate image surface\n"); - return; - } +/** + * Write to a PNG file. If aBinary is true, then it is written + * as binary, otherwise as a data URL. If no file is specified then + * data is copied to the clipboard (must not be binary!). + */ +void +gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary) +{ + nsRefPtr imgsurf = GetAsImageSurface(); + gfxIntSize size; - nsRefPtr ctx = new gfxContext(imgsurf); - if (!ctx || ctx->HasError()) { - printf("Could not allocate image context\n"); - return; - } + if (!imgsurf) { + size = GetSize(); + if (size.width == -1 && size.height == -1) { + printf("Could not determine surface size\n"); + return; + } - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(this, gfxPoint(0, 0)); - ctx->Paint(); + imgsurf = + new gfxImageSurface(gfxIntSize(size.width, size.height), + gfxASurface::ImageFormatARGB32); + + if (!imgsurf || imgsurf->CairoStatus()) { + printf("Could not allocate image surface\n"); + return; + } + + nsRefPtr ctx = new gfxContext(imgsurf); + if (!ctx || ctx->HasError()) { + printf("Could not allocate image context\n"); + return; + } + + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(this, gfxPoint(0, 0)); + ctx->Paint(); + } + size = imgsurf->GetSize(); nsCOMPtr encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png"); @@ -757,18 +784,18 @@ gfxASurface::DumpAsDataURL() printf("Could not create encoder. Printing %dx%d pixels.\n", w, h); for (PRInt32 y = 0; y < h; ++y) { for (PRInt32 x = 0; x < w; ++x) { - printf("%x ", reinterpret_cast(imageBuffer.get())[y*size.width + x]); + printf("%x ", reinterpret_cast(imgsurf->Data())[y*imgsurf->Stride()+ x]); } printf("\n"); } return; } - nsresult rv = encoder->InitFromData(imageBuffer.get(), + nsresult rv = encoder->InitFromData(imgsurf->Data(), size.width * size.height * 4, size.width, size.height, - size.width * 4, + imgsurf->Stride(), imgIEncoder::INPUT_FORMAT_HOSTARGB, NS_LITERAL_STRING("")); if (NS_FAILED(rv)) @@ -808,18 +835,38 @@ gfxASurface::DumpAsDataURL() imgData = newImgData; } } + + if (aBinary) { + if (aFile) { + fwrite(imgData, 1, imgSize, aFile); + } else { + NS_WARNING("Can't write binary image data without a file!"); + } + return; + } // base 64, result will be NULL terminated char* encodedImg = PL_Base64Encode(imgData, imgSize, nsnull); PR_Free(imgData); if (!encodedImg) // not sure why this would fail return; - - printf("data:image/png;base64,"); - printf("%s", encodedImg); - printf("\n"); + + nsCString string("data:image/png;base64,"); + string.Append(encodedImg); + + if (aFile) { + fprintf(aFile, "%s", string.BeginReading()); + fprintf(aFile, "\n"); + } else { + nsCOMPtr clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv)); + if (clipboard) { + clipboard->CopyString(NS_ConvertASCIItoUTF16(string)); + } + } + PR_Free(encodedImg); return; } +#endif diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index 4d84a30e26ea..8160ad53633d 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -229,8 +229,29 @@ public: virtual const gfxIntSize GetSize() const { return gfxIntSize(-1, -1); } +#ifdef DEBUG + /** + * Debug functions to encode the current image as a PNG and export it. + */ + + /** + * Writes a binary PNG file. + */ + void WriteAsPNG(const char* aFile); + + /** + * Write as a PNG encoded Data URL to stdout. + */ void DumpAsDataURL(); + /** + * Copy a PNG encoded Data URL to the clipboard. + */ + void CopyAsDataURL(); + + void WriteAsPNG_internal(FILE* aFile, bool aBinary); +#endif + void SetOpaqueRect(const gfxRect& aRect) { if (aRect.IsEmpty()) { mOpaqueRect = nsnull; diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 8c1f74d92370..5185c1655fb6 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -1067,3 +1067,38 @@ gfxContext::RoundedRectangle(const gfxRect& rect, cairo_close_path (mCairo); } + +#ifdef DEBUG +void +gfxContext::WriteAsPNG(const char* aFile) +{ + nsRefPtr surf = CurrentSurface(); + if (surf) { + surf->WriteAsPNG(aFile); + } else { + NS_WARNING("No surface found!"); + } +} + +void +gfxContext::DumpAsDataURL() +{ + nsRefPtr surf = CurrentSurface(); + if (surf) { + surf->DumpAsDataURL(); + } else { + NS_WARNING("No surface found!"); + } +} + +void +gfxContext::CopyAsDataURL() +{ + nsRefPtr surf = CurrentSurface(); + if (surf) { + surf->CopyAsDataURL(); + } else { + NS_WARNING("No surface found!"); + } +} +#endif diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index 0cae1ff0470f..fdc9d4d65022 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -681,6 +681,27 @@ public: void ClearFlag(PRInt32 aFlag) { mFlags &= ~aFlag; } PRInt32 GetFlags() const { return mFlags; } +#ifdef DEBUG + /** + * Debug functions to encode the current surface as a PNG and export it. + */ + + /** + * Writes a binary PNG file. + */ + void WriteAsPNG(const char* aFile); + + /** + * Write as a PNG encoded Data URL to stdout. + */ + void DumpAsDataURL(); + + /** + * Copy a PNG encoded Data URL to the clipboard. + */ + void CopyAsDataURL(); +#endif + private: cairo_t *mCairo; nsRefPtr mSurface; diff --git a/gfx/thebes/gfxGDIShaper.cpp b/gfx/thebes/gfxGDIShaper.cpp index e35f3c16b84a..cc5fe2d39ea9 100644 --- a/gfx/thebes/gfxGDIShaper.cpp +++ b/gfx/thebes/gfxGDIShaper.cpp @@ -58,6 +58,7 @@ gfxGDIShaper::InitTextRun(gfxContext *aContext, PRInt32 aRunScript) { DCFromContext dc(aContext); + AutoSelectFont selectFont(dc, static_cast(mFont)->GetHFONT()); nsAutoTArray glyphArray; if (!glyphArray.SetLength(aRunLength)) { diff --git a/gfx/thebes/gfxMatrix.h b/gfx/thebes/gfxMatrix.h index f329f4f5c535..e60479cb6f05 100644 --- a/gfx/thebes/gfxMatrix.h +++ b/gfx/thebes/gfxMatrix.h @@ -251,8 +251,7 @@ public: if (det == 0.0) return gfxSize(0.0, 0.0); - gfxSize sz((xMajor != 0 ? 1.0 : 0.0), - (xMajor != 0 ? 0.0 : 1.0)); + gfxSize sz = xMajor ? gfxSize(1.0, 0.0) : gfxSize(0.0, 1.0); sz = Transform(sz); double major = sqrt(sz.width * sz.width + sz.height * sz.height); diff --git a/gfx/thebes/nsCoreAnimationSupport.h b/gfx/thebes/nsCoreAnimationSupport.h index a87ee5d2c873..c5f2badffaee 100644 --- a/gfx/thebes/nsCoreAnimationSupport.h +++ b/gfx/thebes/nsCoreAnimationSupport.h @@ -60,9 +60,9 @@ typedef uint32_t IOSurfaceID; class THEBES_API nsCARenderer { NS_INLINE_DECL_REFCOUNTING(nsCARenderer) public: - nsCARenderer() : mCARenderer(nsnull), mPixelBuffer(nsnull), mOpenGLContext(nsnull), + nsCARenderer() : mCARenderer(nsnull), mFBOTexture(nsnull), mOpenGLContext(nsnull), mCGImage(nsnull), mCGData(nsnull), mIOSurface(nsnull), mFBO(nsnull), - mIOTexture(nsnull), + mIOTexture(nsnull), mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX) {} ~nsCARenderer(); nsresult SetupRenderer(void* aCALayer, int aWidth, int aHeight); @@ -72,15 +72,15 @@ public: * Render the CALayer to an IOSurface. If no IOSurface * is attached then an internal pixel buffer will be * used. - */ + */ void AttachIOSurface(nsRefPtr aSurface); IOSurfaceID GetIOSurfaceID(); - static nsresult DrawSurfaceToCGContext(CGContextRef aContext, - nsIOSurface *surf, - CGColorSpaceRef aColorSpace, + static nsresult DrawSurfaceToCGContext(CGContextRef aContext, + nsIOSurface *surf, + CGColorSpaceRef aColorSpace, int aX, int aY, size_t aWidth, size_t aHeight); - + // Remove & Add the layer without destroying // the renderer for fast back buffer swapping. void DettachCALayer(); @@ -92,7 +92,7 @@ private: void Destroy(); void *mCARenderer; - _CGLPBufferObject *mPixelBuffer; + GLuint mFBOTexture; _CGLContextObject *mOpenGLContext; CGImageRef mCGImage; void *mCGData; diff --git a/gfx/thebes/nsCoreAnimationSupport.mm b/gfx/thebes/nsCoreAnimationSupport.mm index 3f85894719b4..964fc9346e05 100644 --- a/gfx/thebes/nsCoreAnimationSupport.mm +++ b/gfx/thebes/nsCoreAnimationSupport.mm @@ -402,15 +402,15 @@ void nsCARenderer::Destroy() { caRenderer.layer = nsnull; [caRenderer release]; } - if (mPixelBuffer) { - ::CGLDestroyPBuffer((CGLPBufferObj)mPixelBuffer); - } if (mOpenGLContext) { - if (mFBO || mIOTexture) { + if (mFBO || mIOTexture || mFBOTexture) { // Release these resources with the context that allocated them CGLContextObj oldContext = ::CGLGetCurrentContext(); ::CGLSetCurrentContext(mOpenGLContext); + if (mFBOTexture) { + ::glDeleteTextures(1, &mFBOTexture); + } if (mIOTexture) { ::glDeleteTextures(1, &mIOTexture); } @@ -430,7 +430,7 @@ void nsCARenderer::Destroy() { // mCGData is deallocated by cgdata_release_callback mCARenderer = nil; - mPixelBuffer = nsnull; + mFBOTexture = 0; mOpenGLContext = nsnull; mCGImage = nsnull; mIOSurface = nsnull; @@ -442,7 +442,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { if (aWidth == 0 || aHeight == 0) return NS_ERROR_FAILURE; - if (aWidth == mUnsupportedWidth && + if (aWidth == mUnsupportedWidth && aHeight == mUnsupportedHeight) { return NS_ERROR_FAILURE; } @@ -457,17 +457,6 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { (CGLPixelFormatAttribute)0 }; - if (!mIOSurface) { - CGLError result = ::CGLCreatePBuffer(aWidth, aHeight, - GL_TEXTURE_2D, GL_RGBA, 0, &mPixelBuffer); - if (result != kCGLNoError) { - mUnsupportedWidth = aWidth; - mUnsupportedHeight = aHeight; - Destroy(); - return NS_ERROR_FAILURE; - } - } - GLint screen; CGLPixelFormatObj format; if (::CGLChoosePixelFormat(attributes, &format, &screen) != kCGLNoError) { @@ -516,7 +505,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { caRenderer.bounds = CGRectMake(0, 0, aWidth, aHeight); [CATransaction commit]; - // We either target rendering to a CGImage or IOSurface. + // We target rendering to a CGImage if no shared IOSurface are given. if (!mIOSurface) { mCGData = malloc(aWidth*aHeight*4); if (!mCGData) { @@ -528,7 +517,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { CGDataProviderRef dataProvider = nsnull; dataProvider = ::CGDataProviderCreateWithData(mCGData, - mCGData, aHeight*aWidth*4, + mCGData, aHeight*aWidth*4, cgdata_release_callback); if (!dataProvider) { cgdata_release_callback(mCGData, mCGData, aHeight*aWidth*4); @@ -540,7 +529,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { CGColorSpaceRef colorSpace = CreateSystemColorSpace(); - mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, + mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider, NULL, true, kCGRenderingIntentDefault); @@ -554,10 +543,12 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { Destroy(); return NS_ERROR_FAILURE; } - } else { - CGLContextObj oldContext = ::CGLGetCurrentContext(); - ::CGLSetCurrentContext(mOpenGLContext); + } + CGLContextObj oldContext = ::CGLGetCurrentContext(); + ::CGLSetCurrentContext(mOpenGLContext); + + if (mIOSurface) { // Create the IOSurface mapped texture. ::glGenTextures(1, &mIOTexture); ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mIOTexture); @@ -565,35 +556,41 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nsIOSurfaceLib::CGLTexImageIOSurface2D(mOpenGLContext, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, aWidth, aHeight, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, mIOSurface->mIOSurfacePtr, 0); ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Create the fbo - ::glGenFramebuffersEXT(1, &mFBO); - ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); - ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0); - - // Make sure that the Framebuffer configuration is supported on the client machine - GLenum fboStatus; - fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) { - NS_ERROR("FBO not supported"); - if (oldContext) - ::CGLSetCurrentContext(oldContext); - mUnsupportedWidth = aWidth; - mUnsupportedHeight = aHeight; - Destroy(); - return NS_ERROR_FAILURE; - } - - if (oldContext) - ::CGLSetCurrentContext(oldContext); + } else { + ::glGenTextures(1, &mFBOTexture); + ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFBOTexture); + ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } - CGLContextObj oldContext = ::CGLGetCurrentContext(); - ::CGLSetCurrentContext(mOpenGLContext); + // Create the fbo + ::glGenFramebuffersEXT(1, &mFBO); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + if (mIOSurface) { + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0); + } else { + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, mFBOTexture, 0); + } + + + // Make sure that the Framebuffer configuration is supported on the client machine + GLenum fboStatus; + fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) { + NS_ERROR("FBO not supported"); + if (oldContext) + ::CGLSetCurrentContext(oldContext); + mUnsupportedWidth = aWidth; + mUnsupportedHeight = aHeight; + Destroy(); + return NS_ERROR_FAILURE; + } ::glViewport(0.0, 0.0, aWidth, aHeight); ::glMatrixMode(GL_PROJECTION); @@ -682,7 +679,9 @@ nsresult nsCARenderer::Render(int aWidth, int aHeight, CGLContextObj oldContext = ::CGLGetCurrentContext(); ::CGLSetCurrentContext(mOpenGLContext); if (!mIOSurface) { - ::CGLSetPBuffer(mOpenGLContext, mPixelBuffer, 0, 0, 0); + // If no shared IOSurface is given render to our own + // texture for readback. + ::glGenTextures(1, &mFBOTexture); } GLenum result = ::glGetError(); diff --git a/hal/HalImpl.h b/hal/HalImpl.h index 03a56aebf0b1..61b3147cfb69 100644 --- a/hal/HalImpl.h +++ b/hal/HalImpl.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/HalSandbox.h b/hal/HalSandbox.h index 7ee1082dee81..10ab8ffeacd5 100644 --- a/hal/HalSandbox.h +++ b/hal/HalSandbox.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/fallback/FallbackHal.cpp b/hal/fallback/FallbackHal.cpp index 80d0a9756c85..da6b0656a52b 100644 --- a/hal/fallback/FallbackHal.cpp +++ b/hal/fallback/FallbackHal.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/PHal.ipdl b/hal/sandbox/PHal.ipdl index ff685e9ba9dc..d32ac911ee60 100644 --- a/hal/sandbox/PHal.ipdl +++ b/hal/sandbox/PHal.ipdl @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index a451a7f99710..5f2d204b7b8b 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/SandboxHal.h b/hal/sandbox/SandboxHal.h index b9033ab162c7..808544efa10a 100644 --- a/hal/sandbox/SandboxHal.h +++ b/hal/sandbox/SandboxHal.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index 661cea4693d2..eca019149681 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -63,7 +63,7 @@ PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder"); #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1)) #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col) -nsBMPDecoder::nsBMPDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsBMPDecoder::nsBMPDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver) { mColors = nsnull; @@ -341,9 +341,9 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount) PRUint32 imageLength; if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 || mBIH.compression == BI_ALPHABITFIELDS) { - rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, - gfxASurface::ImageFormatARGB32, - (PRUint8**)&mImageData, &imageLength); + rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, + gfxASurface::ImageFormatARGB32, + (PRUint8**)&mImageData, &imageLength); } else { // mRow is not used for RLE encoded images mRow = (PRUint8*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4); @@ -356,13 +356,13 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount) } if (mUseAlphaData) { - rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, - gfxASurface::ImageFormatARGB32, - (PRUint8**)&mImageData, &imageLength); + rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, + gfxASurface::ImageFormatARGB32, + (PRUint8**)&mImageData, &imageLength); } else { - rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, - gfxASurface::ImageFormatRGB24, - (PRUint8**)&mImageData, &imageLength); + rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, + gfxASurface::ImageFormatRGB24, + (PRUint8**)&mImageData, &imageLength); } } if (NS_FAILED(rv) || !mImageData) { diff --git a/image/decoders/nsBMPDecoder.h b/image/decoders/nsBMPDecoder.h index 0a8935edb850..5f2322e737db 100644 --- a/image/decoders/nsBMPDecoder.h +++ b/image/decoders/nsBMPDecoder.h @@ -59,7 +59,7 @@ class nsBMPDecoder : public Decoder { public: - nsBMPDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsBMPDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver); ~nsBMPDecoder(); // Specifies whether or not the BMP file will contain alpha data diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index 095b0daca13f..073a7ba545ae 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -107,7 +107,7 @@ namespace imagelib { ////////////////////////////////////////////////////////////////////// // GIF Decoder Implementation -nsGIFDecoder2::nsGIFDecoder2(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsGIFDecoder2::nsGIFDecoder2(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver) , mCurrentRow(-1) , mLastFlushedRow(-1) @@ -150,7 +150,7 @@ nsGIFDecoder2::FinishInternal() mGIFOpen = false; } - mImage->SetLoopCount(mGIFStruct.loop_count - 1); + mImage.SetLoopCount(mGIFStruct.loop_count - 1); } // Push any new rows according to mCurrentPass/mLastFlushedPass and @@ -216,24 +216,24 @@ nsresult nsGIFDecoder2::BeginImageFrame(PRUint16 aDepth) // and include transparency to allow for optimization of opaque images if (mGIFStruct.images_decoded) { // Image data is stored with original depth and palette - rv = mImage->EnsureFrame(mGIFStruct.images_decoded, - mGIFStruct.x_offset, mGIFStruct.y_offset, - mGIFStruct.width, mGIFStruct.height, - format, aDepth, &mImageData, &imageDataLength, - &mColormap, &mColormapSize); + rv = mImage.EnsureFrame(mGIFStruct.images_decoded, + mGIFStruct.x_offset, mGIFStruct.y_offset, + mGIFStruct.width, mGIFStruct.height, + format, aDepth, &mImageData, &imageDataLength, + &mColormap, &mColormapSize); } else { // Regardless of depth of input, image is decoded into 24bit RGB - rv = mImage->EnsureFrame(mGIFStruct.images_decoded, - mGIFStruct.x_offset, mGIFStruct.y_offset, - mGIFStruct.width, mGIFStruct.height, - format, &mImageData, &imageDataLength); + rv = mImage.EnsureFrame(mGIFStruct.images_decoded, + mGIFStruct.x_offset, mGIFStruct.y_offset, + mGIFStruct.width, mGIFStruct.height, + format, &mImageData, &imageDataLength); } if (NS_FAILED(rv)) return rv; - mImage->SetFrameDisposalMethod(mGIFStruct.images_decoded, - mGIFStruct.disposal_method); + mImage.SetFrameDisposalMethod(mGIFStruct.images_decoded, + mGIFStruct.disposal_method); // Tell the superclass we're starting a frame PostFrameStart(); @@ -244,7 +244,7 @@ nsresult nsGIFDecoder2::BeginImageFrame(PRUint16 aDepth) // on the screen. (Bug 37589) if (mGIFStruct.y_offset > 0) { PRInt32 imgWidth; - mImage->GetWidth(&imgWidth); + mImage.GetWidth(&imgWidth); nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset); PostInvalidation(r); } @@ -275,7 +275,7 @@ void nsGIFDecoder2::EndImageFrame() } // This transparency check is only valid for first frame if (mGIFStruct.is_transparent && !mSawTransparency) { - mImage->SetFrameHasNoAlpha(mGIFStruct.images_decoded); + mImage.SetFrameHasNoAlpha(mGIFStruct.images_decoded); } } mCurrentRow = mLastFlushedRow = -1; @@ -293,7 +293,7 @@ void nsGIFDecoder2::EndImageFrame() // image data, at least according to the spec, but we delay in setting the // timeout for the image until here to help ensure that we have the whole // image frame decoded before we go off and try to display another frame. - mImage->SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time); + mImage.SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time); } // Unconditionally increment images_decoded, because we unconditionally diff --git a/image/decoders/nsGIFDecoder2.h b/image/decoders/nsGIFDecoder2.h index 9e7a745e6fee..483badb45aed 100644 --- a/image/decoders/nsGIFDecoder2.h +++ b/image/decoders/nsGIFDecoder2.h @@ -58,7 +58,7 @@ class nsGIFDecoder2 : public Decoder { public: - nsGIFDecoder2(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsGIFDecoder2(RasterImage &aImage, imgIDecoderObserver* aObserver); ~nsGIFDecoder2(); virtual void WriteInternal(const char* aBuffer, PRUint32 aCount); diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index b63f0836a83f..83d025ac20dc 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -99,7 +99,7 @@ nsICODecoder::GetNumColors() } -nsICODecoder::nsICODecoder(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsICODecoder::nsICODecoder(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver) { mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0; @@ -209,8 +209,8 @@ nsICODecoder::SetHotSpotIfCursor() { intwrapx->SetData(mDirEntry.mXHotspot); intwrapy->SetData(mDirEntry.mYHotspot); - mImage->Set("hotspotX", intwrapx); - mImage->Set("hotspotY", intwrapy); + mImage.Set("hotspotX", intwrapx); + mImage.Set("hotspotY", intwrapy); } } @@ -495,8 +495,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount) // Ensure memory has been allocated before decoding. NS_ABORT_IF_FALSE(mRow, "mRow is null"); - NS_ABORT_IF_FALSE(mImage, "mImage is null"); - if (!mRow || !mImage) { + if (!mRow) { PostDataError(); return; } diff --git a/image/decoders/nsICODecoder.h b/image/decoders/nsICODecoder.h index bffe9488d51e..87dec0509c49 100644 --- a/image/decoders/nsICODecoder.h +++ b/image/decoders/nsICODecoder.h @@ -58,7 +58,7 @@ class nsICODecoder : public Decoder { public: - nsICODecoder(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsICODecoder(RasterImage &aImage, imgIDecoderObserver* aObserver); virtual ~nsICODecoder(); // Obtains the width of the icon directory entry diff --git a/image/decoders/nsIconDecoder.cpp b/image/decoders/nsIconDecoder.cpp index 2e0708f922c6..c69b82e1223c 100644 --- a/image/decoders/nsIconDecoder.cpp +++ b/image/decoders/nsIconDecoder.cpp @@ -50,7 +50,7 @@ namespace mozilla { namespace imagelib { -nsIconDecoder::nsIconDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsIconDecoder::nsIconDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver), mWidth(-1), mHeight(-1), @@ -114,9 +114,9 @@ nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount) } // Add the frame and signal - rv = mImage->EnsureFrame(0, 0, 0, mWidth, mHeight, - gfxASurface::ImageFormatARGB32, - &mImageData, &mPixBytesTotal); + rv = mImage.EnsureFrame(0, 0, 0, mWidth, mHeight, + gfxASurface::ImageFormatARGB32, + &mImageData, &mPixBytesTotal); if (NS_FAILED(rv)) { PostDecoderError(rv); return; diff --git a/image/decoders/nsIconDecoder.h b/image/decoders/nsIconDecoder.h index 2f228cde330d..ec775063d3e9 100644 --- a/image/decoders/nsIconDecoder.h +++ b/image/decoders/nsIconDecoder.h @@ -74,7 +74,7 @@ class nsIconDecoder : public Decoder { public: - nsIconDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsIconDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver); virtual ~nsIconDecoder(); virtual void WriteInternal(const char* aBuffer, PRUint32 aCount); diff --git a/image/decoders/nsJPEGDecoder.cpp b/image/decoders/nsJPEGDecoder.cpp index 019cd8ebb539..002568178700 100644 --- a/image/decoders/nsJPEGDecoder.cpp +++ b/image/decoders/nsJPEGDecoder.cpp @@ -109,7 +109,7 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo); #define MAX_JPEG_MARKER_LENGTH (((PRUint32)1 << 16) - 1) -nsJPEGDecoder::nsJPEGDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsJPEGDecoder::nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver) { mState = JPEG_HEADER; @@ -392,9 +392,9 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount) jpeg_calc_output_dimensions(&mInfo); PRUint32 imagelength; - if (NS_FAILED(mImage->EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height, - gfxASurface::ImageFormatRGB24, - &mImageData, &imagelength))) { + if (NS_FAILED(mImage.EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height, + gfxASurface::ImageFormatRGB24, + &mImageData, &imagelength))) { mState = JPEG_ERROR; PostDecoderError(NS_ERROR_OUT_OF_MEMORY); PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, diff --git a/image/decoders/nsJPEGDecoder.h b/image/decoders/nsJPEGDecoder.h index fb0dc99bfcfb..512e0600d5f1 100644 --- a/image/decoders/nsJPEGDecoder.h +++ b/image/decoders/nsJPEGDecoder.h @@ -86,7 +86,7 @@ class RasterImage; class nsJPEGDecoder : public Decoder { public: - nsJPEGDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver); virtual ~nsJPEGDecoder(); virtual void InitInternal(); diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index cd4d74131999..a43b33018c03 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -81,7 +81,7 @@ static PRLogModuleInfo *gPNGDecoderAccountingLog = const PRUint8 nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; -nsPNGDecoder::nsPNGDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver) +nsPNGDecoder::nsPNGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver) : Decoder(aImage, aObserver), mPNG(nsnull), mInfo(nsnull), mCMSLine(nsnull), interlacebuf(nsnull), @@ -117,9 +117,9 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, gfxASurface::gfxImageFormat format) { PRUint32 imageDataLength; - nsresult rv = mImage->EnsureFrame(GetFrameCount(), x_offset, y_offset, - width, height, format, - &mImageData, &imageDataLength); + nsresult rv = mImage.EnsureFrame(GetFrameCount(), x_offset, y_offset, + width, height, format, + &mImageData, &imageDataLength); if (NS_FAILED(rv)) longjmp(png_jmpbuf(mPNG), 5); // NS_ERROR_OUT_OF_MEMORY @@ -140,7 +140,7 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created " "image frame with %dx%d pixels in container %p", width, height, - mImage.get ())); + &mImage)); mFrameHasNoAlpha = true; } @@ -172,24 +172,24 @@ void nsPNGDecoder::SetAnimFrameInfo() (static_cast(delay_num) * 1000 / delay_den); } - PRUint32 numFrames = mImage->GetNumFrames(); + PRUint32 numFrames = mImage.GetNumFrames(); - mImage->SetFrameTimeout(numFrames - 1, timeout); + mImage.SetFrameTimeout(numFrames - 1, timeout); if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) - mImage->SetFrameDisposalMethod(numFrames - 1, - RasterImage::kDisposeRestorePrevious); + mImage.SetFrameDisposalMethod(numFrames - 1, + RasterImage::kDisposeRestorePrevious); else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) - mImage->SetFrameDisposalMethod(numFrames - 1, - RasterImage::kDisposeClear); + mImage.SetFrameDisposalMethod(numFrames - 1, + RasterImage::kDisposeClear); else - mImage->SetFrameDisposalMethod(numFrames - 1, - RasterImage::kDisposeKeep); + mImage.SetFrameDisposalMethod(numFrames - 1, + RasterImage::kDisposeKeep); if (blend_op == PNG_BLEND_OP_SOURCE) - mImage->SetFrameBlendMethod(numFrames - 1, RasterImage::kBlendSource); + mImage.SetFrameBlendMethod(numFrames - 1, RasterImage::kBlendSource); /*else // 'over' is the default - mImage->SetFrameBlendMethod(numFrames - 1, RasterImage::kBlendOver); */ + mImage.SetFrameBlendMethod(numFrames - 1, RasterImage::kBlendOver); */ } #endif @@ -201,13 +201,13 @@ void nsPNGDecoder::EndImageFrame() PRUint32 numFrames = 1; #ifdef PNG_APNG_SUPPORTED - numFrames = mImage->GetNumFrames(); + numFrames = mImage.GetNumFrames(); // We can't use mPNG->num_frames_read as it may be one ahead. if (numFrames > 1) { // Tell the image renderer that the frame is complete if (mFrameHasNoAlpha) - mImage->SetFrameHasNoAlpha(numFrames - 1); + mImage.SetFrameHasNoAlpha(numFrames - 1); PostInvalidation(mFrameRect); } @@ -796,7 +796,7 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row, if (!rowHasNoAlpha) decoder->mFrameHasNoAlpha = false; - PRUint32 numFrames = decoder->mImage->GetNumFrames(); + PRUint32 numFrames = decoder->mImage.GetNumFrames(); if (numFrames <= 1) { // Only do incremental image display for the first frame // XXXbholley - this check should be handled in the superclass @@ -856,7 +856,7 @@ nsPNGDecoder::end_callback(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_APNG_SUPPORTED if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) { PRInt32 num_plays = png_get_num_plays(png_ptr, info_ptr); - decoder->mImage->SetLoopCount(num_plays - 1); + decoder->mImage.SetLoopCount(num_plays - 1); } #endif diff --git a/image/decoders/nsPNGDecoder.h b/image/decoders/nsPNGDecoder.h index 83fd93fcaf25..6824232c4427 100644 --- a/image/decoders/nsPNGDecoder.h +++ b/image/decoders/nsPNGDecoder.h @@ -59,7 +59,7 @@ class RasterImage; class nsPNGDecoder : public Decoder { public: - nsPNGDecoder(RasterImage *aImage, imgIDecoderObserver* aObserver); + nsPNGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver); virtual ~nsPNGDecoder(); virtual void InitInternal(); diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 1d1c91c48502..1350a6f43c58 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -44,8 +44,10 @@ namespace mozilla { namespace imagelib { -Decoder::Decoder(RasterImage *aImage, imgIDecoderObserver* aObserver) - : mDecodeFlags(0) +Decoder::Decoder(RasterImage &aImage, imgIDecoderObserver* aObserver) + : mImage(aImage) + , mObserver(aObserver) + , mDecodeFlags(0) , mFrameCount(0) , mFailCode(NS_OK) , mInitialized(false) @@ -54,12 +56,6 @@ Decoder::Decoder(RasterImage *aImage, imgIDecoderObserver* aObserver) , mDecodeDone(false) , mDataError(false) { - // We should always have an image - NS_ABORT_IF_FALSE(aImage, "Can't initialize decoder without an image!"); - - // Save our paremeters - mImage = aImage; - mObserver = aObserver; } Decoder::~Decoder() @@ -138,14 +134,14 @@ Decoder::Finish() if (consoleService && errorObject && !HasDecoderError()) { nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") + - NS_ConvertASCIItoUTF16(mImage->GetURIString())); + NS_ConvertASCIItoUTF16(mImage.GetURIString())); errorObject->InitWithWindowID (msg.get(), - NS_ConvertUTF8toUTF16(mImage->GetURIString()).get(), + NS_ConvertUTF8toUTF16(mImage.GetURIString()).get(), nsnull, 0, 0, nsIScriptError::errorFlag, - "Image", mImage->InnerWindowID() + "Image", mImage.InnerWindowID() ); nsCOMPtr error = do_QueryInterface(errorObject); @@ -153,15 +149,15 @@ Decoder::Finish() } // If we only have a data error, see if things are worth salvaging - bool salvage = !HasDecoderError() && mImage->GetNumFrames(); + bool salvage = !HasDecoderError() && mImage.GetNumFrames(); // If we're salvaging, say we finished decoding if (salvage) - mImage->DecodingComplete(); + mImage.DecodingComplete(); // Fire teardown notifications if (mObserver) { - mObserver->OnStopContainer(nsnull, mImage); + mObserver->OnStopContainer(nsnull, &mImage); mObserver->OnStopDecode(nsnull, salvage ? NS_OK : NS_ERROR_FAILURE, nsnull); } } @@ -186,11 +182,11 @@ Decoder::FlushInvalidations() return; // Tell the image that it's been updated - mImage->FrameUpdated(mFrameCount - 1, mInvalidRect); + mImage.FrameUpdated(mFrameCount - 1, mInvalidRect); // Fire OnDataAvailable if (mObserver) { - bool isCurrentFrame = mImage->GetCurrentFrameIndex() == (mFrameCount - 1); + bool isCurrentFrame = mImage.GetCurrentFrameIndex() == (mFrameCount - 1); mObserver->OnDataAvailable(nsnull, isCurrentFrame, &mInvalidRect); } @@ -218,11 +214,11 @@ Decoder::PostSize(PRInt32 aWidth, PRInt32 aHeight) NS_ABORT_IF_FALSE(aHeight >= 0, "Height can't be negative!"); // Tell the image - mImage->SetSize(aWidth, aHeight); + mImage.SetSize(aWidth, aHeight); // Notify the observer if (mObserver) - mObserver->OnStartContainer(nsnull, mImage); + mObserver->OnStartContainer(nsnull, &mImage); } void @@ -243,7 +239,7 @@ Decoder::PostFrameStart() // Decoder implementations should only call this method if they successfully // appended the frame to the image. So mFrameCount should always match that // reported by the Image. - NS_ABORT_IF_FALSE(mFrameCount == mImage->GetNumFrames(), + NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(), "Decoder frame count doesn't match image's!"); // Fire notification @@ -287,9 +283,9 @@ Decoder::PostDecodeDone() mDecodeDone = true; // Notify - mImage->DecodingComplete(); + mImage.DecodingComplete(); if (mObserver) { - mObserver->OnStopContainer(nsnull, mImage); + mObserver->OnStopContainer(nsnull, &mImage); mObserver->OnStopDecode(nsnull, NS_OK, nsnull); } } diff --git a/image/src/Decoder.h b/image/src/Decoder.h index 869c509385e0..6b93c41c0b18 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -50,7 +50,7 @@ class Decoder { public: - Decoder(RasterImage* aImage, imgIDecoderObserver* aObserver); + Decoder(RasterImage& aImage, imgIDecoderObserver* aObserver); virtual ~Decoder(); /** @@ -201,7 +201,7 @@ protected: * Member variables. * */ - nsRefPtr mImage; + RasterImage &mImage; nsCOMPtr mObserver; PRUint32 mDecodeFlags; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 78ad76a96f21..57940dbe839b 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -339,7 +339,6 @@ RasterImage::ExtractFrame(PRUint32 aWhichFrame, // Make a new container. This should switch to another class with bug 505959. nsRefPtr img(new RasterImage()); - NS_ENSURE_TRUE(img, NS_ERROR_OUT_OF_MEMORY); // We don't actually have a mimetype in this case. The empty string tells the // init routine not to try to instantiate a decoder. This should be fixed in @@ -849,7 +848,6 @@ RasterImage::InternalAddFrame(PRUint32 framenum, return NS_ERROR_INVALID_ARG; nsAutoPtr frame(new imgFrame()); - NS_ENSURE_TRUE(frame, NS_ERROR_OUT_OF_MEMORY); nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth); NS_ENSURE_SUCCESS(rv, rv); @@ -1650,10 +1648,6 @@ RasterImage::DoComposite(nsIntRect* aDirtyRect, // Create the Compositing Frame if (!mAnim->compositingFrame) { mAnim->compositingFrame = new imgFrame(); - if (!mAnim->compositingFrame) { - NS_WARNING("Failed to init compositingFrame!\n"); - return NS_ERROR_OUT_OF_MEMORY; - } nsresult rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height, gfxASurface::ImageFormatARGB32); if (NS_FAILED(rv)) { @@ -1765,10 +1759,6 @@ RasterImage::DoComposite(nsIntRect* aDirtyRect, // overwrite. if (!mAnim->compositingPrevFrame) { mAnim->compositingPrevFrame = new imgFrame(); - if (!mAnim->compositingPrevFrame) { - NS_WARNING("Failed to init compositingPrevFrame!\n"); - return NS_ERROR_OUT_OF_MEMORY; - } nsresult rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height, gfxASurface::ImageFormatARGB32); if (NS_FAILED(rv)) { @@ -2162,22 +2152,22 @@ RasterImage::InitDecoder(bool aDoSizeDecode) // Instantiate the appropriate decoder switch (type) { case eDecoderType_png: - mDecoder = new nsPNGDecoder(this, observer); + mDecoder = new nsPNGDecoder(*this, observer); break; case eDecoderType_gif: - mDecoder = new nsGIFDecoder2(this, observer); + mDecoder = new nsGIFDecoder2(*this, observer); break; case eDecoderType_jpeg: - mDecoder = new nsJPEGDecoder(this, observer); + mDecoder = new nsJPEGDecoder(*this, observer); break; case eDecoderType_bmp: - mDecoder = new nsBMPDecoder(this, observer); + mDecoder = new nsBMPDecoder(*this, observer); break; case eDecoderType_ico: - mDecoder = new nsICODecoder(this, observer); + mDecoder = new nsICODecoder(*this, observer); break; case eDecoderType_icon: - mDecoder = new nsIconDecoder(this, observer); + mDecoder = new nsIconDecoder(*this, observer); break; default: NS_ABORT_IF_FALSE(0, "Shouldn't get here!"); @@ -2291,16 +2281,13 @@ RasterImage::WriteToDecoder(const char *aBuffer, PRUint32 aCount) curframe->UnlockImageData(); } - if (!mDecoder) - return NS_ERROR_FAILURE; - - CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError()); - - // Keep track of the total number of bytes written over the lifetime of the - // decoder - mBytesDecoded += aCount; - - return NS_OK; + nsresult status = mDecoder->GetDecoderError(); + if (NS_SUCCEEDED(status)) { + // Keep track of the total number of bytes written over the lifetime of the + // decoder + mBytesDecoded += aCount; + } + return status; } // This function is called in situations where it's clear that we want the @@ -2356,8 +2343,6 @@ RasterImage::RequestDecode() // a little slower). if (mInDecoder) { nsRefPtr requestor = new imgDecodeRequestor(this); - if (!requestor) - return NS_ERROR_OUT_OF_MEMORY; return NS_DispatchToCurrentThread(requestor); } diff --git a/image/src/imgFrame.cpp b/image/src/imgFrame.cpp index 3aee4733349d..b0ebac2419e9 100644 --- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -474,8 +474,6 @@ void imgFrame::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, nsresult imgFrame::Extract(const nsIntRect& aRegion, imgFrame** aResult) { nsAutoPtr subImage(new imgFrame()); - if (!subImage) - return NS_ERROR_OUT_OF_MEMORY; // The scaling problems described in bug 468496 are especially // likely to be visible for the sub-image, as at present the only diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index 4af67a312edd..529eb53d5b25 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -735,7 +735,6 @@ nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup proxyRequest = static_cast(aProxyRequest); } else { proxyRequest = new imgRequestProxy(); - if (!proxyRequest) return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(proxyRequest); @@ -893,8 +892,6 @@ nsresult imgLoader::InitCache() return NS_ERROR_FAILURE; gCacheObserver = new imgCacheObserver(); - if (!gCacheObserver) - return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(gCacheObserver); os->AddObserver(gCacheObserver, "memory-pressure", false); @@ -902,8 +899,6 @@ nsresult imgLoader::InitCache() os->AddObserver(gCacheObserver, "chrome-flush-caches", false); gCacheTracker = new imgCacheExpirationTracker(); - if (!gCacheTracker) - return NS_ERROR_OUT_OF_MEMORY; if (!sCache.Init()) return NS_ERROR_OUT_OF_MEMORY; diff --git a/image/src/imgTools.cpp b/image/src/imgTools.cpp index bfef4490528e..bcdc0937b6ce 100644 --- a/image/src/imgTools.cpp +++ b/image/src/imgTools.cpp @@ -197,9 +197,6 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer, // Create a temporary image surface dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight), gfxASurface::ImageFormatARGB32); - if (!dest) - return NS_ERROR_OUT_OF_MEMORY; - gfxContext ctx(dest); // Set scaling diff --git a/js/src/Makefile.in b/js/src/Makefile.in index ca60f5fa4f21..0e8c213ae9b2 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -182,7 +182,7 @@ CPPSRCS = \ # doing! INSTALLED_HEADERS = \ js-config.h \ - jsautocfg.h \ + jscpucfg.h \ $(CURDIR)/jsautokw.h \ js.msg \ jsalloc.h \ @@ -542,10 +542,6 @@ else CPPSRCS += pm_stub.cpp endif -ifeq ($(OS_ARCH),WINNT) -INSTALLED_HEADERS += jscpucfg.h -endif - EXPORTS = $(INSTALLED_HEADERS) DASH_R = -r @@ -760,12 +756,6 @@ DEFINES += -DIMPL_MFBT INCLUDES += -I$(srcdir) -GARBAGE += jscpucfg.o jsautocfg.h jsautocfg.tmp jscpucfg - -ifneq (,$(CROSS_COMPILE)$(filter-out WINNT,$(OS_ARCH))) -TARGETS += jscpucfg$(HOST_BIN_SUFFIX) -endif - ifdef JS_THREADSAFE DEFINES += -DJS_THREADSAFE endif @@ -820,9 +810,6 @@ endif ifeq ($(OS_ARCH),Linux) EXTRA_LIBS += -ldl endif -ifeq ($(OS_ARCH),OSF1) -EXTRA_LIBS += -lc_r -endif # Silence warnings on AIX/HP-UX from non-GNU compilers ifndef GNU_CC ifeq ($(OS_ARCH),AIX) @@ -883,45 +870,6 @@ jsdtoa.o: jsdtoa.cpp Makefile.in $(CXX) -o $@ -c $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(COMPILE_CFLAGS)) $< endif -export:: jsautocfg.h - -ifeq (,$(CROSS_COMPILE)$(GNU_CC)$(filter-out WINNT,$(OS_ARCH))) -jsautocfg.h: - $(TOUCH) $@ -else -jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX) - @$(RM) $@ jsautocfg.tmp - ./jscpucfg > jsautocfg.tmp - mv jsautocfg.tmp $@ -endif - -# jscpucfg is a strange target -# Needs to be built with the host compiler but needs to include -# the mdcpucfg for the target so it needs the appropriate target defines -ifdef HOST_NSPR_MDCPUCFG -HOST_CXX := $(HOST_CXX) -DMDCPUCFG=$(TARGET_NSPR_MDCPUCFG) -HOST_CXXFLAGS := $(patsubst -DXP_%,,$(HOST_CXXFLAGS)) -endif - -ifdef CROSS_COMPILE -# jscpucfg needs to know when it's supposed to produce a config for the target -JSCPUCFG_DEFINES = $(ACDEFINES) -endif - -ifeq ($(OS_ARCH),QNX) -ifneq ($(OS_TARGET),NTO) -# QNX's compiler apparently can't build a binary directly from a source file. -jscpucfg.o: jscpucfg.cpp Makefile.in - $(HOST_CXX) $(HOST_CXXFLAGS) -c $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) -o $@ $< - -jscpucfg: jscpucfg.o - $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) -o $@ $< -endif -else -jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in - $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $< -endif - # Compute the linker flags that programs linking against SpiderMonkey should # pass to get SpiderMonkey and its dependencies, beyond just the -L and -l # for the SpiderMonkey library itself. diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h index 2ab019c5da3b..db97652d972d 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.h +++ b/js/src/assembler/assembler/MacroAssemblerARM.h @@ -43,8 +43,7 @@ namespace JSC { class MacroAssemblerARM : public AbstractMacroAssembler { static const int DoubleConditionMask = 0x0f; - static const int DoubleConditionBitSpecial = 0x10; - COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); + static const int DoubleConditionBitSpecial = 0x8; public: enum Condition { Equal = ARMAssembler::EQ, diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h index 97b2e4b1f7fa..87eb8c948a8f 100644 --- a/js/src/assembler/assembler/MacroAssemblerSparc.h +++ b/js/src/assembler/assembler/MacroAssemblerSparc.h @@ -42,7 +42,7 @@ #ifndef MacroAssemblerSparc_h #define MacroAssemblerSparc_h -#include +#include #if ENABLE_ASSEMBLER && WTF_CPU_SPARC diff --git a/js/src/assembler/assembler/SparcAssembler.h b/js/src/assembler/assembler/SparcAssembler.h index 4457c62f7238..b508898bc1d3 100644 --- a/js/src/assembler/assembler/SparcAssembler.h +++ b/js/src/assembler/assembler/SparcAssembler.h @@ -42,7 +42,7 @@ #ifndef SparcAssembler_h #define SparcAssembler_h -#include +#include // Some debug code uses s(n)printf for instruction logging. #include @@ -50,7 +50,7 @@ #if ENABLE_ASSEMBLER && WTF_CPU_SPARC #include "AssemblerBufferWithConstantPool.h" -#include +#include #include "methodjit/Logging.h" #define IPFX " %s" diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index 4232641061d5..7c9114cb5868 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -150,7 +150,6 @@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ -MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@ PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index e9d9414aa49f..bdeb86d599ca 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -362,9 +362,6 @@ endif endif # !GNU_CC -ifdef ENABLE_CXX_EXCEPTIONS -CXXFLAGS += $(MOZ_EXCEPTIONS_FLAGS_ON) -DMOZ_CPP_EXCEPTIONS=1 -endif # ENABLE_CXX_EXCEPTIONS endif # WINNT ifeq ($(SOLARIS_SUNPRO_CXX),1) diff --git a/js/src/configure.in b/js/src/configure.in index 0bf21eabccf0..11f5d6b6d939 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -752,8 +752,6 @@ case "$target" in _MOZ_RTTI_FLAGS_ON='-GR' _MOZ_RTTI_FLAGS_OFF='-GR-' - _MOZ_EXCEPTIONS_FLAGS_ON='-EHsc' - _MOZ_EXCEPTIONS_FLAGS_OFF='' dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool', dnl not something else like "magnetic tape manipulation utility". @@ -1491,8 +1489,6 @@ if test "$GNU_CC"; then ASFLAGS="$ASFLAGS -fPIC" _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti - _MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions' - _MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions' # Turn on GNU specific features # -Wall - turn on all warnings @@ -2336,9 +2332,7 @@ ia64*-hpux*) LIBS="-lCrun -lCstd -lc $LIBS" AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" - CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" - _MOZ_EXCEPTIONS_FLAGS_ON='-features=except' - _MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except' + CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions,no%except -norunpath -D__FUNCTION__=__func__ -template=no%extdef" LDFLAGS="-xildoff $LDFLAGS" if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then _SAVE_LDFLAGS=$LDFLAGS @@ -2724,6 +2718,16 @@ fi MOZ_ALIGN_OF_TYPE(JS_ALIGN_OF_POINTER, void*, 2 4 8 16) MOZ_SIZE_OF_TYPE(JS_BYTES_PER_DOUBLE, double, 6 8 10 12 14) +AC_CHECK_HEADERS(endian.h) +if test "$ac_cv_header_endian_h" = yes; then + AC_DEFINE(JS_HAVE_ENDIAN_H) +fi + +AC_CHECK_HEADERS(sys/isa_defs.h) +if test "$ac_cv_header_sys_isa_defs_h" = yes; then + AC_DEFINE(JS_HAVE_SYS_ISA_DEFS_H) +fi + dnl Check for int16_t, int32_t, int64_t, int64, uint, uint_t, and uint16_t. dnl ======================================================== AC_MSG_CHECKING(for int16_t) @@ -4856,24 +4860,6 @@ fi AC_SUBST(_MOZ_RTTI_FLAGS_ON) -dnl ======================================================== -dnl C++ exceptions (g++/VC/Sun only - for now) -dnl Should be smarter and check that the compiler does indeed have exceptions -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(cpp-exceptions, -[ --enable-cpp-exceptions Enable C++ exceptions ], -[ _MOZ_CPP_EXCEPTIONS=1 ], -[ _MOZ_CPP_EXCEPTIONS= ]) - -if test "$_MOZ_CPP_EXCEPTIONS"; then - _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON - AC_DEFINE(MOZ_CPP_EXCEPTIONS) -else - _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF -fi - -AC_SUBST(_MOZ_EXCEPTIONS_FLAGS_ON) - AC_DEFINE(CPP_THROW_NEW, [throw()]) AC_LANG_C @@ -5138,7 +5124,6 @@ CFLAGS=`echo \ CXXFLAGS=`echo \ $_MOZ_RTTI_FLAGS \ - $_MOZ_EXCEPTIONS_FLAGS \ $_WARNINGS_CXXFLAGS \ $CXXFLAGS` diff --git a/js/src/editline/editline.c b/js/src/editline/editline.c index cc3a71881db0..92af9f918651 100644 --- a/js/src/editline/editline.c +++ b/js/src/editline/editline.c @@ -1002,6 +1002,7 @@ void rl_reset_terminal(p) char *p; { + (void)p; } void diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index c8750b4586e6..864c67c129cc 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -48,30 +48,31 @@ #include "jsinferinlines.h" -namespace js { +using namespace js; +using namespace js::frontend; /* * Compile a top-level script. */ -Compiler::Compiler(JSContext *cx, JSPrincipals *prin, StackFrame *cfp) +BytecodeCompiler::BytecodeCompiler(JSContext *cx, JSPrincipals *prin, StackFrame *cfp) : parser(cx, prin, cfp), globalScope(NULL) {} JSScript * -Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame, - JSPrincipals *principals, uint32 tcflags, - const jschar *chars, size_t length, - const char *filename, uintN lineno, JSVersion version, - JSString *source /* = NULL */, - uintN staticLevel /* = 0 */) +BytecodeCompiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame, + JSPrincipals *principals, uint32 tcflags, + const jschar *chars, size_t length, + const char *filename, uintN lineno, JSVersion version, + JSString *source /* = NULL */, + uintN staticLevel /* = 0 */) { TokenKind tt; - JSParseNode *pn; + ParseNode *pn; JSScript *script; bool inDirectivePrologue; JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT | - TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_OBJECT))); + TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_GLOBAL))); /* * The scripted callerFrame can only be given for compile-and-go scripts @@ -80,15 +81,15 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO); JS_ASSERT_IF(staticLevel != 0, callerFrame); - Compiler compiler(cx, principals, callerFrame); + BytecodeCompiler compiler(cx, principals, callerFrame); if (!compiler.init(chars, length, filename, lineno, version)) return NULL; Parser &parser = compiler.parser; TokenStream &tokenStream = parser.tokenStream; - JSCodeGenerator cg(&parser, tokenStream.getLineno()); - if (!cg.init(cx, JSTreeContext::USED_AS_TREE_CONTEXT)) + CodeGenerator cg(&parser, tokenStream.getLineno()); + if (!cg.init(cx, TreeContext::USED_AS_TREE_CONTEXT)) return NULL; Probes::compileScriptBegin(cx, filename, lineno); @@ -143,7 +144,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF * function captured in case it refers to an upvar, and someone * wishes to decompile it while it's running. */ - JSObjectBox *funbox = parser.newObjectBox(callerFrame->fun()); + ObjectBox *funbox = parser.newObjectBox(callerFrame->fun()); if (!funbox) goto out; funbox->emitLink = cg.objectList.lastbox; @@ -189,21 +190,21 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue)) goto out; - if (!js_FoldConstants(cx, pn, &cg)) + if (!FoldConstants(cx, pn, &cg)) goto out; if (!parser.analyzeFunctions(&cg)) goto out; cg.functionList = NULL; - if (!js_EmitTree(cx, &cg, pn)) + if (!EmitTree(cx, &cg, pn)) goto out; #if JS_HAS_XML_SUPPORT if (!pn->isKind(TOK_SEMI) || !pn->pn_kid || !TreeTypeIsXML(pn->pn_kid->getKind())) onlyXML = false; #endif - RecycleTree(pn, &cg); + cg.freeTree(pn); } #if JS_HAS_XML_SUPPORT @@ -257,7 +258,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF * Nowadays the threaded interpreter needs a stop instruction, so we * do have to emit that here. */ - if (js_Emit1(cx, &cg, JSOP_STOP) < 0) + if (Emit1(cx, &cg, JSOP_STOP) < 0) goto out; JS_ASSERT(cg.version() == version); @@ -282,7 +283,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF } bool -Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script) +BytecodeCompiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script) { JSObject *globalObj = globalScope.globalObj; @@ -325,7 +326,7 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip def.knownSlot = shape->slot(); } - js::Vector worklist(cx); + Vector worklist(cx); if (!worklist.append(script)) return false; @@ -388,11 +389,11 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip * handler attribute in an HTML tag. */ bool -Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals, - Bindings *bindings, const jschar *chars, size_t length, - const char *filename, uintN lineno, JSVersion version) +BytecodeCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals, + Bindings *bindings, const jschar *chars, size_t length, + const char *filename, uintN lineno, JSVersion version) { - Compiler compiler(cx, principals); + BytecodeCompiler compiler(cx, principals); if (!compiler.init(chars, length, filename, lineno, version)) return false; @@ -400,8 +401,8 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin Parser &parser = compiler.parser; TokenStream &tokenStream = parser.tokenStream; - JSCodeGenerator funcg(&parser, tokenStream.getLineno()); - if (!funcg.init(cx, JSTreeContext::USED_AS_TREE_CONTEXT)) + CodeGenerator funcg(&parser, tokenStream.getLineno()); + if (!funcg.init(cx, TreeContext::USED_AS_TREE_CONTEXT)) return false; funcg.flags |= TCF_IN_FUNCTION; @@ -413,7 +414,7 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin /* FIXME: make Function format the source for a function definition. */ tokenStream.mungeCurrentToken(TOK_NAME); - JSParseNode *fn = FunctionNode::create(&funcg); + ParseNode *fn = FunctionNode::create(&funcg); if (fn) { fn->pn_body = NULL; fn->pn_cookie.makeFree(); @@ -422,7 +423,7 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin if (nargs) { /* * NB: do not use AutoLocalNameArray because it will release space - * allocated from cx->tempPool by DefineArg. + * allocated from cx->tempLifoAlloc by DefineArg. */ Vector names(cx); if (!funcg.bindings.getLocalNameArray(cx, &names)) { @@ -439,21 +440,22 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin } /* - * Farble the body so that it looks like a block statement to js_EmitTree, - * which is called from js_EmitFunctionBody (see jsemit.cpp). After we're - * done parsing, we must fold constants, analyze any nested functions, and - * generate code for this function, including a stop opcode at the end. + * Farble the body so that it looks like a block statement to EmitTree, + * which is called from EmitFunctionBody (see BytecodeGenerator.cpp). + * After we're done parsing, we must fold constants, analyze any nested + * functions, and generate code for this function, including a stop opcode + * at the end. */ tokenStream.mungeCurrentToken(TOK_LC); - JSParseNode *pn = fn ? parser.functionBody() : NULL; + ParseNode *pn = fn ? parser.functionBody() : NULL; if (pn) { if (!CheckStrictParameters(cx, &funcg)) { pn = NULL; } else if (!tokenStream.matchToken(TOK_EOF)) { parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; - } else if (!js_FoldConstants(cx, pn, &funcg)) { - /* js_FoldConstants reported the error already. */ + } else if (!FoldConstants(cx, pn, &funcg)) { + /* FoldConstants reported the error already. */ pn = NULL; } else if (!parser.analyzeFunctions(&funcg)) { pn = NULL; @@ -465,12 +467,10 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin pn = fn->pn_body; } - if (!js_EmitFunctionScript(cx, &funcg, pn)) + if (!EmitFunctionScript(cx, &funcg, pn)) pn = NULL; } } return pn != NULL; } - -} /* namespace js */ diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index fcb198acf910..ca7c51836de6 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -45,12 +45,12 @@ namespace js { -struct Compiler +struct BytecodeCompiler { Parser parser; GlobalScope *globalScope; - Compiler(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL); + BytecodeCompiler(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL); JSContext *context() { return parser.context; @@ -63,7 +63,7 @@ struct Compiler static bool compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals, - js::Bindings *bindings, const jschar *chars, size_t length, + Bindings *bindings, const jschar *chars, size_t length, const char *filename, uintN lineno, JSVersion version); static JSScript * diff --git a/js/src/frontend/BytecodeGenerator.cpp b/js/src/frontend/BytecodeGenerator.cpp index 55bb4a2ef8fd..3ea4d891fffc 100644 --- a/js/src/frontend/BytecodeGenerator.cpp +++ b/js/src/frontend/BytecodeGenerator.cpp @@ -87,26 +87,33 @@ using namespace js; using namespace js::gc; +using namespace js::frontend; + +#ifdef JS_TRACER +extern uint8 js_opcode2extra[]; +#endif static JSBool -NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, - uintN stackDepth, size_t start, size_t end); +NewTryNote(JSContext *cx, CodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, + size_t start, size_t end); static bool -EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg, - JSOp *psuffix = NULL); +EmitIndexOp(JSContext *cx, JSOp op, uintN index, CodeGenerator *cg, JSOp *psuffix = NULL); static JSBool -EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, JSObjectBox *box); +EmitLeaveBlock(JSContext *cx, CodeGenerator *cg, JSOp op, ObjectBox *box); + +static JSBool +SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset); void -JSTreeContext::trace(JSTracer *trc) +TreeContext::trace(JSTracer *trc) { bindings.trace(trc); } -JSCodeGenerator::JSCodeGenerator(Parser *parser, uintN lineno) - : JSTreeContext(parser), +CodeGenerator::CodeGenerator(Parser *parser, uintN lineno) + : TreeContext(parser), atomIndices(parser->context), stackDepth(0), maxStackDepth(0), ntrynotes(0), lastTryNode(NULL), @@ -133,13 +140,13 @@ JSCodeGenerator::JSCodeGenerator(Parser *parser, uintN lineno) } bool -JSCodeGenerator::init(JSContext *cx, JSTreeContext::InitBehavior ib) +CodeGenerator::init(JSContext *cx, TreeContext::InitBehavior ib) { roLexdeps.init(); - return JSTreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx); + return TreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx); } -JSCodeGenerator::~JSCodeGenerator() +CodeGenerator::~CodeGenerator() { JSContext *cx = parser->context; @@ -154,7 +161,7 @@ JSCodeGenerator::~JSCodeGenerator() } static ptrdiff_t -EmitCheck(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t delta) +EmitCheck(JSContext *cx, CodeGenerator *cg, ptrdiff_t delta) { jsbytecode *base = CG_BASE(cg); jsbytecode *newbase; @@ -191,7 +198,7 @@ EmitCheck(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t delta) } static void -UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) +UpdateDepth(JSContext *cx, CodeGenerator *cg, ptrdiff_t target) { jsbytecode *pc; JSOp op; @@ -203,7 +210,6 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) op = (JSOp) *pc; cs = &js_CodeSpec[op]; #ifdef JS_TRACER - extern uint8 js_opcode2extra[]; extra = js_opcode2extra[op]; #else extra = 0; @@ -251,7 +257,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) } static inline void -UpdateDecomposeLength(JSCodeGenerator *cg, uintN start) +UpdateDecomposeLength(CodeGenerator *cg, uintN start) { uintN end = CG_OFFSET(cg); JS_ASSERT(uintN(end - start) < 256); @@ -259,7 +265,7 @@ UpdateDecomposeLength(JSCodeGenerator *cg, uintN start) } ptrdiff_t -js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op) +frontend::Emit1(JSContext *cx, CodeGenerator *cg, JSOp op) { ptrdiff_t offset = EmitCheck(cx, cg, 1); @@ -271,7 +277,7 @@ js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op) } ptrdiff_t -js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1) +frontend::Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1) { ptrdiff_t offset = EmitCheck(cx, cg, 2); @@ -286,8 +292,8 @@ js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1) } ptrdiff_t -js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, - jsbytecode op2) +frontend::Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1, + jsbytecode op2) { ptrdiff_t offset = EmitCheck(cx, cg, 3); @@ -303,7 +309,7 @@ js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, } ptrdiff_t -js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, uint16 op2) +frontend::Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1, uint16 op2) { ptrdiff_t offset = EmitCheck(cx, cg, 5); @@ -321,7 +327,7 @@ js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, uint16 op2) } ptrdiff_t -js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra) +frontend::EmitN(JSContext *cx, CodeGenerator *cg, JSOp op, size_t extra) { ptrdiff_t length = 1 + (ptrdiff_t)extra; ptrdiff_t offset = EmitCheck(cx, cg, length); @@ -368,7 +374,7 @@ static const char *statementName[] = { JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT); static const char * -StatementName(JSCodeGenerator *cg) +StatementName(CodeGenerator *cg) { if (!cg->topStmt) return js_script_str; @@ -376,7 +382,7 @@ StatementName(JSCodeGenerator *cg) } static void -ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) +ReportStatementTooLarge(JSContext *cx, CodeGenerator *cg) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET, StatementName(cg)); @@ -405,19 +411,19 @@ ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) case by generating short jumps until we know a long jump is needed. After that point, we keep generating short jumps, but each jump's 16-bit immediate offset operand is actually an unsigned index into cg->spanDeps, an array of - JSSpanDep structs. Each struct tells the top offset in the script of the + js::SpanDep structs. Each struct tells the top offset in the script of the opcode, the "before" offset of the jump (which will be the same as top for simplex jumps, but which will index further into the bytecode array for a non-initial jump offset in a lookup or table switch), the after "offset" adjusted during span-dependent instruction selection (initially the same value as the "before" offset), and the jump target (more below). - Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must + Since we generate cg->spanDeps lazily, from within SetJumpOffset, we must ensure that all bytecode generated so far can be inspected to discover where the jump offset immediate operands lie within CG_CODE(cg). But the bonus is that we generate span-dependency records sorted by their offsets, so we can - binary-search when trying to find a JSSpanDep for a given bytecode offset, - or the nearest JSSpanDep at or above a given pc. + binary-search when trying to find a SpanDep for a given bytecode offset, or + the nearest SpanDep at or above a given pc. To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows 65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand. This @@ -436,8 +442,8 @@ ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) positive sign, even though they link "backward" (i.e., toward lower bytecode address). We don't want to waste space and search time in the AVL tree for such temporary backpatch deltas, so we use a single-bit wildcard scheme to - tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas - in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known + tag true JumpTarget pointers and encode untagged, signed (positive) deltas in + SpanDep::target pointers, depending on whether the SpanDep has a known target, or is still awaiting backpatching. Note that backpatch chains would present a problem for BuildSpanDepTable, @@ -449,15 +455,13 @@ ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) offset. */ static int -BalanceJumpTargets(JSJumpTarget **jtp) +BalanceJumpTargets(JumpTarget **jtp) { - JSJumpTarget *jt, *jt2, *root; - int dir, otherDir, heightChanged; - JSBool doubleRotate; - - jt = *jtp; + JumpTarget *jt = *jtp; JS_ASSERT(jt->balance != 0); + int dir; + JSBool doubleRotate; if (jt->balance < -1) { dir = JT_RIGHT; doubleRotate = (jt->kids[JT_LEFT]->balance > 0); @@ -468,9 +472,11 @@ BalanceJumpTargets(JSJumpTarget **jtp) return 0; } - otherDir = JT_OTHER_DIR(dir); + int otherDir = JT_OTHER_DIR(dir); + JumpTarget *root; + int heightChanged; if (doubleRotate) { - jt2 = jt->kids[otherDir]; + JumpTarget *jt2 = jt->kids[otherDir]; *jtp = root = jt2->kids[dir]; jt->kids[otherDir] = root->kids[dir]; @@ -495,28 +501,25 @@ BalanceJumpTargets(JSJumpTarget **jtp) return heightChanged; } -typedef struct AddJumpTargetArgs { +struct AddJumpTargetArgs { JSContext *cx; - JSCodeGenerator *cg; + CodeGenerator *cg; ptrdiff_t offset; - JSJumpTarget *node; -} AddJumpTargetArgs; + JumpTarget *node; +}; static int -AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp) +AddJumpTarget(AddJumpTargetArgs *args, JumpTarget **jtp) { - JSJumpTarget *jt; - int balanceDelta; - - jt = *jtp; + JumpTarget *jt = *jtp; if (!jt) { - JSCodeGenerator *cg = args->cg; + CodeGenerator *cg = args->cg; jt = cg->jtFreeList; if (jt) { cg->jtFreeList = jt->kids[JT_LEFT]; } else { - jt = args->cx->tempLifoAlloc().new_(); + jt = args->cx->tempLifoAlloc().new_(); if (!jt) { js_ReportOutOfMemory(args->cx); return 0; @@ -536,6 +539,7 @@ AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp) return 0; } + int balanceDelta; if (args->offset < jt->offset) balanceDelta = -AddJumpTarget(args, &jt->kids[JT_LEFT]); else @@ -550,7 +554,8 @@ AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp) } #ifdef DEBUG_brendan -static int AVLCheck(JSJumpTarget *jt) +static int +AVLCheck(JumpTarget *jt) { int lh, rh; @@ -564,8 +569,7 @@ static int AVLCheck(JSJumpTarget *jt) #endif static JSBool -SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd, - ptrdiff_t off) +SetSpanDepTarget(JSContext *cx, CodeGenerator *cg, SpanDep *sd, ptrdiff_t off) { AddJumpTargetArgs args; @@ -591,34 +595,31 @@ SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd, } #define SPANDEPS_MIN 256 -#define SPANDEPS_SIZE(n) ((n) * sizeof(JSSpanDep)) +#define SPANDEPS_SIZE(n) ((n) * sizeof(js::SpanDep)) #define SPANDEPS_SIZE_MIN SPANDEPS_SIZE(SPANDEPS_MIN) static JSBool -AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2, - ptrdiff_t off) +AddSpanDep(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2, ptrdiff_t off) { - uintN index; - JSSpanDep *sdbase, *sd; - size_t size; - - index = cg->numSpanDeps; + uintN index = cg->numSpanDeps; if (index + 1 == 0) { ReportStatementTooLarge(cx, cg); return JS_FALSE; } + SpanDep *sdbase; if ((index & (index - 1)) == 0 && - (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) { - size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2; - sdbase = (JSSpanDep *) cx->realloc_(sdbase, size + size); + (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) + { + size_t size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2; + sdbase = (SpanDep *) cx->realloc_(sdbase, size + size); if (!sdbase) return JS_FALSE; cg->spanDeps = sdbase; } cg->numSpanDeps = index + 1; - sd = cg->spanDeps + index; + SpanDep *sd = cg->spanDeps + index; sd->top = pc - CG_BASE(cg); sd->offset = sd->before = pc2 - CG_BASE(cg); @@ -648,7 +649,7 @@ AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2, } static jsbytecode * -AddSwitchSpanDeps(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc) +AddSwitchSpanDeps(JSContext *cx, CodeGenerator *cg, jsbytecode *pc) { JSOp op; jsbytecode *pc2; @@ -687,7 +688,7 @@ AddSwitchSpanDeps(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc) } static JSBool -BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg) +BuildSpanDepTable(JSContext *cx, CodeGenerator *cg) { jsbytecode *pc, *end; JSOp op; @@ -723,13 +724,13 @@ BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg) return JS_TRUE; } -static JSSpanDep * -GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc) +static SpanDep * +GetSpanDep(CodeGenerator *cg, jsbytecode *pc) { uintN index; ptrdiff_t offset; int lo, hi, mid; - JSSpanDep *sd; + SpanDep *sd; index = GET_SPANDEP_INDEX(pc); if (index != SPANDEP_INDEX_HUGE) @@ -754,10 +755,9 @@ GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc) } static JSBool -SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, - ptrdiff_t delta) +SetBackPatchDelta(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t delta) { - JSSpanDep *sd; + SpanDep *sd; JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN); if (!cg->spanDeps && delta < JUMP_OFFSET_MAX) { @@ -780,7 +780,7 @@ SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, } static void -UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta) +UpdateJumpTargets(JumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta) { if (jt->offset > pivot) { jt->offset += delta; @@ -791,20 +791,16 @@ UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta) UpdateJumpTargets(jt->kids[JT_RIGHT], pivot, delta); } -static JSSpanDep * -FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo, - JSSpanDep *guard) +static SpanDep * +FindNearestSpanDep(CodeGenerator *cg, ptrdiff_t offset, int lo, SpanDep *guard) { - int num, hi, mid; - JSSpanDep *sdbase, *sd; - - num = cg->numSpanDeps; + int num = cg->numSpanDeps; JS_ASSERT(num > 0); - hi = num - 1; - sdbase = cg->spanDeps; + int hi = num - 1; + SpanDep *sdbase = cg->spanDeps; while (lo <= hi) { - mid = (lo + hi) / 2; - sd = sdbase + mid; + int mid = (lo + hi) / 2; + SpanDep *sd = sdbase + mid; if (sd->before == offset) return sd; if (sd->before < offset) @@ -814,13 +810,13 @@ FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo, } if (lo == num) return guard; - sd = sdbase + lo; + SpanDep *sd = sdbase + lo; JS_ASSERT(sd->before >= offset && (lo == 0 || sd[-1].before < offset)); return sd; } static void -FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt) +FreeJumpTargets(CodeGenerator *cg, JumpTarget *jt) { if (jt->kids[JT_LEFT]) FreeJumpTargets(cg, jt->kids[JT_LEFT]); @@ -831,10 +827,10 @@ FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt) } static JSBool -OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) +OptimizeSpanDeps(JSContext *cx, CodeGenerator *cg) { jsbytecode *pc, *oldpc, *base, *limit, *next; - JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard; + SpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard; ptrdiff_t offset, growth, delta, top, pivot, span, length, target; JSBool done; JSOp op; @@ -842,7 +838,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) jssrcnote *sn, *snlimit; JSSrcNoteSpec *spec; uintN i, n, noteIndex; - JSTryNode *tryNode; + TryNode *tryNode; DebugOnly passes = 0; base = CG_BASE(cg); @@ -1092,7 +1088,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) delta = sd2->offset - (sd2->before + growth); if (delta > 0) { JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN); - sn = js_AddToSrcNoteDelta(cx, cg, sn, delta); + sn = AddToSrcNoteDelta(cx, cg, sn, delta); if (!sn) return JS_FALSE; snlimit = cg->main.notes + cg->main.noteCount; @@ -1134,7 +1130,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) span = target - (pivot + growth); span *= spec->isSpanDep; noteIndex = sn - cg->main.notes; - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, i, span)) return JS_FALSE; sn = cg->main.notes + noteIndex; snlimit = cg->main.notes + cg->main.noteCount; @@ -1230,7 +1226,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) } static ptrdiff_t -EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) +EmitJump(JSContext *cx, CodeGenerator *cg, JSOp op, ptrdiff_t off) { JSBool extend; ptrdiff_t jmp; @@ -1240,7 +1236,7 @@ EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) if (extend && !cg->spanDeps && !BuildSpanDepTable(cx, cg)) return -1; - jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off)); + jmp = Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off)); if (jmp >= 0 && (extend || cg->spanDeps)) { pc = CG_CODE(cg, jmp); if (!AddSpanDep(cx, cg, pc, pc, off)) @@ -1250,21 +1246,17 @@ EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) } static ptrdiff_t -GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc) +GetJumpOffset(CodeGenerator *cg, jsbytecode *pc) { - JSSpanDep *sd; - JSJumpTarget *jt; - ptrdiff_t top; - if (!cg->spanDeps) return GET_JUMP_OFFSET(pc); - sd = GetSpanDep(cg, pc); - jt = sd->target; + SpanDep *sd = GetSpanDep(cg, pc); + JumpTarget *jt = sd->target; if (!JT_HAS_TAG(jt)) return JT_TO_BPDELTA(jt); - top = sd->top; + ptrdiff_t top = sd->top; while (--sd >= cg->spanDeps && sd->top == top) continue; sd++; @@ -1272,8 +1264,7 @@ GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc) } JSBool -js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, - ptrdiff_t off) +frontend::SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off) { if (!cg->spanDeps) { if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) { @@ -1289,9 +1280,9 @@ js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, } bool -JSTreeContext::inStatement(JSStmtType type) +TreeContext::inStatement(StmtType type) { - for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { + for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { if (stmt->type == type) return true; } @@ -1299,7 +1290,7 @@ JSTreeContext::inStatement(JSStmtType type) } bool -JSTreeContext::ensureSharpSlots() +TreeContext::ensureSharpSlots() { #if JS_HAS_SHARP_VARS JS_STATIC_ASSERT(SHARP_NSLOTS == 2); @@ -1324,9 +1315,9 @@ JSTreeContext::ensureSharpSlots() return false; } else { /* - * Compiler::compileScript will rebase immediate operands indexing - * the sharp slots to come at the end of the global script's |nfixed| - * slots storage, after gvars and regexps. + * BytecodeCompiler::compileScript will rebase immediate operands + * indexing the sharp slots to come at the end of the global script's + * |nfixed| slots storage, after gvars and regexps. */ sharpSlotBase = 0; } @@ -1336,9 +1327,9 @@ JSTreeContext::ensureSharpSlots() } bool -JSTreeContext::skipSpansGenerator(unsigned skip) +TreeContext::skipSpansGenerator(unsigned skip) { - JSTreeContext *tc = this; + TreeContext *tc = this; for (unsigned i = 0; i < skip; ++i, tc = tc->parent) { if (!tc) return false; @@ -1348,10 +1339,8 @@ JSTreeContext::skipSpansGenerator(unsigned skip) return false; } -namespace js { - bool -SetStaticLevel(JSTreeContext *tc, uintN staticLevel) +frontend::SetStaticLevel(TreeContext *tc, uintN staticLevel) { /* * This is a lot simpler than error-checking every UpvarCookie::set, and @@ -1367,7 +1356,7 @@ SetStaticLevel(JSTreeContext *tc, uintN staticLevel) } bool -GenerateBlockId(JSTreeContext *tc, uint32& blockid) +frontend::GenerateBlockId(TreeContext *tc, uint32& blockid) { if (tc->blockidGen == JS_BIT(20)) { JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL, @@ -1378,11 +1367,8 @@ GenerateBlockId(JSTreeContext *tc, uint32& blockid) return true; } -} /* namespace js */ - void -js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, - ptrdiff_t top) +frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top) { stmt->type = type; stmt->flags = 0; @@ -1401,10 +1387,9 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, } void -js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox, - ptrdiff_t top) +frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top) { - js_PushStatement(tc, stmt, STMT_BLOCK, top); + PushStatement(tc, stmt, STMT_BLOCK, top); stmt->flags |= SIF_SCOPE; blockBox->parent = tc->blockChainBox; if (tc->blockChain()) @@ -1420,7 +1405,7 @@ js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox, * so that we can walk back up the chain fixing up the op and jump offset. */ static ptrdiff_t -EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) +EmitBackPatchOp(JSContext *cx, CodeGenerator *cg, JSOp op, ptrdiff_t *lastp) { ptrdiff_t offset, delta; @@ -1431,7 +1416,7 @@ EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) return EmitJump(cx, cg, op, delta); } -/* A macro for inlining at the top of js_EmitTree (whence it came). */ +/* A macro for inlining at the top of EmitTree (whence it came). */ #define UPDATE_LINE_NUMBER_NOTES(cx, cg, line) \ JS_BEGIN_MACRO \ uintN line_ = (line); \ @@ -1450,11 +1435,11 @@ EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) */ \ CG_CURRENT_LINE(cg) = line_; \ if (delta_ >= (uintN)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \ - if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0)\ + if (NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0) \ return JS_FALSE; \ } else { \ do { \ - if (js_NewSrcNote(cx, cg, SRC_NEWLINE) < 0) \ + if (NewSrcNote(cx, cg, SRC_NEWLINE) < 0) \ return JS_FALSE; \ } while (--delta_ != 0); \ } \ @@ -1463,14 +1448,14 @@ EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) /* A function, so that we avoid macro-bloating all the other callsites. */ static JSBool -UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line) +UpdateLineNumberNotes(JSContext *cx, CodeGenerator *cg, uintN line) { UPDATE_LINE_NUMBER_NOTES(cx, cg, line); return JS_TRUE; } static ptrdiff_t -EmitTraceOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *nextpn) +EmitTraceOp(JSContext *cx, CodeGenerator *cg, ParseNode *nextpn) { if (nextpn) { /* @@ -1487,7 +1472,7 @@ EmitTraceOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *nextpn) uint32 index = cg->traceIndex; if (index < UINT16_MAX) cg->traceIndex++; - return js_Emit3(cx, cg, JSOP_TRACE, UINT16_HI(index), UINT16_LO(index)); + return Emit3(cx, cg, JSOP_TRACE, UINT16_HI(index), UINT16_LO(index)); } /* @@ -1495,7 +1480,7 @@ EmitTraceOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *nextpn) * a type set to store its result. */ static inline void -CheckTypeSet(JSContext *cx, JSCodeGenerator *cg, JSOp op) +CheckTypeSet(JSContext *cx, CodeGenerator *cg, JSOp op) { if (js_CodeSpec[op].format & JOF_TYPESET) { if (cg->typesetCount < UINT16_MAX) @@ -1511,14 +1496,14 @@ CheckTypeSet(JSContext *cx, JSCodeGenerator *cg, JSOp op) */ #define EMIT_UINT16_IMM_OP(op, i) \ JS_BEGIN_MACRO \ - if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0) \ + if (Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0) \ return JS_FALSE; \ CheckTypeSet(cx, cg, op); \ JS_END_MACRO #define EMIT_UINT16PAIR_IMM_OP(op, i, j) \ JS_BEGIN_MACRO \ - ptrdiff_t off_ = js_EmitN(cx, cg, op, 2 * UINT16_LEN); \ + ptrdiff_t off_ = EmitN(cx, cg, op, 2 * UINT16_LEN); \ if (off_ < 0) \ return JS_FALSE; \ jsbytecode *pc_ = CG_CODE(cg, off_); \ @@ -1535,10 +1520,10 @@ CheckTypeSet(JSContext *cx, JSCodeGenerator *cg, JSOp op) JS_END_MACRO static JSBool -FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops) +FlushPops(JSContext *cx, CodeGenerator *cg, intN *npops) { JS_ASSERT(*npops != 0); - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; EMIT_UINT16_IMM_OP(JSOP_POPN, *npops); *npops = 0; @@ -1549,27 +1534,24 @@ FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops) * Emit additional bytecode(s) for non-local jumps. */ static JSBool -EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) +EmitNonLocalJumpFixup(JSContext *cx, CodeGenerator *cg, StmtInfo *toStmt) { - intN depth, npops; - JSStmtInfo *stmt; - /* * The non-local jump fixup we emit will unbalance cg->stackDepth, because * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the * end of a with statement, so we save cg->stackDepth here and restore it * just before a successful return. */ - depth = cg->stackDepth; - npops = 0; + intN depth = cg->stackDepth; + intN npops = 0; #define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE - for (stmt = cg->topStmt; stmt != toStmt; stmt = stmt->down) { + for (StmtInfo *stmt = cg->topStmt; stmt != toStmt; stmt = stmt->down) { switch (stmt->type) { case STMT_FINALLY: FLUSH_POPS(); - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0) return JS_FALSE; @@ -1578,9 +1560,9 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) case STMT_WITH: /* There's a With object on the stack that we need to pop. */ FLUSH_POPS(); - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + if (Emit1(cx, cg, JSOP_LEAVEWITH) < 0) return JS_FALSE; break; @@ -1589,9 +1571,9 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) * The iterator and the object being iterated need to be popped. */ FLUSH_POPS(); - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_ENDITER) < 0) + if (Emit1(cx, cg, JSOP_ENDITER) < 0) return JS_FALSE; break; @@ -1609,7 +1591,7 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) if (stmt->flags & SIF_SCOPE) { /* There is a Block object with locals on the stack to pop. */ FLUSH_POPS(); - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, stmt->blockBox)) return JS_FALSE; @@ -1624,15 +1606,15 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) } static JSBool -EmitKnownBlockChain(JSContext *cx, JSCodeGenerator *cg, JSObjectBox *box) +EmitKnownBlockChain(JSContext *cx, CodeGenerator *cg, ObjectBox *box) { if (box) return EmitIndexOp(cx, JSOP_BLOCKCHAIN, box->index, cg); - return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0; + return Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0; } static JSBool -EmitBlockChain(JSContext *cx, JSCodeGenerator *cg) +EmitBlockChain(JSContext *cx, CodeGenerator *cg) { return EmitKnownBlockChain(cx, cg, cg->blockChainBox); } @@ -1640,8 +1622,8 @@ EmitBlockChain(JSContext *cx, JSCodeGenerator *cg) static const jsatomid INVALID_ATOMID = -1; static ptrdiff_t -EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, - ptrdiff_t *lastp, jsatomid labelIndex = INVALID_ATOMID, JSSrcNoteType noteType = SRC_NULL) +EmitGoto(JSContext *cx, CodeGenerator *cg, StmtInfo *toStmt, ptrdiff_t *lastp, + jsatomid labelIndex = INVALID_ATOMID, SrcNoteType noteType = SRC_NULL) { intN index; @@ -1649,9 +1631,9 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, return -1; if (labelIndex != INVALID_ATOMID) - index = js_NewSrcNote2(cx, cg, noteType, ptrdiff_t(labelIndex)); + index = NewSrcNote2(cx, cg, noteType, ptrdiff_t(labelIndex)); else if (noteType != SRC_NULL) - index = js_NewSrcNote(cx, cg, noteType); + index = NewSrcNote(cx, cg, noteType); else index = 0; if (index < 0) @@ -1668,8 +1650,7 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, } static JSBool -BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last, - jsbytecode *target, jsbytecode op) +BackPatch(JSContext *cx, CodeGenerator *cg, ptrdiff_t last, jsbytecode *target, jsbytecode op) { jsbytecode *pc, *stop; ptrdiff_t delta, span; @@ -1693,11 +1674,9 @@ BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last, } void -js_PopStatement(JSTreeContext *tc) +frontend::PopStatementTC(TreeContext *tc) { - JSStmtInfo *stmt; - - stmt = tc->topStmt; + StmtInfo *stmt = tc->topStmt; tc->topStmt = stmt->down; if (STMT_LINKS_SCOPE(stmt)) { tc->topScopeStmt = stmt->downScope; @@ -1708,24 +1687,21 @@ js_PopStatement(JSTreeContext *tc) } JSBool -js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg) +frontend::PopStatementCG(JSContext *cx, CodeGenerator *cg) { - JSStmtInfo *stmt; - - stmt = cg->topStmt; + StmtInfo *stmt = cg->topStmt; if (!STMT_IS_TRYING(stmt) && (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) || !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update), JSOP_GOTO))) { return JS_FALSE; } - js_PopStatement(cg); + PopStatementTC(cg); return JS_TRUE; } JSBool -js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - JSParseNode *pn) +frontend::DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseNode *pn) { /* XXX just do numbers for now */ if (pn->isKind(TOK_NUMBER)) { @@ -1735,8 +1711,8 @@ js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, return JS_TRUE; } -JSStmtInfo * -js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt) +StmtInfo * +frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt) { if (!stmt) stmt = tc->topScopeStmt; @@ -1773,12 +1749,8 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt * name defining a constant. */ static JSBool -LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - Value *constp) +LookupCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, Value *constp) { - JSStmtInfo *stmt; - JSObject *obj; - /* * Chase down the cg stack, but only until we reach the outermost cg. * This enables propagating consts from top-level into switch cases in a @@ -1788,11 +1760,11 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, do { if (cg->inFunction() || cg->compileAndGo()) { /* XXX this will need revising if 'const' becomes block-scoped. */ - stmt = js_LexicalLookup(cg, atom, NULL); + StmtInfo *stmt = LexicalLookup(cg, atom, NULL); if (stmt) return JS_TRUE; - if (JSCodeGenerator::ConstMap::Ptr p = cg->constMap.lookup(atom)) { + if (CodeGenerator::ConstMap::Ptr p = cg->constMap.lookup(atom)) { JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT)); *constp = p->value; return JS_TRUE; @@ -1810,7 +1782,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, break; } else { JS_ASSERT(cg->compileAndGo()); - obj = cg->scopeChain(); + JSObject *obj = cg->scopeChain(); const Shape *shape = obj->nativeLookup(cx, ATOM_TO_JSID(atom)); if (shape) { @@ -1847,7 +1819,7 @@ FitsWithoutBigIndex(uintN index) * after the main bytecode sequence. */ static JSOp -EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) +EmitBigIndexPrefix(JSContext *cx, CodeGenerator *cg, uintN index) { uintN indexBase; @@ -1863,7 +1835,7 @@ EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) return JSOP_NOP; indexBase = index >> 16; if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) { - if (js_Emit1(cx, cg, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0) + if (Emit1(cx, cg, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0) return JSOP_FALSE; return JSOP_RESETBASE0; } @@ -1874,7 +1846,7 @@ EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) return JSOP_FALSE; } - if (js_Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0) + if (Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0) return JSOP_FALSE; return JSOP_RESETBASE; } @@ -1890,7 +1862,7 @@ EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) * register setting, but this could be optimized further. */ static bool -EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg, JSOp *psuffix) +EmitIndexOp(JSContext *cx, JSOp op, uintN index, CodeGenerator *cg, JSOp *psuffix) { JSOp bigSuffix; @@ -1910,7 +1882,7 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg, JSOp *psuf return true; } - return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; + return bigSuffix == JSOP_NOP || Emit1(cx, cg, bigSuffix) >= 0; } /* @@ -1924,8 +1896,7 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg, JSOp *psuf JS_END_MACRO static bool -EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, - JSOp *psuffix = NULL) +EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg, JSOp *psuffix = NULL) { JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); @@ -1943,8 +1914,7 @@ EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, } static JSBool -EmitObjectOp(JSContext *cx, JSObjectBox *objbox, JSOp op, - JSCodeGenerator *cg) +EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, CodeGenerator *cg) { JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT); return EmitIndexOp(cx, op, cg->objectList.index(objbox), cg); @@ -1961,8 +1931,7 @@ JS_STATIC_ASSERT(ARGNO_LEN == 2); JS_STATIC_ASSERT(SLOTNO_LEN == 2); static JSBool -EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, - JSCodeGenerator *cg) +EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, CodeGenerator *cg) { JSOp bigSuffix; ptrdiff_t off; @@ -1975,18 +1944,18 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, return JS_FALSE; /* Emit [op, slot, index]. */ - off = js_EmitN(cx, cg, op, 2 + INDEX_LEN); + off = EmitN(cx, cg, op, 2 + INDEX_LEN); if (off < 0) return JS_FALSE; pc = CG_CODE(cg, off); SET_UINT16(pc, slot); pc += 2; SET_INDEX(pc, index); - return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; + return bigSuffix == JSOP_NOP || Emit1(cx, cg, bigSuffix) >= 0; } bool -JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn) +CodeGenerator::shouldNoteClosedName(ParseNode *pn) { return !callsEval() && pn->isDefn() && pn->isClosed(); } @@ -1995,12 +1964,12 @@ JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn) * Adjust the slot for a block local to account for the number of variables * that share the same index space with locals. Due to the incremental code * generation for top-level script, we do the adjustment via code patching in - * Compiler::compileScript; see comments there. + * BytecodeCompiler::compileScript; see comments there. * * The function returns -1 on failures. */ static jsint -AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) +AdjustBlockSlot(JSContext *cx, CodeGenerator *cg, jsint slot) { JS_ASSERT((jsuint) slot < cg->maxStackDepth); if (cg->inFunction()) { @@ -2014,7 +1983,7 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) } static bool -EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) +EmitEnterBlock(JSContext *cx, ParseNode *pn, CodeGenerator *cg) { JS_ASSERT(pn->isKind(TOK_LEXICALSCOPE)); if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg)) @@ -2035,12 +2004,12 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) continue; } - JSDefinition *dn = (JSDefinition *) v.toPrivate(); + Definition *dn = (Definition *) v.toPrivate(); JS_ASSERT(dn->isDefn()); JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16)); dn->pn_cookie.set(dn->pn_cookie.level(), uint16(dn->frameSlot() + depth)); #ifdef DEBUG - for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { + for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->pn_lexdef == dn); JS_ASSERT(!(pnu->pn_dflags & PND_BOUND)); JS_ASSERT(pnu->pn_cookie.isFree()); @@ -2057,9 +2026,9 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) } /* - * If clones of this block will have any extensible parents, then the clones - * must get unique shapes; see the comments for js::Bindings:: - * extensibleParents. + * If clones of this block will have any extensible parents, then the + * clones must get unique shapes; see the comments for + * js::Bindings::extensibleParents. */ if ((cg->flags & TCF_FUN_EXTENSIBLE_SCOPE) || cg->bindings.extensibleParents()) { @@ -2073,18 +2042,17 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) } static JSBool -EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, - JSObjectBox *box) +EmitLeaveBlock(JSContext *cx, CodeGenerator *cg, JSOp op, ObjectBox *box) { JSOp bigSuffix; uintN count = OBJ_BLOCK_COUNT(cx, box->object); - + bigSuffix = EmitBigIndexPrefix(cx, cg, box->index); if (bigSuffix == JSOP_FALSE) return JS_FALSE; - if (js_Emit5(cx, cg, op, count, box->index) < 0) + if (Emit5(cx, cg, op, count, box->index) < 0) return JS_FALSE; - return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; + return bigSuffix == JSOP_NOP || Emit1(cx, cg, bigSuffix) >= 0; } /* @@ -2109,13 +2077,14 @@ EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, * foo(); */ static bool -TryConvertToGname(JSCodeGenerator *cg, JSParseNode *pn, JSOp *op) +TryConvertToGname(CodeGenerator *cg, ParseNode *pn, JSOp *op) { - if (cg->compileAndGo() && + if (cg->compileAndGo() && cg->compiler()->globalScope->globalObj && !cg->mightAliasLocals() && !pn->isDeoptimized() && - !(cg->flags & TCF_STRICT_MODE_CODE)) { + !(cg->flags & TCF_STRICT_MODE_CODE)) + { switch (*op) { case JSOP_NAME: *op = JSOP_GETGNAME; break; case JSOP_SETNAME: *op = JSOP_SETGNAME; break; @@ -2138,7 +2107,7 @@ TryConvertToGname(JSCodeGenerator *cg, JSParseNode *pn, JSOp *op) // that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam // that will be free (meaning no binding), or a slot number. static bool -BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode *pn, JSAtom *atom) +BindKnownGlobal(JSContext *cx, CodeGenerator *cg, ParseNode *dn, ParseNode *pn, JSAtom *atom) { // Cookie is an outparam; make sure caller knew to clear it. JS_ASSERT(pn->pn_cookie.isFree()); @@ -2156,7 +2125,7 @@ BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode JS_ASSERT(!!p); index = p.value(); } else { - JSCodeGenerator *globalcg = globalScope->cg; + CodeGenerator *globalcg = globalScope->cg; // If the definition is bound, and we're in the same cg, we can re-use // its cookie. @@ -2182,17 +2151,17 @@ BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode // See BindKnownGlobal()'s comment. static bool -BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom) +BindGlobal(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSAtom *atom) { pn->pn_cookie.makeFree(); - JSDefinition *dn; + Definition *dn; if (pn->isUsed()) { dn = pn->pn_lexdef; } else { if (!pn->isDefn()) return true; - dn = (JSDefinition *)pn; + dn = (Definition *)pn; } // Only optimize for defined globals. @@ -2217,15 +2186,15 @@ BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom) * * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget * to update the TOK_FOR (for-in) and TOK_ASSIGN (op=, e.g. +=) special cases - * in js_EmitTree. + * in EmitTree. */ static JSBool -BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +BindNameToSlot(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { - JSDefinition *dn; + Definition *dn; JSOp op; JSAtom *atom; - JSDefinition::Kind dn_kind; + Definition::Kind dn_kind; JS_ASSERT(pn->isKind(TOK_NAME)); @@ -2250,7 +2219,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } else { if (!pn->isDefn()) return JS_TRUE; - dn = (JSDefinition *) pn; + dn = (Definition *) pn; } op = pn->getOp(); @@ -2276,7 +2245,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case JSOP_SETCONST: break; case JSOP_DELNAME: - if (dn_kind != JSDefinition::UNKNOWN) { + if (dn_kind != Definition::UNKNOWN) { if (cg->parser->callerFrame && dn->isTopLevel()) JS_ASSERT(cg->compileAndGo()); else @@ -2428,8 +2397,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } uintN slot = cookie.slot(); - if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != JSDefinition::ARG) { - JSTreeContext *tc = cg; + if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != Definition::ARG) { + TreeContext *tc = cg; do { tc = tc->parent; } while (tc->staticLevel != level); @@ -2454,10 +2423,10 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * rewrite pn_op and update pn accordingly. */ switch (dn_kind) { - case JSDefinition::UNKNOWN: + case Definition::UNKNOWN: return JS_TRUE; - case JSDefinition::LET: + case Definition::LET: switch (op) { case JSOP_NAME: op = JSOP_GETLOCAL; break; case JSOP_SETNAME: op = JSOP_SETLOCAL; break; @@ -2469,7 +2438,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } break; - case JSDefinition::ARG: + case Definition::ARG: switch (op) { case JSOP_NAME: op = JSOP_GETARG; break; case JSOP_SETNAME: op = JSOP_SETARG; break; @@ -2482,7 +2451,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ASSERT(!pn->isConst()); break; - case JSDefinition::VAR: + case Definition::VAR: if (dn->isOp(JSOP_CALLEE)) { JS_ASSERT(op != JSOP_CALLEE); JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom); @@ -2524,9 +2493,9 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* FALL THROUGH */ default: - JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION, - dn_kind == JSDefinition::VAR || - dn_kind == JSDefinition::CONST); + JS_ASSERT_IF(dn_kind != Definition::FUNCTION, + dn_kind == Definition::VAR || + dn_kind == Definition::CONST); switch (op) { case JSOP_NAME: op = JSOP_GETLOCAL; break; case JSOP_SETNAME: op = JSOP_SETLOCAL; break; @@ -2537,7 +2506,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case JSOP_NAMEDEC: op = JSOP_LOCALDEC; break; default: JS_NOT_REACHED("local"); } - JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST); + JS_ASSERT_IF(dn_kind == Definition::CONST, pn->pn_dflags & PND_CONST); break; } @@ -2549,7 +2518,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } bool -JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie) +CodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie) { if (!globalMap.ensureMap(context())) return false; @@ -2595,11 +2564,10 @@ JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie) * pop bytecode. */ static JSBool -CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, - JSBool *answer) +CheckSideEffects(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool *answer) { JSBool ok; - JSParseNode *pn2; + ParseNode *pn2; ok = JS_TRUE; if (!pn || *answer) @@ -2710,6 +2678,9 @@ CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, case TOK_DOT: #if JS_HAS_XML_SUPPORT case TOK_DBLDOT: + JS_ASSERT_IF(pn2->getKind() == TOK_DBLDOT, !cg->inStrictMode()); + /* FALL THROUGH */ + #endif case TOK_LP: case TOK_LB: @@ -2790,8 +2761,7 @@ CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, } static JSBool -EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, - JSBool callContext) +EmitNameOp(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool callContext) { JSOp op; @@ -2823,9 +2793,9 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, } if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) { - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; - if (callContext && js_Emit1(cx, cg, JSOP_PUSH) < 0) + if (callContext && Emit1(cx, cg, JSOP_PUSH) < 0) return JS_FALSE; } else { if (!pn->pn_cookie.isFree()) { @@ -2840,42 +2810,38 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, } #if JS_HAS_XML_SUPPORT -static JSBool -EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +static bool +EmitXMLName(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { - JSParseNode *pn2; - uintN oldflags; - + JS_ASSERT(!cg->inStrictMode()); JS_ASSERT(pn->isKind(TOK_UNARYOP)); JS_ASSERT(pn->isOp(JSOP_XMLNAME)); JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME); - pn2 = pn->pn_kid; - oldflags = cg->flags; + ParseNode *pn2 = pn->pn_kid; + uintN oldflags = cg->flags; cg->flags &= ~TCF_IN_FOR_INIT; - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; + if (!EmitTree(cx, cg, pn2)) + return false; cg->flags |= oldflags & TCF_IN_FOR_INIT; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, - CG_OFFSET(cg) - pn2->pn_offset) < 0) { - return JS_FALSE; - } + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0) + return false; - return js_Emit1(cx, cg, op) >= 0; + return Emit1(cx, cg, op) >= 0; } #endif static inline bool -EmitElemOpBase(JSContext *cx, JSCodeGenerator *cg, JSOp op) +EmitElemOpBase(JSContext *cx, CodeGenerator *cg, JSOp op) { - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return false; CheckTypeSet(cx, cg, op); return true; } static bool -EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +EmitSpecialPropOp(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { /* * Special case for obj.__proto__ to deoptimize away from fast paths in the @@ -2890,11 +2856,11 @@ EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) return EmitElemOpBase(cx, cg, op); } -static JSBool -EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, +static bool +EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg, JSBool callContext, JSOp *psuffix = NULL) { - JSParseNode *pn2, *pndot, *pnup, *pndown; + ParseNode *pn2, *pndot, *pnup, *pndown; ptrdiff_t top; JS_ASSERT(pn->isArity(PN_NAME)); @@ -2903,8 +2869,8 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, /* Special case deoptimization for __proto__. */ if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) && pn->pn_atom == cx->runtime->atomState.protoAtom) { - if (pn2 && !js_EmitTree(cx, cg, pn2)) - return JS_FALSE; + if (pn2 && !EmitTree(cx, cg, pn2)) + return false; return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg); } @@ -2919,11 +2885,11 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, * inference is enabled this is optimized separately. */ if (!BindNameToSlot(cx, cg, pn2)) - return JS_FALSE; + return false; if (!cx->typeInferenceEnabled() && pn->pn_atom == cx->runtime->atomState.lengthAtom) { if (pn2->isOp(JSOP_ARGUMENTS)) - return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0; + return Emit1(cx, cg, JSOP_ARGCNT) >= 0; } } } @@ -2950,22 +2916,20 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, } /* pndown is a primary expression, not a dotted property reference. */ - if (!js_EmitTree(cx, cg, pndown)) - return JS_FALSE; + if (!EmitTree(cx, cg, pndown)) + return false; do { /* Walk back up the list, emitting annotated name ops. */ - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, - CG_OFFSET(cg) - pndown->pn_offset) < 0) { - return JS_FALSE; - } + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pndown->pn_offset) < 0) + return false; /* Special case deoptimization on __proto__, as above. */ if (pndot->isArity(PN_NAME) && pndot->pn_atom == cx->runtime->atomState.protoAtom) { if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg)) - return JS_FALSE; + return false; } else if (!EmitAtomOp(cx, pndot, pndot->getOp(), cg)) { - return JS_FALSE; + return false; } /* Reverse the pn_expr link again. */ @@ -2974,25 +2938,23 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, pndown = pndot; } while ((pndot = pnup) != NULL); } else { - if (!js_EmitTree(cx, cg, pn2)) - return JS_FALSE; + if (!EmitTree(cx, cg, pn2)) + return false; } - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, - CG_OFFSET(cg) - pn2->pn_offset) < 0) { - return JS_FALSE; - } + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0) + return false; return EmitAtomOp(cx, pn, op, cg, psuffix); } static bool -EmitPropIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { JSOp suffix = JSOP_NOP; if (!EmitPropOp(cx, pn, op, cg, false, &suffix)) return false; - if (js_Emit1(cx, cg, JSOP_NOP) < 0) + if (Emit1(cx, cg, JSOP_NOP) < 0) return false; /* @@ -3001,7 +2963,7 @@ EmitPropIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) */ int start = CG_OFFSET(cg); - if (suffix != JSOP_NOP && js_Emit1(cx, cg, suffix) < 0) + if (suffix != JSOP_NOP && Emit1(cx, cg, suffix) < 0) return false; const JSCodeSpec *cs = &js_CodeSpec[op]; @@ -3012,46 +2974,46 @@ EmitPropIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB; // OBJ - if (js_Emit1(cx, cg, JSOP_DUP) < 0) // OBJ OBJ + if (Emit1(cx, cg, JSOP_DUP) < 0) // OBJ OBJ return false; if (!EmitAtomOp(cx, pn, JSOP_GETPROP, cg)) // OBJ V return false; - if (js_Emit1(cx, cg, JSOP_POS) < 0) // OBJ N + if (Emit1(cx, cg, JSOP_POS) < 0) // OBJ N return false; - if (post && js_Emit1(cx, cg, JSOP_DUP) < 0) // OBJ N? N + if (post && Emit1(cx, cg, JSOP_DUP) < 0) // OBJ N? N return false; - if (js_Emit1(cx, cg, JSOP_ONE) < 0) // OBJ N? N 1 + if (Emit1(cx, cg, JSOP_ONE) < 0) // OBJ N? N 1 return false; - if (js_Emit1(cx, cg, binop) < 0) // OBJ N? N+1 + if (Emit1(cx, cg, binop) < 0) // OBJ N? N+1 return false; if (post) { - if (js_Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N? N+1 OBJ + if (Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N? N+1 OBJ return false; - if (js_Emit1(cx, cg, JSOP_SWAP) < 0) // N? OBJ N+1 + if (Emit1(cx, cg, JSOP_SWAP) < 0) // N? OBJ N+1 return false; } if (!EmitAtomOp(cx, pn, JSOP_SETPROP, cg)) // N? N+1 return false; - if (post && js_Emit1(cx, cg, JSOP_POP) < 0) // RESULT + if (post && Emit1(cx, cg, JSOP_POP) < 0) // RESULT return false; UpdateDecomposeLength(cg, start); - if (suffix != JSOP_NOP && js_Emit1(cx, cg, suffix) < 0) + if (suffix != JSOP_NOP && Emit1(cx, cg, suffix) < 0) return false; return true; } static bool -EmitNameIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { JSOp suffix = JSOP_NOP; if (!EmitAtomOp(cx, pn, op, cg, &suffix)) return false; - if (js_Emit1(cx, cg, JSOP_NOP) < 0) + if (Emit1(cx, cg, JSOP_NOP) < 0) return false; /* Remove the result to restore the stack depth before the INCNAME. */ @@ -3059,7 +3021,7 @@ EmitNameIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) int start = CG_OFFSET(cg); - if (suffix != JSOP_NOP && js_Emit1(cx, cg, suffix) < 0) + if (suffix != JSOP_NOP && Emit1(cx, cg, suffix) < 0) return false; const JSCodeSpec *cs = &js_CodeSpec[op]; @@ -3074,40 +3036,40 @@ EmitNameIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) return false; if (!EmitAtomOp(cx, pn, global ? JSOP_GETGNAME : JSOP_NAME, cg)) // OBJ V return false; - if (js_Emit1(cx, cg, JSOP_POS) < 0) // OBJ N + if (Emit1(cx, cg, JSOP_POS) < 0) // OBJ N return false; - if (post && js_Emit1(cx, cg, JSOP_DUP) < 0) // OBJ N? N + if (post && Emit1(cx, cg, JSOP_DUP) < 0) // OBJ N? N return false; - if (js_Emit1(cx, cg, JSOP_ONE) < 0) // OBJ N? N 1 + if (Emit1(cx, cg, JSOP_ONE) < 0) // OBJ N? N 1 return false; - if (js_Emit1(cx, cg, binop) < 0) // OBJ N? N+1 + if (Emit1(cx, cg, binop) < 0) // OBJ N? N+1 return false; if (post) { - if (js_Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N? N+1 OBJ + if (Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N? N+1 OBJ return false; - if (js_Emit1(cx, cg, JSOP_SWAP) < 0) // N? OBJ N+1 + if (Emit1(cx, cg, JSOP_SWAP) < 0) // N? OBJ N+1 return false; } if (!EmitAtomOp(cx, pn, global ? JSOP_SETGNAME : JSOP_SETNAME, cg)) // N? N+1 return false; - if (post && js_Emit1(cx, cg, JSOP_POP) < 0) // RESULT + if (post && Emit1(cx, cg, JSOP_POP) < 0) // RESULT return false; UpdateDecomposeLength(cg, start); - if (suffix != JSOP_NOP && js_Emit1(cx, cg, suffix) < 0) + if (suffix != JSOP_NOP && Emit1(cx, cg, suffix) < 0) return false; return true; } static JSBool -EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +EmitElemOp(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { ptrdiff_t top; - JSParseNode *left, *right, *next, ltmp, rtmp; + ParseNode *left, *right, *next; int32_t slot; top = CG_OFFSET(cg); @@ -3127,7 +3089,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) */ if (left->isKind(TOK_NAME) && next->isKind(TOK_NUMBER)) { if (!BindNameToSlot(cx, cg, left)) - return JS_FALSE; + return false; if (left->isOp(JSOP_ARGUMENTS) && JSDOUBLE_IS_INT32(next->pn_dval, &slot) && jsuint(slot) < JS_BIT(16) && @@ -3155,40 +3117,42 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) */ JS_ASSERT(next != right || pn->pn_count == 3); if (left == pn->pn_head) { - if (!js_EmitTree(cx, cg, left)) - return JS_FALSE; + if (!EmitTree(cx, cg, left)) + return false; } while (next != right) { - if (!js_EmitTree(cx, cg, next)) - return JS_FALSE; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) - return JS_FALSE; + if (!EmitTree(cx, cg, next)) + return false; + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return false; if (!EmitElemOpBase(cx, cg, JSOP_GETELEM)) - return JS_FALSE; + return false; next = next->pn_next; } } else { if (pn->isArity(PN_NAME)) { /* * Set left and right so pn appears to be a TOK_LB node, instead - * of a TOK_DOT node. See the TOK_FOR/IN case in js_EmitTree, and + * of a TOK_DOT node. See the TOK_FOR/IN case in EmitTree, and * EmitDestructuringOps nearer below. In the destructuring case, * the base expression (pn_expr) of the name may be null, which * means we have to emit a JSOP_BINDNAME. */ left = pn->maybeExpr(); if (!left) { - left = <mp; + left = NullaryNode::create(cg); + if (!left) + return false; left->setKind(TOK_STRING); left->setOp(JSOP_BINDNAME); - left->setArity(PN_NULLARY); left->pn_pos = pn->pn_pos; left->pn_atom = pn->pn_atom; } - right = &rtmp; + right = NullaryNode::create(cg); + if (!right) + return false; right->setKind(TOK_STRING); - right->setOp(js_IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING); - right->setArity(PN_NULLARY); + right->setOp(IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING); right->pn_pos = pn->pn_pos; right->pn_atom = pn->pn_atom; } else { @@ -3205,7 +3169,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) left->isKind(TOK_NAME) && right->isKind(TOK_NUMBER)) { if (!BindNameToSlot(cx, cg, left)) - return JS_FALSE; + return false; if (left->isOp(JSOP_ARGUMENTS) && JSDOUBLE_IS_INT32(right->pn_dval, &slot) && jsuint(slot) < JS_BIT(16) && @@ -3214,26 +3178,26 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) (!cg->mutatesParameter() && !cg->callsEval()))) { left->pn_offset = right->pn_offset = top; EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); - return JS_TRUE; + return true; } } - if (!js_EmitTree(cx, cg, left)) - return JS_FALSE; + if (!EmitTree(cx, cg, left)) + return false; } /* The right side of the descendant operator is implicitly quoted. */ JS_ASSERT(op != JSOP_DESCENDANTS || !right->isKind(TOK_STRING) || right->isOp(JSOP_QNAMEPART)); - if (!js_EmitTree(cx, cg, right)) - return JS_FALSE; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) - return JS_FALSE; + if (!EmitTree(cx, cg, right)) + return false; + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return false; return EmitElemOpBase(cx, cg, op); } static bool -EmitElemIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +EmitElemIncDec(JSContext *cx, ParseNode *pn, JSOp op, CodeGenerator *cg) { if (pn) { if (!EmitElemOp(cx, pn, op, cg)) @@ -3242,7 +3206,7 @@ EmitElemIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) if (!EmitElemOpBase(cx, cg, op)) return false; } - if (js_Emit1(cx, cg, JSOP_NOP) < 0) + if (Emit1(cx, cg, JSOP_NOP) < 0) return false; /* INCELEM pops two values and pushes one, so restore the initial depth. */ @@ -3262,33 +3226,33 @@ EmitElemIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) * it inside both the GETELEM and the SETELEM. */ // OBJ KEY* - if (js_Emit1(cx, cg, JSOP_TOID) < 0) // OBJ KEY + if (Emit1(cx, cg, JSOP_TOID) < 0) // OBJ KEY return false; - if (js_Emit1(cx, cg, JSOP_DUP2) < 0) // OBJ KEY OBJ KEY + if (Emit1(cx, cg, JSOP_DUP2) < 0) // OBJ KEY OBJ KEY return false; if (!EmitElemOpBase(cx, cg, JSOP_GETELEM)) // OBJ KEY V return false; - if (js_Emit1(cx, cg, JSOP_POS) < 0) // OBJ KEY N + if (Emit1(cx, cg, JSOP_POS) < 0) // OBJ KEY N return false; - if (post && js_Emit1(cx, cg, JSOP_DUP) < 0) // OBJ KEY N? N + if (post && Emit1(cx, cg, JSOP_DUP) < 0) // OBJ KEY N? N return false; - if (js_Emit1(cx, cg, JSOP_ONE) < 0) // OBJ KEY N? N 1 + if (Emit1(cx, cg, JSOP_ONE) < 0) // OBJ KEY N? N 1 return false; - if (js_Emit1(cx, cg, binop) < 0) // OBJ KEY N? N+1 + if (Emit1(cx, cg, binop) < 0) // OBJ KEY N? N+1 return false; if (post) { - if (js_Emit2(cx, cg, JSOP_PICK, (jsbytecode)3) < 0) // KEY N N+1 OBJ + if (Emit2(cx, cg, JSOP_PICK, (jsbytecode)3) < 0) // KEY N N+1 OBJ return false; - if (js_Emit2(cx, cg, JSOP_PICK, (jsbytecode)3) < 0) // N N+1 OBJ KEY + if (Emit2(cx, cg, JSOP_PICK, (jsbytecode)3) < 0) // N N+1 OBJ KEY return false; - if (js_Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N OBJ KEY N+1 + if (Emit2(cx, cg, JSOP_PICK, (jsbytecode)2) < 0) // N OBJ KEY N+1 return false; } if (!EmitElemOpBase(cx, cg, JSOP_SETELEM)) // N? N+1 return false; - if (post && js_Emit1(cx, cg, JSOP_POP) < 0) // RESULT + if (post && Emit1(cx, cg, JSOP_POP) < 0) // RESULT return false; UpdateDecomposeLength(cg, start); @@ -3297,7 +3261,7 @@ EmitElemIncDec(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) } static JSBool -EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) +EmitNumberOp(JSContext *cx, jsdouble dval, CodeGenerator *cg) { int32_t ival; uint32 u; @@ -3306,23 +3270,23 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) if (JSDOUBLE_IS_INT32(dval, &ival)) { if (ival == 0) - return js_Emit1(cx, cg, JSOP_ZERO) >= 0; + return Emit1(cx, cg, JSOP_ZERO) >= 0; if (ival == 1) - return js_Emit1(cx, cg, JSOP_ONE) >= 0; + return Emit1(cx, cg, JSOP_ONE) >= 0; if ((jsint)(int8)ival == ival) - return js_Emit2(cx, cg, JSOP_INT8, (jsbytecode)(int8)ival) >= 0; + return Emit2(cx, cg, JSOP_INT8, (jsbytecode)(int8)ival) >= 0; u = (uint32)ival; if (u < JS_BIT(16)) { EMIT_UINT16_IMM_OP(JSOP_UINT16, u); } else if (u < JS_BIT(24)) { - off = js_EmitN(cx, cg, JSOP_UINT24, 3); + off = EmitN(cx, cg, JSOP_UINT24, 3); if (off < 0) return JS_FALSE; pc = CG_CODE(cg, off); SET_UINT24(pc, u); } else { - off = js_EmitN(cx, cg, JSOP_INT32, 4); + off = EmitN(cx, cg, JSOP_INT32, 4); if (off < 0) return JS_FALSE; pc = CG_CODE(cg, off); @@ -3359,28 +3323,28 @@ AllocateSwitchConstant(JSContext *cx) * though EXPR is evaluated in the enclosing scope; it does not see x. * * In those cases we use TempPopScope around the code to emit EXPR. It - * temporarily removes the let-scope from the JSCodeGenerator's scope stack and + * temporarily removes the let-scope from the CodeGenerator's scope stack and * emits extra bytecode to ensure that js::GetBlockChain also finds the correct * scope at run time. */ class TempPopScope { - JSStmtInfo *savedStmt; - JSStmtInfo *savedScopeStmt; - JSObjectBox *savedBlockBox; + StmtInfo *savedStmt; + StmtInfo *savedScopeStmt; + ObjectBox *savedBlockBox; public: TempPopScope() : savedStmt(NULL), savedScopeStmt(NULL), savedBlockBox(NULL) {} - bool popBlock(JSContext *cx, JSCodeGenerator *cg) { + bool popBlock(JSContext *cx, CodeGenerator *cg) { savedStmt = cg->topStmt; savedScopeStmt = cg->topScopeStmt; savedBlockBox = cg->blockChainBox; if (cg->topStmt->type == STMT_FOR_LOOP || cg->topStmt->type == STMT_FOR_IN_LOOP) - js_PopStatement(cg); + PopStatementTC(cg); JS_ASSERT(STMT_LINKS_SCOPE(cg->topStmt)); JS_ASSERT(cg->topStmt->flags & SIF_SCOPE); - js_PopStatement(cg); + PopStatementTC(cg); /* * Since we have changed the block chain, emit an instruction marking @@ -3389,35 +3353,35 @@ class TempPopScope { * * FIXME bug 671360 - The JSOP_NOP instruction should not be necessary. */ - return js_Emit1(cx, cg, JSOP_NOP) >= 0 && EmitBlockChain(cx, cg); + return Emit1(cx, cg, JSOP_NOP) >= 0 && EmitBlockChain(cx, cg); } - bool repushBlock(JSContext *cx, JSCodeGenerator *cg) { + bool repushBlock(JSContext *cx, CodeGenerator *cg) { JS_ASSERT(savedStmt); cg->topStmt = savedStmt; cg->topScopeStmt = savedScopeStmt; cg->blockChainBox = savedBlockBox; - return js_Emit1(cx, cg, JSOP_NOP) >= 0 && EmitBlockChain(cx, cg); + return Emit1(cx, cg, JSOP_NOP) >= 0 && EmitBlockChain(cx, cg); } }; static JSBool -EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitSwitch(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { JSOp switchOp; JSBool ok, hasDefault, constPropagated; ptrdiff_t top, off, defaultOffset; - JSParseNode *pn2, *pn3, *pn4; + ParseNode *pn2, *pn3, *pn4; uint32 caseCount, tableLength; - JSParseNode **table; + ParseNode **table; int32_t i, low, high; intN noteIndex; size_t switchSize, tableSize; jsbytecode *pc, *savepc; #if JS_HAS_BLOCK_SCOPE - JSObjectBox *box; + ObjectBox *box; #endif - JSStmtInfo stmtInfo; + StmtInfo stmtInfo; /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */ switchOp = JSOP_TABLESWITCH; @@ -3442,7 +3406,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * find the discriminant on top of stack. */ box = pn2->pn_objbox; - js_PushBlockScope(cg, &stmtInfo, box, -1); + PushBlockScope(cg, &stmtInfo, box, -1); stmtInfo.type = STMT_SWITCH; /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */ @@ -3467,16 +3431,16 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Emit code for the discriminant first (or nearly first, in the case of a * switch whose body is a block scope). */ - if (!js_EmitTree(cx, cg, pn->pn_left)) + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; /* Switch bytecodes run from here till end of final case. */ top = CG_OFFSET(cg); #if !JS_HAS_BLOCK_SCOPE - js_PushStatement(cg, &stmtInfo, STMT_SWITCH, top); + PushStatement(cg, &stmtInfo, STMT_SWITCH, top); #else if (pn2->isKind(TOK_LC)) { - js_PushStatement(cg, &stmtInfo, STMT_SWITCH, top); + PushStatement(cg, &stmtInfo, STMT_SWITCH, top); } else { /* Re-push the switch's statement info record. */ if (!tps.repushBlock(cx, cg)) @@ -3660,7 +3624,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Emit a note with two offsets: first tells total switch code length, * second tells offset to first JSOP_CASE if condswitch. */ - noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0); + noteIndex = NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0); if (noteIndex < 0) return JS_FALSE; @@ -3690,12 +3654,12 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * If switchOp is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial * to emit the immediate operand(s) by which bytecode readers such as * BuildSpanDepTable discover the length of the switch opcode *before* - * calling js_SetJumpOffset (which may call BuildSpanDepTable). It's + * calling SetJumpOffset (which may call BuildSpanDepTable). It's * also important to zero all unknown jump offset immediate operands, * so they can be converted to span dependencies with null targets to - * be computed later (js_EmitN zeros switchSize bytes after switchOp). + * be computed later (EmitN zeros switchSize bytes after switchOp). */ - if (js_EmitN(cx, cg, switchOp, switchSize) < 0) + if (EmitN(cx, cg, switchOp, switchSize) < 0) return JS_FALSE; off = -1; @@ -3706,20 +3670,18 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Emit code for evaluating cases and jumping to case statements. */ for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { pn4 = pn3->pn_left; - if (pn4 && !js_EmitTree(cx, cg, pn4)) + if (pn4 && !EmitTree(cx, cg, pn4)) return JS_FALSE; if (caseNoteIndex >= 0) { /* off is the previous JSOP_CASE's bytecode offset. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, - CG_OFFSET(cg) - off)) { + if (!SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, CG_OFFSET(cg) - off)) return JS_FALSE; - } } if (!pn4) { JS_ASSERT(pn3->isKind(TOK_DEFAULT)); continue; } - caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + caseNoteIndex = NewSrcNote2(cx, cg, SRC_PCDELTA, 0); if (caseNoteIndex < 0) return JS_FALSE; off = EmitJump(cx, cg, JSOP_CASE, 0); @@ -3731,9 +3693,8 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Switch note's second offset is to first JSOP_CASE. */ noteCount = CG_NOTE_COUNT(cg); - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, off - top)) { + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, off - top)) return JS_FALSE; - } noteCountDelta = CG_NOTE_COUNT(cg) - noteCount; if (noteCountDelta != 0) caseNoteIndex += noteCountDelta; @@ -3743,14 +3704,14 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * If we didn't have an explicit default (which could fall in between - * cases, preventing us from fusing this js_SetSrcNoteOffset with the - * call in the loop above), link the last case to the implicit default - * for the decompiler. + * cases, preventing us from fusing this SetSrcNoteOffset with the call + * in the loop above), link the last case to the implicit default for + * the decompiler. */ if (!hasDefault && caseNoteIndex >= 0 && - !js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, - CG_OFFSET(cg) - off)) { + !SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, CG_OFFSET(cg) - off)) + { return JS_FALSE; } @@ -3775,7 +3736,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ if (tableLength != 0) { tableSize = (size_t)tableLength * sizeof *table; - table = (JSParseNode **) cx->malloc_(tableSize); + table = (ParseNode **) cx->malloc_(tableSize); if (!table) return JS_FALSE; memset(table, 0, tableSize); @@ -3806,8 +3767,8 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * We have already generated at least one big jump so we must * explicitly add span dependencies for the switch jumps. When - * called below, js_SetJumpOffset can only do it when patching - * the first big jump or when cg->spanDeps is null. + * called below, SetJumpOffset can only do it when patching the + * first big jump or when cg->spanDeps is null. */ if (!AddSwitchSpanDeps(cx, cg, CG_CODE(cg, top))) goto bad; @@ -3833,7 +3794,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!cg->makeAtomIndex(pn4->pn_atom, &index)) goto bad; CG_NEXT(cg) = pc; - if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0) + if (NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0) goto bad; } pc += JUMP_OFFSET_LEN; @@ -3848,7 +3809,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!cg->makeAtomIndex(pn4->pn_atom, &index)) goto bad; CG_NEXT(cg) = pc; - if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0) + if (NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0) goto bad; } pc += INDEX_LEN + JUMP_OFFSET_LEN; @@ -3863,7 +3824,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(TOK_DEFAULT)) CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad); pn4 = pn3->pn_right; - ok = js_EmitTree(cx, cg, pn4); + ok = EmitTree(cx, cg, pn4); if (!ok) goto out; pn3->pn_offset = pn4->pn_offset; @@ -3883,13 +3844,12 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (switchOp == JSOP_CONDSWITCH) { pc = NULL; JS_ASSERT(defaultOffset != -1); - ok = js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset), - off - (defaultOffset - top)); + ok = SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset), off - (defaultOffset - top)); if (!ok) goto out; } else { pc = CG_CODE(cg, top); - ok = js_SetJumpOffset(cx, cg, pc, off); + ok = SetJumpOffset(cx, cg, pc, off); if (!ok) goto out; pc += JUMP_OFFSET_LEN; @@ -3897,7 +3857,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Set the SRC_SWITCH note's offset operand to tell end of switch. */ off = CG_OFFSET(cg) - top; - ok = js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off); + ok = SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off); if (!ok) goto out; @@ -3909,7 +3869,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) for (i = 0; i < (jsint)tableLength; i++) { pn3 = table[i]; off = pn3 ? pn3->pn_offset - top : 0; - ok = js_SetJumpOffset(cx, cg, pc, off); + ok = SetJumpOffset(cx, cg, pc, off); if (!ok) goto out; pc += JUMP_OFFSET_LEN; @@ -3927,7 +3887,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pc += INDEX_LEN; off = pn3->pn_offset - top; - ok = js_SetJumpOffset(cx, cg, pc, off); + ok = SetJumpOffset(cx, cg, pc, off); if (!ok) goto out; pc += JUMP_OFFSET_LEN; @@ -3938,7 +3898,7 @@ out: if (table) cx->free_(table); if (ok) { - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); #if JS_HAS_BLOCK_SCOPE if (ok && pn->pn_right->isKind(TOK_LEXICALSCOPE)) @@ -3953,7 +3913,7 @@ bad: } JSBool -js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body) +frontend::EmitFunctionScript(JSContext *cx, CodeGenerator *cg, ParseNode *body) { /* * The decompiler has assumptions about what may occur immediately after @@ -3966,7 +3926,7 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body) /* JSOP_GENERATOR must be the first instruction. */ CG_SWITCH_TO_PROLOG(cg); JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg)); - if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0) + if (Emit1(cx, cg, JSOP_GENERATOR) < 0) return false; CG_SWITCH_TO_MAIN(cg); } @@ -3980,19 +3940,19 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body) */ if (cg->needsEagerArguments()) { CG_SWITCH_TO_PROLOG(cg); - if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || Emit1(cx, cg, JSOP_POP) < 0) return false; CG_SWITCH_TO_MAIN(cg); } - return js_EmitTree(cx, cg, body) && - js_Emit1(cx, cg, JSOP_STOP) >= 0 && + return EmitTree(cx, cg, body) && + Emit1(cx, cg, JSOP_STOP) >= 0 && JSScript::NewScriptFromCG(cx, cg); } static bool -MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn, jsatomid *result) +MaybeEmitVarDecl(JSContext *cx, CodeGenerator *cg, JSOp prologOp, + ParseNode *pn, jsatomid *result) { jsatomid atomIndex; @@ -4031,12 +3991,10 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, #if JS_HAS_DESTRUCTURING typedef JSBool -(*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn); +(*DestructuringDeclEmitter)(JSContext *cx, CodeGenerator *cg, JSOp prologOp, ParseNode *pn); static JSBool -EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn) +EmitDestructuringDecl(JSContext *cx, CodeGenerator *cg, JSOp prologOp, ParseNode *pn) { JS_ASSERT(pn->isKind(TOK_NAME)); if (!BindNameToSlot(cx, cg, pn)) @@ -4047,10 +4005,9 @@ EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, } static JSBool -EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn) +EmitDestructuringDecls(JSContext *cx, CodeGenerator *cg, JSOp prologOp, ParseNode *pn) { - JSParseNode *pn2, *pn3; + ParseNode *pn2, *pn3; DestructuringDeclEmitter emitter; if (pn->isKind(TOK_RB)) { @@ -4076,10 +4033,10 @@ EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, } static JSBool -EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); +EmitDestructuringOpsHelper(JSContext *cx, CodeGenerator *cg, ParseNode *pn); static JSBool -EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitDestructuringLHS(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { /* * Now emit the lvalue opcode sequence. If the lvalue is a nested @@ -4090,14 +4047,14 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) { if (!EmitDestructuringOpsHelper(cx, cg, pn)) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; } else { if (pn->isKind(TOK_NAME)) { if (!BindNameToSlot(cx, cg, pn)) return JS_FALSE; if (pn->isConst() && !pn->isInitialized()) - return js_Emit1(cx, cg, JSOP_POP) >= 0; + return Emit1(cx, cg, JSOP_POP) >= 0; } switch (pn->getOp()) { @@ -4128,7 +4085,7 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) { jsuint slot = pn->pn_cookie.asInteger(); EMIT_UINT16_IMM_OP(pn->getOp(), slot); - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; break; } @@ -4138,9 +4095,9 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) ptrdiff_t top; top = CG_OFFSET(cg); - if (!js_EmitTree(cx, cg, pn)) + if (!EmitTree(cx, cg, pn)) return JS_FALSE; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) return JS_FALSE; if (!EmitElemOpBase(cx, cg, JSOP_ENUMELEM)) return JS_FALSE; @@ -4163,10 +4120,10 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * them in the lvalues identified by the matched property names. */ static JSBool -EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitDestructuringOpsHelper(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { jsuint index; - JSParseNode *pn2, *pn3; + ParseNode *pn2, *pn3; JSBool doElemOp; #ifdef DEBUG @@ -4178,8 +4135,8 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn->pn_count == 0) { /* Emit a DUP;POP sequence for the decompiler. */ - return js_Emit1(cx, cg, JSOP_DUP) >= 0 && - js_Emit1(cx, cg, JSOP_POP) >= 0; + return Emit1(cx, cg, JSOP_DUP) >= 0 && + Emit1(cx, cg, JSOP_POP) >= 0; } index = 0; @@ -4188,9 +4145,9 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Duplicate the value being destructured to use as a reference base. * If dup is not the first one, annotate it for the decompiler. */ - if (pn2 != pn->pn_head && js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0) + if (pn2 != pn->pn_head && NewSrcNote(cx, cg, SRC_CONTINUE) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_DUP) < 0) + if (Emit1(cx, cg, JSOP_DUP) < 0) return JS_FALSE; /* @@ -4214,7 +4171,7 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * annotate the index op with SRC_INITPROP so we know we are * not decompiling an array initialiser. */ - if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + if (NewSrcNote(cx, cg, SRC_INITPROP) < 0) return JS_FALSE; if (!EmitNumberOp(cx, pn3->pn_dval, cg)) return JS_FALSE; @@ -4242,7 +4199,7 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn3->isKind(TOK_COMMA) && pn3->isArity(PN_NULLARY)) { JS_ASSERT(pn->isKind(TOK_RB)); JS_ASSERT(pn2 == pn3); - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; } else { if (!EmitDestructuringLHS(cx, cg, pn3)) @@ -4272,8 +4229,7 @@ OpToDeclType(JSOp op) } static JSBool -EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn) +EmitDestructuringOps(JSContext *cx, CodeGenerator *cg, JSOp prologOp, ParseNode *pn) { /* * If we're called from a variable declaration, help the decompiler by @@ -4281,7 +4237,7 @@ EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, * If the destructuring initialiser is empty, our helper will emit a * JSOP_DUP followed by a JSOP_POP for the decompiler. */ - if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(prologOp)) < 0) + if (NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(prologOp)) < 0) return JS_FALSE; /* @@ -4292,11 +4248,11 @@ EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, } static JSBool -EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *lhs, JSParseNode *rhs) +EmitGroupAssignment(JSContext *cx, CodeGenerator *cg, JSOp prologOp, + ParseNode *lhs, ParseNode *rhs) { jsuint depth, limit, i, nslots; - JSParseNode *pn; + ParseNode *pn; depth = limit = (uintN) cg->stackDepth; for (pn = rhs->pn_head; pn; pn = pn->pn_next) { @@ -4307,12 +4263,12 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, /* MaybeEmitGroupAssignment won't call us if rhs is holey. */ JS_ASSERT(!(pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY))); - if (!js_EmitTree(cx, cg, pn)) + if (!EmitTree(cx, cg, pn)) return JS_FALSE; ++limit; } - if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0) + if (NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0) return JS_FALSE; i = depth; @@ -4325,7 +4281,7 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot); if (pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY)) { - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; } else { if (!EmitDestructuringLHS(cx, cg, pn)) @@ -4345,10 +4301,9 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop. */ static JSBool -MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, - JSParseNode *pn, JSOp *pop) +MaybeEmitGroupAssignment(JSContext *cx, CodeGenerator *cg, JSOp prologOp, ParseNode *pn, JSOp *pop) { - JSParseNode *lhs, *rhs; + ParseNode *lhs, *rhs; JS_ASSERT(pn->isKind(TOK_ASSIGN)); JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV); @@ -4367,12 +4322,12 @@ MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, #endif /* JS_HAS_DESTRUCTURING */ static JSBool -EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, - JSBool inLetHead, ptrdiff_t *headNoteIndex) +EmitVariables(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool inLetHead, + ptrdiff_t *headNoteIndex) { bool forInVar, first; ptrdiff_t off, noteIndex, tmp; - JSParseNode *pn2, *pn3, *next; + ParseNode *pn2, *pn3, *next; JSOp op; jsatomid atomIndex; uintN oldflags; @@ -4404,12 +4359,12 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, #if JS_HAS_DESTRUCTURING if (pn2->isKind(TOK_RB) || pn2->isKind(TOK_RC)) { /* - * Emit variable binding ops, but not destructuring ops. - * The parser (see Variables, jsparse.c) has ensured that - * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree, - * and that case will emit the destructuring code only after - * emitting an enumerating opcode and a branch that tests - * whether the enumeration ended. + * Emit variable binding ops, but not destructuring ops. The + * parser (see Parser::variables) has ensured that our caller + * will be the TOK_FOR/TOK_IN case in EmitTree, and that case + * will emit the destructuring code only after emitting an + * enumerating opcode and a branch that tests whether the + * enumeration ended. */ JS_ASSERT(forInVar); JS_ASSERT(pn->pn_count == 1); @@ -4469,7 +4424,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, if (!EmitDestructuringDecls(cx, cg, pn->getOp(), pn3)) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn2->pn_right)) + if (!EmitTree(cx, cg, pn2->pn_right)) return JS_FALSE; /* @@ -4522,13 +4477,14 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex); } if (pn->isOp(JSOP_DEFCONST) && - !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) { + !DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) + { return JS_FALSE; } oldflags = cg->flags; cg->flags &= ~TCF_IN_FOR_INIT; - if (!js_EmitTree(cx, cg, pn3)) + if (!EmitTree(cx, cg, pn3)) return JS_FALSE; cg->flags |= oldflags & TCF_IN_FOR_INIT; } @@ -4540,7 +4496,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, * a TOK_SEQ node to make the two statements appear as one. Therefore * if this declaration is part of a for-in loop head, we do not need to * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in - * js_EmitTree, will annotate appropriately. + * EmitTree, will annotate appropriately. */ JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr); if (forInVar) { @@ -4551,16 +4507,17 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, if (first && !inLetHead && - js_NewSrcNote2(cx, cg, SRC_DECL, - (pn->isOp(JSOP_DEFCONST)) - ? SRC_DECL_CONST - : (pn->isOp(JSOP_DEFVAR)) - ? SRC_DECL_VAR - : SRC_DECL_LET) < 0) { + NewSrcNote2(cx, cg, SRC_DECL, + (pn->isOp(JSOP_DEFCONST)) + ? SRC_DECL_CONST + : (pn->isOp(JSOP_DEFVAR)) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) + { return JS_FALSE; } if (op == JSOP_ARGUMENTS) { - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } else if (!pn2->pn_cookie.isFree()) { EMIT_UINT16_IMM_OP(op, atomIndex); @@ -4573,31 +4530,31 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, #endif tmp = CG_OFFSET(cg); if (noteIndex >= 0) { - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) return JS_FALSE; } if (!next) break; off = tmp; - noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); - if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + noteIndex = NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; } /* If this is a let head, emit and return a srcnote on the pop. */ if (inLetHead) { - *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL); + *headNoteIndex = NewSrcNote(cx, cg, SRC_DECL); if (*headNoteIndex < 0) return JS_FALSE; if (!(pn->pn_xflags & PNX_POPVAR)) - return js_Emit1(cx, cg, JSOP_NOP) >= 0; + return Emit1(cx, cg, JSOP_NOP) >= 0; } - return !(pn->pn_xflags & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0; + return !(pn->pn_xflags & PNX_POPVAR) || Emit1(cx, cg, JSOP_POP) >= 0; } static bool -EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JSParseNode *rhs) +EmitAssignment(JSContext *cx, CodeGenerator *cg, ParseNode *lhs, JSOp op, ParseNode *rhs) { ptrdiff_t top = CG_OFFSET(cg); @@ -4626,7 +4583,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS } break; case TOK_DOT: - if (!js_EmitTree(cx, cg, lhs->expr())) + if (!EmitTree(cx, cg, lhs->expr())) return false; offset++; if (!cg->makeAtomIndex(lhs->pn_atom, &atomIndex)) @@ -4634,9 +4591,9 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS break; case TOK_LB: JS_ASSERT(lhs->isArity(PN_BINARY)); - if (!js_EmitTree(cx, cg, lhs->pn_left)) + if (!EmitTree(cx, cg, lhs->pn_left)) return false; - if (!js_EmitTree(cx, cg, lhs->pn_right)) + if (!EmitTree(cx, cg, lhs->pn_right)) return false; offset += 2; break; @@ -4646,16 +4603,18 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS break; #endif case TOK_LP: - if (!js_EmitTree(cx, cg, lhs)) + if (!EmitTree(cx, cg, lhs)) return false; offset++; break; #if JS_HAS_XML_SUPPORT case TOK_UNARYOP: + JS_ASSERT(!cg->inStrictMode()); JS_ASSERT(lhs->isOp(JSOP_SETXMLNAME)); - if (!js_EmitTree(cx, cg, lhs->pn_kid)) + + if (!EmitTree(cx, cg, lhs->pn_kid)) return false; - if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + if (Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) return false; offset++; break; @@ -4670,13 +4629,13 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS case TOK_NAME: if (lhs->isConst()) { if (lhs->isOp(JSOP_CALLEE)) { - if (js_Emit1(cx, cg, JSOP_CALLEE) < 0) + if (Emit1(cx, cg, JSOP_CALLEE) < 0) return false; } else { EMIT_INDEX_OP(lhs->getOp(), atomIndex); } } else if (lhs->isOp(JSOP_SETNAME)) { - if (js_Emit1(cx, cg, JSOP_DUP) < 0) + if (Emit1(cx, cg, JSOP_DUP) < 0) return false; EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex); } else if (lhs->isOp(JSOP_SETGNAME)) { @@ -4688,7 +4647,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS } break; case TOK_DOT: - if (js_Emit1(cx, cg, JSOP_DUP) < 0) + if (Emit1(cx, cg, JSOP_DUP) < 0) return false; if (lhs->pn_atom == cx->runtime->atomState.protoAtom) { if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg)) @@ -4705,7 +4664,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS #if JS_HAS_XML_SUPPORT case TOK_UNARYOP: #endif - if (js_Emit1(cx, cg, JSOP_DUP2) < 0) + if (Emit1(cx, cg, JSOP_DUP2) < 0) return false; if (!EmitElemOpBase(cx, cg, JSOP_GETELEM)) return false; @@ -4716,11 +4675,11 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS /* Now emit the right operand (it may affect the namespace). */ if (rhs) { - if (!js_EmitTree(cx, cg, rhs)) + if (!EmitTree(cx, cg, rhs)) return false; } else { /* The value to assign is the next enumeration value in a for-in loop. */ - if (js_Emit2(cx, cg, JSOP_ITERNEXT, offset) < 0) + if (Emit2(cx, cg, JSOP_ITERNEXT, offset) < 0) return false; } @@ -4732,10 +4691,10 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS * a bit further below) we will avoid emitting the assignment op. */ if (!lhs->isKind(TOK_NAME) || !lhs->isConst()) { - if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0) + if (NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0) return false; } - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return false; } @@ -4745,7 +4704,8 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS !lhs->isKind(TOK_RB) && !lhs->isKind(TOK_RC) && #endif - js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) { + NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + { return false; } @@ -4766,7 +4726,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS break; case TOK_LB: case TOK_LP: - if (js_Emit1(cx, cg, JSOP_SETELEM) < 0) + if (Emit1(cx, cg, JSOP_SETELEM) < 0) return false; break; #if JS_HAS_DESTRUCTURING @@ -4778,7 +4738,8 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS #endif #if JS_HAS_XML_SUPPORT case TOK_UNARYOP: - if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0) + JS_ASSERT(!cg->inStrictMode()); + if (Emit1(cx, cg, JSOP_SETXMLNAME) < 0) return false; break; #endif @@ -4790,7 +4751,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS #if defined DEBUG_brendan || defined DEBUG_mrbkap static JSBool -GettableNoteForNextOp(JSCodeGenerator *cg) +GettableNoteForNextOp(CodeGenerator *cg) { ptrdiff_t offset, target; jssrcnote *sn, *end; @@ -4809,16 +4770,16 @@ GettableNoteForNextOp(JSCodeGenerator *cg) /* Top-level named functions need a nop for decompilation. */ static JSBool -EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index) +EmitFunctionDefNop(JSContext *cx, CodeGenerator *cg, uintN index) { - return js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 && - js_Emit1(cx, cg, JSOP_NOP) >= 0; + return NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 && + Emit1(cx, cg, JSOP_NOP) >= 0; } static bool -EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum) +EmitNewInit(JSContext *cx, CodeGenerator *cg, JSProtoKey key, ParseNode *pn, int sharpnum) { - if (js_Emit3(cx, cg, JSOP_NEWINIT, (jsbytecode) key, 0) < 0) + if (Emit3(cx, cg, JSOP_NEWINIT, (jsbytecode) key, 0) < 0) return false; #if JS_HAS_SHARP_VARS if (cg->hasSharps()) { @@ -4834,18 +4795,18 @@ EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, } static bool -EmitEndInit(JSContext *cx, JSCodeGenerator *cg, uint32 count) +EmitEndInit(JSContext *cx, CodeGenerator *cg, uint32 count) { #if JS_HAS_SHARP_VARS /* Emit an op for sharp array cleanup and decompilation. */ if (cg->hasSharps() && count != 0) EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase); #endif - return js_Emit1(cx, cg, JSOP_ENDINIT) >= 0; + return Emit1(cx, cg, JSOP_ENDINIT) >= 0; } bool -JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) +ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) { switch (getKind()) { case TOK_NUMBER: @@ -4871,17 +4832,17 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) } case TOK_RB: { JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); - + JSObject *obj = NewDenseAllocatedArray(cx, pn_count); if (!obj) return false; unsigned idx = 0; - for (JSParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) { + for (ParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) { Value value; if (!pn->getConstantValue(cx, strictChecks, &value)) return false; - if (!obj->defineProperty(cx, INT_TO_JSID(idx), value, NULL, NULL, JSPROP_ENUMERATE)) + if (!obj->defineGeneric(cx, INT_TO_JSID(idx), value, NULL, NULL, JSPROP_ENUMERATE)) return false; } JS_ASSERT(idx == pn_count); @@ -4898,12 +4859,12 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) if (!obj) return false; - for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) { + for (ParseNode *pn = pn_head; pn; pn = pn->pn_next) { Value value; if (!pn->pn_right->getConstantValue(cx, strictChecks, &value)) return false; - JSParseNode *pnid = pn->pn_left; + ParseNode *pnid = pn->pn_left; if (pnid->isKind(TOK_NUMBER)) { Value idvalue = NumberValue(pnid->pn_dval); jsid id; @@ -4911,7 +4872,7 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) id = INT_TO_JSID(idvalue.toInt32()); else if (!js_InternNonIntElementId(cx, obj, idvalue, &id)) return false; - if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE)) + if (!obj->defineGeneric(cx, id, value, NULL, NULL, JSPROP_ENUMERATE)) return false; } else { JS_ASSERT(pnid->isKind(TOK_NAME) || @@ -4936,14 +4897,14 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) } static bool -EmitSingletonInitialiser(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitSingletonInitialiser(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { Value value; if (!pn->getConstantValue(cx, cg->needStrictChecks(), &value)) return false; JS_ASSERT(value.isObject()); - JSObjectBox *objbox = cg->parser->newObjectBox(&value.toObject()); + ObjectBox *objbox = cg->parser->newObjectBox(&value.toObject()); if (!objbox) return false; @@ -4956,17 +4917,14 @@ JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1); class EmitLevelManager { -private: - JSCodeGenerator *cg; - -public: - EmitLevelManager(JSCodeGenerator *cg) : cg(cg) { cg->emitLevel++; } - + CodeGenerator *cg; + public: + EmitLevelManager(CodeGenerator *cg) : cg(cg) { cg->emitLevel++; } ~EmitLevelManager() { cg->emitLevel--; } }; static bool -EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitCatch(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { ptrdiff_t catchStart, guardJump; @@ -4974,7 +4932,7 @@ EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset, * and save the block object atom. */ - JSStmtInfo *stmt = cg->topStmt; + StmtInfo *stmt = cg->topStmt; JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE)); stmt->type = STMT_CATCH; catchStart = stmt->update; @@ -4984,24 +4942,24 @@ EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY); /* Pick up the pending exception and bind it to the catch variable. */ - if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) + if (Emit1(cx, cg, JSOP_EXCEPTION) < 0) return false; /* * Dup the exception object if there is a guard for rethrowing to use * it later when rethrowing or in other catches. */ - if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0) + if (pn->pn_kid2 && Emit1(cx, cg, JSOP_DUP) < 0) return false; - JSParseNode *pn2 = pn->pn_kid1; + ParseNode *pn2 = pn->pn_kid1; switch (pn2->getKind()) { #if JS_HAS_DESTRUCTURING case TOK_RB: case TOK_RC: if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2)) return false; - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return false; break; #endif @@ -5018,12 +4976,10 @@ EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Emit the guard expression, if there is one. */ if (pn->pn_kid2) { - if (!js_EmitTree(cx, cg, pn->pn_kid2)) + if (!EmitTree(cx, cg, pn->pn_kid2)) return false; - if (!js_SetSrcNoteOffset(cx, cg, CATCHNOTE(*stmt), 0, - CG_OFFSET(cg) - catchStart)) { + if (!SetSrcNoteOffset(cx, cg, CATCHNOTE(*stmt), 0, CG_OFFSET(cg) - catchStart)) return false; - } /* ifeq */ guardJump = EmitJump(cx, cg, JSOP_IFEQ, 0); if (guardJump < 0) @@ -5031,12 +4987,12 @@ EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) GUARDJUMP(*stmt) = guardJump; /* Pop duplicated exception object as we no longer need it. */ - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return false; } /* Emit the catch body. */ - if (!js_EmitTree(cx, cg, pn->pn_kid3)) + if (!EmitTree(cx, cg, pn->pn_kid3)) return false; /* @@ -5044,15 +5000,15 @@ EmitCatch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * our TOK_LEXICALSCOPE parent, so the decompiler knows to pop. */ ptrdiff_t off = cg->stackDepth; - if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0) + if (NewSrcNote2(cx, cg, SRC_CATCH, off) < 0) return false; return true; } static bool -EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitTry(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { - JSStmtInfo stmtInfo; + StmtInfo stmtInfo; ptrdiff_t catchJump = -1; /* @@ -5064,7 +5020,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * being written into the bytecode stream and fixed-up later (c.f. * EmitBackPatchOp and BackPatch). */ - js_PushStatement(cg, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, CG_OFFSET(cg)); + PushStatement(cg, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, CG_OFFSET(cg)); /* * Since an exception can be thrown at any place inside the try block, @@ -5078,35 +5034,35 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) intN depth = cg->stackDepth; /* Mark try location for decompilation, then emit try block. */ - if (js_Emit1(cx, cg, JSOP_TRY) < 0) + if (Emit1(cx, cg, JSOP_TRY) < 0) return false; ptrdiff_t tryStart = CG_OFFSET(cg); - if (!js_EmitTree(cx, cg, pn->pn_kid1)) + if (!EmitTree(cx, cg, pn->pn_kid1)) return false; JS_ASSERT(depth == cg->stackDepth); /* GOSUB to finally, if present. */ if (pn->pn_kid3) { - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return false; if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(stmtInfo)) < 0) return false; } /* Emit (hidden) jump over catch and/or finally. */ - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return false; if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump) < 0) return false; ptrdiff_t tryEnd = CG_OFFSET(cg); - JSObjectBox *prevBox = NULL; + ObjectBox *prevBox = NULL; /* If this try has a catch block, emit it. */ - JSParseNode *lastCatch = NULL; - if (JSParseNode *pn2 = pn->pn_kid2) { + ParseNode *lastCatch = NULL; + if (ParseNode *pn2 = pn->pn_kid2) { uintN count = 0; /* previous catch block's population */ - + /* * The emitted code for a catch block looks like: * @@ -5130,7 +5086,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * also used for the catch-all trynote for capturing exceptions * thrown from catch{} blocks. */ - for (JSParseNode *pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + for (ParseNode *pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { ptrdiff_t guardJump, catchNote; JS_ASSERT(cg->stackDepth == depth); @@ -5138,7 +5094,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (guardJump != -1) { if (EmitKnownBlockChain(cx, cg, prevBox) < 0) return false; - + /* Fix up and clean up previous catch block. */ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, guardJump); @@ -5155,11 +5111,11 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * since it compensates for the hidden JSOP_DUP at the * start of the previous guarded catch. */ - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || - js_Emit1(cx, cg, JSOP_THROWING) < 0) { + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + Emit1(cx, cg, JSOP_THROWING) < 0) { return false; } - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return false; if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, prevBox)) return false; @@ -5168,12 +5124,12 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * Annotate the JSOP_ENTERBLOCK that's about to be generated - * by the call to js_EmitTree immediately below. Save this + * by the call to EmitTree immediately below. Save this * source note's index in stmtInfo for use by the TOK_CATCH: * case, where the length of the catch guard is set as the * note's offset. */ - catchNote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0); + catchNote = NewSrcNote2(cx, cg, SRC_CATCH, 0); if (catchNote < 0) return false; CATCHNOTE(stmtInfo) = catchNote; @@ -5186,7 +5142,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ASSERT(pn3->isKind(TOK_LEXICALSCOPE)); count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object); prevBox = pn3->pn_objbox; - if (!js_EmitTree(cx, cg, pn3)) + if (!EmitTree(cx, cg, pn3)) return false; /* gosub , if required */ @@ -5200,7 +5156,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Jump over the remaining catch blocks. This will get fixed * up to jump to after catch/finally. */ - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return false; if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump) < 0) return false; @@ -5222,7 +5178,7 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (lastCatch && lastCatch->pn_kid2) { if (EmitKnownBlockChain(cx, cg, prevBox) < 0) return false; - + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, GUARDJUMP(stmtInfo)); /* Sync the stack to take into account pushed exception. */ @@ -5233,10 +5189,8 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Rethrow the exception, delegating executing of finally if any * to the exception handler. */ - if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || - js_Emit1(cx, cg, JSOP_THROW) < 0) { + if (NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || Emit1(cx, cg, JSOP_THROW) < 0) return false; - } if (EmitBlockChain(cx, cg) < 0) return false; @@ -5260,17 +5214,18 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) stmtInfo.type = STMT_SUBROUTINE; if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3->pn_pos.begin.lineno)) return false; - if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 || - !js_EmitTree(cx, cg, pn->pn_kid3) || - js_Emit1(cx, cg, JSOP_RETSUB) < 0) { + if (Emit1(cx, cg, JSOP_FINALLY) < 0 || + !EmitTree(cx, cg, pn->pn_kid3) || + Emit1(cx, cg, JSOP_RETSUB) < 0) + { return false; } JS_ASSERT(cg->stackDepth == depth); } - if (!js_PopStatementCG(cx, cg)) + if (!PopStatementCG(cx, cg)) return false; - if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + if (NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || Emit1(cx, cg, JSOP_NOP) < 0) return false; /* Fix up the end-of-try/catch jumps to come here. */ @@ -5296,9 +5251,9 @@ EmitTry(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } static bool -EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitIf(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { - JSStmtInfo stmtInfo; + StmtInfo stmtInfo; /* Initialize so we can detect else-if chains and avoid recursion. */ stmtInfo.type = STMT_IF; @@ -5308,11 +5263,11 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if_again: /* Emit code for the condition before pushing stmtInfo. */ - if (!js_EmitTree(cx, cg, pn->pn_kid1)) + if (!EmitTree(cx, cg, pn->pn_kid1)) return JS_FALSE; ptrdiff_t top = CG_OFFSET(cg); if (stmtInfo.type == STMT_IF) { - js_PushStatement(cg, &stmtInfo, STMT_IF, top); + PushStatement(cg, &stmtInfo, STMT_IF, top); } else { /* * We came here from the goto further below that detects else-if @@ -5326,15 +5281,15 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ASSERT(stmtInfo.type == STMT_ELSE); stmtInfo.type = STMT_IF; stmtInfo.update = top; - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) return JS_FALSE; - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 1, top - beq)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 1, top - beq)) return JS_FALSE; } /* Emit an annotated branch-if-false around the then part. */ - JSParseNode *pn3 = pn->pn_kid3; - noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF); + ParseNode *pn3 = pn->pn_kid3; + noteIndex = NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF); if (noteIndex < 0) return JS_FALSE; beq = EmitJump(cx, cg, JSOP_IFEQ, 0); @@ -5342,7 +5297,7 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; /* Emit code for the then and optional else parts. */ - if (!js_EmitTree(cx, cg, pn->pn_kid2)) + if (!EmitTree(cx, cg, pn->pn_kid2)) return JS_FALSE; if (pn3) { /* Modify stmtInfo so we know we're in the else part. */ @@ -5350,8 +5305,8 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * Emit a JSOP_BACKPATCH op to jump from the end of our then part - * around the else part. The js_PopStatementCG call at the bottom - * of this function will fix up the backpatch chain linked from + * around the else part. The PopStatementCG call at the bottom of this + * function will fix up the backpatch chain linked from * stmtInfo.breaks. */ jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks); @@ -5365,7 +5320,7 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) goto if_again; } - if (!js_EmitTree(cx, cg, pn3)) + if (!EmitTree(cx, cg, pn3)) return JS_FALSE; /* @@ -5375,18 +5330,18 @@ EmitIf(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * jump was required to leap from the end of the then clause over * the else clause. */ - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) return JS_FALSE; } else { /* No else part, fixup the branch-if-false to come here. */ CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); } - return js_PopStatementCG(cx, cg); + return PopStatementCG(cx, cg); } #if JS_HAS_BLOCK_SCOPE static bool -EmitLet(JSContext *cx, JSCodeGenerator *cg, JSParseNode *&pn) +EmitLet(JSContext *cx, CodeGenerator *cg, ParseNode *&pn) { /* * pn represents one of these syntactic constructs: @@ -5399,7 +5354,7 @@ EmitLet(JSContext *cx, JSCodeGenerator *cg, JSParseNode *&pn) * with their variable declarations on the left and the body on the * right. */ - JSParseNode *pn2; + ParseNode *pn2; if (pn->isArity(PN_BINARY)) { pn2 = pn->pn_right; pn = pn->pn_left; @@ -5429,10 +5384,10 @@ EmitLet(JSContext *cx, JSCodeGenerator *cg, JSParseNode *&pn) return false; /* Thus non-null pn2 is the body of the let block or expression. */ - if (pn2 && !js_EmitTree(cx, cg, pn2)) + if (pn2 && !EmitTree(cx, cg, pn2)) return false; - if (noteIndex >= 0 && !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - tmp)) + if (noteIndex >= 0 && !SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - tmp)) return false; return true; @@ -5441,45 +5396,44 @@ EmitLet(JSContext *cx, JSCodeGenerator *cg, JSParseNode *&pn) #if JS_HAS_XML_SUPPORT static bool -EmitXMLTag(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitXMLTag(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { - if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + JS_ASSERT(!cg->inStrictMode()); + + if (Emit1(cx, cg, JSOP_STARTXML) < 0) return false; { jsatomid index; - JSAtom *tmp = (pn->isKind(TOK_XMLETAGO)) ? cx->runtime->atomState.etagoAtom - : cx->runtime->atomState.stagoAtom; - if (!cg->makeAtomIndex(tmp, &index)) + JSAtom *tagAtom = (pn->isKind(TOK_XMLETAGO)) + ? cx->runtime->atomState.etagoAtom + : cx->runtime->atomState.stagoAtom; + if (!cg->makeAtomIndex(tagAtom, &index)) return false; EMIT_INDEX_OP(JSOP_STRING, index); } JS_ASSERT(pn->pn_count != 0); - JSParseNode *pn2 = pn->pn_head; - if (pn2->isKind(TOK_LC) && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) + ParseNode *pn2 = pn->pn_head; + if (pn2->isKind(TOK_LC) && Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) return false; - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return false; - if (js_Emit1(cx, cg, JSOP_ADD) < 0) + if (Emit1(cx, cg, JSOP_ADD) < 0) return false; uint32 i; for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) { - if (pn2->isKind(TOK_LC) && - js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + if (pn2->isKind(TOK_LC) && Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) return false; - } - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return false; if ((i & 1) && pn2->isKind(TOK_LC)) { - if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0) + if (Emit1(cx, cg, JSOP_TOATTRVAL) < 0) return false; } - if (js_Emit1(cx, cg, - (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) { + if (Emit1(cx, cg, (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) return false; - } } { @@ -5490,18 +5444,20 @@ EmitXMLTag(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return false; EMIT_INDEX_OP(JSOP_STRING, index); } - if (js_Emit1(cx, cg, JSOP_ADD) < 0) + if (Emit1(cx, cg, JSOP_ADD) < 0) return false; - if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, pn->getOp()) < 0) + if ((pn->pn_xflags & PNX_XMLROOT) && Emit1(cx, cg, pn->getOp()) < 0) return false; return true; } static bool -EmitXMLProcessingInstruction(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +EmitXMLProcessingInstruction(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { + JS_ASSERT(!cg->inStrictMode()); + jsatomid index; if (!cg->makeAtomIndex(pn->pn_pidata, &index)) return false; @@ -5514,12 +5470,12 @@ EmitXMLProcessingInstruction(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn #endif static bool -EmitLexicalScope(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSBool &ok) +EmitLexicalScope(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool &ok) { - JSStmtInfo stmtInfo; - JSStmtInfo *stmt; - JSObjectBox *objbox = pn->pn_objbox; - js_PushBlockScope(cg, &stmtInfo, objbox, CG_OFFSET(cg)); + StmtInfo stmtInfo; + StmtInfo *stmt; + ObjectBox *objbox = pn->pn_objbox; + PushBlockScope(cg, &stmtInfo, objbox, CG_OFFSET(cg)); /* * If this lexical scope is not for a catch block, let block or let @@ -5541,7 +5497,7 @@ EmitLexicalScope(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSBool &ok CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) || !GettableNoteForNextOp(cg)); #endif - noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); + noteIndex = NewSrcNote2(cx, cg, SRC_BRACE, 0); if (noteIndex < 0) return false; } @@ -5550,52 +5506,49 @@ EmitLexicalScope(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSBool &ok if (!EmitEnterBlock(cx, pn, cg)) return false; - if (!js_EmitTree(cx, cg, pn->pn_expr)) + if (!EmitTree(cx, cg, pn->pn_expr)) return false; JSOp op = pn->getOp(); if (op == JSOP_LEAVEBLOCKEXPR) { - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) return false; } else { - if (noteIndex >= 0 && - !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, - CG_OFFSET(cg) - top)) { + if (noteIndex >= 0 && !SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - top)) return false; - } } /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */ if (!EmitLeaveBlock(cx, cg, op, objbox)) return false; - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); return true; } static bool -EmitWith(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSBool &ok) +EmitWith(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool &ok) { - JSStmtInfo stmtInfo; - if (!js_EmitTree(cx, cg, pn->pn_left)) + StmtInfo stmtInfo; + if (!EmitTree(cx, cg, pn->pn_left)) return false; - js_PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg)); - if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) + PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg)); + if (Emit1(cx, cg, JSOP_ENTERWITH) < 0) return false; /* Make blockChain determination quicker. */ if (EmitBlockChain(cx, cg) < 0) return false; - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return false; - if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + if (Emit1(cx, cg, JSOP_LEAVEWITH) < 0) return false; - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); return true; } static bool -SetMethodFunction(JSContext *cx, JSFunctionBox *funbox, JSAtom *atom) +SetMethodFunction(JSContext *cx, FunctionBox *funbox, JSAtom *atom) { /* Replace a boxed function with a new one with a method atom. */ JSFunction *fun = js_NewFunction(cx, NULL, NULL, @@ -5620,23 +5573,310 @@ SetMethodFunction(JSContext *cx, JSFunctionBox *funbox, JSAtom *atom) fun->setMethodAtom(atom); funbox->object = fun; - return true; } +static bool +EmitForIn(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top) +{ + StmtInfo stmtInfo; + PushStatement(cg, &stmtInfo, STMT_FOR_IN_LOOP, top); + + ParseNode *forHead = pn->pn_left; + ParseNode *forBody = pn->pn_right; + + /* + * If the left part is 'var x', emit code to define x if necessary + * using a prolog opcode, but do not emit a pop. If the left part + * was originally 'var x = i', the parser will have rewritten it; + * see Parser::forStatement. 'for (let x = i in o)' is mercifully + * banned. + */ + bool forLet = false; + if (ParseNode *decl = forHead->pn_kid1) { + JS_ASSERT(TokenKindIsDecl(decl->getKind())); + forLet = decl->isKind(TOK_LET); + cg->flags |= TCF_IN_FOR_INIT; + if (!EmitTree(cx, cg, decl)) + return false; + cg->flags &= ~TCF_IN_FOR_INIT; + } + + /* Compile the object expression to the right of 'in'. */ + { + TempPopScope tps; + if (forLet && !tps.popBlock(cx, cg)) + return false; + if (!EmitTree(cx, cg, forHead->pn_kid3)) + return false; + if (forLet && !tps.repushBlock(cx, cg)) + return false; + } + + /* + * Emit a bytecode to convert top of stack value to the iterator + * object depending on the loop variant (for-in, for-each-in, or + * destructuring for-in). + */ + JS_ASSERT(pn->isOp(JSOP_ITER)); + if (Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0) + return false; + + /* Annotate so the decompiler can find the loop-closing jump. */ + intN noteIndex = NewSrcNote(cx, cg, SRC_FOR_IN); + if (noteIndex < 0) + return false; + + /* + * Jump down to the loop condition to minimize overhead assuming at + * least one iteration, as the other loop forms do. + */ + ptrdiff_t jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return false; + + intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return false; + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + if (EmitTraceOp(cx, cg, NULL) < 0) + return false; + +#ifdef DEBUG + intN loopDepth = cg->stackDepth; +#endif + + /* + * Emit code to get the next enumeration value and assign it to the + * left hand side. The JSOP_POP after this assignment is annotated + * so that the decompiler can distinguish 'for (x in y)' from + * 'for (var x in y)'. + */ + if (!EmitAssignment(cx, cg, forHead->pn_kid2, JSOP_NOP, NULL)) + return false; + ptrdiff_t tmp2 = CG_OFFSET(cg); + if (forHead->pn_kid1 && NewSrcNote2(cx, cg, SRC_DECL, + (forHead->pn_kid1->isOp(JSOP_DEFVAR)) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) { + return false; + } + if (Emit1(cx, cg, JSOP_POP) < 0) + return false; + + /* The stack should be balanced around the assignment opcode sequence. */ + JS_ASSERT(cg->stackDepth == loopDepth); + + /* Emit code for the loop body. */ + if (!EmitTree(cx, cg, forBody)) + return false; + + /* Set loop and enclosing "update" offsets, for continue. */ + StmtInfo *stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* + * Fixup the goto that starts the loop to jump down to JSOP_MOREITER. + */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (Emit1(cx, cg, JSOP_MOREITER) < 0) + return false; + ptrdiff_t beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return false; + + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top)) + return false; + /* Set the first srcnote offset so we can find the start of the loop body. */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp)) + return false; + /* Set the second srcnote offset so we can find the closing jump. */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp)) + return false; + + /* Now fixup all breaks and continues (before the JSOP_ENDITER). */ + if (!PopStatementCG(cx, cg)) + return false; + + if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg))) + return false; + + return Emit1(cx, cg, JSOP_ENDITER) >= 0; +} + +static bool +EmitNormalFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top) +{ + StmtInfo stmtInfo; + PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top); + + ParseNode *forHead = pn->pn_left; + ParseNode *forBody = pn->pn_right; + + /* C-style for (init; cond; update) ... loop. */ + JSOp op = JSOP_POP; + ParseNode *pn3 = forHead->pn_kid1; + if (!pn3) { + /* No initializer: emit an annotated nop for the decompiler. */ + op = JSOP_NOP; + } else { + cg->flags |= TCF_IN_FOR_INIT; +#if JS_HAS_DESTRUCTURING + if (pn3->isKind(TOK_ASSIGN) && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return false; + } +#endif + if (op == JSOP_POP) { + if (!EmitTree(cx, cg, pn3)) + return false; + if (TokenKindIsDecl(pn3->getKind())) { + /* + * Check whether a destructuring-initialized var decl + * was optimized to a group assignment. If so, we do + * not need to emit a pop below, so switch to a nop, + * just for the decompiler. + */ + JS_ASSERT(pn3->isArity(PN_LIST)); + if (pn3->pn_xflags & PNX_GROUPINIT) + op = JSOP_NOP; + } + } + cg->flags &= ~TCF_IN_FOR_INIT; + } + + /* + * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH). + * Use tmp to hold the biased srcnote "top" offset, which differs + * from the top local variable by the length of the JSOP_GOTO{,X} + * emitted in between tmp and top if this loop has a condition. + */ + intN noteIndex = NewSrcNote(cx, cg, SRC_FOR); + if (noteIndex < 0 || Emit1(cx, cg, op) < 0) + return false; + ptrdiff_t tmp = CG_OFFSET(cg); + + ptrdiff_t jmp = -1; + if (forHead->pn_kid2) { + /* Goto the loop condition, which branches back to iterate. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return false; + } + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + + intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return false; + + /* Emit code for the loop body. */ + if (EmitTraceOp(cx, cg, forBody) < 0) + return false; + if (!EmitTree(cx, cg, forBody)) + return false; + + /* Set the second note offset so we can find the update part. */ + JS_ASSERT(noteIndex != -1); + ptrdiff_t tmp2 = CG_OFFSET(cg); + + /* Set loop and enclosing "update" offsets, for continue. */ + StmtInfo *stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* Check for update code to do before the condition (if any). */ + pn3 = forHead->pn_kid3; + if (pn3) { + op = JSOP_POP; +#if JS_HAS_DESTRUCTURING + if (pn3->isKind(TOK_ASSIGN) && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return false; + } +#endif + if (op == JSOP_POP && !EmitTree(cx, cg, pn3)) + return false; + + /* Always emit the POP or NOP, to help the decompiler. */ + if (Emit1(cx, cg, op) < 0) + return false; + + /* Restore the absolute line number for source note readers. */ + ptrdiff_t lineno = pn->pn_pos.end.lineno; + if (CG_CURRENT_LINE(cg) != (uintN) lineno) { + if (NewSrcNote2(cx, cg, SRC_SETLINE, lineno) < 0) + return false; + CG_CURRENT_LINE(cg) = (uintN) lineno; + } + } + + ptrdiff_t tmp3 = CG_OFFSET(cg); + + if (forHead->pn_kid2) { + /* Fix up the goto from top to target the loop condition. */ + JS_ASSERT(jmp >= 0); + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + + if (!EmitTree(cx, cg, forHead->pn_kid2)) + return false; + } + + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, CG_OFFSET(cg) - top)) + return false; + /* Set the first note offset so we can find the loop condition. */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp3 - tmp)) + return false; + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, tmp2 - tmp)) + return false; + /* The third note offset helps us find the loop-closing jump. */ + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, CG_OFFSET(cg) - tmp)) + return false; + + /* If no loop condition, just emit a loop-closing jump. */ + op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO; + if (EmitJump(cx, cg, op, top - CG_OFFSET(cg)) < 0) + return false; + + /* Now fixup all breaks and continues. */ + return PopStatementCG(cx, cg); +} + +static inline bool +EmitFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top) +{ + return pn->pn_left->isKind(TOK_IN) + ? EmitForIn(cx, cg, pn, top) + : EmitNormalFor(cx, cg, pn, top); +} + JSBool -js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +frontend::EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn) { JSBool useful, wantval; - JSStmtInfo stmtInfo; - JSStmtInfo *stmt; - ptrdiff_t top, off, tmp, beq, jmp, tmp2, tmp3; - JSParseNode *pn2, *pn3; + StmtInfo stmtInfo; + StmtInfo *stmt; + ptrdiff_t top, off, tmp, beq, jmp; + ParseNode *pn2, *pn3; JSAtom *atom; jsatomid atomIndex; uintN index; ptrdiff_t noteIndex, noteIndex2; - JSSrcNoteType noteType; + SrcNoteType noteType; jsbytecode *pc; JSOp op; uint32 argc; @@ -5661,7 +5901,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_XML_SUPPORT if (pn->isArity(PN_NULLARY)) { - if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0) + if (Emit1(cx, cg, JSOP_GETFUNNS) < 0) return JS_FALSE; break; } @@ -5686,7 +5926,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) fun->kind() == JSFUN_INTERPRETED); /* Generate code for the function's body. */ - JSCodeGenerator *cg2 = cx->new_(cg->parser, pn->pn_pos.begin.lineno); + CodeGenerator *cg2 = cx->new_(cg->parser, pn->pn_pos.begin.lineno); if (!cg2) { js_ReportOutOfMemory(cx); return JS_FALSE; @@ -5709,15 +5949,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) cg2->parent = cg; /* - * jsparse.cpp:SetStaticLevel limited static nesting depth to fit in 16 - * bits and to reserve the all-ones value, thereby reserving the magic - * FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment below. + * js::frontend::SetStaticLevel limited static nesting depth to fit in + * 16 bits and to reserve the all-ones value, thereby reserving the + * magic FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment + * below. */ JS_ASSERT(cg->staticLevel < JS_BITMASK(16) - 1); cg2->staticLevel = cg->staticLevel + 1; /* We measured the max scope depth when we parsed the function. */ - if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) + if (!EmitFunctionScript(cx, cg2, pn->pn_body)) pn = NULL; cx->delete_(cg2); @@ -5732,7 +5973,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) op = pn->getOp(); if (op != JSOP_NOP) { if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) && - js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) { + NewSrcNote(cx, cg, SRC_GENEXP) < 0) + { return JS_FALSE; } EMIT_INDEX_OP(op, index); @@ -5749,7 +5991,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * names in the variable object before the already-generated main code * is executed. This extra work for top-level scripts is not necessary * when we emit the code for a function. It is fully parsed prior to - * invocation of the emitter and calls to js_EmitTree for function + * invocation of the emitter and calls to EmitTree for function * definitions can be scheduled before generating the rest of code. */ if (!cg->inFunction()) { @@ -5793,8 +6035,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_ARGSBODY: { - JSParseNode *pnlast = pn->last(); - for (JSParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) { + ParseNode *pnlast = pn->last(); + for (ParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) { if (!pn2->isDefn()) continue; if (!BindNameToSlot(cx, cg, pn2)) @@ -5804,14 +6046,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; } } - ok = js_EmitTree(cx, cg, pnlast); + ok = EmitTree(cx, cg, pnlast); break; } case TOK_UPVARS: JS_ASSERT(pn->pn_names->count() != 0); cg->roLexdeps = pn->pn_names; - ok = js_EmitTree(cx, cg, pn->pn_tree); + ok = EmitTree(cx, cg, pn->pn_tree); cg->roLexdeps.clearMap(); pn->pn_names.releaseMap(cx); break; @@ -5839,29 +6081,29 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail * * SpiderMonkey, pre-mozilla.org, emitted while parsing and so used - * test at the top. When JSParseNode trees were added during the ES3 + * test at the top. When ParseNode trees were added during the ES3 * work (1998-9), the code generation scheme was not optimized, and * the decompiler continued to take advantage of the branch and jump * that bracketed the body. But given the SRC_WHILE note, it is easy * to support the more efficient scheme. */ - js_PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top); - noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); + PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top); + noteIndex = NewSrcNote(cx, cg, SRC_WHILE); if (noteIndex < 0) return JS_FALSE; jmp = EmitJump(cx, cg, JSOP_GOTO, 0); if (jmp < 0) return JS_FALSE; - noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE); if (noteIndex2 < 0) return JS_FALSE; top = EmitTraceOp(cx, cg, pn->pn_right); if (top < 0) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return JS_FALSE; CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); - if (!js_EmitTree(cx, cg, pn->pn_left)) + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); if (beq < 0) @@ -5870,20 +6112,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex * note gets bigger. */ - if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) + if (!SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) return JS_FALSE; - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp)) return JS_FALSE; - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); break; case TOK_DO: /* Emit an annotated nop so we know to decompile a 'do' keyword. */ - noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); - if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + noteIndex = NewSrcNote(cx, cg, SRC_WHILE); + if (noteIndex < 0 || Emit1(cx, cg, JSOP_NOP) < 0) return JS_FALSE; - noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE); if (noteIndex2 < 0) return JS_FALSE; @@ -5891,8 +6133,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) top = EmitTraceOp(cx, cg, pn->pn_left); if (top < 0) return JS_FALSE; - js_PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top); - if (!js_EmitTree(cx, cg, pn->pn_left)) + PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top); + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; /* Set loop and enclosing label update offsets, for continue. */ @@ -5903,7 +6145,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); /* Compile the loop condition, now that continues know where to go. */ - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return JS_FALSE; /* @@ -5918,295 +6160,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex * note gets bigger. */ - if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) + if (!SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) return JS_FALSE; - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (off - top))) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (off - top))) return JS_FALSE; - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); break; case TOK_FOR: - beq = 0; /* suppress gcc warnings */ - jmp = -1; - pn2 = pn->pn_left; - js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top); - - if (pn2->isKind(TOK_IN)) { - /* Set stmtInfo type for later testing. */ - stmtInfo.type = STMT_FOR_IN_LOOP; - - /* - * If the left part is 'var x', emit code to define x if necessary - * using a prolog opcode, but do not emit a pop. If the left part - * was originally 'var x = i', the parser will have rewritten it; - * see Parser::forStatement. 'for (let x = i in o)' is mercifully - * banned. - */ - bool forLet = false; - if (JSParseNode *decl = pn2->pn_kid1) { - JS_ASSERT(TokenKindIsDecl(decl->getKind())); - forLet = decl->isKind(TOK_LET); - cg->flags |= TCF_IN_FOR_INIT; - if (!js_EmitTree(cx, cg, decl)) - return JS_FALSE; - cg->flags &= ~TCF_IN_FOR_INIT; - } - - /* Compile the object expression to the right of 'in'. */ - { - TempPopScope tps; - if (forLet && !tps.popBlock(cx, cg)) - return JS_FALSE; - if (!js_EmitTree(cx, cg, pn2->pn_kid3)) - return JS_FALSE; - if (forLet && !tps.repushBlock(cx, cg)) - return JS_FALSE; - } - - /* - * Emit a bytecode to convert top of stack value to the iterator - * object depending on the loop variant (for-in, for-each-in, or - * destructuring for-in). - */ - JS_ASSERT(pn->isOp(JSOP_ITER)); - if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0) - return JS_FALSE; - - /* Annotate so the decompiler can find the loop-closing jump. */ - noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN); - if (noteIndex < 0) - return JS_FALSE; - - /* - * Jump down to the loop condition to minimize overhead assuming at - * least one iteration, as the other loop forms do. - */ - jmp = EmitJump(cx, cg, JSOP_GOTO, 0); - if (jmp < 0) - return JS_FALSE; - - noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); - if (noteIndex2 < 0) - return JS_FALSE; - - top = CG_OFFSET(cg); - SET_STATEMENT_TOP(&stmtInfo, top); - if (EmitTraceOp(cx, cg, NULL) < 0) - return JS_FALSE; - -#ifdef DEBUG - intN loopDepth = cg->stackDepth; -#endif - - /* - * Emit code to get the next enumeration value and assign it to the - * left hand side. The JSOP_POP after this assignment is annotated - * so that the decompiler can distinguish 'for (x in y)' from - * 'for (var x in y)'. - */ - if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL)) - return false; - tmp2 = CG_OFFSET(cg); - if (pn2->pn_kid1 && js_NewSrcNote2(cx, cg, SRC_DECL, - (pn2->pn_kid1->isOp(JSOP_DEFVAR)) - ? SRC_DECL_VAR - : SRC_DECL_LET) < 0) { - return false; - } - if (js_Emit1(cx, cg, JSOP_POP) < 0) - return false; - - /* The stack should be balanced around the assignment opcode sequence. */ - JS_ASSERT(cg->stackDepth == loopDepth); - - /* Emit code for the loop body. */ - if (!js_EmitTree(cx, cg, pn->pn_right)) - return JS_FALSE; - - /* Set loop and enclosing "update" offsets, for continue. */ - stmt = &stmtInfo; - do { - stmt->update = CG_OFFSET(cg); - } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); - - /* - * Fixup the goto that starts the loop to jump down to JSOP_MOREITER. - */ - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); - if (js_Emit1(cx, cg, JSOP_MOREITER) < 0) - return JS_FALSE; - beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); - if (beq < 0) - return JS_FALSE; - - /* - * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex - * note gets bigger. - */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top)) - return JS_FALSE; - /* Set the first srcnote offset so we can find the start of the loop body. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp)) - return JS_FALSE; - /* Set the second srcnote offset so we can find the closing jump. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp)) - return JS_FALSE; - } else { - /* C-style for (init; cond; update) ... loop. */ - op = JSOP_POP; - pn3 = pn2->pn_kid1; - if (!pn3) { - /* No initializer: emit an annotated nop for the decompiler. */ - op = JSOP_NOP; - } else { - cg->flags |= TCF_IN_FOR_INIT; -#if JS_HAS_DESTRUCTURING - if (pn3->isKind(TOK_ASSIGN) && - !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { - return JS_FALSE; - } -#endif - if (op == JSOP_POP) { - if (!js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - if (TokenKindIsDecl(pn3->getKind())) { - /* - * Check whether a destructuring-initialized var decl - * was optimized to a group assignment. If so, we do - * not need to emit a pop below, so switch to a nop, - * just for the decompiler. - */ - JS_ASSERT(pn3->isArity(PN_LIST)); - if (pn3->pn_xflags & PNX_GROUPINIT) - op = JSOP_NOP; - } - } - cg->flags &= ~TCF_IN_FOR_INIT; - } - - /* - * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH). - * Use tmp to hold the biased srcnote "top" offset, which differs - * from the top local variable by the length of the JSOP_GOTO{,X} - * emitted in between tmp and top if this loop has a condition. - */ - noteIndex = js_NewSrcNote(cx, cg, SRC_FOR); - if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0) - return JS_FALSE; - tmp = CG_OFFSET(cg); - - if (pn2->pn_kid2) { - /* Goto the loop condition, which branches back to iterate. */ - jmp = EmitJump(cx, cg, JSOP_GOTO, 0); - if (jmp < 0) - return JS_FALSE; - } - - top = CG_OFFSET(cg); - SET_STATEMENT_TOP(&stmtInfo, top); - - noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); - if (noteIndex2 < 0) - return JS_FALSE; - - /* Emit code for the loop body. */ - if (EmitTraceOp(cx, cg, pn->pn_right) < 0) - return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) - return JS_FALSE; - - /* Set the second note offset so we can find the update part. */ - JS_ASSERT(noteIndex != -1); - tmp2 = CG_OFFSET(cg); - - /* Set loop and enclosing "update" offsets, for continue. */ - stmt = &stmtInfo; - do { - stmt->update = CG_OFFSET(cg); - } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); - - /* Check for update code to do before the condition (if any). */ - pn3 = pn2->pn_kid3; - if (pn3) { - op = JSOP_POP; -#if JS_HAS_DESTRUCTURING - if (pn3->isKind(TOK_ASSIGN) && - !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { - return JS_FALSE; - } -#endif - if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3)) - return JS_FALSE; - - /* Always emit the POP or NOP, to help the decompiler. */ - if (js_Emit1(cx, cg, op) < 0) - return JS_FALSE; - - /* Restore the absolute line number for source note readers. */ - off = (ptrdiff_t) pn->pn_pos.end.lineno; - if (CG_CURRENT_LINE(cg) != (uintN) off) { - if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0) - return JS_FALSE; - CG_CURRENT_LINE(cg) = (uintN) off; - } - } - - tmp3 = CG_OFFSET(cg); - - if (pn2->pn_kid2) { - /* Fix up the goto from top to target the loop condition. */ - JS_ASSERT(jmp >= 0); - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); - - if (!js_EmitTree(cx, cg, pn2->pn_kid2)) - return JS_FALSE; - } - - /* - * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex - * note gets bigger. - */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, - CG_OFFSET(cg) - top)) { - return JS_FALSE; - } - /* Set the first note offset so we can find the loop condition. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, - tmp3 - tmp)) { - return JS_FALSE; - } - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, - tmp2 - tmp)) { - return JS_FALSE; - } - /* The third note offset helps us find the loop-closing jump. */ - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, - CG_OFFSET(cg) - tmp)) { - return JS_FALSE; - } - - if (pn2->pn_kid2) { - beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); - if (beq < 0) - return JS_FALSE; - } else { - /* No loop condition -- emit the loop-closing jump. */ - jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg)); - if (jmp < 0) - return JS_FALSE; - } - } - - /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */ - if (!js_PopStatementCG(cx, cg)) - return JS_FALSE; - - if (pn2->isKind(TOK_IN)) { - if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) || - js_Emit1(cx, cg, JSOP_ENDITER) < 0) { - return JS_FALSE; - } - } + ok = EmitFor(cx, cg, pn, top); break; case TOK_BREAK: { @@ -6240,7 +6202,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) jsatomid labelIndex; if (atom) { /* Find the loop statement enclosed by the matching label. */ - JSStmtInfo *loop = NULL; + StmtInfo *loop = NULL; if (!cg->makeAtomIndex(atom, &labelIndex)) return JS_FALSE; while (stmt->type != STMT_LABEL || stmt->label != atom) { @@ -6286,10 +6248,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Push a return value */ pn2 = pn->pn_kid; if (pn2) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; } else { - if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + if (Emit1(cx, cg, JSOP_PUSH) < 0) return JS_FALSE; } @@ -6305,13 +6267,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * extra JSOP_RETRVAL after the fixups. */ top = CG_OFFSET(cg); - if (js_Emit1(cx, cg, JSOP_RETURN) < 0) + if (Emit1(cx, cg, JSOP_RETURN) < 0) return JS_FALSE; if (!EmitNonLocalJumpFixup(cx, cg, NULL)) return JS_FALSE; if (top + JSOP_RETURN_LENGTH != CG_OFFSET(cg)) { CG_BASE(cg)[top] = JSOP_SETRVAL; - if (js_Emit1(cx, cg, JSOP_RETRVAL) < 0) + if (Emit1(cx, cg, JSOP_RETRVAL) < 0) return JS_FALSE; if (EmitBlockChain(cx, cg) < 0) return JS_FALSE; @@ -6322,15 +6284,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_YIELD: JS_ASSERT(cg->inFunction()); if (pn->pn_kid) { - if (!js_EmitTree(cx, cg, pn->pn_kid)) + if (!EmitTree(cx, cg, pn->pn_kid)) return JS_FALSE; } else { - if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + if (Emit1(cx, cg, JSOP_PUSH) < 0) return JS_FALSE; } - if (pn->pn_hidden && js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + if (pn->pn_hidden && NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_YIELD) < 0) + if (Emit1(cx, cg, JSOP_YIELD) < 0) return JS_FALSE; break; #endif @@ -6339,9 +6301,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) { #if JS_HAS_XML_SUPPORT if (pn->isArity(PN_UNARY)) { - if (!js_EmitTree(cx, cg, pn->pn_kid)) + if (!EmitTree(cx, cg, pn->pn_kid)) return JS_FALSE; - if (js_Emit1(cx, cg, pn->getOp()) < 0) + if (Emit1(cx, cg, pn->getOp()) < 0) return JS_FALSE; break; } @@ -6352,14 +6314,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) noteIndex = -1; tmp = CG_OFFSET(cg); if (pn->pn_xflags & PNX_NEEDBRACES) { - noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); - if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + noteIndex = NewSrcNote2(cx, cg, SRC_BRACE, 0); + if (noteIndex < 0 || Emit1(cx, cg, JSOP_NOP) < 0) return JS_FALSE; } - js_PushStatement(cg, &stmtInfo, STMT_BLOCK, top); + PushStatement(cg, &stmtInfo, STMT_BLOCK, top); - JSParseNode *pnchild = pn->pn_head; + ParseNode *pnchild = pn->pn_head; if (pn->pn_xflags & PNX_FUNCDEFS) { /* * This block contains top-level function definitions. To ensure @@ -6380,7 +6342,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ JS_ASSERT(pnchild->isKind(TOK_SEMI)); JS_ASSERT(pnchild->pn_kid->isKind(TOK_VAR)); - if (!js_EmitTree(cx, cg, pnchild)) + if (!EmitTree(cx, cg, pnchild)) return JS_FALSE; pnchild = pnchild->pn_next; } @@ -6388,7 +6350,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) { if (pn2->isKind(TOK_FUNCTION)) { if (pn2->isOp(JSOP_NOP)) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; } else { /* @@ -6403,28 +6365,25 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } } for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; } - if (noteIndex >= 0 && - !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, - CG_OFFSET(cg) - tmp)) { + if (noteIndex >= 0 && !SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - tmp)) return JS_FALSE; - } - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); break; } case TOK_SEQ: JS_ASSERT(pn->isArity(PN_LIST)); - js_PushStatement(cg, &stmtInfo, STMT_SEQ, top); + PushStatement(cg, &stmtInfo, STMT_SEQ, top); for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; } - ok = js_PopStatementCG(cx, cg); + ok = PopStatementCG(cx, cg); break; case TOK_SEMI: @@ -6450,8 +6409,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * Don't eliminate apparently useless expressions if they are * labeled expression statements. The tc->topStmt->update test - * catches the case where we are nesting in js_EmitTree for a - * labeled compound statement. + * catches the case where we are nesting in EmitTree for a labeled + * compound statement. */ if (!useful && cg->topStmt && @@ -6497,9 +6456,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; pn2->pn_left->setOp(JSOP_SETMETHOD); } - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } } @@ -6520,24 +6479,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn2->expr()->isKind(TOK_LC))) ? SRC_LABELBRACE : SRC_LABEL; - noteIndex = js_NewSrcNote2(cx, cg, noteType, ptrdiff_t(index)); - if (noteIndex < 0 || - js_Emit1(cx, cg, JSOP_NOP) < 0) { + noteIndex = NewSrcNote2(cx, cg, noteType, ptrdiff_t(index)); + if (noteIndex < 0 || Emit1(cx, cg, JSOP_NOP) < 0) return JS_FALSE; - } /* Emit code for the labeled statement. */ - js_PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg)); + PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg)); stmtInfo.label = atom; - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (!js_PopStatementCG(cx, cg)) + if (!PopStatementCG(cx, cg)) return JS_FALSE; /* If the statement was compound, emit a note for the end brace. */ if (noteType == SRC_LABELBRACE) { - if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || - js_Emit1(cx, cg, JSOP_NOP) < 0) { + if (NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || + Emit1(cx, cg, JSOP_NOP) < 0) { return JS_FALSE; } } @@ -6551,19 +6508,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ off = noteIndex = -1; for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; tmp = CG_OFFSET(cg); if (noteIndex >= 0) { - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) return JS_FALSE; } if (!pn2->pn_next) break; off = tmp; - noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + noteIndex = NewSrcNote2(cx, cg, SRC_PCDELTA, 0); if (noteIndex < 0 || - js_Emit1(cx, cg, JSOP_POP) < 0) { + Emit1(cx, cg, JSOP_POP) < 0) { return JS_FALSE; } } @@ -6576,13 +6533,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_HOOK: /* Emit the condition, then branch if false to the else part. */ - if (!js_EmitTree(cx, cg, pn->pn_kid1)) + if (!EmitTree(cx, cg, pn->pn_kid1)) return JS_FALSE; - noteIndex = js_NewSrcNote(cx, cg, SRC_COND); + noteIndex = NewSrcNote(cx, cg, SRC_COND); if (noteIndex < 0) return JS_FALSE; beq = EmitJump(cx, cg, JSOP_IFEQ, 0); - if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2)) + if (beq < 0 || !EmitTree(cx, cg, pn->pn_kid2)) return JS_FALSE; /* Jump around else, fixup the branch, emit else, fixup jump. */ @@ -6605,10 +6562,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ JS_ASSERT(cg->stackDepth > 0); cg->stackDepth--; - if (!js_EmitTree(cx, cg, pn->pn_kid3)) + if (!EmitTree(cx, cg, pn->pn_kid3)) return JS_FALSE; CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); - if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + if (!SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) return JS_FALSE; break; @@ -6625,12 +6582,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * it pops and falls into the right operand's bytecode. */ if (pn->isArity(PN_BINARY)) { - if (!js_EmitTree(cx, cg, pn->pn_left)) + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); if (top < 0) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return JS_FALSE; off = CG_OFFSET(cg); pc = CG_CODE(cg, top); @@ -6642,7 +6599,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Left-associative operator chain: avoid too much recursion. */ pn2 = pn->pn_head; - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); if (top < 0) @@ -6651,7 +6608,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Emit nodes between the head and the tail. */ jmp = top; while ((pn2 = pn2->pn_next)->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); if (off < 0) @@ -6661,7 +6618,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) jmp = off; } - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; pn2 = pn->pn_head; @@ -6691,13 +6648,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn->isArity(PN_LIST)) { /* Left-associative operator chain: avoid too much recursion. */ pn2 = pn->pn_head; - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; op = pn->getOp(); while ((pn2 = pn2->pn_next) != NULL) { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } } else { @@ -6706,7 +6663,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_DBLCOLON: if (pn->isArity(PN_NAME)) { - if (!js_EmitTree(cx, cg, pn->expr())) + if (!EmitTree(cx, cg, pn->expr())) return JS_FALSE; if (!EmitAtomOp(cx, pn, pn->getOp(), cg)) return JS_FALSE; @@ -6723,14 +6680,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #endif /* Binary operators that evaluate both operands unconditionally. */ - if (!js_EmitTree(cx, cg, pn->pn_left)) + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return JS_FALSE; #if JS_HAS_XML_SUPPORT cg->flags |= oldflags & TCF_IN_FOR_INIT; #endif - if (js_Emit1(cx, cg, pn->getOp()) < 0) + if (Emit1(cx, cg, pn->getOp()) < 0) return JS_FALSE; } break; @@ -6762,10 +6719,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) oldflags = cg->flags; cg->flags &= ~TCF_IN_FOR_INIT; - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; cg->flags |= oldflags & TCF_IN_FOR_INIT; - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; break; } @@ -6784,7 +6741,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; op = pn2->getOp(); if (op == JSOP_CALLEE) { - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } else if (!pn2->pn_cookie.isFree()) { atomIndex = pn2->pn_cookie.asInteger(); @@ -6801,14 +6758,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) break; } if (pn2->isConst()) { - if (js_Emit1(cx, cg, JSOP_POS) < 0) + if (Emit1(cx, cg, JSOP_POS) < 0) return JS_FALSE; op = pn->getOp(); if (!(js_CodeSpec[op].format & JOF_POST)) { - if (js_Emit1(cx, cg, JSOP_ONE) < 0) + if (Emit1(cx, cg, JSOP_ONE) < 0) return JS_FALSE; op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB; - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } } @@ -6822,13 +6779,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; break; case TOK_LP: - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, - CG_OFFSET(cg) - pn2->pn_offset) < 0) { + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0) return JS_FALSE; - } - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; /* * This is dead code for the decompiler, don't generate @@ -6837,17 +6792,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ JS_ASSERT(js_CodeSpec[op].format & JOF_DECOMPOSE); JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM); - if (js_Emit1(cx, cg, (JSOp)1) < 0) + if (Emit1(cx, cg, (JSOp)1) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_POP) < 0) + if (Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; break; #if JS_HAS_XML_SUPPORT case TOK_UNARYOP: + JS_ASSERT(!cg->inStrictMode()); JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME)); - if (!js_EmitTree(cx, cg, pn2->pn_kid)) + if (!EmitTree(cx, cg, pn2->pn_kid)) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + if (Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) return JS_FALSE; if (!EmitElemIncDec(cx, NULL, op, cg)) return JS_FALSE; @@ -6868,7 +6824,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; op = pn2->getOp(); if (op == JSOP_FALSE) { - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } else { if (!EmitAtomOp(cx, pn2, op, cg)) @@ -6881,6 +6837,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) break; #if JS_HAS_XML_SUPPORT case TOK_DBLDOT: + JS_ASSERT(!cg->inStrictMode()); if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg)) return JS_FALSE; break; @@ -6901,18 +6858,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) off = noteIndex = -1; } else { JS_ASSERT_IF(pn2->isKind(TOK_LP), !(pn2->pn_xflags & PNX_SETCALL)); - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; off = CG_OFFSET(cg); - noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); - if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + noteIndex = NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || Emit1(cx, cg, JSOP_POP) < 0) return JS_FALSE; } - if (js_Emit1(cx, cg, JSOP_TRUE) < 0) + if (Emit1(cx, cg, JSOP_TRUE) < 0) return JS_FALSE; if (noteIndex >= 0) { tmp = CG_OFFSET(cg); - if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) return JS_FALSE; } } @@ -6920,7 +6877,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_XML_SUPPORT case TOK_FILTER: - if (!js_EmitTree(cx, cg, pn->pn_left)) + JS_ASSERT(!cg->inStrictMode()); + + if (!EmitTree(cx, cg, pn->pn_left)) return JS_FALSE; jmp = EmitJump(cx, cg, JSOP_FILTER, 0); if (jmp < 0) @@ -6928,7 +6887,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) top = EmitTraceOp(cx, cg, pn->pn_right); if (top < 0) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_right)) + if (!EmitTree(cx, cg, pn->pn_right)) return JS_FALSE; CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); if (EmitJump(cx, cg, JSOP_ENDFILTER, top - CG_OFFSET(cg)) < 0) @@ -6949,10 +6908,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) ok = EmitPropOp(cx, pn, pn->getOp(), cg, JS_FALSE); break; - case TOK_LB: #if JS_HAS_XML_SUPPORT case TOK_DBLDOT: + JS_ASSERT(!cg->inStrictMode()); + /* FALL THROUGH */ #endif + case TOK_LB: /* * Pop two operands, convert the left one to object and the right one * to property name (atom or tagged int), get the named property, and @@ -7008,12 +6969,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #endif /* FALL THROUGH */ default: - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; callop = false; /* trigger JSOP_PUSH after */ break; } - if (!callop && js_Emit1(cx, cg, JSOP_PUSH) < 0) + if (!callop && Emit1(cx, cg, JSOP_PUSH) < 0) return JS_FALSE; /* Remember start of callable-object bytecode for decompilation hint. */ @@ -7027,15 +6988,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) uintN oldflags = cg->flags; cg->flags &= ~TCF_IN_FOR_INIT; for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { - if (!js_EmitTree(cx, cg, pn3)) + if (!EmitTree(cx, cg, pn3)) return JS_FALSE; } cg->flags |= oldflags & TCF_IN_FOR_INIT; - if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0) + if (NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0) return JS_FALSE; argc = pn->pn_count - 1; - if (js_Emit3(cx, cg, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0) + if (Emit3(cx, cg, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0) return JS_FALSE; CheckTypeSet(cx, cg, pn->getOp()); if (pn->isOp(JSOP_EVAL)) { @@ -7044,7 +7005,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; } if (pn->pn_xflags & PNX_SETCALL) { - if (js_Emit1(cx, cg, JSOP_SETCALL) < 0) + if (Emit1(cx, cg, JSOP_SETCALL) < 0) return JS_FALSE; } break; @@ -7056,7 +7017,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) break; #if JS_HAS_BLOCK_SCOPE - case TOK_LET: + case TOK_LET: if (!EmitLet(cx, cg, pn)) return false; break; @@ -7071,7 +7032,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * under the array initialiser code generator for array comprehension * special casing. */ - if (!js_EmitTree(cx, cg, pn->pn_kid)) + if (!EmitTree(cx, cg, pn->pn_kid)) return JS_FALSE; slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth); if (slot < 0) @@ -7113,7 +7074,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ASSERT(cg->stackDepth > 0); saveDepth = cg->arrayCompDepth; cg->arrayCompDepth = (uint32) (cg->stackDepth - 1); - if (!js_EmitTree(cx, cg, pn->pn_head)) + if (!EmitTree(cx, cg, pn->pn_head)) return JS_FALSE; cg->arrayCompDepth = saveDepth; @@ -7136,7 +7097,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum)) return JS_FALSE; } else { - ptrdiff_t off = js_EmitN(cx, cg, JSOP_NEWARRAY, 3); + ptrdiff_t off = EmitN(cx, cg, JSOP_NEWARRAY, 3); if (off < 0) return JS_FALSE; pc = CG_CODE(cg, off); @@ -7148,20 +7109,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!EmitNumberOp(cx, atomIndex, cg)) return JS_FALSE; if (pn2->isKind(TOK_COMMA) && pn2->isArity(PN_NULLARY)) { - if (js_Emit1(cx, cg, JSOP_HOLE) < 0) + if (Emit1(cx, cg, JSOP_HOLE) < 0) return JS_FALSE; } else { - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; } - if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) + if (Emit1(cx, cg, JSOP_INITELEM) < 0) return JS_FALSE; } JS_ASSERT(atomIndex == pn->pn_count); if (pn->pn_xflags & PNX_ENDCOMMA) { /* Emit a source note so we know to decompile an extra comma. */ - if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0) + if (NewSrcNote(cx, cg, SRC_CONTINUE) < 0) return JS_FALSE; } @@ -7226,22 +7187,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } /* Emit code for the property initializer. */ - if (!js_EmitTree(cx, cg, pn2->pn_right)) + if (!EmitTree(cx, cg, pn2->pn_right)) return JS_FALSE; op = pn2->getOp(); if (op == JSOP_GETTER || op == JSOP_SETTER) { obj = NULL; - if (js_Emit1(cx, cg, op) < 0) + if (Emit1(cx, cg, op) < 0) return JS_FALSE; } /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */ if (pn3->isKind(TOK_NUMBER)) { obj = NULL; - if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + if (NewSrcNote(cx, cg, SRC_INITPROP) < 0) return JS_FALSE; - if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) + if (Emit1(cx, cg, JSOP_INITELEM) < 0) return JS_FALSE; } else { JS_ASSERT(pn3->isKind(TOK_NAME) || @@ -7251,7 +7212,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; /* Check whether we can optimize to JSOP_INITMETHOD. */ - JSParseNode *init = pn2->pn_right; + ParseNode *init = pn2->pn_right; bool lambda = init->isOp(JSOP_LAMBDA); if (lambda) ++methodInits; @@ -7296,7 +7257,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * The object survived and has a predictable shape. Update the original bytecode, * as long as we can do so without using a big index prefix/suffix. */ - JSObjectBox *objbox = cg->parser->newObjectBox(obj); + ObjectBox *objbox = cg->parser->newObjectBox(obj); if (!objbox) return JS_FALSE; unsigned index = cg->objectList.index(objbox); @@ -7321,7 +7282,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn->isKind(TOK_RC)) goto do_emit_object; - if (!js_EmitTree(cx, cg, pn)) + if (!EmitTree(cx, cg, pn)) return JS_FALSE; EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, (jsatomid) sharpnum); break; @@ -7336,7 +7297,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* * Cope with a left-over function definition that was replaced by a use * of a later function definition of the same name. See FunctionDef and - * MakeDefIntoUse in jsparse.cpp. + * MakeDefIntoUse in Parser.cpp. */ if (pn->isOp(JSOP_NOP)) break; @@ -7350,6 +7311,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_XMLTEXT: case TOK_XMLCDATA: case TOK_XMLCOMMENT: + JS_ASSERT(!cg->inStrictMode()); + /* FALL THROUGH */ #endif case TOK_STRING: ok = EmitAtomOp(cx, pn, pn->getOp(), cg); @@ -7368,19 +7331,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_ANYNAME: #endif case TOK_PRIMARY: - if (js_Emit1(cx, cg, pn->getOp()) < 0) + if (Emit1(cx, cg, pn->getOp()) < 0) return JS_FALSE; break; case TOK_DEBUGGER: - if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0) + if (Emit1(cx, cg, JSOP_DEBUGGER) < 0) return JS_FALSE; break; #if JS_HAS_XML_SUPPORT case TOK_XMLELEM: case TOK_XMLLIST: + JS_ASSERT(!cg->inStrictMode()); JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0); + switch (pn->pn_head ? pn->pn_head->getKind() : TOK_XMLLIST) { case TOK_XMLETAGO: JS_ASSERT(0); @@ -7389,18 +7354,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_XMLSTAGO: break; default: - if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + if (Emit1(cx, cg, JSOP_STARTXML) < 0) return JS_FALSE; } for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { if (pn2->isKind(TOK_LC) && - js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { return JS_FALSE; } - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + if (pn2 != pn->pn_head && Emit1(cx, cg, JSOP_ADD) < 0) return JS_FALSE; } @@ -7413,7 +7378,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; EMIT_INDEX_OP(JSOP_STRING, index); } - if (js_Emit1(cx, cg, pn->getOp()) < 0) + if (Emit1(cx, cg, pn->getOp()) < 0) return JS_FALSE; } #ifdef DEBUG @@ -7430,16 +7395,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) break; case TOK_XMLNAME: + JS_ASSERT(!cg->inStrictMode()); + if (pn->isArity(PN_LIST)) { JS_ASSERT(pn->pn_count != 0); for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { if (pn2->isKind(TOK_LC) && - js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { return JS_FALSE; } - if (!js_EmitTree(cx, cg, pn2)) + if (!EmitTree(cx, cg, pn2)) return JS_FALSE; - if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + if (pn2 != pn->pn_head && Emit1(cx, cg, JSOP_ADD) < 0) return JS_FALSE; } } else { @@ -7471,40 +7438,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return ok; } -/* - * We should try to get rid of offsetBias (always 0 or 1, where 1 is - * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL. - */ -JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = { - {"null", 0, 0, 0}, - {"if", 0, 0, 0}, - {"if-else", 2, 0, 1}, - {"for", 3, 1, 1}, - {"while", 1, 0, 1}, - {"continue", 0, 0, 0}, - {"decl", 1, 1, 1}, - {"pcdelta", 1, 0, 1}, - {"assignop", 0, 0, 0}, - {"cond", 1, 0, 1}, - {"brace", 1, 0, 1}, - {"hidden", 0, 0, 0}, - {"pcbase", 1, 0, -1}, - {"label", 1, 0, 0}, - {"labelbrace", 1, 0, 0}, - {"endbrace", 0, 0, 0}, - {"break2label", 1, 0, 0}, - {"cont2label", 1, 0, 0}, - {"switch", 2, 0, 1}, - {"funcdef", 1, 0, 0}, - {"catch", 1, 0, 1}, - {"extended", -1, 0, 0}, - {"newline", 0, 0, 0}, - {"setline", 1, 0, 0}, - {"xdelta", 0, 0, 0}, -}; - static intN -AllocSrcNote(JSContext *cx, JSCodeGenerator *cg) +AllocSrcNote(JSContext *cx, CodeGenerator *cg) { jssrcnote *notes = CG_NOTES(cg); jssrcnote *newnotes; @@ -7535,7 +7470,7 @@ AllocSrcNote(JSContext *cx, JSCodeGenerator *cg) } intN -js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) +frontend::NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type) { intN index, n; jssrcnote *sn; @@ -7572,48 +7507,47 @@ js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) /* * Initialize type and delta, then allocate the minimum number of notes * needed for type's arity. Usually, we won't need more, but if an offset - * does take two bytes, js_SetSrcNoteOffset will grow CG_NOTES(cg). + * does take two bytes, SetSrcNoteOffset will grow CG_NOTES(cg). */ SN_MAKE_NOTE(sn, type, delta); for (n = (intN)js_SrcNoteSpec[type].arity; n > 0; n--) { - if (js_NewSrcNote(cx, cg, SRC_NULL) < 0) + if (NewSrcNote(cx, cg, SRC_NULL) < 0) return -1; } return index; } intN -js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, - ptrdiff_t offset) +frontend::NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset) { intN index; - index = js_NewSrcNote(cx, cg, type); + index = NewSrcNote(cx, cg, type); if (index >= 0) { - if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset)) + if (!SetSrcNoteOffset(cx, cg, index, 0, offset)) return -1; } return index; } intN -js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, - ptrdiff_t offset1, ptrdiff_t offset2) +frontend::NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset1, + ptrdiff_t offset2) { intN index; - index = js_NewSrcNote(cx, cg, type); + index = NewSrcNote(cx, cg, type); if (index >= 0) { - if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1)) + if (!SetSrcNoteOffset(cx, cg, index, 0, offset1)) return -1; - if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2)) + if (!SetSrcNoteOffset(cx, cg, index, 1, offset2)) return -1; } return index; } static JSBool -GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg) +GrowSrcNotes(JSContext *cx, CodeGenerator *cg) { size_t newlength = CG_NOTE_LIMIT(cg) * 2; jssrcnote *newnotes = (jssrcnote *) cx->realloc_(CG_NOTES(cg), newlength); @@ -7627,14 +7561,13 @@ GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg) } jssrcnote * -js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, - ptrdiff_t delta) +frontend::AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta) { ptrdiff_t base, limit, newdelta, diff; intN index; /* - * Called only from OptimizeSpanDeps and js_FinishTakingSrcNotes to add to + * Called only from OptimizeSpanDeps and FinishTakingSrcNotes to add to * main script note deltas, and only by a small positive amount. */ JS_ASSERT(cg->current == &cg->main); @@ -7661,41 +7594,8 @@ js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, return sn; } -JS_FRIEND_API(uintN) -js_SrcNoteLength(jssrcnote *sn) -{ - uintN arity; - jssrcnote *base; - - arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity; - for (base = sn++; arity; sn++, arity--) { - if (*sn & SN_3BYTE_OFFSET_FLAG) - sn += 2; - } - return sn - base; -} - -JS_FRIEND_API(ptrdiff_t) -js_GetSrcNoteOffset(jssrcnote *sn, uintN which) -{ - /* Find the offset numbered which (i.e., skip exactly which offsets). */ - JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); - JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); - for (sn++; which; sn++, which--) { - if (*sn & SN_3BYTE_OFFSET_FLAG) - sn += 2; - } - if (*sn & SN_3BYTE_OFFSET_FLAG) { - return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16) - | (sn[1] << 8) - | sn[2]); - } - return (ptrdiff_t)*sn; -} - -JSBool -js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, - uintN which, ptrdiff_t offset) +static JSBool +SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset) { jssrcnote *sn; ptrdiff_t diff; @@ -7753,7 +7653,8 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, #define NBINS 10 static uint32 hist[NBINS]; -void DumpSrcNoteSizeHist() +static void +DumpSrcNoteSizeHist() { static FILE *fp; int i, n; @@ -7777,12 +7678,13 @@ void DumpSrcNoteSizeHist() /* * Fill in the storage at notes with prolog and main srcnotes; the space at - * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from jsemit.h. - * SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST CHECKING WHETHER jsemit.h's - * CG_COUNT_FINAL_SRCNOTES MACRO NEEDS CORRESPONDING CHANGES! + * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from + * BytecodeGenerator.h. SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST + * CHECKING WHETHER BytecodeGenerator.h's CG_COUNT_FINAL_SRCNOTES MACRO NEEDS + * CORRESPONDING CHANGES! */ JSBool -js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) +frontend::FinishTakingSrcNotes(JSContext *cx, CodeGenerator *cg, jssrcnote *notes) { uintN prologCount, mainCount, totalCount; ptrdiff_t offset, delta; @@ -7793,8 +7695,8 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) prologCount = cg->prolog.noteCount; if (prologCount && cg->prolog.currentLine != cg->firstLine) { CG_SWITCH_TO_PROLOG(cg); - if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0) - return JS_FALSE; + if (NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0) + return false; prologCount = cg->prolog.noteCount; CG_SWITCH_TO_MAIN(cg); } else { @@ -7816,8 +7718,8 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) if (offset < delta) delta = offset; for (;;) { - if (!js_AddToSrcNoteDelta(cx, cg, sn, delta)) - return JS_FALSE; + if (!AddToSrcNoteDelta(cx, cg, sn, delta)) + return false; offset -= delta; if (offset == 0) break; @@ -7834,19 +7736,19 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount)); SN_MAKE_TERMINATOR(¬es[totalCount]); - return JS_TRUE; + return true; } static JSBool -NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, - uintN stackDepth, size_t start, size_t end) +NewTryNote(JSContext *cx, CodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, + size_t end) { JS_ASSERT((uintN)(uint16)stackDepth == stackDepth); JS_ASSERT(start <= end); JS_ASSERT((size_t)(uint32)start == start); JS_ASSERT((size_t)(uint32)end == end); - JSTryNode *tryNode = cx->tempLifoAlloc().new_(); + TryNode *tryNode = cx->tempLifoAlloc().new_(); if (!tryNode) { js_ReportOutOfMemory(cx); return JS_FALSE; @@ -7863,9 +7765,9 @@ NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, } void -js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array) +frontend::FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array) { - JSTryNode *tryNode; + TryNode *tryNode; JSTryNote *tn; JS_ASSERT(array->length > 0 && array->length == cg->ntrynotes); @@ -7883,15 +7785,15 @@ js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array) * Since the emitter refers to each parsed object only once, for the index we * use the number of already indexes objects. We also add the object to a list * to convert the list to a fixed-size array when we complete code generation, - * see JSCGObjectList::finish below. + * see js::CGObjectList::finish below. * - * Most of the objects go to JSCodeGenerator.objectList but for regexp we use a - * separated JSCodeGenerator.regexpList. In this way the emitted index can be + * Most of the objects go to CodeGenerator::objectList but for regexp we use a + * separated CodeGenerator::regexpList. In this way the emitted index can be * directly used to store and fetch a reference to a cloned RegExp object that * shares the same JSRegExp private data created for the object literal in - * objbox. We need a cloned object to hold lastIndex and other direct properties - * that should not be shared among threads sharing a precompiled function or - * script. + * objbox. We need a cloned object to hold lastIndex and other direct + * properties that should not be shared among threads sharing a precompiled + * function or script. * * If the code being compiled is function code, allocate a reserved slot in * the cloned function object that shares its precompiled script with other @@ -7920,7 +7822,7 @@ js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array) * the pre-compilation prototype, a pigeon-hole problem for instanceof tests. */ uintN -JSCGObjectList::index(JSObjectBox *objbox) +CGObjectList::index(ObjectBox *objbox) { JS_ASSERT(!objbox->emitLink); objbox->emitLink = lastbox; @@ -7930,16 +7832,13 @@ JSCGObjectList::index(JSObjectBox *objbox) } void -JSCGObjectList::finish(JSObjectArray *array) +CGObjectList::finish(JSObjectArray *array) { - JSObject **cursor; - JSObjectBox *objbox; - JS_ASSERT(length <= INDEX_LIMIT); JS_ASSERT(length == array->length); - cursor = array->vector + array->length; - objbox = lastbox; + JSObject **cursor = array->vector + array->length; + ObjectBox *objbox = lastbox; do { --cursor; JS_ASSERT(!*cursor); @@ -7949,7 +7848,7 @@ JSCGObjectList::finish(JSObjectArray *array) } void -JSGCConstList::finish(JSConstArray *array) +GCConstList::finish(JSConstArray *array) { JS_ASSERT(array->length == list.length()); Value *src = list.begin(), *srcend = list.end(); @@ -7957,3 +7856,67 @@ JSGCConstList::finish(JSConstArray *array) for (; src != srcend; ++src, ++dst) *dst = *src; } + +/* + * We should try to get rid of offsetBias (always 0 or 1, where 1 is + * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL. + */ +JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = { + {"null", 0, 0, 0}, + {"if", 0, 0, 0}, + {"if-else", 2, 0, 1}, + {"for", 3, 1, 1}, + {"while", 1, 0, 1}, + {"continue", 0, 0, 0}, + {"decl", 1, 1, 1}, + {"pcdelta", 1, 0, 1}, + {"assignop", 0, 0, 0}, + {"cond", 1, 0, 1}, + {"brace", 1, 0, 1}, + {"hidden", 0, 0, 0}, + {"pcbase", 1, 0, -1}, + {"label", 1, 0, 0}, + {"labelbrace", 1, 0, 0}, + {"endbrace", 0, 0, 0}, + {"break2label", 1, 0, 0}, + {"cont2label", 1, 0, 0}, + {"switch", 2, 0, 1}, + {"funcdef", 1, 0, 0}, + {"catch", 1, 0, 1}, + {"extended", -1, 0, 0}, + {"newline", 0, 0, 0}, + {"setline", 1, 0, 0}, + {"xdelta", 0, 0, 0}, +}; + +JS_FRIEND_API(uintN) +js_SrcNoteLength(jssrcnote *sn) +{ + uintN arity; + jssrcnote *base; + + arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity; + for (base = sn++; arity; sn++, arity--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + return sn - base; +} + +JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which) +{ + /* Find the offset numbered which (i.e., skip exactly which offsets). */ + JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); + JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); + for (sn++; which; sn++, which--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + if (*sn & SN_3BYTE_OFFSET_FLAG) { + return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16) + | (sn[1] << 8) + | sn[2]); + } + return (ptrdiff_t)*sn; +} diff --git a/js/src/frontend/BytecodeGenerator.h b/js/src/frontend/BytecodeGenerator.h index 17052fd2c7e0..35eaa9047d10 100644 --- a/js/src/frontend/BytecodeGenerator.h +++ b/js/src/frontend/BytecodeGenerator.h @@ -56,7 +56,7 @@ #include "jsatominlines.h" -JS_BEGIN_EXTERN_C +namespace js { /* * NB: If you add enumerators for scope statements, add them between STMT_WITH @@ -64,9 +64,10 @@ JS_BEGIN_EXTERN_C * non-looping statement enumerators, add them before STMT_DO_LOOP or you will * break the STMT_TYPE_IS_LOOP macro. * - * Also remember to keep the statementName array in jsemit.c in sync. + * Also remember to keep the statementName array in BytecodeGenerator.cpp in + * sync. */ -typedef enum JSStmtType { +enum StmtType { STMT_LABEL, /* labeled statement: L: s */ STMT_IF, /* if (then) statement */ STMT_ELSE, /* else clause of if statement */ @@ -83,12 +84,12 @@ typedef enum JSStmtType { STMT_FOR_IN_LOOP, /* for/in loop statement */ STMT_WHILE_LOOP, /* while loop statement */ STMT_LIMIT -} JSStmtType; +}; #define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b))) /* - * A comment on the encoding of the JSStmtType enum and type-testing macros: + * A comment on the encoding of the js::StmtType enum and type-testing macros: * * STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may * become, a lexical scope. It therefore includes block and switch (the two @@ -96,7 +97,7 @@ typedef enum JSStmtType { * pending the "reformed with" in ES4/JS2). It includes all try-catch-finally * types, which are high-numbered maybe-scope types. * - * STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly + * STMT_TYPE_LINKS_SCOPE tells whether a js::StmtInfo of the given type eagerly * links to other scoping statement info records. It excludes the two early * "maybe" types, block and switch, as well as the try and both finally types, * since try and the other trailing maybe-scope types don't need block scope @@ -124,9 +125,7 @@ typedef enum JSStmtType { #define STMT_IS_TRYING(stmt) STMT_TYPE_IS_TRYING((stmt)->type) #define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type) -typedef struct JSStmtInfo JSStmtInfo; - -struct JSStmtInfo { +struct StmtInfo { uint16 type; /* statement type */ uint16 flags; /* flags, see below */ uint32 blockid; /* for simplified dominance computation */ @@ -135,10 +134,10 @@ struct JSStmtInfo { ptrdiff_t continues; /* offset of last continue in loop */ union { JSAtom *label; /* name of LABEL */ - JSObjectBox *blockBox; /* block scope object */ + ObjectBox *blockBox; /* block scope object */ }; - JSStmtInfo *down; /* info for enclosing statement */ - JSStmtInfo *downScope; /* next enclosing lexical scope */ + StmtInfo *down; /* info for enclosing statement */ + StmtInfo *downScope; /* next enclosing lexical scope */ }; #define SIF_SCOPE 0x0001 /* statement has its own lexical scope */ @@ -146,12 +145,12 @@ struct JSStmtInfo { #define SIF_FOR_BLOCK 0x0004 /* for (let ...) induced block scope */ /* - * To reuse space in JSStmtInfo, rename breaks and continues for use during + * To reuse space in StmtInfo, rename breaks and continues for use during * try/catch/finally code generation and backpatching. To match most common * use cases, the macro argument is a struct, not a struct pointer. Only a * loop, switch, or label statement info record can have breaks and continues, * and only a for loop has an update backpatch chain, so it's safe to overlay - * these for the "trying" JSStmtTypes. + * these for the "trying" StmtTypes. */ #define CATCHNOTE(stmt) ((stmt).update) #define GOSUBS(stmt) ((stmt).breaks) @@ -160,7 +159,7 @@ struct JSStmtInfo { #define SET_STATEMENT_TOP(stmt, top) \ ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) -#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */ +#define TCF_COMPILING 0x01 /* TreeContext is CodeGenerator */ #define TCF_IN_FUNCTION 0x02 /* parsing inside function body */ #define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */ #define TCF_RETURN_VOID 0x08 /* function has 'return;' */ @@ -196,10 +195,10 @@ struct JSStmtInfo { #define TCF_DECL_DESTRUCTURING 0x10000 /* - * A request flag passed to Compiler::compileScript and then down via - * JSCodeGenerator to js_NewScriptFromCG, from script_compile_sub and any - * kindred functions that need to make mutable scripts (even empty ones; - * i.e., they can't share the const JSScript::emptyScript() singleton). + * A request flag passed to BytecodeCompiler::compileScript and then down via + * CodeGenerator to JSScript::NewScriptFromCG, from script_compile_sub and any + * kindred functions that need to make mutable scripts (even empty ones; i.e., + * they can't share the const JSScript::emptyScript() singleton). */ #define TCF_NEED_MUTABLE_SCRIPT 0x20000 @@ -267,7 +266,7 @@ struct JSStmtInfo { /* * The caller is JS_Compile*Script*. */ -#define TCF_NEED_SCRIPT_OBJECT 0x40000000 +#define TCF_NEED_SCRIPT_GLOBAL 0x40000000 /* * Flags to check for return; vs. return expr; in a function. @@ -290,7 +289,9 @@ struct JSStmtInfo { TCF_STRICT_MODE_CODE | \ TCF_FUN_EXTENSIBLE_SCOPE) -struct JSTreeContext { /* tree context for semantic checks */ +struct CodeGenerator; + +struct TreeContext { /* tree context for semantic checks */ uint32 flags; /* statement state flags, see above */ uint32 bodyid; /* block number of program/function body */ uint32 blockidGen; /* preincremented block number generator */ @@ -300,19 +301,19 @@ struct JSTreeContext { /* tree context for semantic checks */ non-zero depth in current paren tree */ uint32 argumentsCount; /* number of |arguments| references encountered at non-zero depth in current paren tree */ - JSStmtInfo *topStmt; /* top of statement info stack */ - JSStmtInfo *topScopeStmt; /* top lexical scope statement */ - JSObjectBox *blockChainBox; /* compile time block scope chain (NB: one + StmtInfo *topStmt; /* top of statement info stack */ + StmtInfo *topScopeStmt; /* top lexical scope statement */ + ObjectBox *blockChainBox; /* compile time block scope chain (NB: one deeper than the topScopeStmt/downScope chain when in head of let block/expr) */ - JSParseNode *blockNode; /* parse node for a block with let declarations + ParseNode *blockNode; /* parse node for a block with let declarations (block with its own lexical scope) */ - js::AtomDecls decls; /* function, const, and var declarations */ - js::Parser *parser; /* ptr to common parsing and lexing data */ - JSParseNode *yieldNode; /* parse node for a yield expression that might + AtomDecls decls; /* function, const, and var declarations */ + Parser *parser; /* ptr to common parsing and lexing data */ + ParseNode *yieldNode; /* parse node for a yield expression that might be an error if we turn out to be inside a generator expression */ - JSParseNode *argumentsNode; /* parse node for an arguments variable that + ParseNode *argumentsNode; /* parse node for an arguments variable that might be an error if we turn out to be inside a generator expression */ @@ -341,23 +342,23 @@ struct JSTreeContext { /* tree context for semantic checks */ scopeChain_ = scopeChain; } - js::OwnedAtomDefnMapPtr lexdeps;/* unresolved lexical name dependencies */ - JSTreeContext *parent; /* enclosing function or global context */ + OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */ + TreeContext *parent; /* enclosing function or global context */ uintN staticLevel; /* static compilation unit nesting level */ - JSFunctionBox *funbox; /* null or box for function we're compiling + FunctionBox *funbox; /* null or box for function we're compiling if (flags & TCF_IN_FUNCTION) and not in - Compiler::compileFunctionBody */ - JSFunctionBox *functionList; + BytecodeCompiler::compileFunctionBody */ + FunctionBox *functionList; - JSParseNode *innermostWith; /* innermost WITH parse node */ + ParseNode *innermostWith; /* innermost WITH parse node */ - js::Bindings bindings; /* bindings in this code, including + Bindings bindings; /* bindings in this code, including arguments if we're compiling a function */ void trace(JSTracer *trc); - JSTreeContext(js::Parser *prs) + TreeContext(Parser *prs) : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0), argumentsCount(0), topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL), decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL), @@ -372,14 +373,14 @@ struct JSTreeContext { /* tree context for semantic checks */ * time during code generation. To avoid a redundant stats update in such * cases, we store uint16(-1) in maxScopeDepth. */ - ~JSTreeContext() { + ~TreeContext() { parser->tc = this->parent; } /* - * JSCodeGenerator derives from JSTreeContext; however, only the top-level - * JSCodeGenerators are actually used as full-fledged tree contexts (to - * hold decls and lexdeps). We can avoid allocation overhead by making + * js::CodeGenerator derives from js::TreeContext; however, only the + * top-level CodeGenerators are actually used as full-fledged tree contexts + * (to hold decls and lexdeps). We can avoid allocation overhead by making * this distinction explicit. */ enum InitBehavior { @@ -410,7 +411,7 @@ struct JSTreeContext { /* tree context for semantic checks */ bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); } /* Test whether we're in a statement of given type. */ - bool inStatement(JSStmtType type); + bool inStatement(StmtType type); bool inStrictMode() const { return flags & TCF_STRICT_MODE_CODE; @@ -425,7 +426,7 @@ struct JSTreeContext { /* tree context for semantic checks */ int sharpSlotBase; bool ensureSharpSlots(); - js::Compiler *compiler() { return (js::Compiler *)parser; } + BytecodeCompiler *compiler() { return (BytecodeCompiler *) parser; } // Return true there is a generator function within |skip| lexical scopes // (going upward) from this context's lexical scope. Always return true if @@ -436,7 +437,7 @@ struct JSTreeContext { /* tree context for semantic checks */ bool inFunction() const { return flags & TCF_IN_FUNCTION; } bool compiling() const { return flags & TCF_COMPILING; } - inline JSCodeGenerator *asCodeGenerator(); + inline CodeGenerator *asCodeGenerator(); bool usesArguments() const { return flags & TCF_FUN_USES_ARGUMENTS; @@ -468,7 +469,7 @@ struct JSTreeContext { /* tree context for semantic checks */ return flags & TCF_FUN_MUTATES_PARAMETER; } - void noteArgumentsUse(JSParseNode *pn) { + void noteArgumentsUse(ParseNode *pn) { JS_ASSERT(inFunction()); countArgumentsUse(pn); flags |= TCF_FUN_USES_ARGUMENTS; @@ -476,7 +477,7 @@ struct JSTreeContext { /* tree context for semantic checks */ funbox->node->pn_dflags |= PND_FUNARG; } - void countArgumentsUse(JSParseNode *pn) { + void countArgumentsUse(ParseNode *pn) { JS_ASSERT(pn->pn_atom == parser->context->runtime->atomState.argumentsAtom); argumentsCount++; argumentsNode = pn; @@ -493,38 +494,39 @@ struct JSTreeContext { /* tree context for semantic checks */ bool hasExtensibleScope() const { return flags & TCF_FUN_EXTENSIBLE_SCOPE; } + + ParseNode *freeTree(ParseNode *pn) { return parser->freeTree(pn); } }; /* * Return true if we need to check for conditions that elicit * JSOPTION_STRICT warnings or strict mode errors. */ -inline bool JSTreeContext::needStrictChecks() { +inline bool TreeContext::needStrictChecks() { return parser->context->hasStrictOption() || inStrictMode(); } -namespace js { +namespace frontend { bool -SetStaticLevel(JSTreeContext *tc, uintN staticLevel); +SetStaticLevel(TreeContext *tc, uintN staticLevel); bool -GenerateBlockId(JSTreeContext *tc, uint32& blockid); +GenerateBlockId(TreeContext *tc, uint32& blockid); -} /* namespace js */ +} /* namespace frontend */ + +struct JumpTarget; /* * Span-dependent instructions are jumps whose span (from the jump bytecode to * the jump target) may require 2 or 4 bytes of immediate operand. */ -typedef struct JSSpanDep JSSpanDep; -typedef struct JSJumpTarget JSJumpTarget; - -struct JSSpanDep { +struct SpanDep { ptrdiff_t top; /* offset of first bytecode in an opcode */ ptrdiff_t offset; /* offset - 1 within opcode of jump operand */ ptrdiff_t before; /* original offset - 1 of jump operand */ - JSJumpTarget *target; /* tagged target pointer or backpatch delta */ + JumpTarget *target; /* tagged target pointer or backpatch delta */ }; /* @@ -533,10 +535,10 @@ struct JSSpanDep { * instruction whose jump offset operand must be extended can be found quickly * and adjusted upward (toward higher offsets). */ -struct JSJumpTarget { +struct JumpTarget { ptrdiff_t offset; /* offset of span-dependent jump target */ int balance; /* AVL tree balance number */ - JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */ + JumpTarget *kids[2]; /* left and right AVL tree child pointers */ }; #define JT_LEFT 0 @@ -546,20 +548,20 @@ struct JSJumpTarget { #define JT_DIR(imbalance) (((imbalance) + 1) >> 1) /* - * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear, + * Backpatch deltas are encoded in js::SpanDep::target if JT_TAG_BIT is clear, * so we can maintain backpatch chains when using span dependency records to * hold jump offsets that overflow 16 bits. */ #define JT_TAG_BIT ((jsword) 1) #define JT_UNTAG_SHIFT 1 -#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT)) -#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) +#define JT_SET_TAG(jt) ((JumpTarget *)((jsword)(jt) | JT_TAG_BIT)) +#define JT_CLR_TAG(jt) ((JumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) #define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT) #define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE) #define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT) #define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1) -#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT)) +#define BPDELTA_TO_JT(bp) ((JumpTarget *)((bp) << JT_UNTAG_SHIFT)) #define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT)) #define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt)) @@ -574,34 +576,31 @@ struct JSJumpTarget { ? JT_CLR_TAG((sd)->target)->offset - (pivot) \ : 0) -typedef struct JSTryNode JSTryNode; - -struct JSTryNode { +struct TryNode { JSTryNote note; - JSTryNode *prev; + TryNode *prev; }; -struct JSCGObjectList { +struct CGObjectList { uint32 length; /* number of emitted so far objects */ - JSObjectBox *lastbox; /* last emitted object */ + ObjectBox *lastbox; /* last emitted object */ - JSCGObjectList() : length(0), lastbox(NULL) {} + CGObjectList() : length(0), lastbox(NULL) {} - uintN index(JSObjectBox *objbox); + uintN index(ObjectBox *objbox); void finish(JSObjectArray *array); }; -class JSGCConstList { - js::Vector list; +class GCConstList { + Vector list; public: - JSGCConstList(JSContext *cx) : list(cx) {} - bool append(js::Value v) { return list.append(v); } + GCConstList(JSContext *cx) : list(cx) {} + bool append(Value v) { return list.append(v); } size_t length() const { return list.length(); } void finish(JSConstArray *array); - }; -struct JSCodeGenerator : public JSTreeContext +struct CodeGenerator : public TreeContext { struct { jsbytecode *base; /* base of JS bytecode vector */ @@ -614,19 +613,19 @@ struct JSCodeGenerator : public JSTreeContext uintN currentLine; /* line number for tree-based srcnote gen */ } prolog, main, *current; - js::OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */ - js::AtomDefnMapPtr roLexdeps; - uintN firstLine; /* first line, for js_NewScriptFromCG */ + OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */ + AtomDefnMapPtr roLexdeps; + uintN firstLine; /* first line, for JSScript::NewScriptFromCG */ intN stackDepth; /* current stack depth in script frame */ uintN maxStackDepth; /* maximum stack depth so far */ uintN ntrynotes; /* number of allocated so far try notes */ - JSTryNode *lastTryNode; /* the last allocated try node */ + TryNode *lastTryNode; /* the last allocated try node */ - JSSpanDep *spanDeps; /* span dependent instruction records */ - JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */ - JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ + SpanDep *spanDeps; /* span dependent instruction records */ + JumpTarget *jumpTargets; /* AVL tree of jump target offsets */ + JumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ uintN numSpanDeps; /* number of span dependencies */ uintN numJumpTargets; /* number of jump targets */ ptrdiff_t spanDepTodo; /* offset from main.base of potentially @@ -634,47 +633,48 @@ struct JSCodeGenerator : public JSTreeContext uintN arrayCompDepth; /* stack depth of array in comprehension */ - uintN emitLevel; /* js_EmitTree recursion level */ + uintN emitLevel; /* js::frontend::EmitTree recursion level */ - typedef js::HashMap ConstMap; + typedef HashMap ConstMap; ConstMap constMap; /* compile time constants */ - JSGCConstList constList; /* constants to be included with the script */ + GCConstList constList; /* constants to be included with the script */ - JSCGObjectList objectList; /* list of emitted objects */ - JSCGObjectList regexpList; /* list of emitted regexp that will be + CGObjectList objectList; /* list of emitted objects */ + CGObjectList regexpList; /* list of emitted regexp that will be cloned during execution */ - js::OwnedAtomIndexMapPtr upvarIndices; /* map of atoms to upvar indexes */ + OwnedAtomIndexMapPtr upvarIndices; /* map of atoms to upvar indexes */ - js::UpvarCookies upvarMap; /* indexed upvar slot locations */ + UpvarCookies upvarMap; /* indexed upvar slot locations */ - typedef js::Vector GlobalUseVector; + typedef Vector GlobalUseVector; GlobalUseVector globalUses; /* per-script global uses */ - js::OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */ + OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */ /* Vectors of pn_cookie slot values. */ - typedef js::Vector SlotVector; + typedef Vector SlotVector; SlotVector closedArgs; SlotVector closedVars; uint16 traceIndex; /* index for the next JSOP_TRACE instruction */ uint16 typesetCount; /* Number of JOF_TYPESET opcodes generated */ - JSCodeGenerator(js::Parser *parser, uintN lineno); - bool init(JSContext *cx, JSTreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR); + CodeGenerator(Parser *parser, uintN lineno); + bool init(JSContext *cx, TreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR); JSContext *context() { return parser->context; } /* - * Note that cgs are magic: they own the arena "top-of-stack" space above - * their tempMark points. This means that you cannot alloc from tempPool - * and save the pointer beyond the next JSCodeGenerator destructor call. + * Note that cgs are magic: they own the arena "top-of-stack" space + * above their tempMark points. This means that you cannot alloc from + * tempLifoAlloc and save the pointer beyond the next CodeGenerator + * destructor call. */ - ~JSCodeGenerator(); + ~CodeGenerator(); /* * Adds a use of a variable that is statically known to exist on the @@ -690,7 +690,7 @@ struct JSCodeGenerator : public JSTreeContext * If the global use can be cached, |cookie| will be set to |slot|. * Otherwise, |cookie| is set to the free cookie value. */ - bool addGlobalUse(JSAtom *atom, uint32 slot, js::UpvarCookie *cookie); + bool addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie); bool hasUpvarIndices() const { return upvarIndices.hasMap() && !upvarIndices->empty(); @@ -709,11 +709,11 @@ struct JSCodeGenerator : public JSTreeContext bool compilingForEval() const { return !!(flags & TCF_COMPILE_FOR_EVAL); } JSVersion version() const { return parser->versionWithFlags(); } - bool shouldNoteClosedName(JSParseNode *pn); + bool shouldNoteClosedName(ParseNode *pn); JS_ALWAYS_INLINE bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) { - js::AtomIndexAddPtr p = atomIndices->lookupForAdd(atom); + AtomIndexAddPtr p = atomIndices->lookupForAdd(atom); if (p) { *indexp = p.value(); return true; @@ -730,7 +730,7 @@ struct JSCodeGenerator : public JSTreeContext bool checkSingletonContext() { if (!compileAndGo() || inFunction()) return false; - for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { + for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { if (STMT_IS_LOOP(stmt)) return false; } @@ -762,51 +762,53 @@ struct JSCodeGenerator : public JSTreeContext #define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) #define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) -inline JSCodeGenerator * -JSTreeContext::asCodeGenerator() +inline CodeGenerator * +TreeContext::asCodeGenerator() { JS_ASSERT(compiling()); - return static_cast(this); + return static_cast(this); } +namespace frontend { + /* * Emit one bytecode. */ -extern ptrdiff_t -js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op); +ptrdiff_t +Emit1(JSContext *cx, CodeGenerator *cg, JSOp op); /* * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1). */ -extern ptrdiff_t -js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1); +ptrdiff_t +Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1); /* * Emit three bytecodes, an opcode with two bytes of immediate operands. */ -extern ptrdiff_t -js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, +ptrdiff_t +Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1, jsbytecode op2); /* * Emit five bytecodes, an opcode with two 16-bit immediates. */ -extern ptrdiff_t -js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, +ptrdiff_t +Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1, uint16 op2); /* * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. */ -extern ptrdiff_t -js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); +ptrdiff_t +EmitN(JSContext *cx, CodeGenerator *cg, JSOp op, size_t extra); /* - * Unsafe macro to call js_SetJumpOffset and return false if it does. + * Unsafe macro to call SetJumpOffset and return false if it does. */ #define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT) \ JS_BEGIN_MACRO \ - if (!js_SetJumpOffset(cx, cg, pc, off)) { \ + if (!SetJumpOffset(cx, cg, pc, off)) { \ BAD_EXIT; \ } \ JS_END_MACRO @@ -821,56 +823,52 @@ js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); #define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \ CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE) -extern JSBool -js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, - ptrdiff_t off); +JSBool +SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off); /* * Push the C-stack-allocated struct at stmt onto the stmtInfo stack. */ -extern void -js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, - ptrdiff_t top); +void +PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top); /* * Push a block scope statement and link blockObj into tc->blockChain. To pop - * this statement info record, use js_PopStatement as usual, or if appropriate - * (if generating code), js_PopStatementCG. + * this statement info record, use PopStatementTC as usual, or if appropriate + * (if generating code), PopStatementCG. */ -extern void -js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox, - ptrdiff_t top); +void +PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top); /* - * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it + * Pop tc->topStmt. If the top StmtInfo struct is not stack-allocated, it * is up to the caller to free it. */ -extern void -js_PopStatement(JSTreeContext *tc); +void +PopStatementTC(TreeContext *tc); /* - * Like js_PopStatement(cg), also patch breaks and continues unless the top + * Like PopStatementTC(cg), also patch breaks and continues unless the top * statement info record represents a try-catch-finally suite. May fail if a * jump offset overflows. */ -extern JSBool -js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); +JSBool +PopStatementCG(JSContext *cx, CodeGenerator *cg); /* * Define and lookup a primitive jsval associated with the const named by atom. - * js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn + * DefineCompileTimeConstant analyzes the constant-folded initializer at pn * and saves the const's value in cg->constList, if it can be used at compile * time. It returns true unless an error occurred. * - * If the initializer's value could not be saved, js_DefineCompileTimeConstant - * calls will return the undefined value. js_DefineCompileTimeConstant tries + * If the initializer's value could not be saved, DefineCompileTimeConstant + * calls will return the undefined value. DefineCompileTimeConstant tries * to find a const value memorized for atom, returning true with *vp set to a * value other than undefined if the constant was found, true with *vp set to * JSVAL_VOID if not found, and false on error. */ -extern JSBool -js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - JSParseNode *pn); +JSBool +DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseNode *pn); /* * Find a lexically scoped variable (one declared by let, catch, or an array @@ -881,26 +879,27 @@ js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, * null, then if atom is found, set *slotp to its stack slot, otherwise to -1. * This means that if slotp is not null, all the block objects on the lexical * scope chain must have had their depth slots computed by the code generator, - * so the caller must be under js_EmitTree. + * so the caller must be under EmitTree. * * In any event, directly return the statement info record in which atom was * found. Otherwise return null. */ -extern JSStmtInfo * -js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, - JSStmtInfo *stmt = NULL); +StmtInfo * +LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt = NULL); /* * Emit code into cg for the tree rooted at pn. */ -extern JSBool -js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); +JSBool +EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn); /* * Emit function code using cg for the tree rooted at body. */ -extern JSBool -js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); +JSBool +EmitFunctionScript(JSContext *cx, CodeGenerator *cg, ParseNode *body); + +} /* namespace frontend */ /* * Source notes generated along with bytecode for decompiling and debugging. @@ -918,13 +917,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. * - * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its - * initializers need to match the order here. + * NB: the js_SrcNoteSpec array in BytecodeGenerator.cpp is indexed by this + * enum, so its initializers need to match the order here. * * Note on adding new source notes: every pair of bytecodes (A, B) where A and * B have disjoint sets of source notes that could apply to each bytecode may * reuse the same note type value for two notes (snA, snB) that have the same - * arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is + * arity, offsetBias, and isSpanDep initializers in JSSrcNoteSpec. This is * why SRC_IF and SRC_INITPROP have the same value below. For bad historical * reasons, some bytecodes below that could be overlayed have not been, but * before using SRC_EXTENDED, consider compressing the existing note types. @@ -932,7 +931,7 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); * Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such * incompatible source note or other bytecode changes. */ -typedef enum JSSrcNoteType { +enum SrcNoteType { SRC_NULL = 0, /* terminates a note vector */ SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ SRC_BREAK = 1, /* JSOP_GOTO is a break */ @@ -981,7 +980,7 @@ typedef enum JSSrcNoteType { SRC_NEWLINE = 22, /* bytecode follows a source newline */ SRC_SETLINE = 23, /* a file-absolute source line number note */ SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ -} JSSrcNoteType; +}; /* * Constants for the SRC_DECL source note. Note that span-dependent bytecode @@ -1013,9 +1012,9 @@ typedef enum JSSrcNoteType { | ((d) & SN_XDELTA_MASK))) #define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA) -#define SN_TYPE(sn) ((JSSrcNoteType)(SN_IS_XDELTA(sn) \ - ? SRC_XDELTA \ - : *(sn) >> SN_DELTA_BITS)) +#define SN_TYPE(sn) ((js::SrcNoteType)(SN_IS_XDELTA(sn) \ + ? SRC_XDELTA \ + : *(sn) >> SN_DELTA_BITS)) #define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn)) #define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE) @@ -1037,17 +1036,6 @@ typedef enum JSSrcNoteType { #define SN_3BYTE_OFFSET_FLAG 0x80 #define SN_3BYTE_OFFSET_MASK 0x7f -typedef struct JSSrcNoteSpec { - const char *name; /* name for disassembly/debugging output */ - int8 arity; /* number of offset operands */ - uint8 offsetBias; /* bias of offset(s) from annotated pc */ - int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, - 0 otherwise; sign tells span direction */ -} JSSrcNoteSpec; - -extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; -extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); - #define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ : js_SrcNoteLength(sn)) #define SN_NEXT(sn) ((sn) + SN_LENGTH(sn)) @@ -1056,39 +1044,29 @@ extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); #define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL) #define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL) +namespace frontend { + /* * Append a new source note of the given type (and therefore size) to cg's * notes dynamic array, updating cg->noteCount. Return the new note's index * within the array pointed at by cg->current->notes. Return -1 if out of * memory. */ -extern intN -js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type); +intN +NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type); -extern intN -js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, - ptrdiff_t offset); +intN +NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset); -extern intN -js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, - ptrdiff_t offset1, ptrdiff_t offset2); +intN +NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset1, + ptrdiff_t offset2); /* * NB: this function can add at most one extra extended delta note. */ -extern jssrcnote * -js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, - ptrdiff_t delta); - -/* - * Get and set the offset operand identified by which (0 for the first, etc.). - */ -extern JS_FRIEND_API(ptrdiff_t) -js_GetSrcNoteOffset(jssrcnote *sn, uintN which); - -extern JSBool -js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, - uintN which, ptrdiff_t offset); +jssrcnote * +AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta); /* * Finish taking source notes in cx's notePool, copying final notes to the new @@ -1097,8 +1075,8 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, * * To compute the number of jssrcnotes to allocate and pass in via notes, use * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of - * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes - * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! + * FinishTakingSrcNotes, so DON'T CHANGE js::frontend::FinishTakingSrcNotes + * WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! */ #define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \ JS_BEGIN_MACRO \ @@ -1121,12 +1099,30 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, } \ JS_END_MACRO -extern JSBool -js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes); +JSBool +FinishTakingSrcNotes(JSContext *cx, CodeGenerator *cg, jssrcnote *notes); -extern void -js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array); +void +FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array); -JS_END_EXTERN_C +} /* namespace frontend */ +} /* namespace js */ + +struct JSSrcNoteSpec { + const char *name; /* name for disassembly/debugging output */ + int8 arity; /* number of offset operands */ + uint8 offsetBias; /* bias of offset(s) from annotated pc */ + int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, + 0 otherwise; sign tells span direction */ +}; + +extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; +extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); + +/* + * Get and set the offset operand identified by which (0 for the first, etc.). + */ +extern JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which); #endif /* BytecodeGenerator_h__ */ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 79d15e8232ec..c260ebbfa562 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -51,10 +51,10 @@ using namespace js; -static JSParseNode * -ContainsStmt(JSParseNode *pn, TokenKind tt) +static ParseNode * +ContainsStmt(ParseNode *pn, TokenKind tt) { - JSParseNode *pn2, *pnt; + ParseNode *pn2, *pnt; if (!pn) return NULL; @@ -105,7 +105,7 @@ ContainsStmt(JSParseNode *pn, TokenKind tt) * XXX handles only strings and numbers for now */ static JSBool -FoldType(JSContext *cx, JSParseNode *pn, TokenKind type) +FoldType(JSContext *cx, ParseNode *pn, TokenKind type) { if (!pn->isKind(type)) { switch (type) { @@ -145,8 +145,8 @@ FoldType(JSContext *cx, JSParseNode *pn, TokenKind type) * a successful call to this function. */ static JSBool -FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, - JSParseNode *pn, JSTreeContext *tc) +FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2, + ParseNode *pn, TreeContext *tc) { jsdouble d, d2; int32 i, j; @@ -213,9 +213,9 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, /* Take care to allow pn1 or pn2 to alias pn. */ if (pn1 != pn) - RecycleTree(pn1, tc); + tc->freeTree(pn1); if (pn2 != pn) - RecycleTree(pn2, tc); + tc->freeTree(pn2); pn->setKind(TOK_NUMBER); pn->setOp(JSOP_DOUBLE); pn->setArity(PN_NULLARY); @@ -226,10 +226,10 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, #if JS_HAS_XML_SUPPORT static JSBool -FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) +FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc) { TokenKind tt; - JSParseNode **pnp, *pn1, *pn2; + ParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; @@ -303,7 +303,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) #endif } else if (accum && pn1 != pn2) { while (pn1->pn_next != pn2) { - pn1 = RecycleTree(pn1, tc); + pn1 = tc->freeTree(pn1); --pn->pn_count; } pn1->setKind(TOK_XMLTEXT); @@ -356,7 +356,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) JS_ASSERT(*pnp == pn1); while (pn1->pn_next) { - pn1 = RecycleTree(pn1, tc); + pn1 = tc->freeTree(pn1); --pn->pn_count; } pn1->setKind(TOK_XMLTEXT); @@ -392,7 +392,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) enum Truthiness { Truthy, Falsy, Unknown }; static Truthiness -Boolish(JSParseNode *pn) +Boolish(ParseNode *pn) { switch (pn->getOp()) { case JSOP_DOUBLE: @@ -411,7 +411,7 @@ Boolish(JSParseNode *pn) */ if (pn->pn_count != 1) return Unknown; - JSParseNode *pn2 = pn->pn_head; + ParseNode *pn2 = pn->pn_head; if (!pn2->isKind(TOK_FUNCTION)) return Unknown; if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) @@ -434,23 +434,23 @@ Boolish(JSParseNode *pn) } } -JSBool -js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) +bool +js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond) { - JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL; + ParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL; - JS_CHECK_RECURSION(cx, return JS_FALSE); + JS_CHECK_RECURSION(cx, return false); switch (pn->getArity()) { case PN_FUNC: { uint32 oldflags = tc->flags; - JSFunctionBox *oldlist = tc->functionList; + FunctionBox *oldlist = tc->functionList; tc->flags = pn->pn_funbox->tcflags; tc->functionList = pn->pn_funbox->kids; - if (!js_FoldConstants(cx, pn->pn_body, tc)) - return JS_FALSE; + if (!FoldConstants(cx, pn->pn_body, tc)) + return false; pn->pn_funbox->kids = tc->functionList; tc->flags = oldflags; tc->functionList = oldlist; @@ -469,8 +469,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) /* Save the list head in pn1 for later use. */ for (; pn2; pn2 = pn2->pn_next) { - if (!js_FoldConstants(cx, pn2, tc, cond)) - return JS_FALSE; + if (!FoldConstants(cx, pn2, tc, cond)) + return false; } break; } @@ -480,18 +480,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) pn1 = pn->pn_kid1; pn2 = pn->pn_kid2; pn3 = pn->pn_kid3; - if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_IF))) - return JS_FALSE; + if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(TOK_IF))) + return false; if (pn2) { - if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_FORHEAD))) - return JS_FALSE; + if (!FoldConstants(cx, pn2, tc, pn->isKind(TOK_FORHEAD))) + return false; if (pn->isKind(TOK_FORHEAD) && pn2->isOp(JSOP_TRUE)) { - RecycleTree(pn2, tc); + tc->freeTree(pn2); pn->pn_kid2 = NULL; } } - if (pn3 && !js_FoldConstants(cx, pn3, tc)) - return JS_FALSE; + if (pn3 && !FoldConstants(cx, pn3, tc)) + return false; break; case PN_BINARY: @@ -500,18 +500,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) /* Propagate inCond through logical connectives. */ if (pn->isKind(TOK_OR) || pn->isKind(TOK_AND)) { - if (!js_FoldConstants(cx, pn1, tc, inCond)) - return JS_FALSE; - if (!js_FoldConstants(cx, pn2, tc, inCond)) - return JS_FALSE; + if (!FoldConstants(cx, pn1, tc, inCond)) + return false; + if (!FoldConstants(cx, pn2, tc, inCond)) + return false; break; } /* First kid may be null (for default case in switch). */ - if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_WHILE))) - return JS_FALSE; - if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_DO))) - return JS_FALSE; + if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(TOK_WHILE))) + return false; + if (!FoldConstants(cx, pn2, tc, pn->isKind(TOK_DO))) + return false; break; case PN_UNARY: @@ -529,8 +529,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) if (pn->isOp(JSOP_TYPEOF) && !pn1->isKind(TOK_NAME)) pn->setOp(JSOP_TYPEOFEXPR); - if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT))) - return JS_FALSE; + if (pn1 && !FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT))) + return false; break; case PN_NAME: @@ -544,15 +544,15 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) pn1 = pn->pn_expr; while (pn1 && pn1->isArity(PN_NAME) && !pn1->isUsed()) pn1 = pn1->pn_expr; - if (pn1 && !js_FoldConstants(cx, pn1, tc)) - return JS_FALSE; + if (pn1 && !FoldConstants(cx, pn1, tc)) + return false; } break; case PN_NAMESET: pn1 = pn->pn_tree; - if (!js_FoldConstants(cx, pn1, tc)) - return JS_FALSE; + if (!FoldConstants(cx, pn1, tc)) + return false; break; case PN_NULLARY: @@ -586,7 +586,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) /* FALL THROUGH */ default: /* Early return to dodge common code that copies pn2 to pn. */ - return JS_TRUE; + return true; } #if JS_HAS_GENERATOR_EXPRS @@ -609,16 +609,16 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) pn->setArity(PN_LIST); pn->makeEmpty(); } - RecycleTree(pn2, tc); + tc->freeTree(pn2); if (pn3 && pn3 != pn2) - RecycleTree(pn3, tc); + tc->freeTree(pn3); break; case TOK_OR: case TOK_AND: if (inCond) { if (pn->isArity(PN_LIST)) { - JSParseNode **pnp = &pn->pn_head; + ParseNode **pnp = &pn->pn_head; JS_ASSERT(*pnp == pn1); do { Truthiness t = Boolish(pn1); @@ -629,7 +629,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) if ((t == Truthy) == pn->isKind(TOK_OR)) { for (pn2 = pn1->pn_next; pn2; pn2 = pn3) { pn3 = pn2->pn_next; - RecycleTree(pn2, tc); + tc->freeTree(pn2); --pn->pn_count; } pn1->pn_next = NULL; @@ -639,7 +639,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) if (pn->pn_count == 1) break; *pnp = pn1->pn_next; - RecycleTree(pn1, tc); + tc->freeTree(pn1); --pn->pn_count; } while ((pn1 = *pnp) != NULL); @@ -654,17 +654,17 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) pn->pn_right = pn2; } else if (pn->pn_count == 1) { pn->become(pn1); - RecycleTree(pn1, tc); + tc->freeTree(pn1); } } else { Truthiness t = Boolish(pn1); if (t != Unknown) { if ((t == Truthy) == pn->isKind(TOK_OR)) { - RecycleTree(pn2, tc); + tc->freeTree(pn2); pn->become(pn1); } else { JS_ASSERT((t == Truthy) == pn->isKind(TOK_AND)); - RecycleTree(pn1, tc); + tc->freeTree(pn1); pn->become(pn2); } } @@ -694,7 +694,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) */ JS_ASSERT(pn->pn_count > 2); if (pn->pn_xflags & PNX_CANTFOLD) - return JS_TRUE; + return true; if (pn->pn_xflags != PNX_STRCAT) goto do_binary_op; @@ -702,26 +702,26 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) size_t length = 0; for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { if (!FoldType(cx, pn2, TOK_STRING)) - return JS_FALSE; + return false; /* XXX fold only if all operands convert to string */ if (!pn2->isKind(TOK_STRING)) - return JS_TRUE; + return true; length += pn2->pn_atom->length(); } /* Allocate a new buffer and string descriptor for the result. */ jschar *chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar)); if (!chars) - return JS_FALSE; + return false; chars[length] = 0; JSString *str = js_NewString(cx, chars, length); if (!str) { cx->free_(chars); - return JS_FALSE; + return false; } /* Fill the buffer, advancing chars and recycling kids as we go. */ - for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) { + for (pn2 = pn1; pn2; pn2 = tc->freeTree(pn2)) { JSAtom *atom = pn2->pn_atom; size_t length2 = atom->length(); js_strncpy(chars, atom->chars(), length2); @@ -732,7 +732,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) /* Atomize the result string and mutate pn to refer to it. */ pn->pn_atom = js_AtomizeString(cx, str); if (!pn->pn_atom) - return JS_FALSE; + return false; pn->setKind(TOK_STRING); pn->setOp(JSOP_STRING); pn->setArity(PN_NULLARY); @@ -745,22 +745,22 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) JSString *left, *right, *str; if (!FoldType(cx, !pn1->isKind(TOK_STRING) ? pn1 : pn2, TOK_STRING)) - return JS_FALSE; + return false; if (!pn1->isKind(TOK_STRING) || !pn2->isKind(TOK_STRING)) - return JS_TRUE; + return true; left = pn1->pn_atom; right = pn2->pn_atom; str = js_ConcatStrings(cx, left, right); if (!str) - return JS_FALSE; + return false; pn->pn_atom = js_AtomizeString(cx, str); if (!pn->pn_atom) - return JS_FALSE; + return false; pn->setKind(TOK_STRING); pn->setOp(JSOP_STRING); pn->setArity(PN_NULLARY); - RecycleTree(pn1, tc); - RecycleTree(pn2, tc); + tc->freeTree(pn1); + tc->freeTree(pn2); break; } @@ -776,7 +776,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) JS_ASSERT(pn->pn_count > 2); for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { if (!FoldType(cx, pn2, TOK_NUMBER)) - return JS_FALSE; + return false; } for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { /* XXX fold only if all operands convert to number */ @@ -789,22 +789,22 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) pn2 = pn1->pn_next; pn3 = pn2->pn_next; if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc)) - return JS_FALSE; + return false; while ((pn2 = pn3) != NULL) { pn3 = pn2->pn_next; if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc)) - return JS_FALSE; + return false; } } } else { JS_ASSERT(pn->isArity(PN_BINARY)); if (!FoldType(cx, pn1, TOK_NUMBER) || !FoldType(cx, pn2, TOK_NUMBER)) { - return JS_FALSE; + return false; } if (pn1->isKind(TOK_NUMBER) && pn2->isKind(TOK_NUMBER)) { if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn, tc)) - return JS_FALSE; + return false; } } break; @@ -835,18 +835,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) default: /* Return early to dodge the common TOK_NUMBER code. */ - return JS_TRUE; + return true; } pn->setKind(TOK_NUMBER); pn->setOp(JSOP_DOUBLE); pn->setArity(PN_NULLARY); pn->pn_dval = d; - RecycleTree(pn1, tc); + tc->freeTree(pn1); } else if (pn1->isKind(TOK_PRIMARY)) { if (pn->isOp(JSOP_NOT) && (pn1->isOp(JSOP_TRUE) || pn1->isOp(JSOP_FALSE))) { pn->become(pn1); pn->setOp(pn->isOp(JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE); - RecycleTree(pn1, tc); + tc->freeTree(pn1); } } break; @@ -861,28 +861,26 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) if (pn->isArity(PN_LIST)) { JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0); if (!FoldXMLConstants(cx, pn, tc)) - return JS_FALSE; + return false; } break; case TOK_AT: if (pn1->isKind(TOK_XMLNAME)) { - JSObjectBox *xmlbox; - Value v = StringValue(pn1->pn_atom); if (!js_ToAttributeName(cx, &v)) - return JS_FALSE; + return false; JS_ASSERT(v.isObject()); - xmlbox = tc->parser->newObjectBox(&v.toObject()); + ObjectBox *xmlbox = tc->parser->newObjectBox(&v.toObject()); if (!xmlbox) - return JS_FALSE; + return false; pn->setKind(TOK_XMLNAME); pn->setOp(JSOP_OBJECT); pn->setArity(PN_NULLARY); pn->pn_objbox = xmlbox; - RecycleTree(pn1, tc); + tc->freeTree(pn1); } break; #endif /* JS_HAS_XML_SUPPORT */ @@ -899,12 +897,12 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) * a method list corrupts the method list. However, methods are M's in * statements of the form 'this.foo = M;', which we never fold, so we're okay. */ - PrepareNodeForMutation(pn, tc); + tc->parser->allocator.prepareNodeForMutation(pn); pn->setKind(TOK_PRIMARY); pn->setOp(t == Truthy ? JSOP_TRUE : JSOP_FALSE); pn->setArity(PN_NULLARY); } } - return JS_TRUE; + return true; } diff --git a/js/src/frontend/FoldConstants.h b/js/src/frontend/FoldConstants.h index 98ee37821ce1..1496107bb035 100644 --- a/js/src/frontend/FoldConstants.h +++ b/js/src/frontend/FoldConstants.h @@ -43,12 +43,11 @@ #include "jsprvtd.h" -JS_BEGIN_EXTERN_C +namespace js { -extern JSBool -js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, - bool inCond = false); +bool +FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond = false); -JS_END_EXTERN_C +} /* namespace js */ #endif /* FoldConstants_h__ */ diff --git a/js/src/frontend/ParseMaps-inl.h b/js/src/frontend/ParseMaps-inl.h index caa3ae9ebd1b..13fb7d33321d 100644 --- a/js/src/frontend/ParseMaps-inl.h +++ b/js/src/frontend/ParseMaps-inl.h @@ -43,7 +43,7 @@ #include "jscntxt.h" -#include "frontend/ParseNode.h" /* Need sizeof(JSDefinition). */ +#include "frontend/ParseNode.h" /* Need sizeof(js::Definition). */ #include "ParseMaps.h" @@ -81,7 +81,7 @@ ParseMapPool::allocate() return map; } -inline JSDefinition * +inline Definition * AtomDecls::lookupFirst(JSAtom *atom) { JS_ASSERT(map); @@ -101,7 +101,7 @@ AtomDecls::lookupMulti(JSAtom *atom) JS_ASSERT(map); AtomDOHPtr p = map->lookup(atom); if (!p) - return MultiDeclRange((JSDefinition *) NULL); + return MultiDeclRange((Definition *) NULL); DefnOrHeader &doh = p.value(); if (doh.isHeader()) @@ -110,7 +110,7 @@ AtomDecls::lookupMulti(JSAtom *atom) } inline bool -AtomDecls::addUnique(JSAtom *atom, JSDefinition *defn) +AtomDecls::addUnique(JSAtom *atom, Definition *defn) { JS_ASSERT(map); AtomDOHAddPtr p = map->lookupForAdd(atom); diff --git a/js/src/frontend/ParseMaps.cpp b/js/src/frontend/ParseMaps.cpp index edc5623715a4..ab6c345ee4ee 100644 --- a/js/src/frontend/ParseMaps.cpp +++ b/js/src/frontend/ParseMaps.cpp @@ -50,8 +50,8 @@ ParseMapPool::checkInvariants() * Having all values be of the same size permits us to easily reuse the * allocated space for each of the map types. */ - JS_STATIC_ASSERT(sizeof(JSDefinition *) == sizeof(jsatomid)); - JS_STATIC_ASSERT(sizeof(JSDefinition *) == sizeof(DefnOrHeader)); + JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(jsatomid)); + JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(DefnOrHeader)); JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomIndexMap::Entry)); JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomDOHMap::Entry)); JS_STATIC_ASSERT(sizeof(AtomMapT::Entry) == sizeof(AtomDOHMap::Entry)); @@ -124,7 +124,7 @@ DumpAtomDefnMap(const AtomDefnMapPtr &map) #endif AtomDeclNode * -AtomDecls::allocNode(JSDefinition *defn) +AtomDecls::allocNode(Definition *defn) { AtomDeclNode *p = cx->tempLifoAlloc().new_(defn); if (!p) { @@ -135,7 +135,7 @@ AtomDecls::allocNode(JSDefinition *defn) } bool -AtomDecls::addShadow(JSAtom *atom, JSDefinition *defn) +AtomDecls::addShadow(JSAtom *atom, Definition *defn) { AtomDeclNode *node = allocNode(defn); if (!node) @@ -177,7 +177,7 @@ AtomDecls::lastAsNode(DefnOrHeader *doh) } bool -AtomDecls::addHoist(JSAtom *atom, JSDefinition *defn) +AtomDecls::addHoist(JSAtom *atom, Definition *defn) { AtomDeclNode *node = allocNode(defn); if (!node) diff --git a/js/src/frontend/ParseMaps.h b/js/src/frontend/ParseMaps.h index 3b7800816476..296d83b4d3e8 100644 --- a/js/src/frontend/ParseMaps.h +++ b/js/src/frontend/ParseMaps.h @@ -47,6 +47,8 @@ namespace js { +struct Definition; + /* * A pool that permits the reuse of the backing storage for the defn, index, or * defn-or-header (multi) maps. @@ -126,7 +128,7 @@ class ParseMapPool }; /* ParseMapPool */ /* - * N.B. This is a POD-type so that it can be included in the JSParseNode union. + * N.B. This is a POD-type so that it can be included in the ParseNode union. * If possible, use the corresponding |OwnedAtomThingMapPtr| variant. */ template @@ -152,7 +154,7 @@ struct AtomThingMapPtr struct AtomDefnMapPtr : public AtomThingMapPtr { JS_ALWAYS_INLINE - JSDefinition *lookupDefn(JSAtom *atom) { + Definition *lookupDefn(JSAtom *atom) { AtomDefnMap::Ptr p = map_->lookup(atom); return p ? p.value() : NULL; } @@ -185,22 +187,22 @@ typedef OwnedAtomThingMapPtr OwnedAtomIndexMapPtr; /* Node structure for chaining in AtomDecls. */ struct AtomDeclNode { - JSDefinition *defn; + Definition *defn; AtomDeclNode *next; - explicit AtomDeclNode(JSDefinition *defn) + explicit AtomDeclNode(Definition *defn) : defn(defn), next(NULL) {} }; /* - * Tagged union of a JSDefinition and an AtomDeclNode, for use in AtomDecl's + * Tagged union of a Definition and an AtomDeclNode, for use in AtomDecl's * internal map. */ class DefnOrHeader { union { - JSDefinition *defn; + Definition *defn; AtomDeclNode *head; uintptr_t bits; } u; @@ -210,7 +212,7 @@ class DefnOrHeader u.bits = 0; } - explicit DefnOrHeader(JSDefinition *defn) { + explicit DefnOrHeader(Definition *defn) { u.defn = defn; JS_ASSERT(!isHeader()); } @@ -225,7 +227,7 @@ class DefnOrHeader return u.bits & 0x1; } - JSDefinition *defn() const { + Definition *defn() const { JS_ASSERT(!isHeader()); return u.defn; } @@ -268,7 +270,7 @@ class AtomDecls AtomDecls(const AtomDecls &other); void operator=(const AtomDecls &other); - AtomDeclNode *allocNode(JSDefinition *defn); + AtomDeclNode *allocNode(Definition *defn); /* * Fallibly return the value in |doh| as a node. @@ -290,18 +292,18 @@ class AtomDecls } /* Return the definition at the head of the chain for |atom|. */ - inline JSDefinition *lookupFirst(JSAtom *atom); + inline Definition *lookupFirst(JSAtom *atom); /* Perform a lookup that can iterate over the definitions associated with |atom|. */ inline MultiDeclRange lookupMulti(JSAtom *atom); /* Add-or-update a known-unique definition for |atom|. */ - inline bool addUnique(JSAtom *atom, JSDefinition *defn); - bool addShadow(JSAtom *atom, JSDefinition *defn); - bool addHoist(JSAtom *atom, JSDefinition *defn); + inline bool addUnique(JSAtom *atom, Definition *defn); + bool addShadow(JSAtom *atom, Definition *defn); + bool addHoist(JSAtom *atom, Definition *defn); /* Updating the definition for an entry that is known to exist is infallible. */ - void updateFirst(JSAtom *atom, JSDefinition *defn) { + void updateFirst(JSAtom *atom, Definition *defn) { JS_ASSERT(map); AtomDOHMap::Ptr p = map->lookup(atom); JS_ASSERT(p); @@ -352,9 +354,9 @@ class MultiDeclRange friend class AtomDecls; AtomDeclNode *node; - JSDefinition *defn; + Definition *defn; - explicit MultiDeclRange(JSDefinition *defn) : node(NULL), defn(defn) {} + explicit MultiDeclRange(Definition *defn) : node(NULL), defn(defn) {} explicit MultiDeclRange(AtomDeclNode *node) : node(node), defn(node->defn) {} public: @@ -368,7 +370,7 @@ class MultiDeclRange defn = node ? node->defn : NULL; } - JSDefinition *front() { + Definition *front() { JS_ASSERT(!empty()); return defn; } @@ -388,10 +390,10 @@ class AtomDeclsIter public: explicit AtomDeclsIter(AtomDecls *decls) : r(decls->all()), link(NULL) {} - JSDefinition *operator()() { + Definition *operator()() { if (link) { JS_ASSERT(link != link->next); - JSDefinition *result = link->defn; + Definition *result = link->defn; link = link->next; JS_ASSERT(result); return result; diff --git a/js/src/frontend/ParseNode-inl.h b/js/src/frontend/ParseNode-inl.h index df16a46ae1c2..51e62b001c5a 100644 --- a/js/src/frontend/ParseNode-inl.h +++ b/js/src/frontend/ParseNode-inl.h @@ -44,11 +44,11 @@ #include "frontend/BytecodeGenerator.h" #include "frontend/TokenStream.h" -inline bool -JSParseNode::isConstant() -{ - using namespace js; +namespace js { +inline bool +ParseNode::isConstant() +{ switch (pn_type) { case TOK_NUMBER: case TOK_STRING: @@ -70,10 +70,8 @@ JSParseNode::isConstant() } } -namespace js { - inline void -NameNode::initCommon(JSTreeContext *tc) +NameNode::initCommon(TreeContext *tc) { pn_expr = NULL; pn_cookie.makeFree(); diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 8ccc8b67b670..64db91d068e8 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -40,9 +40,6 @@ #include "frontend/ParseNode.h" -#include "frontend/BytecodeGenerator.h" -#include "frontend/Parser.h" - #include "jsscriptinlines.h" #include "frontend/ParseMaps-inl.h" @@ -53,21 +50,21 @@ using namespace js; /* * Asserts to verify assumptions behind pn_ macros. */ -#define pn_offsetof(m) offsetof(JSParseNode, m) +#define pn_offsetof(m) offsetof(ParseNode, m) JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses)); #undef pn_offsetof void -JSParseNode::become(JSParseNode *pn2) +ParseNode::become(ParseNode *pn2) { JS_ASSERT(!pn_defn); JS_ASSERT(!pn2->isDefn()); JS_ASSERT(!pn_used); if (pn2->isUsed()) { - JSParseNode **pnup = &pn2->pn_lexdef->dn_uses; + ParseNode **pnup = &pn2->pn_lexdef->dn_uses; while (*pnup != pn2) pnup = &(*pnup)->pn_link; *pnup = this; @@ -102,7 +99,7 @@ JSParseNode::become(JSParseNode *pn2) } void -JSParseNode::clear() +ParseNode::clear() { pn_type = TOK_EOF; setOp(JSOP_NOP); @@ -111,9 +108,8 @@ JSParseNode::clear() pn_parens = false; } - bool -JSFunctionBox::joinable() const +FunctionBox::joinable() const { return function()->isNullClosure() && (tcflags & (TCF_FUN_USES_ARGUMENTS | @@ -122,9 +118,9 @@ JSFunctionBox::joinable() const } bool -JSFunctionBox::inAnyDynamicScope() const +FunctionBox::inAnyDynamicScope() const { - for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) { + for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) { if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_EXTENSIBLE_SCOPE)) return true; } @@ -132,19 +128,17 @@ JSFunctionBox::inAnyDynamicScope() const } bool -JSFunctionBox::scopeIsExtensible() const +FunctionBox::scopeIsExtensible() const { return tcflags & TCF_FUN_EXTENSIBLE_SCOPE; } -namespace js { - /* Add |node| to |parser|'s free node list. */ void -AddNodeToFreeList(JSParseNode *pn, js::Parser *parser) +ParseNodeAllocator::freeNode(ParseNode *pn) { /* Catch back-to-back dup recycles. */ - JS_ASSERT(pn != parser->nodeList); + JS_ASSERT(pn != freelist); /* * It's too hard to clear these nodes from the AtomDefnMaps, etc. that @@ -156,19 +150,19 @@ AddNodeToFreeList(JSParseNode *pn, js::Parser *parser) JS_ASSERT(!pn->isDefn()); if (pn->isArity(PN_NAMESET) && pn->pn_names.hasMap()) - pn->pn_names.releaseMap(parser->context); + pn->pn_names.releaseMap(cx); #ifdef DEBUG /* Poison the node, to catch attempts to use it without initializing it. */ memset(pn, 0xab, sizeof(*pn)); #endif - pn->pn_next = parser->nodeList; - parser->nodeList = pn; + pn->pn_next = freelist; + freelist = pn; } /* - * A work pool of JSParseNodes. The work pool is a stack, chained together + * A work pool of ParseNodes. The work pool is a stack, chained together * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks * when recycling deep parse trees. * @@ -180,59 +174,56 @@ class NodeStack { public: NodeStack() : top(NULL) { } bool empty() { return top == NULL; } - void push(JSParseNode *pn) { + void push(ParseNode *pn) { pn->pn_next = top; top = pn; } - void pushUnlessNull(JSParseNode *pn) { if (pn) push(pn); } + void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); } /* Push the children of the PN_LIST node |pn| on the stack. */ - void pushList(JSParseNode *pn) { + void pushList(ParseNode *pn) { /* This clobbers pn->pn_head if the list is empty; should be okay. */ *pn->pn_tail = top; top = pn->pn_head; } - JSParseNode *pop() { + ParseNode *pop() { JS_ASSERT(!empty()); - JSParseNode *hold = top; /* my kingdom for a prog1 */ + ParseNode *hold = top; /* my kingdom for a prog1 */ top = top->pn_next; return hold; } private: - JSParseNode *top; + ParseNode *top; }; -} /* namespace js */ - /* * Push the children of |pn| on |stack|. Return true if |pn| itself could be * safely recycled, or false if it must be cleaned later (pn_used and pn_defn * nodes, and all function nodes; see comments for * js::Parser::cleanFunctionList). Some callers want to free |pn|; others - * (PrepareNodeForMutation) don't care about |pn|, and just need to take care of - * its children. + * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and + * just need to take care of its children. */ static bool -PushNodeChildren(JSParseNode *pn, NodeStack *stack) +PushNodeChildren(ParseNode *pn, NodeStack *stack) { switch (pn->getArity()) { case PN_FUNC: /* - * Function nodes are linked into the function box tree, and may - * appear on method lists. Both of those lists are singly-linked, - * so trying to update them now could result in quadratic behavior - * when recycling trees containing many functions; and the lists - * can be very long. So we put off cleaning the lists up until just - * before function analysis, when we call - * js::Parser::cleanFunctionList. + * Function nodes are linked into the function box tree, and may appear + * on method lists. Both of those lists are singly-linked, so trying to + * update them now could result in quadratic behavior when recycling + * trees containing many functions; and the lists can be very long. So + * we put off cleaning the lists up until just before function + * analysis, when we call js::Parser::cleanFunctionList. * - * In fact, we can't recycle the parse node yet, either: it may - * appear on a method list, and reusing the node would corrupt - * that. Instead, we clear its pn_funbox pointer to mark it as - * deleted; js::Parser::cleanFunctionList recycles it as well. + * In fact, we can't recycle the parse node yet, either: it may appear + * on a method list, and reusing the node would corrupt that. Instead, + * we clear its pn_funbox pointer to mark it as deleted; + * js::Parser::cleanFunctionList recycles it as well. * - * We do recycle the nodes around it, though, so we must clear - * pointers to them to avoid leaving dangling references where - * someone can find them. + * We do recycle the nodes around it, though, so we must clear pointers + * to them to avoid leaving dangling references where someone can find + * them. */ pn->pn_funbox = NULL; stack->pushUnlessNull(pn->pn_body); @@ -242,12 +233,11 @@ PushNodeChildren(JSParseNode *pn, NodeStack *stack) case PN_NAME: /* * Because used/defn nodes appear in AtomDefnMaps and elsewhere, we - * don't recycle them. (We'll recover their storage when we free - * the temporary arena.) However, we do recycle the nodes around - * them, so clean up the pointers to avoid dangling references. The - * top-level decls table carries references to them that later - * iterations through the compileScript loop may find, so they need - * to be neat. + * don't recycle them. (We'll recover their storage when we free the + * temporary arena.) However, we do recycle the nodes around them, so + * clean up the pointers to avoid dangling references. The top-level + * decls table carries references to them that later iterations through + * the compileScript loop may find, so they need to be neat. * * pn_expr and pn_lexdef share storage; the latter isn't an owning * reference. @@ -287,15 +277,13 @@ PushNodeChildren(JSParseNode *pn, NodeStack *stack) return true; } -namespace js { - /* * Prepare |pn| to be mutated in place into a new kind of node. Recycle all * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from * metadata structures (the function box tree). */ void -PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc) +ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn) { if (!pn->isArity(PN_NULLARY)) { if (pn->isArity(PN_FUNC)) { @@ -326,7 +314,7 @@ PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc) while (!stack.empty()) { pn = stack.pop(); if (PushNodeChildren(pn, &stack)) - AddNodeToFreeList(pn, tc->parser); + freeNode(pn); } } } @@ -341,18 +329,18 @@ PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc) * recycle some part of it (unless you've updated |tc|->functionList, the * way js_FoldConstants does). */ -JSParseNode * -RecycleTree(JSParseNode *pn, JSTreeContext *tc) +ParseNode * +ParseNodeAllocator::freeTree(ParseNode *pn) { if (!pn) return NULL; - JSParseNode *savedNext = pn->pn_next; + ParseNode *savedNext = pn->pn_next; NodeStack stack; for (;;) { if (PushNodeChildren(pn, &stack)) - AddNodeToFreeList(pn, tc->parser); + freeNode(pn); if (stack.empty()) break; pn = stack.pop(); @@ -362,62 +350,37 @@ RecycleTree(JSParseNode *pn, JSTreeContext *tc) } /* - * Allocate a JSParseNode from tc's node freelist or, failing that, from + * Allocate a ParseNode from parser's node freelist or, failing that, from * cx's temporary arena. */ -JSParseNode * -NewOrRecycledNode(JSTreeContext *tc) +void * +ParseNodeAllocator::allocNode() { - JSParseNode *pn; - - pn = tc->parser->nodeList; - if (!pn) { - JSContext *cx = tc->parser->context; - pn = cx->tempLifoAlloc().new_(); - if (!pn) - js_ReportOutOfMemory(cx); - } else { - tc->parser->nodeList = pn->pn_next; + if (ParseNode *pn = freelist) { + freelist = pn->pn_next; + return pn; } - if (pn) { - pn->setUsed(false); - pn->setDefn(false); - memset(&pn->pn_u, 0, sizeof pn->pn_u); - pn->pn_next = NULL; - } - return pn; + void *p = cx->tempLifoAlloc().alloc(sizeof (ParseNode)); + if (!p) + js_ReportOutOfMemory(cx); + return p; } -} /* namespace js */ - /* used only by static create methods of subclasses */ -JSParseNode * -JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) +ParseNode * +ParseNode::create(ParseNodeArity arity, TreeContext *tc) { - const Token &tok = tc->parser->tokenStream.currentToken(); - return create(arity, tok.type, JSOP_NOP, tok.pos, tc); + Parser *parser = tc->parser; + const Token &tok = parser->tokenStream.currentToken(); + return parser->new_(tok.type, JSOP_NOP, arity, tok.pos); } -JSParseNode * -JSParseNode::create(JSParseNodeArity arity, TokenKind type, JSOp op, const TokenPos &pos, - JSTreeContext *tc) +ParseNode * +ParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, ParseNode *left, ParseNode *right, + TreeContext *tc) { - JSParseNode *pn = NewOrRecycledNode(tc); - if (!pn) - return NULL; - pn->init(type, op, arity); - pn->pn_pos = pos; - return pn; -} - -JSParseNode * -JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParseNode *right, - JSTreeContext *tc) -{ - JSParseNode *pn, *pn1, *pn2; - if (!left || !right) return NULL; @@ -425,11 +388,9 @@ JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParse * Flatten a left-associative (left-heavy) tree of a given operator into * a list, to reduce js_FoldConstants and js_EmitTree recursion. */ - if (left->isKind(tt) && - left->isOp(op) && - (js_CodeSpec[op].format & JOF_LEFTASSOC)) { + if (left->isKind(tt) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) { if (left->pn_arity != PN_LIST) { - pn1 = left->pn_left, pn2 = left->pn_right; + ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right; left->setArity(PN_LIST); left->pn_parens = false; left->initList(pn1); @@ -466,32 +427,21 @@ JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParse if (tt == TOK_PLUS && left->isKind(TOK_NUMBER) && right->isKind(TOK_NUMBER) && - tc->parser->foldConstants) { + tc->parser->foldConstants) + { left->pn_dval += right->pn_dval; left->pn_pos.end = right->pn_pos.end; - RecycleTree(right, tc); + tc->freeTree(right); return left; } - pn = NewOrRecycledNode(tc); - if (!pn) - return NULL; - pn->init(tt, op, PN_BINARY); - pn->pn_pos.begin = left->pn_pos.begin; - pn->pn_pos.end = right->pn_pos.end; - pn->pn_left = left; - pn->pn_right = right; - return pn; + return tc->parser->new_(tt, op, left, right); } -namespace js { - NameNode * -NameNode::create(JSAtom *atom, JSTreeContext *tc) +NameNode::create(JSAtom *atom, TreeContext *tc) { - JSParseNode *pn; - - pn = JSParseNode::create(PN_NAME, tc); + ParseNode *pn = ParseNode::create(PN_NAME, tc); if (pn) { pn->pn_atom = atom; ((NameNode *)pn)->initCommon(tc); @@ -499,14 +449,12 @@ NameNode::create(JSAtom *atom, JSTreeContext *tc) return (NameNode *)pn; } -} /* namespace js */ - const char js_argument_str[] = "argument"; const char js_variable_str[] = "variable"; const char js_unknown_str[] = "unknown"; const char * -JSDefinition::kindString(Kind kind) +Definition::kindString(Kind kind) { static const char *table[] = { js_var_str, js_const_str, js_let_str, @@ -523,23 +471,18 @@ JSDefinition::kindString(Kind kind) * This function assumes the cloned tree is for use in the same statement and * binding context as the original tree. */ -static JSParseNode * -CloneParseTree(JSParseNode *opn, JSTreeContext *tc) +static ParseNode * +CloneParseTree(ParseNode *opn, TreeContext *tc) { JS_CHECK_RECURSION(tc->parser->context, return NULL); - JSParseNode *pn, *pn2, *opn2; - - pn = NewOrRecycledNode(tc); + ParseNode *pn = tc->parser->new_(opn->getKind(), opn->getOp(), opn->getArity(), + opn->pn_pos); if (!pn) return NULL; - pn->setKind(opn->getKind()); - pn->setOp(opn->getOp()); - pn->setUsed(opn->isUsed()); - pn->setDefn(opn->isDefn()); - pn->setArity(opn->getArity()); pn->setInParens(opn->isInParens()); - pn->pn_pos = opn->pn_pos; + pn->setDefn(opn->isDefn()); + pn->setUsed(opn->isUsed()); switch (pn->getArity()) { #define NULLCHECK(e) JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO @@ -555,7 +498,8 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) case PN_LIST: pn->makeEmpty(); - for (opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { + for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { + ParseNode *pn2; NULLCHECK(pn2 = CloneParseTree(opn2, tc)); pn->append(pn2); } @@ -592,7 +536,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) * The old name is a use of its pn_lexdef. Make the clone also be a * use of that definition. */ - JSDefinition *dn = pn->pn_lexdef; + Definition *dn = pn->pn_lexdef; pn->pn_link = dn->dn_uses; dn->dn_uses = pn; @@ -605,7 +549,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) */ if (opn->isDefn()) { opn->setDefn(false); - LinkUseToDef(opn, (JSDefinition *) pn, tc); + LinkUseToDef(opn, (Definition *) pn, tc); } } break; @@ -627,8 +571,6 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) #endif /* JS_HAS_DESTRUCTURING */ -namespace js { - /* * Used by Parser::forStatement and comprehensionTail to clone the TARGET in * for (var/const/let TARGET in EXPR) @@ -639,37 +581,35 @@ namespace js { * The cloned tree is for use only in the same statement and binding context as * the original tree. */ -JSParseNode * -CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc) +ParseNode * +js::CloneLeftHandSide(ParseNode *opn, TreeContext *tc) { - JSParseNode *pn = NewOrRecycledNode(tc); + ParseNode *pn = tc->parser->new_(opn->getKind(), opn->getOp(), opn->getArity(), + opn->pn_pos); if (!pn) return NULL; - pn->setKind(opn->getKind()); - pn->setOp(opn->getOp()); - pn->setUsed(opn->isUsed()); - pn->setDefn(opn->isDefn()); - pn->setArity(opn->getArity()); pn->setInParens(opn->isInParens()); - pn->pn_pos = opn->pn_pos; + pn->setDefn(opn->isDefn()); + pn->setUsed(opn->isUsed()); #if JS_HAS_DESTRUCTURING if (opn->isArity(PN_LIST)) { JS_ASSERT(opn->isKind(TOK_RB) || opn->isKind(TOK_RC)); pn->makeEmpty(); - for (JSParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { - JSParseNode *pn2; + for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { + ParseNode *pn2; if (opn->isKind(TOK_RC)) { JS_ASSERT(opn2->isArity(PN_BINARY)); JS_ASSERT(opn2->isKind(TOK_COLON)); - JSParseNode *tag = CloneParseTree(opn2->pn_left, tc); + ParseNode *tag = CloneParseTree(opn2->pn_left, tc); if (!tag) return NULL; - JSParseNode *target = CloneLeftHandSide(opn2->pn_right, tc); + ParseNode *target = CloneLeftHandSide(opn2->pn_right, tc); if (!target) return NULL; - pn2 = BinaryNode::create(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target, tc); + + pn2 = tc->parser->new_(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target); } else if (opn2->isArity(PN_NULLARY)) { JS_ASSERT(opn2->isKind(TOK_COMMA)); pn2 = CloneParseTree(opn2, tc); @@ -693,7 +633,7 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc) pn->pn_u.name = opn->pn_u.name; pn->setOp(JSOP_SETNAME); if (opn->isUsed()) { - JSDefinition *dn = pn->pn_lexdef; + Definition *dn = pn->pn_lexdef; pn->pn_link = dn->dn_uses; dn->dn_uses = pn; @@ -705,10 +645,8 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc) pn->pn_dflags &= ~PND_BOUND; pn->setDefn(false); - LinkUseToDef(pn, (JSDefinition *) opn, tc); + LinkUseToDef(pn, (Definition *) opn, tc); } } return pn; } - -} /* namespace js */ diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 885c861ff9a3..ee0dc9e798cf 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -46,6 +46,8 @@ #include "frontend/ParseMaps.h" #include "frontend/TokenStream.h" +namespace js { + /* * Parsing builds a tree of nodes that directs code generation. This tree is * not a concrete syntax tree in all respects (for example, || and && are left @@ -57,7 +59,7 @@ * Label Variant Members * ----- ------- ------- * - * TOK_FUNCTION name pn_funbox: ptr to JSFunctionBox holding function + * TOK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function * object containing arg and var properties. We * create the function object at parse (not emit) * time to specialize arg and var bytecodes early. @@ -74,7 +76,7 @@ * TOK_ARGSBODY list list of formal parameters followed by TOK_LC node * for function body statements as final element * pn_count: 1 + number of formal parameters - * TOK_UPVARS nameset pn_names: lexical dependencies (JSDefinitions) + * TOK_UPVARS nameset pn_names: lexical dependencies (js::Definitions) * defined in enclosing scopes, or ultimately not * defined (free variables, either global property * references or reference errors). @@ -281,7 +283,7 @@ * Label Variant Members * ----- ------- ------- * TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR - * pn_objbox: block object in JSObjectBox holder + * pn_objbox: block object in ObjectBox holder * pn_expr: block body * TOK_ARRAYCOMP list pn_count: 1 * pn_head: list of 1 element, which is block @@ -290,7 +292,7 @@ * TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP * pn_kid: array comprehension expression */ -typedef enum JSParseNodeArity { +enum ParseNodeArity { PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */ PN_UNARY, /* one kid, plus a couple of scalars */ PN_BINARY, /* two kids, plus a couple of scalars */ @@ -298,65 +300,85 @@ typedef enum JSParseNodeArity { PN_FUNC, /* function definition node */ PN_LIST, /* generic singly linked list */ PN_NAME, /* name use or definition node */ - PN_NAMESET /* JSAtomDefnMapPtr + JSParseNode ptr */ -} JSParseNodeArity; + PN_NAMESET /* AtomDefnMapPtr + ParseNode ptr */ +}; -struct JSDefinition; +struct Definition; -struct JSParseNode { +struct ParseNode { private: uint32 pn_type : 16, /* TOK_* type, see frontend/TokenStream.h */ pn_op : 8, /* see JSOp enum and jsopcode.tbl */ - pn_arity : 5, /* see JSParseNodeArity enum */ + pn_arity : 5, /* see ParseNodeArity enum */ pn_parens : 1, /* this expr was enclosed in parens */ pn_used : 1, /* name node is on a use-chain */ - pn_defn : 1; /* this node is a JSDefinition */ + pn_defn : 1; /* this node is a Definition */ public: + ParseNode(TokenKind type, JSOp op, ParseNodeArity arity) + : pn_type(type), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0), + pn_offset(0), pn_next(NULL), pn_link(NULL) + { + pn_pos.begin.index = 0; + pn_pos.begin.lineno = 0; + pn_pos.end.index = 0; + pn_pos.end.lineno = 0; + memset(&pn_u, 0, sizeof pn_u); + } + + ParseNode(TokenKind type, JSOp op, ParseNodeArity arity, const TokenPos &pos) + : pn_type(type), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0), + pn_pos(pos), pn_offset(0), pn_next(NULL), pn_link(NULL) + { + memset(&pn_u, 0, sizeof pn_u); + } + JSOp getOp() const { return JSOp(pn_op); } void setOp(JSOp op) { pn_op = op; } bool isOp(JSOp op) const { return getOp() == op; } - js::TokenKind getKind() const { return js::TokenKind(pn_type); } - void setKind(js::TokenKind kind) { pn_type = kind; } - bool isKind(js::TokenKind kind) const { return getKind() == kind; } - JSParseNodeArity getArity() const { return JSParseNodeArity(pn_arity); } - bool isArity(JSParseNodeArity a) const { return getArity() == a; } - void setArity(JSParseNodeArity a) { pn_arity = a; } + TokenKind getKind() const { return TokenKind(pn_type); } + void setKind(TokenKind kind) { pn_type = kind; } + bool isKind(TokenKind kind) const { return getKind() == kind; } + ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); } + bool isArity(ParseNodeArity a) const { return getArity() == a; } + void setArity(ParseNodeArity a) { pn_arity = a; } + /* Boolean attributes. */ bool isInParens() const { return pn_parens; } void setInParens(bool enabled) { pn_parens = enabled; } - bool isDefn() const { return pn_defn; } - void setDefn(bool enabled) { pn_defn = enabled; } bool isUsed() const { return pn_used; } void setUsed(bool enabled) { pn_used = enabled; } + bool isDefn() const { return pn_defn; } + void setDefn(bool enabled) { pn_defn = enabled; } - js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ + TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32 pn_offset; /* first generated bytecode offset */ - JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */ - JSParseNode *pn_link; /* def/use link (alignment freebie); - also links JSFunctionBox::methods + ParseNode *pn_next; /* intrinsic link in parent PN_LIST */ + ParseNode *pn_link; /* def/use link (alignment freebie); + also links FunctionBox::methods lists of would-be |this| methods */ + union { struct { /* list of next-linked nodes */ - JSParseNode *head; /* first node in list */ - JSParseNode **tail; /* ptr to ptr to last node in list */ + ParseNode *head; /* first node in list */ + ParseNode **tail; /* ptr to ptr to last node in list */ uint32 count; /* number of nodes in list */ uint32 xflags:12, /* extra flags, see below */ blockid:20; /* see name variant below */ } list; struct { /* ternary: if, for(;;), ?: */ - JSParseNode *kid1; /* condition, discriminant, etc. */ - JSParseNode *kid2; /* then-part, case list, etc. */ - JSParseNode *kid3; /* else-part, default case, etc. */ + ParseNode *kid1; /* condition, discriminant, etc. */ + ParseNode *kid2; /* then-part, case list, etc. */ + ParseNode *kid3; /* else-part, default case, etc. */ } ternary; struct { /* two kids if binary */ - JSParseNode *left; - JSParseNode *right; - js::Value *pval; /* switch case value */ + ParseNode *left; + ParseNode *right; + Value *pval; /* switch case value */ uintN iflags; /* JSITER_* flags for TOK_FOR node */ } binary; struct { /* one kid if unary */ - JSParseNode *kid; + ParseNode *kid; jsint num; /* -1 or sharp variable number */ JSBool hidden; /* hidden genexp-induced JSOP_YIELD or directive prologue member (as @@ -365,15 +387,15 @@ struct JSParseNode { struct { /* name, labeled statement, etc. */ union { JSAtom *atom; /* lexical name or label atom */ - JSFunctionBox *funbox; /* function object */ - JSObjectBox *objbox; /* block or regexp object */ + FunctionBox *funbox; /* function object */ + ObjectBox *objbox; /* block or regexp object */ }; union { - JSParseNode *expr; /* function body, var initializer, or + ParseNode *expr; /* function body, var initializer, or base object of TOK_DOT */ - JSDefinition *lexdef; /* lexical definition for this use */ + Definition *lexdef; /* lexical definition for this use */ }; - js::UpvarCookie cookie; /* upvar cookie with absolute frame + UpvarCookie cookie; /* upvar cookie with absolute frame level (not relative skip), possibly in current frame */ uint32 dflags:12, /* definition/use flags, see below */ @@ -381,11 +403,11 @@ struct JSParseNode { computation */ } name; struct { /* lexical dependencies + sub-tree */ - js::AtomDefnMapPtr defnMap; - JSParseNode *tree; /* sub-tree containing name uses */ + AtomDefnMapPtr defnMap; + ParseNode *tree; /* sub-tree containing name uses */ } nameset; struct { /* PN_NULLARY variant for E4X XML PI */ - js::PropertyName *target; /* target in */ + PropertyName *target; /* target in */ JSAtom *data; /* data (or null) in */ } xmlpi; jsdouble dval; /* aligned numeric literal value */ @@ -422,8 +444,8 @@ struct JSParseNode { #define pn_pitarget pn_u.xmlpi.target #define pn_pidata pn_u.xmlpi.data -protected: - void init(js::TokenKind type, JSOp op, JSParseNodeArity arity) { + protected: + void init(TokenKind type, JSOp op, ParseNodeArity arity) { pn_type = type; pn_op = op; pn_arity = arity; @@ -434,16 +456,11 @@ protected: pn_next = pn_link = NULL; } - static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc); - static JSParseNode *create(JSParseNodeArity arity, js::TokenKind type, JSOp op, - const js::TokenPos &pos, JSTreeContext *tc); + static ParseNode *create(ParseNodeArity arity, TreeContext *tc); -public: - static JSParseNode *newBinaryOrAppend(js::TokenKind tt, JSOp op, JSParseNode *left, - JSParseNode *right, JSTreeContext *tc); - - static JSParseNode *newTernary(js::TokenKind tt, JSOp op, JSParseNode *kid1, JSParseNode *kid2, - JSParseNode *kid3, JSTreeContext *tc); + public: + static ParseNode *newBinaryOrAppend(TokenKind tt, JSOp op, ParseNode *left, ParseNode *right, + TreeContext *tc); /* * The pn_expr and lexdef members are arms of an unsafe union. Unless you @@ -451,20 +468,20 @@ public: * them. For less overhead and assertions for protection, use pn->expr() * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef(). */ - JSParseNode *expr() const { + ParseNode *expr() const { JS_ASSERT(!pn_used); JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_FUNC); return pn_expr; } - JSDefinition *lexdef() const { + Definition *lexdef() const { JS_ASSERT(pn_used || isDeoptimized()); JS_ASSERT(pn_arity == PN_NAME); return pn_lexdef; } - JSParseNode *maybeExpr() { return pn_used ? NULL : expr(); } - JSDefinition *maybeLexDef() { return pn_used ? lexdef() : NULL; } + ParseNode *maybeExpr() { return pn_used ? NULL : expr(); } + Definition *maybeLexDef() { return pn_used ? lexdef() : NULL; } /* PN_FUNC and PN_NAME pn_dflags bits. */ #define PND_LET 0x01 /* let (block-scoped) binding */ @@ -543,17 +560,17 @@ public: */ bool isTopLevel() const { return test(PND_TOPLEVEL); } - /* Defined below, see after struct JSDefinition. */ + /* Defined below, see after struct Definition. */ void setFunArg(); - void become(JSParseNode *pn2); + void become(ParseNode *pn2); void clear(); /* True if pn is a parsenode representing a literal constant. */ bool isLiteral() const { - return isKind(js::TOK_NUMBER) || - isKind(js::TOK_STRING) || - (isKind(js::TOK_PRIMARY) && !isOp(JSOP_THIS)); + return isKind(TOK_NUMBER) || + isKind(TOK_STRING) || + (isKind(TOK_PRIMARY) && !isOp(JSOP_THIS)); } /* @@ -572,10 +589,10 @@ public: * a directive. */ bool isStringExprStatement() const { - if (getKind() == js::TOK_SEMI) { + if (getKind() == TOK_SEMI) { JS_ASSERT(pn_arity == PN_UNARY); - JSParseNode *kid = pn_kid; - return kid && kid->getKind() == js::TOK_STRING && !kid->pn_parens; + ParseNode *kid = pn_kid; + return kid && kid->getKind() == TOK_STRING && !kid->pn_parens; } return false; } @@ -586,7 +603,7 @@ public: * contain escape sequences or line continuations. */ bool isEscapeFreeStringLiteral() const { - JS_ASSERT(pn_type == js::TOK_STRING && !pn_parens); + JS_ASSERT(pn_type == TOK_STRING && !pn_parens); JSString *str = pn_atom; /* @@ -606,26 +623,26 @@ public: * True if this node is a desugared generator expression. */ bool isGeneratorExpr() const { - if (getKind() == js::TOK_LP) { - JSParseNode *callee = this->pn_head; - if (callee->getKind() == js::TOK_FUNCTION) { - JSParseNode *body = (callee->pn_body->getKind() == js::TOK_UPVARS) - ? callee->pn_body->pn_tree - : callee->pn_body; - if (body->getKind() == js::TOK_LEXICALSCOPE) + if (getKind() == TOK_LP) { + ParseNode *callee = this->pn_head; + if (callee->getKind() == TOK_FUNCTION) { + ParseNode *body = (callee->pn_body->getKind() == TOK_UPVARS) + ? callee->pn_body->pn_tree + : callee->pn_body; + if (body->getKind() == TOK_LEXICALSCOPE) return true; } } return false; } - JSParseNode *generatorExpr() const { + ParseNode *generatorExpr() const { JS_ASSERT(isGeneratorExpr()); - JSParseNode *callee = this->pn_head; - JSParseNode *body = callee->pn_body->getKind() == js::TOK_UPVARS - ? callee->pn_body->pn_tree - : callee->pn_body; - JS_ASSERT(body->getKind() == js::TOK_LEXICALSCOPE); + ParseNode *callee = this->pn_head; + ParseNode *body = callee->pn_body->getKind() == TOK_UPVARS + ? callee->pn_body->pn_tree + : callee->pn_body; + JS_ASSERT(body->getKind() == TOK_LEXICALSCOPE); return body->pn_expr; } #endif @@ -634,10 +651,10 @@ public: * Compute a pointer to the last element in a singly-linked list. NB: list * must be non-empty for correct PN_LAST usage -- this is asserted! */ - JSParseNode *last() const { + ParseNode *last() const { JS_ASSERT(pn_arity == PN_LIST); JS_ASSERT(pn_count != 0); - return (JSParseNode *)(uintptr_t(pn_tail) - offsetof(JSParseNode, pn_next)); + return (ParseNode *)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next)); } void makeEmpty() { @@ -649,7 +666,7 @@ public: pn_blockid = 0; } - void initList(JSParseNode *pn) { + void initList(ParseNode *pn) { JS_ASSERT(pn_arity == PN_LIST); pn_head = pn; pn_tail = &pn->pn_next; @@ -658,122 +675,110 @@ public: pn_blockid = 0; } - void append(JSParseNode *pn) { + void append(ParseNode *pn) { JS_ASSERT(pn_arity == PN_LIST); *pn_tail = pn; pn_tail = &pn->pn_next; pn_count++; } - bool getConstantValue(JSContext *cx, bool strictChecks, js::Value *vp); + bool getConstantValue(JSContext *cx, bool strictChecks, Value *vp); inline bool isConstant(); }; -namespace js { - -struct NullaryNode : public JSParseNode { - static inline NullaryNode *create(JSTreeContext *tc) { - return (NullaryNode *)JSParseNode::create(PN_NULLARY, tc); +struct NullaryNode : public ParseNode { + static inline NullaryNode *create(TreeContext *tc) { + return (NullaryNode *)ParseNode::create(PN_NULLARY, tc); } }; -struct UnaryNode : public JSParseNode { - static inline UnaryNode *create(JSTreeContext *tc) { - return (UnaryNode *)JSParseNode::create(PN_UNARY, tc); +struct UnaryNode : public ParseNode { + UnaryNode(TokenKind type, JSOp op, const TokenPos &pos, ParseNode *kid) + : ParseNode(type, op, PN_UNARY, pos) + { + pn_kid = kid; + } + + static inline UnaryNode *create(TreeContext *tc) { + return (UnaryNode *)ParseNode::create(PN_UNARY, tc); } }; -struct BinaryNode : public JSParseNode { - static inline BinaryNode *create(TokenKind type, JSOp op, const TokenPos &pos, - JSParseNode *left, JSParseNode *right, - JSTreeContext *tc) { - BinaryNode *pn = (BinaryNode *) JSParseNode::create(PN_BINARY, type, op, pos, tc); - if (pn) { - pn->pn_left = left; - pn->pn_right = right; - } - return pn; +struct BinaryNode : public ParseNode { + BinaryNode(TokenKind type, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right) + : ParseNode(type, op, PN_BINARY, pos) + { + pn_left = left; + pn_right = right; } - static inline BinaryNode *create(JSTreeContext *tc) { - return (BinaryNode *)JSParseNode::create(PN_BINARY, tc); + BinaryNode(TokenKind type, JSOp op, ParseNode *left, ParseNode *right) + : ParseNode(type, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos)) + { + pn_left = left; + pn_right = right; + } + + static inline BinaryNode *create(TreeContext *tc) { + return (BinaryNode *)ParseNode::create(PN_BINARY, tc); } }; -struct TernaryNode : public JSParseNode { - static inline TernaryNode *create(TokenKind type, JSOp op, - JSParseNode *kid1, JSParseNode *kid2, JSParseNode *kid3, - JSTreeContext *tc) { - TokenPos pos; - pos.begin = (kid1 ? kid1 : kid2)->pn_pos.begin; - pos.end = kid3->pn_pos.end; - TernaryNode *pn = (TernaryNode *) JSParseNode::create(PN_TERNARY, type, op, pos, tc); - if (pn) { - pn->pn_kid1 = kid1; - pn->pn_kid2 = kid2; - pn->pn_kid3 = kid3; - } - return pn; +struct TernaryNode : public ParseNode { + TernaryNode(TokenKind type, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3) + : ParseNode(type, op, PN_TERNARY, + TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin, + (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end)) + { + pn_kid1 = kid1; + pn_kid2 = kid2; + pn_kid3 = kid3; } - static inline TernaryNode *create(JSTreeContext *tc) { - return (TernaryNode *)JSParseNode::create(PN_TERNARY, tc); + static inline TernaryNode *create(TreeContext *tc) { + return (TernaryNode *)ParseNode::create(PN_TERNARY, tc); } }; -struct ListNode : public JSParseNode { - static inline ListNode *create(JSTreeContext *tc) { - return (ListNode *)JSParseNode::create(PN_LIST, tc); +struct ListNode : public ParseNode { + static inline ListNode *create(TreeContext *tc) { + return (ListNode *)ParseNode::create(PN_LIST, tc); } }; -struct FunctionNode : public JSParseNode { - static inline FunctionNode *create(JSTreeContext *tc) { - return (FunctionNode *)JSParseNode::create(PN_FUNC, tc); +struct FunctionNode : public ParseNode { + static inline FunctionNode *create(TreeContext *tc) { + return (FunctionNode *)ParseNode::create(PN_FUNC, tc); } }; -struct NameNode : public JSParseNode { - static NameNode *create(JSAtom *atom, JSTreeContext *tc); +struct NameNode : public ParseNode { + static NameNode *create(JSAtom *atom, TreeContext *tc); - void inline initCommon(JSTreeContext *tc); + inline void initCommon(TreeContext *tc); }; -struct NameSetNode : public JSParseNode { - static inline NameSetNode *create(JSTreeContext *tc) { - return (NameSetNode *)JSParseNode::create(PN_NAMESET, tc); +struct NameSetNode : public ParseNode { + static inline NameSetNode *create(TreeContext *tc) { + return (NameSetNode *)ParseNode::create(PN_NAMESET, tc); } }; -struct LexicalScopeNode : public JSParseNode { - static inline LexicalScopeNode *create(JSTreeContext *tc) { - return (LexicalScopeNode *)JSParseNode::create(PN_NAME, tc); +struct LexicalScopeNode : public ParseNode { + static inline LexicalScopeNode *create(TreeContext *tc) { + return (LexicalScopeNode *)ParseNode::create(PN_NAME, tc); } }; -JSParseNode * -NewOrRecycledNode(JSTreeContext *tc); - -void -AddNodeToFreeList(JSParseNode *pn, Parser *parser); - -void -PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc); - -JSParseNode * -RecycleTree(JSParseNode *pn, JSTreeContext *tc); - -JSParseNode * -CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc); - -} /* namespace js */ +ParseNode * +CloneLeftHandSide(ParseNode *opn, TreeContext *tc); /* - * JSDefinition is a degenerate subtype of the PN_FUNC and PN_NAME variants of - * JSParseNode, allocated only for function, var, const, and let declarations - * that define truly lexical bindings. This means that a child of a TOK_VAR - * list may be a JSDefinition instead of a JSParseNode. The pn_defn bit is set - * for all JSDefinitions, clear otherwise. + * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants + * of js::ParseNode, allocated only for function, var, const, and let + * declarations that define truly lexical bindings. This means that a child of + * a TOK_VAR list may be a Definition instead of a ParseNode. The pn_defn + * bit is set for all Definitions, clear otherwise. * * In an upvars list, defn->resolve() is the outermost definition the * name may reference. If a with block or a function that calls eval encloses @@ -806,24 +811,24 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc); * for (each use of unqualified name x in parse order) { * if (this use of x is a declaration) { * if (x in tc->decls) { // redeclaring - * pn = allocate a PN_NAME JSParseNode; + * pn = allocate a PN_NAME ParseNode; * } else { // defining * dn = lookup x in tc->lexdeps; * if (dn) // use before def * remove x from tc->lexdeps; * else // def before use - * dn = allocate a PN_NAME JSDefinition; + * dn = allocate a PN_NAME Definition; * map x to dn via tc->decls; * pn = dn; * } * insert pn into its parent TOK_VAR list; * } else { - * pn = allocate a JSParseNode for this reference to x; + * pn = allocate a ParseNode for this reference to x; * dn = lookup x in tc's lexical scope chain; * if (!dn) { * dn = lookup x in tc->lexdeps; * if (!dn) { - * dn = pre-allocate a JSDefinition for x; + * dn = pre-allocate a Definition for x; * map x to dn in tc->lexdeps; * } * } @@ -831,13 +836,13 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc); * } * } * - * See frontend/BytecodeGenerator.h for JSTreeContext and its top*Stmt, decls, and - * lexdeps members. + * See frontend/BytecodeGenerator.h for js::TreeContext and its top*Stmt, + * decls, and lexdeps members. * * Notes: * - * 0. To avoid bloating JSParseNode, we steal a bit from pn_arity for pn_defn - * and set it on a JSParseNode instead of allocating a JSDefinition. + * 0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn + * and set it on a ParseNode instead of allocating a Definition. * * 1. Due to hoisting, a definition cannot be eliminated even if its "Variable * statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in @@ -888,10 +893,10 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc); */ #define dn_uses pn_link -struct JSDefinition : public JSParseNode +struct Definition : public ParseNode { /* - * We store definition pointers in PN_NAMESET JSAtomDefnMapPtrs in the AST, + * We store definition pointers in PN_NAMESET AtomDefnMapPtrs in the AST, * but due to redefinition these nodes may become uses of other * definitions. This is unusual, so we simply chase the pn_lexdef link to * find the final definition node. See methods called from @@ -899,16 +904,16 @@ struct JSDefinition : public JSParseNode * * FIXME: MakeAssignment mutates for want of a parent link... */ - JSDefinition *resolve() { - JSParseNode *pn = this; + Definition *resolve() { + ParseNode *pn = this; while (!pn->isDefn()) { - if (pn->getKind() == js::TOK_ASSIGN) { + if (pn->getKind() == TOK_ASSIGN) { pn = pn->pn_left; continue; } pn = pn->lexdef(); } - return (JSDefinition *) pn; + return (Definition *) pn; } bool isFreeVar() const { @@ -928,9 +933,9 @@ struct JSDefinition : public JSParseNode static const char *kindString(Kind kind); Kind kind() { - if (getKind() == js::TOK_FUNCTION) + if (getKind() == TOK_FUNCTION) return FUNCTION; - JS_ASSERT(getKind() == js::TOK_NAME); + JS_ASSERT(getKind() == TOK_NAME); if (isOp(JSOP_NOP)) return UNKNOWN; if (isOp(JSOP_GETARG)) @@ -943,13 +948,27 @@ struct JSDefinition : public JSParseNode } }; +class ParseNodeAllocator { + public: + explicit ParseNodeAllocator(JSContext *cx) : cx(cx), freelist(NULL) {} + + void *allocNode(); + void freeNode(ParseNode *pn); + ParseNode *freeTree(ParseNode *pn); + void prepareNodeForMutation(ParseNode *pn); + + private: + JSContext *cx; + ParseNode *freelist; +}; + inline bool -JSParseNode::test(uintN flag) const +ParseNode::test(uintN flag) const { JS_ASSERT(pn_defn || pn_arity == PN_FUNC || pn_arity == PN_NAME); #ifdef DEBUG if ((flag & (PND_ASSIGNED | PND_FUNARG)) && pn_defn && !(pn_dflags & flag)) { - for (JSParseNode *pn = ((JSDefinition *) this)->dn_uses; pn; pn = pn->pn_link) { + for (ParseNode *pn = ((Definition *) this)->dn_uses; pn; pn = pn->pn_link) { JS_ASSERT(!pn->pn_defn); JS_ASSERT(!(pn->pn_dflags & flag)); } @@ -959,7 +978,7 @@ JSParseNode::test(uintN flag) const } inline void -JSParseNode::setFunArg() +ParseNode::setFunArg() { /* * pn_defn NAND pn_used must be true, per this chart: @@ -977,10 +996,8 @@ JSParseNode::setFunArg() pn_dflags |= PND_FUNARG; } -namespace js { - inline void -LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc) +LinkUseToDef(ParseNode *pn, Definition *dn, TreeContext *tc) { JS_ASSERT(!pn->isUsed()); JS_ASSERT(!pn->isDefn()); @@ -992,31 +1009,29 @@ LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc) pn->pn_lexdef = dn; } -} /* namespace js */ - -struct JSObjectBox { - JSObjectBox *traceLink; - JSObjectBox *emitLink; +struct ObjectBox { + ObjectBox *traceLink; + ObjectBox *emitLink; JSObject *object; - JSObjectBox *parent; + ObjectBox *parent; uintN index; bool isFunctionBox; }; #define JSFB_LEVEL_BITS 14 -struct JSFunctionBox : public JSObjectBox +struct FunctionBox : public ObjectBox { - JSParseNode *node; - JSFunctionBox *siblings; - JSFunctionBox *kids; - JSFunctionBox *parent; - JSParseNode *methods; /* would-be methods set on this; + ParseNode *node; + FunctionBox *siblings; + FunctionBox *kids; + FunctionBox *parent; + ParseNode *methods; /* would-be methods set on this; these nodes are linked via pn_link, since lambdas are neither definitions nor uses of a binding */ - js::Bindings bindings; /* bindings for this function */ + Bindings bindings; /* bindings for this function */ uint32 queued:1, inLoop:1, /* in a loop in parent function */ level:JSFB_LEVEL_BITS; @@ -1039,26 +1054,26 @@ struct JSFunctionBox : public JSObjectBox bool scopeIsExtensible() const; }; -struct JSFunctionBoxQueue { - JSFunctionBox **vector; +struct FunctionBoxQueue { + FunctionBox **vector; size_t head, tail; size_t lengthMask; size_t count() { return head - tail; } size_t length() { return lengthMask + 1; } - JSFunctionBoxQueue() + FunctionBoxQueue() : vector(NULL), head(0), tail(0), lengthMask(0) { } bool init(uint32 count) { lengthMask = JS_BITMASK(JS_CEILING_LOG2W(count)); - vector = (JSFunctionBox **) js::OffTheBooks::malloc_(sizeof(JSFunctionBox) * length()); + vector = (FunctionBox **) OffTheBooks::malloc_(sizeof(FunctionBox) * length()); return !!vector; } - ~JSFunctionBoxQueue() { js::UnwantedForeground::free_(vector); } + ~FunctionBoxQueue() { UnwantedForeground::free_(vector); } - void push(JSFunctionBox *funbox) { + void push(FunctionBox *funbox) { if (!funbox->queued) { JS_ASSERT(count() < length()); vector[head++ & lengthMask] = funbox; @@ -1066,14 +1081,16 @@ struct JSFunctionBoxQueue { } } - JSFunctionBox *pull() { + FunctionBox *pull() { if (tail == head) return NULL; JS_ASSERT(tail < head); - JSFunctionBox *funbox = vector[tail++ & lengthMask]; + FunctionBox *funbox = vector[tail++ & lengthMask]; funbox->queued = false; return funbox; } }; +} /* namespace js */ + #endif /* ParseNode_h__ */ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8ea4635fc6b6..0d53fb262b97 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -44,10 +44,10 @@ * This is a recursive-descent parser for the JavaScript language specified by * "The JavaScript 1.5 Language Specification". It uses lexical and semantic * feedback to disambiguate non-LL(1) structures. It generates trees of nodes - * induced by the recursive parsing (not precise syntax trees, see jsparse.h). + * induced by the recursive parsing (not precise syntax trees, see Parser.h). * After tree construction, it rewrites trees to fold constants and evaluate - * compile-time expressions. Finally, it calls js_EmitTree (see jsemit.h) to - * generate bytecode. + * compile-time expressions. Finally, it calls js::frontend::EmitTree (see + * CodeGenerator.h) to generate bytecode. * * This parser attempts no error recovery. */ @@ -101,6 +101,7 @@ using namespace js; using namespace js::gc; +using namespace js::frontend; /* * Insist that the next token be of type tt, or report errno and return null. @@ -116,13 +117,13 @@ using namespace js::gc; #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0) Parser::Parser(JSContext *cx, JSPrincipals *prin, StackFrame *cfp, bool foldConstants) - : js::AutoGCRooter(cx, PARSER), + : AutoGCRooter(cx, PARSER), context(cx), tokenStream(cx), principals(NULL), callerFrame(cfp), callerVarObj(cfp ? &cfp->varObj() : NULL), - nodeList(NULL), + allocator(cx), functionCount(0), traceListHead(NULL), tc(NULL), @@ -130,7 +131,7 @@ Parser::Parser(JSContext *cx, JSPrincipals *prin, StackFrame *cfp, bool foldCons foldConstants(foldConstants) { cx->activeCompilations++; - js::PodArrayZero(tempFreeList); + PodArrayZero(tempFreeList); setPrincipals(prin); JS_ASSERT_IF(cfp, cfp->isScriptFrame()); } @@ -169,18 +170,19 @@ Parser::setPrincipals(JSPrincipals *prin) principals = prin; } -JSObjectBox * +ObjectBox * Parser::newObjectBox(JSObject *obj) { JS_ASSERT(obj); /* - * We use JSContext.tempPool to allocate parsed objects and place them on - * a list in this Parser to ensure GC safety. Thus the tempPool arenas - * containing the entries must be alive until we are done with scanning, - * parsing and code generation for the whole script or top-level function. + * We use JSContext.tempLifoAlloc to allocate parsed objects and place them + * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc + * arenas containing the entries must be alive until we are done with + * scanning, parsing and code generation for the whole script or top-level + * function. */ - JSObjectBox *objbox = context->tempLifoAlloc().new_(); + ObjectBox *objbox = context->tempLifoAlloc().new_(); if (!objbox) { js_ReportOutOfMemory(context); return NULL; @@ -193,19 +195,20 @@ Parser::newObjectBox(JSObject *obj) return objbox; } -JSFunctionBox * -Parser::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc) +FunctionBox * +Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc) { JS_ASSERT(obj); JS_ASSERT(obj->isFunction()); /* - * We use JSContext.tempPool to allocate parsed objects and place them on - * a list in this Parser to ensure GC safety. Thus the tempPool arenas - * containing the entries must be alive until we are done with scanning, - * parsing and code generation for the whole script or top-level function. + * We use JSContext.tempLifoAlloc to allocate parsed objects and place them + * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc + * arenas containing the entries must be alive until we are done with + * scanning, parsing and code generation for the whole script or top-level + * function. */ - JSFunctionBox *funbox = context->tempLifoAlloc().newPod(); + FunctionBox *funbox = context->tempLifoAlloc().newPod(); if (!funbox) { js_ReportOutOfMemory(context); return NULL; @@ -225,7 +228,7 @@ Parser::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc) new (&funbox->bindings) Bindings(context); funbox->queued = false; funbox->inLoop = false; - for (JSStmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) { + for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) { if (STMT_IS_LOOP(stmt)) { funbox->inLoop = true; break; @@ -241,15 +244,15 @@ Parser::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc) void Parser::trace(JSTracer *trc) { - JSObjectBox *objbox = traceListHead; + ObjectBox *objbox = traceListHead; while (objbox) { MarkObject(trc, *objbox->object, "parser.object"); if (objbox->isFunctionBox) - static_cast(objbox)->bindings.trace(trc); + static_cast(objbox)->bindings.trace(trc); objbox = objbox->traceLink; } - for (JSTreeContext *tc = this->tc; tc; tc = tc->parent) + for (TreeContext *tc = this->tc; tc; tc = tc->parent) tc->trace(trc); } @@ -278,15 +281,15 @@ Parser::trace(JSTracer *trc) * function box tree; it could later be recycled, reallocated, and turned * into anything at all. (Fortunately, method list members never get * mutated, so we don't have to worry about that case.) - * PrepareNodeForMutation clears the node's function box's node pointer, - * disconnecting it entirely from the function box tree, and marking the - * function box to be trimmed out. + * ParseNodeAllocator::prepareNodeForMutation clears the node's function + * box's node pointer, disconnecting it entirely from the function box tree, + * and marking the function box to be trimmed out. */ void -Parser::cleanFunctionList(JSFunctionBox **funboxHead) +Parser::cleanFunctionList(FunctionBox **funboxHead) { - JSFunctionBox **link = funboxHead; - while (JSFunctionBox *box = *link) { + FunctionBox **link = funboxHead; + while (FunctionBox *box = *link) { if (!box->node) { /* * This funbox's parse node was mutated into something else. Drop the box, @@ -299,14 +302,14 @@ Parser::cleanFunctionList(JSFunctionBox **funboxHead) * the node, and stay at the same link. */ *link = box->siblings; - AddNodeToFreeList(box->node, this); + allocator.freeNode(box->node); } else { /* The function is still live. */ /* First, remove nodes for deleted functions from our methods list. */ { - JSParseNode **methodLink = &box->methods; - while (JSParseNode *method = *methodLink) { + ParseNode **methodLink = &box->methods; + while (ParseNode *method = *methodLink) { /* Method nodes are never rewritten in place to be other kinds of nodes. */ JS_ASSERT(method->isArity(PN_FUNC)); if (!method->pn_funbox) { @@ -329,7 +332,7 @@ Parser::cleanFunctionList(JSFunctionBox **funboxHead) } static bool -GenerateBlockIdForStmtNode(JSParseNode *pn, JSTreeContext *tc) +GenerateBlockIdForStmtNode(ParseNode *pn, TreeContext *tc) { JS_ASSERT(tc->topStmt); JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt)); @@ -343,7 +346,7 @@ GenerateBlockIdForStmtNode(JSParseNode *pn, JSTreeContext *tc) /* * Parse a top-level JS script. */ -JSParseNode * +ParseNode * Parser::parse(JSObject *chain) { /* @@ -354,20 +357,20 @@ Parser::parse(JSObject *chain) * an object lock before it finishes generating bytecode into a script * protected from the GC by a root or a stack frame reference. */ - JSTreeContext globaltc(this); + TreeContext globaltc(this); if (!globaltc.init(context)) return NULL; globaltc.setScopeChain(chain); if (!GenerateBlockId(&globaltc, globaltc.bodyid)) return NULL; - JSParseNode *pn = statements(); + ParseNode *pn = statements(); if (pn) { if (!tokenStream.matchToken(TOK_EOF)) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; } else if (foldConstants) { - if (!js_FoldConstants(context, pn, &globaltc)) + if (!FoldConstants(context, pn, &globaltc)) pn = NULL; } } @@ -387,9 +390,9 @@ JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS)); #define ENDS_IN_BREAK 2 static int -HasFinalReturn(JSParseNode *pn) +HasFinalReturn(ParseNode *pn) { - JSParseNode *pn2, *pn3; + ParseNode *pn2, *pn3; uintN rv, rv2, hasDefault; switch (pn->getKind()) { @@ -504,7 +507,7 @@ HasFinalReturn(JSParseNode *pn) } static JSBool -ReportBadReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn, uintN flags, uintN errnum, +ReportBadReturn(JSContext *cx, TreeContext *tc, ParseNode *pn, uintN flags, uintN errnum, uintN anonerrnum) { JSAutoByteString name; @@ -518,7 +521,7 @@ ReportBadReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn, uintN flags, } static JSBool -CheckFinalReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn) +CheckFinalReturn(JSContext *cx, TreeContext *tc, ParseNode *pn) { JS_ASSERT(tc->inFunction()); return HasFinalReturn(pn) == ENDS_IN_RETURN || @@ -531,7 +534,7 @@ CheckFinalReturn(JSContext *cx, JSTreeContext *tc, JSParseNode *pn) * assign to 'eval' or 'arguments'. */ static bool -CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) +CheckStrictAssignment(JSContext *cx, TreeContext *tc, ParseNode *lhs) { if (tc->needStrictChecks() && lhs->isKind(TOK_NAME)) { JSAtom *atom = lhs->pn_atom; @@ -555,7 +558,7 @@ CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) * tc's token stream if pn is NULL. */ bool -CheckStrictBinding(JSContext *cx, JSTreeContext *tc, PropertyName *name, JSParseNode *pn) +CheckStrictBinding(JSContext *cx, TreeContext *tc, PropertyName *name, ParseNode *pn) { if (!tc->needStrictChecks()) return true; @@ -575,16 +578,14 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, PropertyName *name, JSParse } static bool -ReportBadParameter(JSContext *cx, JSTreeContext *tc, JSAtom *name, uintN errorNumber) +ReportBadParameter(JSContext *cx, TreeContext *tc, JSAtom *name, uintN errorNumber) { - JSDefinition *dn = tc->decls.lookupFirst(name); + Definition *dn = tc->decls.lookupFirst(name); JSAutoByteString bytes; return js_AtomToPrintableString(cx, name, &bytes) && ReportStrictModeError(cx, TS(tc->parser), tc, dn, errorNumber, bytes.ptr()); } -namespace js { - /* * In strict mode code, all parameter names must be distinct, must not be * strict mode reserved keywords, and must not be 'eval' or 'arguments'. We @@ -592,7 +593,7 @@ namespace js { * function's body may turn on strict mode for the function head. */ bool -CheckStrictParameters(JSContext *cx, JSTreeContext *tc) +js::CheckStrictParameters(JSContext *cx, TreeContext *tc) { JS_ASSERT(tc->inFunction()); @@ -646,21 +647,19 @@ CheckStrictParameters(JSContext *cx, JSTreeContext *tc) return true; } -} /* namespace js */ - -JSParseNode * +ParseNode * Parser::functionBody() { JS_ASSERT(tc->inFunction()); - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_BLOCK, -1); stmtInfo.flags = SIF_BODY_BLOCK; uintN oldflags = tc->flags; tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID); - JSParseNode *pn; + ParseNode *pn; #if JS_HAS_EXPR_CLOSURES if (tokenStream.currentToken().type == TOK_LC) { pn = statements(); @@ -690,7 +689,7 @@ Parser::functionBody() if (pn) { JS_ASSERT(!(tc->topStmt->flags & SIF_SCOPE)); - js_PopStatement(tc); + PopStatementTC(tc); /* Check for falling off the end of a function that returns a value. */ if (context->hasStrictOption() && (tc->flags & TCF_RETURN_EXPR) && @@ -703,11 +702,11 @@ Parser::functionBody() return pn; } -/* Create a placeholder JSDefinition node for |atom|. */ -static JSDefinition * -MakePlaceholder(JSParseNode *pn, JSTreeContext *tc) +/* Create a placeholder Definition node for |atom|. */ +static Definition * +MakePlaceholder(ParseNode *pn, TreeContext *tc) { - JSDefinition *dn = (JSDefinition *) NameNode::create(pn->pn_atom, tc); + Definition *dn = (Definition *) NameNode::create(pn->pn_atom, tc); if (!dn) return NULL; @@ -719,13 +718,13 @@ MakePlaceholder(JSParseNode *pn, JSTreeContext *tc) } static bool -Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false) +Define(ParseNode *pn, JSAtom *atom, TreeContext *tc, bool let = false) { JS_ASSERT(!pn->isUsed()); JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder()); bool foundLexdep = false; - JSDefinition *dn = NULL; + Definition *dn = NULL; if (let) dn = tc->decls.lookupFirst(atom); @@ -736,13 +735,13 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false) } if (dn && dn != pn) { - JSParseNode **pnup = &dn->dn_uses; - JSParseNode *pnu; + ParseNode **pnup = &dn->dn_uses; + ParseNode *pnu; uintN start = let ? pn->pn_blockid : tc->bodyid; while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) { JS_ASSERT(pnu->isUsed()); - pnu->pn_lexdef = (JSDefinition *) pn; + pnu->pn_lexdef = (Definition *) pn; pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS; pnup = &pnu->pn_link; } @@ -757,7 +756,7 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false) } } - JSDefinition *toAdd = (JSDefinition *) pn; + Definition *toAdd = (Definition *) pn; bool ok = let ? tc->decls.addShadow(atom, toAdd) : tc->decls.addUnique(atom, toAdd); if (!ok) return false; @@ -769,32 +768,31 @@ Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false) } static void -ForgetUse(JSParseNode *pn) +ForgetUse(ParseNode *pn) { if (!pn->isUsed()) { JS_ASSERT(!pn->isDefn()); return; } - JSParseNode **pnup = &pn->lexdef()->dn_uses; - JSParseNode *pnu; + ParseNode **pnup = &pn->lexdef()->dn_uses; + ParseNode *pnu; while ((pnu = *pnup) != pn) pnup = &pnu->pn_link; *pnup = pn->pn_link; pn->setUsed(false); } -static JSParseNode * -MakeAssignment(JSParseNode *pn, JSParseNode *rhs, JSTreeContext *tc) +static ParseNode * +MakeAssignment(ParseNode *pn, ParseNode *rhs, TreeContext *tc) { - JSParseNode *lhs = NewOrRecycledNode(tc); + ParseNode *lhs = tc->parser->new_(*pn); if (!lhs) return NULL; - *lhs = *pn; if (pn->isUsed()) { - JSDefinition *dn = pn->pn_lexdef; - JSParseNode **pnup = &dn->dn_uses; + Definition *dn = pn->pn_lexdef; + ParseNode **pnup = &dn->dn_uses; while (*pnup != pn) pnup = &(*pnup)->pn_link; @@ -814,8 +812,8 @@ MakeAssignment(JSParseNode *pn, JSParseNode *rhs, JSTreeContext *tc) return lhs; } -static JSParseNode * -MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *tc) +static ParseNode * +MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, TreeContext *tc) { /* * If dn is arg, or in [var, const, let] and has an initializer, then we @@ -823,19 +821,19 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t * left-hand side becomes a use of pn. */ if (dn->isBindingForm()) { - JSParseNode *rhs = dn->expr(); + ParseNode *rhs = dn->expr(); if (rhs) { - JSParseNode *lhs = MakeAssignment(dn, rhs, tc); + ParseNode *lhs = MakeAssignment(dn, rhs, tc); if (!lhs) return NULL; //pn->dn_uses = lhs; - dn = (JSDefinition *) lhs; + dn = (Definition *) lhs; } dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME); - } else if (dn->kind() == JSDefinition::FUNCTION) { + } else if (dn->kind() == Definition::FUNCTION) { JS_ASSERT(dn->isOp(JSOP_NOP)); - PrepareNodeForMutation(dn, tc); + tc->parser->prepareNodeForMutation(dn); dn->setKind(TOK_NAME); dn->setArity(PN_NAME); dn->pn_atom = atom; @@ -846,10 +844,10 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t JS_ASSERT(dn->isArity(PN_NAME)); JS_ASSERT(dn->pn_atom == atom); - for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { + for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->isUsed()); JS_ASSERT(!pnu->isDefn()); - pnu->pn_lexdef = (JSDefinition *) pn; + pnu->pn_lexdef = (Definition *) pn; pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS; } pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS; @@ -857,18 +855,16 @@ MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *t dn->setDefn(false); dn->setUsed(true); - dn->pn_lexdef = (JSDefinition *) pn; + dn->pn_lexdef = (Definition *) pn; dn->pn_cookie.makeFree(); dn->pn_dflags &= ~PND_BOUND; return dn; } -namespace js { - bool -DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc) +js::DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc) { - JSParseNode *argpn, *argsbody; + ParseNode *argpn, *argsbody; /* Flag tc so we don't have to lookup arguments on every use. */ if (atom == tc->parser->context->runtime->atomState.argumentsAtom) @@ -907,8 +903,6 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc) return true; } -} /* namespace js */ - /* * Parameter block types for the several Binder functions. We use a common * helper function signature in order to share code among destructuring and @@ -917,12 +911,12 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc) * of CheckDestructuring and its friends. */ typedef JSBool -(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc); +(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc); struct BindData { BindData() : fresh(true) {} - JSParseNode *pn; /* name node for definition processing and + ParseNode *pn; /* name node for definition processing and error source coordinates */ JSOp op; /* prolog bytecode or nop */ Binder binder; /* binder, discriminates u */ @@ -935,7 +929,7 @@ struct BindData { }; static bool -BindLocalVariable(JSContext *cx, JSTreeContext *tc, JSParseNode *pn, BindingKind kind) +BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind) { JS_ASSERT(kind == VARIABLE || kind == CONSTANT); @@ -953,7 +947,7 @@ BindLocalVariable(JSContext *cx, JSTreeContext *tc, JSParseNode *pn, BindingKind #if JS_HAS_DESTRUCTURING static JSBool -BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) +BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc) { /* Flag tc so we don't have to lookup arguments on every use. */ if (atom == tc->parser->context->runtime->atomState.argumentsAtom) @@ -972,7 +966,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext return JS_FALSE; } - JSParseNode *pn = data->pn; + ParseNode *pn = data->pn; /* * Distinguish destructured-to binding nodes as vars, not args, by setting @@ -1001,7 +995,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext #endif /* JS_HAS_DESTRUCTURING */ JSFunction * -Parser::newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind) +Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind) { JS_ASSERT_IF(kind == Statement, atom != NULL); @@ -1046,7 +1040,7 @@ MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) } bool -Parser::analyzeFunctions(JSTreeContext *tc) +Parser::analyzeFunctions(TreeContext *tc) { cleanFunctionList(&tc->functionList); if (!tc->functionList) @@ -1090,12 +1084,12 @@ Parser::analyzeFunctions(JSTreeContext *tc) * FREE_STATIC_LEVEL. Thus this function never returns 0. */ static uintN -FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue) +FindFunArgs(FunctionBox *funbox, int level, FunctionBoxQueue *queue) { uintN allskipmin = UpvarCookie::FREE_LEVEL; do { - JSParseNode *fn = funbox->node; + ParseNode *fn = funbox->node; JS_ASSERT(fn->isArity(PN_FUNC)); int fnlevel = level; @@ -1115,7 +1109,7 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue) */ if (funbox->tcflags & (TCF_FUN_HEAVYWEIGHT | TCF_FUN_IS_GENERATOR)) { fn->setFunArg(); - for (JSFunctionBox *kid = funbox->kids; kid; kid = kid->siblings) + for (FunctionBox *kid = funbox->kids; kid; kid = kid->siblings) kid->node->setFunArg(); } @@ -1125,15 +1119,15 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue) * nested in fun. */ uintN skipmin = UpvarCookie::FREE_LEVEL; - JSParseNode *pn = fn->pn_body; + ParseNode *pn = fn->pn_body; if (pn->isKind(TOK_UPVARS)) { AtomDefnMapPtr &upvars = pn->pn_names; JS_ASSERT(upvars->count() != 0); for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { - JSDefinition *defn = r.front().value(); - JSDefinition *lexdep = defn->resolve(); + Definition *defn = r.front().value(); + Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) { uintN upvarLevel = lexdep->frameLevel(); @@ -1190,9 +1184,9 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue) } bool -Parser::markFunArgs(JSFunctionBox *funbox) +Parser::markFunArgs(FunctionBox *funbox) { - JSFunctionBoxQueue queue; + FunctionBoxQueue queue; if (!queue.init(functionCount)) { js_ReportOutOfMemory(context); return false; @@ -1200,21 +1194,21 @@ Parser::markFunArgs(JSFunctionBox *funbox) FindFunArgs(funbox, -1, &queue); while ((funbox = queue.pull()) != NULL) { - JSParseNode *fn = funbox->node; + ParseNode *fn = funbox->node; JS_ASSERT(fn->isFunArg()); - JSParseNode *pn = fn->pn_body; + ParseNode *pn = fn->pn_body; if (pn->isKind(TOK_UPVARS)) { AtomDefnMapPtr upvars = pn->pn_names; JS_ASSERT(!upvars->empty()); for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { - JSDefinition *defn = r.front().value(); - JSDefinition *lexdep = defn->resolve(); + Definition *defn = r.front().value(); + Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar() && !lexdep->isFunArg() && - (lexdep->kind() == JSDefinition::FUNCTION || + (lexdep->kind() == Definition::FUNCTION || lexdep->isOp(JSOP_CALLEE))) { /* * Mark this formerly-Algol-like function as an escaping @@ -1227,7 +1221,7 @@ Parser::markFunArgs(JSFunctionBox *funbox) */ lexdep->setFunArg(); - JSFunctionBox *afunbox; + FunctionBox *afunbox; if (lexdep->isOp(JSOP_CALLEE)) { /* * A named function expression will not appear to be a @@ -1265,12 +1259,12 @@ Parser::markFunArgs(JSFunctionBox *funbox) } static uint32 -MinBlockId(JSParseNode *fn, uint32 id) +MinBlockId(ParseNode *fn, uint32 id) { if (fn->pn_blockid < id) return false; if (fn->isDefn()) { - for (JSParseNode *pn = fn->dn_uses; pn; pn = pn->pn_link) { + for (ParseNode *pn = fn->dn_uses; pn; pn = pn->pn_link) { if (pn->pn_blockid < id) return false; } @@ -1279,7 +1273,7 @@ MinBlockId(JSParseNode *fn, uint32 id) } static inline bool -CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) +CanFlattenUpvar(Definition *dn, FunctionBox *funbox, uint32 tcflags) { /* * Consider the current function (the lambda, innermost below) using a var @@ -1299,7 +1293,7 @@ CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) * flat closure. Uncommenting the early call to g makes this optimization * unsafe (z could name a global setter that calls its argument). */ - JSFunctionBox *afunbox = funbox; + FunctionBox *afunbox = funbox; uintN dnLevel = dn->frameLevel(); JS_ASSERT(dnLevel <= funbox->level); @@ -1368,8 +1362,8 @@ CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) if (!dn->isInitialized()) return false; - JSDefinition::Kind dnKind = dn->kind(); - if (dnKind != JSDefinition::CONST) { + Definition::Kind dnKind = dn->kind(); + if (dnKind != Definition::CONST) { if (dn->isAssigned()) return false; @@ -1382,9 +1376,9 @@ CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) * definition or expression, afunbox->parent will be null. The body * source might use |arguments| outside of any nested functions it may * contain, so we have to check the tcflags parameter that was passed - * in from Compiler::compileFunctionBody. + * in from BytecodeCompiler::compileFunctionBody. */ - if (dnKind == JSDefinition::ARG && + if (dnKind == Definition::ARG && ((afunbox->parent ? afunbox->parent->tcflags : tcflags) & TCF_FUN_USES_ARGUMENTS)) { return false; } @@ -1395,7 +1389,7 @@ CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) * their uses thanks to hoisting. Other binding forms hoist as undefined, * of course, so check forward-reference and blockid relations. */ - if (dnKind != JSDefinition::FUNCTION) { + if (dnKind != Definition::FUNCTION) { /* * Watch out for code such as * @@ -1420,7 +1414,7 @@ CanFlattenUpvar(JSDefinition *dn, JSFunctionBox *funbox, uint32 tcflags) } static void -FlagHeavyweights(JSDefinition *dn, JSFunctionBox *funbox, uint32 *tcflags) +FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32 *tcflags) { uintN dnLevel = dn->frameLevel(); @@ -1443,11 +1437,11 @@ FlagHeavyweights(JSDefinition *dn, JSFunctionBox *funbox, uint32 *tcflags) } static bool -DeoptimizeUsesWithin(JSDefinition *dn, const TokenPos &pos) +DeoptimizeUsesWithin(Definition *dn, const TokenPos &pos) { uintN ndeoptimized = 0; - for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { + for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->isUsed()); JS_ASSERT(!pnu->isDefn()); if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) { @@ -1460,11 +1454,11 @@ DeoptimizeUsesWithin(JSDefinition *dn, const TokenPos &pos) } void -Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags) +Parser::setFunctionKinds(FunctionBox *funbox, uint32 *tcflags) { for (; funbox; funbox = funbox->siblings) { - JSParseNode *fn = funbox->node; - JSParseNode *pn = fn->pn_body; + ParseNode *fn = funbox->node; + ParseNode *pn = fn->pn_body; if (funbox->kids) setFunctionKinds(funbox->kids, tcflags); @@ -1491,8 +1485,8 @@ Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags) * value into a flat closure slot when the closure is formed. */ for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { - JSDefinition *defn = r.front().value(); - JSDefinition *lexdep = defn->resolve(); + Definition *defn = r.front().value(); + Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) { hasUpvars = true; @@ -1546,8 +1540,8 @@ Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags) JS_ASSERT(!upvars->empty()); for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { - JSDefinition *defn = r.front().value(); - JSDefinition *lexdep = defn->resolve(); + Definition *defn = r.front().value(); + Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) FlagHeavyweights(lexdep, funbox, tcflags); } @@ -1559,7 +1553,7 @@ Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags) } /* - * Walk the JSFunctionBox tree looking for functions whose call objects may + * Walk the FunctionBox tree looking for functions whose call objects may * acquire new bindings as they execute: non-strict functions that call eval, * and functions that contain function statements (definitions not appearing * within the top statement list, which don't take effect unless they are @@ -1570,13 +1564,13 @@ Parser::setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags) * js::Bindings::extensibleParents explain why. */ bool -Parser::markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensibleParent) +Parser::markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent) { for (; funbox; funbox = funbox->siblings) { /* * It would be nice to use fun->kind() here to recognize functions * that will never consult their parent chains, and thus don't need - * their 'extensible parents' flag set. Filed as bug 619750. + * their 'extensible parents' flag set. Filed as bug 619750. */ JS_ASSERT(!funbox->bindings.extensibleParents()); @@ -1596,17 +1590,17 @@ Parser::markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensible return true; } -static JSFunctionBox * -EnterFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL, +static FunctionBox * +EnterFunction(ParseNode *fn, TreeContext *funtc, JSAtom *funAtom = NULL, FunctionSyntaxKind kind = Expression) { - JSTreeContext *tc = funtc->parent; + TreeContext *tc = funtc->parent; JSFunction *fun = tc->parser->newFunction(tc, funAtom, kind); if (!fun) return NULL; /* Create box for fun->object early to protect against last-ditch GC. */ - JSFunctionBox *funbox = tc->parser->newFunctionBox(fun, fn, tc); + FunctionBox *funbox = tc->parser->newFunctionBox(fun, fn, tc); if (!funbox) return NULL; @@ -1624,13 +1618,13 @@ EnterFunction(JSParseNode *fn, JSTreeContext *funtc, JSAtom *funAtom = NULL, } static bool -LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NULL, +LeaveFunction(ParseNode *fn, TreeContext *funtc, PropertyName *funName = NULL, FunctionSyntaxKind kind = Expression) { - JSTreeContext *tc = funtc->parent; + TreeContext *tc = funtc->parent; tc->blockidGen = funtc->blockidGen; - JSFunctionBox *funbox = fn->pn_funbox; + FunctionBox *funbox = fn->pn_funbox; funbox->tcflags |= funtc->flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO | TCF_RETURN_EXPR); fn->pn_dflags |= PND_INITIALIZED; @@ -1649,7 +1643,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL for (AtomDefnRange r = funtc->lexdeps->all(); !r.empty(); r.popFront()) { JSAtom *atom = r.front().key(); - JSDefinition *dn = r.front().value(); + Definition *dn = r.front().value(); JS_ASSERT(dn->isPlaceholder()); if (atom == funName && kind == Expression) { @@ -1675,7 +1669,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL * backward-reference case; this is the hard forward-reference * case where we pay a higher price. */ - for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { + for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { if (pnu->isAssigned() && pnu->pn_blockid >= funtc->bodyid) { funbox->tcflags |= TCF_FUN_SETS_OUTER_NAME; break; @@ -1683,7 +1677,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL } } - JSDefinition *outer_dn = tc->decls.lookupFirst(atom); + Definition *outer_dn = tc->decls.lookupFirst(atom); /* * Make sure to deoptimize lexical dependencies that are polluted @@ -1741,8 +1735,8 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL * case), and nowhere else, currently. */ if (dn != outer_dn) { - JSParseNode **pnup = &dn->dn_uses; - JSParseNode *pnu; + ParseNode **pnup = &dn->dn_uses; + ParseNode *pnu; while ((pnu = *pnup) != NULL) { pnu->pn_lexdef = outer_dn; @@ -1753,7 +1747,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL * Make dn be a use that redirects to outer_dn, because we * can't replace dn with outer_dn in all the pn_namesets in * the AST where it may be. Instead we make it forward to - * outer_dn. See JSDefinition::resolve. + * outer_dn. See Definition::resolve. */ *pnup = outer_dn->dn_uses; outer_dn->dn_uses = dn; @@ -1768,7 +1762,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL } if (funtc->lexdeps->count() - foundCallee != 0) { - JSParseNode *body = fn->pn_body; + ParseNode *body = fn->pn_body; fn->pn_body = NameSetNode::create(tc); if (!fn->pn_body) @@ -1797,10 +1791,10 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL */ if (funtc->inStrictMode() && funbox->object->toFunction()->nargs > 0) { AtomDeclsIter iter(&funtc->decls); - JSDefinition *dn; + Definition *dn; while ((dn = iter()) != NULL) { - if (dn->kind() == JSDefinition::ARG && dn->isAssigned()) { + if (dn->kind() == Definition::ARG && dn->isAssigned()) { funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER; break; } @@ -1813,7 +1807,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, PropertyName *funName = NUL } static bool -DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name); +DefineGlobal(ParseNode *pn, CodeGenerator *cg, PropertyName *name); /* * FIXME? this Parser method was factored from Parser::functionDef with minimal @@ -1822,7 +1816,7 @@ DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name); * parameters. */ bool -Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNode **listp) +Parser::functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **listp) { if (tokenStream.getToken() != TOK_LP) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL); @@ -1833,7 +1827,7 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo #if JS_HAS_DESTRUCTURING JSAtom *duplicatedArg = NULL; bool destructuringArg = false; - JSParseNode *list = NULL; + ParseNode *list = NULL; #endif do { @@ -1857,7 +1851,7 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo data.pn = NULL; data.op = JSOP_DEFVAR; data.binder = BindDestructuringArg; - JSParseNode *lhs = destructuringExpr(&data, tt); + ParseNode *lhs = destructuringExpr(&data, tt); if (!lhs) return false; @@ -1874,7 +1868,7 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo * anonymous positional parameter into the destructuring * left-hand-side expression and accumulate it in list. */ - JSParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc); + ParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc); if (!rhs) return false; rhs->setKind(TOK_NAME); @@ -1882,8 +1876,8 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo rhs->pn_cookie.set(funtc.staticLevel, slot); rhs->pn_dflags |= PND_BOUND; - JSParseNode *item = - JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc); + ParseNode *item = + ParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc); if (!item) return false; if (!list) { @@ -1943,7 +1937,7 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo #if JS_HAS_DESTRUCTURING report_dup_and_destructuring: - JSDefinition *dn = funtc.decls.lookupFirst(duplicatedArg); + Definition *dn = funtc.decls.lookupFirst(duplicatedArg); reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG); return false; #endif @@ -1959,14 +1953,14 @@ Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNo return true; } -JSParseNode * +ParseNode * Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind kind) { JS_ASSERT_IF(kind == Statement, funName); /* Make a TOK_FUNCTION node. */ tokenStream.mungeCurrentToken(TOK_FUNCTION, JSOP_NOP); - JSParseNode *pn = FunctionNode::create(tc); + ParseNode *pn = FunctionNode::create(tc); if (!pn) return NULL; pn->pn_body = NULL; @@ -1989,28 +1983,28 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind * avoid optimizing variable references that might name a function. */ if (kind == Statement) { - if (JSDefinition *dn = tc->decls.lookupFirst(funName)) { - JSDefinition::Kind dn_kind = dn->kind(); + if (Definition *dn = tc->decls.lookupFirst(funName)) { + Definition::Kind dn_kind = dn->kind(); JS_ASSERT(!dn->isUsed()); JS_ASSERT(dn->isDefn()); - if (context->hasStrictOption() || dn_kind == JSDefinition::CONST) { + if (context->hasStrictOption() || dn_kind == Definition::CONST) { JSAutoByteString name; if (!js_AtomToPrintableString(context, funName, &name) || !reportErrorNumber(NULL, - (dn_kind != JSDefinition::CONST) + (dn_kind != Definition::CONST) ? JSREPORT_WARNING | JSREPORT_STRICT : JSREPORT_ERROR, JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), + Definition::kindString(dn_kind), name.ptr())) { return NULL; } } if (bodyLevel) { - tc->decls.updateFirst(funName, (JSDefinition *) pn); + tc->decls.updateFirst(funName, (Definition *) pn); pn->setDefn(true); pn->dn_uses = dn; /* dn->dn_uses is now pn_link */ @@ -2024,7 +2018,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind * put in tc->lexdeps on first forward reference, and recycle pn. */ - if (JSDefinition *fn = tc->lexdeps.lookupDefn(funName)) { + if (Definition *fn = tc->lexdeps.lookupDefn(funName)) { JS_ASSERT(fn->isDefn()); fn->setKind(TOK_FUNCTION); fn->setArity(PN_FUNC); @@ -2040,7 +2034,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind fn->pn_cookie.makeFree(); tc->lexdeps->remove(funName); - RecycleTree(pn, tc); + freeTree(pn); pn = fn; } @@ -2053,8 +2047,8 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind * variable to bind its name to its value, and not an activation object * property (it might also need the activation property, if the outer * function contains with statements, e.g., but the stack slot wins - * when jsemit.cpp's BindNameToSlot can optimize a JSOP_NAME into a - * JSOP_GETLOCAL bytecode). + * when BytecodeGenerator.cpp's BindNameToSlot can optimize a JSOP_NAME + * into a JSOP_GETLOCAL bytecode). */ if (bodyLevel && tc->inFunction()) { /* @@ -2083,21 +2077,21 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind } } - JSTreeContext *outertc = tc; + TreeContext *outertc = tc; /* Initialize early for possible flags mutation via destructuringExpr. */ - JSTreeContext funtc(tc->parser); + TreeContext funtc(tc->parser); if (!funtc.init(context)) return NULL; - JSFunctionBox *funbox = EnterFunction(pn, &funtc, funName, kind); + FunctionBox *funbox = EnterFunction(pn, &funtc, funName, kind); if (!funbox) return NULL; JSFunction *fun = funbox->function(); /* Now parse formal argument list and compute fun->nargs. */ - JSParseNode *prelude = NULL; + ParseNode *prelude = NULL; if (!functionArguments(funtc, funbox, &prelude)) return NULL; @@ -2115,7 +2109,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind if (prelude) { AtomDeclsIter iter(&funtc.decls); - while (JSDefinition *apn = iter()) { + while (Definition *apn = iter()) { /* Filter based on pn_op -- see BindDestructuringArg, above. */ if (!apn->isOp(JSOP_SETLOCAL)) continue; @@ -2147,7 +2141,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY); #endif - JSParseNode *body = functionBody(); + ParseNode *body = functionBody(); if (!body) return NULL; @@ -2172,11 +2166,11 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind * parent to call eval. We need this for two reasons: (1) the Jaegermonkey * optimizations really need to know if eval is called transitively, and * (2) in strict mode, eval called transitively requires eager argument - * creation in strict mode parent functions. + * creation in strict mode parent functions. * - * For the latter, we really only need to propagate callsEval if both - * functions are strict mode, but we don't lose much by always propagating. - * The only optimization we lose this way is in the case where a function + * For the latter, we really only need to propagate callsEval if both + * functions are strict mode, but we don't lose much by always propagating. + * The only optimization we lose this way is in the case where a function * is strict, does not mutate arguments, does not call eval directly, but * calls eval transitively. */ @@ -2192,7 +2186,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind */ if (prelude) { if (!body->isArity(PN_LIST)) { - JSParseNode *block; + ParseNode *block; block = ListNode::create(outertc); if (!block) @@ -2204,7 +2198,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind body = block; } - JSParseNode *item = UnaryNode::create(outertc); + ParseNode *item = UnaryNode::create(outertc); if (!item) return NULL; @@ -2286,7 +2280,7 @@ Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind return pn; } -JSParseNode * +ParseNode * Parser::functionStmt() { PropertyName *name = NULL; @@ -2307,7 +2301,7 @@ Parser::functionStmt() return functionDef(name, Normal, Statement); } -JSParseNode * +ParseNode * Parser::functionExpr() { PropertyName *name = NULL; @@ -2338,13 +2332,13 @@ Parser::functionExpr() * to the "use strict" statement, which is indeed a directive. */ bool -Parser::recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember) +Parser::recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMember) { *isDirectivePrologueMember = pn->isStringExprStatement(); if (!*isDirectivePrologueMember) return true; - JSParseNode *kid = pn->pn_kid; + ParseNode *kid = pn->pn_kid; if (kid->isEscapeFreeStringLiteral()) { /* * Mark this statement as being a possibly legitimate part of a @@ -2393,10 +2387,10 @@ Parser::recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMem * statements' trees. If called from block-parsing code, the caller must * match { before and } after. */ -JSParseNode * +ParseNode * Parser::statements() { - JSParseNode *pn, *pn2, *saveBlock; + ParseNode *pn, *pn2, *saveBlock; TokenKind tt; JS_CHECK_RECURSION(context, return NULL); @@ -2466,10 +2460,10 @@ Parser::statements() return pn; } -JSParseNode * +ParseNode * Parser::condition() { - JSParseNode *pn; + ParseNode *pn; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND); pn = parenExpr(); @@ -2488,7 +2482,7 @@ Parser::condition() } static bool -MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) +MatchLabel(JSContext *cx, TokenStream *ts, ParseNode *pn) { TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND); if (tt == TOK_ERROR) @@ -2514,9 +2508,9 @@ MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) * data->pn in a slot of the block object. */ static JSBool -BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) +BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc) { - JSParseNode *pn; + ParseNode *pn; JSObject *blockObj; jsint n; @@ -2531,7 +2525,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) return false; blockObj = tc->blockChain(); - JSDefinition *dn = tc->decls.lookupFirst(atom); + Definition *dn = tc->decls.lookupFirst(atom); if (dn && dn->pn_blockid == tc->blockid()) { JSAutoByteString name; if (js_AtomToPrintableString(cx, atom, &name)) { @@ -2561,8 +2555,8 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) * Assign block-local index to pn->pn_cookie right away, encoding it as an * upvar cookie whose skip tells the current static level. The emitter will * adjust the node's slot based on its stack depth model -- and, for global - * and eval code, Compiler::compileScript will adjust the slot again to - * include script->nfixed. + * and eval code, BytecodeCompiler::compileScript will adjust the slot + * again to include script->nfixed. */ pn->setOp(JSOP_GETLOCAL); pn->pn_cookie.set(tc->staticLevel, uint16(n)); @@ -2580,17 +2574,17 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) * Store pn temporarily in what would be shape-mapped slots in a cloned * block object (once the prototype's final population is known, after all * 'let' bindings for this block have been parsed). We free these slots in - * jsemit.cpp:EmitEnterBlock so they don't tie up unused space in the so- - * called "static" prototype Block. + * BytecodeGenerator.cpp:EmitEnterBlock so they don't tie up unused space + * in the so-called "static" prototype Block. */ blockObj->setSlot(shape->slot(), PrivateValue(pn)); return true; } static void -PopStatement(JSTreeContext *tc) +PopStatement(TreeContext *tc) { - JSStmtInfo *stmt = tc->topStmt; + StmtInfo *stmt = tc->topStmt; if (stmt->flags & SIF_SCOPE) { JSObject *obj = stmt->blockBox->object; @@ -2605,14 +2599,14 @@ PopStatement(JSTreeContext *tc) tc->decls.remove(atom); } } - js_PopStatement(tc); + PopStatementTC(tc); } static inline bool -OuterLet(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *atom) +OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom) { while (stmt->downScope) { - stmt = js_LexicalLookup(tc, atom, NULL, stmt->downScope); + stmt = LexicalLookup(tc, atom, NULL, stmt->downScope); if (!stmt) return false; if (stmt->type == STMT_BLOCK) @@ -2637,7 +2631,7 @@ OuterLet(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *atom) * stack frame slots. */ static bool -DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name) +DefineGlobal(ParseNode *pn, CodeGenerator *cg, PropertyName *name) { GlobalScope *globalScope = cg->compiler()->globalScope; JSObject *globalObj = globalScope->globalObj; @@ -2654,7 +2648,7 @@ DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name) if (!globalObj->lookupProperty(cx, name, &holder, &prop)) return false; - JSFunctionBox *funbox = pn->isKind(TOK_FUNCTION) ? pn->pn_funbox : NULL; + FunctionBox *funbox = pn->isKind(TOK_FUNCTION) ? pn->pn_funbox : NULL; GlobalScope::GlobalDef def; if (prop) { @@ -2673,7 +2667,7 @@ DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name) !shape->hasDefaultSetter()) { return true; } - + def = GlobalScope::GlobalDef(shape->slot()); } else { def = GlobalScope::GlobalDef(name, funbox); @@ -2714,7 +2708,7 @@ DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, PropertyName *name) } static bool -BindTopLevelVar(JSContext *cx, BindData *data, JSParseNode *pn, JSTreeContext *tc) +BindTopLevelVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc) { JS_ASSERT(pn->isOp(JSOP_NAME)); JS_ASSERT(!tc->inFunction()); @@ -2767,11 +2761,11 @@ BindTopLevelVar(JSContext *cx, BindData *data, JSParseNode *pn, JSTreeContext *t } static bool -BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, JSTreeContext *tc) +BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContext *tc) { JS_ASSERT(tc->inFunction()); - JSParseNode *pn = data->pn; + ParseNode *pn = data->pn; JSAtom *name = pn->pn_atom; /* @@ -2805,7 +2799,7 @@ BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, JSTreeCont if (kind == ARGUMENT) { JS_ASSERT(tc->inFunction()); - JS_ASSERT(!mdl.empty() && mdl.front()->kind() == JSDefinition::ARG); + JS_ASSERT(!mdl.empty() && mdl.front()->kind() == Definition::ARG); } else { JS_ASSERT(kind == VARIABLE || kind == CONSTANT); } @@ -2814,9 +2808,9 @@ BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, JSTreeCont } static JSBool -BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) +BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc) { - JSParseNode *pn = data->pn; + ParseNode *pn = data->pn; /* Default best op for pn is JSOP_NAME; we'll try to improve below. */ pn->setOp(JSOP_NAME); @@ -2824,7 +2818,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn)) return false; - JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL); + StmtInfo *stmt = LexicalLookup(tc, atom, NULL); if (stmt && stmt->type == STMT_WITH) { data->fresh = false; @@ -2837,10 +2831,10 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) JSOp op = data->op; if (stmt || !mdl.empty()) { - JSDefinition *dn = mdl.empty() ? NULL : mdl.front(); - JSDefinition::Kind dn_kind = dn ? dn->kind() : JSDefinition::VAR; + Definition *dn = mdl.empty() ? NULL : mdl.front(); + Definition::Kind dn_kind = dn ? dn->kind() : Definition::VAR; - if (dn_kind == JSDefinition::ARG) { + if (dn_kind == Definition::ARG) { JSAutoByteString name; if (!js_AtomToPrintableString(cx, atom, &name)) return JS_FALSE; @@ -2858,12 +2852,12 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) } } else { bool error = (op == JSOP_DEFCONST || - dn_kind == JSDefinition::CONST || - (dn_kind == JSDefinition::LET && + dn_kind == Definition::CONST || + (dn_kind == Definition::LET && (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom)))); if (cx->hasStrictOption() - ? op != JSOP_DEFVAR || dn_kind != JSDefinition::VAR + ? op != JSOP_DEFVAR || dn_kind != Definition::VAR : error) { JSAutoByteString name; if (!js_AtomToPrintableString(cx, atom, &name) || @@ -2872,7 +2866,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) ? JSREPORT_WARNING | JSREPORT_STRICT : JSREPORT_ERROR, JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), + Definition::kindString(dn_kind), name.ptr())) { return JS_FALSE; } @@ -2895,13 +2889,13 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) * There the x definition is hoisted but the x = 2 assignment mutates * the block-local binding of x. */ - JSDefinition *dn = mdl.front(); + Definition *dn = mdl.front(); data->fresh = false; if (!pn->isUsed()) { /* Make pnu be a fresh name node that uses dn. */ - JSParseNode *pnu = pn; + ParseNode *pnu = pn; if (pn->isDefn()) { pnu = NameNode::create(atom, tc); @@ -2914,7 +2908,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) } /* Find the first non-let binding of this atom. */ - while (dn->kind() == JSDefinition::LET) { + while (dn->kind() == Definition::LET) { mdl.popFront(); if (mdl.empty()) break; @@ -2923,7 +2917,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (dn) { JS_ASSERT_IF(data->op == JSOP_DEFCONST, - dn->kind() == JSDefinition::CONST); + dn->kind() == Definition::CONST); return JS_TRUE; } @@ -2936,7 +2930,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (tc->lexdeps->lookup(atom)) { tc->lexdeps->remove(atom); } else { - JSParseNode *pn2 = NameNode::create(atom, tc); + ParseNode *pn2 = NameNode::create(atom, tc); if (!pn2) return JS_FALSE; @@ -2948,7 +2942,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) pn->setOp(JSOP_NAME); } - if (!tc->decls.addHoist(atom, (JSDefinition *) pn)) + if (!tc->decls.addHoist(atom, (Definition *) pn)) return JS_FALSE; pn->setDefn(true); pn->pn_dflags &= ~PND_PLACEHOLDER; @@ -2964,7 +2958,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) } static bool -MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) +MakeSetCall(JSContext *cx, ParseNode *pn, TreeContext *tc, uintN msg) { JS_ASSERT(pn->isArity(PN_LIST)); JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_EVAL) || @@ -2972,7 +2966,7 @@ MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) if (!ReportStrictModeError(cx, TS(tc->parser), tc, pn, msg)) return false; - JSParseNode *pn2 = pn->pn_head; + ParseNode *pn2 = pn->pn_head; if (pn2->isKind(TOK_FUNCTION) && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) { ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg); return false; @@ -2982,10 +2976,10 @@ MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) } static void -NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_ASSIGNED) +NoteLValue(JSContext *cx, ParseNode *pn, TreeContext *tc, uintN dflag = PND_ASSIGNED) { if (pn->isUsed()) { - JSDefinition *dn = pn->pn_lexdef; + Definition *dn = pn->pn_lexdef; /* * Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y' @@ -3029,8 +3023,7 @@ NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_ #if JS_HAS_DESTRUCTURING static JSBool -BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn, - JSTreeContext *tc) +BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc) { JSAtom *atom; @@ -3085,7 +3078,7 @@ BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn, * which can be optimized further. So we select JSOP_SETNAME. */ static JSBool -BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) +BindDestructuringLHS(JSContext *cx, ParseNode *pn, TreeContext *tc) { switch (pn->getKind()) { case TOK_NAME: @@ -3167,7 +3160,7 @@ BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) * match. */ static bool -CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeContext *tc) +CheckDestructuring(JSContext *cx, BindData *data, ParseNode *left, TreeContext *tc) { bool ok; @@ -3178,7 +3171,7 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeConte } if (left->isKind(TOK_RB)) { - for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { + for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { /* Nullary comma is an elision; binary comma is an expression.*/ if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) { if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) { @@ -3201,9 +3194,9 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeConte } } else { JS_ASSERT(left->isKind(TOK_RC)); - for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) { + for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) { JS_ASSERT(pair->isKind(TOK_COLON)); - JSParseNode *pn = pair->pn_right; + ParseNode *pn = pair->pn_right; if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) { ok = CheckDestructuring(cx, data, pn, tc); @@ -3272,10 +3265,10 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeConte * functions, you might have to change the other to match. */ static void -UndominateInitializers(JSParseNode *left, const TokenPtr &end, JSTreeContext *tc) +UndominateInitializers(ParseNode *left, const TokenPtr &end, TreeContext *tc) { if (left->isKind(TOK_RB)) { - for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { + for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { /* Nullary comma is an elision; binary comma is an expression.*/ if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) { if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) @@ -3287,9 +3280,9 @@ UndominateInitializers(JSParseNode *left, const TokenPtr &end, JSTreeContext *tc } else { JS_ASSERT(left->isKind(TOK_RC)); - for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) { + for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) { JS_ASSERT(pair->isKind(TOK_COLON)); - JSParseNode *pn = pair->pn_right; + ParseNode *pn = pair->pn_right; if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) UndominateInitializers(pn, end, tc); else @@ -3298,13 +3291,11 @@ UndominateInitializers(JSParseNode *left, const TokenPtr &end, JSTreeContext *tc } } -JSParseNode * +ParseNode * Parser::destructuringExpr(BindData *data, TokenKind tt) { - JSParseNode *pn; - tc->flags |= TCF_DECL_DESTRUCTURING; - pn = primaryExpr(tt, JS_FALSE); + ParseNode *pn = primaryExpr(tt, JS_FALSE); tc->flags &= ~TCF_DECL_DESTRUCTURING; if (!pn) return NULL; @@ -3315,11 +3306,11 @@ Parser::destructuringExpr(BindData *data, TokenKind tt) #endif /* JS_HAS_DESTRUCTURING */ -JSParseNode * +ParseNode * Parser::returnOrYield(bool useAssignExpr) { TokenKind tt, tt2; - JSParseNode *pn, *pn2; + ParseNode *pn, *pn2; tt = tokenStream.currentToken().type; if (!tc->inFunction()) { @@ -3394,27 +3385,22 @@ Parser::returnOrYield(bool useAssignExpr) return pn; } -static JSParseNode * -PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc, - JSStmtInfo *stmt) +static ParseNode * +PushLexicalScope(JSContext *cx, TokenStream *ts, TreeContext *tc, StmtInfo *stmt) { - JSParseNode *pn; - JSObject *obj; - JSObjectBox *blockbox; - - pn = LexicalScopeNode::create(tc); + ParseNode *pn = LexicalScopeNode::create(tc); if (!pn) return NULL; - obj = js_NewBlockObject(cx); + JSObject *obj = js_NewBlockObject(cx); if (!obj) return NULL; - blockbox = tc->parser->newObjectBox(obj); + ObjectBox *blockbox = tc->parser->newObjectBox(obj); if (!blockbox) return NULL; - js_PushBlockScope(tc, stmt, blockbox, -1); + PushBlockScope(tc, stmt, blockbox, -1); pn->setKind(TOK_LEXICALSCOPE); pn->setOp(JSOP_LEAVEBLOCK); pn->pn_objbox = blockbox; @@ -3428,11 +3414,11 @@ PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc, #if JS_HAS_BLOCK_SCOPE -JSParseNode * +ParseNode * Parser::letBlock(JSBool statement) { - JSParseNode *pn, *pnblock, *pnlet; - JSStmtInfo stmtInfo; + ParseNode *pn, *pnblock, *pnlet; + StmtInfo stmtInfo; JS_ASSERT(tokenStream.currentToken().type == TOK_LET); @@ -3509,16 +3495,16 @@ Parser::letBlock(JSBool statement) #endif /* JS_HAS_BLOCK_SCOPE */ static bool -PushBlocklikeStatement(JSStmtInfo *stmt, JSStmtType type, JSTreeContext *tc) +PushBlocklikeStatement(StmtInfo *stmt, StmtType type, TreeContext *tc) { - js_PushStatement(tc, stmt, type, -1); + PushStatement(tc, stmt, type, -1); return GenerateBlockId(tc, stmt->blockid); } -static JSParseNode * -NewBindingNode(JSAtom *atom, JSTreeContext *tc, bool let = false) +static ParseNode * +NewBindingNode(JSAtom *atom, TreeContext *tc, bool let = false) { - JSParseNode *pn; + ParseNode *pn; AtomDefnPtr removal; if ((pn = tc->decls.lookupFirst(atom))) { @@ -3561,19 +3547,19 @@ NewBindingNode(JSAtom *atom, JSTreeContext *tc, bool let = false) return pn; } -JSParseNode * +ParseNode * Parser::switchStatement() { - JSParseNode *pn5, *saveBlock; + ParseNode *pn5, *saveBlock; JSBool seenDefault = JS_FALSE; - JSParseNode *pn = BinaryNode::create(tc); + ParseNode *pn = BinaryNode::create(tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); /* pn1 points to the switch's discriminant. */ - JSParseNode *pn1 = parenExpr(); + ParseNode *pn1 = parenExpr(); if (!pn1) return NULL; @@ -3584,11 +3570,11 @@ Parser::switchStatement() * NB: we must push stmtInfo before calling GenerateBlockIdForStmtNode * because that function states tc->topStmt->blockid. */ - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_SWITCH, -1); /* pn2 is a list of case nodes. The default case has pn_left == NULL */ - JSParseNode *pn2 = ListNode::create(tc); + ParseNode *pn2 = ListNode::create(tc); if (!pn2) return NULL; pn2->makeEmpty(); @@ -3599,7 +3585,7 @@ Parser::switchStatement() TokenKind tt; while ((tt = tokenStream.getToken()) != TOK_RC) { - JSParseNode *pn3; + ParseNode *pn3; switch (tt) { case TOK_DEFAULT: if (seenDefault) { @@ -3636,7 +3622,7 @@ Parser::switchStatement() } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); - JSParseNode *pn4 = ListNode::create(tc); + ParseNode *pn4 = ListNode::create(tc); if (!pn4) return NULL; pn4->setKind(TOK_LC); @@ -3676,21 +3662,21 @@ Parser::switchStatement() return pn; } -JSParseNode * +ParseNode * Parser::forStatement() { - JSParseNode *pnseq = NULL; + ParseNode *pnseq = NULL; #if JS_HAS_BLOCK_SCOPE - JSParseNode *pnlet = NULL; - JSStmtInfo blockInfo; + ParseNode *pnlet = NULL; + StmtInfo blockInfo; #endif /* A FOR node is binary, left is loop control and right is the body. */ - JSParseNode *pn = BinaryNode::create(tc); + ParseNode *pn = BinaryNode::create(tc); if (!pn) return NULL; - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); pn->setOp(JSOP_ITER); pn->pn_iflags = 0; @@ -3708,7 +3694,7 @@ Parser::forStatement() bool let = false; #endif - JSParseNode *pn1; + ParseNode *pn1; if (tt == TOK_SEMI) { if (pn->pn_iflags & JSITER_FOREACH) { reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP); @@ -3762,10 +3748,10 @@ Parser::forStatement() * We can be sure that it's a for/in loop if there's still an 'in' * keyword here, even if JavaScript recognizes 'in' as an operator, * as we've excluded 'in' from being parsed in RelExpr by setting - * the TCF_IN_FOR_INIT flag in our JSTreeContext. + * the TCF_IN_FOR_INIT flag in our TreeContext. */ - JSParseNode *pn2, *pn3; - JSParseNode *pn4 = TernaryNode::create(tc); + ParseNode *pn2, *pn3; + ParseNode *pn4 = TernaryNode::create(tc); if (!pn4) return NULL; if (pn1 && tokenStream.matchToken(TOK_IN)) { @@ -3926,7 +3912,7 @@ Parser::forStatement() * 'for (let x in y)' loop. */ #if JS_HAS_BLOCK_SCOPE - JSStmtInfo *save = tc->topStmt; + StmtInfo *save = tc->topStmt; if (let) tc->topStmt = save->down; #endif @@ -4003,10 +3989,10 @@ Parser::forStatement() return pn; } -JSParseNode * +ParseNode * Parser::tryStatement() { - JSParseNode *catchList, *lastCatch; + ParseNode *catchList, *lastCatch; /* * try nodes are ternary. @@ -4025,13 +4011,13 @@ Parser::tryStatement() * * finally nodes are TOK_LC statement lists. */ - JSParseNode *pn = TernaryNode::create(tc); + ParseNode *pn = TernaryNode::create(tc); if (!pn) return NULL; pn->setOp(JSOP_NOP); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); - JSStmtInfo stmtInfo; + StmtInfo stmtInfo; if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc)) return NULL; pn->pn_kid1 = statements(); @@ -4051,7 +4037,7 @@ Parser::tryStatement() lastCatch = NULL; do { - JSParseNode *pnblock; + ParseNode *pnblock; BindData data; /* Check for another catch after unconditional catch. */ @@ -4076,7 +4062,7 @@ Parser::tryStatement() * where lhs is a name or a destructuring left-hand side. * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) */ - JSParseNode *pn2 = TernaryNode::create(tc); + ParseNode *pn2 = TernaryNode::create(tc); if (!pn2) return NULL; pnblock->pn_expr = pn2; @@ -4093,7 +4079,7 @@ Parser::tryStatement() data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; tt = tokenStream.getToken(); - JSParseNode *pn3; + ParseNode *pn3; switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -4169,7 +4155,7 @@ Parser::tryStatement() return pn; } -JSParseNode * +ParseNode * Parser::withStatement() { /* @@ -4185,21 +4171,21 @@ Parser::withStatement() return NULL; } - JSParseNode *pn = BinaryNode::create(tc); + ParseNode *pn = BinaryNode::create(tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); - JSParseNode *pn2 = parenExpr(); + ParseNode *pn2 = parenExpr(); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH); pn->pn_left = pn2; - JSParseNode *oldWith = tc->innermostWith; + ParseNode *oldWith = tc->innermostWith; tc->innermostWith = pn; - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_WITH, -1); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_WITH, -1); pn2 = statement(); if (!pn2) return NULL; @@ -4215,8 +4201,8 @@ Parser::withStatement() * to safely optimize binding globals (see bug 561923). */ for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) { - JSDefinition *defn = r.front().value(); - JSDefinition *lexdep = defn->resolve(); + Definition *defn = r.front().value(); + Definition *lexdep = defn->resolve(); DeoptimizeUsesWithin(lexdep, pn->pn_pos); } @@ -4224,12 +4210,10 @@ Parser::withStatement() } #if JS_HAS_BLOCK_SCOPE -JSParseNode * +ParseNode * Parser::letStatement() { - JSObjectBox *blockbox; - - JSParseNode *pn; + ParseNode *pn; do { /* Check for a let statement or let expression. */ if (tokenStream.peekToken() == TOK_LP) { @@ -4243,17 +4227,17 @@ Parser::letStatement() } /* - * This is a let declaration. We must be directly under a block per - * the proposed ES4 specs, but not an implicit block created due to + * This is a let declaration. We must be directly under a block per the + * proposed ES4 specs, but not an implicit block created due to * 'for (let ...)'. If we pass this error test, make the enclosing - * JSStmtInfo be our scope. Further let declarations in this block - * will find this scope statement and use the same block object. + * StmtInfo be our scope. Further let declarations in this block will + * find this scope statement and use the same block object. * * If we are the first let declaration in this block (i.e., when the - * enclosing maybe-scope JSStmtInfo isn't yet a scope statement) then + * enclosing maybe-scope StmtInfo isn't yet a scope statement) then * we also need to set tc->blockNode to be our TOK_LEXICALSCOPE. */ - JSStmtInfo *stmt = tc->topStmt; + StmtInfo *stmt = tc->topStmt; if (stmt && (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LET_DECL_NOT_IN_BLOCK); @@ -4295,7 +4279,7 @@ Parser::letStatement() if (!obj) return NULL; - blockbox = tc->parser->newObjectBox(obj); + ObjectBox *blockbox = tc->parser->newObjectBox(obj); if (!blockbox) return NULL; @@ -4316,12 +4300,12 @@ Parser::letStatement() stmt->blockBox = blockbox; #ifdef DEBUG - JSParseNode *tmp = tc->blockNode; + ParseNode *tmp = tc->blockNode; JS_ASSERT(!tmp || !tmp->isKind(TOK_LEXICALSCOPE)); #endif /* Create a new lexical scope node for these statements. */ - JSParseNode *pn1 = LexicalScopeNode::create(tc); + ParseNode *pn1 = LexicalScopeNode::create(tc); if (!pn1) return NULL; @@ -4345,11 +4329,11 @@ Parser::letStatement() } #endif -JSParseNode * +ParseNode * Parser::expressionStatement() { tokenStream.ungetToken(); - JSParseNode *pn2 = expr(); + ParseNode *pn2 = expr(); if (!pn2) return NULL; @@ -4359,7 +4343,7 @@ Parser::expressionStatement() return NULL; } JSAtom *label = pn2->pn_atom; - for (JSStmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) { + for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL); return NULL; @@ -4370,10 +4354,10 @@ Parser::expressionStatement() (void) tokenStream.getToken(); /* Push a label struct and parse the statement. */ - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_LABEL, -1); stmtInfo.label = label; - JSParseNode *pn = statement(); + ParseNode *pn = statement(); if (!pn) return NULL; @@ -4392,7 +4376,7 @@ Parser::expressionStatement() return pn2; } - JSParseNode *pn = UnaryNode::create(tc); + ParseNode *pn = UnaryNode::create(tc); if (!pn) return NULL; pn->setKind(TOK_SEMI); @@ -4434,10 +4418,10 @@ Parser::expressionStatement() return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; } -JSParseNode * +ParseNode * Parser::statement() { - JSParseNode *pn; + ParseNode *pn; JS_CHECK_RECURSION(context, return NULL); @@ -4445,9 +4429,11 @@ Parser::statement() case TOK_FUNCTION: { #if JS_HAS_XML_SUPPORT - TokenKind tt = tokenStream.peekToken(TSF_KEYWORD_IS_NAME); - if (tt == TOK_DBLCOLON) - goto expression; + if (!tc->inStrictMode()) { + TokenKind tt = tokenStream.peekToken(TSF_KEYWORD_IS_NAME); + if (tt == TOK_DBLCOLON) + return expressionStatement(); + } #endif return functionStmt(); } @@ -4458,15 +4444,15 @@ Parser::statement() pn = TernaryNode::create(tc); if (!pn) return NULL; - JSParseNode *pn1 = condition(); + ParseNode *pn1 = condition(); if (!pn1) return NULL; - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_IF, -1); - JSParseNode *pn2 = statement(); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_IF, -1); + ParseNode *pn2 = statement(); if (!pn2) return NULL; - JSParseNode *pn3; + ParseNode *pn3; if (tokenStream.matchToken(TOK_ELSE, TSF_OPERAND)) { stmtInfo.type = STMT_ELSE; pn3 = statement(); @@ -4492,13 +4478,13 @@ Parser::statement() pn = BinaryNode::create(tc); if (!pn) return NULL; - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); - JSParseNode *pn2 = condition(); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); + ParseNode *pn2 = condition(); if (!pn2) return NULL; pn->pn_left = pn2; - JSParseNode *pn3 = statement(); + ParseNode *pn3 = statement(); if (!pn3) return NULL; PopStatement(tc); @@ -4512,14 +4498,14 @@ Parser::statement() pn = BinaryNode::create(tc); if (!pn) return NULL; - JSStmtInfo stmtInfo; - js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); - JSParseNode *pn2 = statement(); + StmtInfo stmtInfo; + PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); + ParseNode *pn2 = statement(); if (!pn2) return NULL; pn->pn_left = pn2; MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO); - JSParseNode *pn3 = condition(); + ParseNode *pn3 = condition(); if (!pn3) return NULL; PopStatement(tc); @@ -4558,7 +4544,7 @@ Parser::statement() return NULL; } - JSParseNode *pn2 = expr(); + ParseNode *pn2 = expr(); if (!pn2) return NULL; pn->pn_pos.end = pn2->pn_pos.end; @@ -4583,7 +4569,7 @@ Parser::statement() return NULL; if (!MatchLabel(context, &tokenStream, pn)) return NULL; - JSStmtInfo *stmt = tc->topStmt; + StmtInfo *stmt = tc->topStmt; JSAtom *label = pn->pn_atom; if (label) { for (; ; stmt = stmt->down) { @@ -4616,10 +4602,10 @@ Parser::statement() return NULL; if (!MatchLabel(context, &tokenStream, pn)) return NULL; - JSStmtInfo *stmt = tc->topStmt; + StmtInfo *stmt = tc->topStmt; JSAtom *label = pn->pn_atom; if (label) { - for (JSStmtInfo *stmt2 = NULL; ; stmt = stmt->down) { + for (StmtInfo *stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; @@ -4680,7 +4666,7 @@ Parser::statement() oldflags = tc->flags; tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT; - JSStmtInfo stmtInfo; + StmtInfo stmtInfo; if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, tc)) return NULL; pn = statements(); @@ -4720,6 +4706,9 @@ Parser::statement() #if JS_HAS_XML_SUPPORT case TOK_DEFAULT: { + if (tc->inStrictMode()) + return expressionStatement(); + pn = UnaryNode::create(tc); if (!pn) return NULL; @@ -4735,7 +4724,7 @@ Parser::statement() /* Is this an E4X dagger I see before me? */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - JSParseNode *pn2 = expr(); + ParseNode *pn2 = expr(); if (!pn2) return NULL; pn->setOp(JSOP_DEFXMLNS); @@ -4749,9 +4738,6 @@ Parser::statement() return NULL; default: -#if JS_HAS_XML_SUPPORT - expression: -#endif return expressionStatement(); } @@ -4759,14 +4745,14 @@ Parser::statement() return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; } -JSParseNode * +ParseNode * Parser::variables(bool inLetHead) { TokenKind tt; bool let; - JSStmtInfo *scopeStmt; + StmtInfo *scopeStmt; BindData data; - JSParseNode *pn, *pn2; + ParseNode *pn, *pn2; /* * The three options here are: @@ -4780,7 +4766,7 @@ Parser::variables(bool inLetHead) #if JS_HAS_BLOCK_SCOPE bool popScope = (inLetHead || (let && (tc->flags & TCF_IN_FOR_INIT))); - JSStmtInfo *save = tc->topStmt, *saveScope = tc->topScopeStmt; + StmtInfo *save = tc->topStmt, *saveScope = tc->topScopeStmt; #endif /* Make sure that statement set up the tree context correctly. */ @@ -4840,7 +4826,7 @@ Parser::variables(bool inLetHead) tc->topScopeStmt = saveScope->downScope; } #endif - JSParseNode *init = assignExpr(); + ParseNode *init = assignExpr(); #if JS_HAS_BLOCK_SCOPE if (popScope) { tc->topStmt = save; @@ -4852,7 +4838,7 @@ Parser::variables(bool inLetHead) return NULL; UndominateInitializers(pn2, init->pn_pos.end, tc); - pn2 = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, pn2, init, tc); + pn2 = ParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, pn2, init, tc); if (!pn2) return NULL; pn->append(pn2); @@ -4887,7 +4873,7 @@ Parser::variables(bool inLetHead) tc->topScopeStmt = saveScope->downScope; } #endif - JSParseNode *init = assignExpr(); + ParseNode *init = assignExpr(); #if JS_HAS_BLOCK_SCOPE if (popScope) { tc->topStmt = save; @@ -4936,12 +4922,12 @@ bad_var_init: return NULL; } -JSParseNode * +ParseNode * Parser::expr() { - JSParseNode *pn = assignExpr(); + ParseNode *pn = assignExpr(); if (pn && tokenStream.matchToken(TOK_COMMA)) { - JSParseNode *pn2 = ListNode::create(tc); + ParseNode *pn2 = ListNode::create(tc); if (!pn2) return NULL; pn2->pn_pos.begin = pn->pn_pos.begin; @@ -4972,11 +4958,11 @@ Parser::expr() * speedup. These macros help avoid some boilerplate code. */ #define BEGIN_EXPR_PARSER(name) \ - JS_ALWAYS_INLINE JSParseNode * \ + JS_ALWAYS_INLINE ParseNode * \ Parser::name##i() #define END_EXPR_PARSER(name) \ - JS_NEVER_INLINE JSParseNode * \ + JS_NEVER_INLINE ParseNode * \ Parser::name##n() { \ return name##i(); \ } @@ -4984,7 +4970,7 @@ Parser::expr() BEGIN_EXPR_PARSER(mulExpr1) { TokenKind tt; - JSParseNode *pn = unaryExpr(); + ParseNode *pn = unaryExpr(); /* * Note: unlike addExpr1() et al, we use getToken() here instead of @@ -4994,7 +4980,7 @@ BEGIN_EXPR_PARSER(mulExpr1) while (pn && ((tt = tokenStream.getToken()) == TOK_STAR || tt == TOK_DIVOP)) { tt = tokenStream.currentToken().type; JSOp op = tokenStream.currentToken().t_op; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); + pn = ParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); } return pn; } @@ -5002,11 +4988,11 @@ END_EXPR_PARSER(mulExpr1) BEGIN_EXPR_PARSER(addExpr1) { - JSParseNode *pn = mulExpr1i(); + ParseNode *pn = mulExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_PLUS, TOK_MINUS)) { TokenKind tt = tokenStream.currentToken().type; JSOp op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(tt, op, pn, mulExpr1n(), tc); } return pn; } @@ -5014,10 +5000,10 @@ END_EXPR_PARSER(addExpr1) BEGIN_EXPR_PARSER(shiftExpr1) { - JSParseNode *pn = addExpr1i(); + ParseNode *pn = addExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_SHOP)) { JSOp op = tokenStream.currentToken().t_op; - pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr1n(), tc); } return pn; } @@ -5033,7 +5019,7 @@ BEGIN_EXPR_PARSER(relExpr1) */ tc->flags &= ~TCF_IN_FOR_INIT; - JSParseNode *pn = shiftExpr1i(); + ParseNode *pn = shiftExpr1i(); while (pn && (tokenStream.isCurrentTokenType(TOK_RELOP) || /* @@ -5044,7 +5030,7 @@ BEGIN_EXPR_PARSER(relExpr1) tokenStream.isCurrentTokenType(TOK_INSTANCEOF))) { TokenKind tt = tokenStream.currentToken().type; JSOp op = tokenStream.currentToken().t_op; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr1n(), tc); } /* Restore previous state of inForInit flag. */ tc->flags |= inForInitFlag; @@ -5055,10 +5041,10 @@ END_EXPR_PARSER(relExpr1) BEGIN_EXPR_PARSER(eqExpr1) { - JSParseNode *pn = relExpr1i(); + ParseNode *pn = relExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_EQOP)) { JSOp op = tokenStream.currentToken().t_op; - pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr1n(), tc); } return pn; } @@ -5066,55 +5052,55 @@ END_EXPR_PARSER(eqExpr1) BEGIN_EXPR_PARSER(bitAndExpr1) { - JSParseNode *pn = eqExpr1i(); + ParseNode *pn = eqExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_BITAND)) - pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr1n(), tc); return pn; } END_EXPR_PARSER(bitAndExpr1) BEGIN_EXPR_PARSER(bitXorExpr1) { - JSParseNode *pn = bitAndExpr1i(); + ParseNode *pn = bitAndExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_BITXOR)) - pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr1n(), tc); return pn; } END_EXPR_PARSER(bitXorExpr1) BEGIN_EXPR_PARSER(bitOrExpr1) { - JSParseNode *pn = bitXorExpr1i(); + ParseNode *pn = bitXorExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_BITOR)) - pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr1n(), tc); return pn; } END_EXPR_PARSER(bitOrExpr1) BEGIN_EXPR_PARSER(andExpr1) { - JSParseNode *pn = bitOrExpr1i(); + ParseNode *pn = bitOrExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_AND)) - pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr1n(), tc); return pn; } END_EXPR_PARSER(andExpr1) -JS_ALWAYS_INLINE JSParseNode * +JS_ALWAYS_INLINE ParseNode * Parser::orExpr1() { - JSParseNode *pn = andExpr1i(); + ParseNode *pn = andExpr1i(); while (pn && tokenStream.isCurrentTokenType(TOK_OR)) - pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr1n(), tc); + pn = ParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr1n(), tc); return pn; } -JS_ALWAYS_INLINE JSParseNode * +JS_ALWAYS_INLINE ParseNode * Parser::condExpr1() { - JSParseNode *pn = orExpr1(); + ParseNode *pn = orExpr1(); if (pn && tokenStream.isCurrentTokenType(TOK_HOOK)) { - JSParseNode *pn1 = pn; + ParseNode *pn1 = pn; pn = TernaryNode::create(tc); if (!pn) return NULL; @@ -5126,13 +5112,13 @@ Parser::condExpr1() */ uintN oldflags = tc->flags; tc->flags &= ~TCF_IN_FOR_INIT; - JSParseNode *pn2 = assignExpr(); + ParseNode *pn2 = assignExpr(); tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND); - JSParseNode *pn3 = assignExpr(); + ParseNode *pn3 = assignExpr(); if (!pn3) return NULL; pn->pn_pos.begin = pn1->pn_pos.begin; @@ -5146,7 +5132,7 @@ Parser::condExpr1() } bool -Parser::setAssignmentLhsOps(JSParseNode *pn, JSOp op) +Parser::setAssignmentLhsOps(ParseNode *pn, JSOp op) { switch (pn->getKind()) { case TOK_NAME: @@ -5191,7 +5177,7 @@ Parser::setAssignmentLhsOps(JSParseNode *pn, JSOp op) return true; } -JSParseNode * +ParseNode * Parser::assignExpr() { JS_CHECK_RECURSION(context, return NULL); @@ -5201,7 +5187,7 @@ Parser::assignExpr() return returnOrYield(true); #endif - JSParseNode *pn = condExpr1(); + ParseNode *pn = condExpr1(); if (!pn) return NULL; @@ -5214,11 +5200,11 @@ Parser::assignExpr() if (!setAssignmentLhsOps(pn, op)) return NULL; - JSParseNode *rhs = assignExpr(); + ParseNode *rhs = assignExpr(); if (!rhs) return NULL; if (pn->isKind(TOK_NAME) && pn->isUsed()) { - JSDefinition *dn = pn->pn_lexdef; + Definition *dn = pn->pn_lexdef; /* * If the definition is not flagged as assigned, we must have imputed @@ -5233,12 +5219,12 @@ Parser::assignExpr() } } - return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); + return ParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); } -static JSParseNode * -SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, JSParseNode *kid, const char *name) +static ParseNode * +SetLvalKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid, + const char *name) { if (!kid->isKind(TOK_NAME) && !kid->isKind(TOK_DOT) && @@ -5261,8 +5247,7 @@ SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, static const char incop_name_str[][10] = {"increment", "decrement"}; static JSBool -SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, JSParseNode *kid, +SetIncOpKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid, TokenKind tt, JSBool preorder) { JSOp op; @@ -5308,10 +5293,10 @@ SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, return JS_TRUE; } -JSParseNode * +ParseNode * Parser::unaryExpr() { - JSParseNode *pn, *pn2; + ParseNode *pn, *pn2; JS_CHECK_RECURSION(context, return NULL); @@ -5360,7 +5345,7 @@ Parser::unaryExpr() * returns true. Here we fold constants before checking for a call * expression, in order to rule out delete of a generator expression. */ - if (foldConstants && !js_FoldConstants(context, pn2, tc)) + if (foldConstants && !FoldConstants(context, pn2, tc)) return NULL; switch (pn2->getKind()) { case TOK_LP: @@ -5442,19 +5427,19 @@ Parser::unaryExpr() * the one or more bindings induced by V have not yet been created. */ class CompExprTransplanter { - JSParseNode *root; - JSTreeContext *tc; + ParseNode *root; + TreeContext *tc; bool genexp; uintN adjust; uintN funcLevel; public: - CompExprTransplanter(JSParseNode *pn, JSTreeContext *tc, bool ge, uintN adj) + CompExprTransplanter(ParseNode *pn, TreeContext *tc, bool ge, uintN adj) : root(pn), tc(tc), genexp(ge), adjust(adj), funcLevel(0) { } - bool transplant(JSParseNode *pn); + bool transplant(ParseNode *pn); }; /* @@ -5466,7 +5451,7 @@ class CompExprTransplanter { * Use in any context which may turn out to be inside a generator expression. This * includes parenthesized expressions and argument lists, and it includes the tail * of generator expressions. - * + * * The guard will keep track of any |yield| or |arguments| tokens that occur while * parsing the body. As soon as the parser reaches the end of the body expression, * call endBody() to reset the context's state, and then immediately call: @@ -5475,12 +5460,12 @@ class CompExprTransplanter { * - maybeNoteGenerator() if this *did not* turn out to be a generator expression */ class GenexpGuard { - JSTreeContext *tc; + TreeContext *tc; uint32 startYieldCount; uint32 startArgumentsCount; public: - explicit GenexpGuard(JSTreeContext *tc) + explicit GenexpGuard(TreeContext *tc) : tc(tc) { if (tc->parenDepth == 0) { @@ -5493,8 +5478,8 @@ class GenexpGuard { } void endBody(); - bool checkValidBody(JSParseNode *pn); - bool maybeNoteGenerator(JSParseNode *pn); + bool checkValidBody(ParseNode *pn); + bool maybeNoteGenerator(ParseNode *pn); }; void @@ -5511,10 +5496,10 @@ GenexpGuard::endBody() * generator expression. */ bool -GenexpGuard::checkValidBody(JSParseNode *pn) +GenexpGuard::checkValidBody(ParseNode *pn) { if (tc->yieldCount > startYieldCount) { - JSParseNode *errorNode = tc->yieldNode; + ParseNode *errorNode = tc->yieldNode; if (!errorNode) errorNode = pn; tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_yield_str); @@ -5522,7 +5507,7 @@ GenexpGuard::checkValidBody(JSParseNode *pn) } if (tc->argumentsCount > startArgumentsCount) { - JSParseNode *errorNode = tc->argumentsNode; + ParseNode *errorNode = tc->argumentsNode; if (!errorNode) errorNode = pn; tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_arguments_str); @@ -5540,7 +5525,7 @@ GenexpGuard::checkValidBody(JSParseNode *pn) * generator expression. */ bool -GenexpGuard::maybeNoteGenerator(JSParseNode *pn) +GenexpGuard::maybeNoteGenerator(ParseNode *pn) { if (tc->yieldCount > 0) { tc->flags |= TCF_FUN_IS_GENERATOR; @@ -5566,7 +5551,7 @@ GenexpGuard::maybeNoteGenerator(JSParseNode *pn) * upvar-frame-skip count. */ static bool -BumpStaticLevel(JSParseNode *pn, JSTreeContext *tc) +BumpStaticLevel(ParseNode *pn, TreeContext *tc) { if (!pn->pn_cookie.isFree()) { uintN level = pn->pn_cookie.level() + 1; @@ -5584,7 +5569,7 @@ BumpStaticLevel(JSParseNode *pn, JSTreeContext *tc) } static void -AdjustBlockId(JSParseNode *pn, uintN adjust, JSTreeContext *tc) +AdjustBlockId(ParseNode *pn, uintN adjust, TreeContext *tc) { JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_FUNC) || pn->isArity(PN_NAME)); pn->pn_blockid += adjust; @@ -5593,14 +5578,14 @@ AdjustBlockId(JSParseNode *pn, uintN adjust, JSTreeContext *tc) } bool -CompExprTransplanter::transplant(JSParseNode *pn) +CompExprTransplanter::transplant(ParseNode *pn) { if (!pn) return true; switch (pn->getArity()) { case PN_LIST: - for (JSParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { if (!transplant(pn2)) return false; } @@ -5643,13 +5628,13 @@ CompExprTransplanter::transplant(JSParseNode *pn) * the definition or expression of the function and not the static level * of the function's body. */ - JSFunctionBox *funbox = pn->pn_funbox; + FunctionBox *funbox = pn->pn_funbox; funbox->level = tc->staticLevel + funcLevel; if (++funcLevel == 1 && genexp) { - JSFunctionBox *parent = tc->funbox; + FunctionBox *parent = tc->funbox; - JSFunctionBox **funboxp = &tc->parent->functionList; + FunctionBox **funboxp = &tc->parent->functionList; while (*funboxp != funbox) funboxp = &(*funboxp)->siblings; *funboxp = funbox->siblings; @@ -5675,7 +5660,7 @@ CompExprTransplanter::transplant(JSParseNode *pn) JS_ASSERT(!pn->isOp(JSOP_NOP)); JS_ASSERT(pn->pn_cookie.isFree()); - JSDefinition *dn = pn->pn_lexdef; + Definition *dn = pn->pn_lexdef; JS_ASSERT(dn->isDefn()); /* @@ -5695,7 +5680,7 @@ CompExprTransplanter::transplant(JSParseNode *pn) JSAtom *atom = pn->pn_atom; #ifdef DEBUG - JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL); + StmtInfo *stmt = LexicalLookup(tc, atom, NULL); JS_ASSERT(!stmt || stmt != tc->topStmt); #endif if (genexp && !dn->isOp(JSOP_CALLEE)) { @@ -5710,17 +5695,17 @@ CompExprTransplanter::transplant(JSParseNode *pn) * generator) a use of a new placeholder in the generator's * lexdeps. */ - JSDefinition *dn2 = MakePlaceholder(pn, tc); + Definition *dn2 = MakePlaceholder(pn, tc); if (!dn2) return false; dn2->pn_pos = root->pn_pos; - /* + /* * Change all uses of |dn| that lie within the generator's * |yield| expression into uses of dn2. */ - JSParseNode **pnup = &dn->dn_uses; - JSParseNode *pnu; + ParseNode **pnup = &dn->dn_uses; + ParseNode *pnu; while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) { pnu->pn_lexdef = dn2; dn2->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS; @@ -5769,13 +5754,13 @@ CompExprTransplanter::transplant(JSParseNode *pn) * comprehension or generator expression, with a unary node as the body of the * (possibly nested) for-loop, initialized by |type, op, kid|. */ -JSParseNode * -Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, +ParseNode * +Parser::comprehensionTail(ParseNode *kid, uintN blockid, bool isGenexp, TokenKind type, JSOp op) { uintN adjust; - JSParseNode *pn, *pn2, *pn3, **pnp; - JSStmtInfo stmtInfo; + ParseNode *pn, *pn2, *pn3, **pnp; + StmtInfo stmtInfo; BindData data; TokenKind tt; @@ -5799,7 +5784,7 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, * this array comprehension. Our caller in primaryExpr, the TOK_LB case * aka the array initialiser case, has passed the blockid to claim for * the comprehension's block scope. We allocate that id or one above it - * here, by calling js_PushLexicalScope. + * here, by calling PushLexicalScope. * * In the case of a comprehension expression that has nested blocks * (e.g., let expressions), we will allocate a higher blockid but then @@ -5888,7 +5873,7 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, } MUST_MATCH_TOKEN(TOK_IN, JSMSG_IN_AFTER_FOR_NAME); - JSParseNode *pn4 = expr(); + ParseNode *pn4 = expr(); if (!pn4) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); @@ -5938,7 +5923,7 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, * Synthesize a declaration. Every definition must appear in the parse * tree in order for ComprehensionTranslator to work. */ - JSParseNode *vars = ListNode::create(tc); + ParseNode *vars = ListNode::create(tc); if (!vars) return NULL; vars->setOp(JSOP_NOP); @@ -5953,7 +5938,7 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, if (!pn3) return NULL; - pn2->pn_left = TernaryNode::create(TOK_IN, JSOP_NOP, vars, pn3, pn4, tc); + pn2->pn_left = new_(TOK_IN, JSOP_NOP, vars, pn3, pn4); if (!pn2->pn_left) return NULL; *pnp = pn2; @@ -6000,11 +5985,11 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, * the first |in| in the chain of |for| heads. Instead, a generator expression * is merely sugar for a generator function expression and its application. */ -JSParseNode * -Parser::generatorExpr(JSParseNode *kid) +ParseNode * +Parser::generatorExpr(ParseNode *kid) { /* Create a |yield| node for |kid|. */ - JSParseNode *pn = UnaryNode::create(tc); + ParseNode *pn = UnaryNode::create(tc); if (!pn) return NULL; pn->setKind(TOK_YIELD); @@ -6015,7 +6000,7 @@ Parser::generatorExpr(JSParseNode *kid) pn->pn_hidden = true; /* Make a new node for the desugared generator function. */ - JSParseNode *genfn = FunctionNode::create(tc); + ParseNode *genfn = FunctionNode::create(tc); if (!genfn) return NULL; genfn->setKind(TOK_FUNCTION); @@ -6024,12 +6009,12 @@ Parser::generatorExpr(JSParseNode *kid) genfn->pn_dflags = PND_FUNARG; { - JSTreeContext *outertc = tc; - JSTreeContext gentc(tc->parser); + TreeContext *outertc = tc; + TreeContext gentc(tc->parser); if (!gentc.init(context)) return NULL; - JSFunctionBox *funbox = EnterFunction(genfn, &gentc); + FunctionBox *funbox = EnterFunction(genfn, &gentc); if (!funbox) return NULL; @@ -6059,7 +6044,7 @@ Parser::generatorExpr(JSParseNode *kid) genfn->pn_funbox = funbox; genfn->pn_blockid = gentc.bodyid; - JSParseNode *body = comprehensionTail(pn, outertc->blockid(), true); + ParseNode *body = comprehensionTail(pn, outertc->blockid(), true); if (!body) return NULL; JS_ASSERT(!genfn->pn_body); @@ -6075,7 +6060,7 @@ Parser::generatorExpr(JSParseNode *kid) * Our result is a call expression that invokes the anonymous generator * function object. */ - JSParseNode *result = ListNode::create(tc); + ParseNode *result = ListNode::create(tc); if (!result) return NULL; result->setKind(TOK_LP); @@ -6091,7 +6076,7 @@ static const char js_generator_str[] = "generator"; #endif /* JS_HAS_GENERATORS */ JSBool -Parser::argumentList(JSParseNode *listNode) +Parser::argumentList(ParseNode *listNode) { if (tokenStream.matchToken(TOK_RP, TSF_OPERAND)) return JS_TRUE; @@ -6100,7 +6085,7 @@ Parser::argumentList(JSParseNode *listNode) bool arg0 = true; do { - JSParseNode *argNode = assignExpr(); + ParseNode *argNode = assignExpr(); if (!argNode) return JS_FALSE; if (arg0) @@ -6145,13 +6130,13 @@ Parser::argumentList(JSParseNode *listNode) } /* Check for an immediately-applied (new'ed) lambda and clear PND_FUNARG. */ -static JSParseNode * -CheckForImmediatelyAppliedLambda(JSParseNode *pn) +static ParseNode * +CheckForImmediatelyAppliedLambda(ParseNode *pn) { if (pn->isKind(TOK_FUNCTION)) { JS_ASSERT(pn->isArity(PN_FUNC)); - JSFunctionBox *funbox = pn->pn_funbox; + FunctionBox *funbox = pn->pn_funbox; JS_ASSERT((funbox->function())->flags & JSFUN_LAMBDA); if (!(funbox->tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME))) pn->pn_dflags &= ~PND_FUNARG; @@ -6159,10 +6144,10 @@ CheckForImmediatelyAppliedLambda(JSParseNode *pn) return pn; } -JSParseNode * +ParseNode * Parser::memberExpr(JSBool allowCallSyntax) { - JSParseNode *pn, *pn2, *pn3; + ParseNode *pn, *pn2, *pn3; JS_CHECK_RECURSION(context, return NULL); @@ -6194,16 +6179,9 @@ Parser::memberExpr(JSBool allowCallSyntax) return NULL; if (pn->isKind(TOK_ANYNAME) || pn->isKind(TOK_AT) || pn->isKind(TOK_DBLCOLON)) { - pn2 = NewOrRecycledNode(tc); - if (!pn2) + pn = new_(TOK_UNARYOP, JSOP_XMLNAME, pn->pn_pos, pn); + if (!pn) return NULL; - pn2->setKind(TOK_UNARYOP); - pn2->pn_pos = pn->pn_pos; - pn2->setOp(JSOP_XMLNAME); - pn2->setArity(PN_UNARY); - pn2->setInParens(false); - pn2->pn_kid = pn; - pn = pn2; } } @@ -6212,15 +6190,21 @@ Parser::memberExpr(JSBool allowCallSyntax) pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; + #if JS_HAS_XML_SUPPORT tt = tokenStream.getToken(TSF_OPERAND | TSF_KEYWORD_IS_NAME); /* Treat filters as 'with' statements for name deoptimization. */ - JSParseNode *oldWith = tc->innermostWith; - JSStmtInfo stmtInfo; + ParseNode *oldWith = tc->innermostWith; + StmtInfo stmtInfo; if (tt == TOK_LP) { + if (tc->inStrictMode()) { + reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT); + return NULL; + } + tc->innermostWith = pn; - js_PushStatement(tc, &stmtInfo, STMT_WITH, -1); + PushStatement(tc, &stmtInfo, STMT_WITH, -1); } pn3 = primaryExpr(tt, JS_TRUE); @@ -6237,7 +6221,7 @@ Parser::memberExpr(JSBool allowCallSyntax) pn2->setOp(JSOP_GETPROP); pn2->pn_expr = pn; pn2->pn_atom = pn3->pn_atom; - RecycleTree(pn3, tc); + freeTree(pn3); } else { if (tt == TOK_LP) { pn2->setKind(TOK_FILTER); @@ -6246,6 +6230,7 @@ Parser::memberExpr(JSBool allowCallSyntax) /* A filtering predicate is like a with statement. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; } else if (TokenKindIsXML(pn3->getKind())) { + JS_ASSERT(!tc->inStrictMode()); pn2->setKind(TOK_LB); pn2->setOp(JSOP_GETELEM); } else { @@ -6266,6 +6251,11 @@ Parser::memberExpr(JSBool allowCallSyntax) pn2->pn_pos.end = tokenStream.currentToken().pos.end; #if JS_HAS_XML_SUPPORT } else if (tt == TOK_DBLDOT) { + if (tc->inStrictMode()) { + reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT); + return NULL; + } + pn2 = BinaryNode::create(tc); if (!pn2) return NULL; @@ -6378,11 +6368,11 @@ Parser::memberExpr(JSBool allowCallSyntax) return pn; } -JSParseNode * +ParseNode * Parser::bracketedExpr() { uintN oldflags; - JSParseNode *pn; + ParseNode *pn; /* * Always accept the 'in' operator in a parenthesized expression, @@ -6398,12 +6388,12 @@ Parser::bracketedExpr() #if JS_HAS_XML_SUPPORT -JSParseNode * +ParseNode * Parser::endBracketedExpr() { - JSParseNode *pn; + JS_ASSERT(!tc->inStrictMode()); - pn = bracketedExpr(); + ParseNode *pn = bracketedExpr(); if (!pn) return NULL; @@ -6462,13 +6452,15 @@ Parser::endBracketedExpr() * We hoist the :: match into callers of QualifiedSuffix, in order to tweak * PropertySelector vs. Identifier pn_arity, pn_op, and other members. */ -JSParseNode * +ParseNode * Parser::propertySelector() { + JS_ASSERT(!tc->inStrictMode()); + DebugOnly tp = &tokenStream.currentToken(); JS_ASSERT(tp->type == TOK_STAR || tp->type == TOK_NAME); - JSParseNode *pn = NullaryNode::create(tc); + ParseNode *pn = NullaryNode::create(tc); if (!pn) return NULL; if (pn->isKind(TOK_STAR)) { @@ -6485,10 +6477,12 @@ Parser::propertySelector() return pn; } -JSParseNode * -Parser::qualifiedSuffix(JSParseNode *pn) +ParseNode * +Parser::qualifiedSuffix(ParseNode *pn) { - JSParseNode *pn2, *pn3; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn2, *pn3; TokenKind tt; JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON); @@ -6530,13 +6524,15 @@ Parser::qualifiedSuffix(JSParseNode *pn) return pn2; } -JSParseNode * +ParseNode * Parser::qualifiedIdentifier() { + JS_ASSERT(!tc->inStrictMode()); + DebugOnly tp = &tokenStream.currentToken(); JS_ASSERT(tp->type == TOK_STAR || tp->type == TOK_NAME); - JSParseNode *pn = propertySelector(); + ParseNode *pn = propertySelector(); if (!pn) return NULL; if (tokenStream.matchToken(TOK_DBLCOLON)) { @@ -6547,10 +6543,12 @@ Parser::qualifiedIdentifier() return pn; } -JSParseNode * +ParseNode * Parser::attributeIdentifier() { - JSParseNode *pn, *pn2; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn, *pn2; TokenKind tt; JS_ASSERT(tokenStream.currentToken().type == TOK_AT); @@ -6576,10 +6574,12 @@ Parser::attributeIdentifier() /* * Make a TOK_LC unary node whose pn_kid is an expression. */ -JSParseNode * +ParseNode * Parser::xmlExpr(JSBool inTag) { - JSParseNode *pn, *pn2; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn, *pn2; JS_ASSERT(tokenStream.currentToken().type == TOK_LC); pn = UnaryNode::create(tc); @@ -6611,10 +6611,12 @@ Parser::xmlExpr(JSBool inTag) * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole * child of a container tag. */ -JSParseNode * +ParseNode * Parser::xmlAtomNode() { - JSParseNode *pn = NullaryNode::create(tc); + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn = NullaryNode::create(tc); if (!pn) return NULL; const Token &tok = tokenStream.currentToken(); @@ -6640,10 +6642,12 @@ Parser::xmlAtomNode() * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME; if PN_UNARY, pn_type * will be TOK_LC. */ -JSParseNode * +ParseNode * Parser::xmlNameExpr() { - JSParseNode *pn, *pn2, *list; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn, *pn2, *list; TokenKind tt; pn = list = NULL; @@ -6707,10 +6711,12 @@ Parser::xmlNameExpr() * PN_LIST, pn_type will be tagtype. If PN_UNARY, pn_type will be TOK_LC and * we parsed exactly one expression. */ -JSParseNode * +ParseNode * Parser::xmlTagContent(TokenKind tagtype, JSAtom **namep) { - JSParseNode *pn, *pn2, *list; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn, *pn2, *list; TokenKind tt; pn = xmlNameExpr(); @@ -6780,8 +6786,10 @@ Parser::xmlTagContent(TokenKind tagtype, JSAtom **namep) * that opens the end tag for the container. */ JSBool -Parser::xmlElementContent(JSParseNode *pn) +Parser::xmlElementContent(ParseNode *pn) { + JS_ASSERT(!tc->inStrictMode()); + tokenStream.setXMLTagMode(false); for (;;) { TokenKind tt = tokenStream.getToken(TSF_XMLTEXTMODE); @@ -6791,7 +6799,7 @@ Parser::xmlElementContent(JSParseNode *pn) JSAtom *textAtom = tokenStream.currentToken().atom(); if (textAtom) { /* Non-zero-length XML text scanned. */ - JSParseNode *pn2 = xmlAtomNode(); + ParseNode *pn2 = xmlAtomNode(); if (!pn2) return JS_FALSE; pn->pn_pos.end = pn2->pn_pos.end; @@ -6803,7 +6811,7 @@ Parser::xmlElementContent(JSParseNode *pn) if (tt == TOK_XMLETAGO) break; - JSParseNode *pn2; + ParseNode *pn2; if (tt == TOK_LC) { pn2 = xmlExpr(JS_FALSE); pn->pn_xflags |= PNX_CANTFOLD; @@ -6832,10 +6840,12 @@ Parser::xmlElementContent(JSParseNode *pn) /* * Return a PN_LIST node containing an XML or XMLList Initialiser. */ -JSParseNode * +ParseNode * Parser::xmlElementOrList(JSBool allowList) { - JSParseNode *pn, *pn2, *list; + JS_ASSERT(!tc->inStrictMode()); + + ParseNode *pn, *pn2, *list; TokenKind tt; JSAtom *startAtom, *endAtom; @@ -6865,7 +6875,7 @@ Parser::xmlElementOrList(JSBool allowList) /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->isKind(TOK_XMLSTAGO)) { pn->makeEmpty(); - RecycleTree(pn, tc); + freeTree(pn); pn = pn2; } else { JS_ASSERT(pn2->isKind(TOK_XMLNAME) || @@ -6969,9 +6979,11 @@ Parser::xmlElementOrList(JSBool allowList) return pn; } -JSParseNode * +ParseNode * Parser::xmlElementOrListRoot(JSBool allowList) { + JS_ASSERT(!tc->inStrictMode()); + /* * Force XML support to be enabled so that comments and CDATA literals * are recognized, instead of tc->blockid()) return false; - for (JSStmtInfo *stmt = tc->topScopeStmt; stmt; stmt = stmt->downScope) { + for (StmtInfo *stmt = tc->topScopeStmt; stmt; stmt = stmt->downScope) { if (stmt->blockid == blockid) return true; } @@ -7050,10 +7063,10 @@ BlockIdInScope(uintN blockid, JSTreeContext *tc) } #endif -JSParseNode * +ParseNode * Parser::primaryExpr(TokenKind tt, JSBool afterDot) { - JSParseNode *pn, *pn2, *pn3; + ParseNode *pn, *pn2, *pn3; JSOp op; JS_CHECK_RECURSION(context, return NULL); @@ -7061,7 +7074,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) switch (tt) { case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT - if (tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) { + if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) { pn2 = NullaryNode::create(tc); if (!pn2) return NULL; @@ -7171,7 +7184,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) * where is the index of array's stack slot. */ if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) { - JSParseNode *pnexp, *pntop; + ParseNode *pnexp, *pntop; /* Relabel pn as an array comprehension node. */ pn->setKind(TOK_ARRAYCOMP); @@ -7203,7 +7216,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) case TOK_LC: { - JSParseNode *pnval; + ParseNode *pnval; /* * A map from property names we've seen thus far to a mask of property @@ -7232,7 +7245,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) pn3 = NullaryNode::create(tc); if (!pn3) return NULL; - pn3->pn_dval = tokenStream.currentToken().t_dval; + pn3->pn_dval = tokenStream.currentToken().number(); if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom)) return NULL; break; @@ -7258,7 +7271,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) pn3 = NullaryNode::create(tc); if (!pn3) return NULL; - pn3->pn_dval = tokenStream.currentToken().t_dval; + pn3->pn_dval = tokenStream.currentToken().number(); if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom)) return NULL; } else { @@ -7270,7 +7283,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) /* NB: Getter function in { get x(){} } is unnamed. */ pn2 = functionDef(NULL, op == JSOP_GETTER ? Getter : Setter, Expression); - pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pn2, tc); + pn2 = ParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pn2, tc); goto skip; } case TOK_STRING: @@ -7325,7 +7338,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) #endif } - pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pnval, tc); + pn2 = ParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pnval, tc); skip: if (!pn2) return NULL; @@ -7404,7 +7417,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) pn = UnaryNode::create(tc); if (!pn) return NULL; - pn->pn_num = (jsint) tokenStream.currentToken().t_dval; + pn->pn_num = tokenStream.currentToken().sharpNumber(); tt = tokenStream.getToken(TSF_OPERAND); pn->pn_kid = primaryExpr(tt, JS_FALSE); if (!pn->pn_kid) @@ -7428,7 +7441,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; if (!tc->ensureSharpSlots()) return NULL; - pn->pn_num = (jsint) tokenStream.currentToken().t_dval; + pn->pn_num = tokenStream.currentToken().sharpNumber(); break; #endif /* JS_HAS_SHARP_VARS */ @@ -7465,11 +7478,13 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) break; #endif /* JS_HAS_XML_SUPPORT */ - case TOK_STRING: #if JS_HAS_XML_SUPPORT case TOK_XMLCDATA: case TOK_XMLCOMMENT: + JS_ASSERT(!tc->inStrictMode()); + /* FALL THROUGH */ #endif + case TOK_STRING: pn = NullaryNode::create(tc); if (!pn) return NULL; @@ -7479,6 +7494,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) #if JS_HAS_XML_SUPPORT case TOK_XMLPI: + JS_ASSERT(!tc->inStrictMode()); pn = NullaryNode::create(tc); if (!pn) return NULL; @@ -7516,7 +7532,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) } } else if ((!afterDot #if JS_HAS_XML_SUPPORT - || tokenStream.peekToken() == TOK_DBLCOLON + || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON) #endif ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) { /* In case this is a generator expression outside of any function. */ @@ -7525,10 +7541,10 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) tc->countArgumentsUse(pn); } - JSStmtInfo *stmt = js_LexicalLookup(tc, pn->pn_atom, NULL); + StmtInfo *stmt = LexicalLookup(tc, pn->pn_atom, NULL); MultiDeclRange mdl = tc->decls.lookupMulti(pn->pn_atom); - JSDefinition *dn; + Definition *dn; if (!mdl.empty()) { dn = mdl.front(); @@ -7596,7 +7612,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) } #if JS_HAS_XML_SUPPORT - if (tokenStream.matchToken(TOK_DBLCOLON)) { + if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) { if (afterDot) { /* * Here primaryExpr is called after . or .. followed by a name @@ -7629,7 +7645,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) const jschar *chars = tokenStream.getTokenbuf().begin(); size_t length = tokenStream.getTokenbuf().length(); - RegExpFlag flags = RegExpFlag(tokenStream.currentToken().t_reflags); + RegExpFlag flags = tokenStream.currentToken().regExpFlags(); RegExpStatics *res = context->regExpStatics(); RegExpObject *reobj; @@ -7661,7 +7677,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) if (!pn) return NULL; pn->setOp(JSOP_DOUBLE); - pn->pn_dval = tokenStream.currentToken().t_dval; + pn->pn_dval = tokenStream.currentToken().number(); break; case TOK_PRIMARY: @@ -7682,11 +7698,11 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) return pn; } -JSParseNode * +ParseNode * Parser::parenExpr(JSBool *genexp) { TokenPtr begin; - JSParseNode *pn; + ParseNode *pn; JS_ASSERT(tokenStream.currentToken().type == TOK_LP); begin = tokenStream.currentToken().pos.begin; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 92e375e24b3e..ee93eb419339 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -54,32 +54,26 @@ #include "frontend/ParseMaps.h" #include "frontend/ParseNode.h" -JS_BEGIN_EXTERN_C - namespace js { struct GlobalScope { - GlobalScope(JSContext *cx, JSObject *globalObj, JSCodeGenerator *cg) + GlobalScope(JSContext *cx, JSObject *globalObj, CodeGenerator *cg) : globalObj(globalObj), cg(cg), defs(cx), names(cx) { } struct GlobalDef { JSAtom *atom; // If non-NULL, specifies the property name to add. - JSFunctionBox *funbox; // If non-NULL, function value for the property. + FunctionBox *funbox; // If non-NULL, function value for the property. // This value is only set/used if atom is non-NULL. uint32 knownSlot; // If atom is NULL, this is the known shape slot. GlobalDef() { } - GlobalDef(uint32 knownSlot) - : atom(NULL), knownSlot(knownSlot) - { } - GlobalDef(JSAtom *atom, JSFunctionBox *box) : - atom(atom), funbox(box) - { } + GlobalDef(uint32 knownSlot) : atom(NULL), knownSlot(knownSlot) { } + GlobalDef(JSAtom *atom, FunctionBox *box) : atom(atom), funbox(box) { } }; JSObject *globalObj; - JSCodeGenerator *cg; + CodeGenerator *cg; /* * This is the table of global names encountered during parsing. Each @@ -103,22 +97,22 @@ namespace js { enum FunctionSyntaxKind { Expression, Statement }; -struct Parser : private js::AutoGCRooter +struct Parser : private AutoGCRooter { JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ void *tempFreeList[NUM_TEMP_FREELISTS]; TokenStream tokenStream; - void *tempPoolMark; /* initial JSContext.tempPool mark */ + void *tempPoolMark; /* initial JSContext.tempLifoAlloc mark */ JSPrincipals *principals; /* principals associated with source */ StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ JSObject *const callerVarObj; /* callerFrame's varObj */ - JSParseNode *nodeList; /* list of recyclable parse-node structs */ + ParseNodeAllocator allocator; uint32 functionCount; /* number of functions in current unit */ - JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ - JSTreeContext *tc; /* innermost tree context (stack-allocated) */ + ObjectBox *traceListHead; /* list of parsed object for GC tracing */ + TreeContext *tc; /* innermost tree context (stack-allocated) */ /* Root atoms and objects allocated for the parsed tree. */ - js::AutoKeepAtoms keepAtoms; + AutoKeepAtoms keepAtoms; /* Perform constant-folding; must be true when interfacing with the emitter. */ bool foldConstants; @@ -126,15 +120,16 @@ struct Parser : private js::AutoGCRooter Parser(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL, bool fold = true); ~Parser(); - friend void js::AutoGCRooter::trace(JSTracer *trc); - friend struct ::JSTreeContext; - friend struct Compiler; + friend void AutoGCRooter::trace(JSTracer *trc); + friend struct TreeContext; + friend struct BytecodeCompiler; /* - * Initialize a parser. Parameters are passed on to init tokenStream. - * The compiler owns the arena pool "tops-of-stack" space above the current - * JSContext.tempPool mark. This means you cannot allocate from tempPool - * and save the pointer beyond the next Parser destructor invocation. + * Initialize a parser. Parameters are passed on to init tokenStream. The + * compiler owns the arena pool "tops-of-stack" space above the current + * JSContext.tempLifoAlloc mark. This means you cannot allocate from + * tempLifoAlloc and save the pointer beyond the next Parser destructor + * invocation. */ bool init(const jschar *base, size_t length, const char *filename, uintN lineno, JSVersion version); @@ -149,48 +144,62 @@ struct Parser : private js::AutoGCRooter /* * Parse a top-level JS script. */ - JSParseNode *parse(JSObject *chain); + ParseNode *parse(JSObject *chain); #if JS_HAS_XML_SUPPORT - JSParseNode *parseXMLText(JSObject *chain, bool allowList); + ParseNode *parseXMLText(JSObject *chain, bool allowList); #endif /* - * Allocate a new parsed object or function container from cx->tempPool. + * Allocate a new parsed object or function container from + * cx->tempLifoAlloc. */ - JSObjectBox *newObjectBox(JSObject *obj); + ObjectBox *newObjectBox(JSObject *obj); - JSFunctionBox *newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc); + FunctionBox *newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc); /* * Create a new function object given tree context (tc) and a name (which * is optional if this is a function expression). */ - JSFunction *newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind); + JSFunction *newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind); /* * Analyze the tree of functions nested within a single compilation unit, * starting at funbox, recursively walking its kids, then following its * siblings, their kids, etc. */ - bool analyzeFunctions(JSTreeContext *tc); - void cleanFunctionList(JSFunctionBox **funbox); - bool markFunArgs(JSFunctionBox *funbox); - bool markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensibleParent); - void setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags); + bool analyzeFunctions(TreeContext *tc); + void cleanFunctionList(FunctionBox **funbox); + bool markFunArgs(FunctionBox *funbox); + bool markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent); + void setFunctionKinds(FunctionBox *funbox, uint32 *tcflags); void trace(JSTracer *trc); /* * Report a parse (compile) error. */ - inline bool reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...); + inline bool reportErrorNumber(ParseNode *pn, uintN flags, uintN errorNumber, ...); -private: + private: + void *allocParseNode(size_t size) { + JS_ASSERT(size == sizeof(ParseNode)); + return allocator.allocNode(); + } + + public: + ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); } + void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); } + + /* new_ methods for creating parse nodes. These report OOM on context. */ + JS_DECLARE_NEW_METHODS(allocParseNode, inline) + + private: /* * JS parsers, from lowest to highest precedence. * - * Each parser must be called during the dynamic scope of a JSTreeContext + * Each parser must be called during the dynamic scope of a TreeContext * object, pointed to by this->tc. * * Each returns a parse node tree or null on error. @@ -203,87 +212,87 @@ private: * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - JSParseNode *functionStmt(); - JSParseNode *functionExpr(); - JSParseNode *statements(); - JSParseNode *statement(); - JSParseNode *switchStatement(); - JSParseNode *forStatement(); - JSParseNode *tryStatement(); - JSParseNode *withStatement(); + ParseNode *functionStmt(); + ParseNode *functionExpr(); + ParseNode *statements(); + ParseNode *statement(); + ParseNode *switchStatement(); + ParseNode *forStatement(); + ParseNode *tryStatement(); + ParseNode *withStatement(); #if JS_HAS_BLOCK_SCOPE - JSParseNode *letStatement(); + ParseNode *letStatement(); #endif - JSParseNode *expressionStatement(); - JSParseNode *variables(bool inLetHead); - JSParseNode *expr(); - JSParseNode *assignExpr(); - JSParseNode *condExpr1(); - JSParseNode *orExpr1(); - JSParseNode *andExpr1i(); - JSParseNode *andExpr1n(); - JSParseNode *bitOrExpr1i(); - JSParseNode *bitOrExpr1n(); - JSParseNode *bitXorExpr1i(); - JSParseNode *bitXorExpr1n(); - JSParseNode *bitAndExpr1i(); - JSParseNode *bitAndExpr1n(); - JSParseNode *eqExpr1i(); - JSParseNode *eqExpr1n(); - JSParseNode *relExpr1i(); - JSParseNode *relExpr1n(); - JSParseNode *shiftExpr1i(); - JSParseNode *shiftExpr1n(); - JSParseNode *addExpr1i(); - JSParseNode *addExpr1n(); - JSParseNode *mulExpr1i(); - JSParseNode *mulExpr1n(); - JSParseNode *unaryExpr(); - JSParseNode *memberExpr(JSBool allowCallSyntax); - JSParseNode *primaryExpr(js::TokenKind tt, JSBool afterDot); - JSParseNode *parenExpr(JSBool *genexp = NULL); + ParseNode *expressionStatement(); + ParseNode *variables(bool inLetHead); + ParseNode *expr(); + ParseNode *assignExpr(); + ParseNode *condExpr1(); + ParseNode *orExpr1(); + ParseNode *andExpr1i(); + ParseNode *andExpr1n(); + ParseNode *bitOrExpr1i(); + ParseNode *bitOrExpr1n(); + ParseNode *bitXorExpr1i(); + ParseNode *bitXorExpr1n(); + ParseNode *bitAndExpr1i(); + ParseNode *bitAndExpr1n(); + ParseNode *eqExpr1i(); + ParseNode *eqExpr1n(); + ParseNode *relExpr1i(); + ParseNode *relExpr1n(); + ParseNode *shiftExpr1i(); + ParseNode *shiftExpr1n(); + ParseNode *addExpr1i(); + ParseNode *addExpr1n(); + ParseNode *mulExpr1i(); + ParseNode *mulExpr1n(); + ParseNode *unaryExpr(); + ParseNode *memberExpr(JSBool allowCallSyntax); + ParseNode *primaryExpr(TokenKind tt, JSBool afterDot); + ParseNode *parenExpr(JSBool *genexp = NULL); /* * Additional JS parsers. */ - bool recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember); + bool recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMember); enum FunctionType { Getter, Setter, Normal }; - bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNode **list); - JSParseNode *functionBody(); - JSParseNode *functionDef(PropertyName *name, FunctionType type, FunctionSyntaxKind kind); + bool functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **list); + ParseNode *functionBody(); + ParseNode *functionDef(PropertyName *name, FunctionType type, FunctionSyntaxKind kind); - JSParseNode *condition(); - JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp, - js::TokenKind type = js::TOK_SEMI, JSOp op = JSOP_NOP); - JSParseNode *generatorExpr(JSParseNode *kid); - JSBool argumentList(JSParseNode *listNode); - JSParseNode *bracketedExpr(); - JSParseNode *letBlock(JSBool statement); - JSParseNode *returnOrYield(bool useAssignExpr); - JSParseNode *destructuringExpr(BindData *data, js::TokenKind tt); + ParseNode *condition(); + ParseNode *comprehensionTail(ParseNode *kid, uintN blockid, bool isGenexp, + TokenKind type = TOK_SEMI, JSOp op = JSOP_NOP); + ParseNode *generatorExpr(ParseNode *kid); + JSBool argumentList(ParseNode *listNode); + ParseNode *bracketedExpr(); + ParseNode *letBlock(JSBool statement); + ParseNode *returnOrYield(bool useAssignExpr); + ParseNode *destructuringExpr(BindData *data, TokenKind tt); #if JS_HAS_XML_SUPPORT - JSParseNode *endBracketedExpr(); + ParseNode *endBracketedExpr(); - JSParseNode *propertySelector(); - JSParseNode *qualifiedSuffix(JSParseNode *pn); - JSParseNode *qualifiedIdentifier(); - JSParseNode *attributeIdentifier(); - JSParseNode *xmlExpr(JSBool inTag); - JSParseNode *xmlAtomNode(); - JSParseNode *xmlNameExpr(); - JSParseNode *xmlTagContent(js::TokenKind tagtype, JSAtom **namep); - JSBool xmlElementContent(JSParseNode *pn); - JSParseNode *xmlElementOrList(JSBool allowList); - JSParseNode *xmlElementOrListRoot(JSBool allowList); + ParseNode *propertySelector(); + ParseNode *qualifiedSuffix(ParseNode *pn); + ParseNode *qualifiedIdentifier(); + ParseNode *attributeIdentifier(); + ParseNode *xmlExpr(JSBool inTag); + ParseNode *xmlAtomNode(); + ParseNode *xmlNameExpr(); + ParseNode *xmlTagContent(TokenKind tagtype, JSAtom **namep); + JSBool xmlElementContent(ParseNode *pn); + ParseNode *xmlElementOrList(JSBool allowList); + ParseNode *xmlElementOrListRoot(JSBool allowList); #endif /* JS_HAS_XML_SUPPORT */ - bool setAssignmentLhsOps(JSParseNode *pn, JSOp op); + bool setAssignmentLhsOps(ParseNode *pn, JSOp op); }; inline bool -Parser::reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...) +Parser::reportErrorNumber(ParseNode *pn, uintN flags, uintN errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -293,10 +302,10 @@ Parser::reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...) } bool -CheckStrictParameters(JSContext *cx, JSTreeContext *tc); +CheckStrictParameters(JSContext *cx, TreeContext *tc); bool -DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc); +DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc); } /* namespace js */ @@ -305,6 +314,4 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc); */ #define TS(p) (&(p)->tokenStream) -JS_END_EXTERN_C - #endif /* Parser_h__ */ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index e727650536a4..1cbc07238dd0 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -91,10 +91,8 @@ static const KeywordInfo keywords[] = { #undef JS_KEYWORD }; -namespace js { - const KeywordInfo * -FindKeyword(const jschar *s, size_t length) +js::FindKeyword(const jschar *s, size_t length) { JS_ASSERT(length != 0); @@ -130,10 +128,8 @@ FindKeyword(const jschar *s, size_t length) return NULL; } -} // namespace js - JSBool -js_IsIdentifier(JSLinearString *str) +js::IsIdentifier(JSLinearString *str) { const jschar *chars = str->chars(); size_t length = str->length(); @@ -259,34 +255,6 @@ TokenStream::~TokenStream() # define fast_getc getc #endif -JS_FRIEND_API(int) -js_fgets(char *buf, int size, FILE *file) -{ - int n, i, c; - JSBool crflag; - - n = size - 1; - if (n < 0) - return -1; - - crflag = JS_FALSE; - for (i = 0; i < n && (c = fast_getc(file)) != EOF; i++) { - buf[i] = c; - if (c == '\n') { /* any \n ends a line */ - i++; /* keep the \n; we know there is room for \0 */ - break; - } - if (crflag) { /* \r not followed by \n ends line at the \r */ - ungetc(c, file); - break; /* and overwrite c in buf with \0 */ - } - crflag = (c == '\r'); - } - - buf[i] = '\0'; - return i; -} - JS_ALWAYS_INLINE void TokenStream::updateLineInfoForEOL() { @@ -451,8 +419,7 @@ TokenStream::TokenBuf::findEOL() } bool -TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, - va_list ap) +TokenStream::reportCompileErrorNumberVA(ParseNode *pn, uintN flags, uintN errorNumber, va_list ap) { JSErrorReport report; char *message; @@ -579,7 +546,7 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro } bool -js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, +js::ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, uintN errorNumber, ...) { JS_ASSERT(ts || tc); @@ -604,13 +571,13 @@ js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSP } bool -js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...) +js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags, + uintN errorNumber, ...) { va_list ap; /* - * We don't accept a JSTreeContext argument, so we can't implement + * We don't accept a TreeContext argument, so we can't implement * JSREPORT_STRICT_MODE_ERROR here. Use ReportStrictModeError instead, * or do the checks in the caller and pass plain old JSREPORT_ERROR. */ @@ -953,7 +920,7 @@ TokenStream::getXMLTextOrTag(TokenKind *ttp, Token **tpp) * * https://bugzilla.mozilla.org/show_bug.cgi?id=336551 * - * The check for this is in jsparse.cpp, Compiler::compileScript. + * The check for this is in BytecodeCompiler::compileScript. */ bool TokenStream::getXMLMarkup(TokenKind *ttp, Token **tpp) @@ -1746,7 +1713,7 @@ TokenStream::getTokenInternal() if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval)) goto error; } - tp->t_dval = dval; + tp->setNumber(dval); tt = TOK_NUMBER; goto out; } @@ -1832,7 +1799,7 @@ TokenStream::getTokenInternal() const jschar *dummy; if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), radix, &dummy, &dval)) goto error; - tp->t_dval = dval; + tp->setNumber(dval); tt = TOK_NUMBER; goto out; } @@ -1900,7 +1867,7 @@ TokenStream::getTokenInternal() case '<': #if JS_HAS_XML_SUPPORT - if ((flags & TSF_OPERAND) && (hasXML() || peekChar() != '!')) { + if ((flags & TSF_OPERAND) && !isStrictMode() && (hasXML() || peekChar() != '!')) { if (!getXMLMarkup(&tt, &tp)) goto error; goto out; @@ -1993,10 +1960,9 @@ TokenStream::getTokenInternal() * Look for a regexp. */ if (flags & TSF_OPERAND) { - uintN reflags, length; - JSBool inCharClass = JS_FALSE; - tokenbuf.clear(); + + bool inCharClass = false; for (;;) { c = getChar(); if (c == '\\') { @@ -2004,9 +1970,9 @@ TokenStream::getTokenInternal() goto error; c = getChar(); } else if (c == '[') { - inCharClass = JS_TRUE; + inCharClass = true; } else if (c == ']') { - inCharClass = JS_FALSE; + inCharClass = false; } else if (c == '/' && !inCharClass) { /* For compat with IE, allow unescaped / in char classes. */ break; @@ -2020,31 +1986,36 @@ TokenStream::getTokenInternal() if (!tokenbuf.append(c)) goto error; } - for (reflags = 0, length = tokenbuf.length() + 1; ; length++) { + + RegExpFlag reflags = NoFlags; + uintN length = tokenbuf.length() + 1; + while (true) { c = peekChar(); - if (c == 'g' && !(reflags & JSREG_GLOB)) - reflags |= JSREG_GLOB; + if (c == 'g' && !(reflags & GlobalFlag)) + reflags = RegExpFlag(reflags | GlobalFlag); else if (c == 'i' && !(reflags & IgnoreCaseFlag)) - reflags |= IgnoreCaseFlag; + reflags = RegExpFlag(reflags | IgnoreCaseFlag); else if (c == 'm' && !(reflags & MultilineFlag)) - reflags |= MultilineFlag; + reflags = RegExpFlag(reflags | MultilineFlag); else if (c == 'y' && !(reflags & StickyFlag)) - reflags |= StickyFlag; + reflags = RegExpFlag(reflags | StickyFlag); else break; getChar(); + length++; } + c = peekChar(); if (JS7_ISLET(c)) { - char buf[2] = { '\0' }; + char buf[2] = { '\0', '\0' }; tp->pos.begin.index += length + 1; - buf[0] = (char)c; + buf[0] = char(c); ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG, buf); (void) getChar(); goto error; } - tp->t_reflags = reflags; + tp->setRegExpFlags(reflags); tt = TOK_REGEXP; break; } @@ -2100,9 +2071,8 @@ TokenStream::getTokenInternal() goto error; } } - tp->t_dval = (jsdouble) n; - if (cx->hasStrictOption() && - (c == '=' || c == '#')) { + tp->setSharpNumber(uint16(n)); + if (cx->hasStrictOption() && (c == '=' || c == '#')) { char buf[20]; JS_snprintf(buf, sizeof buf, "#%u%c", n, c); if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, @@ -2159,3 +2129,30 @@ TokenStream::getTokenInternal() return TOK_ERROR; } +JS_FRIEND_API(int) +js_fgets(char *buf, int size, FILE *file) +{ + int n, i, c; + JSBool crflag; + + n = size - 1; + if (n < 0) + return -1; + + crflag = JS_FALSE; + for (i = 0; i < n && (c = fast_getc(file)) != EOF; i++) { + buf[i] = c; + if (c == '\n') { /* any \n ends a line */ + i++; /* keep the \n; we know there is room for \0 */ + break; + } + if (crflag) { /* \r not followed by \n ends line at the \r */ + ungetc(c, file); + break; /* and overwrite c in buf with \0 */ + } + crflag = (c == '\r'); + } + + buf[i] = '\0'; + return i; +} diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index fd33f6e8117c..47d5758f70d0 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -152,20 +152,20 @@ enum TokenKind { TOK_LIMIT /* domain size */ }; -static inline bool +inline bool TokenKindIsXML(TokenKind tt) { return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME; } -static inline bool +inline bool TreeTypeIsXML(TokenKind tt) { return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI || tt == TOK_XMLELEM || tt == TOK_XMLLIST; } -static inline bool +inline bool TokenKindIsDecl(TokenKind tt) { #if JS_HAS_BLOCK_SCOPE @@ -179,29 +179,29 @@ struct TokenPtr { uint32 index; /* index of char in physical line */ uint32 lineno; /* physical line number */ - bool operator==(const TokenPtr& bptr) { + bool operator==(const TokenPtr& bptr) const { return index == bptr.index && lineno == bptr.lineno; } - bool operator!=(const TokenPtr& bptr) { + bool operator!=(const TokenPtr& bptr) const { return index != bptr.index || lineno != bptr.lineno; } - bool operator <(const TokenPtr& bptr) { + bool operator <(const TokenPtr& bptr) const { return lineno < bptr.lineno || (lineno == bptr.lineno && index < bptr.index); } - bool operator <=(const TokenPtr& bptr) { + bool operator <=(const TokenPtr& bptr) const { return lineno < bptr.lineno || (lineno == bptr.lineno && index <= bptr.index); } - bool operator >(const TokenPtr& bptr) { + bool operator >(const TokenPtr& bptr) const { return !(*this <= bptr); } - bool operator >=(const TokenPtr& bptr) { + bool operator >=(const TokenPtr& bptr) const { return !(*this < bptr); } }; @@ -210,27 +210,43 @@ struct TokenPos { TokenPtr begin; /* first character and line of token */ TokenPtr end; /* index 1 past last char, last line */ - bool operator==(const TokenPos& bpos) { + TokenPos() {} + + TokenPos(const TokenPtr &begin, const TokenPtr &end) : begin(begin), end(end) { + // Assertion temporarily disabled by jorendorff. See bug 695922. + //JS_ASSERT(begin <= end); + } + + /* Return a TokenPos that covers left, right, and anything in between. */ + static TokenPos box(const TokenPos &left, const TokenPos &right) { + // Assertions temporarily disabled by jorendorff. See bug 695922. + //JS_ASSERT(left.begin <= left.end); + //JS_ASSERT(left.end <= right.begin); + //JS_ASSERT(right.begin <= right.end); + return TokenPos(left.begin, right.end); + } + + bool operator==(const TokenPos& bpos) const { return begin == bpos.begin && end == bpos.end; } - bool operator!=(const TokenPos& bpos) { + bool operator!=(const TokenPos& bpos) const { return begin != bpos.begin || end != bpos.end; } - bool operator <(const TokenPos& bpos) { + bool operator <(const TokenPos& bpos) const { return begin < bpos.begin; } - bool operator <=(const TokenPos& bpos) { + bool operator <=(const TokenPos& bpos) const { return begin <= bpos.begin; } - bool operator >(const TokenPos& bpos) { + bool operator >(const TokenPos& bpos) const { return !(*this <= bpos); } - bool operator >=(const TokenPos& bpos) { + bool operator >=(const TokenPos& bpos) const { return !(*this < bpos); } }; @@ -249,18 +265,26 @@ struct Token { JSAtom *atom; /* potentially-numeric atom */ } n; } s; - uintN reflags; /* regexp flags, use tokenbuf to access - regexp chars */ - class { /* pair for XML PI */ - friend struct Token; + + private: + friend struct Token; + struct { /* pair for XML PI */ JSAtom *data; /* auxiliary atom table entry */ PropertyName *target; /* main atom table entry */ } xmlpi; - jsdouble dval; /* floating point number */ + uint16 sharpNumber; /* sharp variable number: #1# or #1= */ + jsdouble number; /* floating point number */ + RegExpFlag reflags; /* regexp flags, use tokenbuf to access + regexp chars */ } u; /* Mutators */ + /* + * FIXME: Init type early enough such that all mutators can assert + * type-safety. See bug 697000. + */ + void setName(JSOp op, PropertyName *name) { JS_ASSERT(op == JSOP_NAME); u.s.op = op; @@ -278,6 +302,19 @@ struct Token { u.xmlpi.data = data; } + void setRegExpFlags(js::RegExpFlag flags) { + JS_ASSERT((flags & AllFlags) == flags); + u.reflags = flags; + } + + void setSharpNumber(uint16 sharpNum) { + u.sharpNumber = sharpNum; + } + + void setNumber(jsdouble n) { + u.number = n; + } + /* Type-safe accessors */ PropertyName *name() const { @@ -304,11 +341,25 @@ struct Token { JS_ASSERT(type == TOK_XMLPI); return u.xmlpi.data; } + + js::RegExpFlag regExpFlags() const { + JS_ASSERT(type == TOK_REGEXP); + JS_ASSERT((u.reflags & AllFlags) == u.reflags); + return u.reflags; + } + + uint16 sharpNumber() const { + JS_ASSERT(type == TOK_DEFSHARP || type == TOK_USESHARP); + return u.sharpNumber; + } + + jsdouble number() const { + JS_ASSERT(type == TOK_NUMBER); + return u.number; + } }; #define t_op u.s.op -#define t_reflags u.reflags -#define t_dval u.dval enum TokenStreamFlags { @@ -368,7 +419,7 @@ class TokenStream * first call |close| then call the destructor. If |init| fails, do not call * |close|. * - * This class uses JSContext.tempPool to allocate internal buffers. The + * This class uses JSContext.tempLifoAlloc to allocate internal buffers. The * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE * after calling |close|. */ @@ -417,7 +468,7 @@ class TokenStream bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; } /* Mutators. */ - bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); + bool reportCompileErrorNumberVA(ParseNode *pn, uintN flags, uintN errorNumber, va_list ap); void mungeCurrentToken(TokenKind newKind) { tokens[cursor].type = newKind; } void mungeCurrentToken(JSOp newOp) { tokens[cursor].t_op = newOp; } void mungeCurrentToken(TokenKind newKind, JSOp newOp) { @@ -704,16 +755,6 @@ class TokenStream bool xml; /* see JSOPTION_XML */ }; -} /* namespace js */ - -extern void -js_CloseTokenStream(JSContext *cx, js::TokenStream *ts); - -extern JS_FRIEND_API(int) -js_fgets(char *buf, int size, FILE *file); - -namespace js { - struct KeywordInfo { const char *chars; /* C string with keyword text */ TokenKind tokentype; @@ -725,23 +766,15 @@ struct KeywordInfo { * Returns a KeywordInfo for the specified characters, or NULL if the string is * not a keyword. */ -extern const KeywordInfo * +const KeywordInfo * FindKeyword(const jschar *s, size_t length); -} // namespace js - -/* - * Friend-exported API entry point to call a mapping function on each reserved - * identifier in the scanner's keyword table. - */ -typedef void (*JSMapKeywordFun)(const char *); - /* * Check that str forms a valid JS identifier name. The function does not * check if str is a JS keyword. */ -extern JSBool -js_IsIdentifier(JSLinearString *str); +JSBool +IsIdentifier(JSLinearString *str); /* * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error @@ -749,15 +782,13 @@ js_IsIdentifier(JSLinearString *str); */ #define JSREPORT_UC 0x100 -namespace js { - /* * Report a compile-time error by its number. Return true for a warning, false * for an error. When pn is not null, use it to report error's location. * Otherwise use ts, which must not be null. */ bool -ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags, +ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags, uintN errorNumber, ...); /* @@ -770,7 +801,7 @@ ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN * One could have ReportCompileErrorNumber recognize the * JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function * like this one. However, the strict mode code flag we need to test is - * in the JSTreeContext structure for that code; we would have to change + * in the TreeContext structure for that code; we would have to change * the ~120 ReportCompileErrorNumber calls to pass the additional * argument, even though many of those sites would never use it. Using * ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some @@ -778,9 +809,12 @@ ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN * error. */ bool -ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, +ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, uintN errorNumber, ...); } /* namespace js */ +extern JS_FRIEND_API(int) +js_fgets(char *buf, int size, FILE *file); + #endif /* TokenStream_h__ */ diff --git a/js/src/js-config.h.in b/js/src/js-config.h.in index e3a5f74f52c2..3061021894af 100644 --- a/js/src/js-config.h.in +++ b/js/src/js-config.h.in @@ -59,6 +59,14 @@ useable. See jstypes.h and jsstdint.h. */ #undef JS_HAVE_STDINT_H +/* Define to 1 if the header is present and + useable. See jscpucfg.h. */ +#undef JS_HAVE_ENDIAN_H + +/* Define to 1 if the header is present and + useable. See jscpucfg.h. */ +#undef JS_HAVE_SYS_ISA_DEFS_H + /* Define to 1 if the defines int8_t, etc. */ #undef JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES diff --git a/js/src/js.msg b/js/src/js.msg index 107e4f96de50..f02bd06ab8ee 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -370,3 +370,4 @@ MSG_DEF(JSMSG_DEBUG_BAD_LINE, 283, 0, JSEXN_TYPEERR, "invalid line numbe MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 284, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee") MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 285, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object") MSG_DEF(JSMSG_DEBUG_NOT_SCRIPT_FRAME, 286, 0, JSEXN_ERR, "stack frame is not running JavaScript code") +MSG_DEF(JSMSG_CANT_WATCH_PROP, 287, 0, JSEXN_TYPEERR, "properties whose names are objects can't be watched") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 757d72324e87..b2a1d3f0bf70 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1275,30 +1275,33 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target) return reinterpret_cast(call); } +namespace js { + // Declared in jscompartment.h -JSClass js_dummy_class = { +Class dummy_class = { "jdummy", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, NULL, - JSCLASS_NO_OPTIONAL_MEMBERS + JS_ConvertStub }; +} /*namespace js */ + JS_PUBLIC_API(JSCrossCompartmentCall *) JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target) { CHECK_REQUEST(cx); - - JSObject *scriptObject = target->u.object; - if (!scriptObject) { + JS_ASSERT(!target->isCachedEval); + GlobalObject *global = target->u.globalObject; + if (!global) { SwitchToCompartment sc(cx, target->compartment()); - scriptObject = JS_NewGlobalObject(cx, &js_dummy_class); - if (!scriptObject) + global = GlobalObject::create(cx, &dummy_class); + if (!global) return NULL; } - return JS_EnterCrossCompartmentCall(cx, scriptObject); + return JS_EnterCrossCompartmentCall(cx, global); } JS_PUBLIC_API(JSCrossCompartmentCall *) @@ -1815,7 +1818,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved) atom = rt->atomState.typeAtoms[JSTYPE_VOID]; if (idstr == atom) { *resolved = JS_TRUE; - return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + return obj->defineProperty(cx, atom->asPropertyName(), UndefinedValue(), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY); } @@ -1886,7 +1889,6 @@ JS_PUBLIC_API(JSBool) JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) { JSRuntime *rt; - JSAtom *atom; uintN i; CHECK_REQUEST(cx); @@ -1897,9 +1899,9 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) * Check whether we need to bind 'undefined' and define it if so. * Since ES5 15.1.1.3 undefined can't be deleted. */ - atom = rt->atomState.typeAtoms[JSTYPE_VOID]; - if (!obj->nativeContains(cx, ATOM_TO_JSID(atom)) && - !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyName *name = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (!obj->nativeContains(cx, ATOM_TO_JSID(name)) && + !obj->defineProperty(cx, name, UndefinedValue(), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return JS_FALSE; @@ -2436,6 +2438,22 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, buf[bufsize - 1] = '\0'; } +extern JS_PUBLIC_API(const char *) +JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize) +{ + if (trc->debugPrinter) { + trc->debugPrinter(trc, buffer, bufferSize); + return buffer; + } + if (trc->debugPrintIndex != (size_t) - 1) { + JS_snprintf(buffer, bufferSize, "%s[%lu]", + (const char *)trc->debugPrintArg, + trc->debugPrintIndex); + return buffer; + } + return (const char*)trc->debugPrintArg; +} + typedef struct JSHeapDumpNode JSHeapDumpNode; struct JSHeapDumpNode { @@ -2507,18 +2525,7 @@ DumpNotify(JSTracer *trc, void *thing, JSGCTraceKind kind) entry->key = thing; } - if (dtrc->base.debugPrinter) { - dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer)); - edgeName = dtrc->buffer; - } else if (dtrc->base.debugPrintIndex != (size_t)-1) { - JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]", - (const char *)dtrc->base.debugPrintArg, - dtrc->base.debugPrintIndex); - edgeName = dtrc->buffer; - } else { - edgeName = (const char*)dtrc->base.debugPrintArg; - } - + edgeName = JS_GetTraceEdgeName(&dtrc->base, dtrc->buffer, sizeof(dtrc->buffer)); edgeNameSize = strlen(edgeName) + 1; size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize; node = (JSHeapDumpNode *) OffTheBooks::malloc_(bytes); @@ -3498,7 +3505,7 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value, return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, flags, tinyid); } - return obj->defineProperty(cx, id, value, getter, setter, attrs); + return obj->defineGeneric(cx, id, value, getter, setter, attrs); } JS_PUBLIC_API(JSBool) @@ -3704,7 +3711,7 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, ? Proxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc) : Proxy::getPropertyDescriptor(cx, obj2, id, false, desc); } - if (!obj2->getAttributes(cx, id, &desc->attrs)) + if (!obj2->getGenericAttributes(cx, id, &desc->attrs)) return false; desc->getter = NULL; desc->setter = NULL; @@ -3798,7 +3805,7 @@ SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JS } JSBool ok = obj->isNative() ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs) - : obj->setAttributes(cx, id, &attrs); + : obj->setGenericAttributes(cx, id, &attrs); if (ok) *foundp = true; return ok; @@ -3891,7 +3898,7 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); - return obj->setProperty(cx, id, vp, false); + return obj->setGeneric(cx, id, vp, false); } JS_PUBLIC_API(JSBool) @@ -3924,7 +3931,7 @@ JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); - return obj->deleteProperty(cx, id, rval, false); + return obj->deleteGeneric(cx, id, rval, false); } JS_PUBLIC_API(JSBool) @@ -4579,9 +4586,9 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p assertSameCompartment(cx, obj, principals); AutoLastFrameCheck lfc(cx); - uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT; - return Compiler::compileScript(cx, obj, NULL, principals, tcflags, - chars, length, filename, lineno, version); + uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL; + return BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, chars, length, + filename, lineno, version); } extern JS_PUBLIC_API(JSScript *) @@ -4756,9 +4763,9 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, JS_ASSERT(i <= len); len = i; - uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT; - script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1, - cx->findVersion()); + uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL; + script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, + filename, 1, cx->findVersion()); cx->free_(buf); return script; } @@ -4817,11 +4824,12 @@ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *f } JS_PUBLIC_API(JSObject *) -JS_GetObjectFromScript(JSScript *script) +JS_GetGlobalFromScript(JSScript *script) { - JS_ASSERT(script->u.object); + JS_ASSERT(!script->isCachedEval); + JS_ASSERT(script->u.globalObject); - return script->u.object; + return script->u.globalObject; } static JSFunction * @@ -4857,14 +4865,16 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj, if (!fun) return NULL; - if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings, - chars, length, filename, lineno, version)) { + if (!BytecodeCompiler::compileFunctionBody(cx, fun, principals, &bindings, + chars, length, filename, lineno, version)) + { return NULL; } if (obj && funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun), - NULL, NULL, JSPROP_ENUMERATE)) { + !obj->defineGeneric(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun), NULL, NULL, + JSPROP_ENUMERATE)) + { return NULL; } @@ -5013,14 +5023,14 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, { JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); - uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT; + uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL; if (!rval) flags |= TCF_NO_SCRIPT_RVAL; CHECK_REQUEST(cx); AutoLastFrameCheck lfc(cx); - JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, flags, - chars, length, filename, lineno, compileVersion); + JSScript *script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, flags, chars, + length, filename, lineno, compileVersion); if (!script) return false; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 21e80a37e8fa..0e9a33a1cea6 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2807,6 +2807,9 @@ extern JS_PUBLIC_API(void) JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, JSGCTraceKind kind, JSBool includeDetails); +extern JS_PUBLIC_API(const char *) +JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize); + /* * DEBUG-only method to dump the object graph of heap-allocated things. * @@ -3813,7 +3816,7 @@ JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, JSVersion version); extern JS_PUBLIC_API(JSObject *) -JS_GetObjectFromScript(JSScript *script); +JS_GetGlobalFromScript(JSScript *script); extern JS_PUBLIC_API(JSFunction *) JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name, diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index f492a090342d..a9a40a25a176 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -197,7 +197,7 @@ namespace js { * "08" or "4.0" as array indices, which they are not. * */ -bool +JS_FRIEND_API(bool) StringIsArrayIndex(JSLinearString *str, jsuint *indexp) { const jschar *s = str->chars(); @@ -481,7 +481,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v) JS_ASSERT(!JSID_IS_VOID(idr.id())); Value tmp = v; - return obj->setProperty(cx, idr.id(), &tmp, true); + return obj->setGeneric(cx, idr.id(), &tmp, true); } #ifdef JS_TRACER @@ -541,7 +541,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict) return 1; Value v; - if (!obj->deleteProperty(cx, idr.id(), &v, strict)) + if (!obj->deleteGeneric(cx, idr.id(), &v, strict)) return -1; return v.isTrue() ? 1 : 0; } @@ -564,13 +564,10 @@ SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length) { - Value v; - jsid id; + Value v = NumberValue(length); - v.setNumber(length); - id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); /* We don't support read-only array length yet. */ - return obj->setProperty(cx, id, &v, false); + return obj->setProperty(cx, cx->runtime->atomState.lengthAtom, &v, false); } /* @@ -596,9 +593,8 @@ static JSBool array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) { if (!obj->isArray()) { - jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - - return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE); + return obj->defineProperty(cx, cx->runtime->atomState.lengthAtom, *vp, + NULL, NULL, JSPROP_ENUMERATE); } uint32 newlen; @@ -674,7 +670,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value jsuint index; Value junk; if (js_IdIsIndex(id, &index) && index - newlen < gap && - !obj->deleteProperty(cx, id, &junk, false)) { + !obj->deleteElement(cx, index, &junk, false)) { return false; } } @@ -900,7 +896,7 @@ array_typeOf(JSContext *cx, JSObject *obj) } static JSBool -array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +array_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { uint32 i; @@ -935,6 +931,12 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric return js_SetPropertyHelper(cx, obj, id, 0, vp, strict); } +static JSBool +array_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) +{ + return array_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict); +} + static JSBool array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict) { @@ -977,7 +979,7 @@ array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool s static JSBool array_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict) { - return array_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); + return array_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); } JSBool @@ -1002,12 +1004,9 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj) return JS_FALSE; } -namespace js { - -/* non-static for direct definition of array elements within the engine */ -JSBool -array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, - JSPropertyOp getter, StrictPropertyOp setter, uintN attrs) +static JSBool +array_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value, + JSPropertyOp getter, StrictPropertyOp setter, uintN attrs) { if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) return JS_TRUE; @@ -1040,6 +1039,15 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); } +static JSBool +array_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value, + JSPropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + return array_defineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs); +} + +namespace js { + /* non-static for direct definition of array elements within the engine */ JSBool array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value, @@ -1085,15 +1093,24 @@ static JSBool array_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value, PropertyOp getter, StrictPropertyOp setter, uintN attrs) { - return array_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs); + return array_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs); } static JSBool -array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +array_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ? JSPROP_PERMANENT : JSPROP_ENUMERATE; - return JS_TRUE; + return true; +} + +static JSBool +array_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + *attrsp = (name == cx->runtime->atomState.lengthAtom) + ? JSPROP_PERMANENT + : JSPROP_ENUMERATE; + return true; } static JSBool @@ -1106,11 +1123,19 @@ array_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *at static JSBool array_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return array_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + *attrsp = JSPROP_ENUMERATE; + return true; } static JSBool -array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +array_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); + return false; +} + +static JSBool +array_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); return false; @@ -1126,14 +1151,12 @@ array_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *at static JSBool array_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return array_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); + return false; } -namespace js { - -/* non-static for direct deletion of array elements within the engine */ -JSBool -array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +static JSBool +array_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { uint32 i; @@ -1157,6 +1180,14 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool return true; } +static JSBool +array_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) +{ + return array_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict); +} + +namespace js { + /* non-static for direct deletion of array elements within the engine */ JSBool array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) @@ -1181,7 +1212,7 @@ array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSB static JSBool array_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return array_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return array_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } static void @@ -1234,7 +1265,7 @@ Class js::ArrayClass = { array_lookupProperty, array_lookupElement, array_lookupSpecial, - array_defineProperty, + array_defineGeneric, array_defineProperty, array_defineElement, array_defineSpecial, @@ -1242,19 +1273,19 @@ Class js::ArrayClass = { array_getProperty, array_getElement, array_getSpecial, - array_setProperty, + array_setGeneric, array_setProperty, array_setElement, array_setSpecial, - array_getAttributes, - array_getAttributes, + array_getGenericAttributes, + array_getPropertyAttributes, array_getElementAttributes, array_getSpecialAttributes, - array_setAttributes, - array_setAttributes, + array_setGenericAttributes, + array_setPropertyAttributes, array_setElementAttributes, array_setSpecialAttributes, - array_deleteProperty, + array_deleteGeneric, array_deleteProperty, array_deleteElement, array_deleteSpecial, @@ -1500,9 +1531,9 @@ array_toSource(JSContext *cx, uintN argc, Value *vp) for (jsuint index = 0; index < length; index++) { JSBool hole; - Value tmp; + Value elt; if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, index, &hole, &tmp)) { + !GetElement(cx, obj, index, &hole, &elt)) { return false; } @@ -1511,7 +1542,7 @@ array_toSource(JSContext *cx, uintN argc, Value *vp) if (hole) { str = cx->runtime->emptyString; } else { - str = js_ValueToSource(cx, tmp); + str = js_ValueToSource(cx, elt); if (!str) return false; } @@ -1590,7 +1621,7 @@ class AutoArrayCycleDetector static JSBool array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, - JSString *sepstr, Value *rval) + JSString *sepstr, CallArgs &args) { static const jschar comma = ','; const jschar *sep; @@ -1610,7 +1641,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, return false; if (detector.foundCycle()) { - rval->setString(cx->runtime->atomState.emptyAtom); + args.rval().setString(cx->runtime->atomState.emptyAtom); return true; } @@ -1639,19 +1670,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, return false; JSBool hole; - if (!GetElement(cx, obj, index, &hole, rval)) + Value elt; + if (!GetElement(cx, obj, index, &hole, &elt)) return false; - if (!hole && !rval->isNullOrUndefined()) { + if (!hole && !elt.isNullOrUndefined()) { if (locale) { - JSObject *robj = ToObject(cx, rval); + JSObject *robj = ToObject(cx, &elt); if (!robj) return false; jsid id = ATOM_TO_JSID(cx->runtime->atomState.toLocaleStringAtom); - if (!robj->callMethod(cx, id, 0, NULL, rval)) + if (!robj->callMethod(cx, id, 0, NULL, &elt)) return false; } - if (!ValueToStringBuffer(cx, *rval, sb)) + if (!ValueToStringBuffer(cx, elt, sb)) return false; } @@ -1665,7 +1697,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, JSString *str = sb.finishString(); if (!str) return false; - rval->setString(str); + args.rval().setString(str); return true; } @@ -1675,11 +1707,12 @@ array_toString(JSContext *cx, uintN argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; - Value &join = vp[0]; + Value join = args.calleev(); if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join)) return false; @@ -1687,22 +1720,22 @@ array_toString(JSContext *cx, uintN argc, Value *vp) JSString *str = obj_toStringHelper(cx, obj); if (!str) return false; - vp->setString(str); + args.rval().setString(str); return true; } LeaveTrace(cx); - InvokeArgsGuard args; - if (!cx->stack.pushInvokeArgs(cx, 0, &args)) + InvokeArgsGuard ag; + if (!cx->stack.pushInvokeArgs(cx, 0, &ag)) return false; - args.calleev() = join; - args.thisv().setObject(*obj); + ag.calleev() = join; + ag.thisv().setObject(*obj); /* Do the call. */ - if (!Invoke(cx, args)) + if (!Invoke(cx, ag)) return false; - *vp = args.rval(); + args.rval() = ag.rval(); return true; } @@ -1711,7 +1744,8 @@ array_toLocaleString(JSContext *cx, uintN argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; @@ -1719,7 +1753,7 @@ array_toLocaleString(JSContext *cx, uintN argc, Value *vp) * Passing comma here as the separator. Need a way to get a * locale-specific version. */ - return array_toString_sub(cx, obj, JS_TRUE, NULL, vp); + return array_toString_sub(cx, obj, JS_TRUE, NULL, args); } static inline bool @@ -1802,7 +1836,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, cons do { *tvr.addr() = *vector++; if (!js_ValueToStringId(cx, idval, idr.addr()) || - !obj->setProperty(cx, idr.id(), tvr.addr(), true)) { + !obj->setGeneric(cx, idr.id(), tvr.addr(), true)) { return JS_FALSE; } idval.getDoubleRef() += 1; @@ -1851,32 +1885,33 @@ array_join(JSContext *cx, uintN argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); + CallArgs args = CallArgsFromVp(argc, vp); JSString *str; - if (argc == 0 || vp[2].isUndefined()) { + if (args.length() == 0 || args[0].isUndefined()) { str = NULL; } else { - str = js_ValueToString(cx, vp[2]); + str = js_ValueToString(cx, args[0]); if (!str) return JS_FALSE; - vp[2].setString(str); + args[0].setString(str); } - JSObject *obj = ToObject(cx, &vp[1]); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; - return array_toString_sub(cx, obj, JS_FALSE, str, vp); + return array_toString_sub(cx, obj, JS_FALSE, str, args); } static JSBool array_reverse(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; jsuint len; if (!js_GetLengthProperty(cx, obj, &len)) return false; - vp->setObject(*obj); do { if (!obj->isDenseArray()) @@ -1885,8 +1920,10 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) break; /* An empty array or an array with no elements is already reversed. */ - if (len == 0 || obj->getDenseArrayCapacity() == 0) + if (len == 0 || obj->getDenseArrayCapacity() == 0) { + args.rval().setObject(*obj); return true; + } /* * It's actually surprisingly complicated to reverse an array due to the @@ -1929,21 +1966,22 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) * array has trailing holes (and thus the original array began with * holes). */ + args.rval().setObject(*obj); return true; } while (false); - AutoValueRooter tvr(cx); + Value lowval, hival; for (jsuint i = 0, half = len / 2; i < half; i++) { JSBool hole, hole2; if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, i, &hole, tvr.addr()) || - !GetElement(cx, obj, len - i - 1, &hole2, vp) || - !SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) || - !SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) { + !GetElement(cx, obj, i, &hole, &lowval) || + !GetElement(cx, obj, len - i - 1, &hole2, &hival) || + !SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, lowval) || + !SetOrDeleteArrayElement(cx, obj, i, hole2, hival)) { return false; } } - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } @@ -2125,21 +2163,21 @@ sort_compare(void *arg, const void *a, const void *b, int *result) if (!JS_CHECK_OPERATION_LIMIT(cx)) return JS_FALSE; - InvokeArgsGuard &args = ca->args; - if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &args)) + InvokeArgsGuard &ag = ca->args; + if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag)) return JS_FALSE; - args.calleeHasBeenReset(); - args.calleev() = ca->fval; - args.thisv() = UndefinedValue(); - args[0] = *av; - args[1] = *bv; + ag.calleeHasBeenReset(); + ag.calleev() = ca->fval; + ag.thisv() = UndefinedValue(); + ag[0] = *av; + ag[1] = *bv; - if (!Invoke(cx, args)) + if (!Invoke(cx, ag)) return JS_FALSE; jsdouble cmp; - if (!ToNumber(cx, args.rval(), &cmp)) + if (!ToNumber(cx, ag.rval(), &cmp)) return JS_FALSE; /* Clamp cmp to -1, 0, 1. */ @@ -2180,26 +2218,26 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) jsuint len, newlen, i, undefs; size_t elemsize; JSString *str; - - Value *argv = JS_ARGV(cx, vp); + + CallArgs args = CallArgsFromVp(argc, vp); Value fval; - if (argc > 0 && !argv[0].isUndefined()) { - if (argv[0].isPrimitive()) { + if (args.length() > 0 && !args[0].isUndefined()) { + if (args[0].isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); return false; } - fval = argv[0]; /* non-default compare function */ + fval = args[0]; /* non-default compare function */ } else { fval.setNull(); } - JSObject *obj = ToObject(cx, &vp[1]); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; if (!js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } @@ -2278,7 +2316,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) } if (newlen == 0) { - vp->setObject(*obj); + args.rval().setObject(*obj); return true; /* The array has only holes and undefs. */ } @@ -2409,52 +2447,49 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) return false; } - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } /* * Perl-inspired push, pop, shift, unshift, and splice methods. */ -static JSBool -array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +static bool +array_push_slowly(JSContext *cx, JSObject *obj, CallArgs &args) { jsuint length; if (!js_GetLengthProperty(cx, obj, &length)) - return JS_FALSE; - if (!InitArrayElements(cx, obj, length, argc, argv, true)) - return JS_FALSE; + return false; + if (!InitArrayElements(cx, obj, length, args.length(), args.array(), true)) + return false; /* Per ECMA-262, return the new array length. */ - jsdouble newlength = length + jsdouble(argc); - rval->setNumber(newlength); + jsdouble newlength = length + jsdouble(args.length()); + args.rval().setNumber(newlength); return js_SetLengthProperty(cx, obj, newlength); } -static JSBool -array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval) +static bool +array_push1_dense(JSContext* cx, JSObject* obj, CallArgs &args) { + JS_ASSERT(args.length() == 1); + uint32 length = obj->getArrayLength(); - do { - JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1); - if (result != JSObject::ED_OK) { - if (result == JSObject::ED_FAILED) - return false; - JS_ASSERT(result == JSObject::ED_SPARSE); - break; - } + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + if (!obj->makeDenseArraySlow(cx)) + return false; + return array_push_slowly(cx, obj, args); + } - obj->setDenseArrayLength(length + 1); - obj->setDenseArrayElementWithType(cx, length, v); - rval->setNumber(obj->getArrayLength()); - return true; - } while (false); - - if (!obj->makeDenseArraySlow(cx)) - return false; - Value tmp = v; - return array_push_slowly(cx, obj, 1, &tmp, rval); + obj->setDenseArrayLength(length + 1); + obj->setDenseArrayElementWithType(cx, length, args[0]); + args.rval().setNumber(obj->getArrayLength()); + return true; } JS_ALWAYS_INLINE JSBool @@ -2508,71 +2543,81 @@ JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_NewbornArrayPush_tn, CONTEXT, OBJECT, JSBool js::array_push(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; /* Insist on one argument and obj of the expected class. */ - if (argc != 1 || !obj->isDenseArray()) - return array_push_slowly(cx, obj, argc, vp + 2, vp); + if (args.length() != 1 || !obj->isDenseArray()) + return array_push_slowly(cx, obj, args); - return array_push1_dense(cx, obj, vp[2], vp); + return array_push1_dense(cx, obj, args); } static JSBool -array_pop_slowly(JSContext *cx, JSObject* obj, Value *vp) +array_pop_slowly(JSContext *cx, JSObject* obj, CallArgs &args) { jsuint index; - JSBool hole; - if (!js_GetLengthProperty(cx, obj, &index)) - return JS_FALSE; - if (index == 0) { - vp->setUndefined(); - } else { - index--; + return false; - /* Get the to-be-deleted property's value into vp. */ - if (!GetElement(cx, obj, index, &hole, vp)) - return JS_FALSE; - if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) - return JS_FALSE; + if (index == 0) { + args.rval().setUndefined(); + return js_SetLengthProperty(cx, obj, index); } + + index--; + + JSBool hole; + Value elt; + if (!GetElement(cx, obj, index, &hole, &elt)) + return false; + + if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + return false; + + args.rval() = elt; return js_SetLengthProperty(cx, obj, index); } static JSBool -array_pop_dense(JSContext *cx, JSObject* obj, Value *vp) +array_pop_dense(JSContext *cx, JSObject* obj, CallArgs &args) { - jsuint index; - JSBool hole; - - index = obj->getArrayLength(); + jsuint index = obj->getArrayLength(); if (index == 0) { - vp->setUndefined(); + args.rval().setUndefined(); return JS_TRUE; } + index--; - if (!GetElement(cx, obj, index, &hole, vp)) - return JS_FALSE; - if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + + JSBool hole; + Value elt; + if (!GetElement(cx, obj, index, &hole, &elt)) return JS_FALSE; + if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + return JS_FALSE; if (obj->getDenseArrayInitializedLength() > index) obj->setDenseArrayInitializedLength(index); + obj->setArrayLength(cx, index); + + args.rval() = elt; return JS_TRUE; } JSBool js::array_pop(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; if (obj->isDenseArray()) - return array_pop_dense(cx, obj, vp); - return array_pop_slowly(cx, obj, vp); + return array_pop_dense(cx, obj, args); + return array_pop_slowly(cx, obj, args); } #ifdef JS_METHODJIT @@ -2596,7 +2641,8 @@ mjit::stubs::ArrayShift(VMFrame &f) JSBool js::array_shift(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return JS_FALSE; @@ -2605,16 +2651,16 @@ js::array_shift(JSContext *cx, uintN argc, Value *vp) return JS_FALSE; if (length == 0) { - vp->setUndefined(); + args.rval().setUndefined(); } else { length--; if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && length < obj->getDenseArrayCapacity() && 0 < obj->getDenseArrayInitializedLength()) { - *vp = obj->getDenseArrayElement(0); - if (vp->isMagic(JS_ARRAY_HOLE)) - vp->setUndefined(); + args.rval() = obj->getDenseArrayElement(0); + if (args.rval().isMagic(JS_ARRAY_HOLE)) + args.rval().setUndefined(); obj->moveDenseArrayElements(0, 1, length); obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1); obj->setArrayLength(cx, length); @@ -2623,9 +2669,8 @@ js::array_shift(JSContext *cx, uintN argc, Value *vp) return JS_TRUE; } - /* Get the to-be-deleted property's value into vp ASAP. */ JSBool hole; - if (!GetElement(cx, obj, 0, &hole, vp)) + if (!GetElement(cx, obj, 0, &hole, &args.rval())) return JS_FALSE; /* Slide down the array above the first element. */ @@ -2648,11 +2693,8 @@ js::array_shift(JSContext *cx, uintN argc, Value *vp) static JSBool array_unshift(JSContext *cx, uintN argc, Value *vp) { - Value *argv; - JSBool hole; - jsdouble last, newlen; - - JSObject *obj = ToObject(cx, &vp[1]); + CallArgs args = CallArgsFromVp(argc, vp); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; @@ -2660,10 +2702,9 @@ array_unshift(JSContext *cx, uintN argc, Value *vp) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - newlen = length; - if (argc > 0) { - /* Slide up the array to make room for argc at the bottom. */ - argv = JS_ARGV(cx, vp); + jsdouble newlen = length; + if (args.length() > 0) { + /* Slide up the array to make room for all args at the bottom. */ if (length > 0) { bool optimized = false; do { @@ -2671,25 +2712,26 @@ array_unshift(JSContext *cx, uintN argc, Value *vp) break; if (js_PrototypeHasIndexedProperties(cx, obj)) break; - JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, argc); + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, args.length()); if (result != JSObject::ED_OK) { if (result == JSObject::ED_FAILED) return false; JS_ASSERT(result == JSObject::ED_SPARSE); break; } - obj->moveDenseArrayElements(argc, 0, length); - for (uint32 i = 0; i < argc; i++) + obj->moveDenseArrayElements(args.length(), 0, length); + for (uint32 i = 0; i < args.length(); i++) obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); optimized = true; } while (false); if (!optimized) { - last = length; - jsdouble upperIndex = last + argc; + jsdouble last = length; + jsdouble upperIndex = last + args.length(); AutoValueRooter tvr(cx); do { --last, --upperIndex; + JSBool hole; if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, obj, last, &hole, tvr.addr()) || !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) { @@ -2699,17 +2741,17 @@ array_unshift(JSContext *cx, uintN argc, Value *vp) } } - /* Copy from argv to the bottom of the array. */ - if (!InitArrayElements(cx, obj, 0, argc, argv, true)) + /* Copy from args to the bottom of the array. */ + if (!InitArrayElements(cx, obj, 0, args.length(), args.array(), true)) return JS_FALSE; - newlen += argc; + newlen += args.length(); } if (!js_SetLengthProperty(cx, obj, newlen)) return JS_FALSE; /* Follow Perl by returning the new array length. */ - vp->setNumber(newlen); + args.rval().setNumber(newlen); return JS_TRUE; } @@ -2732,18 +2774,39 @@ TryReuseArrayType(JSObject *obj, JSObject *nobj) * Returns true if this is a dense array whose |count| properties starting from * |startingIndex| may be accessed (get, set, delete) directly through its * contiguous vector of elements without fear of getters, setters, etc. along - * the prototype chain. + * the prototype chain, or of enumerators requiring notification of + * modifications. */ static inline bool CanOptimizeForDenseStorage(JSObject *arr, uint32 startingIndex, uint32 count, JSContext *cx) { - JS_ASSERT(UINT32_MAX - startingIndex >= count); + /* If the desired properties overflow dense storage, we can't optimize. */ + if (UINT32_MAX - startingIndex < count) + return false; - uint32 length = startingIndex + count; - return arr->isDenseArray() && - !arr->getType(cx)->hasAllFlags(OBJECT_FLAG_NON_PACKED_ARRAY) && - !js_PrototypeHasIndexedProperties(cx, arr) && - length <= arr->getDenseArrayInitializedLength(); + /* There's no optimizing possible if it's not a dense array. */ + if (!arr->isDenseArray()) + return false; + + /* + * Don't optimize if the array might be in the midst of iteration. We + * rely on this to be able to safely move dense array elements around with + * just a memmove (see JSObject::moveDenseArrayElements), without worrying + * about updating any in-progress enumerators for properties implicitly + * deleted if a hole is moved from one location to another location not yet + * visited. See bug 690622. + * + * Another potential wrinkle: what if the enumeration is happening on an + * object which merely has |arr| on its prototype chain? It turns out this + * case can't happen, because any dense array used as the prototype of + * another object is first slowified, for type inference's sake. + */ + if (JS_UNLIKELY(arr->getType(cx)->hasAllFlags(OBJECT_FLAG_ITERATED))) + return false; + + /* Now just watch out for getters and setters along the prototype chain. */ + return !js_PrototypeHasIndexedProperties(cx, arr) && + startingIndex + count <= arr->getDenseArrayInitializedLength(); } static inline bool @@ -3055,14 +3118,13 @@ js::array_concat(JSContext *cx, uintN argc, Value *vp) static JSBool array_slice(JSContext *cx, uintN argc, Value *vp) { - Value *argv; JSObject *nobj; jsuint length, begin, end, slot; JSBool hole; - argv = JS_ARGV(cx, vp); + CallArgs args = CallArgsFromVp(argc, vp); - JSObject *obj = ToObject(cx, &vp[1]); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; @@ -3071,9 +3133,9 @@ array_slice(JSContext *cx, uintN argc, Value *vp) begin = 0; end = length; - if (argc > 0) { + if (args.length() > 0) { jsdouble d; - if (!ToInteger(cx, argv[0], &d)) + if (!ToInteger(cx, args[0], &d)) return false; if (d < 0) { d += length; @@ -3084,8 +3146,8 @@ array_slice(JSContext *cx, uintN argc, Value *vp) } begin = (jsuint)d; - if (argc > 1 && !argv[1].isUndefined()) { - if (!ToInteger(cx, argv[1], &d)) + if (args.length() > 1 && !args[1].isUndefined()) { + if (!ToInteger(cx, args[1], &d)) return false; if (d < 0) { d += length; @@ -3107,16 +3169,14 @@ array_slice(JSContext *cx, uintN argc, Value *vp) if (!nobj) return JS_FALSE; TryReuseArrayType(obj, nobj); - vp->setObject(*nobj); + args.rval().setObject(*nobj); return JS_TRUE; } - /* Create a new Array object and root it using *vp. */ nobj = NewDenseAllocatedArray(cx, end - begin); if (!nobj) return JS_FALSE; TryReuseArrayType(obj, nobj); - vp->setObject(*nobj); AutoValueRooter tvr(cx); for (slot = begin; slot < end; slot++) { @@ -3128,18 +3188,24 @@ array_slice(JSContext *cx, uintN argc, Value *vp) return JS_FALSE; } + args.rval().setObject(*nobj); return JS_TRUE; } +enum IndexOfKind { + IndexOf, + LastIndexOf +}; + static JSBool -array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) +array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args) { jsuint length, i, stop; Value tosearch; jsint direction; JSBool hole; - JSObject *obj = ToObject(cx, &vp[1]); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; if (!js_GetLengthProperty(cx, obj, &length)) @@ -3147,26 +3213,26 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) if (length == 0) goto not_found; - if (argc <= 1) { - i = isLast ? length - 1 : 0; - tosearch = (argc != 0) ? vp[2] : UndefinedValue(); + if (args.length() <= 1) { + i = (mode == LastIndexOf) ? length - 1 : 0; + tosearch = (args.length() != 0) ? args[0] : UndefinedValue(); } else { jsdouble start; - tosearch = vp[2]; - if (!ToInteger(cx, vp[3], &start)) + tosearch = args[0]; + if (!ToInteger(cx, args[1], &start)) return false; if (start < 0) { start += length; if (start < 0) { - if (isLast) + if (mode == LastIndexOf) goto not_found; i = 0; } else { i = (jsuint)start; } } else if (start >= length) { - if (!isLast) + if (mode == IndexOf) goto not_found; i = length - 1; } else { @@ -3174,7 +3240,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) } } - if (isLast) { + if (mode == LastIndexOf) { stop = 0; direction = -1; } else { @@ -3183,16 +3249,17 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) } for (;;) { + Value elt; if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, (jsuint)i, &hole, vp)) { + !GetElement(cx, obj, (jsuint)i, &hole, &elt)) { return JS_FALSE; } if (!hole) { JSBool equal; - if (!StrictlyEqual(cx, *vp, tosearch, &equal)) + if (!StrictlyEqual(cx, elt, tosearch, &equal)) return JS_FALSE; if (equal) { - vp->setNumber(i); + args.rval().setNumber(i); return JS_TRUE; } } @@ -3202,20 +3269,22 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) } not_found: - vp->setInt32(-1); + args.rval().setInt32(-1); return JS_TRUE; } static JSBool array_indexOf(JSContext *cx, uintN argc, Value *vp) { - return array_indexOfHelper(cx, JS_FALSE, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_indexOfHelper(cx, IndexOf, args); } static JSBool array_lastIndexOf(JSContext *cx, uintN argc, Value *vp) { - return array_indexOfHelper(cx, JS_TRUE, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_indexOfHelper(cx, LastIndexOf, args); } /* Order is important; extras that take a predicate funarg must follow MAP. */ @@ -3232,9 +3301,9 @@ typedef enum ArrayExtraMode { #define REDUCE_MODE(mode) ((mode) == REDUCE || (mode) == REDUCE_RIGHT) static JSBool -array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) +array_extra(JSContext *cx, ArrayExtraMode mode, CallArgs &args) { - JSObject *obj = ToObject(cx, &vp[1]); + JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; @@ -3246,12 +3315,11 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) * First, get or compute our callee, so that we error out consistently * when passed a non-callable object. */ - if (argc == 0) { - js_ReportMissingArg(cx, *vp, 0); + if (args.length() == 0) { + js_ReportMissingArg(cx, args.calleev(), 0); return JS_FALSE; } - Value *argv = vp + 2; - JSObject *callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK); + JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK); if (!callable) return JS_FALSE; @@ -3274,17 +3342,17 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) start = length - 1, end = -1, step = -1; /* FALL THROUGH */ case REDUCE: - if (length == 0 && argc == 1) { + if (length == 0 && args.length() == 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE); return JS_FALSE; } - if (argc >= 2) { - *vp = argv[1]; + if (args.length() >= 2) { + args.rval() = args[1]; } else { JSBool hole; do { - if (!GetElement(cx, obj, start, &hole, vp)) + if (!GetElement(cx, obj, start, &hole, &args.rval())) return JS_FALSE; start += step; } while (hole && start != end); @@ -3306,29 +3374,29 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) if (!newtype) return JS_FALSE; newarr->setType(newtype); - vp->setObject(*newarr); + args.rval().setObject(*newarr); break; case SOME: - vp->setBoolean(false); + args.rval().setBoolean(false); break; case EVERY: - vp->setBoolean(true); + args.rval().setBoolean(true); break; case FOREACH: - vp->setUndefined(); + args.rval().setUndefined(); break; } if (length == 0) return JS_TRUE; - Value thisv = (argc > 1 && !REDUCE_MODE(mode)) ? argv[1] : UndefinedValue(); + Value thisv = (args.length() > 1 && !REDUCE_MODE(mode)) ? args[1] : UndefinedValue(); /* * For all but REDUCE, we call with 3 args (value, index, array). REDUCE * requires 4 args (accum, value, index, array). */ - argc = 3 + REDUCE_MODE(mode); + uintN agArgc = 3 + REDUCE_MODE(mode); MUST_FLOW_THROUGH("out"); JSBool ok = JS_TRUE; @@ -3336,7 +3404,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) Value objv = ObjectValue(*obj); AutoValueRooter tvr(cx); - InvokeArgsGuard args; + InvokeArgsGuard ag; for (jsuint i = start; i != end; i += step) { JSBool hole; ok = JS_CHECK_OPERATION_LIMIT(cx) && @@ -3346,29 +3414,29 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) if (hole) continue; - if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, argc, &args)) + if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, agArgc, &ag)) return false; /* * Push callable and 'this', then args. We must do this for every * iteration around the loop since Invoke clobbers its arguments. */ - args.calleeHasBeenReset(); - args.calleev() = ObjectValue(*callable); - args.thisv() = thisv; + ag.calleeHasBeenReset(); + ag.calleev() = ObjectValue(*callable); + ag.thisv() = thisv; uintN argi = 0; if (REDUCE_MODE(mode)) - args[argi++] = *vp; - args[argi++] = tvr.value(); - args[argi++] = Int32Value(i); - args[argi] = objv; + ag[argi++] = args.rval(); + ag[argi++] = tvr.value(); + ag[argi++] = Int32Value(i); + ag[argi] = objv; /* Do the call. */ - ok = Invoke(cx, args); + ok = Invoke(cx, ag); if (!ok) break; - const Value &rval = args.rval(); + const Value &rval = ag.rval(); if (mode > MAP) cond = js_ValueToBoolean(rval); @@ -3382,7 +3450,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) break; case REDUCE: case REDUCE_RIGHT: - *vp = rval; + args.rval() = rval; break; case MAP: if (!ok) @@ -3403,13 +3471,13 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) break; case SOME: if (cond) { - vp->setBoolean(true); + args.rval().setBoolean(true); goto out; } break; case EVERY: if (!cond) { - vp->setBoolean(false); + args.rval().setBoolean(false); goto out; } break; @@ -3425,43 +3493,50 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) static JSBool array_forEach(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, FOREACH, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, FOREACH, args); } static JSBool array_map(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, MAP, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, MAP, args); } static JSBool array_reduce(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, REDUCE, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, REDUCE, args); } static JSBool array_reduceRight(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, REDUCE_RIGHT, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, REDUCE_RIGHT, args); } static JSBool array_filter(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, FILTER, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, FILTER, args); } static JSBool array_some(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, SOME, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, SOME, args); } static JSBool array_every(JSContext *cx, uintN argc, Value *vp) { - return array_extra(cx, EVERY, argc, vp); + CallArgs args = CallArgsFromVp(argc, vp); + return array_extra(cx, EVERY, args); } static JSBool @@ -3520,33 +3595,34 @@ static JSFunctionSpec array_static_methods[] = { JSBool js_Array(JSContext *cx, uintN argc, Value *vp) { + CallArgs args = CallArgsFromVp(argc, vp); TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array); if (!type) return JS_FALSE; - if (argc != 1 || !vp[2].isNumber()) { - if (!InitArrayTypes(cx, type, vp + 2, argc)) + if (args.length() != 1 || !args[0].isNumber()) { + if (!InitArrayTypes(cx, type, args.array(), args.length())) return false; - JSObject *obj = (argc == 0) + JSObject *obj = (args.length() == 0) ? NewDenseEmptyArray(cx) - : NewDenseCopiedArray(cx, argc, vp + 2); + : NewDenseCopiedArray(cx, args.length(), args.array()); if (!obj) return false; obj->setType(type); - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } uint32 length; - if (vp[2].isInt32()) { - int32_t i = vp[2].toInt32(); + if (args[0].isInt32()) { + int32 i = args[0].toInt32(); if (i < 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return false; } length = uint32(i); } else { - jsdouble d = vp[2].toDouble(); + jsdouble d = args[0].toDouble(); length = js_DoubleToECMAUint32(d); if (d != jsdouble(length)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); @@ -3564,7 +3640,7 @@ js_Array(JSContext *cx, uintN argc, Value *vp) if (obj->getArrayLength() > INT32_MAX) obj->setArrayLength(cx, obj->getArrayLength()); - vp->setObject(*obj); + args.rval().setObject(*obj); return true; } @@ -3724,11 +3800,11 @@ NewSlowEmptyArray(JSContext *cx) JSBool js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp) { - uintN i; + CallArgs args = CallArgsFromVp(argc, vp); JSObject *array; - for (i = 0; i < argc; i++) { - Value arg = JS_ARGV(cx, vp)[i]; + for (uintN i = 0; i < args.length(); i++) { + Value arg = args[i]; char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL); if (!bytes) @@ -3750,7 +3826,7 @@ js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp) cx->free_(bytes); } - JS_SET_RVAL(cx, vp, JSVAL_VOID); + args.rval().setUndefined(); return true; } #endif diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 6134c386ddbb..5d259179cace 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -51,28 +51,9 @@ /* Small arrays are dense, no matter what. */ const uintN MIN_SPARSE_INDEX = 256; -inline uint32 -JSObject::getDenseArrayInitializedLength() -{ - JS_ASSERT(isDenseArray()); - return getElementsHeader()->initializedLength; -} - -inline void -JSObject::setDenseArrayInitializedLength(uint32 length) -{ - JS_ASSERT(isDenseArray()); - JS_ASSERT(length <= getDenseArrayCapacity()); - getElementsHeader()->initializedLength = length; -} - namespace js { /* 2^32-2, inclusive */ const uint32 MAX_ARRAY_INDEX = 4294967294u; - -extern bool -StringIsArrayIndex(JSLinearString *str, jsuint *indexp); - } inline JSBool @@ -166,11 +147,11 @@ js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length); namespace js { extern JSBool -array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, - PropertyOp getter, StrictPropertyOp setter, uintN attrs); +array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs); extern JSBool -array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict); +array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict); /* * Copy 'length' elements from aobj to vp. diff --git a/js/src/jsarrayinlines.h b/js/src/jsarrayinlines.h index cbaf027f62e0..7a9cff93d951 100644 --- a/js/src/jsarrayinlines.h +++ b/js/src/jsarrayinlines.h @@ -41,6 +41,7 @@ #define jsarrayinlines_h___ #include "jsinferinlines.h" +#include "jsobjinlines.h" inline void JSObject::markDenseArrayNotPacked(JSContext *cx) diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index af67f64299f8..a28a9231eb7e 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -54,6 +54,7 @@ #include "jsobj.h" #include "jsstr.h" +#include "vm/BooleanObject-inl.h" #include "vm/GlobalObject.h" #include "jsinferinlines.h" @@ -134,17 +135,15 @@ static JSFunctionSpec boolean_methods[] = { static JSBool Boolean(JSContext *cx, uintN argc, Value *vp) { - Value *argv = vp + 2; - bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false; + CallArgs args = CallArgsFromVp(argc, vp); + + bool b = args.length() != 0 ? js_ValueToBoolean(args[0]) : false; if (IsConstructing(vp)) { - JSObject *obj = NewBuiltinClassInstance(cx, &BooleanClass); - if (!obj) - return false; - obj->setPrimitiveThis(BooleanValue(b)); - vp->setObject(*obj); + JSObject *obj = BooleanObject::create(cx, b); + args.rval().setObject(*obj); } else { - vp->setBoolean(b); + args.rval().setBoolean(b); } return true; } @@ -205,14 +204,14 @@ BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp) * its [[Class]] is "Boolean". Boolean.prototype.valueOf is specified to * return the [[PrimitiveValue]] internal property, so call that instead. */ - InvokeArgsGuard args; - if (!cx->stack.pushInvokeArgs(cx, 0, &args)) + InvokeArgsGuard ag; + if (!cx->stack.pushInvokeArgs(cx, 0, &ag)) return false; - args.calleev().setUndefined(); - args.thisv().setObject(obj); - if (!GetProxyHandler(&obj)->nativeCall(cx, &obj, &BooleanClass, bool_valueOf, args)) + ag.calleev().setUndefined(); + ag.thisv().setObject(obj); + if (!GetProxyHandler(&obj)->nativeCall(cx, &obj, &BooleanClass, bool_valueOf, ag)) return false; - *vp = args.rval(); + *vp = ag.rval(); return true; } diff --git a/js/src/jsbool.h b/js/src/jsbool.h index 07c25d9c45de..c5e857fcecbe 100644 --- a/js/src/jsbool.h +++ b/js/src/jsbool.h @@ -58,16 +58,7 @@ extern bool BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb); inline bool -BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp) -{ - if (obj.isBoolean()) { - *vp = obj.getPrimitiveThis(); - return true; - } - - extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *); - return BooleanGetPrimitiveValueSlow(cx, obj, vp); -} +BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp); } /* namespace js */ diff --git a/js/src/jsboolinlines.h b/js/src/jsboolinlines.h new file mode 100644 index 000000000000..c9f172593461 --- /dev/null +++ b/js/src/jsboolinlines.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Walden (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsboolinlines_h___ +#define jsboolinlines_h___ + +#include "jsobjinlines.h" + +namespace js { + +inline bool +BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp) +{ + if (obj.isBoolean()) { + *vp = obj.getPrimitiveThis(); + return true; + } + + extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *); + return BooleanGetPrimitiveValueSlow(cx, obj, vp); +} + +} /* namespace js */ + +#endif /* jsboolinlines_h___ */ diff --git a/js/src/jsclass.h b/js/src/jsclass.h index 27ade4415063..a2a8a8430412 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -193,7 +193,7 @@ typedef JSBool (* DefineGenericOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value, PropertyOp getter, StrictPropertyOp setter, uintN attrs); typedef JSBool -(* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value, +(* DefinePropOp)(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value, PropertyOp getter, StrictPropertyOp setter, uintN attrs); typedef JSBool (* DefineElementOp)(JSContext *cx, JSObject *obj, uint32 index, const Value *value, @@ -212,7 +212,7 @@ typedef JSBool typedef JSBool (* StrictGenericIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); typedef JSBool -(* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); +(* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict); typedef JSBool (* StrictElementIdOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict); typedef JSBool @@ -220,7 +220,7 @@ typedef JSBool typedef JSBool (* GenericAttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); typedef JSBool -(* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); +(* PropertyAttributesOp)(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp); typedef JSBool (* ElementAttributesOp)(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp); typedef JSBool @@ -228,7 +228,7 @@ typedef JSBool typedef JSBool (* DeleteGenericOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); typedef JSBool -(* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); +(* DeleteIdOp)(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict); typedef JSBool (* DeleteElementOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict); typedef JSBool @@ -319,11 +319,11 @@ struct ObjectOps StrictElementIdOp setElement; StrictSpecialIdOp setSpecial; GenericAttributesOp getGenericAttributes; - AttributesOp getAttributes; + PropertyAttributesOp getPropertyAttributes; ElementAttributesOp getElementAttributes; SpecialAttributesOp getSpecialAttributes; GenericAttributesOp setGenericAttributes; - AttributesOp setAttributes; + PropertyAttributesOp setPropertyAttributes; ElementAttributesOp setElementAttributes; SpecialAttributesOp setSpecialAttributes; DeleteGenericOp deleteGeneric; diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 4f52c677c886..5d99c953c9ad 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -876,7 +876,7 @@ JSStructuredCloneReader::read(Value *vp) objs.popBack(); } else { Value v; - if (!startRead(&v) || !obj->defineProperty(context(), id, v)) + if (!startRead(&v) || !obj->defineGeneric(context(), id, v)) return false; } } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 5cdfb9ac1ff6..dbfec29974ae 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -208,8 +208,8 @@ class CompartmentChecker void check(JSScript *script) { if (script) { check(script->compartment()); - if (script->u.object) - check(script->u.object); + if (!script->isCachedEval && script->u.globalObject) + check(script->u.globalObject); } } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 778ef9527600..56c3f3aeb412 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -271,7 +271,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) if (vp->isObject()) { JSObject *obj = &vp->toObject(); JS_ASSERT(obj->isCrossCompartmentWrapper()); - if (global->getJSClass() != &js_dummy_class && obj->getParent() != global) { + if (global->getClass() != &dummy_class && obj->getParent() != global) { do { if (!obj->setParent(cx, global)) return false; @@ -407,42 +407,6 @@ JSCompartment::wrap(JSContext *cx, AutoIdVector &props) return true; } -#if defined JS_METHODJIT && defined JS_MONOIC -/* - * Check if the pool containing the code for jit should be destroyed, per the - * heuristics in JSCompartment::sweep. - */ -static inline bool -ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit, - uint32 releaseInterval, uint32 &counter) -{ - JSC::ExecutablePool *pool = jit->code.m_executablePool; - if (pool->m_gcNumber != cx->runtime->gcNumber) { - /* - * The m_destroy flag may have been set in a previous GC for a pool which had - * references we did not remove (e.g. from the compartment's ExecutableAllocator) - * and is still around. Forget we tried to destroy it in such cases. - */ - pool->m_destroy = false; - pool->m_gcNumber = cx->runtime->gcNumber; - if (--counter == 0) { - pool->m_destroy = true; - counter = releaseInterval; - } - } - return pool->m_destroy; -} - -static inline void -ScriptTryDestroyCode(JSContext *cx, JSScript *script, bool normal, - uint32 releaseInterval, uint32 &counter) -{ - mjit::JITScript *jit = normal ? script->jitNormal : script->jitCtor; - if (jit && ScriptPoolDestroyed(cx, jit, releaseInterval, counter)) - mjit::ReleaseScriptCode(cx, script, !normal); -} -#endif // JS_METHODJIT && JS_MONOIC - /* * This method marks pointers that cross compartment boundaries. It should be * called only for per-compartment GCs, since full GCs naturally follow pointers @@ -487,7 +451,7 @@ JSCompartment::markTypes(JSTracer *trc) } void -JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) +JSCompartment::sweep(JSContext *cx, bool releaseTypes) { /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { @@ -516,86 +480,27 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) traceMonitor()->sweep(cx); #endif + /* + * Kick all frames on the stack into the interpreter, and release all JIT + * code in the compartment. + */ #ifdef JS_METHODJIT - /* - * Purge PICs in the compartment, along with native call stubs for - * compartments which do not have such stubs on the stack. PICs can - * reference shapes and type data, and native call stubs are disassociated - * from the PIC or MIC they were generated for. - */ - bool canPurgeNativeCalls = true; - VMFrame *f = hasJaegerCompartment() ? jaegerCompartment()->activeFrame() : NULL; - for (; f; f = f->previous) { - if (f->stubRejoin) - canPurgeNativeCalls = false; - } - for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { - JSScript *script = i.get(); - if (script->hasJITCode()) { -#ifdef JS_POLYIC - mjit::ic::PurgePICs(cx, script); -#endif -#ifdef JS_MONOIC - mjit::ic::PurgeMICs(cx, script); -#endif - if (canPurgeNativeCalls) { - if (script->jitNormal) - script->jitNormal->purgeNativeCallStubs(); - if (script->jitCtor) - script->jitCtor->purgeNativeCallStubs(); - } - } - } -#endif - - bool discardScripts = !active && (releaseInterval != 0 || hasDebugModeCodeToDrop); - -#if defined JS_METHODJIT && defined JS_MONOIC - - /* - * The release interval is the frequency with which we should try to destroy - * executable pools by releasing all JIT code in them, zero to never destroy pools. - * Initialize counter so that the first pool will be destroyed, and eventually drive - * the amount of JIT code in never-used compartments to zero. Don't discard anything - * for compartments which currently have active stack frames. - */ - uint32 counter = 1; - if (discardScripts) - hasDebugModeCodeToDrop = false; + mjit::ClearAllFrames(this); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); - if (script->hasJITCode()) { - mjit::ic::SweepCallICs(cx, script, discardScripts); - if (discardScripts) { - ScriptTryDestroyCode(cx, script, true, releaseInterval, counter); - ScriptTryDestroyCode(cx, script, false, releaseInterval, counter); - } - } - } + mjit::ReleaseScriptCode(cx, script); -#endif - -#ifdef JS_METHODJIT - if (types.inferenceEnabled) - mjit::ClearAllFrames(this); -#endif - - if (activeAnalysis) { /* - * Analysis information is in use, so don't clear the analysis pool. - * jitcode still needs to be released, if this is a shape-regenerating - * GC then shape numbers baked into the code may change. + * Use counts for scripts are reset on GC. After discarding code we + * need to let it warm back up to get information like which opcodes + * are setting array holes or accessing getter properties. */ -#ifdef JS_METHODJIT - if (types.inferenceEnabled) { - for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { - JSScript *script = i.get(); - mjit::ReleaseScriptCode(cx, script); - } - } + script->resetUseCount(); + } #endif - } else { + + if (!activeAnalysis) { /* * Clear the analysis pool, but don't release its data yet. While * sweeping types any live data will be allocated into the pool. @@ -603,6 +508,13 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize()); oldAlloc.steal(&typeLifoAlloc); + /* + * Periodically release observed types for all scripts. This is safe to + * do when there are no frames for the compartment on the stack. + */ + if (active) + releaseTypes = false; + /* * Sweep analysis information and everything depending on it from the * compartment, including all remaining mjit code if inference is @@ -614,12 +526,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) if (script->types) { types::TypeScript::Sweep(cx, script); - /* - * On each 1/8 lifetime, release observed types for all scripts. - * This is always safe to do when there are no frames for the - * compartment on the stack. - */ - if (discardScripts) { + if (releaseTypes) { script->types->destroy(); script->types = NULL; script->typesPurged = true; @@ -825,14 +732,11 @@ JSCompartment::getBreakpointSite(jsbytecode *pc) } BreakpointSite * -JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc, JSObject *scriptObject) +JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc, + GlobalObject *scriptGlobal) { JS_ASSERT(script->code <= pc); JS_ASSERT(pc < script->code + script->length); - JS_ASSERT_IF(scriptObject, scriptObject->isScript() || scriptObject->isFunction()); - JS_ASSERT_IF(scriptObject && scriptObject->isFunction(), - scriptObject->toFunction()->script() == script); - JS_ASSERT_IF(scriptObject && scriptObject->isScript(), scriptObject->getScript() == script); BreakpointSiteMap::AddPtr p = breakpointSites.lookupForAdd(pc); if (!p) { @@ -844,10 +748,10 @@ JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbyte } BreakpointSite *site = p->value; - if (site->scriptObject) - JS_ASSERT_IF(scriptObject, site->scriptObject == scriptObject); + if (site->scriptGlobal) + JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal); else - site->scriptObject = scriptObject; + site->scriptGlobal = scriptGlobal; return site; } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 2f0dd04f6933..4b12417dd314 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -293,10 +293,11 @@ struct TraceMonitor { namespace mjit { class JaegerCompartment; } -} /* Defined in jsapi.cpp */ -extern JSClass js_dummy_class; +extern Class dummy_class; + +} /* namespace js */ #ifndef JS_EVAL_CACHE_SHIFT # define JS_EVAL_CACHE_SHIFT 6 @@ -560,7 +561,7 @@ struct JS_FRIEND_API(JSCompartment) { bool wrap(JSContext *cx, js::AutoIdVector &props); void markTypes(JSTracer *trc); - void sweep(JSContext *cx, uint32 releaseInterval); + void sweep(JSContext *cx, bool releaseTypes); void purge(JSContext *cx); void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind); @@ -642,7 +643,7 @@ struct JS_FRIEND_API(JSCompartment) { js::BreakpointSite *getBreakpointSite(jsbytecode *pc); js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc, - JSObject *scriptObject); + js::GlobalObject *scriptGlobal); void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script, JSObject *handler); void clearTraps(JSContext *cx, JSScript *script); bool markTrapClosuresIteratively(JSTracer *trc); diff --git a/js/src/jscpucfg.cpp b/js/src/jscpucfg.cpp deleted file mode 100644 index 028def676f5d..000000000000 --- a/js/src/jscpucfg.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Roland Mainz - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Generate CPU-specific bit-size and similar #defines. - */ -#include -#include - -#if defined(CROSS_COMPILE) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN) -#include -#endif - -/************************************************************************/ - -int main(int argc, char **argv) -{ - printf("#ifndef js_cpucfg___\n"); - printf("#define js_cpucfg___\n\n"); - - printf("/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n"); - -#ifdef CROSS_COMPILE -#if defined(__APPLE__) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN) - /* - * Darwin NSPR uses the same MDCPUCFG (_darwin.cfg) for multiple - * processors, and determines which processor to configure for based - * on compiler predefined macros. We do the same thing here. - */ - printf("#ifdef __LITTLE_ENDIAN__\n"); - printf("#define IS_LITTLE_ENDIAN 1\n"); - printf("#undef IS_BIG_ENDIAN\n"); - printf("#else\n"); - printf("#undef IS_LITTLE_ENDIAN\n"); - printf("#define IS_BIG_ENDIAN 1\n"); - printf("#endif\n\n"); -#elif defined(IS_LITTLE_ENDIAN) || defined(FORCE_LITTLE_ENDIAN) - printf("#define IS_LITTLE_ENDIAN 1\n"); - printf("#undef IS_BIG_ENDIAN\n\n"); -#elif defined(IS_BIG_ENDIAN) || defined(FORCE_BIG_ENDIAN) - printf("#undef IS_LITTLE_ENDIAN\n"); - printf("#define IS_BIG_ENDIAN 1\n\n"); -#else -#error "Endianess not defined." -#endif - -#else - - /* - * We don't handle PDP-endian or similar orders: if a short is big-endian, - * so must int and long be big-endian for us to generate the IS_BIG_ENDIAN - * #define and the IS_LITTLE_ENDIAN #undef. - */ - { - int big_endian = 0, little_endian = 0, ntests = 0; - - if (sizeof(short) == 2) { - /* force |volatile| here to get rid of any compiler optimisations - * (var in register etc.) which may be appiled to |auto| vars - - * even those in |union|s... - * (|static| is used to get the same functionality for compilers - * which do not honor |volatile|...). - */ - volatile static union { - short i; - char c[2]; - } u; - - u.i = 0x0102; - big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02); - little_endian += (u.c[0] == 0x02 && u.c[1] == 0x01); - ntests++; - } - - if (sizeof(int) == 4) { - /* force |volatile| here ... */ - volatile static union { - int i; - char c[4]; - } u; - - u.i = 0x01020304; - big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && - u.c[2] == 0x03 && u.c[3] == 0x04); - little_endian += (u.c[0] == 0x04 && u.c[1] == 0x03 && - u.c[2] == 0x02 && u.c[3] == 0x01); - ntests++; - } - - if (sizeof(long) == 8) { - /* force |volatile| here ... */ - volatile static union { - long i; - char c[8]; - } u; - - /* - * Write this as portably as possible: avoid 0x0102030405060708L - * and <<= 32. - */ - u.i = 0x01020304; - u.i <<= 16, u.i <<= 16; - u.i |= 0x05060708; - big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && - u.c[2] == 0x03 && u.c[3] == 0x04 && - u.c[4] == 0x05 && u.c[5] == 0x06 && - u.c[6] == 0x07 && u.c[7] == 0x08); - little_endian += (u.c[0] == 0x08 && u.c[1] == 0x07 && - u.c[2] == 0x06 && u.c[3] == 0x05 && - u.c[4] == 0x04 && u.c[5] == 0x03 && - u.c[6] == 0x02 && u.c[7] == 0x01); - ntests++; - } - - if (big_endian && big_endian == ntests) { - printf("#undef IS_LITTLE_ENDIAN\n"); - printf("#define IS_BIG_ENDIAN 1\n\n"); - } else if (little_endian && little_endian == ntests) { - printf("#define IS_LITTLE_ENDIAN 1\n"); - printf("#undef IS_BIG_ENDIAN\n\n"); - } else { - fprintf(stderr, "%s: unknown byte order" - "(big_endian=%d, little_endian=%d, ntests=%d)!\n", - argv[0], big_endian, little_endian, ntests); - return EXIT_FAILURE; - } - } - -#endif /* CROSS_COMPILE */ - - // PA-RISC is the only platform we try to support on which the stack - // grows towards higher addresses. Trying to detect it here has - // historically led to portability problems, which aren't worth it - // given the near consensus on stack growth direction. - printf("#ifdef __hppa\n" - "# define JS_STACK_GROWTH_DIRECTION (1)\n" - "#else\n" - "# define JS_STACK_GROWTH_DIRECTION (-1)\n" - "#endif\n"); - - printf("#endif /* js_cpucfg___ */\n"); - - return EXIT_SUCCESS; -} - diff --git a/js/src/jscpucfg.h b/js/src/jscpucfg.h index 1ad122bad860..fdee3e8c2f51 100644 --- a/js/src/jscpucfg.h +++ b/js/src/jscpucfg.h @@ -68,16 +68,70 @@ #define JS_BITS_PER_WORD_LOG2 5 #define JS_ALIGN_OF_POINTER 4L -#else +#elif defined(__APPLE__) +#if __LITTLE_ENDIAN__ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#elif __BIG_ENDIAN__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif -#error "This file is supposed to be auto-generated on most platforms, but the" -#error "static version for Windows and OS2 platforms is being used." -#error "Something's probably wrong with paths/headers/dependencies/Makefiles." +#elif defined(JS_HAVE_ENDIAN_H) +#include +#if defined(__BYTE_ORDER) +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif +#else /* !defined(__BYTE_ORDER) */ +#error "endian.h does not define __BYTE_ORDER. Cannot determine endianness." +#endif + +#elif defined(JS_HAVE_SYS_ISA_DEFS_H) +#include + +#if defined(_BIG_ENDIAN) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#elif defined(_LITTLE_ENDIAN) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else /* !defined(_LITTLE_ENDIAN) */ +#error "sys/isa_defs.h does not define _BIG_ENDIAN or _LITTLE_ENDIAN. Cannot determine endianness." +#endif +#if !defined(JS_STACK_GROWTH_DIRECTION) +#if defined(_STACK_GROWS_UPWARD) +#define JS_STACK_GROWTH_DIRECTION (1) +#elif defined(_STACK_GROWS_DOWNWARD) +#define JS_STACK_GROWTH_DIRECTION (-1) +#endif +#endif + +#elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__hppa) || \ + defined(_MIPSEB) || defined(_BIG_ENDIAN) +/* IA64 running HP-UX will have _BIG_ENDIAN defined. + * IA64 running Linux will have endian.h and be handled above. + */ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#else /* !defined(__sparc) && !defined(__sparc__) && ... */ +#error "Cannot determine endianness of your platform. Please add support to jscpucfg.h." #endif #ifndef JS_STACK_GROWTH_DIRECTION -#define JS_STACK_GROWTH_DIRECTION (-1) +#ifdef __hppa +# define JS_STACK_GROWTH_DIRECTION (1) +#else +# define JS_STACK_GROWTH_DIRECTION (-1) +#endif #endif #endif /* js_cpucfg___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index b771d290b8af..f57f60e81c3f 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -297,6 +297,9 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, AutoValueRooter idroot(cx); if (JSID_IS_INT(id)) { propid = id; + } else if (JSID_IS_OBJECT(id)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP); + return false; } else { if (!js_ValueToStringId(cx, IdToValue(id), &propid)) return false; @@ -328,7 +331,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, } cx->compartment->watchpointMap = wpmap; } - return wpmap->watch(cx, obj, id, handler, closure); + return wpmap->watch(cx, obj, propid, handler, closure); } JS_PUBLIC_API(JSBool) @@ -406,7 +409,7 @@ JS_GetLinePCs(JSContext *cx, JSScript *script, uintN i = 0; for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { offset += SN_DELTA(sn); - JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn); + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE || type == SRC_NEWLINE) { if (type == SRC_SETLINE) lineno = (uintN) js_GetSrcNoteOffset(sn, 0); @@ -1045,9 +1048,6 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script) JSPrincipals *principals; nbytes = sizeof *script; - if (script->u.object) - nbytes += JS_GetObjectTotalSize(cx, script->u.object); - nbytes += script->length * sizeof script->code[0]; nbytes += script->natoms * sizeof script->atoms[0]; for (size_t i = 0; i < script->natoms; i++) diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 2909b33fa6a2..b31136aa4262 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -1238,7 +1238,7 @@ js_ReportUncaughtException(JSContext *cx) JS_ClearPendingException(cx); reportp = js_ErrorFromException(cx, exn); - /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ + /* XXX L10N angels cry once again. see also everywhere else */ str = js_ValueToString(cx, exn); JSAutoByteString bytesStorage; if (!str) { diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 558eea8936a8..783bc202958d 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -253,3 +253,94 @@ JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallba { rt->telemetryCallback = callback; } + +#ifdef DEBUG + +struct DumpingChildInfo { + void *node; + JSGCTraceKind kind; + + DumpingChildInfo (void *n, JSGCTraceKind k) + : node(n), kind(k) + {} +}; + +typedef HashSet, ContextAllocPolicy> PtrSet; + +struct JSDumpHeapTracer : public JSTracer { + PtrSet visited; + FILE *output; + Vector nodes; + char buffer[200]; + bool rootTracing; + + JSDumpHeapTracer(JSContext *cx, FILE *fp) + : visited(cx), output(fp), nodes(cx) + {} +}; + +static void +DumpHeapVisitChild(JSTracer *trc, void *thing, JSGCTraceKind kind); + +static void +DumpHeapPushIfNew(JSTracer *trc, void *thing, JSGCTraceKind kind) +{ + JS_ASSERT(trc->callback == DumpHeapPushIfNew || + trc->callback == DumpHeapVisitChild); + JSDumpHeapTracer *dtrc = static_cast(trc); + + /* + * If we're tracing roots, print root information. Do this even if we've + * already seen thing, for complete root information. + */ + if (dtrc->rootTracing) { + fprintf(dtrc->output, "%p %s\n", thing, + JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer))); + } + + PtrSet::AddPtr ptrEntry = dtrc->visited.lookupForAdd(thing); + if (ptrEntry || !dtrc->visited.add(ptrEntry, thing)) + return; + + dtrc->nodes.append(DumpingChildInfo(thing, kind)); +} + +static void +DumpHeapVisitChild(JSTracer *trc, void *thing, JSGCTraceKind kind) +{ + JS_ASSERT(trc->callback == DumpHeapVisitChild); + JSDumpHeapTracer *dtrc = static_cast(trc); + const char *edgeName = JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer)); + fprintf(dtrc->output, "> %p %s\n", (void *)thing, edgeName); + DumpHeapPushIfNew(dtrc, thing, kind); +} + +void +js::DumpHeapComplete(JSContext *cx, FILE *fp) +{ + JSDumpHeapTracer dtrc(cx, fp); + JS_TRACER_INIT(&dtrc, cx, DumpHeapPushIfNew); + if (!dtrc.visited.init(10000)) + return; + + /* Store and log the root information. */ + dtrc.rootTracing = true; + TraceRuntime(&dtrc); + fprintf(dtrc.output, "==========\n"); + + /* Log the graph. */ + dtrc.rootTracing = false; + dtrc.callback = DumpHeapVisitChild; + + while (!dtrc.nodes.empty()) { + DumpingChildInfo dci = dtrc.nodes.popCopy(); + JS_PrintTraceThingInfo(dtrc.buffer, sizeof(dtrc.buffer), + &dtrc, dci.node, dci.kind, JS_TRUE); + fprintf(fp, "%p %s\n", dci.node, dtrc.buffer); + JS_TraceChildren(&dtrc, dci.node, dci.kind); + } + + dtrc.visited.finish(); +} + +#endif diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index db0b2d6c9a0b..608f1dbf05d3 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -151,6 +151,16 @@ JS_END_EXTERN_C namespace js { +#ifdef DEBUG + /* + * DEBUG-only method to dump the complete object graph of heap-allocated things. + * fp is the file for the dump output. + */ +extern JS_FRIEND_API(void) +DumpHeapComplete(JSContext *cx, FILE *fp); + +#endif + class JS_FRIEND_API(AutoPreserveCompartment) { private: JSContext *cx; @@ -346,6 +356,9 @@ CastAsJSStrictPropertyOp(JSObject *object) JS_FRIEND_API(bool) GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector *props); +JS_FRIEND_API(bool) +StringIsArrayIndex(JSLinearString *str, jsuint *indexp); + /* * NB: these flag bits are encoded into the bytecode stream in the immediate * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index c529f73f3f48..2063bd828331 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -192,8 +192,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee) { JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX); - JSObject *proto; - if (!js_GetClassPrototype(cx, callee.getGlobal(), JSProto_Object, &proto)) + JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx); + if (!proto) return NULL; TypeObject *type = proto->getNewType(cx); @@ -1455,10 +1455,10 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj) * the prototype's .constructor property is configurable, non-enumerable, * and writable. */ - if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT) || - !proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom, ObjectValue(*obj), JS_PropertyStub, JS_StrictPropertyStub, 0)) { return NULL; @@ -1562,6 +1562,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) uint32 flagsword; /* word for argument count and fun->flags */ cx = xdr->cx; + JSScript *script; if (xdr->mode == JSXDR_ENCODE) { fun = (*objp)->toFunction(); if (!fun->isInterpreted()) { @@ -1574,6 +1575,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } firstword = !!fun->atom; flagsword = (fun->nargs << 16) | fun->flags; + script = fun->script(); } else { fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); if (!fun) @@ -1582,6 +1584,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) return false; if (!fun->clearType(cx)) return false; + script = NULL; } AutoObjectRooter tvr(cx, fun); @@ -1593,27 +1596,19 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) if (!JS_XDRUint32(xdr, &flagsword)) return false; - if (xdr->mode == JSXDR_DECODE) { - fun->nargs = flagsword >> 16; - JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED); - fun->flags = uint16(flagsword); - } - - /* - * Don't directly store into fun->u.i.script because we want this to happen - * at the same time as we set the script's owner. - */ - JSScript *script = fun->script(); if (!js_XDRScript(xdr, &script)) return false; if (xdr->mode == JSXDR_DECODE) { - *objp = fun; + fun->nargs = flagsword >> 16; + JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED); + fun->flags = uint16(flagsword); fun->setScript(script); - if (!fun->script()->typeSetFunction(cx, fun)) + if (!script->typeSetFunction(cx, fun)) return false; JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs()); js_CallNewScriptHook(cx, fun->script(), fun); + *objp = fun; } return true; @@ -1690,8 +1685,6 @@ JSFunction::trace(JSTracer *trc) } } - - static void fun_trace(JSTracer *trc, JSObject *obj) { @@ -2203,8 +2196,8 @@ Function(JSContext *cx, uintN argc, Value *vp) /* * Allocate a string to hold the concatenated arguments, including room - * for a terminating 0. Mark cx->tempPool for later release, to free - * collected_args and its tokenstream in one swoop. + * for a terminating 0. Mark cx->tempLifeAlloc for later release, to + * free collected_args and its tokenstream in one swoop. */ LifoAllocScope las(&cx->tempLifoAlloc()); jschar *cp = cx->tempLifoAlloc().newArray(args_length + 1); @@ -2306,9 +2299,8 @@ Function(JSContext *cx, uintN argc, Value *vp) return false; JSPrincipals *principals = PrincipalsForCompiledCode(args, cx); - bool ok = Compiler::compileFunctionBody(cx, fun, principals, &bindings, - chars, length, filename, lineno, - cx->findVersion()); + bool ok = BytecodeCompiler::compileFunctionBody(cx, fun, principals, &bindings, chars, length, + filename, lineno, cx->findVersion()); args.rval().setObject(*fun); return ok; } @@ -2436,19 +2428,19 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JS_ASSERT(script); JS_ASSERT(script->compartment() == fun->compartment()); JS_ASSERT(script->compartment() != cx->compartment); - JS_OPT_ASSERT(script->ownerObject == fun); clone->u.i.script_ = NULL; JSScript *cscript = js_CloneScript(cx, script); if (!cscript) return NULL; + cscript->u.globalObject = clone->getGlobal(); clone->setScript(cscript); if (!clone->script()->typeSetFunction(cx, clone)) return NULL; js_CallNewScriptHook(cx, clone->script(), clone); - Debugger::onNewScript(cx, clone->script(), clone, NULL); + Debugger::onNewScript(cx, clone->script(), NULL); } } return clone; @@ -2544,7 +2536,7 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native, if (!fun) return NULL; - if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK)) + if (!obj->defineGeneric(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK)) return NULL; return fun; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 801e4c92d023..689f343dd221 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -179,10 +179,9 @@ struct JSFunction : public JSObject void setScript(JSScript *script) { JS_ASSERT(isInterpreted()); u.i.script_ = script; - script->setOwnerObject(this); } - JSScript * maybeScript() const { + JSScript *maybeScript() const { return isInterpreted() ? script() : NULL; } diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index 631eda9f8d23..d87b0950cc2f 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -43,6 +43,8 @@ #include "jsfun.h" #include "jsscript.h" +#include "vm/GlobalObject.h" + inline bool JSFunction::inStrictMode() const { @@ -336,8 +338,8 @@ CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, gc::AllocKind kind = JSFunction::FinalizeKind) { JS_ASSERT(parent); - JSObject *proto; - if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto)) + JSObject *proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx); + if (!proto) return NULL; return js_CloneFunctionObject(cx, fun, parent, proto, kind); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b255637df959..4cfe67ac0d7e 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -732,12 +732,8 @@ js_GCThingIsMarked(void *thing, uintN color = BLACK) return reinterpret_cast(thing)->isMarked(color); } -/* - * 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all - * JIT code is discarded in inactive compartments, regardless of how often that - * code runs. - */ -static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 60 * 1000 * 1000; +/* Lifetime for type sets attached to scripts containing observed types. */ +static const int64 JIT_SCRIPT_RELEASE_TYPES_INTERVAL = 60 * 1000 * 1000; JSBool js_InitGC(JSRuntime *rt, uint32 maxbytes) @@ -779,7 +775,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes) */ rt->setGCLastBytes(8192, GC_NORMAL); - rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME; + rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; return true; } @@ -2276,27 +2272,19 @@ GCHelperThread::doSweep() #endif /* JS_THREADSAFE */ -static uint32 -ComputeJitReleaseInterval(JSContext *cx) +static bool +ReleaseObservedTypes(JSContext *cx) { JSRuntime *rt = cx->runtime; - /* - * Figure out how much JIT code should be released from inactive compartments. - * If multiple eighth-lives have passed, compound the release interval linearly; - * if enough time has passed, all inactive JIT code will be released. - */ - uint32 releaseInterval = 0; + + bool releaseTypes = false; int64 now = PRMJ_Now(); if (now >= rt->gcJitReleaseTime) { - releaseInterval = 8; - while (now >= rt->gcJitReleaseTime) { - if (--releaseInterval == 1) - rt->gcJitReleaseTime = now; - rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME; - } + releaseTypes = true; + rt->gcJitReleaseTime = now + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; } - return releaseInterval; + return releaseTypes; } static void @@ -2435,9 +2423,9 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) if (!rt->gcCurrentCompartment) Debugger::sweepAll(cx); - uint32 releaseInterval = rt->gcCurrentCompartment ? 0 : ComputeJitReleaseInterval(cx); + bool releaseTypes = !rt->gcCurrentCompartment && ReleaseObservedTypes(cx); for (GCCompartmentsIter c(rt); !c.done(); c.next()) - c->sweep(cx, releaseInterval); + c->sweep(cx, releaseTypes); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_OBJECT); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 625496134b47..4aea5e78bba8 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -615,12 +615,22 @@ struct ChunkBitmap { JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap)); +const size_t ChunkPadSize = GC_CHUNK_SIZE + - (sizeof(Arena) * ArenasPerChunk) + - sizeof(ChunkBitmap) + - sizeof(ChunkInfo); +JS_STATIC_ASSERT(ChunkPadSize < BytesPerArena); + /* * Chunks contain arenas and associated data structures (mark bitmap, delayed * marking state). */ struct Chunk { Arena arenas[ArenasPerChunk]; + + /* Pad to full size to ensure cache alignment of ChunkInfo. */ + uint8 padding[ChunkPadSize]; + ChunkBitmap bitmap; ChunkInfo info; @@ -667,8 +677,7 @@ struct Chunk { inline void init(); }; -JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE); -JS_STATIC_ASSERT(sizeof(Chunk) + BytesPerArena > GC_CHUNK_SIZE); +JS_STATIC_ASSERT(sizeof(Chunk) == GC_CHUNK_SIZE); class ChunkPool { Chunk *emptyChunkListHead; diff --git a/js/src/jsgcmark.cpp b/js/src/jsgcmark.cpp index d52ed4e66227..4ac41e1fff88 100644 --- a/js/src/jsgcmark.cpp +++ b/js/src/jsgcmark.cpp @@ -98,9 +98,6 @@ PushMarkStack(GCMarker *gcmarker, JSScript *thing); static inline void PushMarkStack(GCMarker *gcmarker, const Shape *thing); -static inline void -PushMarkStack(GCMarker *gcmarker, JSShortString *thing); - static inline void PushMarkStack(GCMarker *gcmarker, JSString *thing); @@ -186,7 +183,7 @@ MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name) void MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer, - const void *arg, size_t index) + const void *arg, size_t index) { JS_ASSERT(trc); JS_ASSERT(&obj); @@ -292,15 +289,6 @@ PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing) gcmarker->pushType(thing); } -void -PushMarkStack(GCMarker *gcmarker, JSShortString *thing) -{ - JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment, - thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment); - - (void) thing->markIfUnmarked(gcmarker->getMarkColor()); -} - void PushMarkStack(GCMarker *gcmarker, JSScript *thing) { @@ -843,8 +831,8 @@ MarkChildren(JSTracer *trc, JSScript *script) if (script->function_) MarkObject(trc, *script->function_, "function"); - if (!script->isCachedEval && script->u.object) - MarkObject(trc, *script->u.object, "object"); + if (!script->isCachedEval && script->u.globalObject) + MarkObject(trc, *script->u.globalObject, "object"); if (IS_GC_MARKING_TRACER(trc) && script->filename) js_MarkScriptFilename(script->filename); @@ -853,13 +841,6 @@ MarkChildren(JSTracer *trc, JSScript *script) if (script->types) script->types->trace(trc); - -#ifdef JS_METHODJIT - if (script->jitNormal) - script->jitNormal->trace(trc); - if (script->jitCtor) - script->jitCtor->trace(trc); -#endif } void @@ -1017,19 +998,19 @@ JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind) { switch (kind) { case JSTRACE_OBJECT: - MarkChildren(trc, static_cast(thing)); + MarkChildren(trc, static_cast(thing)); break; case JSTRACE_STRING: - MarkChildren(trc, static_cast(thing)); + MarkChildren(trc, static_cast(thing)); break; case JSTRACE_SCRIPT: - MarkChildren(trc, static_cast(thing)); + MarkChildren(trc, static_cast(thing)); break; case JSTRACE_SHAPE: - MarkChildren(trc, static_cast(thing)); + MarkChildren(trc, static_cast(thing)); break; case JSTRACE_BASE_SHAPE: diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index c4e9fa6f06cc..858dae281679 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -347,7 +347,7 @@ types::TypeFailure(JSContext *cx, const char *fmt, ...) /* Always active, even in release builds */ JS_Assert(msgbuf, __FILE__, __LINE__); - *((int*)NULL) = 0; /* Should never be reached */ + *((volatile int *)NULL) = 0; /* Should never be reached */ } ///////////////////////////////////////////////////////////////////// @@ -1458,6 +1458,8 @@ GetValueTypeFromTypeFlags(TypeFlags flags) return JSVAL_TYPE_STRING; case TYPE_FLAG_LAZYARGS: return JSVAL_TYPE_MAGIC; + case TYPE_FLAG_ANYOBJECT: + return JSVAL_TYPE_OBJECT; default: return JSVAL_TYPE_UNKNOWN; } @@ -4944,7 +4946,7 @@ MarkIteratorUnknownSlow(JSContext *cx) void TypeMonitorCallSlow(JSContext *cx, JSObject *callee, - const CallArgs &args, bool constructing) + CallArgs &args, bool constructing) { unsigned nargs = callee->toFunction()->nargs; JSScript *script = callee->toFunction()->script(); @@ -4962,8 +4964,10 @@ TypeMonitorCallSlow(JSContext *cx, JSObject *callee, TypeScript::SetArgument(cx, script, arg, args[arg]); /* Watch for fewer actuals than formals to the call. */ - for (; arg < nargs; arg++) - TypeScript::SetArgument(cx, script, arg, UndefinedValue()); + for (; arg < nargs; arg++) { + Value v = UndefinedValue(); + TypeScript::SetArgument(cx, script, arg, v); + } } static inline bool @@ -5081,8 +5085,10 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type) } void -TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval) +TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::Value &rval) { + TryCoerceNumberToInt32(rval); + UntrapOpcode untrap(cx, script, pc); /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */ @@ -6149,21 +6155,6 @@ TypeScript::Sweep(JSContext *cx, JSScript *script) * cannot alias the most recent one, and future activations will overwrite * activeCall on creation. */ - - /* - * Method JIT code depends on the type inference data which is about to - * be purged, so purge the jitcode as well. - */ -#ifdef JS_METHODJIT - mjit::ReleaseScriptCode(cx, script); - - /* - * Use counts for scripts are reset on GC. After discarding code we need to - * let it warm back up to get information like which opcodes are setting - * array holes or accessing getter properties. - */ - script->resetUseCount(); -#endif } void diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 58deaa90df9e..a7ec56553558 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1075,9 +1075,14 @@ class TypeScript * by type inference or where the pc has type barriers. For simplicity, we * always monitor JOF_TYPESET opcodes in the interpreter and stub calls, * and only look at barriers when generating JIT code for the script. + * + * 'val' is passed by reference, and must refer to the location of the op's + * result which will be subsequently used (i.e. not a temporary value). + * This call may change val by coercing a double-representable-as-an-int + * into an integer. */ static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, - const js::Value &val); + js::Value &val); /* Monitor an assignment at a SETELEM on a non-integer identifier. */ static inline void MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc, @@ -1089,7 +1094,7 @@ class TypeScript static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type); static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value); static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type); - static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value); + static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, js::Value &value); static void Sweep(JSContext *cx, JSScript *script); inline void trace(JSTracer *trc); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index c8fcf2fd523b..0d2933d516a9 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -310,14 +310,15 @@ MarkIteratorUnknown(JSContext *cx) } /* - * Monitor a javascript call, either on entry to the interpreter or made - * from within the interpreter. + * Monitor a javascript call, either on entry to the interpreter or made from + * within the interpreter. As with TypeScript::Monitor, this may coerce double + * arguments to the call into integers. */ inline void -TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing) +TypeMonitorCall(JSContext *cx, js::CallArgs &args, bool constructing) { extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee, - const CallArgs &args, bool constructing); + CallArgs &args, bool constructing); JSObject *callee = &args.callee(); if (callee->isFunction()) { @@ -444,7 +445,7 @@ FixObjectType(JSContext *cx, JSObject *obj) } /* Interface helpers for JSScript */ -extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval); +extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::Value &rval); extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type); inline bool @@ -559,7 +560,7 @@ TypeScript::InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JS } /* static */ inline void -TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval) +TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, js::Value &rval) { if (cx->typeInferenceEnabled()) TypeMonitorResult(cx, script, pc, rval); @@ -677,9 +678,10 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type } /* static */ inline void -TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value) +TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, js::Value &value) { if (cx->typeInferenceEnabled()) { + TryCoerceNumberToInt32(value); Type type = GetValueType(cx, value); SetArgument(cx, script, arg, type); } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 6b40e0905802..96fcc24fbc19 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -839,7 +839,7 @@ js::CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs) if (obj2->isNative()) { oldAttrs = ((Shape *) prop)->attributes(); } else { - if (!obj2->getAttributes(cx, id, &oldAttrs)) + if (!obj2->getGenericAttributes(cx, id, &oldAttrs)) return false; } @@ -1778,30 +1778,12 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) goto error; \ JS_END_MACRO -#if defined(JS_TRACER) && defined(JS_METHODJIT) -# define LEAVE_ON_SAFE_POINT() \ - do { \ - JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \ - JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx)); \ - JS_ASSERT_IF(leaveOnSafePoint, interpMode != JSINTERP_NORMAL); \ - if (leaveOnSafePoint && !regs.fp()->hasImacropc() && \ - script->maybeNativeCodeForPC(regs.fp()->isConstructing(), regs.pc)) { \ - JS_ASSERT(!TRACE_RECORDER(cx)); \ - interpReturnOK = true; \ - goto leave_on_safe_point; \ - } \ - } while (0) -#else -# define LEAVE_ON_SAFE_POINT() /* nop */ -#endif - #define BRANCH(n) \ JS_BEGIN_MACRO \ regs.pc += (n); \ op = (JSOp) *regs.pc; \ if ((n) <= 0) \ goto check_backedge; \ - LEAVE_ON_SAFE_POINT(); \ DO_OP(); \ JS_END_MACRO @@ -1837,13 +1819,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) Value *argv = regs.fp()->maybeFormalArgs(); CHECK_INTERRUPT_HANDLER(); -#if defined(JS_TRACER) && defined(JS_METHODJIT) - bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT); -# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false)) -#else -# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0) -#endif - if (!entryFrame) entryFrame = regs.fp(); @@ -2026,17 +2001,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) LoopProfile *prof = TRACE_PROFILER(cx); JS_ASSERT(!TRACE_RECORDER(cx)); LoopProfile::ProfileAction act = prof->profileOperation(cx, op); - switch (act) { - case LoopProfile::ProfComplete: - if (interpMode != JSINTERP_NORMAL) { - leaveOnSafePoint = true; - LEAVE_ON_SAFE_POINT(); - } - break; - default: - moreInterrupts = true; - break; - } + if (act != LoopProfile::ProfComplete) + moreInterrupts = true; } #endif if (TraceRecorder* tr = TRACE_RECORDER(cx)) { @@ -2044,23 +2010,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) AbortableRecordingStatus status = tr->monitorRecording(op); JS_ASSERT_IF(cx->isExceptionPending(), status == ARECORD_ERROR); - if (interpMode != JSINTERP_NORMAL) { - JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT); - switch (status) { - case ARECORD_IMACRO_ABORTED: - case ARECORD_ABORTED: - case ARECORD_COMPLETED: - case ARECORD_STOP: -#ifdef JS_METHODJIT - leaveOnSafePoint = true; - LEAVE_ON_SAFE_POINT(); -#endif - break; - default: - break; - } - } - switch (status) { case ARECORD_CONTINUE: moreInterrupts = true; @@ -2069,7 +2018,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) case ARECORD_IMACRO_ABORTED: atoms = rt->atomState.commonAtomsStart(); op = JSOp(*regs.pc); - CLEAR_LEAVE_ON_TRACE_POINT(); if (status == ARECORD_IMACRO) DO_OP(); /* keep interrupting for op. */ break; @@ -2114,7 +2062,7 @@ END_EMPTY_CASES BEGIN_CASE(JSOP_TRACE) BEGIN_CASE(JSOP_NOTRACE) - LEAVE_ON_SAFE_POINT(); + /* No-op */ END_CASE(JSOP_TRACE) check_backedge: @@ -2131,7 +2079,6 @@ check_backedge: JS_ASSERT(!TRACE_PROFILER(cx)); MONITOR_BRANCH_TRACEVIS; ENABLE_INTERRUPTS(); - CLEAR_LEAVE_ON_TRACE_POINT(); } JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR); RESTORE_INTERP_VARS_CHECK_EXCEPTION(); @@ -2256,7 +2203,6 @@ BEGIN_CASE(JSOP_STOP) if (js_CodeSpec[*imacpc].format & JOF_DECOMPOSE) regs.pc += GetDecomposeLength(imacpc, js_CodeSpec[*imacpc].length); regs.fp()->clearImacropc(); - LEAVE_ON_SAFE_POINT(); atoms = script->atoms; op = JSOp(*regs.pc); DO_OP(); @@ -2637,7 +2583,7 @@ BEGIN_CASE(JSOP_SETCONST) LOAD_ATOM(0, atom); JSObject &obj = regs.fp()->varObj(); const Value &ref = regs.sp[-1]; - if (!obj.defineProperty(cx, ATOM_TO_JSID(atom), ref, + if (!obj.defineProperty(cx, atom->asPropertyName(), ref, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { goto error; @@ -2653,9 +2599,9 @@ BEGIN_CASE(JSOP_ENUMCONSTELEM) FETCH_OBJECT(cx, -2, obj); jsid id; FETCH_ELEMENT_ID(obj, -1, id); - if (!obj->defineProperty(cx, id, ref, - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + if (!obj->defineGeneric(cx, id, ref, + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { goto error; } regs.sp -= 3; @@ -3113,7 +3059,7 @@ BEGIN_CASE(JSOP_DELNAME) /* ECMA says to return true if name is undefined or inherited. */ PUSH_BOOLEAN(true); if (prop) { - if (!obj->deleteProperty(cx, id, ®s.sp[-1], false)) + if (!obj->deleteProperty(cx, atom->asPropertyName(), ®s.sp[-1], false)) goto error; } } @@ -3129,7 +3075,7 @@ BEGIN_CASE(JSOP_DELPROP) FETCH_OBJECT(cx, -1, obj); Value rval; - if (!obj->deleteProperty(cx, id, &rval, script->strictModeCode)) + if (!obj->deleteGeneric(cx, id, &rval, script->strictModeCode)) goto error; regs.sp[-1] = rval; @@ -3147,7 +3093,7 @@ BEGIN_CASE(JSOP_DELELEM) FETCH_ELEMENT_ID(obj, -1, id); /* Get or set the element. */ - if (!obj->deleteProperty(cx, id, ®s.sp[-2], script->strictModeCode)) + if (!obj->deleteGeneric(cx, id, ®s.sp[-2], script->strictModeCode)) goto error; regs.sp--; @@ -3350,10 +3296,10 @@ BEGIN_CASE(JSOP_LENGTH) } } while (0); - TypeScript::Monitor(cx, script, regs.pc, rval); - regs.sp[-1] = rval; assertSameCompartment(cx, regs.sp[-1]); + + TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]); } END_CASE(JSOP_GETPROP) @@ -3365,20 +3311,20 @@ BEGIN_CASE(JSOP_CALLPROP) if (lval.isObject()) { objv = lval; } else { - JSProtoKey protoKey; + GlobalObject *global = regs.fp()->scopeChain().getGlobal(); + JSObject *pobj; if (lval.isString()) { - protoKey = JSProto_String; + pobj = global->getOrCreateStringPrototype(cx); } else if (lval.isNumber()) { - protoKey = JSProto_Number; + pobj = global->getOrCreateNumberPrototype(cx); } else if (lval.isBoolean()) { - protoKey = JSProto_Boolean; + pobj = global->getOrCreateBooleanPrototype(cx); } else { JS_ASSERT(lval.isNull() || lval.isUndefined()); js_ReportIsNullOrUndefined(cx, -1, lval, NULL); goto error; } - JSObject *pobj; - if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + if (!pobj) goto error; objv.setObject(*pobj); } @@ -3436,7 +3382,7 @@ BEGIN_CASE(JSOP_CALLPROP) goto error; } #endif - TypeScript::Monitor(cx, script, regs.pc, rval); + TypeScript::Monitor(cx, script, regs.pc, regs.sp[-2]); } END_CASE(JSOP_CALLPROP) @@ -3529,7 +3475,7 @@ BEGIN_CASE(JSOP_SETMETHOD) if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode)) goto error; } else { - if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + if (!obj->setGeneric(cx, id, &rval, script->strictModeCode)) goto error; ABORT_RECORDING(cx, "Non-native set"); } @@ -3678,7 +3624,7 @@ BEGIN_CASE(JSOP_SETELEM) } } while (0); rval = regs.sp[-1]; - if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + if (!obj->setGeneric(cx, id, &rval, script->strictModeCode)) goto error; end_setelem:; } @@ -3692,7 +3638,7 @@ BEGIN_CASE(JSOP_ENUMELEM) jsid id; FETCH_ELEMENT_ID(obj, -1, id); Value rval = regs.sp[-3]; - if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + if (!obj->setGeneric(cx, id, &rval, script->strictModeCode)) goto error; regs.sp -= 3; } @@ -3866,7 +3812,7 @@ BEGIN_CASE(JSOP_CALLNAME) } PUSH_COPY(rval); - TypeScript::Monitor(cx, script, regs.pc, rval); + TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]); /* obj must be on the scope chain, thus not a function. */ if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME) @@ -3938,17 +3884,12 @@ BEGIN_CASE(JSOP_REGEXP) { /* * Push a regexp object cloned from the regexp literal object mapped by the - * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was - * flouted by many browser-based implementations. - * - * We avoid the GetScopeChain call here and pass fp->scopeChain as - * js_GetClassPrototype uses the latter only to locate the global. + * bytecode at pc. */ jsatomid index = GET_FULL_INDEX(0); - JSObject *proto; - if (!js_GetClassPrototype(cx, ®s.fp()->scopeChain(), JSProto_RegExp, &proto)) + JSObject *proto = regs.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(cx); + if (!proto) goto error; - JS_ASSERT(proto); JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto); if (!obj) goto error; @@ -4390,8 +4331,11 @@ BEGIN_CASE(JSOP_DEFFUN) do { /* Steps 5d, 5f. */ if (!prop || pobj != parent) { - if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) + if (!parent->defineProperty(cx, name, rval, + JS_PropertyStub, JS_StrictPropertyStub, attrs)) + { goto error; + } break; } @@ -4400,8 +4344,11 @@ BEGIN_CASE(JSOP_DEFFUN) Shape *shape = reinterpret_cast(prop); if (parent->isGlobal()) { if (shape->configurable()) { - if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) + if (!parent->defineProperty(cx, name, rval, + JS_PropertyStub, JS_StrictPropertyStub, attrs)) + { goto error; + } break; } @@ -4423,7 +4370,7 @@ BEGIN_CASE(JSOP_DEFFUN) */ /* Step 5f. */ - if (!parent->setProperty(cx, id, &rval, script->strictModeCode)) + if (!parent->setProperty(cx, name, &rval, script->strictModeCode)) goto error; } while (false); } @@ -4450,9 +4397,11 @@ BEGIN_CASE(JSOP_DEFFUN_FC) if (!CheckRedeclaration(cx, &parent, id, attrs)) goto error; + PropertyName *name = fun->atom->asPropertyName(); if ((attrs == JSPROP_ENUMERATE) - ? !parent.setProperty(cx, id, &rval, script->strictModeCode) - : !parent.defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) { + ? !parent.setProperty(cx, name, &rval, script->strictModeCode) + : !parent.defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) + { goto error; } } @@ -4740,7 +4689,7 @@ BEGIN_CASE(JSOP_SETTER) if (!CheckRedeclaration(cx, obj, id, attrs)) goto error; - if (!obj->defineProperty(cx, id, UndefinedValue(), getter, setter, attrs)) + if (!obj->defineGeneric(cx, id, UndefinedValue(), getter, setter, attrs)) goto error; regs.sp += i; @@ -4904,7 +4853,7 @@ BEGIN_CASE(JSOP_INITELEM) goto error; } } else { - if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) goto error; } regs.sp -= 2; @@ -4938,7 +4887,7 @@ BEGIN_CASE(JSOP_DEFSHARP) JSMSG_BAD_SHARP_DEF, numBuf); goto error; } - if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) goto error; } END_CASE(JSOP_DEFSHARP) @@ -5041,12 +4990,6 @@ END_VARLEN_CASE BEGIN_CASE(JSOP_EXCEPTION) PUSH_COPY(cx->getPendingException()); cx->clearPendingException(); -#if defined(JS_TRACER) && defined(JS_METHODJIT) - if (interpMode == JSINTERP_PROFILE) { - leaveOnSafePoint = true; - LEAVE_ON_SAFE_POINT(); - } -#endif CHECK_BRANCH(); END_CASE(JSOP_EXCEPTION) @@ -5161,6 +5104,8 @@ END_CASE(JSOP_DEBUGGER) #if JS_HAS_XML_SUPPORT BEGIN_CASE(JSOP_DEFXMLNS) { + JS_ASSERT(!script->strictModeCode); + if (!js_SetDefaultXMLNamespace(cx, regs.sp[-1])) goto error; regs.sp--; @@ -5169,6 +5114,8 @@ END_CASE(JSOP_DEFXMLNS) BEGIN_CASE(JSOP_ANYNAME) { + JS_ASSERT(!script->strictModeCode); + jsid id; if (!js_GetAnyName(cx, &id)) goto error; @@ -5178,6 +5125,12 @@ END_CASE(JSOP_ANYNAME) BEGIN_CASE(JSOP_QNAMEPART) { + /* + * We do not JS_ASSERT(!script->strictModeCode) here because JSOP_QNAMEPART + * is used for __proto__ and (in contexts where we favor JSOP_*ELEM instead + * of JSOP_*PROP) obj.prop compiled as obj['prop']. + */ + JSAtom *atom; LOAD_ATOM(0, atom); PUSH_STRING(atom); @@ -5186,6 +5139,8 @@ END_CASE(JSOP_QNAMEPART) BEGIN_CASE(JSOP_QNAMECONST) { + JS_ASSERT(!script->strictModeCode); + JSAtom *atom; LOAD_ATOM(0, atom); Value rval = StringValue(atom); @@ -5199,6 +5154,8 @@ END_CASE(JSOP_QNAMECONST) BEGIN_CASE(JSOP_QNAME) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; Value lval = regs.sp[-2]; JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); @@ -5211,6 +5168,8 @@ END_CASE(JSOP_QNAME) BEGIN_CASE(JSOP_TOATTRNAME) { + JS_ASSERT(!script->strictModeCode); + Value rval; rval = regs.sp[-1]; if (!js_ToAttributeName(cx, &rval)) @@ -5221,6 +5180,8 @@ END_CASE(JSOP_TOATTRNAME) BEGIN_CASE(JSOP_TOATTRVAL) { + JS_ASSERT(!script->strictModeCode); + Value rval; rval = regs.sp[-1]; JS_ASSERT(rval.isString()); @@ -5234,6 +5195,8 @@ END_CASE(JSOP_TOATTRVAL) BEGIN_CASE(JSOP_ADDATTRNAME) BEGIN_CASE(JSOP_ADDATTRVAL) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; Value lval = regs.sp[-2]; JSString *str = lval.toString(); @@ -5248,6 +5211,8 @@ END_CASE(JSOP_ADDATTRNAME) BEGIN_CASE(JSOP_BINDXMLNAME) { + JS_ASSERT(!script->strictModeCode); + Value lval; lval = regs.sp[-1]; JSObject *obj; @@ -5261,11 +5226,13 @@ END_CASE(JSOP_BINDXMLNAME) BEGIN_CASE(JSOP_SETXMLNAME) { + JS_ASSERT(!script->strictModeCode); + JSObject *obj = ®s.sp[-3].toObject(); Value rval = regs.sp[-1]; jsid id; FETCH_ELEMENT_ID(obj, -2, id); - if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + if (!obj->setGeneric(cx, id, &rval, script->strictModeCode)) goto error; rval = regs.sp[-1]; regs.sp -= 2; @@ -5276,6 +5243,8 @@ END_CASE(JSOP_SETXMLNAME) BEGIN_CASE(JSOP_CALLXMLNAME) BEGIN_CASE(JSOP_XMLNAME) { + JS_ASSERT(!script->strictModeCode); + Value lval = regs.sp[-1]; JSObject *obj; jsid id; @@ -5293,6 +5262,8 @@ END_CASE(JSOP_XMLNAME) BEGIN_CASE(JSOP_DESCENDANTS) BEGIN_CASE(JSOP_DELDESC) { + JS_ASSERT(!script->strictModeCode); + JSObject *obj; FETCH_OBJECT(cx, -2, obj); jsval rval = regs.sp[-1]; @@ -5311,8 +5282,10 @@ BEGIN_CASE(JSOP_DELDESC) } END_CASE(JSOP_DESCENDANTS) -{ BEGIN_CASE(JSOP_FILTER) +{ + JS_ASSERT(!script->strictModeCode); + /* * We push the hole value before jumping to [enditer] so we can detect the * first iteration and direct js_StepXMLListFilter to initialize filter's @@ -5321,11 +5294,13 @@ BEGIN_CASE(JSOP_FILTER) PUSH_HOLE(); len = GET_JUMP_OFFSET(regs.pc); JS_ASSERT(len > 0); -END_VARLEN_CASE } +END_VARLEN_CASE BEGIN_CASE(JSOP_ENDFILTER) { + JS_ASSERT(!script->strictModeCode); + bool cond = !regs.sp[-1].isMagic(); if (cond) { /* Exit the "with" block left from the previous iteration. */ @@ -5352,6 +5327,8 @@ END_CASE(JSOP_ENDFILTER); BEGIN_CASE(JSOP_TOXML) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; JSObject *obj = js_ValueToXMLObject(cx, rval); if (!obj) @@ -5362,6 +5339,8 @@ END_CASE(JSOP_TOXML) BEGIN_CASE(JSOP_TOXMLLIST) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; JSObject *obj = js_ValueToXMLListObject(cx, rval); if (!obj) @@ -5372,6 +5351,8 @@ END_CASE(JSOP_TOXMLLIST) BEGIN_CASE(JSOP_XMLTAGEXPR) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; JSString *str = js_ValueToString(cx, rval); if (!str) @@ -5382,6 +5363,8 @@ END_CASE(JSOP_XMLTAGEXPR) BEGIN_CASE(JSOP_XMLELTEXPR) { + JS_ASSERT(!script->strictModeCode); + Value rval = regs.sp[-1]; JSString *str; if (IsXML(rval)) { @@ -5399,6 +5382,8 @@ END_CASE(JSOP_XMLELTEXPR) BEGIN_CASE(JSOP_XMLCDATA) { + JS_ASSERT(!script->strictModeCode); + JSAtom *atom; LOAD_ATOM(0, atom); JSString *str = atom; @@ -5411,6 +5396,8 @@ END_CASE(JSOP_XMLCDATA) BEGIN_CASE(JSOP_XMLCOMMENT) { + JS_ASSERT(!script->strictModeCode); + JSAtom *atom; LOAD_ATOM(0, atom); JSString *str = atom; @@ -5423,6 +5410,8 @@ END_CASE(JSOP_XMLCOMMENT) BEGIN_CASE(JSOP_XMLPI) { + JS_ASSERT(!script->strictModeCode); + JSAtom *atom; LOAD_ATOM(0, atom); JSString *str = atom; @@ -5437,6 +5426,8 @@ END_CASE(JSOP_XMLPI) BEGIN_CASE(JSOP_GETFUNNS) { + JS_ASSERT(!script->strictModeCode); + Value rval; if (!cx->fp()->scopeChain().getGlobal()->getFunctionNamespace(cx, &rval)) goto error; diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 5767b1cd9c08..0ba6462afa54 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -215,10 +215,9 @@ enum InterpMode { JSINTERP_NORMAL = 0, /* interpreter is running normally */ JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */ - JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */ - JSINTERP_PROFILE = 3, /* interpreter should profile a loop */ - JSINTERP_REJOIN = 4, /* as normal, but the frame has already started */ - JSINTERP_SKIP_TRAP = 5 /* as REJOIN, but skip trap at first opcode */ + JSINTERP_PROFILE = 2, /* interpreter should profile a loop */ + JSINTERP_REJOIN = 3, /* as normal, but the frame has already started */ + JSINTERP_SKIP_TRAP = 4 /* as REJOIN, but skip trap at first opcode */ }; /* diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 777b8e6c77fb..02ef26f502da 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -880,7 +880,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat uintN attrs; if (obj2.object()->isNative()) attrs = ((Shape *) prop)->attributes(); - else if (!obj2.object()->getAttributes(cx, *idp, &attrs)) + else if (!obj2.object()->getGenericAttributes(cx, *idp, &attrs)) return false; if (attrs & JSPROP_ENUMERATE) diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 57cb6bae807c..c0f764cf59fe 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -658,6 +658,17 @@ ToInteger(JSContext *cx, const js::Value &v, jsdouble *dp) return true; } +/* If v is a double value which fits in an int32, coerce it to that int32. */ +static inline void +TryCoerceNumberToInt32(Value &v) +{ + if (v.isDouble()) { + int32_t res; + if (JSDOUBLE_IS_INT32(v.toDouble(), &res)) + v.setInt32(res); + } +} + } /* namespace js */ #endif /* jsnum_h___ */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ff56837aa459..cd4df713b328 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -91,6 +91,7 @@ #include "jsscriptinlines.h" #include "jsobjinlines.h" +#include "vm/BooleanObject-inl.h" #include "vm/NumberObject-inl.h" #include "vm/StringObject-inl.h" @@ -638,7 +639,7 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp) * If id is a string that's not an identifier, or if it's a negative * integer, then it must be quoted. */ - bool idIsLexicalIdentifier = js_IsIdentifier(idstr); + bool idIsLexicalIdentifier = IsIdentifier(idstr); if (JSID_IS_ATOM(id) ? !idIsLexicalIdentifier : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) { @@ -1025,14 +1026,14 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st script->principals->subsume(script->principals, principals)))) { /* * Get the prior (cache-filling) eval's saved caller function. - * See Compiler::compileScript in jsparse.cpp. + * See BytecodeCompiler::compileScript. */ JSFunction *fun = script->getCallerFunction(); if (fun == caller->fun()) { /* - * Get the source string passed for safekeeping in the - * atom map by the prior eval to Compiler::compileScript. + * Get the source string passed for safekeeping in the atom map + * by the prior eval to BytecodeCompiler::compileScript. */ JSAtom *src = script->atoms[0]; @@ -1112,7 +1113,6 @@ class EvalScriptGuard void setNewScript(JSScript *script) { /* NewScriptFromCG has already called js_CallNewScriptHook. */ JS_ASSERT(!script_ && script); - script->setOwnerObject(JS_CACHED_SCRIPT); script_ = script; script_->isActiveEval = true; } @@ -1260,9 +1260,10 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c ? CALLED_FROM_JSOP_EVAL : NOT_CALLED_FROM_JSOP_EVAL); uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL; - JSScript *compiled = Compiler::compileScript(cx, &scopeobj, caller, principals, tcflags, - chars, length, filename, lineno, - cx->findVersion(), linearStr, staticLevel); + JSScript *compiled = BytecodeCompiler::compileScript(cx, &scopeobj, caller, principals, + tcflags, chars, length, filename, + lineno, cx->findVersion(), linearStr, + staticLevel); if (!compiled) return false; @@ -1582,7 +1583,7 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, Value *vp) } uintN attrs; - if (!pobj->getAttributes(cx, id, &attrs)) + if (!pobj->getGenericAttributes(cx, id, &attrs)) return false; vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0); @@ -1626,8 +1627,8 @@ js::obj_defineGetter(JSContext *cx, uintN argc, Value *vp) if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; args.rval().setUndefined(); - return obj->defineProperty(cx, id, UndefinedValue(), getter, JS_StrictPropertyStub, - JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED); + return obj->defineGeneric(cx, id, UndefinedValue(), getter, JS_StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED); } JS_FRIEND_API(JSBool) @@ -1660,8 +1661,8 @@ js::obj_defineSetter(JSContext *cx, uintN argc, Value *vp) if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; args.rval().setUndefined(); - return obj->defineProperty(cx, id, UndefinedValue(), JS_PropertyStub, setter, - JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED); + return obj->defineGeneric(cx, id, UndefinedValue(), JS_PropertyStub, setter, + JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED); } static JSBool @@ -1795,26 +1796,20 @@ PropDesc::makeObject(JSContext *cx) const JSAtomState &atomState = cx->runtime->atomState; if ((hasConfigurable && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom), - BooleanValue((attrs & JSPROP_PERMANENT) == 0), - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) || + !obj->defineProperty(cx, atomState.configurableAtom, + BooleanValue((attrs & JSPROP_PERMANENT) == 0))) || (hasEnumerable && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom), - BooleanValue((attrs & JSPROP_ENUMERATE) != 0), - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) || + !obj->defineProperty(cx, atomState.enumerableAtom, + BooleanValue((attrs & JSPROP_ENUMERATE) != 0))) || (hasGet && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), get, - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) || + !obj->defineProperty(cx, atomState.getAtom, get)) || (hasSet && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), set, - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) || + !obj->defineProperty(cx, atomState.setAtom, set)) || (hasValue && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), value, - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) || + !obj->defineProperty(cx, atomState.valueAtom, value)) || (hasWritable && - !obj->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom), - BooleanValue((attrs & JSPROP_READONLY) == 0), - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE))) + !obj->defineProperty(cx, atomState.writableAtom, + BooleanValue((attrs & JSPROP_READONLY) == 0)))) { return false; } @@ -1850,7 +1845,7 @@ GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescript desc->setter = CastAsStrictPropertyOp(shape->setterObject()); } } else { - if (!pobj->getAttributes(cx, id, &desc->attrs)) + if (!pobj->getGenericAttributes(cx, id, &desc->attrs)) return false; } @@ -2728,7 +2723,7 @@ JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) jsid id = props[i]; uintN attrs; - if (!getAttributes(cx, id, &attrs)) + if (!getGenericAttributes(cx, id, &attrs)) return false; /* Make all attributes permanent; if freezing, make data attributes read-only. */ @@ -2743,7 +2738,7 @@ JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) continue; attrs |= new_attrs; - if (!setAttributes(cx, id, &attrs)) + if (!setGenericAttributes(cx, id, &attrs)) return false; } @@ -2766,7 +2761,7 @@ JSObject::isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp) jsid id = props[i]; uintN attrs; - if (!getAttributes(cx, id, &attrs)) + if (!getGenericAttributes(cx, id, &attrs)) return false; /* @@ -3110,7 +3105,8 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot) * GetInterpretedFunctionPrototype found that ctor.prototype is * primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7. */ - if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) + proto = parent->getGlobal()->getOrCreateObjectPrototype(cx); + if (!proto) return NULL; } @@ -3295,87 +3291,99 @@ with_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, } static JSBool -with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +with_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { - return obj->getProto()->setProperty(cx, id, vp, strict); + return obj->getProto()->setGeneric(cx, id, vp, strict); +} + +static JSBool +with_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) +{ + return obj->getProto()->setProperty(cx, name, vp, strict); } static JSBool with_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict) { - jsid id; - if (!IndexToId(cx, index, &id)) - return false; - return with_SetProperty(cx, obj, id, vp, strict); + return obj->getProto()->setElement(cx, index, vp, strict); } static JSBool with_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict) { - return with_SetProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); + return obj->getProto()->setSpecial(cx, sid, vp, strict); } static JSBool -with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +with_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { - return obj->getProto()->getAttributes(cx, id, attrsp); + return obj->getProto()->getGenericAttributes(cx, id, attrsp); +} + +static JSBool +with_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return obj->getProto()->getPropertyAttributes(cx, name, attrsp); } static JSBool with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { - jsid id; - if (!IndexToId(cx, index, &id)) - return false; - return with_GetAttributes(cx, obj, id, attrsp); + return obj->getProto()->getElementAttributes(cx, index, attrsp); } static JSBool with_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return with_GetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return obj->getProto()->getSpecialAttributes(cx, sid, attrsp); } static JSBool -with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +with_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { - return obj->getProto()->setAttributes(cx, id, attrsp); + return obj->getProto()->setGenericAttributes(cx, id, attrsp); +} + +static JSBool +with_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return obj->getProto()->setPropertyAttributes(cx, name, attrsp); } static JSBool with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { - jsid id; - if (!IndexToId(cx, index, &id)) - return false; - return with_SetAttributes(cx, obj, id, attrsp); + return obj->getProto()->setElementAttributes(cx, index, attrsp); } static JSBool with_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return with_SetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return obj->getProto()->setSpecialAttributes(cx, sid, attrsp); } static JSBool -with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +with_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { - return obj->getProto()->deleteProperty(cx, id, rval, strict); + return obj->getProto()->deleteGeneric(cx, id, rval, strict); +} + +static JSBool +with_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) +{ + return obj->getProto()->deleteProperty(cx, name, rval, strict); } static JSBool with_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) { - jsid id; - if (!IndexToId(cx, index, &id)) - return false; - return with_DeleteProperty(cx, obj, id, rval, strict); + return obj->getProto()->deleteElement(cx, index, rval, strict); } static JSBool with_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return with_DeleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return obj->getProto()->deleteSpecial(cx, sid, rval, strict); } static JSBool @@ -3429,19 +3437,19 @@ Class js::WithClass = { with_GetProperty, with_GetElement, with_GetSpecial, - with_SetProperty, + with_SetGeneric, with_SetProperty, with_SetElement, with_SetSpecial, - with_GetAttributes, - with_GetAttributes, + with_GetGenericAttributes, + with_GetPropertyAttributes, with_GetElementAttributes, with_GetSpecialAttributes, - with_SetAttributes, - with_SetAttributes, + with_SetGenericAttributes, + with_SetPropertyAttributes, with_SetElementAttributes, with_SetSpecialAttributes, - with_DeleteProperty, + with_DeleteGeneric, with_DeleteProperty, with_DeleteElement, with_DeleteSpecial, @@ -3565,7 +3573,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind) JS_ASSERT(depth <= size_t(cx->regs().sp - fp->base())); JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth)); - /* See comments in CheckDestructuring from jsparse.cpp. */ + /* See comments in CheckDestructuring in frontend/Parser.cpp. */ JS_ASSERT(count >= 1); if (normalUnwind) { @@ -3658,7 +3666,7 @@ JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool str if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp)) return false; } - return getOps()->setProperty(cx, this, id, vp, strict); + return getOps()->setGeneric(cx, this, id, vp, strict); } JSBool @@ -3703,7 +3711,7 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj) Value v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue(); if (!cx->compartment->wrap(cx, &v)) return false; - if (!target->defineProperty(cx, shape->propid(), v, getter, setter, attrs)) + if (!target->defineGeneric(cx, shape->propid(), v, getter, setter, attrs)) return false; } return true; @@ -4209,7 +4217,7 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, } } - named = obj->defineProperty(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs); + named = obj->defineGeneric(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs); return named; } @@ -4386,7 +4394,7 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt bad: if (named) { Value rval; - obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, false); + obj->deleteGeneric(cx, ATOM_TO_JSID(atom), &rval, false); } if (cached) ClearClassObject(cx, obj, key); @@ -6414,7 +6422,7 @@ js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return true; } if (!obj->isNative()) - return obj->getAttributes(cx, id, attrsp); + return obj->getGenericAttributes(cx, id, attrsp); const Shape *shape = (Shape *)prop; *attrsp = shape->attributes(); @@ -6457,7 +6465,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return true; return obj->isNative() ? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp) - : obj->setAttributes(cx, id, attrsp); + : obj->setGenericAttributes(cx, id, attrsp); } JSBool @@ -6813,25 +6821,21 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey, JS_ASSERT(protoKey < JSProto_LIMIT); if (protoKey != JSProto_Null) { - if (!scopeobj) { - if (cx->hasfp()) - scopeobj = &cx->fp()->scopeChain(); - if (!scopeobj) { - scopeobj = cx->globalObject; - if (!scopeobj) { - *protop = NULL; - return true; - } - } - } - scopeobj = scopeobj->getGlobal(); - if (scopeobj->isGlobal()) { - const Value &v = scopeobj->getReservedSlot(JSProto_LIMIT + protoKey); - if (v.isObject()) { - *protop = &v.toObject(); + GlobalObject *global; + if (scopeobj) { + global = scopeobj->getGlobal(); + } else { + global = GetCurrentGlobal(cx); + if (!global) { + *protop = NULL; return true; } } + const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey); + if (v.isObject()) { + *protop = &v.toObject(); + return true; + } } return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp); @@ -6846,12 +6850,7 @@ PrimitiveToObject(JSContext *cx, const Value &v) return NumberObject::create(cx, v.toNumber()); JS_ASSERT(v.isBoolean()); - JSObject *obj = NewBuiltinClassInstance(cx, &BooleanClass); - if (!obj) - return NULL; - - obj->setPrimitiveThis(v); - return obj; + return BooleanObject::create(cx, v.toBoolean()); } JSBool diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 783513718232..d086a891a8b9 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -343,6 +343,7 @@ extern Class WithClass; extern Class XMLFilterClass; class ArgumentsObject; +class BooleanObject; class GlobalObject; class NormalArgumentsObject; class NumberObject; @@ -913,6 +914,7 @@ struct JSObject : js::gc::Cell } public: + inline js::BooleanObject *asBoolean(); inline js::NumberObject *asNumber(); inline js::StringObject *asString(); inline js::RegExpObject *asRegExp(); @@ -1059,12 +1061,6 @@ struct JSObject : js::gc::Cell inline js::NativeIterator *getNativeIterator() const; inline void setNativeIterator(js::NativeIterator *); - /* - * Script-related getters. - */ - - inline JSScript *getScript() const; - /* * XML-related getters and setters. */ @@ -1233,7 +1229,11 @@ struct JSObject : js::gc::Cell inline JSBool lookupElement(JSContext *cx, uint32 index, JSObject **objp, JSProperty **propp); inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSProperty **propp); - inline JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value, + inline JSBool defineGeneric(JSContext *cx, jsid id, const js::Value &value, + JSPropertyOp getter = JS_PropertyStub, + JSStrictPropertyOp setter = JS_StrictPropertyStub, + uintN attrs = JSPROP_ENUMERATE); + inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value, JSPropertyOp getter = JS_PropertyStub, JSStrictPropertyOp setter = JS_StrictPropertyStub, uintN attrs = JSPROP_ENUMERATE); @@ -1242,6 +1242,10 @@ struct JSObject : js::gc::Cell JSPropertyOp getter = JS_PropertyStub, JSStrictPropertyOp setter = JS_StrictPropertyStub, uintN attrs = JSPROP_ENUMERATE); + inline JSBool defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value, + JSPropertyOp getter = JS_PropertyStub, + JSStrictPropertyOp setter = JS_StrictPropertyStub, + uintN attrs = JSPROP_ENUMERATE); inline JSBool getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp); inline JSBool getProperty(JSContext *cx, JSObject *receiver, js::PropertyName *name, @@ -1254,24 +1258,32 @@ struct JSObject : js::gc::Cell inline JSBool getElement(JSContext *cx, uint32 index, js::Value *vp); inline JSBool getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp); - inline JSBool setProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict); + inline JSBool setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict); + inline JSBool setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict); inline JSBool setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict); + inline JSBool setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict); JSBool nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict); JSBool nonNativeSetElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict); - inline JSBool getAttributes(JSContext *cx, jsid id, uintN *attrsp); + inline JSBool getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp); + inline JSBool getPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp); inline JSBool getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp); + inline JSBool getSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp); - inline JSBool setAttributes(JSContext *cx, jsid id, uintN *attrsp); + inline JSBool setGenericAttributes(JSContext *cx, jsid id, uintN *attrsp); + inline JSBool setPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp); inline JSBool setElementAttributes(JSContext *cx, uint32 index, uintN *attrsp); + inline JSBool setSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp); - inline JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict); + inline JSBool deleteGeneric(JSContext *cx, jsid id, js::Value *rval, JSBool strict); + inline JSBool deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, JSBool strict); inline JSBool deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict); + inline JSBool deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, JSBool strict); + inline bool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp); inline bool defaultValue(JSContext *cx, JSType hint, js::Value *vp); inline JSType typeOf(JSContext *cx); - inline JSObject *thisObject(JSContext *cx); static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 52e991d764c0..970d050bb74f 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -72,19 +72,6 @@ #include "jsgcinlines.h" #include "jsscopeinlines.h" -inline bool -JSObject::isGlobal() const -{ - return !!(getClass()->flags & JSCLASS_IS_GLOBAL); -} - -js::GlobalObject * -JSObject::asGlobal() -{ - JS_ASSERT(isGlobal()); - return reinterpret_cast(this); -} - inline bool JSObject::hasPrivate() const { @@ -148,29 +135,19 @@ JSObject::thisObject(JSContext *cx) } inline JSBool -JSObject::defineProperty(JSContext *cx, jsid id, const js::Value &value, - JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +JSObject::setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict) { - js::DefinePropOp op = getOps()->defineProperty; - return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs); -} - -inline JSBool -JSObject::defineElement(JSContext *cx, uint32 index, const js::Value &value, - JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) -{ - js::DefineElementOp op = getOps()->defineElement; - return (op ? op : js_DefineElement)(cx, this, index, &value, getter, setter, attrs); -} - -inline JSBool -JSObject::setProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict) -{ - if (getOps()->setProperty) + if (getOps()->setGeneric) return nonNativeSetProperty(cx, id, vp, strict); return js_SetPropertyHelper(cx, this, id, 0, vp, strict); } +inline JSBool +JSObject::setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict) +{ + return setGeneric(cx, ATOM_TO_JSID(name), vp, strict); +} + inline JSBool JSObject::setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict) { @@ -180,25 +157,23 @@ JSObject::setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict) } inline JSBool -JSObject::getAttributes(JSContext *cx, jsid id, uintN *attrsp) +JSObject::setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict) { - js::AttributesOp op = getOps()->getAttributes; - return (op ? op : js_GetAttributes)(cx, this, id, attrsp); + return setGeneric(cx, SPECIALID_TO_JSID(sid), vp, strict); } inline JSBool -JSObject::setAttributes(JSContext *cx, jsid id, uintN *attrsp) +JSObject::setGenericAttributes(JSContext *cx, jsid id, uintN *attrsp) { js::types::MarkTypePropertyConfigured(cx, this, id); - js::AttributesOp op = getOps()->setAttributes; + js::GenericAttributesOp op = getOps()->setGenericAttributes; return (op ? op : js_SetAttributes)(cx, this, id, attrsp); } inline JSBool -JSObject::getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp) +JSObject::setPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp) { - js::ElementAttributesOp op = getOps()->getElementAttributes; - return (op ? op : js_GetElementAttributes)(cx, this, index, attrsp); + return setGenericAttributes(cx, ATOM_TO_JSID(name), attrsp); } inline JSBool @@ -208,6 +183,12 @@ JSObject::setElementAttributes(JSContext *cx, uint32 index, uintN *attrsp) return (op ? op : js_SetElementAttributes)(cx, this, index, attrsp); } +inline JSBool +JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp) +{ + return setGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp); +} + inline JSBool JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp) { @@ -241,15 +222,36 @@ JSObject::getProperty(JSContext *cx, js::PropertyName *name, js::Value *vp) } inline JSBool -JSObject::deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict) +JSObject::deleteGeneric(JSContext *cx, jsid id, js::Value *rval, JSBool strict) { js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType()); js::types::MarkTypePropertyConfigured(cx, this, id); - js::DeleteIdOp op = getOps()->deleteProperty; + js::DeleteGenericOp op = getOps()->deleteGeneric; return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict); } +inline JSBool +JSObject::deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, JSBool strict) +{ + return deleteGeneric(cx, ATOM_TO_JSID(name), rval, strict); +} + +inline JSBool +JSObject::deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict) +{ + jsid id; + if (!js::IndexToId(cx, index, &id)) + return false; + return deleteGeneric(cx, id, rval, strict); +} + +inline JSBool +JSObject::deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, JSBool strict) +{ + return deleteGeneric(cx, SPECIALID_TO_JSID(sid), rval, strict); +} + inline void JSObject::finalize(JSContext *cx, bool background) { @@ -599,6 +601,21 @@ JSObject::setDenseArrayLength(uint32 length) getElementsHeader()->length = length; } +inline uint32 +JSObject::getDenseArrayInitializedLength() +{ + JS_ASSERT(isDenseArray()); + return getElementsHeader()->initializedLength; +} + +inline void +JSObject::setDenseArrayInitializedLength(uint32 length) +{ + JS_ASSERT(isDenseArray()); + JS_ASSERT(length <= getDenseArrayCapacity()); + getElementsHeader()->initializedLength = length; +} + inline uint32 JSObject::getDenseArrayCapacity() { @@ -1184,6 +1201,44 @@ JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, return lookupGeneric(cx, ATOM_TO_JSID(name), objp, propp); } +inline JSBool +JSObject::defineGeneric(JSContext *cx, jsid id, const js::Value &value, + JSPropertyOp getter /* = JS_PropertyStub */, + JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, + uintN attrs /* = JSPROP_ENUMERATE */) +{ + js::DefineGenericOp op = getOps()->defineGeneric; + return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs); +} + +inline JSBool +JSObject::defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value, + JSPropertyOp getter /* = JS_PropertyStub */, + JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, + uintN attrs /* = JSPROP_ENUMERATE */) +{ + return defineGeneric(cx, ATOM_TO_JSID(name), value, getter, setter, attrs); +} + +inline JSBool +JSObject::defineElement(JSContext *cx, uint32 index, const js::Value &value, + JSPropertyOp getter /* = JS_PropertyStub */, + JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, + uintN attrs /* = JSPROP_ENUMERATE */) +{ + js::DefineElementOp op = getOps()->defineElement; + return (op ? op : js_DefineElement)(cx, this, index, &value, getter, setter, attrs); +} + +inline JSBool +JSObject::defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value, + JSPropertyOp getter /* = JS_PropertyStub */, + JSStrictPropertyOp setter /* = JS_StrictPropertyStub */, + uintN attrs /* = JSPROP_ENUMERATE */) +{ + return defineGeneric(cx, SPECIALID_TO_JSID(sid), value, getter, setter, attrs); +} + inline JSBool JSObject::lookupElement(JSContext *cx, uint32 index, JSObject **objp, JSProperty **propp) { @@ -1216,18 +1271,37 @@ JSObject::getElement(JSContext *cx, uint32 index, js::Value *vp) } inline JSBool -JSObject::deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict) +JSObject::getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp) +{ + return getGeneric(cx, SPECIALID_TO_JSID(sid), vp); +} + +inline JSBool +JSObject::getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp) +{ + js::GenericAttributesOp op = getOps()->getGenericAttributes; + return (op ? op : js_GetAttributes)(cx, this, id, attrsp); +} + +inline JSBool +JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp) +{ + return getGenericAttributes(cx, ATOM_TO_JSID(name), attrsp); +} + +inline JSBool +JSObject::getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp) { jsid id; if (!js::IndexToId(cx, index, &id)) return false; - return deleteProperty(cx, id, rval, strict); + return getGenericAttributes(cx, id, attrsp); } inline JSBool -JSObject::getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp) +JSObject::getSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp) { - return getGeneric(cx, SPECIALID_TO_JSID(sid), vp); + return getGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp); } inline bool @@ -1477,6 +1551,13 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto) return NewNativeClassInstance(cx, clasp, proto, kind); } +inline GlobalObject * +GetCurrentGlobal(JSContext *cx) +{ + JSObject *scopeChain = (cx->hasfp()) ? &cx->fp()->scopeChain() : cx->globalObject; + return scopeChain ? scopeChain->getGlobal() : NULL; +} + bool FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop, Class *clasp); diff --git a/js/src/json.cpp b/js/src/json.cpp index b0ef520c1548..c18712858c77 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -62,6 +62,7 @@ #include "frontend/TokenStream.h" #include "jsatominlines.h" +#include "jsboolinlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsstrinlines.h" @@ -791,10 +792,10 @@ Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp JS_ASSERT(!obj->isProxy()); if (obj->isArray()) { /* Step 2a(ii). */ - jsuint length = obj->getArrayLength(); + uint32 length = obj->getArrayLength(); /* Step 2a(i), 2a(iii-iv). */ - for (jsuint i = 0; i < length; i++) { + for (uint32 i = 0; i < length; i++) { jsid id; if (!IndexToId(cx, i, &id)) return false; @@ -817,11 +818,11 @@ Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp */ if (newElement.isUndefined()) { /* Step 2a(iii)(2). */ - JS_ALWAYS_TRUE(array_deleteProperty(cx, obj, id, &newElement, false)); + JS_ALWAYS_TRUE(array_deleteElement(cx, obj, i, &newElement, false)); } else { /* Step 2a(iii)(3). */ - JS_ALWAYS_TRUE(array_defineProperty(cx, obj, id, &newElement, JS_PropertyStub, - JS_StrictPropertyStub, JSPROP_ENUMERATE)); + JS_ALWAYS_TRUE(array_defineElement(cx, obj, i, &newElement, JS_PropertyStub, + JS_StrictPropertyStub, JSPROP_ENUMERATE)); } } } else { @@ -884,11 +885,8 @@ Revive(JSContext *cx, const Value &reviver, Value *vp) if (!obj) return false; - AutoObjectRooter tvr(cx, obj); - if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), - *vp, NULL, NULL, JSPROP_ENUMERATE)) { + if (!obj->defineProperty(cx, cx->runtime->atomState.emptyAtom, *vp)) return false; - } return Walk(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), reviver, vp); } diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 8b450eadfc75..fe9f43f75fd0 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1752,10 +1752,8 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc) #if JS_HAS_DESTRUCTURING_SHORTHAND nameoff = ss->sprinter.offset; #endif - if (!QuoteString(&ss->sprinter, atom, - js_IsIdentifier(atom) ? 0 : (jschar)'\'')) { + if (!QuoteString(&ss->sprinter, atom, IsIdentifier(atom) ? 0 : (jschar)'\'')) return NULL; - } if (SprintPut(&ss->sprinter, ": ", 2) < 0) return NULL; break; @@ -1997,8 +1995,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) ? JSOP_IFEQ \ : JSOP_NOP) -#define ATOM_IS_IDENTIFIER(atom) js_IsIdentifier(atom) - /* * Given an atom already fetched from jp->script's atom map, quote/escape its * string appropriately into rval, and select fmt from the quoted and unquoted @@ -2007,7 +2003,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) #define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ JS_BEGIN_MACRO \ jschar quote_; \ - if (!ATOM_IS_IDENTIFIER(atom)) { \ + if (!IsIdentifier(atom)) { \ quote_ = '\''; \ fmt = qfmt; \ } else { \ @@ -4070,10 +4066,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) LOAD_FUNCTION(0); /* - * All allocation when decompiling is LIFO, using malloc - * or, more commonly, arena-allocating from cx->tempPool. - * Therefore after InitSprintStack succeeds, we must - * release to mark before returning. + * All allocation when decompiling is LIFO, using malloc or, + * more commonly, arena-allocating from cx->tempLifoAlloc + * Therefore after InitSprintStack succeeds, we must release + * to mark before returning. */ LifoAllocScope las(&cx->tempLifoAlloc()); if (fun->script()->bindings.hasLocalNames()) { @@ -4182,9 +4178,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) } /* - * Alas, we have to malloc a copy of the result left on - * the top of ss2 because both ss and ss2 arena-allocate - * from cx's tempPool. + * Alas, we have to malloc a copy of the result left on the + * top of ss2 because both ss and ss2 arena-allocate from + * cx's tempLifoAlloc */ rval = JS_strdup(cx, PopStr(&ss2, op)); las.releaseEarly(); @@ -4562,8 +4558,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) case JSOP_INITPROP: case JSOP_INITMETHOD: LOAD_ATOM(0); - xval = QuoteString(&ss->sprinter, atom, - jschar(ATOM_IS_IDENTIFIER(atom) ? 0 : '\'')); + xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\'')); if (!xval) return NULL; isFirst = IsInitializerOp(ss->opcodes[ss->top - 2]); @@ -4811,7 +4806,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) #undef POP_STR #undef POP_STR_PREC #undef LOCAL_ASSERT -#undef ATOM_IS_IDENTIFIER #undef GET_QUOTE_AND_FMT #undef GET_ATOM_QUOTE_AND_FMT diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 3e88f0f351bf..5ce1e420fd59 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -133,7 +133,7 @@ typedef enum JSOp { #define JOF_SHARPSLOT (1U<<24) /* first immediate is uint16 stack slot no. that needs fixup when in global code (see - Compiler::compileScript) */ + BytecodeCompiler::compileScript) */ #define JOF_GNAME (1U<<25) /* predicted global name */ #define JOF_TYPESET (1U<<26) /* has an entry in a script's type sets */ #define JOF_DECOMPOSE (1U<<27) /* followed by an equivalent decomposed @@ -176,7 +176,8 @@ typedef enum JSOp { * When a short jump won't hold a relative offset, its 2-byte immediate offset * operand is an unsigned index of a span-dependency record, maintained until * code generation finishes -- after which some (but we hope not nearly all) - * span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c). + * span-dependent jumps must be extended (see js::frontend::OptimizeSpanDeps in + * frontend/BytecodeGenerator.cpp). * * If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump * offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index a6a400775ccd..97d6a4bcf599 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -955,8 +955,8 @@ proxy_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp } static JSBool -proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, - PropertyOp getter, StrictPropertyOp setter, uintN attrs) +proxy_DefineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) { id = js_CheckForStringIndex(id); @@ -970,6 +970,13 @@ proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, return Proxy::defineProperty(cx, obj, id, &desc); } +static JSBool +proxy_DefineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + return proxy_DefineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs); +} + static JSBool proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value, PropertyOp getter, StrictPropertyOp setter, uintN attrs) @@ -977,14 +984,14 @@ proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *val jsid id; if (!IndexToId(cx, index, &id)) return false; - return proxy_DefineProperty(cx, obj, id, value, getter, setter, attrs); + return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs); } static JSBool proxy_DefineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value, PropertyOp getter, StrictPropertyOp setter, uintN attrs) { - return proxy_DefineProperty(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs); + return proxy_DefineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs); } static JSBool @@ -1017,30 +1024,36 @@ proxy_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid } static JSBool -proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +proxy_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { id = js_CheckForStringIndex(id); return Proxy::set(cx, obj, obj, id, strict, vp); } +static JSBool +proxy_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) +{ + return proxy_SetGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict); +} + static JSBool proxy_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return proxy_SetProperty(cx, obj, id, vp, strict); + return proxy_SetGeneric(cx, obj, id, vp, strict); } static JSBool proxy_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict) { - return proxy_SetProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); + return proxy_SetGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); } static JSBool -proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +proxy_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { id = js_CheckForStringIndex(id); @@ -1051,23 +1064,29 @@ proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return true; } +static JSBool +proxy_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return proxy_GetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + static JSBool proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return proxy_GetAttributes(cx, obj, id, attrsp); + return proxy_GetGenericAttributes(cx, obj, id, attrsp); } static JSBool proxy_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return proxy_GetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return proxy_GetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } static JSBool -proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +proxy_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { id = js_CheckForStringIndex(id); @@ -1079,23 +1098,29 @@ proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return Proxy::defineProperty(cx, obj, id, &desc); } +static JSBool +proxy_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return proxy_SetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + static JSBool proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return proxy_SetAttributes(cx, obj, id, attrsp); + return proxy_SetGenericAttributes(cx, obj, id, attrsp); } static JSBool proxy_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return proxy_SetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return proxy_SetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } static JSBool -proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +proxy_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { id = js_CheckForStringIndex(id); @@ -1107,19 +1132,25 @@ proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool return true; } +static JSBool +proxy_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) +{ + return proxy_DeleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict); +} + static JSBool proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return proxy_DeleteProperty(cx, obj, id, rval, strict); + return proxy_DeleteGeneric(cx, obj, id, rval, strict); } static JSBool proxy_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return proxy_DeleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } static void @@ -1213,7 +1244,7 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = { proxy_LookupProperty, proxy_LookupElement, proxy_LookupSpecial, - proxy_DefineProperty, + proxy_DefineGeneric, proxy_DefineProperty, proxy_DefineElement, proxy_DefineSpecial, @@ -1221,19 +1252,19 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = { proxy_GetProperty, proxy_GetElement, proxy_GetSpecial, - proxy_SetProperty, + proxy_SetGeneric, proxy_SetProperty, proxy_SetElement, proxy_SetSpecial, - proxy_GetAttributes, - proxy_GetAttributes, + proxy_GetGenericAttributes, + proxy_GetPropertyAttributes, proxy_GetElementAttributes, proxy_GetSpecialAttributes, - proxy_SetAttributes, - proxy_SetAttributes, + proxy_SetGenericAttributes, + proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, - proxy_DeleteProperty, + proxy_DeleteGeneric, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, @@ -1274,7 +1305,7 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { proxy_LookupProperty, proxy_LookupElement, proxy_LookupSpecial, - proxy_DefineProperty, + proxy_DefineGeneric, proxy_DefineProperty, proxy_DefineElement, proxy_DefineSpecial, @@ -1282,19 +1313,19 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { proxy_GetProperty, proxy_GetElement, proxy_GetSpecial, - proxy_SetProperty, + proxy_SetGeneric, proxy_SetProperty, proxy_SetElement, proxy_SetSpecial, - proxy_GetAttributes, - proxy_GetAttributes, + proxy_GetGenericAttributes, + proxy_GetPropertyAttributes, proxy_GetElementAttributes, proxy_GetSpecialAttributes, - proxy_SetAttributes, - proxy_SetAttributes, + proxy_SetGenericAttributes, + proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, - proxy_DeleteProperty, + proxy_DeleteGeneric, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, @@ -1347,7 +1378,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = { proxy_LookupProperty, proxy_LookupElement, proxy_LookupSpecial, - proxy_DefineProperty, + proxy_DefineGeneric, proxy_DefineProperty, proxy_DefineElement, proxy_DefineSpecial, @@ -1355,19 +1386,19 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = { proxy_GetProperty, proxy_GetElement, proxy_GetSpecial, - proxy_SetProperty, + proxy_SetGeneric, proxy_SetProperty, proxy_SetElement, proxy_SetSpecial, - proxy_GetAttributes, - proxy_GetAttributes, + proxy_GetGenericAttributes, + proxy_GetPropertyAttributes, proxy_GetElementAttributes, proxy_GetSpecialAttributes, - proxy_SetAttributes, - proxy_SetAttributes, + proxy_SetGenericAttributes, + proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, - proxy_DeleteProperty, + proxy_DeleteGeneric, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, @@ -1461,7 +1492,8 @@ proxy_createFunction(JSContext *cx, uintN argc, Value *vp) return false; JSObject *proto, *parent; parent = vp[0].toObject().getParent(); - if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto)) + proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx); + if (!proto) return false; parent = proto->getParent(); @@ -1574,7 +1606,8 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp) if (protov.isObject()) { proto = &protov.toObject(); } else { - if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto)) + proto = callable->getGlobal()->getOrCreateObjectPrototype(cx); + if (!proto) return false; } diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 34fccfe5ce3d..6d21c034d319 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -76,17 +76,12 @@ typedef uintptr_t jsatomid; /* Struct typedefs. */ typedef struct JSArgumentFormatMap JSArgumentFormatMap; -typedef struct JSCodeGenerator JSCodeGenerator; typedef struct JSGCThing JSGCThing; typedef struct JSGenerator JSGenerator; typedef struct JSNativeEnumerator JSNativeEnumerator; -typedef struct JSFunctionBox JSFunctionBox; -typedef struct JSObjectBox JSObjectBox; -typedef struct JSParseNode JSParseNode; typedef struct JSProperty JSProperty; typedef struct JSSharpObjectMap JSSharpObjectMap; typedef struct JSThread JSThread; -typedef struct JSTreeContext JSTreeContext; typedef struct JSTryNote JSTryNote; /* Friend "Advanced API" typedefs. */ @@ -120,7 +115,6 @@ class JSFixedString; class JSStaticAtom; class JSRope; class JSAtom; -struct JSDefinition; class JSWrapper; namespace js { @@ -135,10 +129,13 @@ class MatchPairs; enum RegExpFlag { - IgnoreCaseFlag = JS_BIT(0), - GlobalFlag = JS_BIT(1), - MultilineFlag = JS_BIT(2), - StickyFlag = JS_BIT(3) + IgnoreCaseFlag = 0x01, + GlobalFlag = 0x02, + MultilineFlag = 0x04, + StickyFlag = 0x08, + + NoFlags = 0x00, + AllFlags = 0x0f }; enum RegExpExecType @@ -164,12 +161,18 @@ class FrameRegsIter; class CallReceiver; class CallArgs; -struct Compiler; +struct BytecodeCompiler; +struct CodeGenerator; +struct Definition; +struct FunctionBox; +struct ObjectBox; +struct ParseNode; struct Parser; class TokenStream; struct Token; struct TokenPos; struct TokenPtr; +struct TreeContext; class UpvarCookie; class Proxy; @@ -221,7 +224,7 @@ class Bindings; class MultiDeclRange; class ParseMapPool; class DefnOrHeader; -typedef InlineMap AtomDefnMap; +typedef InlineMap AtomDefnMap; typedef InlineMap AtomIndexMap; typedef InlineMap AtomDOHMap; typedef Vector UpvarCookies; diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 2d0a578f4c46..024b2c25ff42 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -137,7 +137,7 @@ char const *callbackNames[] = { typedef AutoValueVector NodeVector; /* - * JSParseNode is a somewhat intricate data structure, and its invariants have + * ParseNode is a somewhat intricate data structure, and its invariants have * evolved, making it more likely that there could be a disconnect between the * parser and the AST serializer. We use these macros to check invariants on a * parse node and raise a dynamic error on failure. @@ -428,7 +428,7 @@ class NodeBuilder if (!atom) return false; - return obj->defineProperty(cx, ATOM_TO_JSID(atom), val); + return obj->defineProperty(cx, atom->asPropertyName(), val); } bool newNodeLoc(TokenPos *pos, Value *dst); @@ -660,7 +660,7 @@ NodeBuilder::newArray(NodeVector &elts, Value *dst) if (val.isMagic(JS_SERIALIZE_NO_NODE)) continue; - if (!array->setProperty(cx, INT_TO_JSID(i), &val, false)) + if (!array->setElement(cx, i, &val, false)) return false; } @@ -1593,7 +1593,7 @@ NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst) /* * Serialization of parse nodes to JavaScript objects. * - * All serialization methods take a non-nullable JSParseNode pointer. + * All serialization methods take a non-nullable ParseNode pointer. */ class ASTSerializer @@ -1611,21 +1611,21 @@ class ASTSerializer UnaryOperator unop(TokenKind tk, JSOp op); AssignmentOperator aop(JSOp op); - bool statements(JSParseNode *pn, NodeVector &elts); - bool expressions(JSParseNode *pn, NodeVector &elts); - bool xmls(JSParseNode *pn, NodeVector &elts); - bool leftAssociate(JSParseNode *pn, Value *dst); - bool functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct, - JSParseNode *pnbody, NodeVector &args); + bool statements(ParseNode *pn, NodeVector &elts); + bool expressions(ParseNode *pn, NodeVector &elts); + bool xmls(ParseNode *pn, NodeVector &elts); + bool leftAssociate(ParseNode *pn, Value *dst); + bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody, + NodeVector &args); - bool sourceElement(JSParseNode *pn, Value *dst); + bool sourceElement(ParseNode *pn, Value *dst); - bool declaration(JSParseNode *pn, Value *dst); - bool variableDeclaration(JSParseNode *pn, bool let, Value *dst); - bool variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst); - bool letHead(JSParseNode *pn, NodeVector &dtors); + bool declaration(ParseNode *pn, Value *dst); + bool variableDeclaration(ParseNode *pn, bool let, Value *dst); + bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst); + bool letHead(ParseNode *pn, NodeVector &dtors); - bool optStatement(JSParseNode *pn, Value *dst) { + bool optStatement(ParseNode *pn, Value *dst) { if (!pn) { dst->setMagic(JS_SERIALIZE_NO_NODE); return true; @@ -1633,15 +1633,15 @@ class ASTSerializer return statement(pn, dst); } - bool forInit(JSParseNode *pn, Value *dst); - bool statement(JSParseNode *pn, Value *dst); - bool blockStatement(JSParseNode *pn, Value *dst); - bool switchStatement(JSParseNode *pn, Value *dst); - bool switchCase(JSParseNode *pn, Value *dst); - bool tryStatement(JSParseNode *pn, Value *dst); - bool catchClause(JSParseNode *pn, Value *dst); + bool forInit(ParseNode *pn, Value *dst); + bool statement(ParseNode *pn, Value *dst); + bool blockStatement(ParseNode *pn, Value *dst); + bool switchStatement(ParseNode *pn, Value *dst); + bool switchCase(ParseNode *pn, Value *dst); + bool tryStatement(ParseNode *pn, Value *dst); + bool catchClause(ParseNode *pn, Value *dst); - bool optExpression(JSParseNode *pn, Value *dst) { + bool optExpression(ParseNode *pn, Value *dst) { if (!pn) { dst->setMagic(JS_SERIALIZE_NO_NODE); return true; @@ -1649,10 +1649,10 @@ class ASTSerializer return expression(pn, dst); } - bool expression(JSParseNode *pn, Value *dst); + bool expression(ParseNode *pn, Value *dst); - bool propertyName(JSParseNode *pn, Value *dst); - bool property(JSParseNode *pn, Value *dst); + bool propertyName(ParseNode *pn, Value *dst); + bool property(ParseNode *pn, Value *dst); bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) { if (!atom) { @@ -1663,22 +1663,22 @@ class ASTSerializer } bool identifier(JSAtom *atom, TokenPos *pos, Value *dst); - bool identifier(JSParseNode *pn, Value *dst); - bool literal(JSParseNode *pn, Value *dst); + bool identifier(ParseNode *pn, Value *dst); + bool literal(ParseNode *pn, Value *dst); - bool pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst); - bool arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst); - bool objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst); + bool pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst); + bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst); + bool objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst); - bool function(JSParseNode *pn, ASTType type, Value *dst); - bool functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body); - bool functionBody(JSParseNode *pn, TokenPos *pos, Value *dst); + bool function(ParseNode *pn, ASTType type, Value *dst); + bool functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body); + bool functionBody(ParseNode *pn, TokenPos *pos, Value *dst); - bool comprehensionBlock(JSParseNode *pn, Value *dst); - bool comprehension(JSParseNode *pn, Value *dst); - bool generatorExpression(JSParseNode *pn, Value *dst); + bool comprehensionBlock(ParseNode *pn, Value *dst); + bool comprehension(ParseNode *pn, Value *dst); + bool generatorExpression(ParseNode *pn, Value *dst); - bool xml(JSParseNode *pn, Value *dst); + bool xml(ParseNode *pn, Value *dst); public: ASTSerializer(JSContext *c, bool l, char const *src, uint32 ln) @@ -1693,7 +1693,7 @@ class ASTSerializer parser = p; } - bool program(JSParseNode *pn, Value *dst); + bool program(ParseNode *pn, Value *dst); }; AssignmentOperator @@ -1824,14 +1824,14 @@ ASTSerializer::binop(TokenKind tk, JSOp op) } bool -ASTSerializer::statements(JSParseNode *pn, NodeVector &elts) +ASTSerializer::statements(ParseNode *pn, NodeVector &elts) { JS_ASSERT(pn->isKind(TOK_LC) && pn->isArity(PN_LIST)); if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value elt; if (!sourceElement(next, &elt)) return false; @@ -1842,12 +1842,12 @@ ASTSerializer::statements(JSParseNode *pn, NodeVector &elts) } bool -ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts) +ASTSerializer::expressions(ParseNode *pn, NodeVector &elts) { if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value elt; if (!expression(next, &elt)) return false; @@ -1858,12 +1858,12 @@ ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts) } bool -ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts) +ASTSerializer::xmls(ParseNode *pn, NodeVector &elts) { if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value elt; if (!xml(next, &elt)) return false; @@ -1874,7 +1874,7 @@ ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts) } bool -ASTSerializer::blockStatement(JSParseNode *pn, Value *dst) +ASTSerializer::blockStatement(ParseNode *pn, Value *dst) { JS_ASSERT(pn->isKind(TOK_LC)); @@ -1884,7 +1884,7 @@ ASTSerializer::blockStatement(JSParseNode *pn, Value *dst) } bool -ASTSerializer::program(JSParseNode *pn, Value *dst) +ASTSerializer::program(ParseNode *pn, Value *dst) { JS_ASSERT(pn->pn_pos.begin.lineno == lineno); @@ -1894,14 +1894,14 @@ ASTSerializer::program(JSParseNode *pn, Value *dst) } bool -ASTSerializer::sourceElement(JSParseNode *pn, Value *dst) +ASTSerializer::sourceElement(ParseNode *pn, Value *dst) { /* SpiderMonkey allows declarations even in pure statement contexts. */ return statement(pn, dst); } bool -ASTSerializer::declaration(JSParseNode *pn, Value *dst) +ASTSerializer::declaration(ParseNode *pn, Value *dst) { JS_ASSERT(pn->isKind(TOK_FUNCTION) || pn->isKind(TOK_VAR) || pn->isKind(TOK_LET)); @@ -1919,7 +1919,7 @@ ASTSerializer::declaration(JSParseNode *pn, Value *dst) } bool -ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst) +ASTSerializer::variableDeclaration(ParseNode *pn, bool let, Value *dst) { JS_ASSERT(let ? pn->isKind(TOK_LET) : pn->isKind(TOK_VAR)); @@ -1939,7 +1939,7 @@ ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst) if (!dtors.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value child; if (!variableDeclarator(next, &kind, &child)) return false; @@ -1950,13 +1950,13 @@ ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst) } bool -ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst) +ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst) { /* A destructuring declarator is always a TOK_ASSIGN. */ JS_ASSERT(pn->isKind(TOK_NAME) || pn->isKind(TOK_ASSIGN)); - JSParseNode *pnleft; - JSParseNode *pnright; + ParseNode *pnleft; + ParseNode *pnright; if (pn->isKind(TOK_NAME)) { pnleft = pn; @@ -1974,14 +1974,14 @@ ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *ds } bool -ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors) +ASTSerializer::letHead(ParseNode *pn, NodeVector &dtors) { if (!dtors.reserve(pn->pn_count)) return false; VarDeclKind kind = VARDECL_LET_HEAD; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value child; /* * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do @@ -1996,7 +1996,7 @@ ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors) } bool -ASTSerializer::switchCase(JSParseNode *pn, Value *dst) +ASTSerializer::switchCase(ParseNode *pn, Value *dst) { NodeVector stmts(cx); @@ -2008,14 +2008,14 @@ ASTSerializer::switchCase(JSParseNode *pn, Value *dst) } bool -ASTSerializer::switchStatement(JSParseNode *pn, Value *dst) +ASTSerializer::switchStatement(ParseNode *pn, Value *dst) { Value disc; if (!expression(pn->pn_left, &disc)) return false; - JSParseNode *listNode; + ParseNode *listNode; bool lexical; if (pn->pn_right->isKind(TOK_LEXICALSCOPE)) { @@ -2030,7 +2030,7 @@ ASTSerializer::switchStatement(JSParseNode *pn, Value *dst) if (!cases.reserve(listNode->pn_count)) return false; - for (JSParseNode *next = listNode->pn_head; next; next = next->pn_next) { + for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) { Value child; #ifdef __GNUC__ /* quell GCC overwarning */ child = UndefinedValue(); @@ -2044,7 +2044,7 @@ ASTSerializer::switchStatement(JSParseNode *pn, Value *dst) } bool -ASTSerializer::catchClause(JSParseNode *pn, Value *dst) +ASTSerializer::catchClause(ParseNode *pn, Value *dst) { Value var, guard, body; @@ -2055,7 +2055,7 @@ ASTSerializer::catchClause(JSParseNode *pn, Value *dst) } bool -ASTSerializer::tryStatement(JSParseNode *pn, Value *dst) +ASTSerializer::tryStatement(ParseNode *pn, Value *dst) { Value body; if (!statement(pn->pn_kid1, &body)) @@ -2066,7 +2066,7 @@ ASTSerializer::tryStatement(JSParseNode *pn, Value *dst) if (!clauses.reserve(pn->pn_kid2->pn_count)) return false; - for (JSParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) { Value clause; if (!catchClause(next->pn_expr, &clause)) return false; @@ -2080,7 +2080,7 @@ ASTSerializer::tryStatement(JSParseNode *pn, Value *dst) } bool -ASTSerializer::forInit(JSParseNode *pn, Value *dst) +ASTSerializer::forInit(ParseNode *pn, Value *dst) { if (!pn) { dst->setMagic(JS_SERIALIZE_NO_NODE); @@ -2095,7 +2095,7 @@ ASTSerializer::forInit(JSParseNode *pn, Value *dst) } bool -ASTSerializer::statement(JSParseNode *pn, Value *dst) +ASTSerializer::statement(ParseNode *pn, Value *dst) { JS_CHECK_RECURSION(cx, return false); switch (pn->getKind()) { @@ -2157,9 +2157,9 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst) return expression(pn->pn_left, &expr) && statement(pn->pn_right, &stmt) && - pn->isKind(TOK_WITH) - ? builder.withStatement(expr, stmt, &pn->pn_pos, dst) - : builder.whileStatement(expr, stmt, &pn->pn_pos, dst); + (pn->isKind(TOK_WITH) + ? builder.withStatement(expr, stmt, &pn->pn_pos, dst) + : builder.whileStatement(expr, stmt, &pn->pn_pos, dst)); } case TOK_DO: @@ -2173,7 +2173,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst) case TOK_FOR: { - JSParseNode *head = pn->pn_left; + ParseNode *head = pn->pn_left; Value stmt; if (!statement(pn->pn_right, &stmt)) @@ -2206,8 +2206,8 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst) { LOCAL_ASSERT(pn->pn_count == 2); - JSParseNode *prelude = pn->pn_head; - JSParseNode *loop = prelude->pn_next; + ParseNode *prelude = pn->pn_head; + ParseNode *loop = prelude->pn_next; LOCAL_ASSERT(prelude->isKind(TOK_VAR) && loop->isKind(TOK_FOR)); @@ -2215,7 +2215,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst) if (!variableDeclaration(prelude, false, &var)) return false; - JSParseNode *head = loop->pn_left; + ParseNode *head = loop->pn_left; JS_ASSERT(head->isKind(TOK_IN)); bool isForEach = loop->pn_iflags & JSITER_FOREACH; @@ -2279,7 +2279,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst) } bool -ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst) +ASTSerializer::leftAssociate(ParseNode *pn, Value *dst) { JS_ASSERT(pn->isArity(PN_LIST)); JS_ASSERT(pn->pn_count >= 1); @@ -2288,16 +2288,16 @@ ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst) bool lor = tk == TOK_OR; bool logop = lor || (tk == TOK_AND); - JSParseNode *head = pn->pn_head; + ParseNode *head = pn->pn_head; Value left; if (!expression(head, &left)) return false; - for (JSParseNode *next = head->pn_next; next; next = next->pn_next) { + for (ParseNode *next = head->pn_next; next; next = next->pn_next) { Value right; if (!expression(next, &right)) return false; - TokenPos subpos = { pn->pn_pos.begin, next->pn_pos.end }; + TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end); if (logop) { if (!builder.logicalExpression(lor, left, right, &subpos, &left)) @@ -2316,11 +2316,11 @@ ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst) } bool -ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst) +ASTSerializer::comprehensionBlock(ParseNode *pn, Value *dst) { LOCAL_ASSERT(pn->isArity(PN_BINARY)); - JSParseNode *in = pn->pn_left; + ParseNode *in = pn->pn_left; LOCAL_ASSERT(in && in->isKind(TOK_IN)); @@ -2333,13 +2333,13 @@ ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst) } bool -ASTSerializer::comprehension(JSParseNode *pn, Value *dst) +ASTSerializer::comprehension(ParseNode *pn, Value *dst) { LOCAL_ASSERT(pn->isKind(TOK_FOR)); NodeVector blocks(cx); - JSParseNode *next = pn; + ParseNode *next = pn; while (next->isKind(TOK_FOR)) { Value block; if (!comprehensionBlock(next, &block) || !blocks.append(block)) @@ -2354,7 +2354,7 @@ ASTSerializer::comprehension(JSParseNode *pn, Value *dst) return false; next = next->pn_kid2; } else if (next->isKind(TOK_LC) && next->pn_count == 0) { - /* js_FoldConstants optimized away the push. */ + /* FoldConstants optimized away the push. */ NodeVector empty(cx); return builder.arrayExpression(empty, &pn->pn_pos, dst); } @@ -2368,13 +2368,13 @@ ASTSerializer::comprehension(JSParseNode *pn, Value *dst) } bool -ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst) +ASTSerializer::generatorExpression(ParseNode *pn, Value *dst) { LOCAL_ASSERT(pn->isKind(TOK_FOR)); NodeVector blocks(cx); - JSParseNode *next = pn; + ParseNode *next = pn; while (next->isKind(TOK_FOR)) { Value block; if (!comprehensionBlock(next, &block) || !blocks.append(block)) @@ -2401,7 +2401,7 @@ ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst) } bool -ASTSerializer::expression(JSParseNode *pn, Value *dst) +ASTSerializer::expression(ParseNode *pn, Value *dst) { JS_CHECK_RECURSION(cx, return false); switch (pn->getKind()) { @@ -2509,7 +2509,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) return generatorExpression(pn->generatorExpr(), dst); #endif - JSParseNode *next = pn->pn_head; + ParseNode *next = pn->pn_head; Value callee; if (!expression(next, &callee)) @@ -2559,7 +2559,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { if (next->isKind(TOK_COMMA)) { elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE)); } else { @@ -2584,7 +2584,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { Value prop; if (!property(next, &prop)) return false; @@ -2649,7 +2649,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_BINARY)); - JSParseNode *pnleft; + ParseNode *pnleft; bool computed; if (pn->isArity(PN_BINARY)) { @@ -2676,7 +2676,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) case TOK_AT: { Value expr; - JSParseNode *kid = pn->pn_kid; + ParseNode *kid = pn->pn_kid; bool computed = ((!kid->isKind(TOK_NAME) || !kid->isOp(JSOP_QNAMEPART)) && !kid->isKind(TOK_DBLCOLON) && !kid->isKind(TOK_ANYNAME)); @@ -2703,7 +2703,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst) } bool -ASTSerializer::xml(JSParseNode *pn, Value *dst) +ASTSerializer::xml(ParseNode *pn, Value *dst) { JS_CHECK_RECURSION(cx, return false); switch (pn->getKind()) { @@ -2796,7 +2796,7 @@ ASTSerializer::xml(JSParseNode *pn, Value *dst) } bool -ASTSerializer::propertyName(JSParseNode *pn, Value *dst) +ASTSerializer::propertyName(ParseNode *pn, Value *dst) { if (pn->isKind(TOK_NAME)) return identifier(pn, dst); @@ -2807,7 +2807,7 @@ ASTSerializer::propertyName(JSParseNode *pn, Value *dst) } bool -ASTSerializer::property(JSParseNode *pn, Value *dst) +ASTSerializer::property(ParseNode *pn, Value *dst) { PropKind kind; switch (pn->getOp()) { @@ -2834,7 +2834,7 @@ ASTSerializer::property(JSParseNode *pn, Value *dst) } bool -ASTSerializer::literal(JSParseNode *pn, Value *dst) +ASTSerializer::literal(ParseNode *pn, Value *dst) { Value val; switch (pn->getKind()) { @@ -2878,7 +2878,7 @@ ASTSerializer::literal(JSParseNode *pn, Value *dst) } bool -ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) +ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst) { JS_ASSERT(pn->isKind(TOK_RB)); @@ -2886,7 +2886,7 @@ ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { if (next->isKind(TOK_COMMA)) { elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE)); } else { @@ -2901,7 +2901,7 @@ ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) } bool -ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) +ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst) { JS_ASSERT(pn->isKind(TOK_RC)); @@ -2909,7 +2909,7 @@ ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) if (!elts.reserve(pn->pn_count)) return false; - for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { LOCAL_ASSERT(next->isOp(JSOP_INITPROP)); Value key, patt, prop; @@ -2926,7 +2926,7 @@ ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) } bool -ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst) +ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst) { JS_CHECK_RECURSION(cx, return false); switch (pn->getKind()) { @@ -2953,7 +2953,7 @@ ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst) } bool -ASTSerializer::identifier(JSParseNode *pn, Value *dst) +ASTSerializer::identifier(ParseNode *pn, Value *dst) { LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY)); LOCAL_ASSERT(pn->pn_atom); @@ -2962,7 +2962,7 @@ ASTSerializer::identifier(JSParseNode *pn, Value *dst) } bool -ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst) +ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst) { JSFunction *func = (JSFunction *)pn->pn_funbox->object; @@ -2986,9 +2986,9 @@ ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst) NodeVector args(cx); - JSParseNode *argsAndBody = pn->pn_body->isKind(TOK_UPVARS) - ? pn->pn_body->pn_tree - : pn->pn_body; + ParseNode *argsAndBody = pn->pn_body->isKind(TOK_UPVARS) + ? pn->pn_body->pn_tree + : pn->pn_body; Value body; return functionArgsAndBody(argsAndBody, args, &body) && @@ -2996,10 +2996,10 @@ ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst) } bool -ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body) +ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body) { - JSParseNode *pnargs; - JSParseNode *pnbody; + ParseNode *pnargs; + ParseNode *pnbody; /* Extract the args and body separately. */ if (pn->isKind(TOK_ARGSBODY)) { @@ -3010,11 +3010,11 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod pnbody = pn; } - JSParseNode *pndestruct; + ParseNode *pndestruct; /* Extract the destructuring assignments. */ if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) { - JSParseNode *head = pnbody->pn_head; + ParseNode *head = pnbody->pn_head; LOCAL_ASSERT(head && head->isKind(TOK_SEMI)); pndestruct = head->pn_kid; @@ -3031,7 +3031,7 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod case TOK_SEQ: /* expression closure with destructured args */ { - JSParseNode *pnstart = pnbody->pn_head->pn_next; + ParseNode *pnstart = pnbody->pn_head->pn_next; LOCAL_ASSERT(pnstart && pnstart->isKind(TOK_RETURN)); return functionArgs(pn, pnargs, pndestruct, pnbody, args) && @@ -3040,7 +3040,7 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod case TOK_LC: /* statement closure */ { - JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT) + ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT) ? pnbody->pn_head->pn_next : pnbody->pn_head; @@ -3054,12 +3054,12 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod } bool -ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct, - JSParseNode *pnbody, NodeVector &args) +ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, + ParseNode *pnbody, NodeVector &args) { uint32 i = 0; - JSParseNode *arg = pnargs ? pnargs->pn_head : NULL; - JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL; + ParseNode *arg = pnargs ? pnargs->pn_head : NULL; + ParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL; Value node; /* @@ -3100,12 +3100,12 @@ ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *p } bool -ASTSerializer::functionBody(JSParseNode *pn, TokenPos *pos, Value *dst) +ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, Value *dst) { NodeVector elts(cx); /* We aren't sure how many elements there are up front, so we'll check each append. */ - for (JSParseNode *next = pn; next; next = next->pn_next) { + for (ParseNode *next = pn; next; next = next->pn_next) { Value child; if (!sourceElement(next, &child) || !elts.append(child)) return false; @@ -3221,7 +3221,7 @@ reflect_parse(JSContext *cx, uint32 argc, jsval *vp) serialize.setParser(&parser); - JSParseNode *pn = parser.parse(NULL); + ParseNode *pn = parser.parse(NULL); if (!pn) return JS_FALSE; diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index e138f5ba4f95..3a9986e73dad 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -935,7 +935,7 @@ JSObject::removeProperty(JSContext *cx, jsid id) spare = js_NewGCShape(cx); if (!spare) return false; - PodZero(spare); + new (spare) Shape(shape->base(), 0); } /* If shape has a slot, free its slot number. */ @@ -1063,6 +1063,7 @@ JSObject::generateOwnShape(JSContext *cx, Shape *newShape) newShape = js_NewGCShape(cx); if (!newShape) return false; + new (newShape) Shape(lastProperty()->base(), 0); } PropertyTable &table = lastProperty()->table(); @@ -1092,6 +1093,7 @@ JSObject::methodShapeChange(JSContext *cx, const Shape &shape) Shape *spare = js_NewGCShape(cx); if (!spare) return NULL; + new (spare) Shape(shape.base(), 0); #ifdef DEBUG JS_ASSERT(canHaveMethodBarrier()); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index eb6e6b47b148..1041e7c875a7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -80,6 +80,7 @@ using namespace js; using namespace js::gc; +using namespace js::frontend; namespace js { @@ -305,14 +306,6 @@ CheckScript(JSScript *script, JSScript *prev) } } -void -CheckScriptOwner(JSScript *script, JSObject *owner) -{ - // JS_OPT_ASSERT(script->ownerObject == owner); - if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT) - JS_OPT_ASSERT(script->compartment() == owner->compartment()); -} - #endif /* JS_CRASH_DIAGNOSTICS */ } /* namespace js */ @@ -755,37 +748,6 @@ JSPCCounters::destroy(JSContext *cx) } } -static void -script_trace(JSTracer *trc, JSObject *obj) -{ - JSScript *script = (JSScript *) obj->getPrivate(); - if (script) { - CheckScriptOwner(script, obj); - MarkScript(trc, script, "script"); - } -} - -JS_FRIEND_DATA(Class) js::ScriptClass = { - "Script", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - NULL, /* finalize */ - NULL, /* reserved0 */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* construct */ - NULL, /* xdrObject */ - NULL, /* hasInstance */ - script_trace -}; - /* * Shared script filename management. */ @@ -964,7 +926,6 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom PodZero(script); #ifdef JS_CRASH_DIAGNOSTICS script->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE; - script->ownerObject = JS_NEW_SCRIPT; #endif #if JS_SCRIPT_INLINE_DATA_LIMIT if (!data) @@ -1097,7 +1058,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom } JSScript * -JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) +JSScript::NewScriptFromCG(JSContext *cx, CodeGenerator *cg) { uint32 mainLength, prologLength, nsrcnotes, nfixed; JSScript *script; @@ -1162,10 +1123,10 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap(); - if (!js_FinishTakingSrcNotes(cx, cg, script->notes())) + if (!FinishTakingSrcNotes(cx, cg, script->notes())) return NULL; if (cg->ntrynotes != 0) - js_FinishTakingTryNotes(cg, script->trynotes()); + FinishTakingTryNotes(cg, script->trynotes()); if (cg->objectList.length != 0) cg->objectList.finish(script->objects()); if (cg->regexpList.length != 0) @@ -1246,23 +1207,26 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) return NULL; fun->setScript(script); + script->u.globalObject = fun->getParent() ? fun->getParent()->getGlobal() : NULL; } else { /* * Initialize script->object, if necessary, so that the debugger has a * valid holder object. */ - if ((cg->flags & TCF_NEED_SCRIPT_OBJECT) && !js_NewScriptObject(cx, script)) - return NULL; + if (cg->flags & TCF_NEED_SCRIPT_GLOBAL) + script->u.globalObject = GetCurrentGlobal(cx); } /* Tell the debugger about this compiled script. */ js_CallNewScriptHook(cx, script, fun); if (!cg->parent) { - JSObject *owner = fun ? fun : script->u.object; GlobalObject *compileAndGoGlobal = NULL; - if (script->compileAndGo) - compileAndGoGlobal = (owner ? owner : cg->scopeChain())->getGlobal(); - Debugger::onNewScript(cx, script, owner, compileAndGoGlobal); + if (script->compileAndGo) { + compileAndGoGlobal = script->u.globalObject; + if (!compileAndGoGlobal) + compileAndGoGlobal = cg->scopeChain()->getGlobal(); + } + Debugger::onNewScript(cx, script, compileAndGoGlobal); } return script; @@ -1293,15 +1257,6 @@ JSScript::dataSize(JSUsableSizeFun usf) return usable ? usable : dataSize(); } -void -JSScript::setOwnerObject(JSObject *owner) -{ -#ifdef JS_CRASH_DIAGNOSTICS - CheckScriptOwner(this, JS_NEW_SCRIPT); - ownerObject = owner; -#endif -} - /* * Nb: srcnotes are variable-length. This function computes the number of * srcnote *slots*, which may be greater than the number of srcnotes. @@ -1376,28 +1331,6 @@ JSScript::finalize(JSContext *cx, bool background) } } -JSObject * -js_NewScriptObject(JSContext *cx, JSScript *script) -{ - JS_ASSERT(!script->u.object); - - JSObject *obj = NewNonFunction(cx, &ScriptClass, NULL, NULL); - if (!obj) - return NULL; - obj->setPrivate(script); - script->u.object = obj; - script->setOwnerObject(obj); - - /* - * Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent - * for security checks, then we can clear the parent, too. - */ - if (!obj->clearType(cx)) - return NULL; - - return obj; -} - namespace js { static const uint32 GSN_CACHE_THRESHOLD = 100; @@ -1477,13 +1410,6 @@ js_FramePCToLineNumber(JSContext *cx, StackFrame *fp, jsbytecode *pc) uintN js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) { - JSOp op; - JSFunction *fun; - uintN lineno; - ptrdiff_t offset, target; - jssrcnote *sn; - JSSrcNoteType type; - /* Cope with StackFrame.pc value prior to entering js_Interpret. */ if (!pc) return 0; @@ -1492,10 +1418,11 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) * Special case: function definition needs no line number note because * the function's script contains its starting line number. */ - op = js_GetOpcode(cx, script, pc); + JSOp op = js_GetOpcode(cx, script, pc); if (js_CodeSpec[op].format & JOF_INDEXBASE) pc += js_CodeSpec[op].length; if (*pc == JSOP_DEFFUN) { + JSFunction *fun; GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); return fun->script()->lineno; } @@ -1505,12 +1432,12 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) * keeping track of line-number notes, until we pass the note for pc's * offset within script->code. */ - lineno = script->lineno; - offset = 0; - target = pc - script->code; - for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + uintN lineno = script->lineno; + ptrdiff_t offset = 0; + ptrdiff_t target = pc - script->code; + for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { offset += SN_DELTA(sn); - type = (JSSrcNoteType) SN_TYPE(sn); + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) { if (offset <= target) lineno = (uintN) js_GetSrcNoteOffset(sn, 0); @@ -1530,16 +1457,11 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) jsbytecode * js_LineNumberToPC(JSScript *script, uintN target) { - ptrdiff_t offset, best; - uintN lineno, bestdiff, diff; - jssrcnote *sn; - JSSrcNoteType type; - - offset = 0; - best = -1; - lineno = script->lineno; - bestdiff = SN_LINE_LIMIT; - for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + ptrdiff_t offset = 0; + ptrdiff_t best = -1; + uintN lineno = script->lineno; + uintN bestdiff = SN_LINE_LIMIT; + for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { /* * Exact-match only if offset is not in the prolog; otherwise use * nearest greater-or-equal line number match. @@ -1547,14 +1469,14 @@ js_LineNumberToPC(JSScript *script, uintN target) if (lineno == target && offset >= ptrdiff_t(script->mainOffset)) goto out; if (lineno >= target) { - diff = lineno - target; + uintN diff = lineno - target; if (diff < bestdiff) { bestdiff = diff; best = offset; } } offset += SN_DELTA(sn); - type = (JSSrcNoteType) SN_TYPE(sn); + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) { lineno = (uintN) js_GetSrcNoteOffset(sn, 0); } else if (type == SRC_NEWLINE) { @@ -1570,18 +1492,11 @@ out: JS_FRIEND_API(uintN) js_GetScriptLineExtent(JSScript *script) { - - bool counting; - uintN lineno; - uintN maxLineNo; - jssrcnote *sn; - JSSrcNoteType type; - - lineno = script->lineno; - maxLineNo = 0; - counting = true; - for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - type = (JSSrcNoteType) SN_TYPE(sn); + uintN lineno = script->lineno; + uintN maxLineNo = 0; + bool counting = true; + for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) { if (maxLineNo < lineno) maxLineNo = lineno; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 26bfa8bfdf1c..85fbedf698db 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -383,9 +383,6 @@ class JSPCCounters { static const uint32 JS_SCRIPT_COOKIE = 0xc00cee; -static JSObject * const JS_NEW_SCRIPT = (JSObject *)0x12345678; -static JSObject * const JS_CACHED_SCRIPT = (JSObject *)0x12341234; - struct JSScript : public js::gc::Cell { /* * Two successively less primitive ways to make a new JSScript. The first @@ -404,7 +401,7 @@ struct JSScript : public js::gc::Cell { uint16 nClosedArgs, uint16 nClosedVars, uint32 nTypeSets, JSVersion version); - static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg); + static JSScript *NewScriptFromCG(JSContext *cx, js::CodeGenerator *cg); #ifdef JS_CRASH_DIAGNOSTICS /* @@ -514,19 +511,20 @@ struct JSScript : public js::gc::Cell { union { /* - * A script object of class ScriptClass, to ensure the script is GC'd. + * A global object for the script. * - All scripts returned by JSAPI functions (JS_CompileScript, - * JS_CompileFile, etc.) have these objects. - * - Function scripts never have script objects; such scripts are owned - * by their function objects. + * JS_CompileFile, etc.) have a non-null globalObject. + * - A function script has a globalObject if the function comes from a + * compile-and-go script. * - Temporary scripts created by obj_eval, JS_EvaluateScript, and - * similar functions never have these objects; such scripts are - * explicitly destroyed by the code that created them. + * similar functions never have the globalObject field set; for such + * scripts the global should be extracted from the JS frame that + * execute scripts. */ - JSObject *object; + js::GlobalObject *globalObject; /* Hash table chaining for JSCompartment::evalCache. */ - JSScript *evalHashLink; + JSScript *evalHashLink; } u; uint32 *closedSlots; /* vector of closed slots; args first, then vars. */ @@ -540,14 +538,10 @@ struct JSScript : public js::gc::Cell { JSFunction *function() const { return function_; } #ifdef JS_CRASH_DIAGNOSTICS - JSObject *ownerObject; - /* All diagnostic fields must be multiples of Cell::CellSize. */ - uint32 cookie2[sizeof(JSObject *) == 4 ? 1 : 2]; + uint32 cookie2[Cell::CellSize / sizeof(uint32)]; #endif - void setOwnerObject(JSObject *owner); - #ifdef DEBUG /* * Unique identifier within the compartment for this script, used for @@ -595,6 +589,11 @@ struct JSScript : public js::gc::Cell { inline void clearNesting(); + /* Return creation time global or null. */ + js::GlobalObject *getGlobalObjectOrNull() const { + return isCachedEval ? NULL : u.globalObject; + } + private: bool makeTypes(JSContext *cx); bool makeAnalysis(JSContext *cx); @@ -642,7 +641,7 @@ struct JSScript : public js::gc::Cell { /* Size of the JITScript and all sections. (This method is implemented in MethodJIT.h.) */ JS_FRIEND_API(size_t) jitDataSize(JSUsableSizeFun usf); - + #endif jsbytecode *main() { @@ -760,7 +759,7 @@ struct JSScript : public js::gc::Cell { * count-style interface.) */ bool setStepModeFlag(JSContext *cx, bool step); - + /* * Increment or decrement the single-step count. If the count is non-zero or * the flag (set by setStepModeFlag) is set, then the script is in @@ -805,9 +804,6 @@ StackDepth(JSScript *script) JS_END_MACRO -extern JSObject * -js_InitScriptClass(JSContext *cx, JSObject *obj); - extern void js_MarkScriptFilename(const char *filename); @@ -830,19 +826,11 @@ namespace js { #ifdef JS_CRASH_DIAGNOSTICS -void -CheckScriptOwner(JSScript *script, JSObject *owner); - void CheckScript(JSScript *script, JSScript *prev); #else -inline void -CheckScriptOwner(JSScript *script, JSObject *owner) -{ -} - inline void CheckScript(JSScript *script, JSScript *prev) { @@ -852,9 +840,6 @@ CheckScript(JSScript *script, JSScript *prev) } /* namespace js */ -extern JSObject * -js_NewScriptObject(JSContext *cx, JSScript *script); - /* * To perturb as little code as possible, we introduce a js_GetSrcNote lookup * cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 6c127c30b27f..b1eae02e36bc 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -207,11 +207,4 @@ JSScript::clearNesting() } } -inline JSScript * -JSObject::getScript() const -{ - JS_ASSERT(isScript()); - return static_cast(getPrivate()); -} - #endif /* jsscriptinlines_h___ */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 29777b6ccdfd..a877bc1417e6 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1524,10 +1524,8 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value vp->setObject(*obj); return obj->defineElement(cx, 0, StringValue(fm.pattern())) && - obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom), - Int32Value(fm.match())) && - obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom), - StringValue(textstr)); + obj->defineProperty(cx, cx->runtime->atomState.indexAtom, Int32Value(fm.match())) && + obj->defineProperty(cx, cx->runtime->atomState.inputAtom, StringValue(textstr)); } typedef JSObject **MatchArgType; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 8cb06f97d96d..32ced3670e81 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1323,14 +1323,8 @@ static void Unblacklist(JSScript *script, jsbytecode *pc) { JS_ASSERT(*pc == JSOP_NOTRACE || *pc == JSOP_TRACE); - if (*pc == JSOP_NOTRACE) { + if (*pc == JSOP_NOTRACE) *pc = JSOP_TRACE; - -#ifdef JS_METHODJIT - /* This code takes care of unblacklisting in the method JIT. */ - js::mjit::ResetTraceHint(script, pc, GET_UINT16(pc), false); -#endif - } } #ifdef JS_METHODJIT @@ -2701,17 +2695,6 @@ TraceMonitor::flush() flushEpoch++; -#ifdef JS_METHODJIT - if (loopProfiles) { - for (LoopProfileMap::Enum e(*loopProfiles); !e.empty(); e.popFront()) { - jsbytecode *pc = e.front().key; - LoopProfile *prof = e.front().value; - /* This code takes care of resetting all methodjit state. */ - js::mjit::ResetTraceHint(prof->entryScript, pc, GET_UINT16(pc), true); - } - } -#endif - frameCache->reset(); dataAlloc->reset(); traceAlloc->reset(); @@ -10965,36 +10948,42 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins) return RECORD_CONTINUE; } +static inline void +AssertValidPrototype(JSObject *proto, JSProtoKey key, DebugOnly localtm, + JSContext *cx) +{ + JS_NOT_REACHED("FIXME"); +} + RecordingStatus -TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins) +TraceRecorder::getObjectPrototype(LIns*& proto_ins) { proto_ins = NULL; JS_NOT_REACHED("FIXME"); -#if 0 -#ifdef DEBUG - TraceMonitor &localtm = *traceMonitor; -#endif + return RECORD_CONTINUE; +} - JSObject* proto; - if (!js_GetClassPrototype(cx, globalObj, key, &proto)) - RETURN_ERROR("error in js_GetClassPrototype"); +RecordingStatus +TraceRecorder::getFunctionPrototype(LIns*& proto_ins) +{ + proto_ins = NULL; + JS_NOT_REACHED("FIXME"); + return RECORD_CONTINUE; +} - // This should not have reentered. - JS_ASSERT(localtm.recorder); +RecordingStatus +TraceRecorder::getArrayPrototype(LIns*& proto_ins) +{ + proto_ins = NULL; + JS_NOT_REACHED("FIXME"); + return RECORD_CONTINUE; +} -#ifdef DEBUG - /* Double-check that a native proto has a matching emptyShape. */ - if (key != JSProto_Array) { - JS_ASSERT(proto->isNative()); - JS_ASSERT(proto->getNewType(cx)->emptyShapes); - EmptyShape *empty = proto->getNewType(cx)->emptyShapes[0]; - JS_ASSERT(empty); - JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getObjectClass()) == key); - } -#endif - - proto_ins = w.immpObjGC(proto); -#endif +RecordingStatus +TraceRecorder::getRegExpPrototype(LIns*& proto_ins) +{ + proto_ins = NULL; + JS_NOT_REACHED("FIXME"); return RECORD_CONTINUE; } @@ -11694,7 +11683,7 @@ DeleteIntKey(JSContext* cx, JSObject* obj, int32 i, JSBool strict) } } - if (!obj->deleteProperty(cx, id, &v, strict)) + if (!obj->deleteGeneric(cx, id, &v, strict)) SetBuiltinError(tm); return v.toBoolean(); } @@ -11716,7 +11705,7 @@ DeleteStrKey(JSContext* cx, JSObject* obj, JSString* str, JSBool strict) * jsatominlines.h) that helper early-returns if the computed property name * string is already atomized, and we are *not* on a perf-critical path! */ - if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteProperty(cx, id, &v, strict)) + if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteGeneric(cx, id, &v, strict)) SetBuiltinError(tm); return v.toBoolean(); } @@ -12934,7 +12923,7 @@ SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, JSB LeaveTraceIfGlobalObject(cx, obj); jsid id; - if (!RootedStringToId(cx, namep, &id) || !obj->setProperty(cx, id, vp, strict)) { + if (!RootedStringToId(cx, namep, &id) || !obj->setGeneric(cx, id, vp, strict)) { SetBuiltinError(tm); return false; } @@ -12953,7 +12942,7 @@ InitPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, ValueArgType jsid id; if (!RootedStringToId(cx, namep, &id) || - !obj->defineProperty(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { + !obj->defineGeneric(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(tm); return JS_FALSE; } @@ -12994,7 +12983,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp, JSBool LeaveTraceIfGlobalObject(cx, obj); AutoIdRooter idr(cx); - if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp, strict)) { + if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setGeneric(cx, idr.id(), vp, strict)) { SetBuiltinError(tm); return false; } @@ -13012,7 +13001,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, ValueArgType arg) AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || - !obj->defineProperty(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { + !obj->defineGeneric(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(tm); return JS_FALSE; } @@ -14436,15 +14425,16 @@ TraceRecorder::record_JSOP_NEWINIT() hadNewInit = true; JSProtoKey key = JSProtoKey(cx->regs().pc[1]); + JS_ASSERT(key == JSProto_Array || key == JSProto_Object); - LIns* proto_ins; - CHECK_STATUS_A(getClassPrototype(key, proto_ins)); - + LIns* proto_ins = NULL; LIns *v_ins; if (key == JSProto_Array) { + CHECK_STATUS_A(getArrayPrototype(proto_ins)); LIns *args[] = { proto_ins, cx_ins }; v_ins = w.call(&NewDenseEmptyArray_ci, args); } else { + CHECK_STATUS_A(getObjectPrototype(proto_ins)); LIns *args[] = { w.immpNull(), proto_ins, cx_ins }; v_ins = w.call(&js_InitializerObject_ci, args); } @@ -14458,8 +14448,8 @@ TraceRecorder::record_JSOP_NEWARRAY() { initDepth++; - LIns* proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins)); + LIns* proto_ins = NULL; + CHECK_STATUS_A(getArrayPrototype(proto_ins)); unsigned count = GET_UINT24(cx->regs().pc); LIns *args[] = { proto_ins, w.immi(count), cx_ins }; @@ -14475,8 +14465,8 @@ TraceRecorder::record_JSOP_NEWOBJECT() { initDepth++; - LIns* proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_Object, proto_ins)); + LIns* proto_ins = NULL; + CHECK_STATUS_A(getObjectPrototype(proto_ins)); JSObject* baseobj = cx->fp()->script()->getObject(getFullIndex(0)); @@ -15381,8 +15371,8 @@ TraceRecorder::record_JSOP_LAMBDA() } } - LIns *proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + LIns *proto_ins = NULL; + CHECK_STATUS_A(getFunctionPrototype(proto_ins)); LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins }; LIns* x = w.call(&js_NewNullClosure_ci, args); @@ -15396,13 +15386,14 @@ TraceRecorder::record_JSOP_LAMBDA() if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH)) RETURN_STOP_A("Unable to trace creating lambda in let"); - LIns *proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + //LIns *proto_ins; + //CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); //LIns* scopeChain_ins = scopeChain(); //JS_ASSERT(scopeChain_ins); //LIns* args[] = { proto_ins, scopeChain_ins, w.nameImmpNonGC(fun), cx_ins }; LIns* call_ins = NULL; // w.call(&js_CloneFunctionObject_ci, args); + guard(false, w.name(w.eqp0(call_ins), "guard(js_CloneFunctionObject)"), OOM_EXIT); @@ -15567,8 +15558,8 @@ TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj) JSFunction* fun = obj->toFunction(); if (fun->isNullClosure() && fun->getParent() == globalObj) { - LIns *proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + LIns *proto_ins = NULL; + CHECK_STATUS_A(getFunctionPrototype(proto_ins)); LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins }; LIns* x = w.call(&js_NewNullClosure_ci, args); @@ -15690,8 +15681,8 @@ TraceRecorder::record_JSOP_REGEXP() JSScript* script = fp->script(); unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc); - LIns* proto_ins; - CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins)); + LIns* proto_ins = NULL; + CHECK_STATUS_A(getRegExpPrototype(proto_ins)); LIns* args[] = { proto_ins, diff --git a/js/src/jstracer.h b/js/src/jstracer.h index a3ea825bbba8..1189d588e6fe 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1491,10 +1491,14 @@ class TraceRecorder unsigned *depthp); JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins); JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins); + JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins); - JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key, - nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus getObjectPrototype(nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus getFunctionPrototype(nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus getArrayPrototype(nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus getRegExpPrototype(nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval); JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, Value* argv, diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index a5143fce3998..55b34e46dadb 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -338,8 +338,8 @@ ArrayBuffer::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, } JSBool -ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, - PropertyOp getter, StrictPropertyOp setter, uintN attrs) +ArrayBuffer::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) return true; @@ -350,6 +350,13 @@ ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Val return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs); } +JSBool +ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs); +} + JSBool ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs) @@ -364,7 +371,7 @@ JSBool ArrayBuffer::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs) { - return obj_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); + return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); } JSBool @@ -405,7 +412,7 @@ ArrayBuffer::obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, Sp } JSBool -ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) return true; @@ -458,6 +465,12 @@ ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, J return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict); } +JSBool +ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) +{ + return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict); +} + JSBool ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict) { @@ -471,11 +484,11 @@ ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *v JSBool ArrayBuffer::obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict) { - return obj_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); + return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); } JSBool -ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +ArrayBuffer::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { *attrsp = JSPROP_PERMANENT | JSPROP_READONLY; @@ -488,6 +501,12 @@ ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *att return js_GetAttributes(cx, delegate, id, attrsp); } +JSBool +ArrayBuffer::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return obj_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + JSBool ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { @@ -500,11 +519,11 @@ ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index JSBool ArrayBuffer::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return obj_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } JSBool -ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +ArrayBuffer::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -518,6 +537,12 @@ ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *att return js_SetAttributes(cx, delegate, id, attrsp); } +JSBool +ArrayBuffer::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return obj_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + JSBool ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { @@ -530,11 +555,11 @@ ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index JSBool ArrayBuffer::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return obj_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return obj_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } JSBool -ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +ArrayBuffer::obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) { rval->setBoolean(false); @@ -547,6 +572,12 @@ ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rv return js_DeleteProperty(cx, delegate, id, rval, strict); } +JSBool +ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) +{ + return obj_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict); +} + JSBool ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) { @@ -559,7 +590,7 @@ ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value JSBool ArrayBuffer::obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return obj_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return obj_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } JSBool @@ -735,7 +766,7 @@ TypedArray::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, } JSBool -TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +TypedArray::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) ? JSPROP_PERMANENT | JSPROP_READONLY @@ -743,6 +774,13 @@ TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attr return true; } +JSBool +TypedArray::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE; + return true; +} + JSBool TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { @@ -753,11 +791,18 @@ TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, JSBool TypedArray::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return obj_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } JSBool -TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +TypedArray::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); + return false; +} + +JSBool +TypedArray::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); return false; @@ -773,13 +818,14 @@ TypedArray::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, JSBool TypedArray::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return obj_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS); + return false; } /* static */ int TypedArray::lengthOffset() { - return JSObject::getFixedSlotOffset(FIELD_LENGTH) + offsetof(jsval_layout, s.payload); + return JSObject::getFixedSlotOffset(FIELD_LENGTH); } /* static */ int @@ -1101,7 +1147,7 @@ class TypedArrayTemplate } static JSBool - obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) + obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) { JSObject *tarray = getTypedArray(obj); JS_ASSERT(tarray); @@ -1126,6 +1172,12 @@ class TypedArrayTemplate return setElementTail(cx, tarray, index, vp, strict); } + static JSBool + obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) + { + return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict); + } + static JSBool obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict) { @@ -1148,18 +1200,25 @@ class TypedArrayTemplate static JSBool obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict) { - return obj_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); + return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict); } static JSBool - obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, - PropertyOp getter, StrictPropertyOp setter, uintN attrs) + obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) { if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) return true; Value tmp = *v; - return obj_setProperty(cx, obj, id, &tmp, false); + return obj_setGeneric(cx, obj, id, &tmp, false); + } + + static JSBool + obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) + { + return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs); } static JSBool @@ -1174,11 +1233,11 @@ class TypedArrayTemplate obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs) { - return obj_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); + return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); } static JSBool - obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) + obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { rval->setBoolean(false); @@ -1197,6 +1256,12 @@ class TypedArrayTemplate return true; } + static JSBool + obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) + { + return obj_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict); + } + static JSBool obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) { @@ -1215,7 +1280,7 @@ class TypedArrayTemplate static JSBool obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return obj_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return obj_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } static JSBool @@ -2051,7 +2116,7 @@ Class js::ArrayBufferClass = { ArrayBuffer::obj_lookupProperty, ArrayBuffer::obj_lookupElement, ArrayBuffer::obj_lookupSpecial, - ArrayBuffer::obj_defineProperty, + ArrayBuffer::obj_defineGeneric, ArrayBuffer::obj_defineProperty, ArrayBuffer::obj_defineElement, ArrayBuffer::obj_defineSpecial, @@ -2059,19 +2124,19 @@ Class js::ArrayBufferClass = { ArrayBuffer::obj_getProperty, ArrayBuffer::obj_getElement, ArrayBuffer::obj_getSpecial, - ArrayBuffer::obj_setProperty, + ArrayBuffer::obj_setGeneric, ArrayBuffer::obj_setProperty, ArrayBuffer::obj_setElement, ArrayBuffer::obj_setSpecial, - ArrayBuffer::obj_getAttributes, - ArrayBuffer::obj_getAttributes, + ArrayBuffer::obj_getGenericAttributes, + ArrayBuffer::obj_getPropertyAttributes, ArrayBuffer::obj_getElementAttributes, ArrayBuffer::obj_getSpecialAttributes, - ArrayBuffer::obj_setAttributes, - ArrayBuffer::obj_setAttributes, + ArrayBuffer::obj_setGenericAttributes, + ArrayBuffer::obj_setPropertyAttributes, ArrayBuffer::obj_setElementAttributes, ArrayBuffer::obj_setSpecialAttributes, - ArrayBuffer::obj_deleteProperty, + ArrayBuffer::obj_deleteGeneric, ArrayBuffer::obj_deleteProperty, ArrayBuffer::obj_deleteElement, ArrayBuffer::obj_deleteSpecial, @@ -2163,27 +2228,27 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \ _typedArray::obj_lookupProperty, \ _typedArray::obj_lookupElement, \ _typedArray::obj_lookupSpecial, \ - _typedArray::obj_defineProperty, \ + _typedArray::obj_defineGeneric, \ _typedArray::obj_defineProperty, \ _typedArray::obj_defineElement, \ _typedArray::obj_defineSpecial, \ - _typedArray::obj_getGeneric, \ + _typedArray::obj_getGeneric, \ _typedArray::obj_getProperty, \ _typedArray::obj_getElement, \ _typedArray::obj_getSpecial, \ - _typedArray::obj_setProperty, \ + _typedArray::obj_setGeneric, \ _typedArray::obj_setProperty, \ _typedArray::obj_setElement, \ _typedArray::obj_setSpecial, \ - _typedArray::obj_getAttributes, \ - _typedArray::obj_getAttributes, \ + _typedArray::obj_getGenericAttributes, \ + _typedArray::obj_getPropertyAttributes, \ _typedArray::obj_getElementAttributes, \ _typedArray::obj_getSpecialAttributes, \ - _typedArray::obj_setAttributes, \ - _typedArray::obj_setAttributes, \ + _typedArray::obj_setGenericAttributes, \ + _typedArray::obj_setPropertyAttributes, \ _typedArray::obj_setElementAttributes, \ _typedArray::obj_setSpecialAttributes, \ - _typedArray::obj_deleteProperty, \ + _typedArray::obj_deleteGeneric, \ _typedArray::obj_deleteProperty, \ _typedArray::obj_deleteElement, \ _typedArray::obj_deleteSpecial, \ @@ -2211,11 +2276,11 @@ InitTypedArrayClass(JSContext *cx, GlobalObject *global) if (!LinkConstructorAndPrototype(cx, ctor, proto)) return NULL; - if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom), + if (!ctor->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom, Int32Value(ArrayType::BYTES_PER_ELEMENT), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY) || - !proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom), + !proto->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom, Int32Value(ArrayType::BYTES_PER_ELEMENT), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h index 614a884fd5d2..e5d852a0791b 100644 --- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -88,13 +88,14 @@ struct JS_FRIEND_API(ArrayBuffer) { JSProperty **propp); static JSBool - obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, + obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs); + static JSBool + obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs); - static JSBool obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs); - static JSBool obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs); @@ -113,38 +114,38 @@ struct JS_FRIEND_API(ArrayBuffer) { obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp); static JSBool - obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); - + obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); + static JSBool + obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict); static JSBool obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict); - static JSBool obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict); static JSBool - obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); - + obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool + obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp); static JSBool obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp); - static JSBool obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp); static JSBool - obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); - + obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool + obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp); static JSBool obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp); - static JSBool obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp); static JSBool - obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict); - + obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict); + static JSBool + obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict); static JSBool obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict); - static JSBool obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict); @@ -223,11 +224,13 @@ struct JS_FRIEND_API(TypedArray) { static JSBool obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, JSProperty **propp); - static JSBool obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp); static JSBool obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp); static JSBool obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp); - static JSBool obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + static JSBool obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp); static JSBool obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp); static JSBool obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp); diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 994e5bd2e1ab..51571604c044 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -290,11 +290,7 @@ #define JS_MIN(x,y) ((x)<(y)?(x):(y)) #define JS_MAX(x,y) ((x)>(y)?(x):(y)) -#ifdef _MSC_VER -# include "jscpucfg.h" /* We can't auto-detect MSVC configuration */ -#else -# include "jsautocfg.h" /* Use auto-detected configuration */ -#endif +#include "jscpucfg.h" /* * Define JS_64BIT iff we are building in an environment with 64-bit diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 414c8b62c101..e1683f12302e 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -82,14 +82,14 @@ CrashInJS() * We used to call DebugBreak() on Windows, but amazingly, it causes * the MSVS 2010 debugger not to be able to recover a call stack. */ - *((int *) NULL) = 123; + *((volatile int *) NULL) = 123; exit(3); #elif defined(__APPLE__) /* * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are * trapped. */ - *((int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */ + *((volatile int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */ raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */ #else raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 2ca7797b0094..56b95e662d7c 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -84,8 +84,11 @@ WatchpointMap::watch(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler handler, JSObject *closure) { JS_ASSERT(id == js_CheckForStringIndex(id)); + JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id)); + if (!obj->setWatched(cx)) return false; + Watchpoint w; w.handler = handler; w.closure = closure; diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index daf1d497a313..087fe8e19b2b 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -223,9 +223,9 @@ WeakMap_set(JSContext *cx, uintN argc, Value *vp) obj->setPrivate(map); } - args.thisv() = UndefinedValue(); if (!map->put(key, value)) goto out_of_memory; + args.rval().setUndefined(); return true; out_of_memory: diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 69568c73ac67..8313315d4384 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -235,7 +235,7 @@ Wrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool Value *vp) { // FIXME (bug 596351): Need deal with strict mode. - SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false)); + SET(wrappedObject(wrapper)->setGeneric(cx, id, vp, false)); } bool @@ -877,5 +877,5 @@ SecurityWrapper::objectClassIs(JSObject *obj, ESClassValue classValue, JSC return ret; } -template class SecurityWrapper; -template class SecurityWrapper; +template class js::SecurityWrapper; +template class js::SecurityWrapper; diff --git a/js/src/jsxdrapi.cpp b/js/src/jsxdrapi.cpp index 2be0735114fc..4f3b16649c02 100644 --- a/js/src/jsxdrapi.cpp +++ b/js/src/jsxdrapi.cpp @@ -648,8 +648,9 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) chars = stackChars; } else { /* - * This is very uncommon. Don't use the tempPool arena for this as - * most allocations here will be bigger than tempPool's arenasize. + * This is very uncommon. Don't use the tempLifoAlloc arena for this as + * most allocations here will be bigger than tempLifoAlloc's default + * chunk size. */ chars = (jschar *) cx->malloc_(nchars * sizeof(jschar)); if (!chars) @@ -722,10 +723,9 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) if (xdr->mode == JSXDR_DECODE) { JS_ASSERT(!script->compileAndGo); - if (!js_NewScriptObject(xdr->cx, script)) - return false; + script->u.globalObject = GetCurrentGlobal(xdr->cx); js_CallNewScriptHook(xdr->cx, script, NULL); - Debugger::onNewScript(xdr->cx, script, script->u.object, NULL); + Debugger::onNewScript(xdr->cx, script, NULL); *scriptp = script; } diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index bc06997911ca..374902d8f48e 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1153,8 +1153,7 @@ static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace"; static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/"; static JSObject * -ParseNodeToQName(Parser *parser, JSParseNode *pn, - JSXMLArray *inScopeNSes, JSBool isAttributeName) +ParseNodeToQName(Parser *parser, ParseNode *pn, JSXMLArray *inScopeNSes, JSBool isAttributeName) { JSContext *cx = parser->context; JSLinearString *uri, *prefix; @@ -1282,14 +1281,13 @@ ChompXMLWhitespace(JSContext *cx, JSString *str) } static JSXML * -ParseNodeToXML(Parser *parser, JSParseNode *pn, - JSXMLArray *inScopeNSes, uintN flags) +ParseNodeToXML(Parser *parser, ParseNode *pn, JSXMLArray *inScopeNSes, uintN flags) { JSContext *cx = parser->context; JSXML *xml, *kid, *attr, *attrj; JSLinearString *str; uint32 length, n, i, j; - JSParseNode *pn2, *pn3, *head, **pnp; + ParseNode *pn2, *pn3, *head, **pnp; JSObject *ns; JSObject *qn, *attrjqn; JSXMLClass xml_class; @@ -1765,10 +1763,10 @@ ParseXMLSource(JSContext *cx, JSString *src) JSObject *scopeChain = GetCurrentScopeChain(cx); if (!scopeChain) { cx->free_(chars); - return false; + return NULL; } - JSParseNode *pn = parser.parseXMLText(scopeChain, false); + ParseNode *pn = parser.parseXMLText(scopeChain, false); uintN flags; if (pn && GetXMLSettingFlags(cx, &flags)) { AutoNamespaceArray namespaces(cx); @@ -2043,6 +2041,74 @@ MakeXMLPIString(JSContext *cx, StringBuffer &sb, JSString *name, pi_suffix_ucNstr, 2); } +/* + * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. + * + * This function appends the output into the supplied string buffer. + */ +static bool +EscapeAttributeValueBuffer(JSContext *cx, StringBuffer &sb, JSString *str, JSBool quote) +{ + size_t length = str->length(); + const jschar *start = str->getChars(cx); + if (!start) + return false; + + if (quote && !sb.append('"')) + return false; + + for (const jschar *cp = start, *end = start + length; cp != end; ++cp) { + jschar c = *cp; + switch (c) { + case '"': + if (!sb.append(js_quot_entity_str)) + return false; + break; + case '<': + if (!sb.append(js_lt_entity_str)) + return false; + break; + case '&': + if (!sb.append(js_amp_entity_str)) + return false; + break; + case '\n': + if (!sb.append(" ")) + return false; + break; + case '\r': + if (!sb.append(" ")) + return false; + break; + case '\t': + if (!sb.append(" ")) + return false; + break; + default: + if (!sb.append(c)) + return false; + } + } + + if (quote && !sb.append('"')) + return false; + + return true; +} + +/* + * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. + * + * This function mutates sb, leaving it empty. + */ +static JSFlatString * +EscapeAttributeValue(JSContext *cx, StringBuffer &sb, JSString *str, JSBool quote) +{ + if (!EscapeAttributeValueBuffer(cx, sb, str, quote)) + return NULL; + return sb.finishString(); +} + /* * ECMA-357 10.2.1 17(d-g) pulled out into a common subroutine that appends * equals, a double quote, an attribute value, and a closing double quote. @@ -2052,8 +2118,7 @@ AppendAttributeValue(JSContext *cx, StringBuffer &sb, JSString *valstr) { if (!sb.append('=')) return false; - valstr = js_EscapeAttributeValue(cx, valstr, JS_TRUE); - return valstr && sb.append(valstr); + return EscapeAttributeValueBuffer(cx, sb, valstr, JS_TRUE); } /* @@ -2103,61 +2168,6 @@ EscapeElementValue(JSContext *cx, StringBuffer &sb, JSString *str, uint32 toSour return sb.finishString(); } -/* - * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. - * - * These functions mutate sb, leaving it empty. - */ -static JSFlatString * -EscapeAttributeValue(JSContext *cx, StringBuffer &sb, JSString *str, JSBool quote) -{ - size_t length = str->length(); - const jschar *start = str->getChars(cx); - if (!start) - return NULL; - - if (quote && !sb.append('"')) - return NULL; - - for (const jschar *cp = start, *end = start + length; cp != end; ++cp) { - jschar c = *cp; - switch (c) { - case '"': - if (!sb.append(js_quot_entity_str)) - return NULL; - break; - case '<': - if (!sb.append(js_lt_entity_str)) - return NULL; - break; - case '&': - if (!sb.append(js_amp_entity_str)) - return NULL; - break; - case '\n': - if (!sb.append(" ")) - return NULL; - break; - case '\r': - if (!sb.append(" ")) - return NULL; - break; - case '\t': - if (!sb.append(" ")) - return NULL; - break; - default: - if (!sb.append(c)) - return NULL; - } - } - - if (quote && !sb.append('"')) - return NULL; - - return sb.finishString(); -} - /* 13.3.5.4 [[GetNamespace]]([InScopeNamespaces]) */ static JSObject * GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) @@ -2375,9 +2385,9 @@ namespace_match(const void *a, const void *b) static JSString * XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, - uint32 indentLevel) + uint32 indentLevel, JSBool pretty) { - JSBool pretty, indentKids; + JSBool indentKids; StringBuffer sb(cx); JSString *str; JSLinearString *prefix, *nsuri; @@ -2385,9 +2395,6 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, JSObject *ns, *ns2; AutoNamespaceArray empty(cx), decls(cx), ancdecls(cx); - if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty)) - return NULL; - if (pretty) { if (!sb.appendN(' ', indentLevel & ~TO_SOURCE_FLAG)) return NULL; @@ -2432,7 +2439,7 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, return NULL; } - JSString *kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel); + JSString *kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel, pretty); if (!kidstr || !sb.append(kidstr)) return NULL; ++i; @@ -2451,8 +2458,16 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, return NULL; /* ECMA-357 10.2.1 step 8 onward: handle ToXMLString on an XML element. */ - if (!ancestorNSes) + if (!ancestorNSes) { + // Ensure a namespace with empty strings exists in the initial array, + // otherwise every call to GetNamespace() when running toString() on + // an XML object with no namespace defined will create a new Namespace + // object on every call. + JSObject *emptyns = NewXMLNamespace(cx, cx->runtime->emptyString, cx->runtime->emptyString, JS_FALSE); + if (!emptyns || !XMLARRAY_APPEND(cx, &empty.array, emptyns)) + goto out; ancestorNSes = &empty.array; + } /* Clone in-scope namespaces not in ancestorNSes into decls. */ { @@ -2691,7 +2706,7 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, goto out; } - JSString *kidstr = XMLToXMLString(cx, kid, &ancdecls.array, nextIndentLevel); + JSString *kidstr = XMLToXMLString(cx, kid, &ancdecls.array, nextIndentLevel, pretty); if (!kidstr) goto out; @@ -2756,10 +2771,14 @@ ToXMLString(JSContext *cx, jsval v, uint32 toSourceFlag) return EscapeElementValue(cx, sb, str, toSourceFlag); } + JSBool pretty; + if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty)) + return NULL; + /* Handle non-element cases in this switch, returning from each case. */ JS::Anchor anch(obj); JSXML *xml = reinterpret_cast(obj->getPrivate()); - return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0); + return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0, pretty); } static JSObject * @@ -4591,17 +4610,15 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) if (!prop) { xml = (JSXML *) obj->getPrivate(); if (HasSimpleContent(xml)) { - AutoObjectRooter tvr(cx); - /* * Search in String.prototype to set found whenever * GetXMLFunction returns existing function. */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx); + if (!proto) return false; - JS_ASSERT(tvr.object()); - if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) + if (!js_LookupProperty(cx, proto, funid, &pobj, &prop)) return false; } } @@ -4784,8 +4801,8 @@ xml_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, } static JSBool -xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, - PropertyOp getter, StrictPropertyOp setter, uintN attrs) +xml_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) { if (IsFunctionObject(*v) || getter || setter || (attrs & JSPROP_ENUMERATE) == 0 || @@ -4797,6 +4814,13 @@ xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, return PutProperty(cx, obj, id, false, &tmp); } +static JSBool +xml_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + return xml_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs); +} + static JSBool xml_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs) @@ -4804,14 +4828,14 @@ xml_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v, jsid id; if (!IndexToId(cx, index, &id)) return false; - return xml_defineProperty(cx, obj, id, v, getter, setter, attrs); + return xml_defineGeneric(cx, obj, id, v, getter, setter, attrs); } static JSBool xml_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v, PropertyOp getter, StrictPropertyOp setter, uintN attrs) { - return xml_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); + return xml_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs); } static JSBool @@ -4853,9 +4877,9 @@ xml_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) } static JSBool -xml_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +xml_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict) { - return xml_setGeneric(cx, obj, id, vp, strict); + return xml_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict); } static JSBool @@ -4874,7 +4898,7 @@ xml_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool st } static JSBool -xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +xml_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { JSBool found; if (!HasProperty(cx, obj, IdToJsval(id), &found)) @@ -4884,23 +4908,29 @@ xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return JS_TRUE; } +static JSBool +xml_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return xml_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + static JSBool xml_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return xml_getAttributes(cx, obj, id, attrsp); + return xml_getGenericAttributes(cx, obj, id, attrsp); } static JSBool xml_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return xml_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return xml_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } static JSBool -xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +xml_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { JSBool found; if (!HasProperty(cx, obj, IdToJsval(id), &found)) @@ -4914,23 +4944,29 @@ xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) return true; } +static JSBool +xml_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp) +{ + return xml_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp); +} + static JSBool xml_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp) { jsid id; if (!IndexToId(cx, index, &id)) return false; - return xml_setAttributes(cx, obj, id, attrsp); + return xml_setGenericAttributes(cx, obj, id, attrsp); } static JSBool xml_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp) { - return xml_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); + return xml_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp); } static JSBool -xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +xml_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) { JSXML *xml; jsval idval; @@ -4974,6 +5010,12 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool st return true; } +static JSBool +xml_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict) +{ + return xml_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict); +} + static JSBool xml_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict) { @@ -5004,7 +5046,7 @@ xml_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBoo static JSBool xml_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict) { - return xml_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); + return xml_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } static JSString * @@ -5309,7 +5351,7 @@ JS_FRIEND_DATA(Class) js::XMLClass = { xml_lookupProperty, xml_lookupElement, xml_lookupSpecial, - xml_defineProperty, + xml_defineGeneric, xml_defineProperty, xml_defineElement, xml_defineSpecial, @@ -5317,19 +5359,19 @@ JS_FRIEND_DATA(Class) js::XMLClass = { xml_getProperty, xml_getElement, xml_getSpecial, - xml_setProperty, + xml_setGeneric, xml_setProperty, xml_setElement, xml_setSpecial, - xml_getAttributes, - xml_getAttributes, + xml_getGenericAttributes, + xml_getPropertyAttributes, xml_getElementAttributes, xml_getSpecialAttributes, - xml_setAttributes, - xml_setAttributes, + xml_setGenericAttributes, + xml_setPropertyAttributes, xml_setElementAttributes, xml_setSpecialAttributes, - xml_deleteProperty, + xml_deleteGeneric, xml_deleteProperty, xml_deleteElement, xml_deleteSpecial, @@ -6004,7 +6046,7 @@ NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval) if (!ns) continue; tvr.set(ObjectValue(*ns)); - if (!arrayobj->setProperty(cx, INT_TO_JSID(i), tvr.addr(), false)) + if (!arrayobj->setElement(cx, i, tvr.addr(), false)) return false; } return true; @@ -6765,6 +6807,12 @@ xml_setName(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } +/* Utility function used within xml_setNamespace */ +static JSBool qn_match(const void *xml, const void *qn) { + return qname_identity(((JSXML *)xml)->name, (JSObject *)qn); +} + +/* ECMA-357 13.4.4.36 */ static JSBool xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) { @@ -6793,6 +6841,22 @@ xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) if (!qn) return JS_FALSE; + /* + * Erratum: setting the namespace of an attribute may cause it to duplicate + * an already-existing attribute. To preserve the invariant that there are + * not multiple attributes with the same name, we delete the existing + * attribute so that the mutated attribute will not be a duplicate. + */ + if (xml->xml_class == JSXML_CLASS_ATTRIBUTE && + xml->parent && xml->parent->xml_class == JSXML_CLASS_ELEMENT && + !qn_match(xml, qn)) + { + JSXMLArray *array = &xml->parent->xml_attrs; + uint32 i = XMLArrayFindMember(array, qn, qn_match); + if (i != XML_NOT_FOUND) + XMLArrayDelete(cx, array, i, JS_TRUE); + } + xml->name = qn; /* @@ -7398,7 +7462,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) JS_DefineFunction(cx, global, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR); if (!xmllist) return NULL; - if (!xmllist->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + if (!xmllist->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, ObjectValue(*xmlProto), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { @@ -7501,8 +7565,8 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) if (!ns) return JS_FALSE; v = OBJECT_TO_JSVAL(ns); - if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, v, - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) { + if (!obj->defineSpecial(cx, SpecialId::defaultXMLNamespace(), v, + JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) { return JS_FALSE; } *vp = v; @@ -7520,8 +7584,8 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) return JS_FALSE; JSObject &varobj = cx->fp()->varObj(); - if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns), - JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) { + if (!varobj.defineSpecial(cx, SpecialId::defaultXMLNamespace(), ObjectValue(*ns), + JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) { return JS_FALSE; } return JS_TRUE; @@ -7703,7 +7767,6 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * chain lookup. */ JSObject *target = obj; - AutoObjectRooter tvr(cx); for (;;) { if (!js_GetProperty(cx, target, id, vp)) return false; @@ -7712,7 +7775,6 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) target = target->getProto(); if (target == NULL || !target->isNative()) break; - tvr.setObject(target); } JSXML *xml = (JSXML *) obj->getPrivate(); @@ -7720,11 +7782,11 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return true; /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx); + if (!proto) return false; - JS_ASSERT(tvr.object()); - return tvr.object()->getGeneric(cx, id, vp); + return proto->getGeneric(cx, id, vp); } static JSXML * diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h index 8212ebf39021..ac15ef158edb 100644 --- a/js/src/methodjit/BaseAssembler.h +++ b/js/src/methodjit/BaseAssembler.h @@ -225,6 +225,17 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } #endif + void moveDoubleRegisters(RegisterID data, RegisterID type, Address address, FPRegisterID fpreg) + { +#ifdef JS_CPU_X86 + fastLoadDouble(data, type, fpreg); +#else + /* Store the components, then read it back out as a double. */ + storeValueFromComponents(type, data, address); + loadDouble(address, fpreg); +#endif + } + /* * Move a register pair which may indicate either an int32 or double into fpreg, * converting to double in the int32 case. @@ -1168,6 +1179,29 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } else if (types->hasType(types::Type::Int32Type())) { if (!matches.append(testInt32(Assembler::Equal, address))) return false; + + /* Generate a path to try coercing doubles to integers in place. */ + Jump notDouble = testDouble(Assembler::NotEqual, address); + + Registers tempRegs(Registers::AvailRegs); + RegisterID T1 = tempRegs.takeAnyReg().reg(); + + Registers tempFPRegs(Registers::TempFPRegs); + FPRegisterID FP1 = tempFPRegs.takeAnyReg().fpreg(); + FPRegisterID FP2 = tempFPRegs.takeAnyReg().fpreg(); + + loadDouble(address, FP1); + + JumpList isDouble; + branchConvertDoubleToInt32(FP1, T1, isDouble, FP2); + + storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), T1, address); + + if (!matches.append(jump())) + return false; + + isDouble.linkTo(label(), this); + notDouble.linkTo(label(), this); } if (types->hasType(types::Type::UndefinedType())) { diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 9d036fc33abc..3a89f646ee90 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -112,7 +112,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())), callICs(CompilerAllocPolicy(cx, *thisFromCtor())), equalityICs(CompilerAllocPolicy(cx, *thisFromCtor())), - traceICs(CompilerAllocPolicy(cx, *thisFromCtor())), #endif #if defined JS_POLYIC pics(CompilerAllocPolicy(cx, *thisFromCtor())), @@ -127,14 +126,8 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())), jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())), loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())), - rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())), stubcc(cx, *thisFromCtor(), frame), debugMode_(cx->compartment->debugMode()), -#if defined JS_TRACER - addTraceHints(cx->traceJitEnabled), -#else - addTraceHints(false), -#endif inlining_(false), hasGlobalReallocation(false), oomInVector(false), @@ -143,10 +136,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi applyTricks(NoApplyTricks), pcLengths(NULL) { - /* :FIXME: bug 637856 disabling traceJit if inference is enabled */ - if (cx->typeInferenceEnabled()) - addTraceHints = false; - /* Once a script starts getting really hot we will inline calls in it. */ if (!debugMode() && cx->typeInferenceEnabled() && globalObj && (outerScript->getUseCount() >= USES_BEFORE_INLINING || @@ -762,10 +751,9 @@ mjit::Compiler::generatePrologue() /* * Set locals to undefined, as in initCallFrameLatePrologue. * Skip locals which aren't closed and are known to be defined before used, - * :FIXME: bug 604541: write undefined if we might be using the tracer, so it works. */ for (uint32 i = 0; i < script->nfixed; i++) { - if (analysis->localHasUseBeforeDef(i) || addTraceHints) { + if (analysis->localHasUseBeforeDef(i)) { Address local(JSFrameReg, sizeof(StackFrame) + i * sizeof(Value)); masm.storeValue(UndefinedValue(), local); } @@ -970,13 +958,11 @@ mjit::Compiler::finishThisUp(JITScript **jitp) sizeof(NativeMapEntry) * nNmapLive + sizeof(InlineFrame) * inlineFrames.length() + sizeof(CallSite) * callSites.length() + - sizeof(JSObject *) * rootedObjects.length() + #if defined JS_MONOIC sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() + sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() + sizeof(ic::CallICInfo) * callICs.length() + sizeof(ic::EqualityICInfo) * equalityICs.length() + - sizeof(ic::TraceICInfo) * traceICs.length() + #endif #if defined JS_POLYIC sizeof(ic::PICInfo) * pics.length() + @@ -1102,13 +1088,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp) stubCode.patch(from.loopPatch.codePatch, result + codeOffset); } - /* Build the list of objects rooted by the script. */ - JSObject **jitRooted = (JSObject **)cursor; - jit->nRootedObjects = rootedObjects.length(); - cursor += sizeof(JSObject *) * jit->nRootedObjects; - for (size_t i = 0; i < jit->nRootedObjects; i++) - jitRooted[i] = rootedObjects[i]; - #if defined JS_MONOIC JS_INIT_CLIST(&jit->callers); @@ -1250,43 +1229,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp) stubCode.patch(equalityICs[i].addrLabel, &jitEqualityICs[i]); } - - ic::TraceICInfo *jitTraceICs = (ic::TraceICInfo *)cursor; - jit->nTraceICs = traceICs.length(); - cursor += sizeof(ic::TraceICInfo) * jit->nTraceICs; - for (size_t i = 0; i < jit->nTraceICs; i++) { - jitTraceICs[i].initialized = traceICs[i].initialized; - if (!traceICs[i].initialized) - continue; - - if (traceICs[i].fastTrampoline) { - jitTraceICs[i].fastTarget = stubCode.locationOf(traceICs[i].trampolineStart); - } else { - uint32 offs = uint32(traceICs[i].jumpTarget - script->code); - JS_ASSERT(jumpMap[offs].isSet()); - jitTraceICs[i].fastTarget = fullCode.locationOf(jumpMap[offs]); - } - jitTraceICs[i].slowTarget = stubCode.locationOf(traceICs[i].trampolineStart); - - jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint); - jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry); - jitTraceICs[i].traceData = NULL; -#ifdef DEBUG - jitTraceICs[i].jumpTargetPC = traceICs[i].jumpTarget; -#endif - - jitTraceICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet(); - if (traceICs[i].slowTraceHint.isSet()) - jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get()); -#ifdef JS_TRACER - uint32 hotloop = GetHotloop(cx); - uint32 prevCount = cx->compartment->backEdgeCount(traceICs[i].jumpTarget); - jitTraceICs[i].loopCounterStart = hotloop; - jitTraceICs[i].loopCounter = hotloop < prevCount ? 1 : hotloop - prevCount; -#endif - - stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]); - } #endif /* JS_MONOIC */ for (size_t i = 0; i < callPatches.length(); i++) { @@ -1499,7 +1441,7 @@ public: ptrdiff_t nextOffset; while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) { offset = nextOffset; - JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn); + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE || type == SRC_NEWLINE) { if (type == SRC_SETLINE) lineno = js_GetSrcNoteOffset(sn, 0); @@ -4702,22 +4644,11 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom) return true; } - /* - * Bake in String.prototype. This is safe because of compileAndGo. - * We must pass an explicit scope chain only because JSD calls into - * here via the recompiler with a dummy context, and we need to use - * the global object for the script we are now compiling. - */ - JSObject *obj; - if (!js_GetClassPrototype(cx, globalObj, JSProto_String, &obj)) + /* Bake in String.prototype. This is safe because of compileAndGo. */ + JSObject *obj = globalObj->getOrCreateStringPrototype(cx); + if (!obj) return false; - /* - * Root the proto, since JS_ClearScope might overwrite the global object's - * copy. - */ - rootedObjects.append(obj); - /* Force into a register because getprop won't expect a constant. */ RegisterID reg = frame.allocReg(); @@ -5653,13 +5584,20 @@ mjit::Compiler::jsop_this() if (script->function() && !script->strictModeCode) { FrameEntry *thisFe = frame.peek(-1); - /* - * We don't inline calls to scripts which use 'this' but might require - * 'this' to be wrapped. - */ - JS_ASSERT(!thisFe->isNotType(JSVAL_TYPE_OBJECT)); - if (!thisFe->isType(JSVAL_TYPE_OBJECT)) { + /* + * Watch out for an obscure case where we don't know we are pushing + * an object: the script has not yet had a 'this' value assigned, + * so no pushed 'this' type has been inferred. Don't mark the type + * as known in this case, preserving the invariant that compiler + * types reflect inferred types. + */ + if (cx->typeInferenceEnabled() && knownPushedType(0) != JSVAL_TYPE_OBJECT) { + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::This, REJOIN_FALLTHROUGH); + return; + } + JSValueType type = cx->typeInferenceEnabled() ? types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN; @@ -5671,16 +5609,6 @@ mjit::Compiler::jsop_this() stubcc.rejoin(Changes(1)); } - /* - * Watch out for an obscure case where we don't know we are pushing - * an object: the script has not yet had a 'this' value assigned, - * so no pushed 'this' type has been inferred. Don't mark the type - * as known in this case, preserving the invariant that compiler - * types reflect inferred types. - */ - if (cx->typeInferenceEnabled() && knownPushedType(0) != JSVAL_TYPE_OBJECT) - return; - // Now we know that |this| is an object. frame.pop(); frame.learnThisIsObject(type != JSVAL_TYPE_OBJECT); @@ -6836,150 +6764,50 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow, bool *tramp consistent = frame.consistentRegisters(target); } - if (!addTraceHints || target >= PC || - (JSOp(*target) != JSOP_TRACE && JSOp(*target) != JSOP_NOTRACE) -#ifdef JS_MONOIC - || GET_UINT16(target) == BAD_TRACEIC_INDEX -#endif - ) - { - if (!lvtarget || lvtarget->synced()) { - JS_ASSERT(consistent); - if (!jumpInScript(j, target)) - return false; - if (slow && !stubcc.jumpInScript(*slow, target)) - return false; - } else { - if (consistent) { - if (!jumpInScript(j, target)) - return false; - } else { - /* - * Make a trampoline to issue remaining loads for the register - * state at target. - */ - Label start = stubcc.masm.label(); - stubcc.linkExitDirect(j, start); - frame.prepareForJump(target, stubcc.masm, false); - if (!stubcc.jumpInScript(stubcc.masm.jump(), target)) - return false; - if (trampoline) - *trampoline = true; - if (pcLengths) { - /* - * This is OOL code but will usually be executed, so track - * it in the CODE_LENGTH for the opcode. - */ - uint32 offset = ssa.frameLength(a->inlineIndex) + PC - script->code; - size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start); - pcLengths[offset].codeLength += length; - } - } - - if (slow) { - slow->linkTo(stubcc.masm.label(), &stubcc.masm); - frame.prepareForJump(target, stubcc.masm, true); - if (!stubcc.jumpInScript(stubcc.masm.jump(), target)) - return false; - } - } - - if (target < PC) - return finishLoop(target); - return true; - } - - /* The trampoline should not be specified if we need to generate a trace IC. */ - JS_ASSERT(!trampoline); - -#ifndef JS_TRACER - JS_NOT_REACHED("Bad addTraceHints"); - return false; -#else - -# if JS_MONOIC - TraceGenInfo ic; - - ic.initialized = true; - ic.stubEntry = stubcc.masm.label(); - ic.traceHint = j; - if (slow) - ic.slowTraceHint = *slow; - - uint16 index = GET_UINT16(target); - if (traceICs.length() <= index) - if (!traceICs.resize(index+1)) + if (!lvtarget || lvtarget->synced()) { + JS_ASSERT(consistent); + if (!jumpInScript(j, target)) return false; -# endif - - Label traceStart = stubcc.masm.label(); - - stubcc.linkExitDirect(j, traceStart); - if (slow) - slow->linkTo(traceStart, &stubcc.masm); - -# if JS_MONOIC - ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); - - Jump nonzero = stubcc.masm.branchSub32(Assembler::NonZero, Imm32(1), - Address(Registers::ArgReg1, - offsetof(TraceICInfo, loopCounter))); -# endif - - /* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */ - { - jsbytecode* pc = PC; - PC = target; - - OOL_STUBCALL(stubs::InvokeTracer, REJOIN_NONE); - - PC = pc; - } - - Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg, - Registers::ReturnReg); - if (!cx->typeInferenceEnabled()) - stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg); - stubcc.masm.jump(Registers::ReturnReg); - no.linkTo(stubcc.masm.label(), &stubcc.masm); - -#ifdef JS_MONOIC - nonzero.linkTo(stubcc.masm.label(), &stubcc.masm); - - ic.jumpTarget = target; - ic.fastTrampoline = !consistent; - ic.trampolineStart = stubcc.masm.label(); - - traceICs[index] = ic; -#endif - - /* - * Jump past the tracer call if the trace has been blacklisted. We still make - * a trace IC in such cases, in case it is un-blacklisted later. - */ - if (JSOp(*target) == JSOP_NOTRACE) { + if (slow && !stubcc.jumpInScript(*slow, target)) + return false; + } else { if (consistent) { if (!jumpInScript(j, target)) return false; } else { - stubcc.linkExitDirect(j, stubcc.masm.label()); + /* + * Make a trampoline to issue remaining loads for the register + * state at target. + */ + Label start = stubcc.masm.label(); + stubcc.linkExitDirect(j, start); + frame.prepareForJump(target, stubcc.masm, false); + if (!stubcc.jumpInScript(stubcc.masm.jump(), target)) + return false; + if (trampoline) + *trampoline = true; + if (pcLengths) { + /* + * This is OOL code but will usually be executed, so track + * it in the CODE_LENGTH for the opcode. + */ + uint32 offset = ssa.frameLength(a->inlineIndex) + PC - script->code; + size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start); + pcLengths[offset].codeLength += length; + } } - if (slow) + + if (slow) { slow->linkTo(stubcc.masm.label(), &stubcc.masm); + frame.prepareForJump(target, stubcc.masm, true); + if (!stubcc.jumpInScript(stubcc.masm.jump(), target)) + return false; + } } - /* - * Reload any registers needed at the head of the loop. Note that we didn't - * need to do syncing before calling InvokeTracer, as state is always synced - * on backwards jumps. - */ - frame.prepareForJump(target, stubcc.masm, true); - - if (!stubcc.jumpInScript(stubcc.masm.jump(), target)) - return false; -#endif - - return finishLoop(target); + if (target < PC) + return finishLoop(target); + return true; } void @@ -7531,39 +7359,6 @@ mjit::Compiler::pushAddressMaybeBarrier(Address address, JSValueType type, bool return testBarrier(typeReg, dataReg, testUndefined); } -MaybeJump -mjit::Compiler::trySingleTypeTest(types::TypeSet *types, RegisterID typeReg) -{ - /* - * If a type set we have a barrier on is monomorphic, generate a single - * jump taken if a type register has a match. This doesn't handle type sets - * containing objects, as these require two jumps regardless (test for - * object, then test the type of the object). - */ - MaybeJump res; - - switch (types->getKnownTypeTag(cx)) { - case JSVAL_TYPE_INT32: - res.setJump(masm.testInt32(Assembler::NotEqual, typeReg)); - return res; - - case JSVAL_TYPE_DOUBLE: - res.setJump(masm.testNumber(Assembler::NotEqual, typeReg)); - return res; - - case JSVAL_TYPE_BOOLEAN: - res.setJump(masm.testBoolean(Assembler::NotEqual, typeReg)); - return res; - - case JSVAL_TYPE_STRING: - res.setJump(masm.testString(Assembler::NotEqual, typeReg)); - return res; - - default: - return res; - } -} - JSC::MacroAssembler::Jump mjit::Compiler::addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterID dataReg) { @@ -7575,11 +7370,32 @@ mjit::Compiler::addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterI Vector matches(CompilerAllocPolicy(cx, *this)); - if (types->hasType(types::Type::Int32Type())) + if (types->hasType(types::Type::DoubleType())) { + matches.append(masm.testNumber(Assembler::Equal, typeReg)); + } else if (types->hasType(types::Type::Int32Type())) { matches.append(masm.testInt32(Assembler::Equal, typeReg)); - if (types->hasType(types::Type::DoubleType())) - matches.append(masm.testDouble(Assembler::Equal, typeReg)); + /* Generate a path to try coercing doubles to integers in place. */ + Jump notDouble = masm.testDouble(Assembler::NotEqual, typeReg); + + FPRegisterID fpTemp = frame.getScratchFPReg(); + masm.moveDoubleRegisters(dataReg, typeReg, frame.addressOfTop(), fpTemp); + + JumpList isDouble; + masm.branchConvertDoubleToInt32(fpTemp, dataReg, isDouble, Registers::FPConversionTemp); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + + frame.restoreScratchFPReg(fpTemp); + + matches.append(masm.jump()); + + isDouble.linkTo(masm.label(), &masm); + + masm.breakDouble(fpTemp, typeReg, dataReg); + frame.restoreScratchFPReg(fpTemp); + + notDouble.linkTo(masm.label(), &masm); + } if (types->hasType(types::Type::UndefinedType())) matches.append(masm.testUndefined(Assembler::Equal, typeReg)); @@ -7659,9 +7475,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg, /* Cannot have type barriers when the result of the operation is already unknown. */ JS_ASSERT(!types->unknown()); - state.jump = trySingleTypeTest(types, typeReg); - if (!state.jump.isSet()) - state.jump.setJump(addTypeTest(types, typeReg, dataReg)); + state.jump.setJump(addTypeTest(types, typeReg, dataReg)); return state; } diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 9c39688f5a65..3376bbb25bb7 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -125,19 +125,6 @@ class Compiler : public BaseCompiler Assembler::Condition cond; JSC::MacroAssembler::RegisterID tempReg; }; - - struct TraceGenInfo { - bool initialized; - Label stubEntry; - DataLabelPtr addrLabel; - jsbytecode *jumpTarget; - bool fastTrampoline; - Label trampolineStart; - Jump traceHint; - MaybeJump slowTraceHint; - - TraceGenInfo() : initialized(false) {} - }; /* InlineFrameAssembler wants to see this. */ public: @@ -426,7 +413,6 @@ private: js::Vector setGlobalNames; js::Vector callICs; js::Vector equalityICs; - js::Vector traceICs; #endif #if defined JS_POLYIC js::Vector pics; @@ -441,7 +427,6 @@ private: js::Vector jumpTables; js::Vector jumpTableOffsets; js::Vector loopEntries; - js::Vector rootedObjects; StubCompiler stubcc; Label invokeLabel; Label arityLabel; @@ -452,7 +437,6 @@ private: Jump argsCheckJump; #endif bool debugMode_; - bool addTraceHints; bool inlining_; bool hasGlobalReallocation; bool oomInVector; // True if we have OOM'd appending to a vector. @@ -549,7 +533,6 @@ private: RegisterID dataReg; }; - MaybeJump trySingleTypeTest(types::TypeSet *types, RegisterID typeReg); Jump addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterID dataReg); BarrierState pushAddressMaybeBarrier(Address address, JSValueType type, bool reuseBase, bool testUndefined = false); diff --git a/js/src/methodjit/FastArithmetic.cpp b/js/src/methodjit/FastArithmetic.cpp index cf2786b9e5f0..27f88956403a 100644 --- a/js/src/methodjit/FastArithmetic.cpp +++ b/js/src/methodjit/FastArithmetic.cpp @@ -1162,7 +1162,7 @@ mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, ic.stubEntry = stubEntry; ic.stub = stub; - bool useIC = (!addTraceHints || target >= PC) && !a->parent; + bool useIC = !a->parent; /* Call the IC stub, which may generate a fast path. */ if (useIC) { diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index d15926be0f7e..7de5a5556b84 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -187,26 +187,6 @@ mjit::Compiler::jsop_bitop(JSOp op) return; } - bool lhsIntOrDouble = !(lhs->isNotType(JSVAL_TYPE_DOUBLE) && - lhs->isNotType(JSVAL_TYPE_INT32)); - - /* Fast-path double to int conversion. */ - if (!lhs->isConstant() && rhs->isConstant() && lhsIntOrDouble && - rhs->isType(JSVAL_TYPE_INT32) && rhs->getValue().toInt32() == 0 && - (op == JSOP_BITOR || op == JSOP_LSH)) { - ensureInteger(lhs, Uses(2)); - RegisterID reg = frame.ownRegForData(lhs); - - stubcc.leave(); - OOL_STUBCALL(stub, REJOIN_FALLTHROUGH); - - frame.popn(2); - frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); - - stubcc.rejoin(Changes(1)); - return; - } - /* Convert a double RHS to integer if it's constant for the test below. */ if (rhs->isConstant() && rhs->getValue().isDouble()) rhs->convertConstantDoubleToInt32(cx); @@ -282,7 +262,7 @@ mjit::Compiler::jsop_bitop(JSOp op) masm.and32(Imm32(rhsInt), reg); else if (op == JSOP_BITXOR) masm.xor32(Imm32(rhsInt), reg); - else + else if (rhsInt != 0) masm.or32(Imm32(rhsInt), reg); } else if (frame.shouldAvoidDataRemat(rhs)) { Address rhsAddr = masm.payloadOf(frame.addressOf(rhs)); @@ -1404,7 +1384,8 @@ mjit::Compiler::jsop_setelem_typed(int atype) objReg = frame.copyDataIntoReg(obj); // Bounds check. - Jump lengthGuard = masm.guardArrayExtent(TypedArray::lengthOffset(), + int lengthOffset = TypedArray::lengthOffset() + offsetof(jsval_layout, s.payload); + Jump lengthGuard = masm.guardArrayExtent(lengthOffset, objReg, key, Assembler::BelowOrEqual); stubcc.linkExit(lengthGuard, Uses(3)); @@ -1932,7 +1913,8 @@ mjit::Compiler::jsop_getelem_typed(int atype) objReg = frame.copyDataIntoReg(obj); // Bounds check. - Jump lengthGuard = masm.guardArrayExtent(TypedArray::lengthOffset(), + int lengthOffset = TypedArray::lengthOffset() + offsetof(jsval_layout, s.payload); + Jump lengthGuard = masm.guardArrayExtent(lengthOffset, objReg, key, Assembler::BelowOrEqual); stubcc.linkExit(lengthGuard, Uses(2)); @@ -1991,7 +1973,6 @@ mjit::Compiler::jsop_getelem_typed(int atype) frame.popn(2); - BarrierState barrier; if (dataReg.isFPReg()) { frame.pushDouble(dataReg.fpreg()); } else if (typeReg.isSet()) { @@ -2002,8 +1983,6 @@ mjit::Compiler::jsop_getelem_typed(int atype) } stubcc.rejoin(Changes(2)); - finishBarrier(barrier, REJOIN_FALLTHROUGH, 0); - return true; } #endif /* JS_METHODJIT_TYPED_ARRAY */ @@ -2027,7 +2006,12 @@ mjit::Compiler::jsop_getelem(bool isCall) if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32) && !isCall) { types::TypeSet *types = analysis->poppedTypes(PC, 1); if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) { - // Inline arguments path. + // Inline arguments path. This path can access non-canonical args + // if fun->nargs != 0, so we require that the script never has any + // of its arguments directly modified. Note that the canonical and + // formal arg may not be the exact same value if we coerced a + // double actual into an int32 formal from a type barrier at entry, + // but this is ok as the underlying number is the same. jsop_getelem_args(); return true; } diff --git a/js/src/methodjit/FrameState.cpp b/js/src/methodjit/FrameState.cpp index c0bd80da60d0..431b16828b26 100644 --- a/js/src/methodjit/FrameState.cpp +++ b/js/src/methodjit/FrameState.cpp @@ -195,6 +195,36 @@ FrameState::takeReg(AnyRegisterID reg) } } +JSC::MacroAssembler::FPRegisterID +FrameState::getScratchFPReg() +{ + if (freeRegs.hasRegInMask(Registers::TempFPRegs)) { + FPRegisterID reg = freeRegs.takeAnyReg(Registers::TempFPRegs).fpreg(); + freeRegs.putReg(reg); + return reg; + } + + Registers regs(Registers::TempFPRegs); + FPRegisterID reg; + + do { + reg = regs.takeAnyReg().fpreg(); + } while (!regstate(reg).fe()); + + masm.storeDouble(reg, addressOf(regstate(reg).fe())); + + return reg; +} + +void +FrameState::restoreScratchFPReg(FPRegisterID reg) +{ + if (freeRegs.hasReg(reg)) + return; + + masm.loadDouble(addressOf(regstate(reg).fe()), reg); +} + #ifdef DEBUG const char * FrameState::entryName(const FrameEntry *fe) const @@ -1325,11 +1355,7 @@ FrameState::sync(Assembler &masm, Uses uses) const Registers avail(freeRegs.freeMask & Registers::AvailRegs); Registers temp(Registers::TempAnyRegs); - FrameEntry *bottom = (cx->typeInferenceEnabled() || cx->compartment->debugMode()) - ? entries - : a->sp - uses.nuses; - - for (FrameEntry *fe = a->sp - 1; fe >= bottom; fe--) { + for (FrameEntry *fe = a->sp - 1; fe >= entries; fe--) { if (!fe->isTracked()) continue; @@ -1379,7 +1405,7 @@ FrameState::sync(Assembler &masm, Uses uses) const /* Fall back to a slower sync algorithm if load required. */ if ((!fe->type.synced() && backing->type.inMemory()) || (!fe->data.synced() && backing->data.inMemory())) { - syncFancy(masm, avail, fe, bottom); + syncFancy(masm, avail, fe, entries); return; } #endif @@ -1460,11 +1486,7 @@ FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore) uint32 maxvisits = tracker.nentries; - FrameEntry *bottom = (cx->typeInferenceEnabled() || cx->compartment->debugMode()) - ? entries - : a->sp - uses.nuses; - - for (FrameEntry *fe = a->sp - 1; fe >= bottom && maxvisits; fe--) { + for (FrameEntry *fe = a->sp - 1; fe >= entries && maxvisits; fe--) { if (!fe->isTracked()) continue; diff --git a/js/src/methodjit/FrameState.h b/js/src/methodjit/FrameState.h index fa84ed72fe50..a472b624fad4 100644 --- a/js/src/methodjit/FrameState.h +++ b/js/src/methodjit/FrameState.h @@ -613,6 +613,14 @@ class FrameState */ void takeReg(AnyRegisterID reg); + /* + * Gets an FP register which the compiler does not own but can freely write + * over. Can only be used in the inline path, and must be matched with a + * restoreScratchFPReg. (Emits sync/restore code if the reg is in use). + */ + FPRegisterID getScratchFPReg(); + void restoreScratchFPReg(FPRegisterID reg); + /* * Returns a FrameEntry * for a slot on the operation stack. */ diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index 67a69acc4da5..8fefae36e02b 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -528,21 +528,7 @@ js_InternalThrow(VMFrame &f) // or SplatApplyArgs threw an exception. RemoveOrphanedNative(cx, f.fp()); - // It's possible that from within RunTracer(), Interpret() returned with - // an error and finished the frame (i.e., called ScriptEpilogue), but has - // not yet performed an inline return. - // - // In this case, RunTracer() has no choice but to propagate the error - // up to the method JIT, and thus to this function. But ScriptEpilogue() - // has already been called. Detect this, and avoid double-finishing the - // frame. See HandleErrorInExcessFrame() and bug 624100. - if (f.fp()->finishedInInterpreter()) { - // If it's the last frame, just propagate the failure up again. - if (f.fp() == f.entryfp) - return NULL; - - InlineReturn(f); - } + JS_ASSERT(!f.fp()->finishedInInterpreter()); // Make sure sp is up to date. JS_ASSERT(&cx->regs() == &f.regs); @@ -611,50 +597,46 @@ js_InternalThrow(VMFrame &f) StackFrame *fp = cx->fp(); JSScript *script = fp->script(); - if (cx->typeInferenceEnabled() || !fp->jit()) { - /* - * Fall back to EnterMethodJIT and finish the frame in the interpreter. - * With type inference enabled, we may wipe out all JIT code on the - * stack without patching ncode values to jump to the interpreter, and - * thus can only enter JIT code via EnterMethodJIT (which overwrites - * its entry frame's ncode). See ClearAllFrames. - */ - cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished); - - if (!script->ensureRanAnalysis(cx, NULL)) { - js_ReportOutOfMemory(cx); - return NULL; - } - - analyze::AutoEnterAnalysis enter(cx); - - cx->regs().pc = pc; - cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth; - - /* - * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go - * back into the interpreter with a pending exception. This will cause - * it to immediately rethrow. - */ - if (cx->isExceptionPending()) { - JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK); - JSObject *obj = script->getObject(GET_SLOTNO(pc)); - Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj); - SetValueRangeToUndefined(cx->regs().sp, vp); - cx->regs().sp = vp; - JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION); - cx->regs().sp[0] = cx->getPendingException(); - cx->clearPendingException(); - cx->regs().sp++; - cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH; - } - - *f.oldregs = f.regs; + /* + * Fall back to EnterMethodJIT and finish the frame in the interpreter. + * With type inference enabled, we may wipe out all JIT code on the + * stack without patching ncode values to jump to the interpreter, and + * thus can only enter JIT code via EnterMethodJIT (which overwrites + * its entry frame's ncode). See ClearAllFrames. + */ + cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished); + if (!script->ensureRanAnalysis(cx, NULL)) { + js_ReportOutOfMemory(cx); return NULL; } - return script->nativeCodeForPC(fp->isConstructing(), pc); + analyze::AutoEnterAnalysis enter(cx); + + cx->regs().pc = pc; + cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth; + + /* + * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go + * back into the interpreter with a pending exception. This will cause + * it to immediately rethrow. + */ + if (cx->isExceptionPending()) { + JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK); + JSObject *obj = script->getObject(GET_SLOTNO(pc)); + Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj); + SetValueRangeToUndefined(cx->regs().sp, vp); + cx->regs().sp = vp; + JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION); + cx->regs().sp[0] = cx->getPendingException(); + cx->clearPendingException(); + cx->regs().sp++; + cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH; + } + + *f.oldregs = f.regs; + + return NULL; } void JS_FASTCALL @@ -696,481 +678,8 @@ stubs::ScriptProbeOnlyEpilogue(VMFrame &f) Probes::exitJSFun(f.cx, f.fp()->fun(), f.fp()->script()); } -#ifdef JS_TRACER - -/* - * Called when an error is in progress and the topmost frame could not handle - * it. This will unwind to a given frame, or find and align to an exception - * handler in the process. - */ -static inline bool -HandleErrorInExcessFrame(VMFrame &f, StackFrame *stopFp, bool searchedTopmostFrame = true) -{ - JSContext *cx = f.cx; - - /* - * Callers of this called either Interpret() or JaegerShot(), which would - * have searched for exception handlers already. If we see stopFp, just - * return false. Otherwise, pop the frame, since it's guaranteed useless. - * - * Note that this also guarantees ScriptEpilogue() has been called. - */ - StackFrame *fp = cx->fp(); - if (searchedTopmostFrame) { - /* - * This is a special case meaning that fp->finishedInInterpreter() is - * true. If so, and fp == stopFp, our only choice is to propagate this - * error up, back to the method JIT, and then to js_InternalThrow, - * where this becomes a special case. See the comment there and bug - * 624100. - */ - if (fp == stopFp) - return false; - - /* - * Otherwise, the protocol here (like Invoke) is to assume that the - * execution mode finished the frame, and to just pop it. - */ - InlineReturn(f); - } - - /* Remove the bottom frame. */ - bool returnOK = false; - for (;;) { - fp = cx->fp(); - - /* Clear imacros. */ - if (fp->hasImacropc()) { - cx->regs().pc = fp->imacropc(); - fp->clearImacropc(); - } - JS_ASSERT(!fp->hasImacropc()); - - /* If there's an exception and a handler, set the pc and leave. */ - if (cx->isExceptionPending()) { - jsbytecode *pc = FindExceptionHandler(cx); - if (pc) { - cx->regs().pc = pc; - returnOK = true; - break; - } - } - - /* Don't unwind if this was the entry frame. */ - if (fp == stopFp) - break; - - /* Unwind and return. */ - returnOK &= UnwindScope(cx, 0, returnOK || cx->isExceptionPending()); - returnOK = ScriptEpilogue(cx, fp, returnOK); - InlineReturn(f); - } - - JS_ASSERT(&f.regs == &cx->regs()); - JS_ASSERT_IF(!returnOK, cx->fp() == stopFp); - - return returnOK; -} - -/* Returns whether the current PC has method JIT'd code. */ -static inline void * -AtSafePoint(JSContext *cx) -{ - StackFrame *fp = cx->fp(); - if (fp->hasImacropc()) - return NULL; - - JSScript *script = fp->script(); - return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc); -} - -/* - * Interprets until either a safe point is reached that has method JIT'd - * code, or the current frame tries to return. - */ -static inline JSBool -PartialInterpret(VMFrame &f) -{ - JSContext *cx = f.cx; - StackFrame *fp = cx->fp(); - -#ifdef DEBUG - JSScript *script = fp->script(); - JS_ASSERT(!fp->finishedInInterpreter()); - JS_ASSERT(fp->hasImacropc() || - !script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc)); -#endif - - JSBool ok = JS_TRUE; - ok = Interpret(cx, fp, JSINTERP_SAFEPOINT); - - return ok; -} - JS_STATIC_ASSERT(JSOP_NOP == 0); -/* - * Returns whether the current PC would return, or if the frame has already - * been completed. This distinction avoids re-entering the interpreter or JIT - * to complete a JSOP_RETURN. Instead, that edge case is handled in - * HandleFinishedFrame. We could consider reducing complexity, and making this - * function return only "finishedInInterpreter", and always using the full VM - * machinery to fully finish frames. - */ -static inline bool -FrameIsFinished(JSContext *cx) -{ - JSOp op = JSOp(*cx->regs().pc); - return (op == JSOP_RETURN || - op == JSOP_RETRVAL || - op == JSOP_STOP) - ? true - : cx->fp()->finishedInInterpreter(); -} - -/* - * Given a frame that is about to return, make sure its return value and - * activation objects are fixed up. Then, pop the frame and advance the - * current PC. Note that while we could enter the JIT at this point, the - * logic would still be necessary for the interpreter, so it's easier - * (and faster) to finish frames in C++ even if at a safe point here. - */ -static bool -HandleFinishedFrame(VMFrame &f, StackFrame *entryFrame) -{ - JSContext *cx = f.cx; - - JS_ASSERT(FrameIsFinished(cx)); - - /* - * This is the most difficult and complicated piece of the tracer - * integration, and historically has been very buggy. The problem is that - * although this frame has to be popped (see RemoveExcessFrames), it may - * be at a JSOP_RETURN opcode, and it might not have ever been executed. - * That is, fp->rval may not be set to the top of the stack, and if it - * has, the stack has already been decremented. Note that fp->rval is not - * the only problem: the epilogue may never have been executed. - * - * Here are the edge cases and whether the frame has been exited cleanly: - * 1. No: A trace exited directly before a RETURN op, and the - * interpreter never ran. - * 2. Yes: The interpreter exited cleanly. - * 3. No: The interpreter exited on a safe point. LEAVE_ON_SAFE_POINT - * is not used in between JSOP_RETURN and advancing the PC, - * therefore, it cannot have been run if at a safe point. - * 4. No: Somewhere in the RunTracer call tree, we removed a frame, - * and we returned to a JSOP_RETURN opcode. Note carefully - * that in this situation, FrameIsFinished() returns true! - * 5. Yes: The function exited in the method JIT, during - * FinishExcessFrames() However, in this case, we'll never enter - * HandleFinishedFrame(): we always immediately pop JIT'd frames. - * - * Since the only scenario where this fixup is NOT needed is a normal exit - * from the interpreter, we can cleanly check for this scenario by checking - * a bit it sets in the frame. - */ - bool returnOK = true; - if (!cx->fp()->finishedInInterpreter()) { - if (JSOp(*cx->regs().pc) == JSOP_RETURN) - cx->fp()->setReturnValue(f.regs.sp[-1]); - - returnOK = ScriptEpilogue(cx, cx->fp(), true); - } - - if (cx->fp() != entryFrame) { - InlineReturn(f); - } - - return returnOK; -} - -/* - * Given a frame newer than the entry frame, try to finish it. If it's at a - * return position, pop the frame. If it's at a safe point, execute it in - * Jaeger code. Otherwise, try to interpret until a safe point. - * - * While this function is guaranteed to make progress, it may not actually - * finish or pop the current frame. It can either: - * 1) Finalize a finished frame, or - * 2) Finish and finalize the frame in the Method JIT, or - * 3) Interpret, which can: - * a) Propagate an error, or - * b) Finish the frame, but not finalize it, or - * c) Abruptly leave at any point in the frame, or in a newer frame - * pushed by a call, that has method JIT'd code. - */ -static bool -EvaluateExcessFrame(VMFrame &f, StackFrame *entryFrame) -{ - JSContext *cx = f.cx; - StackFrame *fp = cx->fp(); - - /* - * A "finished" frame is when the interpreter rested on a STOP, - * RETURN, RETRVAL, etc. We check for finished frames BEFORE looking - * for a safe point. If the frame was finished, we could have already - * called ScriptEpilogue(), and entering the JIT could call it twice. - */ - if (!fp->hasImacropc() && FrameIsFinished(cx)) - return HandleFinishedFrame(f, entryFrame); - - if (void *ncode = AtSafePoint(cx)) { - if (!JaegerShotAtSafePoint(cx, ncode, false)) - return false; - InlineReturn(f); - return true; - } - - return PartialInterpret(f); -} - -/* - * Evaluate frames newer than the entry frame until all are gone. This will - * always leave f.regs.fp == entryFrame. - */ -static bool -FinishExcessFrames(VMFrame &f, StackFrame *entryFrame) -{ - JSContext *cx = f.cx; - - while (cx->fp() != entryFrame || entryFrame->hasImacropc()) { - if (!EvaluateExcessFrame(f, entryFrame)) { - if (!HandleErrorInExcessFrame(f, entryFrame)) - return false; - } - } - - return true; -} - -#if defined JS_MONOIC -static void -UpdateTraceHintSingle(Repatcher &repatcher, JSC::CodeLocationJump jump, JSC::CodeLocationLabel target) -{ - /* - * Hack: The value that will be patched is before the executable address, - * so to get protection right, just unprotect the general region around - * the jump. - */ - repatcher.relink(jump, target); - - JaegerSpew(JSpew_PICs, "relinking trace hint %p to %p\n", - jump.executableAddress(), target.executableAddress()); -} - -static void -DisableTraceHint(JITScript *jit, ic::TraceICInfo &ic) -{ - Repatcher repatcher(jit); - UpdateTraceHintSingle(repatcher, ic.traceHint, ic.fastTarget); - - if (ic.hasSlowTraceHint) - UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.slowTarget); -} - -static void -ResetTraceHintAt(JSScript *script, js::mjit::JITScript *jit, - jsbytecode *pc, uint16_t index, bool full) -{ - if (index >= jit->nTraceICs) - return; - ic::TraceICInfo &ic = jit->traceICs()[index]; - if (!ic.initialized) - return; - - JS_ASSERT(ic.jumpTargetPC == pc); - - JaegerSpew(JSpew_PICs, "Enabling trace IC %u in script %p\n", index, - static_cast(script)); - - Repatcher repatcher(jit); - - UpdateTraceHintSingle(repatcher, ic.traceHint, ic.stubEntry); - - if (ic.hasSlowTraceHint) - UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.stubEntry); - - if (full) { - ic.traceData = NULL; - ic.loopCounterStart = 1; - ic.loopCounter = ic.loopCounterStart; - } -} -#endif - -void -js::mjit::ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full) -{ -#if JS_MONOIC - if (script->jitNormal) - ResetTraceHintAt(script, script->jitNormal, pc, index, full); - - if (script->jitCtor) - ResetTraceHintAt(script, script->jitCtor, pc, index, full); -#endif -} - -#if JS_MONOIC -void * -RunTracer(VMFrame &f, ic::TraceICInfo &ic) -#else -void * -RunTracer(VMFrame &f) -#endif -{ - JSContext *cx = f.cx; - StackFrame *entryFrame = f.fp(); - TracePointAction tpa; - - /* :TODO: nuke PIC? */ - if (!cx->traceJitEnabled) - return NULL; - - /* - * Force initialization of the entry frame's scope chain and return value, - * if necessary. The tracer can query the scope chain without needing to - * check the HAS_SCOPECHAIN flag, and the frame is guaranteed to have the - * correct return value stored if we trace/interpret through to the end - * of the frame. - */ - entryFrame->scopeChain(); - entryFrame->returnValue(); - - bool blacklist; - void **traceData; - uintN *traceEpoch; - uint32 *loopCounter; - uint32 hits; -#if JS_MONOIC - traceData = &ic.traceData; - traceEpoch = &ic.traceEpoch; - loopCounter = &ic.loopCounter; - *loopCounter = 1; - hits = ic.loopCounterStart; -#else - traceData = NULL; - traceEpoch = NULL; - loopCounter = NULL; - hits = 1; -#endif - - { - /* - * While the tracer is running, redirect the regs to a local variable here. - * If the tracer exits during an inlined frame, it will synthesize those - * frames, point f.regs.fp at them and then enter the interpreter. If the - * interpreter pops the frames it will not be reflected here as a local - * set of regs is used by the interpreter, and f->regs end up pointing at - * garbage, confusing the recompiler. - */ - FrameRegs regs = f.regs; - PreserveRegsGuard regsGuard(cx, regs); - - tpa = MonitorTracePoint(f.cx, &blacklist, traceData, traceEpoch, - loopCounter, hits); - JS_ASSERT(!TRACE_RECORDER(cx)); - } - -#if JS_MONOIC - ic.loopCounterStart = *loopCounter; - if (blacklist) - DisableTraceHint(entryFrame->jit(), ic); -#endif - - // Even though ExecuteTree() bypasses the interpreter, it should propagate - // error failures correctly. - JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error); - - JS_ASSERT(f.fp() == cx->fp()); - switch (tpa) { - case TPA_Nothing: - return NULL; - - case TPA_Error: - if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter())) - THROWV(NULL); - JS_ASSERT(!cx->fp()->hasImacropc()); - break; - - case TPA_RanStuff: - case TPA_Recorded: - break; - } - - /* - * The tracer could have dropped us off on any frame at any position. - * Well, it could not have removed frames (recursion is disabled). - * - * Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint() - * unless each is at a safe point. We can JaegerShotAtSafePoint these - * frames individually, but we must unwind to the entryFrame. - * - * Note carefully that JaegerShotAtSafePoint can resume methods at - * arbitrary safe points whereas JaegerShot cannot. - * - * If we land on entryFrame without a safe point in sight, we'll end up - * at the RETURN op. This is an edge case with two paths: - * - * 1) The entryFrame is the last inline frame. If it fell on a RETURN, - * move the return value down. - * 2) The entryFrame is NOT the last inline frame. Pop the frame. - * - * In both cases, we hijack the stub to return to the force-return - * trampoline. This trampoline simulates the frame-popping portion of - * emitReturn (except without the benefit of the FrameState) and will - * produce the necessary register state to return to the caller. - */ - - restart: - /* Step 1. Finish frames created after the entry frame. */ - if (!FinishExcessFrames(f, entryFrame)) - THROWV(NULL); - - /* IMacros are guaranteed to have been removed by now. */ - JS_ASSERT(f.fp() == entryFrame); - JS_ASSERT(!entryFrame->hasImacropc()); - - /* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */ - if (FrameIsFinished(cx)) { - if (!HandleFinishedFrame(f, entryFrame)) - THROWV(NULL); - *f.returnAddressLocation() = cx->jaegerCompartment()->forceReturnFromFastCall(); - return NULL; - } - - /* Step 3. If entryFrame is at a safe point, just leave. */ - if (void *ncode = AtSafePoint(cx)) - return ncode; - - /* Step 4. Do a partial interp, then restart the whole process. */ - if (!PartialInterpret(f)) { - if (!HandleErrorInExcessFrame(f, entryFrame)) - THROWV(NULL); - } - - goto restart; -} - -#endif /* JS_TRACER */ - -#if defined JS_TRACER -# if defined JS_MONOIC -void *JS_FASTCALL -stubs::InvokeTracer(VMFrame &f, ic::TraceICInfo *ic) -{ - return RunTracer(f, *ic); -} - -# else - -void *JS_FASTCALL -stubs::InvokeTracer(VMFrame &f) -{ - return RunTracer(f); -} -# endif /* JS_MONOIC */ -#endif /* JS_TRACER */ - /* :XXX: common out with identical copy in Compiler.cpp */ #if defined(JS_METHODJIT_SPEW) static const char *OpcodeNames[] = { diff --git a/js/src/methodjit/LoopState.cpp b/js/src/methodjit/LoopState.cpp index 8646b2cb21ec..5cf990e4dcca 100644 --- a/js/src/methodjit/LoopState.cpp +++ b/js/src/methodjit/LoopState.cpp @@ -1328,7 +1328,7 @@ LoopState::restoreInvariants(jsbytecode *pc, Assembler &masm, masm.loadPtr(Address(T0, JSObject::offsetOfElements()), T0); masm.load32(Address(T0, ObjectElements::offsetOfInitializedLength()), T0); } else { - masm.load32(Address(T0, TypedArray::lengthOffset()), T0); + masm.loadPayload(Address(T0, TypedArray::lengthOffset()), T0); } int32 constant = entry.u.check.constant; @@ -1418,7 +1418,7 @@ LoopState::restoreInvariants(jsbytecode *pc, Assembler &masm, Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary)); if (entry.kind == InvariantEntry::TYPED_ARRAY_LENGTH) { - masm.load32(Address(T0, TypedArray::lengthOffset()), T0); + masm.loadPayload(Address(T0, TypedArray::lengthOffset()), T0); masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), T0, address); } else { masm.loadPtr(Address(T0, js::TypedArray::dataOffset()), T0); diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index 6cce006393ab..cf09b0079b0f 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1091,16 +1091,10 @@ JITScript::callSites() const return (js::mjit::CallSite *)&inlineFrames()[nInlineFrames]; } -JSObject ** -JITScript::rootedObjects() const -{ - return (JSObject **)&callSites()[nCallSites]; -} - char * JITScript::commonSectionLimit() const { - return (char *)&rootedObjects()[nRootedObjects]; + return (char *)&callSites()[nCallSites]; } #ifdef JS_MONOIC @@ -1129,16 +1123,10 @@ JITScript::equalityICs() const return (ic::EqualityICInfo *)&callICs()[nCallICs]; } -ic::TraceICInfo * -JITScript::traceICs() const -{ - return (ic::TraceICInfo *)&equalityICs()[nEqualityICs]; -} - char * JITScript::monoICSectionsLimit() const { - return (char *)&traceICs()[nTraceICs]; + return (char *)&equalityICs()[nEqualityICs]; } #else // JS_MONOIC char * @@ -1186,17 +1174,6 @@ static inline void Destroy(T &t) t.~T(); } -void -mjit::JITScript::purgeNativeCallStubs() -{ - for (unsigned i = 0; i < nativeCallStubs.length(); i++) { - JSC::ExecutablePool *pool = nativeCallStubs[i].pool; - if (pool) - pool->release(); - } - nativeCallStubs.clear(); -} - mjit::JITScript::~JITScript() { code.release(); @@ -1227,7 +1204,11 @@ mjit::JITScript::~JITScript() (*pExecPool)->release(); } - purgeNativeCallStubs(); + for (unsigned i = 0; i < nativeCallStubs.length(); i++) { + JSC::ExecutablePool *pool = nativeCallStubs[i].pool; + if (pool) + pool->release(); + } ic::CallICInfo *callICs_ = callICs(); for (uint32 i = 0; i < nCallICs; i++) { @@ -1272,13 +1253,11 @@ mjit::JITScript::scriptDataSize(JSUsableSizeFun usf) sizeof(NativeMapEntry) * nNmapPairs + sizeof(InlineFrame) * nInlineFrames + sizeof(CallSite) * nCallSites + - sizeof(JSObject *) * nRootedObjects + #if defined JS_MONOIC sizeof(ic::GetGlobalNameIC) * nGetGlobalNames + sizeof(ic::SetGlobalNameIC) * nSetGlobalNames + sizeof(ic::CallICInfo) * nCallICs + sizeof(ic::EqualityICInfo) * nEqualityICs + - sizeof(ic::TraceICInfo) * nTraceICs + #endif #if defined JS_POLYIC sizeof(ic::PICInfo) * nPICs + @@ -1413,20 +1392,4 @@ mjit::NativeToPC(JITScript *jit, void *ncode, mjit::CallSite **pinline) return jit->nativeToPC(ncode, pinline); } -void -JITScript::trace(JSTracer *trc) -{ - /* - * MICs and PICs attached to the JITScript are weak references, and either - * entirely purged or selectively purged on each GC. We do, however, need - * to maintain references to any scripts whose code was inlined into this. - */ - InlineFrame *inlineFrames_ = inlineFrames(); - for (unsigned i = 0; i < nInlineFrames; i++) - MarkObject(trc, *inlineFrames_[i].fun, "jitscript_fun"); - - for (uint32 i = 0; i < nRootedObjects; ++i) - MarkObject(trc, *rootedObjects()[i], "mjit rooted object"); -} - /* static */ const double mjit::Assembler::oneDouble = 1.0; diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index c65f2dd95fbc..6e43f1c9232c 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -500,7 +500,6 @@ namespace ic { struct GetGlobalNameIC; struct SetGlobalNameIC; struct EqualityICInfo; - struct TraceICInfo; struct CallICInfo; # endif } @@ -531,7 +530,6 @@ typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICI typedef void (JS_FASTCALL *VoidStubGetGlobal)(VMFrame &, js::mjit::ic::GetGlobalNameIC *); typedef void (JS_FASTCALL *VoidStubSetGlobal)(VMFrame &, js::mjit::ic::SetGlobalNameIC *); typedef JSBool (JS_FASTCALL *BoolStubEqualityIC)(VMFrame &, js::mjit::ic::EqualityICInfo *); -typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceICInfo *); #endif #ifdef JS_POLYIC typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *); @@ -605,13 +603,11 @@ struct JITScript { bool singleStepMode:1; /* compiled in "single step mode" */ uint32 nInlineFrames; uint32 nCallSites; - uint32 nRootedObjects; #ifdef JS_MONOIC uint32 nGetGlobalNames; uint32 nSetGlobalNames; uint32 nCallICs; uint32 nEqualityICs; - uint32 nTraceICs; #endif #ifdef JS_POLYIC uint32 nGetElems; @@ -643,13 +639,11 @@ struct JITScript { NativeMapEntry *nmap() const; js::mjit::InlineFrame *inlineFrames() const; js::mjit::CallSite *callSites() const; - JSObject **rootedObjects() const; #ifdef JS_MONOIC ic::GetGlobalNameIC *getGlobalNames() const; ic::SetGlobalNameIC *setGlobalNames() const; ic::CallICInfo *callICs() const; ic::EqualityICInfo *equalityICs() const; - ic::TraceICInfo *traceICs() const; #endif #ifdef JS_POLYIC ic::GetElementIC *getElems() const; @@ -666,12 +660,6 @@ struct JITScript { } void nukeScriptDependentICs(); - void sweepCallICs(JSContext *cx, bool purgeAll); - void purgeMICs(); - void purgePICs(); - void purgeNativeCallStubs(); - - void trace(JSTracer *trc); /* |usf| can be NULL here, in which case the fallback size computation will be used. */ size_t scriptDataSize(JSUsableSizeFun usf); @@ -766,13 +754,6 @@ struct CallSite } }; -/* - * Re-enables a tracepoint in the method JIT. When full is true, we - * also reset the iteration counter. - */ -void -ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full); - uintN GetCallTargetCount(JSScript *script, jsbytecode *pc); diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 2ce022e9e367..d819dcc33328 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -818,18 +818,27 @@ class CallCompiler : public BaseCompiler types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); + /* + * Native stubs are not generated for inline frames. The overhead of + * bailing out from the IC is far greater than the time saved by + * inlining the parent frame in the first place, so mark the immediate + * caller as uninlineable. + */ + if (f.script()->function()) { + f.script()->uninlineable = true; + MarkTypeObjectFlags(cx, f.script()->function(), types::OBJECT_FLAG_UNINLINEABLE); + } + /* Don't touch the IC if the call triggered a recompilation. */ if (monitor.recompiled()) return true; + JS_ASSERT(!f.regs.inlined()); + /* Right now, take slow-path for IC misses or multiple stubs. */ if (ic.fastGuardedNative || ic.hasJsFunCheck) return true; - /* Don't generate native MICs within inlined frames, we can't recompile them yet. */ - if (f.regs.inlined()) - return true; - /* Native MIC needs to warm up first. */ if (!ic.hit) { ic.hit = true; @@ -1252,165 +1261,5 @@ JITScript::resetArgsCheck() repatch.relink(argsCheckJump, argsCheckStub); } -void -JITScript::purgeMICs() -{ - if (!nGetGlobalNames || !nSetGlobalNames) - return; - - Repatcher repatch(this); - - ic::GetGlobalNameIC *getGlobalNames_ = getGlobalNames(); - for (uint32 i = 0; i < nGetGlobalNames; i++) { - ic::GetGlobalNameIC &ic = getGlobalNames_[i]; - JSC::CodeLocationDataLabelPtr label = ic.fastPathStart.dataLabelPtrAtOffset(ic.shapeOffset); - repatch.repatch(label, NULL); - } - - ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames(); - for (uint32 i = 0; i < nSetGlobalNames; i++) { - ic::SetGlobalNameIC &ic = setGlobalNames_[i]; - ic.patchInlineShapeGuard(repatch, NULL); - - if (ic.hasExtraStub) { - Repatcher repatcher(ic.extraStub); - ic.patchExtraShapeGuard(repatcher, NULL); - } - } -} - -void -ic::PurgeMICs(JSContext *cx, JSScript *script) -{ - if (script->jitNormal) - script->jitNormal->purgeMICs(); - if (script->jitCtor) - script->jitCtor->purgeMICs(); -} - -void -JITScript::nukeScriptDependentICs() -{ - if (!nCallICs) - return; - - Repatcher repatcher(this); - - ic::CallICInfo *callICs_ = callICs(); - for (uint32 i = 0; i < nCallICs; i++) { - ic::CallICInfo &ic = callICs_[i]; - if (!ic.fastGuardedObject) - continue; - repatcher.repatch(ic.funGuard, NULL); - repatcher.relink(ic.funJump, ic.slowPathStart); - ic.releasePool(CallICInfo::Pool_ClosureStub); - ic.fastGuardedObject = NULL; - ic.hasJsFunCheck = false; - } -} - -void -JITScript::sweepCallICs(JSContext *cx, bool purgeAll) -{ - Repatcher repatcher(this); - - /* - * If purgeAll is set, purge stubs in the script except those covered by PurgePICs - * (which is always called during GC). We want to remove references which can keep - * alive pools that we are trying to destroy (see JSCompartment::sweep). - */ - - ic::CallICInfo *callICs_ = callICs(); - for (uint32 i = 0; i < nCallICs; i++) { - ic::CallICInfo &ic = callICs_[i]; - - /* - * If the object is unreachable, we're guaranteed not to be currently - * executing a stub generated by a guard on that object. This lets us - * precisely GC call ICs while keeping the identity guard safe. - */ - bool fastFunDead = ic.fastGuardedObject && - (purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedObject)); - bool hasNative = ic.fastGuardedNative != NULL; - - /* - * There are three conditions where we need to relink: - * (1) purgeAll is true. - * (2) There is a native stub. These have a NativeCallStub, which will - * all be released if the compartment has no code on the stack. - * (3) The fastFun is dead *and* there is a closure stub. - * - * Note although both objects can be non-NULL, there can only be one - * of [closure, native] stub per call IC. - */ - if (purgeAll || hasNative || (fastFunDead && ic.hasJsFunCheck)) { - repatcher.relink(ic.funJump, ic.slowPathStart); - ic.hit = false; - } - - if (fastFunDead) { - repatcher.repatch(ic.funGuard, NULL); - ic.purgeGuardedObject(); - } - - if (hasNative) - ic.fastGuardedNative = NULL; - - if (purgeAll) { - ic.releasePool(CallICInfo::Pool_ScriptStub); - JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset); - JSC::CodeLocationLabel icCall = ic.slowPathStart.labelAtOffset(ic.icCallOffset); - repatcher.relink(oolJump, icCall); - } - } - - /* The arguments type check IC can refer to type objects which might be swept. */ - if (argsCheckPool) - resetArgsCheck(); - - if (purgeAll) { - /* Purge ICs generating stubs into execPools. */ - uint32 released = 0; - - ic::EqualityICInfo *equalityICs_ = equalityICs(); - for (uint32 i = 0; i < nEqualityICs; i++) { - ic::EqualityICInfo &ic = equalityICs_[i]; - if (!ic.generated) - continue; - - JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, ic::Equality)); - repatcher.relink(ic.stubCall, fptr); - repatcher.relink(ic.jumpToStub, ic.stubEntry); - - ic.generated = false; - released++; - } - - ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames(); - for (uint32 i = 0; i < nSetGlobalNames; i ++) { - ic::SetGlobalNameIC &ic = setGlobalNames_[i]; - if (!ic.hasExtraStub) - continue; - repatcher.relink(ic.fastPathStart.jumpAtOffset(ic.inlineShapeJump), ic.slowPathStart); - ic.hasExtraStub = false; - released++; - } - - JS_ASSERT(released == execPools.length()); - for (uint32 i = 0; i < released; i++) - execPools[i]->release(); - execPools.clear(); - } -} - -void -ic::SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll) -{ - if (script->jitNormal) - script->jitNormal->sweepCallICs(cx, purgeAll); - if (script->jitCtor) - script->jitCtor->sweepCallICs(cx, purgeAll); -} - #endif /* JS_MONOIC */ diff --git a/js/src/methodjit/MonoIC.h b/js/src/methodjit/MonoIC.h index 5752651a85e1..9a1ba3d6b57b 100644 --- a/js/src/methodjit/MonoIC.h +++ b/js/src/methodjit/MonoIC.h @@ -160,30 +160,6 @@ struct SetGlobalNameIC : public GlobalNameIC void patchExtraShapeGuard(Repatcher &repatcher, const Shape *shape); }; -struct TraceICInfo { - TraceICInfo() {} - - JSC::CodeLocationLabel stubEntry; - JSC::CodeLocationLabel fastTarget; - JSC::CodeLocationLabel slowTarget; - JSC::CodeLocationJump traceHint; - JSC::CodeLocationJump slowTraceHint; -#ifdef DEBUG - jsbytecode *jumpTargetPC; -#endif - - /* This data is used by the tracing JIT. */ - void *traceData; - uintN traceEpoch; - uint32 loopCounter; - uint32 loopCounterStart; - - bool initialized : 1; - bool hasSlowTraceHint : 1; -}; - -static const uint16 BAD_TRACEIC_INDEX = (uint16)0xffff; - void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic); void JS_FASTCALL SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic); @@ -300,9 +276,6 @@ JSBool JS_FASTCALL SplatApplyArgs(VMFrame &f); void GenerateArgumentCheckStub(VMFrame &f); -void PurgeMICs(JSContext *cx, JSScript *script); -void SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll); - } /* namespace ic */ } /* namespace mjit */ } /* namespace js */ diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index 5762f25a9273..8b8e19b30c00 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -739,8 +739,17 @@ struct GetPropertyHelper { return ic.disable(cx, "slotful getter hook through prototype"); if (!ic.canCallHook) return ic.disable(cx, "can't call getter hook"); - if (f.regs.inlined()) - return ic.disable(cx, "hook called from inline frame"); + if (f.regs.inlined()) { + /* + * As with native stubs, getter hook stubs can't be + * generated for inline frames. Mark the inner function + * as uninlineable and recompile. + */ + f.script()->uninlineable = true; + MarkTypeObjectFlags(cx, f.script()->function(), + types::OBJECT_FLAG_UNINLINEABLE); + return Lookup_Uncacheable; + } } } else if (!shape->hasSlot()) { return ic.disable(cx, "no slot"); @@ -1994,20 +2003,20 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic) if (lval.isObject()) { objv = lval; } else { - JSProtoKey protoKey; + GlobalObject *global = f.fp()->scopeChain().getGlobal(); + JSObject *pobj; if (lval.isString()) { - protoKey = JSProto_String; + pobj = global->getOrCreateStringPrototype(cx); } else if (lval.isNumber()) { - protoKey = JSProto_Number; + pobj = global->getOrCreateNumberPrototype(cx); } else if (lval.isBoolean()) { - protoKey = JSProto_Boolean; + pobj = global->getOrCreateBooleanPrototype(cx); } else { JS_ASSERT(lval.isNull() || lval.isUndefined()); js_ReportIsNullOrUndefined(cx, -1, lval, NULL); THROW(); } - JSObject *pobj; - if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + if (!pobj) THROW(); objv.setObject(*pobj); } @@ -2670,7 +2679,7 @@ GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid i // Bounds check. Jump outOfBounds; - Address typedArrayLength(objReg, TypedArray::lengthOffset()); + Address typedArrayLength = masm.payloadOf(Address(objReg, TypedArray::lengthOffset())); if (idRemat.isConstant()) { JS_ASSERT(idRemat.value().toInt32() == v.toInt32()); outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32())); @@ -3025,7 +3034,7 @@ SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32 key) // Bounds check. Jump outOfBounds; - Address typedArrayLength(objReg, TypedArray::lengthOffset()); + Address typedArrayLength = masm.payloadOf(Address(objReg, TypedArray::lengthOffset())); if (hasConstantKey) outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue)); else @@ -3139,57 +3148,5 @@ ic::SetElement(VMFrame &f, ic::SetElementIC *ic) template void JS_FASTCALL ic::SetElement(VMFrame &f, SetElementIC *ic); template void JS_FASTCALL ic::SetElement(VMFrame &f, SetElementIC *ic); -void -JITScript::purgePICs() -{ - if (!nPICs && !nGetElems && !nSetElems) - return; - - Repatcher repatcher(this); - - ic::PICInfo *pics_ = pics(); - for (uint32 i = 0; i < nPICs; i++) { - ic::PICInfo &pic = pics_[i]; - switch (pic.kind) { - case ic::PICInfo::SET: - case ic::PICInfo::SETMETHOD: - SetPropCompiler::reset(repatcher, pic); - break; - case ic::PICInfo::NAME: - case ic::PICInfo::XNAME: - case ic::PICInfo::CALLNAME: - ScopeNameCompiler::reset(repatcher, pic); - break; - case ic::PICInfo::BIND: - BindNameCompiler::reset(repatcher, pic); - break; - case ic::PICInfo::CALL: /* fall-through */ - case ic::PICInfo::GET: - GetPropCompiler::reset(repatcher, pic); - break; - default: - JS_NOT_REACHED("Unhandled PIC kind"); - break; - } - pic.reset(); - } - - ic::GetElementIC *getElems_ = getElems(); - ic::SetElementIC *setElems_ = setElems(); - for (uint32 i = 0; i < nGetElems; i++) - getElems_[i].purge(repatcher); - for (uint32 i = 0; i < nSetElems; i++) - setElems_[i].purge(repatcher); -} - -void -ic::PurgePICs(JSContext *cx, JSScript *script) -{ - if (script->jitNormal) - script->jitNormal->purgePICs(); - if (script->jitCtor) - script->jitCtor->purgePICs(); -} - #endif /* JS_POLYIC */ diff --git a/js/src/methodjit/PolyIC.h b/js/src/methodjit/PolyIC.h index e7946e197a8c..17af388882a7 100644 --- a/js/src/methodjit/PolyIC.h +++ b/js/src/methodjit/PolyIC.h @@ -60,8 +60,6 @@ namespace ic { static const uint32 MAX_PIC_STUBS = 16; static const uint32 MAX_GETELEM_IC_STUBS = 17; -void PurgePICs(JSContext *cx); - enum LookupStatus { Lookup_Error = 0, Lookup_Uncacheable, @@ -547,7 +545,6 @@ struct PICInfo : public BasePolyIC { }; #ifdef JS_POLYIC -void PurgePICs(JSContext *cx, JSScript *script); void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *); void JS_FASTCALL GetPropNoCache(VMFrame &f, ic::PICInfo *); void JS_FASTCALL SetProp(VMFrame &f, ic::PICInfo *); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 27a9acd99ed0..a2155e01b23b 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -195,6 +195,7 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom) JS_ASSERT(atom); } + PropertyName *name = atom->asPropertyName(); jsid id = ATOM_TO_JSID(atom); if (entry && JS_LIKELY(!obj->getOps()->setProperty)) { uintN defineHow; @@ -208,7 +209,7 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom) if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, strict)) THROW(); } else { - if (!obj->setProperty(cx, id, &rval, strict)) + if (!obj->setProperty(cx, name, &rval, strict)) THROW(); } } while (0); @@ -228,7 +229,7 @@ stubs::SetPropNoCache(VMFrame &f, JSAtom *atom) THROW(); Value rval = f.regs.sp[-1]; - if (!obj->setProperty(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1], strict)) + if (!obj->setGeneric(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1], strict)) THROW(); f.regs.sp[-2] = rval; } @@ -245,11 +246,7 @@ stubs::SetGlobalNameNoCache(VMFrame &f, JSAtom *atom) Value rval = f.regs.sp[-1]; Value &lref = f.regs.sp[-2]; JSObject *obj = ValueToObject(cx, &lref); - if (!obj) - THROW(); - jsid id = ATOM_TO_JSID(atom); - - if (!obj->setProperty(cx, id, &rval, strict)) + if (!obj || !obj->setProperty(cx, atom->asPropertyName(), &rval, strict)) THROW(); f.regs.sp[-2] = f.regs.sp[-1]; @@ -512,7 +509,7 @@ stubs::SetElem(VMFrame &f) } } } while (0); - if (!obj->setProperty(cx, id, &rval, strict)) + if (!obj->setGeneric(cx, id, &rval, strict)) THROW(); end_setelem: /* :FIXME: Moving the assigned object into the lowest stack slot @@ -728,8 +725,11 @@ stubs::DefFun(VMFrame &f, JSFunction *fun) do { /* Steps 5d, 5f. */ if (!prop || pobj != parent) { - if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) + if (!parent->defineProperty(cx, name, rval, + JS_PropertyStub, JS_StrictPropertyStub, attrs)) + { THROW(); + } break; } @@ -738,8 +738,11 @@ stubs::DefFun(VMFrame &f, JSFunction *fun) Shape *shape = reinterpret_cast(prop); if (parent->isGlobal()) { if (shape->configurable()) { - if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) + if (!parent->defineProperty(cx, name, rval, + JS_PropertyStub, JS_StrictPropertyStub, attrs)) + { THROW(); + } break; } @@ -761,7 +764,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun) */ /* Step 5f. */ - if (!parent->setProperty(cx, id, &rval, strict)) + if (!parent->setProperty(cx, name, &rval, strict)) THROW(); } while (false); } @@ -1299,7 +1302,7 @@ stubs::InitElem(VMFrame &f, uint32 last) if (last && !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) THROW(); } else { - if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) THROW(); } } @@ -1364,14 +1367,10 @@ stubs::RegExp(VMFrame &f, JSObject *regex) { /* * Push a regexp object cloned from the regexp literal object mapped by the - * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was - * flouted by many browser-based implementations. - * - * We avoid the GetScopeChain call here and pass fp->scopeChain() as - * js_GetClassPrototype uses the latter only to locate the global. + * bytecode at pc. */ - JSObject *proto; - if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto)) + JSObject *proto = f.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(f.cx); + if (!proto) THROW(); JS_ASSERT(proto); JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto); @@ -1554,20 +1553,20 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom) if (lval.isObject()) { objv = lval; } else { - JSProtoKey protoKey; + GlobalObject *global = f.fp()->scopeChain().getGlobal(); + JSObject *pobj; if (lval.isString()) { - protoKey = JSProto_String; + pobj = global->getOrCreateStringPrototype(cx); } else if (lval.isNumber()) { - protoKey = JSProto_Number; + pobj = global->getOrCreateNumberPrototype(cx); } else if (lval.isBoolean()) { - protoKey = JSProto_Boolean; + pobj = global->getOrCreateBooleanPrototype(cx); } else { JS_ASSERT(lval.isNull() || lval.isUndefined()); js_ReportIsNullOrUndefined(cx, -1, lval, NULL); THROW(); } - JSObject *pobj; - if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + if (!pobj) THROW(); objv.setObject(*pobj); } @@ -2074,7 +2073,7 @@ stubs::DelName(VMFrame &f, JSAtom *atom) f.regs.sp++; f.regs.sp[-1] = BooleanValue(true); if (prop) { - if (!obj->deleteProperty(f.cx, id, &f.regs.sp[-1], false)) + if (!obj->deleteProperty(f.cx, atom->asPropertyName(), &f.regs.sp[-1], false)) THROW(); } } @@ -2090,7 +2089,7 @@ stubs::DelProp(VMFrame &f, JSAtom *atom) THROW(); Value rval; - if (!obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, strict)) + if (!obj->deleteGeneric(cx, ATOM_TO_JSID(atom), &rval, strict)) THROW(); f.regs.sp[-1] = rval; @@ -2113,7 +2112,7 @@ stubs::DelElem(VMFrame &f) if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) THROW(); - if (!obj->deleteProperty(cx, id, &f.regs.sp[-2], strict)) + if (!obj->deleteGeneric(cx, id, &f.regs.sp[-2], strict)) THROW(); } @@ -2172,7 +2171,7 @@ stubs::SetConst(VMFrame &f, JSAtom *atom) JSObject *obj = &f.fp()->varObj(); const Value &ref = f.regs.sp[-1]; - if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref, + if (!obj->defineProperty(cx, atom->asPropertyName(), ref, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { THROW(); @@ -2232,7 +2231,7 @@ stubs::TypeBarrierHelper(VMFrame &f, uint32 which) void JS_FASTCALL stubs::StubTypeHelper(VMFrame &f, int32 which) { - const Value &result = f.regs.sp[which]; + Value &result = f.regs.sp[which]; if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) { AutoEnterTypeInference enter(f.cx); diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h index c7273b749c39..e45c26901e12 100644 --- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -111,11 +111,6 @@ void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr); void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto); void JS_FASTCALL Throw(VMFrame &f); -#if JS_MONOIC -void * JS_FASTCALL InvokeTracer(VMFrame &f, ic::TraceICInfo *tic); -#else -void * JS_FASTCALL InvokeTracer(VMFrame &f); -#endif void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc); void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a38855c5aec0..a40d0b4b645d 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1562,9 +1562,7 @@ ValueToScript(JSContext *cx, jsval v, JSFunction **funp = NULL) JSObject *obj = JSVAL_TO_OBJECT(v); JSClass *clasp = JS_GET_CLASS(cx, obj); - if (clasp == Jsvalify(&ScriptClass)) { - script = (JSScript *) JS_GetPrivate(cx, obj); - } else if (clasp == Jsvalify(&GeneratorClass)) { + if (clasp == Jsvalify(&GeneratorClass)) { JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj); fun = gen->floatingFrame()->fun(); script = fun->script(); @@ -1624,8 +1622,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, v = argv[0]; intarg = 0; if (!JSVAL_IS_PRIMITIVE(v) && - (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass) || - JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&ScriptClass))) { + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass)) { script = ValueToScript(cx, v); if (!script) return JS_FALSE; @@ -1841,27 +1838,19 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset, static void SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp) { - uintN offset, lineno, delta, caseOff, switchTableStart, switchTableEnd; - jssrcnote *notes, *sn; - JSSrcNoteType type; - const char *name; - uint32 index; - JSAtom *atom; - JSString *str; - Sprint(sp, "\nSource notes:\n"); Sprint(sp, "%4s %4s %5s %6s %-8s %s\n", "ofs", "line", "pc", "delta", "desc", "args"); Sprint(sp, "---- ---- ----- ------ -------- ------\n"); - offset = 0; - lineno = script->lineno; - notes = script->notes(); - switchTableEnd = switchTableStart = 0; - for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - delta = SN_DELTA(sn); + uintN offset = 0; + uintN lineno = script->lineno; + jssrcnote *notes = script->notes(); + uintN switchTableEnd = 0, switchTableStart = 0; + for (jssrcnote *sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + uintN delta = SN_DELTA(sn); offset += delta; - type = (JSSrcNoteType) SN_TYPE(sn); - name = js_SrcNoteSpec[type].name; + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); + const char *name = js_SrcNoteSpec[type].name; if (type == SRC_LABEL) { /* Check if the source note is for a switch case. */ if (switchTableStart <= offset && offset < switchTableEnd) { @@ -1901,24 +1890,23 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp) case SRC_LABEL: case SRC_LABELBRACE: case SRC_BREAK2LABEL: - case SRC_CONT2LABEL: - index = js_GetSrcNoteOffset(sn, 0); - atom = script->getAtom(index); + case SRC_CONT2LABEL: { + uint32 index = js_GetSrcNoteOffset(sn, 0); + JSAtom *atom = script->getAtom(index); Sprint(sp, " atom %u (", index); - { - size_t len = PutEscapedString(NULL, 0, atom, '\0'); - if (char *buf = SprintReserveAmount(sp, len)) { - PutEscapedString(buf, len, atom, 0); - buf[len] = '\0'; - } + size_t len = PutEscapedString(NULL, 0, atom, '\0'); + if (char *buf = SprintReserveAmount(sp, len)) { + PutEscapedString(buf, len, atom, 0); + buf[len] = '\0'; } Sprint(sp, ")"); break; + } case SRC_FUNCDEF: { - index = js_GetSrcNoteOffset(sn, 0); + uint32 index = js_GetSrcNoteOffset(sn, 0); JSObject *obj = script->getObject(index); JSFunction *fun = obj->toFunction(); - str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); + JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); JSAutoByteString bytes; if (!str || !bytes.encode(cx, str)) ReportException(cx); @@ -1930,7 +1918,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp) if (op == JSOP_GOTO || op == JSOP_GOTOX) break; Sprint(sp, " length %u", uintN(js_GetSrcNoteOffset(sn, 0))); - caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); + uintN caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); if (caseOff) Sprint(sp, " first case offset %u", caseOff); UpdateSwitchTableBounds(cx, script, offset, @@ -3162,7 +3150,7 @@ CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id, if (*objp != referent) return true; if (!referent->getGeneric(cx, id, &desc.value) || - !referent->getAttributes(cx, id, &desc.attrs)) { + !referent->getGenericAttributes(cx, id, &desc.attrs)) { return false; } desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; @@ -4622,42 +4610,6 @@ static JSPropertySpec its_props[] = { {NULL,0,0,NULL,NULL} }; -#ifdef JSD_LOWLEVEL_SOURCE -/* - * This facilitates sending source to JSD (the debugger system) in the shell - * where the source is loaded using the JSFILE hack in jsscan. The function - * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook. - * A more normal embedding (e.g. mozilla) loads source itself and can send - * source directly to JSD without using this hook scheme. - */ -static void -SendSourceToJSDebugger(const char *filename, uintN lineno, - jschar *str, size_t length, - void **listenerTSData, JSDContext* jsdc) -{ - JSDSourceText *jsdsrc = (JSDSourceText *) *listenerTSData; - - if (!jsdsrc) { - if (!filename) - filename = "typein"; - if (1 == lineno) { - jsdsrc = JSD_NewSourceText(jsdc, filename); - } else { - jsdsrc = JSD_FindSourceForURL(jsdc, filename); - if (jsdsrc && JSD_SOURCE_PARTIAL != - JSD_GetSourceStatus(jsdc, jsdsrc)) { - jsdsrc = NULL; - } - } - } - if (jsdsrc) { - jsdsrc = JSD_AppendUCSourceText(jsdc,jsdsrc, str, length, - JSD_SOURCE_PARTIAL); - } - *listenerTSData = jsdsrc; -} -#endif /* JSD_LOWLEVEL_SOURCE */ - static JSBool its_noisy; /* whether to be noisy when finalizing it */ static JSBool its_enum_fail;/* whether to fail when enumerating it */ diff --git a/js/src/tests/e4x/XML/13.4.4.36.js b/js/src/tests/e4x/XML/13.4.4.36.js index e967f056dca8..599ab4034b80 100644 --- a/js/src/tests/e4x/XML/13.4.4.36.js +++ b/js/src/tests/e4x/XML/13.4.4.36.js @@ -68,4 +68,15 @@ TEST(3, 1, xhtml.namespaceDeclarations().length); TEST(4, xhtml1NS, xhtml.namespace()); +var xml = +var ns = new Namespace('ns','http://example.org/'); +xml.blah.@foo = 'bar'; +xml.blah.@foo.setNamespace(ns); +xml.blah.@foo = 'baz'; +xml.blah.@foo.setNamespace(ns); + +var expected = ; + +TEST(5, xml, expected); + END(); diff --git a/js/src/tests/ecma_5/extensions/jstests.list b/js/src/tests/ecma_5/extensions/jstests.list index 214ea89c89f1..41ebe27b0568 100644 --- a/js/src/tests/ecma_5/extensions/jstests.list +++ b/js/src/tests/ecma_5/extensions/jstests.list @@ -26,6 +26,7 @@ script proxy-strict.js script regress-bug567606.js script regress-bug607284.js script regress-bug629723.js +skip-if(!xulRuntime.shell) script strict-e4x-ban.js script strict-function-statements.js script strict-option-redeclared-parameter.js script string-literal-getter-setter-decompilation.js diff --git a/js/src/tests/ecma_5/extensions/strict-e4x-ban.js b/js/src/tests/ecma_5/extensions/strict-e4x-ban.js new file mode 100644 index 000000000000..2c8a067683e6 --- /dev/null +++ b/js/src/tests/ecma_5/extensions/strict-e4x-ban.js @@ -0,0 +1,52 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +assertEq(testLenientAndStrict("var o = {m:function(){}}; o.function::m()", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +assertEq(testLenientAndStrict("default xml namespace = 'foo'", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +assertEq(testLenientAndStrict("var x = ", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +assertEq(testLenientAndStrict("var x =

42

", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +assertEq(testLenientAndStrict("var x =

42

; x.(p == 42)", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +assertEq(testLenientAndStrict("var x =

42

; x..p", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + +if (typeof this.options == "function") { + this.options('xml'); + + assertEq(testLenientAndStrict("var cdata = ", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + + assertEq(testLenientAndStrict("var comment = ", + parsesSuccessfully, + parseRaisesException(SyntaxError)), + true); + + this.options('xml'); +} + +reportCompare(true, true); diff --git a/js/src/tests/js1_8_5/extensions/jstests.list b/js/src/tests/js1_8_5/extensions/jstests.list index f3d5dd301c68..337eadd0d240 100644 --- a/js/src/tests/js1_8_5/extensions/jstests.list +++ b/js/src/tests/js1_8_5/extensions/jstests.list @@ -58,3 +58,6 @@ require-or(debugMode,skip) script regress-672804-2.js require-or(debugMode,skip) script regress-672804-3.js skip-if(!xulRuntime.shell) script regress-677589.js script regress-677924.js +skip-if(!xulRuntime.shell) script regress-696109.js +script regress-691746.js +script regress-697515.js diff --git a/js/src/tests/js1_8_5/extensions/regress-691746.js b/js/src/tests/js1_8_5/extensions/regress-691746.js new file mode 100644 index 000000000000..26f732d07d64 --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/regress-691746.js @@ -0,0 +1,11 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var obj = {}; +try { + obj.watch(QName(), function () {}); +} catch (exc) { +} +gc(); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/extensions/regress-696109.js b/js/src/tests/js1_8_5/extensions/regress-696109.js new file mode 100644 index 000000000000..ca61ca057b7c --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/regress-696109.js @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Dave Herman + */ + +// Bug 696109 - fixed a precedence bug in with/while nodes +try { + Reflect.parse("with({foo})bar"); + throw new Error("supposed to be a syntax error"); +} catch (e if e instanceof SyntaxError) { } +try { + Reflect.parse("while({foo})bar"); + throw new Error("supposed to be a syntax error"); +} catch (e if e instanceof SyntaxError) { } + +reportCompare(true, true); diff --git a/js/src/tests/js1_8_5/extensions/regress-697515.js b/js/src/tests/js1_8_5/extensions/regress-697515.js new file mode 100644 index 000000000000..55f042ab0552 --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/regress-697515.js @@ -0,0 +1,6 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +assertEq(new WeakMap().set({}, 0), undefined); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tracejit/Writer.h b/js/src/tracejit/Writer.h index 374520fa17e2..f2bf363fc2d6 100644 --- a/js/src/tracejit/Writer.h +++ b/js/src/tracejit/Writer.h @@ -556,7 +556,7 @@ class Writer } nj::LIns *ldiConstTypedArrayLength(nj::LIns *obj) const { - return name(lir->insLoad(nj::LIR_ldi, obj, TypedArray::lengthOffset(), ACCSET_TARRAY, + return name(lir->insLoad(nj::LIR_ldi, obj, TypedArray::lengthOffset() + sPayloadOffset, ACCSET_TARRAY, nj::LOAD_CONST), "typedArrayLength"); } diff --git a/js/src/v8-dtoa/platform.cc b/js/src/v8-dtoa/platform.cc index 97ec6b997b0f..5fd4ce85b658 100644 --- a/js/src/v8-dtoa/platform.cc +++ b/js/src/v8-dtoa/platform.cc @@ -66,14 +66,14 @@ void OS::Abort() { * We used to call DebugBreak() on Windows, but amazingly, it causes * the MSVS 2010 debugger not to be able to recover a call stack. */ - *((int *) NULL) = 0; + *((volatile int *) NULL) = 0; exit(3); #elif defined(__APPLE__) /* * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are * trapped. */ - *((int *) NULL) = 0; /* To continue from here in GDB: "return" then "continue". */ + *((volatile int *) NULL) = 0; /* To continue from here in GDB: "return" then "continue". */ raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */ #else raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ diff --git a/js/src/vm/BooleanObject-inl.h b/js/src/vm/BooleanObject-inl.h new file mode 100644 index 000000000000..1472394b3cce --- /dev/null +++ b/js/src/vm/BooleanObject-inl.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey string object code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Terrence Cole (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef BooleanObject_inl_h___ +#define BooleanObject_inl_h___ + +#include "jsobjinlines.h" + +#include "vm/BooleanObject.h" + +inline js::BooleanObject * +JSObject::asBoolean() +{ + JS_ASSERT(isBoolean()); + return static_cast(const_cast(this)); +} + +namespace js { + +inline BooleanObject * +BooleanObject::create(JSContext *cx, bool b) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &BooleanClass); + if (!obj) + return NULL; + BooleanObject *boolobj = obj->asBoolean(); + boolobj->setPrimitiveValue(b); + return boolobj; +} + +inline BooleanObject * +BooleanObject::createWithProto(JSContext *cx, bool b, JSObject &proto) +{ + JSObject *obj = NewObjectWithClassProto(cx, &BooleanClass, &proto, + gc::GetGCObjectKind(RESERVED_SLOTS)); + if (!obj) + return NULL; + BooleanObject *boolobj = obj->asBoolean(); + boolobj->setPrimitiveValue(b); + return boolobj; +} + +} // namespace js + +#endif /* BooleanObject_inl_h__ */ diff --git a/js/src/vm/BooleanObject.h b/js/src/vm/BooleanObject.h new file mode 100644 index 000000000000..c166fb3d11a7 --- /dev/null +++ b/js/src/vm/BooleanObject.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey boolean object code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Terrence Cole (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef BooleanObject_h___ +#define BooleanObject_h___ + +#include "jsbool.h" + +namespace js { + +class BooleanObject : public ::JSObject +{ + /* Stores this Boolean object's [[PrimitiveValue]]. */ + static const uintN PRIMITIVE_VALUE_SLOT = 0; + + public: + static const uintN RESERVED_SLOTS = 1; + + /* + * Creates a new Boolean object boxing the given primitive bool. The + * object's [[Prototype]] is determined from context. + */ + static inline BooleanObject *create(JSContext *cx, bool b); + + /* + * Identical to create(), but uses |proto| as [[Prototype]]. This method + * must not be used to create |Boolean.prototype|. + */ + static inline BooleanObject *createWithProto(JSContext *cx, bool b, JSObject &proto); + + Value unbox() const { + JS_ASSERT(getSlot(PRIMITIVE_VALUE_SLOT).isBoolean()); + return getSlot(PRIMITIVE_VALUE_SLOT); + } + + private: + inline void setPrimitiveValue(bool b) { + setSlot(PRIMITIVE_VALUE_SLOT, BooleanValue(b)); + } + + /* For access to init, as Boolean.prototype is special. */ + friend JSObject * + ::js_InitBooleanClass(JSContext *cx, JSObject *global); + + private: + BooleanObject(); + BooleanObject &operator=(const BooleanObject &bo); +}; + +} // namespace js + +#endif /* BooleanObject_h__ */ diff --git a/js/src/vm/CallObject.h b/js/src/vm/CallObject.h index 6c677b2b6a75..b7624009181f 100644 --- a/js/src/vm/CallObject.h +++ b/js/src/vm/CallObject.h @@ -63,7 +63,7 @@ class CallObject : public ::JSObject static const uint32 CALLEE_SLOT = 1; static const uint32 ARGUMENTS_SLOT = 2; -public: + public: /* Create a CallObject for the given callee function. */ static CallObject * create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 9e17cd165650..f93901fb358e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -88,7 +88,6 @@ extern Class DebuggerScript_class; enum { JSSLOT_DEBUGSCRIPT_OWNER, - JSSLOT_DEBUGSCRIPT_HOLDER, /* PrivateValue, cross-compartment pointer */ JSSLOT_DEBUGSCRIPT_COUNT }; @@ -125,7 +124,7 @@ ReportObjectRequired(JSContext *cx) /*** Breakpoints *********************************************************************************/ BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc) - : script(script), pc(pc), realOpcode(JSOp(*pc)), scriptObject(NULL), enabledCount(0), + : script(script), pc(pc), realOpcode(JSOp(*pc)), scriptGlobal(NULL), enabledCount(0), trapHandler(NULL), trapClosure(UndefinedValue()) { JS_ASSERT(realOpcode != JSOP_TRAP); @@ -136,11 +135,11 @@ BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc) * Precondition: script is live, meaning either it is a non-held script that is * on the stack or a held script that hasn't been GC'd. */ -static JSObject * -ScriptScope(JSContext *cx, JSScript *script, JSObject *holder) +static GlobalObject * +ScriptGlobal(JSContext *cx, JSScript *script, GlobalObject *scriptGlobal) { - if (holder) - return holder; + if (scriptGlobal) + return scriptGlobal; /* * The referent is a non-held script. There is no direct reference from @@ -149,9 +148,9 @@ ScriptScope(JSContext *cx, JSScript *script, JSObject *holder) for (AllFramesIter i(cx->stack.space()); ; ++i) { JS_ASSERT(!i.done()); if (i.fp()->maybeScript() == script) - return &i.fp()->scopeChain(); + return i.fp()->scopeChain().getGlobal(); } - JS_NOT_REACHED("ScriptScope: live non-held script not on stack"); + JS_NOT_REACHED("ScriptGlobal: live non-held script not on stack"); } bool @@ -161,7 +160,7 @@ BreakpointSite::recompile(JSContext *cx, bool forTrap) if (script->hasJITCode()) { Maybe ac; if (!forTrap) { - ac.construct(cx, ScriptScope(cx, script, scriptObject)); + ac.construct(cx, ScriptGlobal(cx, script, scriptGlobal)); if (!ac.ref().enter()) return false; } @@ -733,7 +732,7 @@ Debugger::fireEnterFrame(JSContext *cx) } void -Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj) +Debugger::fireNewScript(JSContext *cx, JSScript *script) { JSObject *hook = getHook(OnNewScript); JS_ASSERT(hook); @@ -743,7 +742,7 @@ Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj) if (!ac.enter()) return; - JSObject *dsobj = wrapScript(cx, script, obj); + JSObject *dsobj = wrapScript(cx, script); if (!dsobj) { handleUncaughtException(ac, NULL, false); return; @@ -816,8 +815,7 @@ AddNewScriptRecipients(GlobalObject::DebuggerVector *src, AutoValueVector *dest) } void -Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, - GlobalObject *compileAndGoGlobal) +Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal) { JS_ASSERT(script->compileAndGo == !!compileAndGoGlobal); @@ -849,7 +847,7 @@ Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, Debugger *dbg = Debugger::fromJSObject(&p->toObject()); if ((!compileAndGoGlobal || dbg->debuggees.has(compileAndGoGlobal)) && dbg->enabled && dbg->getHook(OnNewScript)) { - dbg->fireNewScript(cx, script, obj); + dbg->fireNewScript(cx, script); } } } @@ -1782,15 +1780,7 @@ static inline JSScript * GetScriptReferent(JSObject *obj) { JS_ASSERT(obj->getClass() == &DebuggerScript_class); - return (JSScript *) obj->getPrivate(); -} - -static inline JSObject * -GetScriptHolder(JSObject *obj) -{ - JS_ASSERT(obj->getClass() == &DebuggerScript_class); - Value v = obj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER); - return (JSObject *) v.toPrivate(); + return static_cast(obj->getPrivate()); } static void @@ -1799,11 +1789,6 @@ DebuggerScript_trace(JSTracer *trc, JSObject *obj) if (!trc->context->runtime->gcCurrentCompartment) { if (JSScript *script = GetScriptReferent(obj)) MarkScript(trc, script, "Debugger.Script referent"); - Value v = obj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER); - if (!v.isUndefined()) { - if (JSObject *obj = (JSObject *) v.toPrivate()) - MarkObject(trc, *obj, "Debugger.Script referent holder"); - } } } @@ -1821,7 +1806,7 @@ Class DebuggerScript_class = { }; JSObject * -Debugger::newDebuggerScript(JSContext *cx, JSScript *script, JSObject *holder) +Debugger::newDebuggerScript(JSContext *cx, JSScript *script) { assertSameCompartment(cx, object); @@ -1829,24 +1814,21 @@ Debugger::newDebuggerScript(JSContext *cx, JSScript *script, JSObject *holder) JS_ASSERT(proto); JSObject *scriptobj = NewNonFunction(cx, &DebuggerScript_class, proto, NULL); if (!scriptobj) - return false; + return NULL; scriptobj->setPrivate(script); scriptobj->setReservedSlot(JSSLOT_DEBUGSCRIPT_OWNER, ObjectValue(*object)); - scriptobj->setReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER, PrivateValue(holder)); return scriptobj; } JSObject * -Debugger::wrapScript(JSContext *cx, JSScript *script, JSObject *obj) +Debugger::wrapScript(JSContext *cx, JSScript *script) { assertSameCompartment(cx, object); JS_ASSERT(cx->compartment != script->compartment()); - JS_ASSERT_IF(obj, script->compartment() == obj->compartment()); - CellWeakMap::AddPtr p = scripts.lookupForAdd(script); if (!p) { - JSObject *scriptobj = newDebuggerScript(cx, script, obj); + JSObject *scriptobj = newDebuggerScript(cx, script); /* The allocation may have caused a GC, which can remove table entries. */ if (!scriptobj || !scripts.relookupOrAdd(p, script, scriptobj)) @@ -1857,12 +1839,6 @@ Debugger::wrapScript(JSContext *cx, JSScript *script, JSObject *obj) return p->value; } -JSObject * -Debugger::wrapFunctionScript(JSContext *cx, JSFunction *fun) -{ - return wrapScript(cx, fun->script(), fun); -} - static JSObject * DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const char *fnname) { @@ -1879,15 +1855,14 @@ DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const c /* * Check for Debugger.Script.prototype, which is of class DebuggerScript_class - * but whose holding object is undefined. + * but whose script is null. */ - if (thisobj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER).isUndefined()) { + if (!GetScriptReferent(thisobj)) { JS_ASSERT(!GetScriptReferent(thisobj)); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, clsname, fnname, "prototype object"); return NULL; } - JS_ASSERT(GetScriptReferent(thisobj)); return thisobj; } @@ -1954,7 +1929,8 @@ DebuggerScript_getChildScripts(JSContext *cx, uintN argc, Value *vp) for (uint32 i = script->savedCallerFun ? 1 : 0; i < objects->length; i++) { JSObject *obj = objects->vector[i]; if (obj->isFunction()) { - JSObject *s = dbg->wrapFunctionScript(cx, (JSFunction *) obj); + JSFunction *fun = static_cast(obj); + JSObject *s = dbg->wrapScript(cx, fun->script()); if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s))) return false; } @@ -2027,7 +2003,7 @@ class BytecodeRangeWithLineNumbers : private BytecodeRange * and including the current offset. */ while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) { - JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn); + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); if (type == SRC_SETLINE) lineno = size_t(js_GetSrcNoteOffset(sn, 0)); else if (type == SRC_NEWLINE) @@ -2186,7 +2162,7 @@ DebuggerScript_getAllOffsets(JSContext *cx, uintN argc, Value *vp) offsets = NewDenseEmptyArray(cx); if (!offsets || !ValueToId(cx, NumberValue(lineno), &id) || - !result->defineProperty(cx, id, ObjectValue(*offsets))) + !result->defineGeneric(cx, id, ObjectValue(*offsets))) { return false; } @@ -2257,8 +2233,8 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp) THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script); Debugger *dbg = Debugger::fromChildJSObject(obj); - JSObject *holder = GetScriptHolder(obj); - if (!dbg->observesScope(ScriptScope(cx, script, holder))) { + GlobalObject *scriptGlobal = script->getGlobalObjectOrNull(); + if (!dbg->observesGlobal(ScriptGlobal(cx, script, scriptGlobal))) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_DEBUGGING); return false; } @@ -2273,7 +2249,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp) JSCompartment *comp = script->compartment(); jsbytecode *pc = script->code + offset; - BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, holder); + BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, scriptGlobal); if (!site) return false; if (site->inc(cx)) { @@ -2629,7 +2605,7 @@ DebuggerFrame_getScript(JSContext *cx, uintN argc, Value *vp) if (fp->isFunctionFrame() && !fp->isEvalFrame()) { JSFunction *callee = fp->callee().toFunction(); if (callee->isInterpreted()) { - scriptObject = debug->wrapFunctionScript(cx, callee); + scriptObject = debug->wrapScript(cx, callee->script()); if (!scriptObject) return false; } @@ -2639,8 +2615,7 @@ DebuggerFrame_getScript(JSContext *cx, uintN argc, Value *vp) * frames. */ JSScript *script = fp->script(); - scriptObject = debug->wrapScript(cx, script, - script->isCachedEval ? NULL : script->u.object); + scriptObject = debug->wrapScript(cx, script); if (!scriptObject) return false; } @@ -2743,11 +2718,12 @@ EvaluateInScope(JSContext *cx, JSObject *scobj, StackFrame *fp, const jschar *ch * we use a static level that will cause us not to attempt to optimize * variable references made by this frame. */ - JSScript *script = Compiler::compileScript(cx, scobj, fp, fp->scopeChain().principals(cx), - TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT, - chars, length, - filename, lineno, cx->findVersion(), - NULL, UpvarCookie::UPVAR_LEVEL_LIMIT); + JSScript *script = BytecodeCompiler::compileScript(cx, scobj, fp, + fp->scopeChain().principals(cx), + TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL, + chars, length, filename, lineno, + cx->findVersion(), NULL, + UpvarCookie::UPVAR_LEVEL_LIMIT); if (!script) return false; @@ -3056,7 +3032,7 @@ DebuggerObject_getScript(JSContext *cx, uintN argc, Value *vp) if (!fun->isInterpreted()) return true; - JSObject *scriptObject = dbg->wrapFunctionScript(cx, fun); + JSObject *scriptObject = dbg->wrapScript(cx, fun->script()); if (!scriptObject) return false; @@ -3291,7 +3267,7 @@ DebuggerObject_deleteProperty(JSContext *cx, uintN argc, Value *vp) return false; ErrorCopier ec(ac, dbg->toJSObject()); - return obj->deleteProperty(cx, id, &args.rval(), false); + return obj->deleteGeneric(cx, id, &args.rval(), false); } enum SealHelperOp { Seal, Freeze, PreventExtensions }; diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 2495503e1757..2638e19e289d 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -201,7 +201,7 @@ class Debugger { static void slowPathOnEnterFrame(JSContext *cx); static void slowPathOnLeaveFrame(JSContext *cx); - static void slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, + static void slowPathOnNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal); static JSTrapStatus dispatchHook(JSContext *cx, js::Value *vp, Hook which); @@ -210,18 +210,16 @@ class Debugger { void fireEnterFrame(JSContext *cx); /* - * Allocate and initialize a Debugger.Script instance whose referent is |script| and - * whose holder is |obj|. If |obj| is NULL, this creates a Debugger.Script whose holder - * is null, for non-held scripts. + * Allocate and initialize a Debugger.Script instance whose referent is + * |script|. */ - JSObject *newDebuggerScript(JSContext *cx, JSScript *script, JSObject *obj); + JSObject *newDebuggerScript(JSContext *cx, JSScript *script); /* * Receive a "new script" event from the engine. A new script was compiled - * or deserialized. For eval scripts obj must be null, otherwise it must be - * a script object. + * or deserialized. */ - void fireNewScript(JSContext *cx, JSScript *script, JSObject *obj); + void fireNewScript(JSContext *cx, JSScript *script); static inline Debugger *fromLinks(JSCList *links); inline Breakpoint *firstBreakpoint() const; @@ -262,7 +260,7 @@ class Debugger { static inline void onLeaveFrame(JSContext *cx); static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp); static inline JSTrapStatus onExceptionUnwind(JSContext *cx, js::Value *vp); - static inline void onNewScript(JSContext *cx, JSScript *script, JSObject *obj, + static inline void onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal); static JSTrapStatus onTrap(JSContext *cx, Value *vp); static JSTrapStatus onSingleStep(JSContext *cx, Value *vp); @@ -271,7 +269,7 @@ class Debugger { inline bool observesEnterFrame() const; inline bool observesNewScript() const; - inline bool observesScope(JSObject *obj) const; + inline bool observesGlobal(GlobalObject *global) const; inline bool observesFrame(StackFrame *fp) const; /* @@ -331,21 +329,12 @@ class Debugger { */ bool newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp); - /* - * Return the Debugger.Script object for |fun|'s script, or create a new - * one if needed. The context |cx| must be in the debugger compartment; - * |fun| must be a cross-compartment wrapper referring to the JSFunction in - * a debuggee compartment. - */ - JSObject *wrapFunctionScript(JSContext *cx, JSFunction *fun); - /* * Return the Debugger.Script object for |script|, or create a new one if - * needed. The context |cx| must be in the debugger compartment; |script| must - * be a script in a debuggee compartment. |obj| is either the script holder or - * null for non-held scripts. + * needed. The context |cx| must be in the debugger compartment; |script| + * must be a script in a debuggee compartment. */ - JSObject *wrapScript(JSContext *cx, JSScript *script, JSObject *obj); + JSObject *wrapScript(JSContext *cx, JSScript *script); private: /* Prohibit copying. */ @@ -369,7 +358,7 @@ class BreakpointSite { * cached eval scripts and for JSD1 traps. It is always non-null for JSD2 * breakpoints in held scripts. */ - JSObject *scriptObject; + GlobalObject *scriptGlobal; JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */ size_t enabledCount; /* number of breakpoints in the list that are enabled */ @@ -383,7 +372,7 @@ class BreakpointSite { Breakpoint *firstBreakpoint() const; bool hasBreakpoint(Breakpoint *bp); bool hasTrap() const { return !!trapHandler; } - JSObject *getScriptObject() const { return scriptObject; } + GlobalObject *getScriptGlobal() const { return scriptGlobal; } bool inc(JSContext *cx); void dec(JSContext *cx); @@ -458,7 +447,7 @@ Debugger::toJSObject() const Debugger * Debugger::fromJSObject(JSObject *obj) { - JS_ASSERT(obj->getClass() == &jsclass); + JS_ASSERT(js::GetObjectClass(obj) == &jsclass); return (Debugger *) obj->getPrivate(); } @@ -475,15 +464,15 @@ Debugger::observesNewScript() const } bool -Debugger::observesScope(JSObject *obj) const +Debugger::observesGlobal(GlobalObject *global) const { - return debuggees.has(obj->getGlobal()); + return debuggees.has(global); } bool Debugger::observesFrame(StackFrame *fp) const { - return observesScope(&fp->scopeChain()); + return observesGlobal(fp->scopeChain().getGlobal()); } void @@ -517,13 +506,12 @@ Debugger::onExceptionUnwind(JSContext *cx, js::Value *vp) } void -Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj, - GlobalObject *compileAndGoGlobal) +Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal) { JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal); JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal); if (!script->compartment()->getDebuggees().empty()) - slowPathOnNewScript(cx, script, obj, compileAndGoGlobal); + slowPathOnNewScript(cx, script, compileAndGoGlobal); } extern JSBool diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index df1e5d6b6ad0..26e0a2cbd8e2 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -58,13 +58,7 @@ js_InitObjectClass(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isNative()); - GlobalObject *global = obj->asGlobal(); - if (!global->functionObjectClassesInitialized()) { - if (!global->initFunctionAndObjectClasses(cx)) - return NULL; - } - - return global->getObjectPrototype(); + return obj->asGlobal()->getOrCreateObjectPrototype(cx); } JSObject * @@ -72,10 +66,7 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isNative()); - GlobalObject *global = obj->asGlobal(); - return global->functionObjectClassesInitialized() - ? global->getFunctionPrototype() - : global->initFunctionAndObjectClasses(cx); + return obj->asGlobal()->getOrCreateFunctionPrototype(cx); } static JSBool @@ -283,7 +274,7 @@ GlobalObject::initStandardClasses(JSContext *cx) JSAtomState &state = cx->runtime->atomState; /* Define a top-level property 'undefined' with the undefined value. */ - if (!defineProperty(cx, ATOM_TO_JSID(state.typeAtoms[JSTYPE_VOID]), UndefinedValue(), + if (!defineProperty(cx, state.typeAtoms[JSTYPE_VOID], UndefinedValue(), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return false; @@ -398,8 +389,8 @@ CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &glo JSObject * GlobalObject::createBlankPrototype(JSContext *cx, Class *clasp) { - JSObject *objectProto; - if (!js_GetClassPrototype(cx, this, JSProto_Object, &objectProto)) + JSObject *objectProto = getOrCreateObjectPrototype(cx); + if (!objectProto) return NULL; return CreateBlankProto(cx, clasp, *objectProto, *this); @@ -414,10 +405,10 @@ GlobalObject::createBlankPrototypeInheriting(JSContext *cx, Class *clasp, JSObje bool LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto) { - return ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + return ctor->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY) && - proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + proto->defineProperty(cx, cx->runtime->atomState.constructorAtom, ObjectValue(*ctor), JS_PropertyStub, JS_StrictPropertyStub, 0); } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 80d8371776ed..09873c20f806 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -41,11 +41,17 @@ #ifndef GlobalObject_h___ #define GlobalObject_h___ +#include "jsarray.h" +#include "jsbool.h" #include "jsfun.h" #include "jsiter.h" +#include "jsnum.h" +#include "jstypedarray.h" #include "js/Vector.h" +#include "builtin/RegExp.h" + extern JSObject * js_InitObjectClass(JSContext *cx, JSObject *obj); @@ -159,6 +165,48 @@ class GlobalObject : public ::JSObject { v.setObject(*evalobj); } + Value getConstructor(JSProtoKey key) const { + JS_ASSERT(key <= JSProto_LIMIT); + return getSlot(key); + } + + Value getPrototype(JSProtoKey key) const { + JS_ASSERT(key <= JSProto_LIMIT); + return getSlot(JSProto_LIMIT + key); + } + + bool classIsInitialized(JSProtoKey key) const { + bool inited = !getConstructor(key).isUndefined(); + JS_ASSERT(inited == !getPrototype(key).isUndefined()); + return inited; + } + + bool functionObjectClassesInitialized() const { + bool inited = classIsInitialized(JSProto_Function); + JS_ASSERT(inited == classIsInitialized(JSProto_Object)); + return inited; + } + + bool arrayClassInitialized() const { + return classIsInitialized(JSProto_Array); + } + + bool booleanClassInitialized() const { + return classIsInitialized(JSProto_Boolean); + } + bool numberClassInitialized() const { + return classIsInitialized(JSProto_Number); + } + bool stringClassInitialized() const { + return classIsInitialized(JSProto_String); + } + bool regexpClassInitialized() const { + return classIsInitialized(JSProto_RegExp); + } + bool arrayBufferClassInitialized() const { + return classIsInitialized(JSProto_ArrayBuffer); + } + public: static GlobalObject *create(JSContext *cx, Class *clasp); @@ -186,27 +234,68 @@ class GlobalObject : public ::JSObject { */ JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto); - bool functionObjectClassesInitialized() const { - bool inited = !getSlot(JSProto_Function).isUndefined(); - JS_ASSERT(inited == !getSlot(JSProto_LIMIT + JSProto_Function).isUndefined()); - JS_ASSERT(inited == !getSlot(JSProto_Object).isUndefined()); - JS_ASSERT(inited == !getSlot(JSProto_LIMIT + JSProto_Object).isUndefined()); - return inited; + JSObject *getOrCreateObjectPrototype(JSContext *cx) { + if (!functionObjectClassesInitialized()) { + if (!initFunctionAndObjectClasses(cx)) + return NULL; + } + return &getPrototype(JSProto_Object).toObject(); } - JSObject *getFunctionPrototype() const { - JS_ASSERT(functionObjectClassesInitialized()); - return &getSlot(JSProto_LIMIT + JSProto_Function).toObject(); + JSObject *getOrCreateFunctionPrototype(JSContext *cx) { + if (!functionObjectClassesInitialized()) { + if (!initFunctionAndObjectClasses(cx)) + return NULL; + } + return &getPrototype(JSProto_Function).toObject(); } - JSObject *getObjectPrototype() const { - JS_ASSERT(functionObjectClassesInitialized()); - return &getSlot(JSProto_LIMIT + JSProto_Object).toObject(); + JSObject *getOrCreateArrayPrototype(JSContext *cx) { + if (!arrayClassInitialized()) { + if (!js_InitArrayClass(cx, this)) + return NULL; + } + return &getPrototype(JSProto_Array).toObject(); } - JSObject *getThrowTypeError() const { - JS_ASSERT(functionObjectClassesInitialized()); - return &getSlot(THROWTYPEERROR).toObject(); + JSObject *getOrCreateBooleanPrototype(JSContext *cx) { + if (!booleanClassInitialized()) { + if (!js_InitBooleanClass(cx, this)) + return NULL; + } + return &getPrototype(JSProto_Boolean).toObject(); + } + + JSObject *getOrCreateNumberPrototype(JSContext *cx) { + if (!numberClassInitialized()) { + if (!js_InitNumberClass(cx, this)) + return NULL; + } + return &getPrototype(JSProto_Number).toObject(); + } + + JSObject *getOrCreateStringPrototype(JSContext *cx) { + if (!stringClassInitialized()) { + if (!js_InitStringClass(cx, this)) + return NULL; + } + return &getPrototype(JSProto_String).toObject(); + } + + JSObject *getOrCreateRegExpPrototype(JSContext *cx) { + if (!regexpClassInitialized()) { + if (!js_InitRegExpClass(cx, this)) + return NULL; + } + return &getPrototype(JSProto_RegExp).toObject(); + } + + JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) { + if (!arrayBufferClassInitialized()) { + if (!js_InitTypedArrayClasses(cx, this)) + return NULL; + } + return &getPrototype(JSProto_ArrayBuffer).toObject(); } JSObject *getOrCreateGeneratorPrototype(JSContext *cx) { @@ -218,6 +307,11 @@ class GlobalObject : public ::JSObject { inline RegExpStatics *getRegExpStatics() const; + JSObject *getThrowTypeError() const { + JS_ASSERT(functionObjectClassesInitialized()); + return &getSlot(THROWTYPEERROR).toObject(); + } + void clear(JSContext *cx); bool isCleared() const { @@ -272,4 +366,17 @@ typedef HashSet, SystemAllocPolicy } // namespace js +inline bool +JSObject::isGlobal() const +{ + return !!(js::GetObjectClass(this)->flags & JSCLASS_IS_GLOBAL); +} + +js::GlobalObject * +JSObject::asGlobal() +{ + JS_ASSERT(isGlobal()); + return static_cast(this); +} + #endif /* GlobalObject_h___ */ diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp index 9cdfbd4bb112..d5b88fac7673 100644 --- a/js/src/yarr/YarrJIT.cpp +++ b/js/src/yarr/YarrJIT.cpp @@ -1205,8 +1205,10 @@ class YarrGenerator : private MacroAssembler { // If we get here, the prior alternative matched - return success. // Adjust the stack pointer to remove the pattern's frame. +#if !WTF_CPU_SPARC if (m_pattern.m_body->m_callFrameSize) addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); +#endif // Load appropriate values into the return register and the first output // slot, and return. In the case of pattern with a fixed size, we will @@ -1513,8 +1515,10 @@ class YarrGenerator : private MacroAssembler { } case OpMatchFailed: +#if !WTF_CPU_SPARC if (m_pattern.m_body->m_callFrameSize) addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); +#endif move(TrustedImm32(-1), returnRegister); generateReturn(); break; @@ -1753,8 +1757,10 @@ class YarrGenerator : private MacroAssembler { // run any matches, and need to return a failure state from JIT code. matchFailed.link(this); +#if !WTF_CPU_SPARC if (m_pattern.m_body->m_callFrameSize) addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); +#endif move(TrustedImm32(-1), returnRegister); generateReturn(); break; @@ -2326,8 +2332,6 @@ class YarrGenerator : private MacroAssembler { push(SH4Registers::r13); #elif WTF_CPU_SPARC save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); - // set m_callFrameSize to 0 avoid and stack movement later. - m_pattern.m_body->m_callFrameSize = 0; #elif WTF_CPU_MIPS // Do nothing. #endif @@ -2377,8 +2381,10 @@ public: if (!m_pattern.m_body->m_hasFixedSize) store32(index, Address(output)); +#if !WTF_CPU_SPARC if (m_pattern.m_body->m_callFrameSize) subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); +#endif // Compile the pattern to the internal 'YarrOp' representation. opCompileBody(m_pattern.m_body); diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index faab65f100ae..7fbde0c7408e 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -204,7 +204,8 @@ Dump(JSContext *cx, uintN argc, jsval *vp) if (!chars) return JS_FALSE; - fputs(NS_ConvertUTF16toUTF8(reinterpret_cast(chars)).get(), stderr); + fputs(NS_ConvertUTF16toUTF8(reinterpret_cast(chars)).get(), stdout); + fflush(stdout); return JS_TRUE; } diff --git a/js/xpconnect/shell/Makefile.in b/js/xpconnect/shell/Makefile.in index f5c3fdd3c715..37c58fdde771 100644 --- a/js/xpconnect/shell/Makefile.in +++ b/js/xpconnect/shell/Makefile.in @@ -74,6 +74,9 @@ WIN32_EXE_LDFLAGS += -STACK:2097152 endif endif +ifeq ($(OS_TEST),ia64) +LIBS += $(JEMALLOC_LIBS) +endif include $(topsrcdir)/config/config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/config/rules.mk diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 27f1e3ec0d9b..34e83e78a9dd 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -436,7 +436,7 @@ void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc) while ((acx = JS_ContextIterator(GetJSRuntime(), &iter))) { JS_ASSERT(acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL)); if (acx->globalObject) - JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object"); + JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "XPC global object"); } XPCAutoLock lock(mMapLock); diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf index 3148a229f08a..47ce440d7a72 100644 --- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -65,6 +65,7 @@ members = [ 'nsIDOMWindow.name', 'nsIDOMWindow.parent', 'nsIDOMWindow.top', + 'nsIDOMWindow.self', # Several window properties are magically resolved, including # location, _content, navigator, document, and window itself. # These do not need quick stubs. @@ -452,8 +453,8 @@ members = [ 'nsIIDBRequest.*', 'nsIIDBTransaction.*', 'nsIIDBFactory.*', + 'nsIIDBOpenDBRequest.*', 'nsIIDBVersionChangeEvent.*', - 'nsIIDBVersionChangeRequest.*', 'nsIIndexedDatabaseUsageCallback.*', 'nsIIndexedDatabaseManager.*', ] @@ -486,6 +487,7 @@ irregularFilenames = { 'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext', 'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext', 'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext', + 'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext', 'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager', diff --git a/js/xpconnect/src/dombindings.cpp b/js/xpconnect/src/dombindings.cpp index dc11fa28825c..bf1b882585f8 100644 --- a/js/xpconnect/src/dombindings.cpp +++ b/js/xpconnect/src/dombindings.cpp @@ -487,6 +487,8 @@ ListBase::create(JSContext *cx, XPCWrappedNativeScope *scope, ListType *aLis } JSObject *proto = getPrototype(cx, scope, triedToWrap); + if (!proto && !*triedToWrap) + aWrapperCache->ClearIsProxy(); if (!proto) return NULL; JSObject *obj = NewProxyObject(cx, &ListBase::instance, @@ -539,6 +541,9 @@ GetArrayIndexFromId(JSContext *cx, jsid id) jschar s = *atom->chars(); if (NS_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z')) return -1; + + jsuint i; + return js::StringIsArrayIndex(JSID_TO_ATOM(id), &i) ? i : -1; } return IdToInt32(cx, id); } @@ -806,7 +811,23 @@ template bool ListBase::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { - return ProxyHandler::has(cx, proxy, id, bp); + if (!hasOwn(cx, proxy, id, bp)) + return false; + // We have the property ourselves; no need to worry about our + // prototype chain. + if (*bp) + return true; + + // OK, now we have to look at the proto + JSObject *proto = js::GetObjectProto(proxy); + if (!proto) + return true; + + JSBool protoHasProp; + bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp); + if (ok) + *bp = protoHasProp; + return ok; } template diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index ddd23bb3ae7f..aa9a6419349a 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -779,15 +779,6 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) if (si) { JS_snprintf(name, sizeof(name), "JS Object (%s - %s)", clazz->name, si->GetJSClass()->name); - } else if (clazz == &js::ScriptClass) { - JSScript* script = (JSScript*) xpc_GetJSPrivate(obj); - if (script->filename) { - JS_snprintf(name, sizeof(name), - "JS Object (Script - %s)", - script->filename); - } else { - JS_snprintf(name, sizeof(name), "JS Object (Script)"); - } } else if (clazz == &js::FunctionClass) { JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj); JSString* str = JS_GetFunctionId(fun); diff --git a/js/xpconnect/src/qsgen.py b/js/xpconnect/src/qsgen.py index 94c7130551b4..69c88fee3a07 100644 --- a/js/xpconnect/src/qsgen.py +++ b/js/xpconnect/src/qsgen.py @@ -663,7 +663,7 @@ resultConvTemplates = { " return xpc_qsInt32ToJsval(cx, result, ${jsvalPtr});\n", 'long long': - " return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr};\n", + " return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr});\n", 'unsigned short': " ${jsvalRef} = INT_TO_JSVAL((int32) result);\n" diff --git a/js/xpconnect/tests/chrome/test_nodelists.xul b/js/xpconnect/tests/chrome/test_nodelists.xul index 7c4d5f44ce62..92ba3192a86e 100644 --- a/js/xpconnect/tests/chrome/test_nodelists.xul +++ b/js/xpconnect/tests/chrome/test_nodelists.xul @@ -30,7 +30,10 @@ ok("2" in list, "in operator works"); is(win.document.body.removeChild(win.document.body.lastChild), list2, "remove last paragraph element"); - ok(!("2" in list), "in operator doesn't see phantom element"); + if (SpecialPowers.getBoolPref("dom.new_bindings")) + ok(!("2" in list), "in operator doesn't see phantom element"); + else + todo(!("2" in list), "in operator doesn't see phantom element"); is(list[2], undefined, "no node there!"); SimpleTest.finish(); } diff --git a/js/xpconnect/tests/components/native/xpctest_attributes.cpp b/js/xpconnect/tests/components/native/xpctest_attributes.cpp index 38b2261d5f7f..55a807e55eea 100644 --- a/js/xpconnect/tests/components/native/xpctest_attributes.cpp +++ b/js/xpconnect/tests/components/native/xpctest_attributes.cpp @@ -118,8 +118,6 @@ NS_IMETHODIMP xpcTestObjectReadWrite :: GetBooleanProperty(bool *aBooleanPropert return NS_OK; } NS_IMETHODIMP xpcTestObjectReadWrite :: SetBooleanProperty(bool aBooleanProperty) { - NS_ENSURE_TRUE(aBooleanProperty == true || aBooleanProperty == false, - NS_ERROR_INVALID_ARG); boolProperty = aBooleanProperty; return NS_OK; } diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 30470c706dc6..1a18cf5069cc 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -970,6 +970,12 @@ ContainerState::PopThebesLayerData() nsRefPtr imageLayer = CreateOrRecycleImageLayer(); imageLayer->SetContainer(imageContainer); data->mImage->ConfigureLayer(imageLayer); + if (mParameters.mInActiveTransformedSubtree) { + // The layer's current transform is applied first, then the result is scaled. + gfx3DMatrix transform = imageLayer->GetTransform()* + gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f); + imageLayer->SetTransform(transform); + } NS_ASSERTION(data->mImageClip.mRoundedClipRects.IsEmpty(), "How did we get rounded clip rects here?"); if (data->mImageClip.mHaveClipRect) { @@ -1124,6 +1130,17 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, { nscolor uniformColor; bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor); + + /* Mark as available for conversion to image layer if this is a nsDisplayImage and + * we are the first visible item in the ThebesLayerData object. + */ + if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) { + mImage = static_cast(aItem); + mImageClip = aClip; + } else { + mImage = nsnull; + } + // Some display items have to exist (so they can set forceTransparentSurface // below) but don't draw anything. They'll return true for isUniform but // a color with opacity 0. @@ -1152,16 +1169,6 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, mDrawRegion.Or(mDrawRegion, aDrawRect); mDrawRegion.SimplifyOutward(4); } - - /* Mark as available for conversion to image layer if this is a nsDisplayImage and - * we are the first visible item in the ThebesLayerData object. - */ - if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) { - mImage = static_cast(aItem); - mImageClip = aClip; - } else { - mImage = nsnull; - } bool forceTransparentSurface = false; nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &forceTransparentSurface); @@ -2106,6 +2113,10 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, if (cdi->mInactiveLayer) { PaintInactiveLayer(builder, cdi->mItem, aContext); } else { + nsIFrame* frame = cdi->mItem->GetUnderlyingFrame(); + if (frame) { + frame->AddStateBits(NS_FRAME_PAINTED_THEBES); + } cdi->mItem->Paint(builder, rc); } diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index fe9afda75a32..3769c8cd4088 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -9288,9 +9288,15 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState, spaceEndIter.item().IsWhitespace(aState)) { bool trailingSpaces = spaceEndIter.SkipWhitespace(aState); - // See whether we can drop the whitespace - if (trailingSpaces || - spaceEndIter.item().DesiredParentType() != eTypeBlock) { + // We drop the whitespace if these are not trailing spaces and the next item + // does not want a block parent (see case 2 above) + // if these are trailing spaces and aParentFrame is a tabular container + // according to rule 1.3 of CSS 2.1 Sec 17.2.1. (Being a tabular container + // pretty much means ourParentType != eTypeBlock besides the eTypeColGroup case, + // which won't reach here.) + if ((trailingSpaces && ourParentType != eTypeBlock) || + (!trailingSpaces && spaceEndIter.item().DesiredParentType() != + eTypeBlock)) { bool updateStart = (iter == endIter); endIter.DeleteItemsTo(spaceEndIter); NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match"); diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index c88b3cc9c1be..64c09f189f3b 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -1804,6 +1804,13 @@ ComputeLinearGradientLine(nsPresContext* aPresContext, gfxPoint center(aBoxSize.width/2, aBoxSize.height/2); *aLineEnd = ComputeGradientLineEndFromAngle(center, angle, aBoxSize); *aLineStart = gfxPoint(aBoxSize.width, aBoxSize.height) - *aLineEnd; + } else if (aGradient->mToCorner) { + float xSign = aGradient->mBgPosX.GetPercentValue() * 2 - 1; + float ySign = 1 - aGradient->mBgPosY.GetPercentValue() * 2; + double angle = atan2(ySign * aBoxSize.width, xSign * aBoxSize.height); + gfxPoint center(aBoxSize.width/2, aBoxSize.height/2); + *aLineEnd = ComputeGradientLineEndFromAngle(center, angle, aBoxSize); + *aLineStart = gfxPoint(aBoxSize.width, aBoxSize.height) - *aLineEnd; } else { PRInt32 appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel(); *aLineStart = gfxPoint( diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index bef625719a2d..95c84d54d565 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -620,6 +620,12 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, root, mVisibleRect, mVisibleRect, (usingDisplayport ? &displayport : nsnull), id, containerParameters); + if (usingDisplayport && + !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) { + // See bug 693938, attachment 567017 + NS_WARNING("We don't support transparent content with displayports, force it to be opqaue"); + root->SetContentFlags(Layer::CONTENT_OPAQUE); + } layerManager->SetRoot(root); aBuilder->LayerBuilder()->WillEndTransaction(layerManager); @@ -1774,10 +1780,26 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, return layer.forget(); } +/** + * This doesn't take into account layer scaling --- the layer may be + * rendered at a higher (or lower) resolution, affecting the retained layer + * size --- but this should be good enough. + */ +static bool +IsItemTooSmallForActiveLayer(nsDisplayItem* aItem) +{ + nsIntRect visibleDevPixels = aItem->GetVisibleRect().ToOutsidePixels( + aItem->GetUnderlyingFrame()->PresContext()->AppUnitsPerDevPixel()); + static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16; + return visibleDevPixels.Size() < + nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS); +} + nsDisplayItem::LayerState nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager) { - if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer)) + if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) && + !IsItemTooSmallForActiveLayer(this)) return LAYER_ACTIVE; nsIFrame* activeScrolledRoot = nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull); @@ -2599,7 +2621,10 @@ already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu nsDisplayItem::LayerState nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager) { - if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) + // Here we check if the *post-transform* bounds of this item are big enough + // to justify an active layer. + if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) && + !IsItemTooSmallForActiveLayer(this)) return LAYER_ACTIVE; if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D()) return LAYER_ACTIVE; @@ -2977,20 +3002,3 @@ bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame)); return true; } - -nsDisplayForcePaintOnScroll::nsDisplayForcePaintOnScroll( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayForcePaintOnScroll); -} - -#ifdef NS_BUILD_REFCNT_LOGGING -nsDisplayForcePaintOnScroll::~nsDisplayForcePaintOnScroll() { - MOZ_COUNT_DTOR(nsDisplayForcePaintOnScroll); -} -#endif - -bool nsDisplayForcePaintOnScroll::IsVaryingRelativeToMovingFrame( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) { - return true; -} diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index f805e8a7f27c..59a3a18d9185 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2261,22 +2261,4 @@ public: nscoord mRightEdge; // length from the right side }; - -/** - * This is a dummy item that reports true for IsVaryingRelativeToMovingFrame. - * It forces the bounds of its frame to be repainted every time it is scrolled. - * It is transparent to events and does not paint anything. - */ -class nsDisplayForcePaintOnScroll : public nsDisplayItem -{ -public: - nsDisplayForcePaintOnScroll(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayForcePaintOnScroll(); -#endif - NS_DISPLAY_DECL_NAME("ForcePaintOnScroll", TYPE_FORCEPAINTONSCROLL) - virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame); -}; - #endif /*NSDISPLAYLIST_H_*/ diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 9fa34d761c2e..e5ae9c16e2b2 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1959,7 +1959,7 @@ DocumentViewerImpl::Show(void) printf("About to evict content viewers: prev=%d, loaded=%d\n", prevIndex, loadedIndex); #endif - historyInt->EvictContentViewers(prevIndex, loadedIndex); + historyInt->EvictOutOfRangeContentViewers(loadedIndex); } } } diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 55614903d46a..9e23a3abc8c1 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1173,6 +1173,10 @@ public: static void InitializeStatics(); static void ReleaseStatics(); + // If a frame in the subtree rooted at aFrame is capturing the mouse then + // clears that capture. + static void ClearMouseCapture(nsIFrame* aFrame); + protected: friend class nsRefreshDriver; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 41d7c4e01cf0..157a82f8e9ee 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4261,23 +4261,22 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, nsTextFrame* curr = static_cast(aFrame); do { - PRInt32 offset = curr->GetContentOffset(); - PRInt32 fstart = NS_MAX(offset, aStartOffset); + PRInt32 fstart = NS_MAX(curr->GetContentOffset(), aStartOffset); PRInt32 fend = NS_MIN(curr->GetContentEnd(), aEndOffset); if (fstart >= fend) { continue; } // overlapping with the offset we want - curr->EnsureTextRun(); + gfxSkipCharsIterator iter = curr->EnsureTextRun(); gfxTextRun* textRun = curr->GetTextRun(); NS_ENSURE_TRUE(textRun, NS_ERROR_OUT_OF_MEMORY); - gfxSkipCharsIterator iter(textRun->GetSkipChars()); - PRUint32 skipStart = iter.ConvertOriginalToSkipped(fstart - offset); - PRUint32 skipEnd = iter.ConvertOriginalToSkipped(fend - offset); + PRUint32 skipStart = iter.ConvertOriginalToSkipped(fstart); + PRUint32 skipEnd = iter.ConvertOriginalToSkipped(fend); aFontFaceList->AddFontsFromTextRun(textRun, - skipStart, skipEnd - skipStart, + skipStart, + skipEnd - skipStart, curr); } while (aFollowContinuations && (curr = static_cast(curr->GetNextContinuation()))); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 6bf4992fb716..60f370d2c198 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2700,3 +2700,27 @@ nsRootPresContext::EnsureEventualDidPaintEvent() mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback, (void*)this, 100, nsITimer::TYPE_ONE_SHOT); } + +void +nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable) +{ + if (!mWillPaintFallbackEvent.IsPending()) { + mWillPaintFallbackEvent = new RunWillPaintObservers(this); + NS_DispatchToMainThread(mWillPaintFallbackEvent.get()); + } + mWillPaintObservers.AppendElement(aRunnable); +} + +/** + * Run all runnables that need to get called before the next paint. + */ +void +nsRootPresContext::FlushWillPaintObservers() +{ + mWillPaintFallbackEvent = nsnull; + nsTArray > observers; + observers.SwapElements(mWillPaintObservers); + for (PRUint32 i = 0; i < observers.Length(); ++i) { + observers[i]->Run(); + } +} diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 25de19447810..fa089302b1b2 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -1304,12 +1304,40 @@ public: */ PRUint32 GetDOMGeneration() { return mDOMGeneration; } -private: + /** + * Add a runnable that will get called before the next paint. They will get + * run eventually even if painting doesn't happen. They might run well before + * painting happens. + */ + void AddWillPaintObserver(nsIRunnable* aRunnable); + + /** + * Run all runnables that need to get called before the next paint. + */ + void FlushWillPaintObservers(); + +protected: + class RunWillPaintObservers : public nsRunnable { + public: + RunWillPaintObservers(nsRootPresContext* aPresContext) : mPresContext(aPresContext) {} + void Revoke() { mPresContext = nsnull; } + NS_IMETHOD Run() + { + if (mPresContext) { + mPresContext->FlushWillPaintObservers(); + } + return NS_OK; + } + nsRootPresContext* mPresContext; + }; + nsCOMPtr mNotifyDidPaintTimer; nsTHashtable > mRegisteredPlugins; // if mNeedsToUpdatePluginGeometry is set, then this is the frame to // use as the root of the subtree to search for plugin updates, or // null to use the root frame of this prescontext + nsTArray > mWillPaintObservers; + nsRevocableEventPtr mWillPaintFallbackEvent; nsIFrame* mUpdatePluginGeometryForFrame; PRUint32 mDOMGeneration; bool mNeedsToUpdatePluginGeometry; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 75e52b87a28f..0066720a8bd9 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -56,6 +56,8 @@ /* a presentation of a document, part 2 */ +#include "mozilla/dom/PBrowserChild.h" +#include "mozilla/dom/TabChild.h" #include "mozilla/Util.h" #include "nsPresShell.h" @@ -197,6 +199,7 @@ #include "mozilla/FunctionTimer.h" #include "mozilla/Preferences.h" +#include "mozilla/Telemetry.h" #include "Layers.h" @@ -1904,6 +1907,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } NS_TIME_FUNCTION_WITH_DOCURL; + mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now(); NS_ASSERTION(!mDidInitialReflow, "Why are we being called?"); @@ -2044,6 +2048,11 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } } + if (root && root->IsXUL()) { + mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_INITIAL_FRAME_CONSTRUCTION, + timerStart); + } + return NS_OK; //XXX this needs to be real. MMP } @@ -3646,40 +3655,49 @@ PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent, NS_IMETHODIMP_(void) PresShell::ClearMouseCapture(nsIView* aView) { - if (gCaptureInfo.mContent) { - if (aView) { - // if a view was specified, ensure that the captured content is within - // this view. - nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame(); - if (frame) { - nsIView* view = frame->GetClosestView(); - // if there is no view, capturing won't be handled any more, so - // just release the capture. - if (view) { - do { - if (view == aView) { - NS_RELEASE(gCaptureInfo.mContent); - // the view containing the captured content likely disappeared so - // disable capture for now. - gCaptureInfo.mAllowed = false; - break; - } - - view = view->GetParent(); - } while (view); - // return if the view wasn't found - return; - } - } - } - - NS_RELEASE(gCaptureInfo.mContent); + if (!aView) { + nsIPresShell::ClearMouseCapture(static_cast(nsnull)); + return; } - // disable mouse capture until the next mousedown as a dialog has opened - // or a drag has started. Otherwise, someone could start capture during - // the modal dialog or drag. - gCaptureInfo.mAllowed = false; + nsIFrame* frame = nsnull; + nsIView* view = aView; + while (!frame && view) { + frame = static_cast(view->GetClientData()); + view = view->GetParent(); + } + + if (frame) { + nsIPresShell::ClearMouseCapture(frame); + } +} + +void +nsIPresShell::ClearMouseCapture(nsIFrame* aFrame) +{ + if (!gCaptureInfo.mContent) { + gCaptureInfo.mAllowed = false; + return; + } + + // null frame argument means clear the capture + if (!aFrame) { + NS_RELEASE(gCaptureInfo.mContent); + gCaptureInfo.mAllowed = false; + return; + } + + nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame(); + if (!capturingFrame) { + NS_RELEASE(gCaptureInfo.mContent); + gCaptureInfo.mAllowed = false; + return; + } + + if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) { + NS_RELEASE(gCaptureInfo.mContent); + gCaptureInfo.mAllowed = false; + } } nsresult @@ -4442,6 +4460,13 @@ PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags, NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED); + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); + if (rootPresContext) { + rootPresContext->FlushWillPaintObservers(); + if (mIsDestroying) + return NS_OK; + } + nsAutoScriptBlocker blockScripts; // Set up the rectangle as the path in aThebesContext @@ -5092,6 +5117,11 @@ void PresShell::UpdateCanvasBackground() if (!FrameConstructor()->GetRootElementFrame()) { mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw(); } + if (XRE_GetProcessType() == GeckoProcessType_Content) { + if (TabChild* tabChild = GetTabChildFrom(this)) { + tabChild->SetBackgroundColor(mCanvasBackgroundColor); + } + } } nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot) @@ -5221,8 +5251,11 @@ static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt) return nsnull; nsIFrame* frame = static_cast(aView->GetClientData()); - if (frame && !frame->PresContext()->PresShell()->IsActive()) { - return nsnull; + if (frame) { + if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) || + !frame->PresContext()->PresShell()->IsActive()) { + return nsnull; + } } for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { @@ -5255,8 +5288,11 @@ static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt) } nsIFrame* frame = static_cast(aView->GetClientData()); - if (frame && !frame->PresContext()->PresShell()->IsActive()) { - return nsnull; + if (frame) { + if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) || + !frame->PresContext()->PresShell()->IsActive()) { + return nsnull; + } } for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { @@ -6020,7 +6056,17 @@ PresShell::HandleEvent(nsIView *aView, // still get sent to the window properly if nothing is focused or if a // frame goes away while it is focused. if (!eventTarget || !eventTarget->GetPrimaryFrame()) { - eventTarget = mDocument->GetRootElement(); + nsCOMPtr htmlDoc = do_QueryInterface(mDocument); + if (htmlDoc) { + nsCOMPtr body; + htmlDoc->GetBody(getter_AddRefs(body)); + eventTarget = do_QueryInterface(body); + if (!eventTarget) { + eventTarget = mDocument->GetRootElement(); + } + } else { + eventTarget = mDocument->GetRootElement(); + } } if (aEvent->message == NS_KEY_DOWN) { @@ -6824,20 +6870,22 @@ PresShell::WillPaint(bool aWillSendDidPaint) { // Don't bother doing anything if some viewmanager in our tree is painting // while we still have painting suppressed or we are not active. - if (mPaintingSuppressed || !mIsActive) { + if (mPaintingSuppressed || !mIsActive || !IsVisible()) { return; } - if (!aWillSendDidPaint) { - nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); - if (!rootPresContext) { - return; - } - if (rootPresContext == mPresContext) { - rootPresContext->UpdatePluginGeometry(); - } + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); + if (!rootPresContext) { + return; } + if (!aWillSendDidPaint && rootPresContext == mPresContext) { + rootPresContext->UpdatePluginGeometry(); + } + rootPresContext->FlushWillPaintObservers(); + if (mIsDestroying) + return; + // Process reflows, if we have them, to reduce flicker due to invalidates and // reflow being interspersed. Note that we _do_ allow this to be // interruptible; if we can't do all the reflows it's better to flicker a bit @@ -6848,7 +6896,7 @@ PresShell::WillPaint(bool aWillSendDidPaint) NS_IMETHODIMP_(void) PresShell::DidPaint() { - if (mPaintingSuppressed || !mIsActive) { + if (mPaintingSuppressed || !mIsActive || !IsVisible()) { return; } @@ -6861,6 +6909,33 @@ PresShell::DidPaint() } } +NS_IMETHODIMP_(bool) +PresShell::IsVisible() +{ + if (!mViewManager) + return false; + + nsIView* view = mViewManager->GetRootView(); + if (!view) + return true; + + // inner view of subdoc frame + view = view->GetParent(); + if (!view) + return true; + + // subdoc view + view = view->GetParent(); + if (!view) + return true; + + nsIFrame* frame = static_cast(view->GetClientData()); + if (!frame) + return true; + + return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY); +} + nsresult PresShell::GetAgentStyleSheets(nsCOMArray& aSheets) { @@ -7324,7 +7399,7 @@ bool PresShell::ProcessReflowCommands(bool aInterruptible) { NS_TIME_FUNCTION_WITH_DOCURL; - + mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now(); bool interrupted = false; if (0 != mDirtyRoots.Length()) { @@ -7403,6 +7478,11 @@ PresShell::ProcessReflowCommands(bool aInterruptible) UnsuppressAndInvalidate(); } + if (mDocument->GetRootElement() && mDocument->GetRootElement()->IsXUL()) { + mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_REFLOW_MS, + timerStart); + } + return !interrupted; } diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index d4d93f7d3e72..132d79225c9a 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -337,6 +337,7 @@ public: NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange); NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView); + NS_IMETHOD_(bool) IsVisible(); // caret handling virtual NS_HIDDEN_(already_AddRefed) GetCaret() const; diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index d241d692af3b..16154bf6e3d6 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -65,6 +65,9 @@ _TEST_FILES = \ border_radius_hit_testing_iframe.html \ test_preserve3d_sorting_hit_testing.html \ preserve3d_sorting_hit_testing_iframe.html \ + test_image_layers.html \ + image_rgrg-256x256.png \ + image_rrgg-256x256.png \ bug369950-subframe.xml \ decoration_line_rendering.js \ test_after_paint_pref.html \ @@ -346,6 +349,7 @@ _TEST_FILES += \ test_bug607529.html \ file_bug607529.html \ test_bug644768.html \ + test_bug696020.html \ $(NULL) endif diff --git a/layout/base/tests/image_rgrg-256x256.png b/layout/base/tests/image_rgrg-256x256.png new file mode 100644 index 000000000000..e6fba3daa5df Binary files /dev/null and b/layout/base/tests/image_rgrg-256x256.png differ diff --git a/layout/base/tests/image_rrgg-256x256.png b/layout/base/tests/image_rrgg-256x256.png new file mode 100644 index 000000000000..7f6351565473 Binary files /dev/null and b/layout/base/tests/image_rrgg-256x256.png differ diff --git a/layout/base/tests/test_bug696020.html b/layout/base/tests/test_bug696020.html new file mode 100644 index 000000000000..41bd2d8b0e22 --- /dev/null +++ b/layout/base/tests/test_bug696020.html @@ -0,0 +1,47 @@ + + + + + Test for Bug 696020 + + + + + +Mozilla Bug 696020 +

+ +
+
+
+ + + diff --git a/layout/base/tests/test_image_layers.html b/layout/base/tests/test_image_layers.html new file mode 100644 index 000000000000..cba1522a3941 --- /dev/null +++ b/layout/base/tests/test_image_layers.html @@ -0,0 +1,46 @@ + + + + Test that images that are the only item in ThebesLayers get put into ImageLayers + + + + +
+ +
+
+
+
+ + diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 563ba2e73cfe..916438376fcc 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -114,7 +114,7 @@ private: nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } void diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index 9c4fc4b518ff..10506d92ce78 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -153,7 +153,7 @@ public: // override bounds because the list item focus ring may extend outside // the nsSelectsAreaFrame nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame()); - return listFrame->GetVisualOverflowRect() + + return listFrame->GetVisualOverflowRectRelativeToSelf() + aBuilder->ToReferenceFrame(listFrame); } virtual void Paint(nsDisplayListBuilder* aBuilder, diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index c5a749977680..29ba6a226b9c 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -51,6 +51,7 @@ #include "nsRect.h" #include "nsRenderingContext.h" #include "nsTextFrame.h" +#include "nsGfxScrollFrame.h" namespace mozilla { namespace css { @@ -278,6 +279,8 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, textOverflow->mCanHaveHorizontalScrollbar = scroll->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN; textOverflow->mContentArea.MoveBy(scroll->GetScrollPosition()); + nsIFrame* scrollFrame = do_QueryFrame(scroll); + scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL); } PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection; textOverflow->mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL; @@ -290,23 +293,6 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, return textOverflow.forget(); } -void -TextOverflow::DidProcessLines() -{ - nsIScrollableFrame* scroll = nsLayoutUtils::GetScrollableFrameFor(mBlock); - if (scroll) { - // Create a dummy item covering the entire area, it doesn't paint - // but reports true for IsVaryingRelativeToMovingFrame(). - nsIFrame* scrollFrame = do_QueryFrame(scroll); - nsDisplayItem* marker = new (mBuilder) - nsDisplayForcePaintOnScroll(mBuilder, scrollFrame); - if (marker) { - mMarkerList->AppendNewToBottom(marker); - mBlock->PresContext()->SetHasFixedBackgroundFrame(); - } - } -} - void TextOverflow::ExamineFrameSubtree(nsIFrame* aFrame, const nsRect& aContentArea, diff --git a/layout/generic/TextOverflow.h b/layout/generic/TextOverflow.h index 0f8eaa2a2b44..abba2b3eb4c7 100644 --- a/layout/generic/TextOverflow.h +++ b/layout/generic/TextOverflow.h @@ -52,7 +52,6 @@ namespace css { * Usage: * 1. allocate an object using WillProcessLines * 2. then call ProcessLine for each line you are building display lists for - * 3. finally call DidProcessLines */ class TextOverflow { public: @@ -70,12 +69,6 @@ class TextOverflow { */ void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine); - /** - * Do final processing, currently just adds a dummy item for scroll frames - * to make IsVaryingRelativeToMovingFrame() true for the entire area. - */ - void DidProcessLines(); - /** * @return true if aBlockFrame needs analysis for text overflow. */ diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 161b6913a71d..bf7b9de51ee0 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -6247,11 +6247,6 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } } - // Finalize text-overflow processing. - if (textOverflow) { - textOverflow->DidProcessLines(); - } - if (NS_SUCCEEDED(rv) && (nsnull != mBullet) && HaveOutsideBullet()) { // Display outside bullets manually rv = BuildDisplayListForChild(aBuilder, mBullet, aDirtyRect, aLists); diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index a49e12375122..eb3cc0137b09 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -226,7 +226,7 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 69e6bec05520..8ce78119cfce 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -119,6 +119,7 @@ #include "nsSVGIntegrationUtils.h" #include "nsSVGEffects.h" #include "nsChangeHint.h" +#include "nsDeckFrame.h" #include "gfxContext.h" #include "CSSCalc.h" @@ -282,6 +283,67 @@ nsIFrame::MarkAsAbsoluteContainingBlock() { Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); } +bool +nsIFrame::CheckAndClearPaintedState() +{ + bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES); + RemoveStateBits(NS_FRAME_PAINTED_THEBES); + + nsIFrame::ChildListIterator lists(this); + for (; !lists.IsDone(); lists.Next()) { + nsFrameList::Enumerator childFrames(lists.CurrentList()); + for (; !childFrames.AtEnd(); childFrames.Next()) { + nsIFrame* child = childFrames.get(); + if (child->CheckAndClearPaintedState()) { + result = true; + } + } + } + return result; +} + +bool +nsIFrame::IsVisibleConsideringAncestors(PRUint32 aFlags) const +{ + if (!GetStyleVisibility()->IsVisible()) { + return false; + } + + const nsIFrame* frame = this; + while (frame) { + nsIView* view = frame->GetView(); + if (view && view->GetVisibility() == nsViewVisibility_kHide) + return false; + + nsIFrame* parent = frame->GetParent(); + nsDeckFrame* deck = do_QueryFrame(parent); + if (deck) { + if (deck->GetSelectedBox() != frame) + return false; + } + + if (parent) { + frame = parent; + } else { + parent = nsLayoutUtils::GetCrossDocParentFrame(frame); + if (!parent) + break; + + if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 && + parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) { + break; + } + + if (!parent->GetStyleVisibility()->IsVisible()) + return false; + + frame = parent; + } + } + + return true; +} + static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame, const nsStyleDisplay* aDisp, @@ -1803,14 +1865,11 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (aChild->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) return NS_OK; - const nsStyleDisplay* disp = aChild->GetStyleDisplay(); // true if this is a real or pseudo stacking context bool pseudoStackingContext = (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0; - // XXX we REALLY need a "are you an inline-block sort of thing?" here!!! if ((aFlags & DISPLAY_CHILD_INLINE) && - (disp->mDisplay != NS_STYLE_DISPLAY_INLINE || - (aChild->IsFrameOfType(eReplaced)))) { + !aChild->IsFrameOfType(eLineParticipant)) { // child is a non-inline frame in an inline context, i.e., // it acts like inline-block or inline-table. Therefore it is a // pseudo-stacking-context. @@ -1827,8 +1886,6 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, NS_ASSERTION(aChild, "No out of flow frame?"); if (!aChild || nsLayoutUtils::IsPopup(aChild)) return NS_OK; - // update for the new child - disp = aChild->GetStyleDisplay(); // Make sure that any attempt to use childType below is disappointed. We // could call GetType again but since we don't currently need it, let's // avoid the virtual call. @@ -1894,6 +1951,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // Child is composited if it's transformed, partially transparent, or has // SVG effects. + const nsStyleDisplay* disp = aChild->GetStyleDisplay(); bool isVisuallyAtomic = disp->mOpacity != 1.0f || aChild->IsTransformed() || nsSVGIntegrationUtils::UsingEffectsForFrame(aChild); @@ -4181,30 +4239,6 @@ NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPoint& aOffset, return NS_OK; } -/* virtual */ bool -nsIFrame::AreAncestorViewsVisible() const -{ - const nsIFrame* parent; - for (const nsIFrame* f = this; f; f = parent) { - nsIView* view = f->GetView(); - if (view && view->GetVisibility() == nsViewVisibility_kHide) { - return false; - } - parent = f->GetParent(); - if (!parent) { - parent = nsLayoutUtils::GetCrossDocParentFrame(f); - if (parent && parent->PresContext()->IsChrome() && - !f->PresContext()->IsChrome()) { - // Don't look beyond chrome/content boundary ... if the chrome - // has hidden a content docshell, the content in the content - // docshell shouldn't be affected (e.g. it should remain focusable). - break; - } - } - } - return true; -} - nsIWidget* nsIFrame::GetNearestWidget() const { @@ -6990,38 +7024,34 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse) } bool isFocusable = false; - if (mContent && mContent->IsElement() && AreAncestorViewsVisible()) { - const nsStyleVisibility* vis = GetStyleVisibility(); - if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE && - vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) { - const nsStyleUserInterface* ui = GetStyleUserInterface(); - if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE && - ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) { - // Pass in default tabindex of -1 for nonfocusable and 0 for focusable - tabIndex = 0; - } - isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse); - if (!isFocusable && !aWithMouse && - GetType() == nsGkAtoms::scrollFrame && - mContent->IsHTML() && - !mContent->IsRootOfNativeAnonymousSubtree() && - mContent->GetParent() && - !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) { - // Elements with scrollable view are focusable with script & tabbable - // Otherwise you couldn't scroll them with keyboard, which is - // an accessibility issue (e.g. Section 508 rules) - // However, we don't make them to be focusable with the mouse, - // because the extra focus outlines are considered unnecessarily ugly. - // When clicked on, the selection position within the element - // will be enough to make them keyboard scrollable. - nsIScrollableFrame *scrollFrame = do_QueryFrame(this); - if (scrollFrame && - scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) && - !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) { - // Scroll bars will be used for overflow - isFocusable = true; - tabIndex = 0; - } + if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) { + const nsStyleUserInterface* ui = GetStyleUserInterface(); + if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE && + ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) { + // Pass in default tabindex of -1 for nonfocusable and 0 for focusable + tabIndex = 0; + } + isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse); + if (!isFocusable && !aWithMouse && + GetType() == nsGkAtoms::scrollFrame && + mContent->IsHTML() && + !mContent->IsRootOfNativeAnonymousSubtree() && + mContent->GetParent() && + !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) { + // Elements with scrollable view are focusable with script & tabbable + // Otherwise you couldn't scroll them with keyboard, which is + // an accessibility issue (e.g. Section 508 rules) + // However, we don't make them to be focusable with the mouse, + // because the extra focus outlines are considered unnecessarily ugly. + // When clicked on, the selection position within the element + // will be enough to make them keyboard scrollable. + nsIScrollableFrame *scrollFrame = do_QueryFrame(this); + if (scrollFrame && + scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) && + !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) { + // Scroll bars will be used for overflow + isFocusable = true; + tabIndex = 0; } } } diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 69ee18c5ea3a..483317193d7e 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1619,6 +1619,9 @@ static void AdjustViews(nsIFrame* aFrame) static bool CanScrollWithBlitting(nsIFrame* aFrame) { + if (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL) + return false; + for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) || @@ -1732,6 +1735,7 @@ void nsGfxScrollFrameInner::ScrollVisual() // to be consistent with the frame hierarchy. PRUint32 flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT; bool canScrollWithBlitting = CanScrollWithBlitting(mOuter); + mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL); if (IsScrollingActive()) { if (!canScrollWithBlitting) { MarkInactive(); @@ -2639,12 +2643,11 @@ nsGfxScrollFrameInner::PostScrollEvent() if (mScrollEvent.IsPending()) return; - nsRefPtr ev = new ScrollEvent(this); - if (NS_FAILED(NS_DispatchToCurrentThread(ev))) { - NS_WARNING("failed to dispatch ScrollEvent"); - } else { - mScrollEvent = ev; - } + nsRootPresContext* rpc = mOuter->PresContext()->GetRootPresContext(); + if (!rpc) + return; + mScrollEvent = new ScrollEvent(this); + rpc->AddWillPaintObserver(mScrollEvent.get()); } NS_IMETHODIMP diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 43e241077244..77fd7a0d42c8 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -64,6 +64,12 @@ class nsIScrollFrameInternal; class nsPresState; struct ScrollReflowState; +// When set, the next scroll operation on the scrollframe will invalidate its +// entire contents. Useful for text-overflow. +// This bit is cleared after each time the scrollframe is scrolled. Whoever +// needs to set it should set it again on each paint. +#define NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL NS_FRAME_STATE_BIT(20) + class nsGfxScrollFrameInner : public nsIReflowCallback { public: class AsyncScroll; diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 8f39ae830506..59bf434d0889 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -140,8 +140,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, NS_PRECONDITION((aContainingBlockWidth == -1) == (aContainingBlockHeight == -1), "cb width and height should only be non-default together"); - NS_PRECONDITION(aInit == true || aInit == false, - "aInit out of range for bool"); NS_PRECONDITION(!mFlags.mSpecialHeightReflow || !NS_SUBTREE_DIRTY(aFrame), "frame should be clean when getting special height reflow"); @@ -163,11 +161,15 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, mLineLayout = aParentReflowState.mLineLayout; else mLineLayout = nsnull; - mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; + + // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in + // this constructor's init list, so the only flags that we need to explicitly + // initialize here are those that may need a value other than our parent's. mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false; mFlags.mHasClearance = false; + mDiscoveredClearance = nsnull; mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index b0124063f2cd..759f463afeac 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -290,6 +290,9 @@ typedef PRUint64 nsFrameState; // Frame can accept absolutely positioned children. #define NS_FRAME_HAS_ABSPOS_CHILDREN NS_FRAME_STATE_BIT(37) +// A display item for this frame has been painted as part of a ThebesLayer. +#define NS_FRAME_PAINTED_THEBES NS_FRAME_STATE_BIT(38) + // The lower 20 bits and upper 32 bits of the frame state are reserved // by this API. #define NS_FRAME_RESERVED ~NS_FRAME_IMPL_RESERVED @@ -1894,12 +1897,6 @@ public: NS_IMETHOD GetOffsetFromView(nsPoint& aOffset, nsIView** aView) const = 0; - /** - * Returns true if and only if all views, from |GetClosestView| up to - * the top of the view hierarchy are visible. - */ - virtual bool AreAncestorViewsVisible() const; - /** * Returns the nearest widget containing this frame. If this frame has a * view and the view has a widget, then this frame's widget is @@ -2753,6 +2750,23 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty())) // Child frame types override this function to select their own child list name virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kAbsoluteList; } + // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set, and + // clears this bit if so. + bool CheckAndClearPaintedState(); + + // CSS visibility just doesn't cut it because it doesn't inherit through + // documents. Also if this frame is in a hidden card of a deck then it isn't + // visible either and that isn't expressed using CSS visibility. Also if it + // is in a hidden view (there are a few cases left and they are hopefully + // going away soon). + // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we + // ignore the chrome/content boundary, otherwise we stop looking when we + // reach it. + enum { + VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 + }; + bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const; + protected: // Members nsRect mRect; diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 451c41fe1692..45275cffd246 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -544,6 +544,7 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) */ nsPresContext *presContext = PresContext(); aImage->SetAnimationMode(presContext->ImageAnimationMode()); + mImageContainer = nsnull; if (IsPendingLoad(aRequest)) { // We don't care @@ -621,6 +622,7 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsPresContext *presContext = PresContext(); nsIPresShell *presShell = presContext->GetPresShell(); NS_ASSERTION(presShell, "No PresShell."); + mImageContainer = nsnull; // Check what request type we're dealing with nsCOMPtr imageLoader = do_QueryInterface(mContent); @@ -1237,7 +1239,10 @@ nsDisplayImage::ConfigureLayer(ImageLayer* aLayer) nsRefPtr nsImageFrame::GetContainer(LayerManager* aManager, imgIContainer* aImage) { - if (mImageContainer && mImageContainer->Manager() == aManager) { + if (mImageContainer && + (mImageContainer->Manager() == aManager || + (!mImageContainer->Manager() && + (mImageContainer->GetBackendType() == aManager->GetBackendType())))) { return mImageContainer; } diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index b4627c5a8b70..55e9251b5592 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -468,7 +468,7 @@ nsObjectFrame::CreateWidget(nscoord aWidth, // mWidget isn't the view's designated widget. EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget); rv = mWidget->Create(parentWidget, nsnull, nsIntRect(0,0,0,0), - eventHandler, dx, nsnull, &initData); + eventHandler, dx, &initData); if (NS_FAILED(rv)) { mWidget->Destroy(); mWidget = nsnull; diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 4715445d46b3..f7868013594d 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4137,7 +4137,7 @@ public: #endif virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { @@ -7608,6 +7608,11 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, textFrame = static_cast(textFrame->GetNextContinuation())) { // For each text frame continuation in this block ... + if (textFrame->GetStateBits() & NS_FRAME_IS_DIRTY) { + // We don't trust dirty frames, expecially when computing rendered text. + break; + } + // Ensure the text run and grab the gfxSkipCharsIterator for it gfxSkipCharsIterator iter = textFrame->EnsureTextRun(); if (!textFrame->mTextRun) diff --git a/layout/inspector/tests/chrome/Makefile.in b/layout/inspector/tests/chrome/Makefile.in index 4518bb32139e..aac68770d0aa 100644 --- a/layout/inspector/tests/chrome/Makefile.in +++ b/layout/inspector/tests/chrome/Makefile.in @@ -47,6 +47,8 @@ include $(topsrcdir)/config/rules.mk _CHROME_FILES =\ test_bug467669.xul \ test_bug467669.css \ + test_bug695639.xul \ + test_bug695639.css \ GentiumPlus-R.woff \ $(NULL) diff --git a/layout/inspector/tests/chrome/test_bug695639.css b/layout/inspector/tests/chrome/test_bug695639.css new file mode 100644 index 000000000000..549537498cec --- /dev/null +++ b/layout/inspector/tests/chrome/test_bug695639.css @@ -0,0 +1,8 @@ +@font-face { + font-family: gent; + src: url(GentiumPlus-R.woff) format("woff"); +} + +.test { + font-family: gent, sans-serif; +} diff --git a/layout/inspector/tests/chrome/test_bug695639.xul b/layout/inspector/tests/chrome/test_bug695639.xul new file mode 100644 index 000000000000..cc2c879c9b6f --- /dev/null +++ b/layout/inspector/tests/chrome/test_bug695639.xul @@ -0,0 +1,80 @@ + + + + + + + + + + + + Mozilla Bug 695639 +
Hello 你好 world
+ + +
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index e429fe5345b1..0762fd43e0ac 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -62,28 +62,6 @@ namespace layout { typedef FrameMetrics::ViewID ViewID; typedef RenderFrameParent::ViewMap ViewMap; -nsRefPtr sCheckerboard = nsnull; - -class CheckerBoardPatternDeleter : public nsIObserver -{ -public: - NS_DECL_NSIOBSERVER - NS_DECL_ISUPPORTS -}; - -NS_IMPL_ISUPPORTS1(CheckerBoardPatternDeleter, nsIObserver) - -NS_IMETHODIMP -CheckerBoardPatternDeleter::Observe(nsISupports* aSubject, - const char* aTopic, - const PRUnichar* aData) -{ - if (!strcmp(aTopic, "xpcom-shutdown")) { - sCheckerboard = nsnull; - } - return NS_OK; -} - // Represents (affine) transforms that are calculated from a content view. struct ViewTransform { ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1) @@ -424,61 +402,14 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews, } } -#define BOARDSIZE 32 -#define CHECKERSIZE 16 -already_AddRefed -GetBackgroundImage() -{ - static unsigned int data[BOARDSIZE * BOARDSIZE]; - static bool initialized = false; - if (!initialized) { - initialized = true; - for (unsigned int y = 0; y < BOARDSIZE; y++) { - for (unsigned int x = 0; x < BOARDSIZE; x++) { - bool col_odd = (x / CHECKERSIZE) & 1; - bool row_odd = (y / CHECKERSIZE) & 1; - if (col_odd ^ row_odd) { // xor - data[y * BOARDSIZE + x] = 0xFFFFFFFF; - } - else { - data[y * BOARDSIZE + x] = 0xFFDDDDDD; - } - } - } - } - - nsRefPtr s = - new gfxImageSurface((unsigned char*) data, - gfxIntSize(BOARDSIZE, BOARDSIZE), - BOARDSIZE * sizeof(unsigned int), - gfxASurface::ImageFormatARGB32); - return s.forget(); -} - static void BuildBackgroundPatternFor(ContainerLayer* aContainer, ContainerLayer* aShadowRoot, - const FrameMetrics& aMetrics, const ViewConfig& aConfig, + const gfxRGBA& aColor, LayerManager* aManager, - nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder) + nsIFrame* aFrame) { - // We tile a visible region that is the frame's area \setminus the - // rect in our frame onto which valid pixels from remote content - // will be drawn. It's just a waste of CPU cycles to draw a - // checkerboard behind that content. - // - // We want to give the background the illusion of moving while the - // user pans, so we nudge the tiling area a bit based on the - // "desired" scroll offset. - // - // The background-image layer is added to the layer tree "behind" - // the shadow tree. It doesn't matter in theory which is behind/in - // front, except that having the background in front of content - // means we have to be more careful about snapping boundaries, - // whereas having it behind allows us to trade off simplicity for - // "wasted" drawing of a few extra pixels. ShadowLayer* shadowRoot = aShadowRoot->AsShadowLayer(); gfxMatrix t; if (!shadowRoot->GetShadowTransform().Is2D(&t)) { @@ -505,57 +436,14 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer, if (localIntContentVis.Contains(frameRect)) { return; } - - nsRefPtr bgImage = GetBackgroundImage(); - gfxIntSize bgImageSize = bgImage->GetSize(); - - // Set up goop needed to get a cairo image into its own layer - if (!sCheckerboard) { - sCheckerboard = aManager->CreateImageContainer().get(); - const Image::Format fmts[] = { Image::CAIRO_SURFACE }; - nsRefPtr img = sCheckerboard->CreateImage(fmts, 1); - CairoImage::Data data = { bgImage.get(), bgImageSize }; - static_cast(img.get())->SetData(data); - sCheckerboard->SetCurrentImage(img); - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - if (!observerService) { - return; - } - nsresult rv = observerService->AddObserver(new CheckerBoardPatternDeleter, "xpcom-shutdown", false); - if (NS_FAILED(rv)) { - return; - } - } - - nsRefPtr layer = aManager->CreateImageLayer(); - layer->SetContainer(sCheckerboard); - - // The tile source is the entire background image - nsIntRect tileSource(0, 0, bgImageSize.width, bgImageSize.height); - layer->SetTileSourceRect(&tileSource); - - // The origin of the tiling plane, top-left of the tile source rect, - // is at layer-space point <0,0>. Set up a translation from that - // origin to the frame top-left, with the little nudge included. - nsIntPoint translation = frameRect.TopLeft(); - nsIntPoint panNudge = aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel); - // This offset must be positive to ensure that the tiling rect - // contains the frame's visible rect. The "desired" scroll offset - // is allowed to be negative, however, so we fix that up here. - panNudge.x = (panNudge.x % bgImageSize.width); - if (panNudge.x < 0) panNudge.x += bgImageSize.width; - panNudge.y = (panNudge.y % bgImageSize.height); - if (panNudge.y < 0) panNudge.y += bgImageSize.height; - - translation -= panNudge; - layer->SetTransform(gfx3DMatrix::Translation(translation.x, translation.y, 0)); + nsRefPtr layer = aManager->CreateColorLayer(); + layer->SetColor(aColor); // The visible area of the background is the frame's area minus the // content area nsIntRegion bgRgn(frameRect); bgRgn.Sub(bgRgn, localIntContentVis); - bgRgn.MoveBy(-translation); + bgRgn.MoveBy(-frameRect.TopLeft()); layer->SetVisibleRegion(bgRgn); aContainer->InsertAfter(layer, nsnull); @@ -564,6 +452,7 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer, RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader) : mFrameLoader(aFrameLoader) , mFrameLoaderDestroyed(false) + , mBackgroundColor(gfxRGBA(1, 1, 1)) { if (aFrameLoader) { mContentViews[FrameMetrics::ROOT_SCROLL_ID] = @@ -691,9 +580,9 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, const nsContentView* view = GetContentView(FrameMetrics::ROOT_SCROLL_ID); BuildBackgroundPatternFor(mContainer, shadowRoot, - shadowRoot->GetFrameMetrics(), view->GetViewConfig(), - aManager, aFrame, aBuilder); + mBackgroundColor, + aManager, aFrame); } mContainer->SetVisibleRegion(aVisibleRect); diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h index 4392f604f739..2a8f40597df3 100644 --- a/layout/ipc/RenderFrameParent.h +++ b/layout/ipc/RenderFrameParent.h @@ -98,6 +98,8 @@ public: void OwnerContentChanged(nsIContent* aContent); + void SetBackgroundColor(nscolor aColor) { mBackgroundColor = gfxRGBA(aColor); }; + protected: NS_OVERRIDE void ActorDestroy(ActorDestroyReason why); @@ -133,6 +135,8 @@ private: // It's possible for mFrameLoader==null and // mFrameLoaderDestroyed==false. bool mFrameLoaderDestroyed; + // this is gfxRGBA because that's what ColorLayer wants. + gfxRGBA mBackgroundColor; }; } // namespace layout diff --git a/layout/reftests/bugs/581317-1-ref.html b/layout/reftests/bugs/581317-1-ref.html index 3316222d9def..27bdbc29d5a4 100644 --- a/layout/reftests/bugs/581317-1-ref.html +++ b/layout/reftests/bugs/581317-1-ref.html @@ -10,9 +10,9 @@
-
+
-
+
diff --git a/layout/reftests/bugs/581317-1.html b/layout/reftests/bugs/581317-1.html index 8371765260f7..08e498cfce19 100644 --- a/layout/reftests/bugs/581317-1.html +++ b/layout/reftests/bugs/581317-1.html @@ -10,9 +10,9 @@
-
+
-
+
diff --git a/layout/reftests/bugs/696739-1-ref.html b/layout/reftests/bugs/696739-1-ref.html new file mode 100644 index 000000000000..1001d88b7da3 --- /dev/null +++ b/layout/reftests/bugs/696739-1-ref.html @@ -0,0 +1,22 @@ + + + + + + +
+
+
I should be black text on a green background
+
+
+
I should be black text on a green background
+
+
+ + diff --git a/layout/reftests/bugs/696739-1.html b/layout/reftests/bugs/696739-1.html new file mode 100644 index 000000000000..efc5c38d7635 --- /dev/null +++ b/layout/reftests/bugs/696739-1.html @@ -0,0 +1,22 @@ + + + + + + +
+
+
I should be black text on a green background
+
+
+
I should be black text on a green background
+
+
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 4a2fb1019411..462e9a12cfe2 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1667,3 +1667,4 @@ fails-if(layersGPUAccelerated&&cocoaWidget) == 654950-1.html 654950-1-ref.html # == 670467-2.html 670467-2-ref.html != 691087-1.html 691087-1-ref.html == 691571-1.html 691571-1-ref.html +== 696739-1.html 696739-1-ref.html diff --git a/layout/reftests/css-gradients/linear-ref.html b/layout/reftests/css-gradients/linear-1-ref.html similarity index 100% rename from layout/reftests/css-gradients/linear-ref.html rename to layout/reftests/css-gradients/linear-1-ref.html diff --git a/layout/reftests/css-gradients/linear-1a.html b/layout/reftests/css-gradients/linear-1a.html new file mode 100644 index 000000000000..e4a50d7791f2 --- /dev/null +++ b/layout/reftests/css-gradients/linear-1a.html @@ -0,0 +1 @@ +

diff --git a/layout/reftests/css-gradients/linear.html b/layout/reftests/css-gradients/linear-1b.html similarity index 100% rename from layout/reftests/css-gradients/linear.html rename to layout/reftests/css-gradients/linear-1b.html diff --git a/layout/reftests/css-gradients/linear-diagonal-1-ref.html b/layout/reftests/css-gradients/linear-diagonal-1-ref.html index ca4177f1b051..e0e834b48129 100644 --- a/layout/reftests/css-gradients/linear-diagonal-1-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-1-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-1c.html b/layout/reftests/css-gradients/linear-diagonal-1c.html new file mode 100644 index 000000000000..ca4177f1b051 --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-1c.html @@ -0,0 +1 @@ +
diff --git a/layout/reftests/css-gradients/linear-diagonal-2-ref.html b/layout/reftests/css-gradients/linear-diagonal-2-ref.html index 6fcab518c16f..265451e2b738 100644 --- a/layout/reftests/css-gradients/linear-diagonal-2-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-2-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-2c.html b/layout/reftests/css-gradients/linear-diagonal-2c.html new file mode 100644 index 000000000000..6fcab518c16f --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-2c.html @@ -0,0 +1 @@ +
diff --git a/layout/reftests/css-gradients/linear-diagonal-3-ref.html b/layout/reftests/css-gradients/linear-diagonal-3-ref.html index d509bfa0470c..48db034f4b14 100644 --- a/layout/reftests/css-gradients/linear-diagonal-3-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-3-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-3c.html b/layout/reftests/css-gradients/linear-diagonal-3c.html new file mode 100644 index 000000000000..d509bfa0470c --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-3c.html @@ -0,0 +1 @@ +
diff --git a/layout/reftests/css-gradients/linear-diagonal-4-ref.html b/layout/reftests/css-gradients/linear-diagonal-4-ref.html index 9c5e47b52a28..0a59b63b5f95 100644 --- a/layout/reftests/css-gradients/linear-diagonal-4-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-4-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-4c.html b/layout/reftests/css-gradients/linear-diagonal-4c.html new file mode 100644 index 000000000000..9c5e47b52a28 --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-4c.html @@ -0,0 +1 @@ +
diff --git a/layout/reftests/css-gradients/linear-diagonal-5-ref.html b/layout/reftests/css-gradients/linear-diagonal-5-ref.html index 4946b1df6f6f..aa636c90e072 100644 --- a/layout/reftests/css-gradients/linear-diagonal-5-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-5-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-6-ref.html b/layout/reftests/css-gradients/linear-diagonal-6-ref.html index 8c93a55808ea..3c7ffe14c628 100644 --- a/layout/reftests/css-gradients/linear-diagonal-6-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-6-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-7-ref.html b/layout/reftests/css-gradients/linear-diagonal-7-ref.html index 555a184419b3..2cda3d58502d 100644 --- a/layout/reftests/css-gradients/linear-diagonal-7-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-7-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-8-ref.html b/layout/reftests/css-gradients/linear-diagonal-8-ref.html index cbbee2dc1423..50c2fec5e210 100644 --- a/layout/reftests/css-gradients/linear-diagonal-8-ref.html +++ b/layout/reftests/css-gradients/linear-diagonal-8-ref.html @@ -1 +1 @@ -
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-9-ref.html b/layout/reftests/css-gradients/linear-diagonal-9-ref.html new file mode 100644 index 000000000000..f271b045366e --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-9-ref.html @@ -0,0 +1,20 @@ + + +
+
+
+
+
+
+
+
diff --git a/layout/reftests/css-gradients/linear-diagonal-9a.html b/layout/reftests/css-gradients/linear-diagonal-9a.html new file mode 100644 index 000000000000..3f41a54411ae --- /dev/null +++ b/layout/reftests/css-gradients/linear-diagonal-9a.html @@ -0,0 +1,20 @@ + + +
+
+
+
+
+
+
+
diff --git a/layout/reftests/css-gradients/linear-keywords-ref.html b/layout/reftests/css-gradients/linear-keywords-1-ref.html similarity index 100% rename from layout/reftests/css-gradients/linear-keywords-ref.html rename to layout/reftests/css-gradients/linear-keywords-1-ref.html diff --git a/layout/reftests/css-gradients/linear-keywords-1a.html b/layout/reftests/css-gradients/linear-keywords-1a.html new file mode 100644 index 000000000000..bd667b8dcba6 --- /dev/null +++ b/layout/reftests/css-gradients/linear-keywords-1a.html @@ -0,0 +1 @@ +

diff --git a/layout/reftests/css-gradients/linear-keywords.html b/layout/reftests/css-gradients/linear-keywords-1b.html similarity index 100% rename from layout/reftests/css-gradients/linear-keywords.html rename to layout/reftests/css-gradients/linear-keywords-1b.html diff --git a/layout/reftests/css-gradients/linear-onestopposition-1-ref.html b/layout/reftests/css-gradients/linear-onestopposition-1-ref.html index c26a7de8dc0a..f984d8581a0e 100644 --- a/layout/reftests/css-gradients/linear-onestopposition-1-ref.html +++ b/layout/reftests/css-gradients/linear-onestopposition-1-ref.html @@ -5,7 +5,7 @@ div { width: 200px; height: 200px; - background-image: -moz-linear-gradient(left, blue 0%, blue 25%, orange 25%, orange 100%); + background-image: -moz-linear-gradient(to right, blue 0%, blue 25%, orange 25%, orange 100%); } diff --git a/layout/reftests/css-gradients/linear-position-1-ref.html b/layout/reftests/css-gradients/linear-position-1-ref.html index bf22da17a332..ce624140a44e 100644 --- a/layout/reftests/css-gradients/linear-position-1-ref.html +++ b/layout/reftests/css-gradients/linear-position-1-ref.html @@ -1,2 +1,2 @@ -

+

diff --git a/layout/reftests/css-gradients/linear-vertical-1e.html b/layout/reftests/css-gradients/linear-vertical-1e.html new file mode 100644 index 000000000000..1f8de8210461 --- /dev/null +++ b/layout/reftests/css-gradients/linear-vertical-1e.html @@ -0,0 +1 @@ +
diff --git a/layout/reftests/css-gradients/nostops.html b/layout/reftests/css-gradients/nostops.html index 5f9933cb3326..5a9899bb7064 100644 --- a/layout/reftests/css-gradients/nostops.html +++ b/layout/reftests/css-gradients/nostops.html @@ -1 +1 @@ -

+

diff --git a/layout/reftests/css-gradients/onestop.html b/layout/reftests/css-gradients/onestop.html index 9d8641e956c7..1e678547abe6 100644 --- a/layout/reftests/css-gradients/onestop.html +++ b/layout/reftests/css-gradients/onestop.html @@ -1 +1 @@ -

+

diff --git a/layout/reftests/css-gradients/reftest.list b/layout/reftests/css-gradients/reftest.list index 8d46b8ed633d..f6164965b140 100644 --- a/layout/reftests/css-gradients/reftest.list +++ b/layout/reftests/css-gradients/reftest.list @@ -1,19 +1,26 @@ -fails-if(Android) == linear.html linear-ref.html -fails-if(Android) == linear-keywords.html linear-keywords-ref.html +fails-if(Android) == linear-1a.html linear-1-ref.html +fails-if(Android) == linear-1b.html linear-1-ref.html +fails-if(Android) == linear-keywords-1a.html linear-keywords-1-ref.html +fails-if(Android) == linear-keywords-1b.html linear-keywords-1-ref.html fails-if(Android) == linear-percent.html linear-percent-ref.html fails-if(Android) == linear-mix.html linear-mix-ref.html == linear-diagonal-1a.html linear-diagonal-1-ref.html == linear-diagonal-1b.html linear-diagonal-1-ref.html +== linear-diagonal-1c.html linear-diagonal-1-ref.html == linear-diagonal-2a.html linear-diagonal-2-ref.html == linear-diagonal-2b.html linear-diagonal-2-ref.html +== linear-diagonal-2c.html linear-diagonal-2-ref.html == linear-diagonal-3a.html linear-diagonal-3-ref.html == linear-diagonal-3b.html linear-diagonal-3-ref.html +== linear-diagonal-3c.html linear-diagonal-3-ref.html == linear-diagonal-4a.html linear-diagonal-4-ref.html == linear-diagonal-4b.html linear-diagonal-4-ref.html +== linear-diagonal-4c.html linear-diagonal-4-ref.html == linear-diagonal-5a.html linear-diagonal-5-ref.html == linear-diagonal-6a.html linear-diagonal-6-ref.html == linear-diagonal-7a.html linear-diagonal-7-ref.html == linear-diagonal-8a.html linear-diagonal-8-ref.html +== linear-diagonal-9a.html linear-diagonal-9-ref.html == linear-position-1a.html linear-position-1-ref.html == linear-repeat-1a.html linear-repeat-1-ref.html fails-if(d2d) == linear-repeat-1b.html linear-repeat-1-ref.html # bug 582236 @@ -33,6 +40,7 @@ fails-if(Android) == linear-vertical-1a.html linear-vertical-1-ref.html fails-if(Android) == linear-vertical-1b.html linear-vertical-1-ref.html fails-if(Android) == linear-vertical-1c.html linear-vertical-1-ref.html fails-if(Android) == linear-vertical-1d.html linear-vertical-1-ref.html +fails-if(Android) == linear-vertical-1e.html linear-vertical-1-ref.html == linear-viewport.html linear-viewport-ref.html == linear-zero-length-1a.html linear-zero-length-1-ref.html == linear-zero-length-1b.html linear-zero-length-1-ref.html @@ -65,6 +73,8 @@ fails-if(d2d) == repeating-linear-1b.html repeating-linear-1-ref.html fails-if(cocoaWidget) == twostops-1c.html twostops-1-ref.html # bug 524173 == twostops-1d.html twostops-1-ref.html == twostops-1e.html twostops-1-ref.html +== twostops-1f.html twostops-1-ref.html +== twostops-1g.html twostops-1-ref.html # from http://www.xanthir.com/:4bhipd by way of http://a-ja.net/newgrad.html fails-if(Android) == aja-linear-1a.html aja-linear-1-ref.html diff --git a/layout/reftests/css-gradients/repeating-linear-onestopposition-1.html b/layout/reftests/css-gradients/repeating-linear-onestopposition-1.html index a61dc828c935..9e895a1a6858 100644 --- a/layout/reftests/css-gradients/repeating-linear-onestopposition-1.html +++ b/layout/reftests/css-gradients/repeating-linear-onestopposition-1.html @@ -5,7 +5,7 @@ div { width: 200px; height: 200px; - background-image: -moz-repeating-linear-gradient(left, blue 25%, orange 25%); + background-image: -moz-repeating-linear-gradient(to right, blue 25%, orange 25%); } diff --git a/layout/reftests/css-gradients/twostops-1f.html b/layout/reftests/css-gradients/twostops-1f.html new file mode 100644 index 000000000000..2cc26313867a --- /dev/null +++ b/layout/reftests/css-gradients/twostops-1f.html @@ -0,0 +1 @@ +

diff --git a/layout/reftests/css-gradients/twostops-1g.html b/layout/reftests/css-gradients/twostops-1g.html new file mode 100644 index 000000000000..19696bc201dd --- /dev/null +++ b/layout/reftests/css-gradients/twostops-1g.html @@ -0,0 +1 @@ +

diff --git a/layout/reftests/editor/694880-1.html b/layout/reftests/editor/694880-1.html new file mode 100644 index 000000000000..373c3070a90e --- /dev/null +++ b/layout/reftests/editor/694880-1.html @@ -0,0 +1,10 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/694880-2.html b/layout/reftests/editor/694880-2.html new file mode 100644 index 000000000000..9f2617883af8 --- /dev/null +++ b/layout/reftests/editor/694880-2.html @@ -0,0 +1,11 @@ + + + + +
test
+
+ + diff --git a/layout/reftests/editor/694880-3.html b/layout/reftests/editor/694880-3.html new file mode 100644 index 000000000000..c6d7837f7433 --- /dev/null +++ b/layout/reftests/editor/694880-3.html @@ -0,0 +1,10 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/694880-ref.html b/layout/reftests/editor/694880-ref.html new file mode 100644 index 000000000000..d5c40547ee4a --- /dev/null +++ b/layout/reftests/editor/694880-ref.html @@ -0,0 +1,9 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/reftest.list b/layout/reftests/editor/reftest.list index 39e08999262e..f50a9a3a4371 100644 --- a/layout/reftests/editor/reftest.list +++ b/layout/reftests/editor/reftest.list @@ -84,3 +84,6 @@ skip-if(Android) == 338427-2.html 338427-2-ref.html skip-if(Android) needs-focus == 338427-3.html 338427-3-ref.html skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.html == dynamic-overflow-change.html dynamic-overflow-change-ref.html +== 694880-1.html 694880-ref.html +== 694880-2.html 694880-ref.html +== 694880-3.html 694880-ref.html diff --git a/layout/reftests/reftest-sanity/reftest.list b/layout/reftests/reftest-sanity/reftest.list index c438657985e3..7830cfeee6a9 100644 --- a/layout/reftests/reftest-sanity/reftest.list +++ b/layout/reftests/reftest-sanity/reftest.list @@ -91,6 +91,7 @@ fails-if(!browserIsRemote) == test-displayport.html test-displayport-ref.html # skip-if(!browserIsRemote) != test-displayport-2.html test-displayport-ref.html # bug 593168 skip-if(!browserIsRemote) == 647192-1.html 647192-1-ref.html skip-if(!browserIsRemote) == 656041-1.html 656041-1-ref.html +skip-if(!browserIsRemote) == test-displayport-bg.html test-displayport-ref.html # bug 694706 # IPC Position-fixed frames/layers test # Fixed layers are temporarily disabled (bug 656167). diff --git a/layout/reftests/reftest-sanity/test-displayport-bg.html b/layout/reftests/reftest-sanity/test-displayport-bg.html new file mode 100644 index 000000000000..9e047d88d8cc --- /dev/null +++ b/layout/reftests/reftest-sanity/test-displayport-bg.html @@ -0,0 +1,7 @@ + + + + + diff --git a/layout/reftests/table-anonymous-boxes/695538-1-ref.html b/layout/reftests/table-anonymous-boxes/695538-1-ref.html new file mode 100644 index 000000000000..00155267c684 --- /dev/null +++ b/layout/reftests/table-anonymous-boxes/695538-1-ref.html @@ -0,0 +1,21 @@ + + + A +B + diff --git a/layout/reftests/table-anonymous-boxes/695538-1.html b/layout/reftests/table-anonymous-boxes/695538-1.html new file mode 100644 index 000000000000..16568885c8f5 --- /dev/null +++ b/layout/reftests/table-anonymous-boxes/695538-1.html @@ -0,0 +1,18 @@ + + + A +B + diff --git a/layout/reftests/table-anonymous-boxes/reftest.list b/layout/reftests/table-anonymous-boxes/reftest.list index 8c01d1dd1a3b..fdbb7e60c2c0 100644 --- a/layout/reftests/table-anonymous-boxes/reftest.list +++ b/layout/reftests/table-anonymous-boxes/reftest.list @@ -35,6 +35,7 @@ random-if(d2d) == 394402-1a.html 394402-1-ref.html # bug 586833 == 443616-1b.html 443616-1-ref.html == 448111-1.html 448111-1-ref.html == 490174-1.html 490174-1-ref.html +== 695538-1.html 695538-1-ref.html == infer-first-row.html 3x3-ref.html == infer-first-row-and-table.html 3x3-ref.html == infer-second-row.html 3x3-ref.html diff --git a/layout/style/crashtests/696188-1.html b/layout/style/crashtests/696188-1.html new file mode 100644 index 000000000000..e52a26747476 --- /dev/null +++ b/layout/style/crashtests/696188-1.html @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list index f68b0910047b..be9766ac4c99 100644 --- a/layout/style/crashtests/crashtests.list +++ b/layout/style/crashtests/crashtests.list @@ -73,3 +73,4 @@ load 665209-1.html asserts(2) load 671799-1.html asserts(2) load 671799-2.html load 690990-1.html +load 696188-1.html diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index f3cca27f623e..bb9252bf8a6c 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -264,7 +264,7 @@ public: bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString, nsIURI* aURL, // for error reporting PRUint32 aLineNumber, // for error reporting - nsTArray& aSelectorList); + InfallibleTArray& aSelectorList); protected: class nsAutoParseCompoundProperty; @@ -331,7 +331,7 @@ protected: bool SkipAtRule(bool aInsideBlock); bool SkipDeclaration(bool aCheckForBraces); - bool PushGroup(css::GroupRule* aRule); + void PushGroup(css::GroupRule* aRule); void PopGroup(); bool ParseRuleSet(RuleAppendFunc aAppendFunc, void* aProcessData, @@ -366,7 +366,7 @@ protected: bool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData); bool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData); already_AddRefed ParseKeyframeRule(); - bool ParseKeyframeSelectorList(nsTArray& aSelectorList); + bool ParseKeyframeSelectorList(InfallibleTArray& aSelectorList); enum nsSelectorParsingStatus { // we have parsed a selector and we saw a token that cannot be @@ -471,7 +471,8 @@ protected: bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id bool ParseBackgroundPosition(); - bool ParseBoxPositionValues(nsCSSValuePair& aOut, bool aAcceptsInherit); + bool ParseBoxPositionValues(nsCSSValuePair& aOut, bool aAcceptsInherit, + bool aAllowExplicitCenter = true); bool ParseBackgroundSize(); bool ParseBackgroundSizeValues(nsCSSValuePair& aOut); bool ParseBorderColor(); @@ -505,7 +506,7 @@ protected: bool ParseOneFamily(nsAString& aValue); bool ParseFamily(nsCSSValue& aValue); bool ParseFontSrc(nsCSSValue& aValue); - bool ParseFontSrcFormat(nsTArray& values); + bool ParseFontSrcFormat(InfallibleTArray& values); bool ParseFontRanges(nsCSSValue& aValue); bool ParseListStyle(); bool ParseMargin(); @@ -586,7 +587,6 @@ protected: bool aIsRepeating); void SetParsingCompoundProperty(bool aBool) { - NS_ASSERTION(aBool == true || aBool == false, "bad bool value"); mParsingCompoundProperty = aBool; } bool IsParsingCompoundProperty(void) const { @@ -601,7 +601,7 @@ protected: bool ParseFunctionInternals(const PRInt32 aVariantMask[], PRUint16 aMinElems, PRUint16 aMaxElems, - nsTArray& aOutput); + InfallibleTArray& aOutput); /* Functions for -moz-transform-origin/-moz-perspective-origin Parsing */ bool ParseMozTransformOrigin(bool aPerspective); @@ -677,7 +677,7 @@ protected: #endif // Stack of rule groups; used for @media and such. - nsTArray > mGroupStack; + InfallibleTArray > mGroupStack; // During the parsing of a property (which may be a shorthand), the data // are stored in |mTempData|. (It is needed to ensure that parser @@ -791,7 +791,6 @@ CSSParserImpl::SetStyleSheet(nsCSSStyleSheet* aSheet) nsresult CSSParserImpl::SetQuirkMode(bool aQuirkMode) { - NS_ASSERTION(aQuirkMode == true || aQuirkMode == false, "bad bool value"); mNavQuirkMode = aQuirkMode; return NS_OK; } @@ -799,8 +798,6 @@ CSSParserImpl::SetQuirkMode(bool aQuirkMode) nsresult CSSParserImpl::SetSVGMode(bool aSVGMode) { - NS_ASSERTION(aSVGMode == true || aSVGMode == false, - "bad bool value"); mScanner.SetSVGMode(aSVGMode); return NS_OK; } @@ -831,8 +828,7 @@ CSSParserImpl::InitScanner(const nsSubstring& aString, nsIURI* aSheetURI, // the stream until we're done parsing. NS_ASSERTION(! mScannerInited, "already have scanner"); - mScanner.Init(nsnull, aString.BeginReading(), aString.Length(), aSheetURI, - aLineNumber, mSheet, mChildLoader); + mScanner.Init(aString, aSheetURI, aLineNumber, mSheet, mChildLoader); #ifdef DEBUG mScannerInited = true; @@ -1017,17 +1013,11 @@ CSSParserImpl::ParseDeclarations(const nsAString& aBuffer, // We could check if it was already empty, but... *aChanged = true; - nsresult rv = NS_OK; for (;;) { // If we cleared the old decl, then we want to be calling // ValueAppended as we parse. if (!ParseDeclaration(aDeclaration, false, true, aChanged)) { - rv = mScanner.GetLowLevelError(); - if (NS_FAILED(rv)) - break; - if (!SkipDeclaration(false)) { - rv = mScanner.GetLowLevelError(); break; } } @@ -1035,7 +1025,7 @@ CSSParserImpl::ParseDeclarations(const nsAString& aBuffer, aDeclaration->CompressFrom(&mData); ReleaseScanner(); - return rv; + return NS_OK; } nsresult @@ -1144,9 +1134,8 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID, mTempData.AssertInitialState(); - nsresult result = mScanner.GetLowLevelError(); ReleaseScanner(); - return result; + return NS_OK; } nsresult @@ -1164,8 +1153,6 @@ CSSParserImpl::ParseMediaList(const nsSubstring& aBuffer, InitScanner(aBuffer, aURI, aLineNumber, aURI, nsnull); AssertInitialState(); - NS_ASSERTION(aHTMLMode == true || aHTMLMode == false, - "invalid bool"); mHTMLMediaMode = aHTMLMode; // XXXldb We need to make the scanner not skip CSS comments! (Or @@ -1180,14 +1167,13 @@ CSSParserImpl::ParseMediaList(const nsSubstring& aBuffer, // to a media query. (The main substative difference is the relative // precedence of commas and paretheses.) - GatherMedia(aMediaList, false); // can only fail on low-level error (OOM) + GatherMedia(aMediaList, false); - nsresult rv = mScanner.GetLowLevelError(); CLEAR_ERROR(); ReleaseScanner(); mHTMLMediaMode = false; - return rv; + return NS_OK; } nsresult @@ -1202,40 +1188,46 @@ CSSParserImpl::ParseColorString(const nsSubstring& aBuffer, nsCSSValue value; // Parse a color, and check that there's nothing else after it. bool colorParsed = ParseColor(value) && !GetToken(true); - nsresult rv = mScanner.GetLowLevelError(); OUTPUT_ERROR(); ReleaseScanner(); if (!colorParsed) { - return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE; + return NS_ERROR_FAILURE; } - if (value.GetUnit() == eCSSUnit_Ident) { + switch (value.GetUnit()) { + case eCSSUnit_Color: + *aColor = value.GetColorValue(); + return NS_OK; + + case eCSSUnit_Ident: { + nsDependentString id(value.GetStringBufferValue()); + if (!NS_ColorNameToRGB(id, aColor)) { + return NS_ERROR_FAILURE; + } + return NS_OK; + } + + case eCSSUnit_EnumColor: { + PRInt32 val = value.GetIntValue(); + if (val < 0) { + // XXX - negative numbers are NS_COLOR_CURRENTCOLOR, + // NS_COLOR_MOZ_HYPERLINKTEXT, etc. which we don't handle. + // Should remove this limitation at some point. + return NS_ERROR_FAILURE; + } nscolor rgba; - if (NS_ColorNameToRGB(nsDependentString(value.GetStringBufferValue()), &rgba)) { - (*aColor) = rgba; - rv = NS_OK; - } - } else if (value.GetUnit() == eCSSUnit_Color) { - (*aColor) = value.GetColorValue(); - rv = NS_OK; - } else if (value.GetUnit() == eCSSUnit_EnumColor) { - PRInt32 intValue = value.GetIntValue(); - if (intValue >= 0) { - nscolor rgba; - rv = LookAndFeel::GetColor((LookAndFeel::ColorID) value.GetIntValue(), - &rgba); - if (NS_SUCCEEDED(rv)) - (*aColor) = rgba; - } else { - // XXX - this is NS_COLOR_CURRENTCOLOR, NS_COLOR_MOZ_HYPERLINKTEXT, etc. - // which we don't handle as per the ParseColorString definition. Should - // remove this limitation at some point. - rv = NS_ERROR_FAILURE; + nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), &rgba); + if (NS_FAILED(rv)) { + return rv; } + *aColor = rgba; + return NS_OK; } - return rv; + default: + return NS_ERROR_FAILURE; + } } nsresult @@ -1304,7 +1296,7 @@ bool CSSParserImpl::ParseKeyframeSelectorString(const nsSubstring& aSelectorString, nsIURI* aURI, // for error reporting PRUint32 aLineNumber, // for error reporting - nsTArray& aSelectorList) + InfallibleTArray& aSelectorList) { NS_ABORT_IF_FALSE(aSelectorList.IsEmpty(), "given list should start empty"); @@ -1654,10 +1646,6 @@ CSSParserImpl::ParseMediaQuery(bool aInAtRule, nsMediaQuery* query = new nsMediaQuery; *aQuery = query; - if (!query) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } if (ExpectSymbol('(', true)) { // we got an expression without a media type @@ -1685,6 +1673,9 @@ CSSParserImpl::ParseMediaQuery(bool aInAtRule, // case insensitive from CSS - must be lower cased nsContentUtils::ASCIIToLower(mToken.mIdent); mediaType = do_GetAtom(mToken.mIdent); + if (!mediaType) { + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); + } if (gotNotOrOnly || (mediaType != nsGkAtoms::_not && mediaType != nsGkAtoms::only)) break; @@ -1746,9 +1737,6 @@ CSSParserImpl::GatherMedia(nsMediaList* aMedia, &hitStop)) { NS_ASSERTION(!hitStop, "should return true when hit stop"); OUTPUT_ERROR(); - if (NS_FAILED(mScanner.GetLowLevelError())) { - return false; - } if (query) { query->SetHadUnknownExpression(); } @@ -1767,11 +1755,7 @@ CSSParserImpl::GatherMedia(nsMediaList* aMedia, } } if (query) { - nsresult rv = aMedia->AppendQuery(query); - if (NS_FAILED(rv)) { - mScanner.SetLowLevelError(rv); - return false; - } + aMedia->AppendQuery(query); } if (hitStop) { break; @@ -1799,11 +1783,6 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery) } nsMediaExpression *expr = aQuery->NewExpression(); - if (!expr) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - SkipUntil(')'); - return false; - } // case insensitive from CSS - must be lower cased nsContentUtils::ASCIIToLower(mToken.mIdent); @@ -1820,6 +1799,9 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery) } nsCOMPtr mediaFeatureAtom = do_GetAtom(featureString); + if (!mediaFeatureAtom) { + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); + } const nsMediaFeature *feature = nsMediaFeatures::features; for (; feature->mName; ++feature) { if (*(feature->mName) == mediaFeatureAtom) { @@ -1928,10 +1910,6 @@ bool CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc, void* aData) { nsRefPtr media = new nsMediaList(); - if (!media) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } nsAutoString url; if (!ParseURLOrString(url)) { @@ -2000,10 +1978,7 @@ CSSParserImpl::ParseGroupRule(css::GroupRule* aRule, } // push rule on stack, loop over children - if (!PushGroup(aRule)) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } + PushGroup(aRule); nsCSSSection holdSection = mSection; mSection = eCSSSection_General; @@ -2164,6 +2139,9 @@ CSSParserImpl::ProcessNameSpace(const nsString& aPrefix, if (!aPrefix.IsEmpty()) { prefix = do_GetAtom(aPrefix); + if (!prefix) { + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); + } } nsRefPtr rule = new css::NameSpaceRule(prefix, aURLSpec); @@ -2187,10 +2165,6 @@ CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aData) } nsRefPtr rule(new nsCSSFontFaceRule()); - if (!rule) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } for (;;) { if (!GetToken(true)) { @@ -2327,7 +2301,7 @@ CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData) already_AddRefed CSSParserImpl::ParseKeyframeRule() { - nsTArray selectorList; + InfallibleTArray selectorList; if (!ParseKeyframeSelectorList(selectorList)) { REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored); return nsnull; @@ -2347,7 +2321,7 @@ CSSParserImpl::ParseKeyframeRule() } bool -CSSParserImpl::ParseKeyframeSelectorList(nsTArray& aSelectorList) +CSSParserImpl::ParseKeyframeSelectorList(InfallibleTArray& aSelectorList) { for (;;) { if (!GetToken(true)) { @@ -2510,16 +2484,13 @@ CSSParserImpl::SkipRuleSet(bool aInsideBraces) eCSSToken_Bad_URL == tk->mType) { SkipUntil(')'); } - } + } } -bool +void CSSParserImpl::PushGroup(css::GroupRule* aRule) { - if (mGroupStack.AppendElement(aRule)) - return true; - - return false; + mGroupStack.AppendElement(aRule); } void @@ -3124,8 +3095,7 @@ CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask, nsContentUtils::ASCIIToLower(buffer); nsCOMPtr pseudo = do_GetAtom(buffer); if (!pseudo) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return eSelectorParsingStatus_Error; + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); } // stash away some info about this pseudo so we only have to get it once. @@ -3335,10 +3305,6 @@ CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask, // thing we need to change to support that is this parsing code and the // serialization code for nsCSSSelector. nsCSSSelector *newSel = new nsCSSSelector(); - if (!newSel) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return eSelectorParsingStatus_Error; - } nsCSSSelector* negations = &aSelector; while (negations->mNegations) { negations = negations->mNegations; @@ -4828,19 +4794,10 @@ CSSParserImpl::SetValueToURL(nsCSSValue& aValue, const nsString& aURL) } nsRefPtr buffer(nsCSSValue::BufferFromString(aURL)); - if (NS_UNLIKELY(!buffer)) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } // Note: urlVal retains its own reference to |buffer|. nsCSSValue::URL *urlVal = new nsCSSValue::URL(buffer, mBaseURI, mSheetURI, mSheetPrincipal); - - if (NS_UNLIKELY(!urlVal)) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } aValue.SetURLValue(urlVal); return true; } @@ -4858,10 +4815,6 @@ CSSParserImpl::ParseImageRect(nsCSSValue& aImage) static const PRUint32 kNumArgs = 5; nsCSSValue::Array* func = newFunction.InitFunction(eCSSKeyword__moz_image_rect, kNumArgs); - if (!func) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - break; - } // func->Item(0) is reserved for the function name. nsCSSValue& url = func->Item(1); @@ -4929,11 +4882,6 @@ bool CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) { nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement(); - if (!stop) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } - if (!ParseVariant(stop->mColor, VARIANT_COLOR, nsnull)) { return false; } @@ -4951,7 +4899,9 @@ CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) // : radial-gradient( ? ? // ')' // -// : [ || ] , +// : [ to [left | right] || [top | bottom] ] , +// | +// : [ || ] , // // : [ || ] , // : circle | ellipse @@ -4980,8 +4930,19 @@ CSSParserImpl::ParseGradient(nsCSSValue& aValue, bool aIsRadial, if (!GetToken(true)) { return false; } + + bool toCorner = false; + if (mToken.mType == eCSSToken_Ident && + mToken.mIdent.LowerCaseEqualsLiteral("to")) { + toCorner = true; + if (!GetToken(true)) { + return false; + } + } + nsCSSTokenType ty = mToken.mType; nsString id = mToken.mIdent; + cssGradient->mIsToCorner = toCorner; UngetToken(); bool haveGradientLine = false; @@ -5022,26 +4983,59 @@ CSSParserImpl::ParseGradient(nsCSSValue& aValue, bool aIsRadial, } if (haveGradientLine) { - bool haveAngle = - ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull); - - // if we got an angle, we might now have a comma, ending the gradient-line - if (!haveAngle || !ExpectSymbol(',', true)) { - if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) { + if (toCorner) { + // "to" syntax only allows box position keywords + if (ty != eCSSToken_Ident) { SkipUntil(')'); return false; } - if (!ExpectSymbol(',', true) && - // if we didn't already get an angle, we might have one now, - // otherwise it's an error - (haveAngle || - !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull) || - // now we better have a comma - !ExpectSymbol(',', true))) { + // "to" syntax doesn't allow explicit "center" + if (!ParseBoxPositionValues(cssGradient->mBgPos, false, false)) { SkipUntil(')'); return false; } + + const nsCSSValue& xValue = cssGradient->mBgPos.mXValue; + const nsCSSValue& yValue = cssGradient->mBgPos.mYValue; + if (xValue.GetUnit() != eCSSUnit_Enumerated || + !(xValue.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT | + NS_STYLE_BG_POSITION_CENTER | + NS_STYLE_BG_POSITION_RIGHT)) || + yValue.GetUnit() != eCSSUnit_Enumerated || + !(yValue.GetIntValue() & (NS_STYLE_BG_POSITION_TOP | + NS_STYLE_BG_POSITION_CENTER | + NS_STYLE_BG_POSITION_BOTTOM))) { + SkipUntil(')'); + return false; + } + + if (!ExpectSymbol(',', true)) { + SkipUntil(')'); + return false; + } + } else { + bool haveAngle = + ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull); + + // if we got an angle, we might now have a comma, ending the gradient-line + if (!haveAngle || !ExpectSymbol(',', true)) { + if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) { + SkipUntil(')'); + return false; + } + + if (!ExpectSymbol(',', true) && + // if we didn't already get an angle, we might have one now, + // otherwise it's an error + (haveAngle || + !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull) || + // now we better have a comma + !ExpectSymbol(',', true))) { + SkipUntil(')'); + return false; + } + } } } @@ -6069,10 +6063,12 @@ CSSParserImpl::ParseBackgroundPosition() * * @param aOut The nsCSSValuePair in which to place the result. * @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values + * @param aAllowExplicitCenter If true, 'center' is a legal value * @return Whether or not the operation succeeded. */ bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut, - bool aAcceptsInherit) + bool aAcceptsInherit, + bool aAllowExplicitCenter) { // First try a percentage or a length value nsCSSValue &xValue = aOut.mXValue, @@ -6143,7 +6139,8 @@ bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut, // Check for bad input. Bad input consists of no matching keywords, // or pairs of x keywords or pairs of y keywords. if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || - (mask == (BG_LEFT | BG_RIGHT))) { + (mask == (BG_LEFT | BG_RIGHT)) || + (!aAllowExplicitCenter && (mask & BG_CENTER))) { return false; } @@ -7212,18 +7209,15 @@ bool CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask[], PRUint16 aMinElems, PRUint16 aMaxElems, - nsTArray &aOutput) + InfallibleTArray &aOutput) { for (PRUint16 index = 0; index < aMaxElems; ++index) { nsCSSValue newValue; if (!ParseVariant(newValue, aVariantMask[index], nsnull)) return false; - if (!aOutput.AppendElement(newValue)) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } - + aOutput.AppendElement(newValue); + // See whether to continue or whether to look for end of function. if (!ExpectSymbol(',', true)) { // We need to read the closing parenthesis, and also must take care @@ -7261,7 +7255,7 @@ CSSParserImpl::ParseFunction(const nsString &aFunction, PRUint16 aMinElems, PRUint16 aMaxElems, nsCSSValue &aValue) { - typedef nsTArray::size_type arrlen_t; + typedef InfallibleTArray::size_type arrlen_t; /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1 * elements stored in the the nsCSSValue::Array. @@ -7274,15 +7268,15 @@ CSSParserImpl::ParseFunction(const nsString &aFunction, */ nsString functionName(aFunction); - /* Read in a list of values as an nsTArray, failing if we can't or if + /* Read in a list of values as an array, failing if we can't or if * it's out of bounds. */ - nsTArray foundValues; + InfallibleTArray foundValues; if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems, foundValues)) return false; - - /* Now, convert this nsTArray into an nsCSSValue::Array object. + + /* Now, convert this array into an nsCSSValue::Array object. * We'll need N + 1 spots, one for the function name and the rest for the * arguments. In case the user has given us more than 2^16 - 2 arguments, * we'll truncate them at 2^16 - 2 arguments. @@ -7296,10 +7290,10 @@ CSSParserImpl::ParseFunction(const nsString &aFunction, convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident); for (PRUint16 index = 0; index + 1 < numElements; ++index) convertedArray->Item(index + 1) = foundValues[static_cast(index)]; - + /* Fill in the outparam value with the array. */ aValue.SetArrayValue(convertedArray, eCSSUnit_Function); - + /* Return it! */ return true; } @@ -7641,8 +7635,8 @@ CSSParserImpl::ParseFamily(nsCSSValue& aValue) bool CSSParserImpl::ParseFontSrc(nsCSSValue& aValue) { - // could we maybe turn nsCSSValue::Array into nsTArray? - nsTArray values; + // could we maybe turn nsCSSValue::Array into InfallibleTArray? + InfallibleTArray values; nsCSSValue cur; for (;;) { if (!GetToken(true)) @@ -7695,11 +7689,7 @@ CSSParserImpl::ParseFontSrc(nsCSSValue& aValue) return false; nsRefPtr srcVals - = nsCSSValue::Array::Create(mozilla::fallible_t(), values.Length()); - if (!srcVals) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } + = nsCSSValue::Array::Create(values.Length()); PRUint32 i; for (i = 0; i < values.Length(); i++) @@ -7709,7 +7699,7 @@ CSSParserImpl::ParseFontSrc(nsCSSValue& aValue) } bool -CSSParserImpl::ParseFontSrcFormat(nsTArray & values) +CSSParserImpl::ParseFontSrcFormat(InfallibleTArray & values) { if (!GetToken(true)) return true; // EOF harmless here @@ -7745,7 +7735,7 @@ CSSParserImpl::ParseFontSrcFormat(nsTArray & values) bool CSSParserImpl::ParseFontRanges(nsCSSValue& aValue) { - nsTArray ranges; + InfallibleTArray ranges; for (;;) { if (!GetToken(true)) break; @@ -7782,11 +7772,7 @@ CSSParserImpl::ParseFontRanges(nsCSSValue& aValue) return false; nsRefPtr srcVals - = nsCSSValue::Array::Create(mozilla::fallible_t(), ranges.Length()); - if (!srcVals) { - mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); - return false; - } + = nsCSSValue::Array::Create(ranges.Length()); for (PRUint32 i = 0; i < ranges.Length(); i++) srcVals->Item(i).SetIntValue(ranges[i], eCSSUnit_Integer); @@ -8711,6 +8697,9 @@ CSSParserImpl::GetNamespaceIdForPrefix(const nsString& aPrefix) if (mNameSpaceMap) { // user-specified identifiers are case-sensitive (bug 416106) nsCOMPtr prefix = do_GetAtom(aPrefix); + if (!prefix) { + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); + } nameSpaceID = mNameSpaceMap->FindNameSpaceID(prefix); } // else no declared namespaces @@ -8991,7 +8980,7 @@ bool nsCSSParser::ParseKeyframeSelectorString(const nsSubstring& aSelectorString, nsIURI* aURI, PRUint32 aLineNumber, - nsTArray& aSelectorList) + InfallibleTArray& aSelectorList) { return static_cast(mImpl)-> ParseKeyframeSelectorString(aSelectorString, aURI, aLineNumber, diff --git a/layout/style/nsCSSParser.h b/layout/style/nsCSSParser.h index 248fd10aac0d..8f8446579ea3 100644 --- a/layout/style/nsCSSParser.h +++ b/layout/style/nsCSSParser.h @@ -204,7 +204,7 @@ public: bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString, nsIURI* aURL, PRUint32 aLineNumber, - nsTArray& aSelectorList); + InfallibleTArray& aSelectorList); protected: // This is a CSSParserImpl*, but if we expose that type name in this diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp index 127950bc895b..e0331801887e 100644 --- a/layout/style/nsCSSRules.cpp +++ b/layout/style/nsCSSRules.cpp @@ -1851,7 +1851,7 @@ nsCSSKeyframeRule::SetKeyText(const nsAString& aKeyText) { nsCSSParser parser; - nsTArray newSelectors; + InfallibleTArray newSelectors; // FIXME: pass filename and line number if (parser.ParseKeyframeSelectorString(aKeyText, nsnull, 0, newSelectors)) { newSelectors.SwapElements(mKeys); @@ -2033,7 +2033,7 @@ nsCSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey) { nsCSSParser parser; - nsTArray keys; + InfallibleTArray keys; // FIXME: pass filename and line number if (parser.ParseKeyframeSelectorString(aKey, nsnull, 0, keys)) { // The spec isn't clear, but we'll match on the key list, which diff --git a/layout/style/nsCSSScanner.cpp b/layout/style/nsCSSScanner.cpp index a21670c38a35..89d0edc18106 100644 --- a/layout/style/nsCSSScanner.cpp +++ b/layout/style/nsCSSScanner.cpp @@ -37,18 +37,15 @@ * * ***** END LICENSE BLOCK ***** */ -#include - -#include "mozilla/Util.h" /* tokenization of CSS style sheets */ +#include // must be first due to symbol conflicts + #include "nsCSSScanner.h" -#include "nsIFactory.h" -#include "nsIInputStream.h" -#include "nsIUnicharInputStream.h" #include "nsString.h" #include "nsCRT.h" +#include "mozilla/Util.h" // for #ifdef CSS_REPORT_PARSE_ERRORS #include "nsCOMPtr.h" @@ -74,12 +71,6 @@ static nsIFactory *gScriptErrorFactory; static nsIStringBundle *gStringBundle; #endif -// Don't bother collecting whitespace characters in token's mIdent buffer -#undef COLLECT_WHITESPACE - -// Table of character classes -static const PRUnichar CSS_ESCAPE = PRUnichar('\\'); - static const PRUint8 IS_HEX_DIGIT = 0x01; static const PRUint8 START_IDENT = 0x02; static const PRUint8 IS_IDENT = 0x04; @@ -234,7 +225,7 @@ nsCSSToken::AppendToString(nsString& aBuffer) case eCSSToken_Percentage: NS_ASSERTION(!mIntegerValid, "How did a percentage token get this set?"); aBuffer.AppendFloat(mNumber * 100.0f); - aBuffer.Append(PRUnichar('%')); // STRING USE WARNING: technically, this should be |AppendWithConversion| + aBuffer.Append(PRUnichar('%')); break; case eCSSToken_Dimension: if (mIntegerValid) { @@ -282,9 +273,7 @@ nsCSSToken::AppendToString(nsString& aBuffer) } nsCSSScanner::nsCSSScanner() - : mInputStream(nsnull) - , mReadPointer(nsnull) - , mLowLevelError(NS_OK) + : mReadPointer(nsnull) , mSVGMode(false) #ifdef CSS_REPORT_PARSE_ERRORS , mError(mErrorBuf, ArrayLength(mErrorBuf), 0) @@ -311,20 +300,6 @@ nsCSSScanner::~nsCSSScanner() } } -nsresult -nsCSSScanner::GetLowLevelError() -{ - return mLowLevelError; -} - -void -nsCSSScanner::SetLowLevelError(nsresult aErrorCode) -{ - NS_ASSERTION(aErrorCode != NS_OK, "SetLowLevelError() used to clear error"); - NS_ASSERTION(mLowLevelError == NS_OK, "there is already a low-level error"); - mLowLevelError = aErrorCode; -} - #ifdef CSS_REPORT_PARSE_ERRORS #define CSS_ERRORS_PREF "layout.css.report_errors" @@ -369,28 +344,14 @@ nsCSSScanner::ReleaseGlobals() } void -nsCSSScanner::Init(nsIUnicharInputStream* aInput, - const PRUnichar * aBuffer, PRUint32 aCount, +nsCSSScanner::Init(const nsAString& aBuffer, nsIURI* aURI, PRUint32 aLineNumber, nsCSSStyleSheet* aSheet, mozilla::css::Loader* aLoader) { - NS_PRECONDITION(!mInputStream, "Should not have an existing input stream!"); NS_PRECONDITION(!mReadPointer, "Should not have an existing input buffer!"); - // Read from stream via my own buffer - if (aInput) { - NS_PRECONDITION(!aBuffer, "Shouldn't have both input and buffer!"); - NS_PRECONDITION(aCount == 0, "Shouldn't have count with a stream"); - mInputStream = aInput; - mReadPointer = mBuffer; - mCount = 0; - } else { - NS_PRECONDITION(aBuffer, "Either aInput or aBuffer must be set"); - // Read directly from the provided buffer - mInputStream = nsnull; - mReadPointer = aBuffer; - mCount = aCount; - } + mReadPointer = aBuffer.BeginReading(); + mCount = aBuffer.Length(); #ifdef CSS_REPORT_PARSE_ERRORS // If aURI is the same as mURI, no need to reget mFileName -- it @@ -409,7 +370,6 @@ nsCSSScanner::Init(nsIUnicharInputStream* aInput, // Reset variables that we use to keep track of our progress through the input mOffset = 0; mPushbackCount = 0; - mLowLevelError = NS_OK; #ifdef CSS_REPORT_PARSE_ERRORS mColNumber = 0; @@ -618,7 +578,6 @@ nsCSSScanner::ReportUnexpectedTokenParams(nsCSSToken& tok, void nsCSSScanner::Close() { - mInputStream = nsnull; mReadPointer = nsnull; // Clean things up so we don't hold on to memory if our parser gets recycled. @@ -638,31 +597,6 @@ nsCSSScanner::Close() } } -#ifdef CSS_REPORT_PARSE_ERRORS -#define TAB_STOP_WIDTH 8 -#endif - -bool -nsCSSScanner::EnsureData() -{ - if (mOffset < mCount) - return true; - - if (!mInputStream) - return false; - - mOffset = 0; - nsresult rv = mInputStream->Read(mBuffer, CSS_BUFFER_SIZE, &mCount); - - if (NS_FAILED(rv)) { - mCount = 0; - SetLowLevelError(rv); - return false; - } - - return mCount > 0; -} - // Returns -1 on error or eof PRInt32 nsCSSScanner::Read() @@ -671,14 +605,14 @@ nsCSSScanner::Read() if (0 < mPushbackCount) { rv = PRInt32(mPushback[--mPushbackCount]); } else { - if (mOffset == mCount && !EnsureData()) { + if (mOffset == mCount) { return -1; } rv = PRInt32(mReadPointer[mOffset++]); // There are four types of newlines in CSS: "\r", "\n", "\r\n", and "\f". // To simplify dealing with newlines, they are all normalized to "\n" here if (rv == '\r') { - if (EnsureData() && mReadPointer[mOffset] == '\n') { + if (mOffset < mCount && mReadPointer[mOffset] == '\n') { mOffset++; } rv = '\n'; @@ -691,18 +625,11 @@ nsCSSScanner::Read() ++mLineNumber; #ifdef CSS_REPORT_PARSE_ERRORS mColNumber = 0; -#endif - } -#ifdef CSS_REPORT_PARSE_ERRORS - else if (rv == '\t') { - mColNumber = ((mColNumber - 1 + TAB_STOP_WIDTH) / TAB_STOP_WIDTH) - * TAB_STOP_WIDTH; - } else if (rv != '\n') { + } else { mColNumber++; - } #endif + } } -//printf("Read => %x\n", rv); return rv; } @@ -717,7 +644,6 @@ nsCSSScanner::Peek() mPushback[0] = PRUnichar(ch); mPushbackCount++; } -//printf("Peek => %x\n", mLookAhead); return PRInt32(mPushback[mPushbackCount - 1]); } @@ -848,17 +774,8 @@ nsCSSScanner::Next(nsCSSToken& aToken) if (ch == '/' && !IsSVGMode()) { PRInt32 nextChar = Peek(); if (nextChar == '*') { - (void) Read(); -#if 0 - // If we change our storage data structures such that comments are - // stored (for Editor), we should reenable this code, condition it - // on being in editor mode, and apply glazou's patch from bug - // 60290. - aToken.mIdent.SetCapacity(2); - aToken.mIdent.Assign(PRUnichar(ch)); - aToken.mIdent.Append(PRUnichar(nextChar)); - return ParseCComment(aToken); -#endif + Read(); + // FIXME: Editor wants comments to be preserved (bug 60290). if (!SkipCComment()) { return false; } @@ -977,7 +894,7 @@ nsCSSScanner::NextURL(nsCSSToken& aToken) for (;;) { ch = Read(); if (ch < 0) break; - if (ch == CSS_ESCAPE) { + if (ch == '\\') { if (!ParseAndAppendEscape(ident, false)) { ok = false; Pushback(ch); @@ -1105,7 +1022,7 @@ nsCSSScanner::ParseAndAppendEscape(nsString& aOutput, bool aInString) bool nsCSSScanner::GatherIdent(PRInt32 aChar, nsString& aIdent) { - if (aChar == CSS_ESCAPE) { + if (aChar == '\\') { if (!ParseAndAppendEscape(aIdent, false)) { return false; } @@ -1115,7 +1032,7 @@ nsCSSScanner::GatherIdent(PRInt32 aChar, nsString& aIdent) } for (;;) { // If nothing in pushback, first try to get as much as possible in one go - if (!mPushbackCount && EnsureData()) { + if (!mPushbackCount && mOffset < mCount) { // See how much we can consume and append in one go PRUint32 n = mOffset; // Count number of Ident characters that can be processed @@ -1134,7 +1051,7 @@ nsCSSScanner::GatherIdent(PRInt32 aChar, nsString& aIdent) aChar = Read(); if (aChar < 0) break; - if (aChar == CSS_ESCAPE) { + if (aChar == '\\') { if (!ParseAndAppendEscape(aIdent, false)) { Pushback(aChar); break; @@ -1160,7 +1077,7 @@ nsCSSScanner::ParseRef(PRInt32 aChar, nsCSSToken& aToken) if (ch < 0) { return true; } - if (IsIdent(ch) || ch == CSS_ESCAPE) { + if (IsIdent(ch) || ch == '\\') { // First char after the '#' is a valid ident char (or an escape), // so it makes sense to keep going nsCSSTokenType type = @@ -1375,23 +1292,18 @@ nsCSSScanner::ParseString(PRInt32 aStop, nsCSSToken& aToken) aToken.mSymbol = PRUnichar(aStop); // remember how it's quoted for (;;) { // If nothing in pushback, first try to get as much as possible in one go - if (!mPushbackCount && EnsureData()) { + if (!mPushbackCount && mOffset < mCount) { // See how much we can consume and append in one go PRUint32 n = mOffset; // Count number of characters that can be processed for (;n < mCount; ++n) { PRUnichar nextChar = mReadPointer[n]; - if ((nextChar == aStop) || (nextChar == CSS_ESCAPE) || + if ((nextChar == aStop) || (nextChar == '\\') || (nextChar == '\n') || (nextChar == '\r') || (nextChar == '\f')) { break; } #ifdef CSS_REPORT_PARSE_ERRORS - if (nextChar == '\t') { - mColNumber = ((mColNumber - 1 + TAB_STOP_WIDTH) / TAB_STOP_WIDTH) - * TAB_STOP_WIDTH; - } else { - ++mColNumber; - } + ++mColNumber; #endif } // Add to the token what we have so far @@ -1411,7 +1323,7 @@ nsCSSScanner::ParseString(PRInt32 aStop, nsCSSToken& aToken) #endif break; } - if (ch == CSS_ESCAPE) { + if (ch == '\\') { if (!ParseAndAppendEscape(aToken.mIdent, true)) { aToken.mType = eCSSToken_Bad_String; Pushback(ch); diff --git a/layout/style/nsCSSScanner.h b/layout/style/nsCSSScanner.h index 8fa2025c2721..6871c10b887c 100644 --- a/layout/style/nsCSSScanner.h +++ b/layout/style/nsCSSScanner.h @@ -47,13 +47,9 @@ #include "mozilla/css/Loader.h" #include "nsCSSStyleSheet.h" -class nsIUnicharInputStream; - // XXX turn this off for minimo builds #define CSS_REPORT_PARSE_ERRORS -#define CSS_BUFFER_SIZE 256 - // for #ifdef CSS_REPORT_PARSE_ERRORS #include "nsXPIDLString.h" class nsIURI; @@ -141,9 +137,7 @@ class nsCSSScanner { // Init the scanner. // |aLineNumber == 1| is the beginning of a file, use |aLineNumber == 0| // when the line number is unknown. - // Either aInput or (aBuffer and aCount) must be set. - void Init(nsIUnicharInputStream* aInput, - const PRUnichar *aBuffer, PRUint32 aCount, + void Init(const nsAString& aBuffer, nsIURI* aURI, PRUint32 aLineNumber, nsCSSStyleSheet* aSheet, mozilla::css::Loader* aLoader); void Close(); @@ -153,8 +147,6 @@ class nsCSSScanner { // Set whether or not we are processing SVG void SetSVGMode(bool aSVGMode) { - NS_ASSERTION(aSVGMode == true || aSVGMode == false, - "bad bool value"); mSVGMode = aSVGMode; } bool IsSVGMode() const { @@ -200,15 +192,7 @@ class nsCSSScanner { // "-1" back so we can read it again as a number.) void Pushback(PRUnichar aChar); - // Reports operating-system level errors, e.g. read failures and - // out of memory. - nsresult GetLowLevelError(); - - // sometimes the parser wants to make note of a low-level error - void SetLowLevelError(nsresult aErrorCode); - protected: - bool EnsureData(); PRInt32 Read(); PRInt32 Peek(); bool LookAhead(PRUnichar aChar); @@ -226,10 +210,6 @@ protected: bool GatherIdent(PRInt32 aChar, nsString& aIdent); - // Only used when input is a stream - nsCOMPtr mInputStream; - PRUnichar mBuffer[CSS_BUFFER_SIZE]; - const PRUnichar *mReadPointer; PRUint32 mOffset; PRUint32 mCount; @@ -237,7 +217,6 @@ protected: PRInt32 mPushbackCount; PRInt32 mPushbackSize; PRUnichar mLocalPushback[4]; - nsresult mLowLevelError; PRUint32 mLineNumber; // True if we are in SVG mode; false in "normal" CSS diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index 5a575aa8259b..b1ef513d4c60 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -621,13 +621,8 @@ nsCSSValue::Array* nsCSSValue::InitFunction(nsCSSKeyword aFunctionId, PRUint32 aNumArgs) { nsRefPtr func = Array::Create(aNumArgs + 1); - if (!func) { - return nsnull; - } - func->Item(0).SetIntValue(aFunctionId, eCSSUnit_Enumerated); SetArrayValue(func, eCSSUnit_Function); - return func; } @@ -657,18 +652,20 @@ nsCSSValue::BufferFromString(const nsString& aValue) buffer->AddRef(); return buffer; } - + PRUnichar length = aValue.Length(); // NOTE: Alloc prouduces a new, already-addref'd (refcnt = 1) buffer. + // NOTE: String buffer allocation is currently fallible. buffer = nsStringBuffer::Alloc((length + 1) * sizeof(PRUnichar)); - if (NS_LIKELY(buffer != 0)) { - PRUnichar* data = static_cast(buffer->Data()); - nsCharTraits::copy(data, aValue.get(), length); - // Null-terminate. - data[length] = 0; + if (NS_UNLIKELY(!buffer)) { + NS_RUNTIMEABORT("out of memory"); } + PRUnichar* data = static_cast(buffer->Data()); + nsCharTraits::copy(data, aValue.get(), length); + // Null-terminate. + data[length] = 0; return buffer; } @@ -960,7 +957,23 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const aResult.AppendLiteral("-moz-linear-gradient("); } - if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None || + if (gradient->mIsToCorner) { + aResult.AppendLiteral("to"); + NS_ABORT_IF_FALSE(gradient->mBgPos.mXValue.GetUnit() == eCSSUnit_Enumerated && + gradient->mBgPos.mYValue.GetUnit() == eCSSUnit_Enumerated, + "unexpected unit"); + if (!(gradient->mBgPos.mXValue.GetIntValue() & NS_STYLE_BG_POSITION_CENTER)) { + aResult.AppendLiteral(" "); + gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position, + aResult); + } + if (!(gradient->mBgPos.mYValue.GetIntValue() & NS_STYLE_BG_POSITION_CENTER)) { + aResult.AppendLiteral(" "); + gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position, + aResult); + } + aResult.AppendLiteral(", "); + } else if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None || gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None || gradient->mAngle.GetUnit() != eCSSUnit_None) { if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None) { @@ -1442,6 +1455,7 @@ nsCSSValueGradient::nsCSSValueGradient(bool aIsRadial, bool aIsRepeating) : mIsRadial(aIsRadial), mIsRepeating(aIsRepeating), + mIsToCorner(false), mBgPos(eCSSUnit_None), mAngle(eCSSUnit_None), mRadialShape(eCSSUnit_None), diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index d2bb4bdb712b..f91493f6e625 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -49,7 +49,6 @@ #include "nsString.h" #include "nsStringBuffer.h" #include "nsTArray.h" -#include "mozilla/mozalloc.h" #include "nsStyleConsts.h" class imgIRequest; @@ -554,11 +553,6 @@ struct nsCSSValue::Array { return new (aItemCount) Array(aItemCount); } - static Array* Create(const mozilla::fallible_t& aFallible, - size_t aItemCount) { - return new (aFallible, aItemCount) Array(aItemCount); - } - nsCSSValue& operator[](size_t aIndex) { NS_ABORT_IF_FALSE(aIndex < mCount, "out of range"); return mArray[aIndex]; @@ -619,13 +613,6 @@ private: return ::operator new(aSelfSize + sizeof(nsCSSValue) * (aItemCount - 1)); } - void* operator new(size_t aSelfSize, const mozilla::fallible_t& aFallible, - size_t aItemCount) CPP_THROW_NEW { - NS_ABORT_IF_FALSE(aItemCount > 0, "cannot have a 0 item count"); - return ::operator new(aSelfSize + sizeof(nsCSSValue) * (aItemCount - 1), - aFallible); - } - void operator delete(void* aPtr) { ::operator delete(aPtr); } nsCSSValue* First() { return mArray; } @@ -1019,7 +1006,8 @@ nsCSSValue::GetPairListValue() const struct nsCSSValueGradientStop { public: nsCSSValueGradientStop(); - // needed to keep bloat logs happy when we use the nsTArray in nsCSSValueGradient + // needed to keep bloat logs happy when we use the TArray + // in nsCSSValueGradient nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther); ~nsCSSValueGradientStop(); @@ -1044,6 +1032,7 @@ struct nsCSSValueGradient { // true if gradient is radial, false if it is linear bool mIsRadial; bool mIsRepeating; + bool mIsToCorner; // line position and angle nsCSSValuePair mBgPos; nsCSSValue mAngle; @@ -1052,12 +1041,13 @@ struct nsCSSValueGradient { nsCSSValue mRadialShape; nsCSSValue mRadialSize; - nsTArray mStops; + InfallibleTArray mStops; bool operator==(const nsCSSValueGradient& aOther) const { if (mIsRadial != aOther.mIsRadial || mIsRepeating != aOther.mIsRepeating || + mIsToCorner != aOther.mIsToCorner || mBgPos != aOther.mBgPos || mAngle != aOther.mAngle || mRadialShape != aOther.mRadialShape || diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 7d8aa1bbb3b3..af3dd8f29c36 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1405,6 +1405,41 @@ AppendCSSGradientLength(const nsStyleCoord& aValue, aString.Append(tokenString); } +static void +AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient, + nsAString& aString, + bool& aNeedSep) +{ + float xValue = aGradient->mBgPosX.GetPercentValue(); + float yValue = aGradient->mBgPosY.GetPercentValue(); + + if (yValue == 1.0f && xValue == 0.5f) { + // omit "to bottom" + return; + } + NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position"); + + aString.AppendLiteral("to"); + + if (yValue == 0.0f) { + aString.AppendLiteral(" top"); + } else if (yValue == 1.0f) { + aString.AppendLiteral(" bottom"); + } else if (yValue != 0.5f) { // do not write "center" keyword + NS_NOTREACHED("invalid box position"); + } + + if (xValue == 0.0f) { + aString.AppendLiteral(" left"); + } else if (xValue == 1.0f) { + aString.AppendLiteral(" right"); + } else if (xValue != 0.5f) { // do not write "center" keyword + NS_NOTREACHED("invalid box position"); + } + + aNeedSep = true; +} + void nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient, nsAString& aString) @@ -1425,16 +1460,20 @@ nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient, nsAutoString tokenString; nsROCSSPrimitiveValue *tmpVal = GetROCSSPrimitiveValue(); - if (aGradient->mBgPosX.mUnit != eStyleUnit_None) { - AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString); - needSep = true; - } - if (aGradient->mBgPosY.mUnit != eStyleUnit_None) { - if (needSep) { - aString.AppendLiteral(" "); + if (aGradient->mToCorner) { + AppendCSSGradientToBoxPosition(aGradient, aString, needSep); + } else { + if (aGradient->mBgPosX.mUnit != eStyleUnit_None) { + AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString); + needSep = true; + } + if (aGradient->mBgPosY.mUnit != eStyleUnit_None) { + if (needSep) { + aString.AppendLiteral(" "); + } + AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString); + needSep = true; } - AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString); - needSep = true; } if (aGradient->mAngle.mUnit != eStyleUnit_None) { if (needSep) { diff --git a/layout/style/nsIMediaList.h b/layout/style/nsIMediaList.h index ced1b10947eb..ac5d71cca182 100644 --- a/layout/style/nsIMediaList.h +++ b/layout/style/nsIMediaList.h @@ -110,7 +110,7 @@ private: }; struct FeatureEntry { const nsMediaFeature *mFeature; - nsTArray mExpressions; + InfallibleTArray mExpressions; }; nsCOMPtr mMedium; nsTArray mFeatureCache; @@ -192,13 +192,9 @@ public: nsMediaQueryResultCacheKey* aKey); nsresult SetStyleSheet(nsCSSStyleSheet* aSheet); - nsresult AppendQuery(nsAutoPtr& aQuery) { - // Takes ownership of aQuery (if it succeeds) - if (!mArray.AppendElement(aQuery.get())) { - return NS_ERROR_OUT_OF_MEMORY; - } - aQuery.forget(); - return NS_OK; + void AppendQuery(nsAutoPtr& aQuery) { + // Takes ownership of aQuery + mArray.AppendElement(aQuery.forget()); } nsresult Clone(nsMediaList** aResult); @@ -213,7 +209,7 @@ protected: nsresult Delete(const nsAString & aOldMedium); nsresult Append(const nsAString & aOldMedium); - nsTArray > mArray; + InfallibleTArray > mArray; // not refcounted; sheet will let us know when it goes away // mStyleSheet is the sheet that needs to be dirtied when this medialist // changes diff --git a/layout/style/nsNthIndexCache.cpp b/layout/style/nsNthIndexCache.cpp index e71de5fd1ec5..9fb188a37f5a 100644 --- a/layout/style/nsNthIndexCache.cpp +++ b/layout/style/nsNthIndexCache.cpp @@ -56,7 +56,10 @@ nsNthIndexCache::~nsNthIndexCache() void nsNthIndexCache::Reset() { - mCache.clear(); + mCaches[0][0].clear(); + mCaches[0][1].clear(); + mCaches[1][0].clear(); + mCaches[1][1].clear(); } inline bool @@ -69,29 +72,28 @@ nsNthIndexCache::SiblingMatchesElement(nsIContent* aSibling, Element* aElement, } inline bool -nsNthIndexCache::IndexDetermined(nsIContent* aSibling, Element* aChild, - bool aIsOfType, bool aIsFromEnd, - bool aCheckEdgeOnly, PRInt32& aResult) +nsNthIndexCache::IndexDeterminedFromPreviousSibling(nsIContent* aSibling, + Element* aChild, + bool aIsOfType, + bool aIsFromEnd, + const Cache& aCache, + PRInt32& aResult) { if (SiblingMatchesElement(aSibling, aChild, aIsOfType)) { - if (aCheckEdgeOnly) { - // The caller only cares whether or not the result is 1, and we - // now know it's not. - aResult = -1; - return true; - } - - Cache::Ptr siblingEntry = mCache.lookup(aSibling); + Cache::Ptr siblingEntry = aCache.lookup(aSibling); if (siblingEntry) { - PRInt32 siblingIndex = siblingEntry->value.mNthIndices[aIsOfType][aIsFromEnd]; + PRInt32 siblingIndex = siblingEntry->value; NS_ASSERTION(siblingIndex != 0, "How can a non-anonymous node have an anonymous sibling?"); if (siblingIndex > 0) { // At this point, aResult is a count of how many elements matching - // aChild we have seen after aSibling, including aChild itself. So if - // |siblingIndex| is the index of aSibling, we need to add aResult to - // get the right answer here. - aResult = siblingIndex + aResult; + // aChild we have seen after aSibling, including aChild itself. + // |siblingIndex| is the index of aSibling. + // So if aIsFromEnd, we want |aResult = siblingIndex - aResult| and + // otherwise we want |aResult = siblingIndex + aResult|. + NS_ABORT_IF_FALSE(aIsFromEnd == 0 || aIsFromEnd == 1, + "Bogus bool value"); + aResult = siblingIndex + aResult * (1 - 2 * aIsFromEnd); return true; } } @@ -112,48 +114,75 @@ nsNthIndexCache::GetNthIndex(Element* aChild, bool aIsOfType, return 0; } - if (!mCache.initialized() && !mCache.init()) { + Cache &cache = mCaches[aIsOfType][aIsFromEnd]; + + if (!cache.initialized() && !cache.init()) { // Give up and just don't match. return 0; } - Cache::AddPtr entry = mCache.lookupForAdd(aChild); - - if (!entry && !mCache.add(entry, aChild)) { + Cache::AddPtr entry = cache.lookupForAdd(aChild); + + // Default the value to -2 when adding + if (!entry && !cache.add(entry, aChild, -2)) { // No good; don't match. return 0; } - PRInt32 &slot = entry->value.mNthIndices[aIsOfType][aIsFromEnd]; + PRInt32 &slot = entry->value; if (slot != -2 && (slot != -1 || aCheckEdgeOnly)) { return slot; } PRInt32 result = 1; - if (aIsFromEnd) { - for (nsIContent *cur = aChild->GetNextSibling(); - cur; - cur = cur->GetNextSibling()) { - // It doesn't make sense to do cache lookups for siblings when - // aIsFromEnd. In general, the cache will only be primed for - // things that are _before_ us in the DOM. - if (SiblingMatchesElement(cur, aChild, aIsOfType)) { - if (aCheckEdgeOnly) { - // The caller only cares whether or not the result is 1, and we - // now know it's not. + if (aCheckEdgeOnly) { + // The caller only cares whether or not the result is 1, so we can + // stop as soon as we see any other elements that match us. + if (aIsFromEnd) { + for (nsIContent *cur = aChild->GetNextSibling(); + cur; + cur = cur->GetNextSibling()) { + if (SiblingMatchesElement(cur, aChild, aIsOfType)) { + result = -1; + break; + } + } + } else { + for (nsIContent *cur = aChild->GetPreviousSibling(); + cur; + cur = cur->GetPreviousSibling()) { + if (SiblingMatchesElement(cur, aChild, aIsOfType)) { result = -1; break; } - ++result; } } } else { + // In the common case, we already have a cached index for one of + // our previous siblings, so check that first. for (nsIContent *cur = aChild->GetPreviousSibling(); cur; cur = cur->GetPreviousSibling()) { - if (IndexDetermined(cur, aChild, aIsOfType, aIsFromEnd, aCheckEdgeOnly, - result)) { - break; + if (IndexDeterminedFromPreviousSibling(cur, aChild, aIsOfType, + aIsFromEnd, cache, result)) { + slot = result; + return result; + } + } + + // Now if aIsFromEnd we lose: need to actually compute our index, + // since looking at previous siblings wouldn't have told us + // anything about it. Note that it doesn't make sense to do cache + // lookups on our following siblings, since chances are the cache + // is not primed for them. + if (aIsFromEnd) { + result = 1; + for (nsIContent *cur = aChild->GetNextSibling(); + cur; + cur = cur->GetNextSibling()) { + if (SiblingMatchesElement(cur, aChild, aIsOfType)) { + ++result; + } } } } diff --git a/layout/style/nsNthIndexCache.h b/layout/style/nsNthIndexCache.h index 0797b19e1ae5..c6b3c773f1f2 100644 --- a/layout/style/nsNthIndexCache.h +++ b/layout/style/nsNthIndexCache.h @@ -80,30 +80,11 @@ private: inline bool SiblingMatchesElement(nsIContent* aSibling, Element* aElement, bool aIsOfType); - /** - * Returns true if aResult has been set to the correct value for aChild and - * no more work needs to be done. Returns false otherwise. - */ - inline bool IndexDetermined(nsIContent* aSibling, Element* aChild, - bool aIsOfType, bool aIsFromEnd, - bool aCheckEdgeOnly, PRInt32& aResult); - - struct CacheEntry { - CacheEntry() { - mNthIndices[0][0] = -2; - mNthIndices[0][1] = -2; - mNthIndices[1][0] = -2; - mNthIndices[1][1] = -2; - } - - // This node's index for :nth-child(), :nth-last-child(), - // :nth-of-type(), :nth-last-of-type(). If -2, needs to be computed. - // If -1, needs to be computed but known not to be 1. - // If 0, the node is not at any index in its parent. - // The first subscript is 0 for -child and 1 for -of-type, the second - // subscript is 0 for nth- and 1 for nth-last-. - PRInt32 mNthIndices[2][2]; - }; + // This node's index for this cache. + // If -2, needs to be computed. + // If -1, needs to be computed but known not to be 1. + // If 0, the node is not at any index in its parent. + typedef PRInt32 CacheEntry; class SystemAllocPolicy { public: @@ -116,7 +97,30 @@ private: typedef js::HashMap, SystemAllocPolicy> Cache; - Cache mCache; + /** + * Returns true if aResult has been set to the correct value for aChild and + * no more work needs to be done. Returns false otherwise. + * + * aResult is an inout parameter. The in value is the number of elements + * that are in the half-open range (aSibling, aChild] (so including aChild + * but not including aSibling) that match aChild. The out value is the + * correct index for aChild if this function returns true and the number of + * elements in the closed range [aSibling, aChild] that match aChild + * otherwise. + */ + inline bool IndexDeterminedFromPreviousSibling(nsIContent* aSibling, + Element* aChild, + bool aIsOfType, + bool aIsFromEnd, + const Cache& aCache, + PRInt32& aResult); + + // Caches of indices for :nth-child(), :nth-last-child(), + // :nth-of-type(), :nth-last-of-type(), keyed by Element*. + // + // The first subscript is 0 for -child and 1 for -of-type, the second + // subscript is 0 for nth- and 1 for nth-last-. + Cache mCaches[2][2]; }; #endif /* nsContentIndexCache_h__ */ diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 5397705fef93..6f2d45ebf21c 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -865,6 +865,8 @@ static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext, "bad unit for linear size"); aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR; aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER; + + aResult.mToCorner = gradient->mIsToCorner; } // bg-position diff --git a/layout/style/nsStyleAnimation.cpp b/layout/style/nsStyleAnimation.cpp index 4865bc3fd9a9..3e36677d2ea7 100644 --- a/layout/style/nsStyleAnimation.cpp +++ b/layout/style/nsStyleAnimation.cpp @@ -1544,7 +1544,8 @@ AddTransformLists(const nsCSSValueList* aList1, double aCoeff1, AddDifferentTransformLists(&tempList1, aCoeff1, &tempList2, aCoeff2); } - while ((*resultTail)->mNext) { + // Now advance resultTail to point to the new tail slot. + while (*resultTail) { resultTail = &(*resultTail)->mNext; } diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index e39d0308b3b9..20d3b23ec081 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1351,6 +1351,7 @@ nsStyleGradient::operator==(const nsStyleGradient& aOther) const if (mShape != aOther.mShape || mSize != aOther.mSize || mRepeating != aOther.mRepeating || + mToCorner != aOther.mToCorner || mBgPosX != aOther.mBgPosX || mBgPosY != aOther.mBgPosY || mAngle != aOther.mAngle) @@ -1372,6 +1373,7 @@ nsStyleGradient::nsStyleGradient(void) : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR) , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) , mRepeating(false) + , mToCorner(false) { } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 4ffbd9ff52a0..db96bc658114 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -158,6 +158,7 @@ public: PRUint8 mSize; // NS_STYLE_GRADIENT_SIZE_*; // not used (must be FARTHEST_CORNER) for linear shape bool mRepeating; + bool mToCorner; nsStyleCoord mBgPosX; // percent, coord, calc, none nsStyleCoord mBgPosY; // percent, coord, calc, none diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index a34f5fa87697..1e20b45c21bf 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -49,7 +49,7 @@ const CSS_TYPE_SHORTHAND_AND_LONGHAND = 2; // Each property has the following fields: // domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties -// inherited: Whether the property is inherited by default (stated as +// inherited: Whether the property is inherited by default (stated as // yes or no in the property header in all CSS specs) // type: see above // get_computed: if present, the property's computed value shows up on @@ -1191,6 +1191,19 @@ var gCSSProperties = { "-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))", "-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)", + "-moz-linear-gradient(to top, red, blue)", + "-moz-linear-gradient(to bottom, red, blue)", + "-moz-linear-gradient(to left, red, blue)", + "-moz-linear-gradient(to right, red, blue)", + "-moz-linear-gradient(to top left, red, blue)", + "-moz-linear-gradient(to top right, red, blue)", + "-moz-linear-gradient(to bottom left, red, blue)", + "-moz-linear-gradient(to bottom right, red, blue)", + "-moz-linear-gradient(to left top, red, blue)", + "-moz-linear-gradient(to left bottom, red, blue)", + "-moz-linear-gradient(to right top, red, blue)", + "-moz-linear-gradient(to right bottom, red, blue)", + "-moz-linear-gradient(top left, red, blue)", "-moz-linear-gradient(0 0, red, blue)", "-moz-linear-gradient(20% bottom, red, blue)", @@ -1269,6 +1282,19 @@ var gCSSProperties = { "-moz-repeating-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))", "-moz-repeating-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)", + "-moz-repeating-linear-gradient(to top, red, blue)", + "-moz-repeating-linear-gradient(to bottom, red, blue)", + "-moz-repeating-linear-gradient(to left, red, blue)", + "-moz-repeating-linear-gradient(to right, red, blue)", + "-moz-repeating-linear-gradient(to top left, red, blue)", + "-moz-repeating-linear-gradient(to top right, red, blue)", + "-moz-repeating-linear-gradient(to bottom left, red, blue)", + "-moz-repeating-linear-gradient(to bottom right, red, blue)", + "-moz-repeating-linear-gradient(to left top, red, blue)", + "-moz-repeating-linear-gradient(to left bottom, red, blue)", + "-moz-repeating-linear-gradient(to right top, red, blue)", + "-moz-repeating-linear-gradient(to right bottom, red, blue)", + "-moz-repeating-linear-gradient(top left, red, blue)", "-moz-repeating-linear-gradient(0 0, red, blue)", "-moz-repeating-linear-gradient(20% bottom, red, blue)", @@ -1398,6 +1424,28 @@ var gCSSProperties = { "-moz-radial-gradient(contain contain, red, blue)", "-moz-radial-gradient(ellipse circle, red, blue)", + "-moz-linear-gradient(to 0 0, red, blue)", + "-moz-linear-gradient(to 20% bottom, red, blue)", + "-moz-linear-gradient(to center 20%, red, blue)", + "-moz-linear-gradient(to left 35px, red, blue)", + "-moz-linear-gradient(to 10% 10em, red, blue)", + "-moz-linear-gradient(to 44px top, red, blue)", + "-moz-linear-gradient(to top left 45deg, red, blue)", + "-moz-linear-gradient(to 20% bottom -300deg, red, blue)", + "-moz-linear-gradient(to center 20% 1.95929rad, red, blue)", + "-moz-linear-gradient(to left 35px 30grad, red, blue)", + "-moz-linear-gradient(to 10% 10em 99999deg, red, blue)", + "-moz-linear-gradient(to 44px top -33deg, red, blue)", + "-moz-linear-gradient(to -33deg, red, blue)", + "-moz-linear-gradient(to 30grad left 35px, red, blue)", + "-moz-linear-gradient(to 10deg 20px, red, blue)", + "-moz-linear-gradient(to .414rad bottom, red, blue)", + + "-moz-linear-gradient(to top top, red, blue)", + "-moz-linear-gradient(to bottom bottom, red, blue)", + "-moz-linear-gradient(to left left, red, blue)", + "-moz-linear-gradient(to right right, red, blue)", + "-moz-repeating-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)", "-moz-repeating-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))", "-moz-repeating-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))", @@ -1408,7 +1456,29 @@ var gCSSProperties = { "-moz-repeating-linear-gradient(left left, top top, blue 0)", "-moz-repeating-linear-gradient(inherit, 10px 10px, blue 0)", "-moz-repeating-linear-gradient(left left blue red)", - "-moz-repeating-linear-gradient()" ] + "-moz-repeating-linear-gradient()", + + "-moz-repeating-linear-gradient(to 0 0, red, blue)", + "-moz-repeating-linear-gradient(to 20% bottom, red, blue)", + "-moz-repeating-linear-gradient(to center 20%, red, blue)", + "-moz-repeating-linear-gradient(to left 35px, red, blue)", + "-moz-repeating-linear-gradient(to 10% 10em, red, blue)", + "-moz-repeating-linear-gradient(to 44px top, red, blue)", + "-moz-repeating-linear-gradient(to top left 45deg, red, blue)", + "-moz-repeating-linear-gradient(to 20% bottom -300deg, red, blue)", + "-moz-repeating-linear-gradient(to center 20% 1.95929rad, red, blue)", + "-moz-repeating-linear-gradient(to left 35px 30grad, red, blue)", + "-moz-repeating-linear-gradient(to 10% 10em 99999deg, red, blue)", + "-moz-repeating-linear-gradient(to 44px top -33deg, red, blue)", + "-moz-repeating-linear-gradient(to -33deg, red, blue)", + "-moz-repeating-linear-gradient(to 30grad left 35px, red, blue)", + "-moz-repeating-linear-gradient(to 10deg 20px, red, blue)", + "-moz-repeating-linear-gradient(to .414rad bottom, red, blue)", + + "-moz-repeating-linear-gradient(to top top, red, blue)", + "-moz-repeating-linear-gradient(to bottom bottom, red, blue)", + "-moz-repeating-linear-gradient(to left left, red, blue)", + "-moz-repeating-linear-gradient(to right right, red, blue)" ] }, "background-origin": { domProp: "backgroundOrigin", @@ -1833,7 +1903,7 @@ var gCSSProperties = { inherited: true, type: CSS_TYPE_LONGHAND, initial_values: [ "show" ], - other_values: [ "hide" ], + other_values: [ "hide", "-moz-show-background" ], invalid_values: [] }, "float": { @@ -1874,7 +1944,7 @@ var gCSSProperties = { inherited: true, type: CSS_TYPE_LONGHAND, initial_values: [ "normal" ], - other_values: [ "'TRK'", "\"TRK\"", "'N\\'Ko'" ], + other_values: [ "'ENG'", "'TRK'", "\"TRK\"", "'N\\'Ko'" ], invalid_values: [ "TRK" ] }, "font-size": { @@ -1935,7 +2005,7 @@ var gCSSProperties = { type: CSS_TYPE_LONGHAND, initial_values: [ "normal", "400" ], other_values: [ "bold", "100", "200", "300", "500", "600", "700", "800", "900", "bolder", "lighter" ], - invalid_values: [ "107", "399", "401", "699", "710" ] + invalid_values: [ "0", "100.0", "107", "399", "401", "699", "710", "1000" ] }, "height": { domProp: "height", diff --git a/layout/style/test/test_unclosed_parentheses.html b/layout/style/test/test_unclosed_parentheses.html index da5040c9eaba..a1e3bde7c28f 100644 --- a/layout/style/test/test_unclosed_parentheses.html +++ b/layout/style/test/test_unclosed_parentheses.html @@ -54,6 +54,14 @@ var declarations = [ "background-image: -moz-linear-gradient(red, yellow, blue", "background-image: -moz-linear-gradient(red 1px, yellow 5px, blue 10px", "background-image: -moz-linear-gradient(red, yellow, rgb(0, 0, 255)", + "background-image: -moz-linear-gradient(to", + "background-image: -moz-linear-gradient(to top", + "background-image: -moz-linear-gradient(to top left", + "background-image: -moz-linear-gradient(to top left,", + "background-image: -moz-repeating-linear-gradient(to top left, red, blue", + "background-image: -moz-linear-gradient(to top left, red, yellow, blue", + "background-image: -moz-linear-gradient(to top left, red 1px, yellow 5px, blue 10px", + "background-image: -moz-linear-gradient(to top left, red, yellow, rgb(0, 0, 255)", "background-image: -moz-repeating-linear-gradient(top left, red, blue", "background-image: -moz-linear-gradient(top left, red, yellow, blue", "background-image: -moz-linear-gradient(top left, red 1px, yellow 5px, blue 10px", diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index 1bd37c3b8162..6f306a3e2ff5 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -47,6 +47,9 @@ #include "nsIInterfaceRequestorUtils.h" #include "gfxPlatform.h" #include "nsSVGSVGElement.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; class nsSVGImageFrame; @@ -72,14 +75,15 @@ private: nsSVGImageFrame *mFrame; }; +typedef nsSVGPathGeometryFrame nsSVGImageFrameBase; -class nsSVGImageFrame : public nsSVGPathGeometryFrame +class nsSVGImageFrame : public nsSVGImageFrameBase { friend nsIFrame* NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); protected: - nsSVGImageFrame(nsStyleContext* aContext) : nsSVGPathGeometryFrame(aContext) {} + nsSVGImageFrame(nsStyleContext* aContext) : nsSVGImageFrameBase(aContext) {} virtual ~nsSVGImageFrame(); public: @@ -168,7 +172,7 @@ nsSVGImageFrame::Init(nsIContent* aContent, NS_ASSERTION(image, "Content is not an SVG image!"); #endif - nsresult rv = nsSVGPathGeometryFrame::Init(aContent, aParent, aPrevInFlow); + nsresult rv = nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow); if (NS_FAILED(rv)) return rv; mListener = new nsSVGImageListener(this); @@ -195,18 +199,34 @@ nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { - if (aNameSpaceID == kNameSpaceID_None && - (aAttribute == nsGkAtoms::x || - aAttribute == nsGkAtoms::y || - aAttribute == nsGkAtoms::width || - aAttribute == nsGkAtoms::height || - aAttribute == nsGkAtoms::preserveAspectRatio)) { - nsSVGUtils::UpdateGraphic(this); - return NS_OK; - } + if (aNameSpaceID == kNameSpaceID_None && + (aAttribute == nsGkAtoms::x || + aAttribute == nsGkAtoms::y || + aAttribute == nsGkAtoms::width || + aAttribute == nsGkAtoms::height || + aAttribute == nsGkAtoms::preserveAspectRatio)) { + nsSVGUtils::UpdateGraphic(this); + return NS_OK; + } + if (aNameSpaceID == kNameSpaceID_XLink && + aAttribute == nsGkAtoms::href) { + // If caller is not chrome and dom.disable_image_src_set is true, + // prevent setting image.src by exiting early + if (Preferences::GetBool("dom.disable_image_src_set") && + !nsContentUtils::IsCallerChrome()) { + return NS_OK; + } + nsSVGImageElement *element = static_cast(mContent); - return nsSVGPathGeometryFrame::AttributeChanged(aNameSpaceID, - aAttribute, aModType); + if (element->mStringAttributes[nsSVGImageElement::HREF].IsExplicitlySet()) { + element->LoadSVGImage(true, true); + } else { + element->CancelImageRequests(true); + } + } + + return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID, + aAttribute, aModType); } gfxMatrix @@ -426,7 +446,7 @@ nsSVGImageFrame::GetFrameForPoint(const nsPoint &aPoint) // just fall back on our element's own bounds here. } - return nsSVGPathGeometryFrame::GetFrameForPoint(aPoint); + return nsSVGImageFrameBase::GetFrameForPoint(aPoint); } nsIAtom * diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index d3a72560ac84..40f4f659a78c 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -1143,10 +1143,10 @@ gfxIntSize nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, bool *aResultOverflows) { - gfxIntSize surfaceSize(ClampToInt(aSize.width), ClampToInt(aSize.height)); + gfxIntSize surfaceSize(ClampToInt(ceil(aSize.width)), ClampToInt(ceil(aSize.height))); - *aResultOverflows = surfaceSize.width != NS_round(aSize.width) || - surfaceSize.height != NS_round(aSize.height); + *aResultOverflows = surfaceSize.width != ceil(aSize.width) || + surfaceSize.height != ceil(aSize.height); if (!gfxASurface::CheckSurfaceSize(surfaceSize)) { surfaceSize.width = NS_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION, diff --git a/layout/tables/crashtests/695430-1.html b/layout/tables/crashtests/695430-1.html new file mode 100644 index 000000000000..696fa731e97f --- /dev/null +++ b/layout/tables/crashtests/695430-1.html @@ -0,0 +1,23 @@ + + + + + +
+ + + + + + + + + + + +
+ diff --git a/layout/tables/crashtests/crashtests.list b/layout/tables/crashtests/crashtests.list index e2ab923e53ad..a0f82cbcb0d1 100644 --- a/layout/tables/crashtests/crashtests.list +++ b/layout/tables/crashtests/crashtests.list @@ -110,3 +110,4 @@ asserts(0-3) load 595758-1.xhtml # Bug 453871 load 595758-2.xhtml load 678447-1.html load 691824-1.xhtml +load 695430-1.html diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 6f60ee27cee7..4f50057e5aed 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -1032,6 +1032,8 @@ nsTableRowGroupFrame::UndoContinuedRow(nsPresContext* aPresContext, // will not have reflowed yet to pick up content from any overflow lines. overflows->DestroyFrame(aRow); + if (overflows->IsEmpty()) + return; // Put the overflow rows into our child list mFrames.InsertFrames(nsnull, rowBefore, *overflows); } diff --git a/layout/tools/reftest/reftest-content.js b/layout/tools/reftest/reftest-content.js index 03abe6665c83..65dc5e466742 100644 --- a/layout/tools/reftest/reftest-content.js +++ b/layout/tools/reftest/reftest-content.js @@ -257,6 +257,10 @@ function setupDisplayport(contentRootElement) { LogInfo("Setting displayport to "); windowUtils().setDisplayPortForElement(dpx, dpy, dpw, dph, content.document.documentElement); } + var asyncScroll = attrOrDefault("reftest-async-scroll", false); + if (asyncScroll) { + SendEnableAsyncScroll(); + } // XXX support resolution when needed @@ -751,6 +755,11 @@ function SendFailedLoad(why) sendAsyncMessage("reftest:FailedLoad", { why: why }); } +function SendEnableAsyncScroll() +{ + sendAsyncMessage("reftest:EnableAsyncScroll"); +} + // Return true if a snapshot was taken. function SendInitCanvasWithSnapshot() { diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 31d9382a1120..5d7d8caeaa8e 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -1346,6 +1346,7 @@ function FinishTestItem() gDumpLog("REFTEST INFO | Loading a blank page\n"); // After clearing, content will notify us of the assertion count // and tests will continue. + SetAsyncScroll(false); SendClear(); } @@ -1442,10 +1443,21 @@ function RegisterMessageListenersAndLoadContentScript() "reftest:ExpectProcessCrash", function (m) { RecvExpectProcessCrash(); } ); + gBrowserMessageManager.addMessageListener( + "reftest:EnableAsyncScroll", + function (m) { SetAsyncScroll(true); } + ); gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true); } +function SetAsyncScroll(enabled) +{ + gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode = + enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL : + CI.nsIFrameLoader.RENDER_MODE_DEFAULT; +} + function RecvAssertionCount(count) { DoAssertionCheck(count); diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 9ecf5355043c..dcdafd3a8847 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -428,9 +428,6 @@ def main(): automation.setRemoteLog(options.remoteLogFile) reftest = RemoteReftest(automation, dm, options, SCRIPT_DIRECTORY) - # Start the webserver - reftest.startWebServer(options) - # Hack in a symbolic link for jsreftest os.system("ln -s ../jsreftest " + str(os.path.join(SCRIPT_DIRECTORY, "jsreftest"))) @@ -441,6 +438,12 @@ def main(): elif os.path.exists(args[0]): manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/') manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + manifestPath + else: + print "ERROR: Could not find test manifest '%s'" % manifest + sys.exit(1) + + # Start the webserver + reftest.startWebServer(options) procName = options.app.split('/')[-1] if (dm.processExist(procName)): diff --git a/layout/xul/base/src/nsDeckFrame.cpp b/layout/xul/base/src/nsDeckFrame.cpp index 769abd33f635..68d6a13b4ea6 100644 --- a/layout/xul/base/src/nsDeckFrame.cpp +++ b/layout/xul/base/src/nsDeckFrame.cpp @@ -66,6 +66,10 @@ NS_NewDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame) +NS_QUERYFRAME_HEAD(nsDeckFrame) + NS_QUERYFRAME_ENTRY(nsDeckFrame) +NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) + nsDeckFrame::nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) : nsBoxFrame(aPresShell, aContext), mIndex(0) @@ -92,7 +96,7 @@ nsDeckFrame::AttributeChanged(PRInt32 aNameSpaceID, // if the index changed hide the old element and make the new element visible if (aAttribute == nsGkAtoms::selectedIndex) { - IndexChanged(PresContext()); + IndexChanged(); } return rv; @@ -110,66 +114,14 @@ nsDeckFrame::Init(nsIContent* aContent, return rv; } -static void -CreateViewsForFrames(const nsFrameList& aFrames) +void +nsDeckFrame::HideBox(nsIBox* aBox) { - for (nsFrameList::Enumerator f(aFrames); !f.AtEnd(); f.Next()) { - nsContainerFrame::CreateViewForFrame(f.get(), true); - } -} - -NS_IMETHODIMP -nsDeckFrame::SetInitialChildList(ChildListID aListID, - nsFrameList& aChildList) -{ - CreateViewsForFrames(aChildList); - return nsBoxFrame::SetInitialChildList(aListID, aChildList); -} - -NS_IMETHODIMP -nsDeckFrame::AppendFrames(ChildListID aListID, - nsFrameList& aFrameList) -{ - CreateViewsForFrames(aFrameList); - return nsBoxFrame::AppendFrames(aListID, aFrameList); -} - -NS_IMETHODIMP -nsDeckFrame::InsertFrames(ChildListID aListID, - nsIFrame* aPrevFrame, - nsFrameList& aFrameList) -{ - CreateViewsForFrames(aFrameList); - return nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList); + nsIPresShell::ClearMouseCapture(aBox); } void -nsDeckFrame::HideBox(nsPresContext* aPresContext, nsIBox* aBox) -{ - nsIView* view = aBox->GetView(); - - if (view) { - nsIViewManager* viewManager = view->GetViewManager(); - viewManager->SetViewVisibility(view, nsViewVisibility_kHide); - viewManager->ResizeView(view, nsRect(0, 0, 0, 0)); - } -} - -void -nsDeckFrame::ShowBox(nsPresContext* aPresContext, nsIBox* aBox) -{ - nsRect rect = aBox->GetRect(); - nsIView* view = aBox->GetView(); - if (view) { - nsIViewManager* viewManager = view->GetViewManager(); - rect.x = rect.y = 0; - viewManager->ResizeView(view, rect); - viewManager->SetViewVisibility(view, nsViewVisibility_kShow); - } -} - -void -nsDeckFrame::IndexChanged(nsPresContext* aPresContext) +nsDeckFrame::IndexChanged() { //did the index change? PRInt32 index = GetSelectedIndex(); @@ -182,14 +134,9 @@ nsDeckFrame::IndexChanged(nsPresContext* aPresContext) // hide the currently showing box nsIBox* currentBox = GetSelectedBox(); if (currentBox) // only hide if it exists - HideBox(aPresContext, currentBox); + HideBox(currentBox); mIndex = index; - - // show the new box - nsIBox* newBox = GetSelectedBox(); - if (newBox) // only show if it exists - ShowBox(aPresContext, newBox); } PRInt32 @@ -211,7 +158,7 @@ nsDeckFrame::GetSelectedIndex() return index; } -nsIBox* +nsIFrame* nsDeckFrame::GetSelectedBox() { return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nsnull; @@ -265,10 +212,8 @@ nsDeckFrame::DoLayout(nsBoxLayoutState& aState) while (box) { // make collapsed children not show up - if (count == mIndex) - ShowBox(aState.PresContext(), box); - else - HideBox(aState.PresContext(), box); + if (count != mIndex) + HideBox(box); box = box->GetNextBox(); count++; diff --git a/layout/xul/base/src/nsDeckFrame.h b/layout/xul/base/src/nsDeckFrame.h index a6b5db9f40cd..e845c21359de 100644 --- a/layout/xul/base/src/nsDeckFrame.h +++ b/layout/xul/base/src/nsDeckFrame.h @@ -51,6 +51,8 @@ class nsDeckFrame : public nsBoxFrame { public: + NS_DECL_QUERYFRAME_TARGET(nsDeckFrame) + NS_DECL_QUERYFRAME NS_DECL_FRAMEARENA_HELPERS friend nsIFrame* NS_NewDeckFrame(nsIPresShell* aPresShell, @@ -74,16 +76,6 @@ public: nsIFrame* aParent, nsIFrame* aPrevInFlow); - // Override SetInitialChildList/AppendFrames/InsertFrames to - // create views for our child frames if necessary - NS_IMETHOD SetInitialChildList(ChildListID aListID, - nsFrameList& aChildList); - NS_IMETHOD AppendFrames(ChildListID aListID, - nsFrameList& aFrameList); - NS_IMETHOD InsertFrames(ChildListID aListID, - nsIFrame* aPrevFrame, - nsFrameList& aFrameList); - virtual nsIAtom* GetType() const; #ifdef NS_DEBUG @@ -95,14 +87,13 @@ public: nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + nsIFrame* GetSelectedBox(); + protected: - // REVIEW: Sorry, I couldn't resist devirtualizing these. - nsIBox* GetSelectedBox(); - void IndexChanged(nsPresContext* aPresContext); + void IndexChanged(); PRInt32 GetSelectedIndex(); - void HideBox(nsPresContext* aPresContext, nsIBox* aBox); - void ShowBox(nsPresContext* aPresContext, nsIBox* aBox); + void HideBox(nsIBox* aBox); private: diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index b65a07e5404b..0bb7b73e93f0 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -155,7 +155,7 @@ nsMenuPopupFrame::Init(nsIContent* aContent, mMenuCanOverlapOSBar = LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar) != 0; - rv = CreatePopupViewForFrame(); + rv = CreatePopupView(); NS_ENSURE_SUCCESS(rv, rv); // XXX Hack. The popup's view should float above all other views, @@ -1921,24 +1921,20 @@ nsMenuPopupFrame::SetConsumeRollupEvent(PRUint32 aConsumeMode) * as much as possible. Until we get rid of views finally... */ nsresult -nsMenuPopupFrame::CreatePopupViewForFrame() +nsMenuPopupFrame::CreatePopupView() { if (HasView()) { return NS_OK; } - nsViewVisibility visibility = nsViewVisibility_kShow; - PRInt32 zIndex = 0; - bool autoZIndex = false; - - nsIView* parentView; nsIViewManager* viewManager = PresContext()->GetPresShell()->GetViewManager(); NS_ASSERTION(nsnull != viewManager, "null view manager"); // Create a view - parentView = viewManager->GetRootView(); - visibility = nsViewVisibility_kHide; - zIndex = PR_INT32_MAX; + nsIView* parentView = viewManager->GetRootView(); + nsViewVisibility visibility = nsViewVisibility_kHide; + PRInt32 zIndex = PR_INT32_MAX; + bool autoZIndex = false; NS_ASSERTION(parentView, "no parent view"); @@ -1954,7 +1950,7 @@ nsMenuPopupFrame::CreatePopupViewForFrame() SetView(view); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsMenuPopupFrame::CreatePopupViewForFrame: frame=%p view=%p", this, view)); + ("nsMenuPopupFrame::CreatePopupView: frame=%p view=%p", this, view)); if (!view) return NS_ERROR_OUT_OF_MEMORY; diff --git a/layout/xul/base/src/nsMenuPopupFrame.h b/layout/xul/base/src/nsMenuPopupFrame.h index fc564b9c094c..ea8b35ef4b88 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.h +++ b/layout/xul/base/src/nsMenuPopupFrame.h @@ -409,7 +409,7 @@ protected: // Create a popup view for this frame. The view is added a child of the root // view, and is initially hidden. - nsresult CreatePopupViewForFrame(); + nsresult CreatePopupView(); nsString mIncrementalString; // for incremental typing navigation diff --git a/layout/xul/base/src/nsTextBoxFrame.cpp b/layout/xul/base/src/nsTextBoxFrame.cpp index 974d0a7fa916..0c1fde0da955 100644 --- a/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/layout/xul/base/src/nsTextBoxFrame.cpp @@ -379,7 +379,7 @@ nsDisplayXULTextBox::PaintTextToContext(nsRenderingContext* aCtx, nsRect nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } nsRect diff --git a/media/libogg/include/ogg/config_types.h b/media/libogg/include/ogg/config_types.h index 00962788e193..1e7d49098909 100644 --- a/media/libogg/include/ogg/config_types.h +++ b/media/libogg/include/ogg/config_types.h @@ -20,6 +20,6 @@ typedef short ogg_int16_t; typedef unsigned short ogg_uint16_t; typedef int ogg_int32_t; typedef unsigned int ogg_uint32_t; -typedef long ogg_int64_t; +typedef long long ogg_int64_t; #endif diff --git a/media/libsydneyaudio/src/sydney_audio_android.c b/media/libsydneyaudio/src/sydney_audio_android.c index 5ebdc89ae81a..0b6e8ef0bedf 100644 --- a/media/libsydneyaudio/src/sydney_audio_android.c +++ b/media/libsydneyaudio/src/sydney_audio_android.c @@ -59,8 +59,10 @@ struct AudioTrack { jclass class; jmethodID constructor; jmethodID flush; + jmethodID getminbufsz; jmethodID pause; jmethodID play; + jmethodID release; jmethodID setvol; jmethodID stop; jmethodID write; @@ -105,6 +107,7 @@ struct sa_stream { int64_t timePlaying; int64_t amountWritten; unsigned int bufferSize; + unsigned int minBufferSize; jclass at_class; }; @@ -120,8 +123,10 @@ init_jni_bindings(JNIEnv *jenv) { "android/media/AudioTrack")); at.constructor = (*jenv)->GetMethodID(jenv, class, "", "(IIIIII)V"); at.flush = (*jenv)->GetMethodID(jenv, class, "flush", "()V"); + at.getminbufsz = (*jenv)->GetStaticMethodID(jenv, class, "getMinBufferSize", "(III)I"); at.pause = (*jenv)->GetMethodID(jenv, class, "pause", "()V"); at.play = (*jenv)->GetMethodID(jenv, class, "play", "()V"); + at.release = (*jenv)->GetMethodID(jenv, class, "release", "()V"); at.setvol = (*jenv)->GetMethodID(jenv, class, "setStereoVolume", "(FF)I"); at.stop = (*jenv)->GetMethodID(jenv, class, "stop", "()V"); at.write = (*jenv)->GetMethodID(jenv, class, "write", "([BII)I"); @@ -181,7 +186,8 @@ sa_stream_create_pcm( s->timePlaying = 0; s->amountWritten = 0; - s->bufferSize = rate * channels; + s->bufferSize = 0; + s->minBufferSize = 0; *_s = s; return SA_SUCCESS; @@ -199,8 +205,9 @@ sa_stream_open(sa_stream_t *s) { } JNIEnv *jenv = GetJNIForThread(); - if (!jenv) + if (!jenv) { return SA_ERROR_NO_DEVICE; + } if ((*jenv)->PushLocalFrame(jenv, 4)) { return SA_ERROR_OOM; @@ -211,6 +218,21 @@ sa_stream_open(sa_stream_t *s) { int32_t chanConfig = s->channels == 1 ? CHANNEL_OUT_MONO : CHANNEL_OUT_STEREO; + jint minsz = (*jenv)->CallStaticIntMethod(jenv, s->at_class, at.getminbufsz, + s->rate, chanConfig, ENCODING_PCM_16BIT); + if (minsz <= 0) { + (*jenv)->DeleteGlobalRef(jenv, s->at_class); + (*jenv)->PopLocalFrame(jenv, NULL); + return SA_ERROR_INVALID; + } + + s->minBufferSize = minsz; + + s->bufferSize = s->rate * s->channels * sizeof(int16_t); + if (s->bufferSize < s->minBufferSize) { + s->bufferSize = s->minBufferSize; + } + jobject obj = (*jenv)->NewObject(jenv, s->at_class, at.constructor, STREAM_MUSIC, @@ -238,7 +260,7 @@ sa_stream_open(sa_stream_t *s) { s->output_unit = (*jenv)->NewGlobalRef(jenv, obj); (*jenv)->PopLocalFrame(jenv, NULL); - ALOG("%x - New stream %d %d", s, s->rate, s->channels); + ALOG("%p - New stream %u %u bsz=%u min=%u", s, s->rate, s->channels, s->bufferSize, s->minBufferSize); return SA_SUCCESS; } @@ -251,14 +273,18 @@ sa_stream_destroy(sa_stream_t *s) { } JNIEnv *jenv = GetJNIForThread(); - if (!jenv) + if (!jenv) { return SA_SUCCESS; + } + (*jenv)->CallVoidMethod(jenv, s->output_unit, at.stop); + (*jenv)->CallVoidMethod(jenv, s->output_unit, at.flush); + (*jenv)->CallVoidMethod(jenv, s->output_unit, at.release); (*jenv)->DeleteGlobalRef(jenv, s->output_unit); (*jenv)->DeleteGlobalRef(jenv, s->at_class); free(s); - ALOG("%x - Stream destroyed", s); + ALOG("%p - Stream destroyed", s); return SA_SUCCESS; } @@ -290,16 +316,11 @@ sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) { return SA_ERROR_OOM; } - jbyte *byte = (*jenv)->GetByteArrayElements(jenv, bytearray, NULL); - if (!byte) { - (*jenv)->PopLocalFrame(jenv, NULL); - return SA_ERROR_OOM; - } - - memcpy(byte, data, nbytes); + (*jenv)->SetByteArrayRegion(jenv, bytearray, 0, nbytes, data); size_t wroteSoFar = 0; jint retval; + int first = 1; do { retval = (*jenv)->CallIntMethod(jenv, @@ -309,27 +330,27 @@ sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) { wroteSoFar, nbytes - wroteSoFar); if (retval < 0) { - ALOG("%x - Write failed %d", s, retval); + ALOG("%p - Write failed %d", s, retval); break; } wroteSoFar += retval; + /* android doesn't start playing until we explictly call play. */ + if (first && !s->isPaused) { + sa_stream_resume(s); + first = 0; + } + if (wroteSoFar != nbytes) { - - /* android doesn't start playing until we explictly call play. */ - if (!s->isPaused) - sa_stream_resume(s); - struct timespec ts = {0, 100000000}; /* .10s */ nanosleep(&ts, NULL); } } while(wroteSoFar < nbytes); + ALOG("%p - Wrote %u", s, nbytes); s->amountWritten += nbytes; - (*jenv)->ReleaseByteArrayElements(jenv, bytearray, byte, 0); - (*jenv)->PopLocalFrame(jenv, NULL); return retval < 0 ? SA_ERROR_INVALID : SA_SUCCESS; @@ -352,9 +373,9 @@ sa_stream_get_write_size(sa_stream_t *s, size_t *size) { /* No android API for this, so estimate based on how much we have played and * how much we have written. */ - *size = s->bufferSize - ((s->timePlaying * s->channels * s->rate / - MILLISECONDS_PER_SECOND) - s->amountWritten); - ALOG("%x - Write Size %d", s, *size); + *size = s->bufferSize - ((s->timePlaying * s->channels * s->rate * sizeof(int16_t) / + MILLISECONDS_PER_SECOND) - s->amountWritten); + ALOG("%p - Write Size tp=%lld aw=%u sz=%zu", s, s->timePlaying, s->amountWritten, *size); return SA_SUCCESS; } @@ -367,7 +388,7 @@ sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) { return SA_ERROR_NO_INIT; } - ALOG("%x - get position", s); + ALOG("%p - get position", s); JNIEnv *jenv = GetJNIForThread(); *pos = (*jenv)->CallIntMethod(jenv, s->output_unit, at.getpos); @@ -398,7 +419,7 @@ sa_stream_pause(sa_stream_t *s) { int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000; s->timePlaying += ticker - s->lastStartTime; } - ALOG("%x - Pause total time playing: %lld total written: %lld", s, s->timePlaying, s->amountWritten); + ALOG("%p - Pause total time playing: %lld total written: %lld", s, s->timePlaying, s->amountWritten); (*jenv)->CallVoidMethod(jenv, s->output_unit, at.pause); return SA_SUCCESS; @@ -412,7 +433,7 @@ sa_stream_resume(sa_stream_t *s) { return SA_ERROR_NO_INIT; } - ALOG("%x - resume", s); + ALOG("%p - resume", s); JNIEnv *jenv = GetJNIForThread(); s->isPaused = 0; @@ -435,15 +456,25 @@ sa_stream_drain(sa_stream_t *s) return SA_ERROR_NO_INIT; } - /* There is no way with the Android SDK to determine exactly how - long to playback. So estimate and sleep for the long. - */ - +/* This is somewhat of a hack (see bug 693131). The AudioTrack documentation + doesn't make it clear how much data must be written before a chunk of data is + played, and experimentation with short streams required filling the entire + allocated buffer. To guarantee that short streams (and the end of longer + streams) are audible, fill the remaining space in the AudioTrack with silence + before sleeping. Note that the sleep duration is calculated from the + duration of audio written before filling the buffer with silence. */ size_t available; sa_stream_get_write_size(s, &available); - long x = (s->bufferSize - available) * 1000 / s->channels / s->rate / sizeof(int16_t) * NANOSECONDS_IN_MILLISECOND; - ALOG("%x - Drain - sleep for %f ns", s, x); + void *p = calloc(1, available); + sa_stream_write(s, p, available); + free(p); + + /* There is no way with the Android SDK to determine exactly how + long to playback. So estimate and sleep for the long. */ + long x = (s->bufferSize - available) * 1000 / s->channels / s->rate / + sizeof(int16_t) * NANOSECONDS_IN_MILLISECOND; + ALOG("%p - Drain - flush %u, sleep for %ld ns", s, available, x); struct timespec ts = {0, x}; nanosleep(&ts, NULL); diff --git a/memory/jemalloc/jemalloc.c b/memory/jemalloc/jemalloc.c index 4783b7dc01c5..867226e67072 100644 --- a/memory/jemalloc/jemalloc.c +++ b/memory/jemalloc/jemalloc.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 8; c-basic-offset: 8; indent-tabs-mode: t -*- */ -/* vim:set softtabstop=8 shiftwidth=8: */ +/* vim:set softtabstop=8 shiftwidth=8 noet: */ /*- * Copyright (C) 2006-2008 Jason Evans . * All rights reserved. @@ -105,6 +105,29 @@ #define _pthread_self() pthread_self() #endif +/* + * On Linux, we use madvise(MADV_DONTNEED) to release memory back to the + * operating system. If we release 1MB of live pages with MADV_DONTNEED, our + * RSS will decrease by 1MB (almost) immediately. + * + * On Mac, we use madvise(MADV_FREE). Unlike MADV_DONTNEED on Linux, MADV_FREE + * on Mac doesn't cause the OS to release the specified pages immediately; the + * OS keeps them in our process until the machine comes under memory pressure. + * + * It's therefore difficult to measure the process's RSS on Mac, since, in the + * absence of memory pressure, the contribution from the heap to RSS will not + * decrease due to our madvise calls. + * + * We therefore define MALLOC_DOUBLE_PURGE on Mac. This causes jemalloc to + * track which pages have been MADV_FREE'd. You can then call + * jemalloc_purge_freed_pages(), which will force the OS to release those + * MADV_FREE'd pages, making the process's RSS reflect its true memory usage. + * + */ +#ifdef MOZ_MEMORY_DARWIN +#define MALLOC_DOUBLE_PURGE +#endif + /* * MALLOC_PRODUCTION disables assertions and statistics gathering. It also * defaults the A and J runtime options to off. These settings are appropriate @@ -354,6 +377,7 @@ __FBSDID("$FreeBSD: head/lib/libc/stdlib/malloc.c 180599 2008-07-18 19:35:44Z ja #endif #include "jemalloc.h" +#include "linkedlist.h" /* Some tools, such as /dev/dsp wrappers, LD_PRELOAD libraries that * happen to override mmap() and call dlsym() from their overridden @@ -605,6 +629,11 @@ static const bool __isthreaded = true; /******************************************************************************/ +/* MALLOC_DECOMMIT and MALLOC_DOUBLE_PURGE are mutually exclusive. */ +#if defined(MALLOC_DECOMMIT) && defined(MALLOC_DOUBLE_PURGE) +#error MALLOC_DECOMMIT and MALLOC_DOUBLE_PURGE are mutually exclusive. +#endif + /* * Mutexes based on spinlocks. We can't use normal pthread spinlocks in all * places, because they require malloc()ed memory, which causes bootstrapping @@ -807,13 +836,14 @@ struct arena_chunk_map_s { * Run address (or size) and various flags are stored together. The bit * layout looks like (assuming 32-bit system): * - * ???????? ???????? ????---- --ckdzla + * ???????? ???????? ????---- -mckdzla * * ? : Unallocated: Run address for first/last pages, unset for internal * pages. * Small: Run address. * Large: Run size for first page, unset for trailing pages. * - : Unused. + * m : MADV_FREE/MADV_DONTNEED'ed? * c : decommitted? * k : key? * d : dirty? @@ -845,8 +875,27 @@ struct arena_chunk_map_s { * -------- -------- -------- ------la */ size_t bits; -#if defined(MALLOC_DECOMMIT) || defined(MALLOC_STATS) + +/* Note that CHUNK_MAP_DECOMMITTED's meaning varies depending on whether + * MALLOC_DECOMMIT and MALLOC_DOUBLE_PURGE are defined. + * + * If MALLOC_DECOMMIT is defined, a page which is CHUNK_MAP_DECOMMITTED must be + * re-committed with pages_commit() before it may be touched. If + * MALLOC_DECOMMIT is defined, MALLOC_DOUBLE_PURGE may not be defined. + * + * If neither MALLOC_DECOMMIT nor MALLOC_DOUBLE_PURGE is defined, pages which + * are madvised (with either MADV_DONTNEED or MADV_FREE) are marked with + * CHUNK_MAP_MADVISED. + * + * Otherwise, if MALLOC_DECOMMIT is not defined and MALLOC_DOUBLE_PURGE is + * defined, then a page which is madvised is marked as CHUNK_MAP_MADVISED. + * When it's finally freed with jemalloc_purge_freed_pages, the page is marked + * as CHUNK_MAP_DECOMMITTED. + */ +#if defined(MALLOC_DECOMMIT) || defined(MALLOC_STATS) || defined(MALLOC_DOUBLE_PURGE) +#define CHUNK_MAP_MADVISED ((size_t)0x40U) #define CHUNK_MAP_DECOMMITTED ((size_t)0x20U) +#define CHUNK_MAP_MADVISED_OR_DECOMMITTED (CHUNK_MAP_MADVISED | CHUNK_MAP_DECOMMITTED) #endif #define CHUNK_MAP_KEY ((size_t)0x10U) #define CHUNK_MAP_DIRTY ((size_t)0x08U) @@ -866,6 +915,16 @@ struct arena_chunk_s { /* Linkage for the arena's chunks_dirty tree. */ rb_node(arena_chunk_t) link_dirty; +#ifdef MALLOC_DOUBLE_PURGE + /* If we're double-purging, we maintain a linked list of chunks which + * have pages which have been madvise(MADV_FREE)'d but not explicitly + * purged. + * + * We're currently lazy and don't remove a chunk from this list when + * all its madvised pages are recommitted. */ + LinkedList chunks_madvised_elem; +#endif + /* Number of dirty pages. */ size_t ndirty; @@ -951,6 +1010,12 @@ struct arena_s { /* Tree of dirty-page-containing chunks this arena manages. */ arena_chunk_tree_t chunks_dirty; +#ifdef MALLOC_DOUBLE_PURGE + /* Head of a linked list of MADV_FREE'd-page-containing chunks this + * arena manages. */ + LinkedList chunks_madvised; +#endif + /* * In order to avoid rapid chunk allocation/deallocation when an arena * oscillates right on the cusp of needing a new chunk, cache the most @@ -1808,7 +1873,6 @@ malloc_printf(const char *format, ...) /******************************************************************************/ -#ifdef MALLOC_DECOMMIT static inline void pages_decommit(void *addr, size_t size) { @@ -1834,7 +1898,6 @@ pages_commit(void *addr, size_t size) abort(); # endif } -#endif static bool base_pages_alloc_mmap(size_t minsize) @@ -3069,25 +3132,29 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, } for (i = 0; i < need_pages; i++) { -#if defined(MALLOC_DECOMMIT) || defined(MALLOC_STATS) +#if defined(MALLOC_DECOMMIT) || defined(MALLOC_STATS) || defined(MALLOC_DOUBLE_PURGE) /* * Commit decommitted pages if necessary. If a decommitted * page is encountered, commit all needed adjacent decommitted * pages in one operation, in order to reduce system call * overhead. */ - if (chunk->map[run_ind + i].bits & CHUNK_MAP_DECOMMITTED) { + if (chunk->map[run_ind + i].bits & CHUNK_MAP_MADVISED_OR_DECOMMITTED) { size_t j; /* * Advance i+j to just past the index of the last page - * to commit. Clear CHUNK_MAP_DECOMMITTED along the - * way. + * to commit. Clear CHUNK_MAP_DECOMMITTED and + * CHUNK_MAP_MADVISED along the way. */ for (j = 0; i + j < need_pages && (chunk->map[run_ind + - i + j].bits & CHUNK_MAP_DECOMMITTED); j++) { - chunk->map[run_ind + i + j].bits ^= - CHUNK_MAP_DECOMMITTED; + i + j].bits & CHUNK_MAP_MADVISED_OR_DECOMMITTED); j++) { + /* DECOMMITTED and MADVISED are mutually exclusive. */ + assert(!(chunk->map[run_ind + i + j].bits & CHUNK_MAP_DECOMMITTED && + chunk->map[run_ind + i + j].bits & CHUNK_MAP_MADVISED)); + + chunk->map[run_ind + i + j].bits &= + ~CHUNK_MAP_MADVISED_OR_DECOMMITTED; } # ifdef MALLOC_DECOMMIT @@ -3204,6 +3271,10 @@ arena_chunk_init(arena_t *arena, arena_chunk_t *chunk) /* Insert the run into the runs_avail tree. */ arena_avail_tree_insert(&arena->runs_avail, &chunk->map[arena_chunk_header_npages]); + +#ifdef MALLOC_DOUBLE_PURGE + LinkedList_Init(&chunk->chunks_madvised_elem); +#endif } static void @@ -3219,6 +3290,12 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) arena->stats.committed -= arena->spare->ndirty; #endif } + +#ifdef MALLOC_DOUBLE_PURGE + /* This is safe to do even if arena->spare is not in the list. */ + LinkedList_Remove(&arena->spare->chunks_madvised_elem); +#endif + VALGRIND_FREELIKE_BLOCK(arena->spare, 0); chunk_dealloc((void *)arena->spare, chunksize); #ifdef MALLOC_STATS @@ -3322,6 +3399,9 @@ arena_purge(arena_t *arena) * purged. */ while (arena->ndirty > (opt_dirty_max >> 1)) { +#ifdef MALLOC_DOUBLE_PURGE + bool madvised = false; +#endif chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty); assert(chunk != NULL); @@ -3329,17 +3409,23 @@ arena_purge(arena_t *arena) assert(i >= arena_chunk_header_npages); if (chunk->map[i].bits & CHUNK_MAP_DIRTY) { +#ifdef MALLOC_DECOMMIT + const size_t free_operation = CHUNK_MAP_DECOMMITTED; +#else + const size_t free_operation = CHUNK_MAP_MADVISED; +#endif assert((chunk->map[i].bits & - CHUNK_MAP_DECOMMITTED) == 0); - chunk->map[i].bits ^= CHUNK_MAP_DECOMMITTED | CHUNK_MAP_DIRTY; + CHUNK_MAP_MADVISED_OR_DECOMMITTED) == 0); + chunk->map[i].bits ^= free_operation | CHUNK_MAP_DIRTY; /* Find adjacent dirty run(s). */ - for (npages = 1; i > arena_chunk_header_npages - && (chunk->map[i - 1].bits & - CHUNK_MAP_DIRTY); npages++) { + for (npages = 1; + i > arena_chunk_header_npages && + (chunk->map[i - 1].bits & CHUNK_MAP_DIRTY); + npages++) { i--; assert((chunk->map[i].bits & - CHUNK_MAP_DECOMMITTED) == 0); - chunk->map[i].bits ^= CHUNK_MAP_DECOMMITTED | CHUNK_MAP_DIRTY; + CHUNK_MAP_MADVISED_OR_DECOMMITTED) == 0); + chunk->map[i].bits ^= free_operation | CHUNK_MAP_DIRTY; } chunk->ndirty -= npages; arena->ndirty -= npages; @@ -3361,6 +3447,9 @@ arena_purge(arena_t *arena) madvise((void *)((uintptr_t)chunk + (i << pagesize_2pow)), (npages << pagesize_2pow), MADV_FREE); +# ifdef MALLOC_DOUBLE_PURGE + madvised = true; +# endif #endif #ifdef MALLOC_STATS arena->stats.nmadvise++; @@ -3375,6 +3464,14 @@ arena_purge(arena_t *arena) arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk); } +#ifdef MALLOC_DOUBLE_PURGE + if (madvised) { + /* The chunk might already be in the list, but this + * makes sure it's at the front. */ + LinkedList_Remove(&chunk->chunks_madvised_elem); + LinkedList_InsertHead(&arena->chunks_madvised, &chunk->chunks_madvised_elem); + } +#endif } } @@ -4562,6 +4659,9 @@ arena_new(arena_t *arena) /* Initialize chunks. */ arena_chunk_tree_dirty_new(&arena->chunks_dirty); +#ifdef MALLOC_DOUBLE_PURGE + LinkedList_Init(&arena->chunks_madvised); +#endif arena->spare = NULL; arena->ndirty = 0; @@ -6381,6 +6481,78 @@ jemalloc_stats(jemalloc_stats_t *stats) assert(stats->committed >= stats->allocated); } +#ifdef MALLOC_DOUBLE_PURGE + +/* Explicitly remove all of this chunk's MADV_FREE'd pages from memory. */ +static void +hard_purge_chunk(arena_chunk_t *chunk) +{ + /* See similar logic in arena_purge(). */ + + size_t i; + for (i = arena_chunk_header_npages; i < chunk_npages; i++) { + /* Find all adjacent pages with CHUNK_MAP_MADVISED set. */ + size_t npages; + for (npages = 0; + chunk->map[i + npages].bits & CHUNK_MAP_MADVISED && i + npages < chunk_npages; + npages++) { + /* Turn off the chunk's MADV_FREED bit and turn on its + * DECOMMITTED bit. */ + assert(!(chunk->map[i + npages].bits & CHUNK_MAP_DECOMMITTED)); + chunk->map[i + npages].bits ^= CHUNK_MAP_MADVISED_OR_DECOMMITTED; + } + + /* We could use mincore to find out which pages are actually + * present, but it's not clear that's better. */ + if (npages > 0) { + pages_decommit(((char*)chunk) + (i << pagesize_2pow), npages << pagesize_2pow); + pages_commit(((char*)chunk) + (i << pagesize_2pow), npages << pagesize_2pow); + } + i += npages; + } +} + +/* Explicitly remove all of this arena's MADV_FREE'd pages from memory. */ +static void +hard_purge_arena(arena_t *arena) +{ + malloc_spin_lock(&arena->lock); + + while (!LinkedList_IsEmpty(&arena->chunks_madvised)) { + LinkedList* next = arena->chunks_madvised.next; + arena_chunk_t *chunk = + LinkedList_Get(arena->chunks_madvised.next, + arena_chunk_t, chunks_madvised_elem); + hard_purge_chunk(chunk); + LinkedList_Remove(&chunk->chunks_madvised_elem); + } + + malloc_spin_unlock(&arena->lock); +} + +void +jemalloc_purge_freed_pages() +{ + size_t i; + for (i = 0; i < narenas; i++) { + arena_t *arena = arenas[i]; + if (arena != NULL) + hard_purge_arena(arena); + } +} + +#else /* !defined MALLOC_DOUBLE_PURGE */ + +void +jemalloc_purge_freed_pages() +{ + /* Do nothing. */ +} + +#endif /* defined MALLOC_DOUBLE_PURGE */ + + + #ifdef MOZ_MEMORY_WINDOWS void* _recalloc(void *ptr, size_t count, size_t size) diff --git a/memory/jemalloc/jemalloc.h b/memory/jemalloc/jemalloc.h index 655d78b16f44..19817f59460e 100644 --- a/memory/jemalloc/jemalloc.h +++ b/memory/jemalloc/jemalloc.h @@ -80,6 +80,33 @@ size_t malloc_usable_size(const void *ptr); void jemalloc_stats(jemalloc_stats_t *stats); +/* + * On some operating systems (Mac), we use madvise(MADV_FREE) to hand pages + * back to the operating system. On Mac, the operating system doesn't take + * this memory back immediately; instead, the OS takes it back only when the + * machine is running out of physical memory. + * + * This is great from the standpoint of efficiency, but it makes measuring our + * actual RSS difficult, because pages which we've MADV_FREE'd shouldn't count + * against our RSS. + * + * This function explicitly purges any MADV_FREE'd pages from physical memory, + * causing our reported RSS match the amount of memory we're actually using. + * + * Note that this call is expensive in two ways. First, it may be slow to + * execute, because it may make a number of slow syscalls to free memory. This + * function holds the big jemalloc locks, so basically all threads are blocked + * while this function runs. + * + * This function is also expensive in that the next time we go to access a page + * which we've just explicitly decommitted, the operating system has to attach + * to it a physical page! If we hadn't run this function, the OS would have + * less work to do. + * + * If MALLOC_DOUBLE_PURGE is not defined, this function does nothing. + */ +void jemalloc_purge_freed_pages(); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/memory/jemalloc/linkedlist.h b/memory/jemalloc/linkedlist.h new file mode 100644 index 000000000000..d75531410512 --- /dev/null +++ b/memory/jemalloc/linkedlist.h @@ -0,0 +1,77 @@ +/* -*- Mode: C; tab-width: 8; c-basic-offset: 8; indent-tabs-mode: t -*- */ +/* vim:set softtabstop=8 shiftwidth=8 noet: */ +/*- + * Copyright (C) the Mozilla Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#ifndef linkedlist_h__ +#define linkedlist_h__ + +#include + +typedef struct LinkedList_s LinkedList; + +struct LinkedList_s { + LinkedList *next; + LinkedList *prev; +}; + +/* Convert from LinkedList* to foo*. */ +#define LinkedList_Get(e, type, prop) \ + (type*)((char*)(e) - offsetof(type, prop)) + +/* Insert |e| at the beginning of |l|. */ +void LinkedList_InsertHead(LinkedList *l, LinkedList *e) +{ + e->next = l; + e->prev = l->prev; + e->next->prev = e; + e->prev->next = e; +} + +void LinkedList_Remove(LinkedList *e) +{ + e->prev->next = e->next; + e->next->prev = e->prev; + e->next = e; + e->prev = e; +} + +bool LinkedList_IsEmpty(LinkedList *e) +{ + return e->next == e; +} + +void LinkedList_Init(LinkedList *e) +{ + e->next = e; + e->prev = e; +} + +#endif diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h index b59b25db17cd..8a9d857b35f1 100644 --- a/memory/mozalloc/mozalloc.h +++ b/memory/mozalloc/mozalloc.h @@ -214,15 +214,13 @@ MOZALLOC_EXPORT void* moz_valloc(size_t size) * to suppress build warning spam (bug 578546). */ #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS /**/ +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS #else #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc) #endif -#ifdef MOZ_CPP_EXCEPTIONS -#define MOZALLOC_THROW_BAD_ALLOC throw(std::bad_alloc) -#else -#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_IF_HAS_EXCEPTIONS -#endif +#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS MOZALLOC_EXPORT_NEW MOZALLOC_INLINE void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC diff --git a/mobile/app/mobile.js b/mobile/app/mobile.js index 8f377b1c38f9..07f29aaf6911 100644 --- a/mobile/app/mobile.js +++ b/mobile/app/mobile.js @@ -140,7 +140,6 @@ pref("browser.display.remotetabs.timeout", 10); /* session history */ pref("browser.sessionhistory.max_total_viewers", 1); pref("browser.sessionhistory.max_entries", 50); -pref("browser.sessionhistory.optimize_eviction", true); /* session store */ pref("browser.sessionstore.resume_session_once", false); @@ -376,9 +375,7 @@ pref("privacy.item.geolocation", true); pref("privacy.item.siteSettings", true); pref("privacy.item.syncAccount", true); -#ifdef MOZ_PLATFORM_MAEMO pref("plugins.force.wmode", "opaque"); -#endif // URL to the Learn More link XXX this is the firefox one. Bug 495578 fixes this. pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/"); diff --git a/mobile/chrome/content/bindings/browser.js b/mobile/chrome/content/bindings/browser.js index a64e91883de1..aa4f52529c8a 100644 --- a/mobile/chrome/content/bindings/browser.js +++ b/mobile/chrome/content/bindings/browser.js @@ -268,8 +268,13 @@ let WebNavigation = { if (aEntry.docshellID) shEntry.docshellID = aEntry.docshellID; - if (aEntry.stateData) - shEntry.stateData = aEntry.stateData; + if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) { + shEntry.stateData = + Cc["@mozilla.org/docshell/structured-clone-container;1"]. + createInstance(Ci.nsIStructuredCloneContainer); + + shEntry.stateData.initFromBase64(aEntry.structuredCloneState, aEntry.structuredCloneVersion); + } if (aEntry.scroll) { let scrollPos = aEntry.scroll.split(","); @@ -278,23 +283,15 @@ let WebNavigation = { } if (aEntry.docIdentifier) { - // Get a new document identifier for this entry to ensure that history - // entries after a session restore are considered to have different - // documents from the history entries before the session restore. - // Document identifiers are 64-bit ints, so JS will loose precision and - // start assigning all entries the same doc identifier if these ever get - // large enough. - // - // It's a potential security issue if document identifiers aren't - // globally unique, but shEntry.setUniqueDocIdentifier() below guarantees - // that we won't re-use a doc identifier within a given instance of the - // application. - let ident = aDocIdentMap[aEntry.docIdentifier]; - if (!ident) { - shEntry.setUniqueDocIdentifier(); - aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier; + // If we have a serialized document identifier, try to find an SHEntry + // which matches that doc identifier and adopt that SHEntry's + // BFCacheEntry. If we don't find a match, insert shEntry as the match + // for the document identifier. + let matchingEntry = aDocIdentMap[aEntry.docIdentifier]; + if (!matchingEntry) { + aDocIdentMap[aEntry.docIdentifier] = shEntry; } else { - shEntry.docIdentifier = ident; + shEntry.adoptBFCacheEntry(matchingEntry); } } @@ -379,11 +376,12 @@ let WebNavigation = { } catch (e) { dump(e); } } - if (aEntry.docIdentifier) - entry.docIdentifier = aEntry.docIdentifier; + entry.docIdentifier = aEntry.BFCacheEntry.ID; - if (aEntry.stateData) - entry.stateData = aEntry.stateData; + if (aEntry.stateData != null) { + entry.structuredCloneState = aEntry.stateData.getDataAsBase64(); + entry.structuredCloneVersion = aEntry.stateData.formatVersion; + } if (!(aEntry instanceof Ci.nsISHContainer)) return entry; diff --git a/mobile/chrome/content/browser.js b/mobile/chrome/content/browser.js index b4958b17bc7f..396727d68e19 100644 --- a/mobile/chrome/content/browser.js +++ b/mobile/chrome/content/browser.js @@ -69,7 +69,8 @@ window.sizeToContent = function() { Cu.reportError("window.sizeToContent is not allowed in this window"); } -#ifdef MOZ_CRASH_REPORTER +#ifdef MOZ_CRASHREPORTER +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif @@ -245,8 +246,9 @@ var Browser = { let { x: x2, y: y2 } = Browser.getScrollboxPosition(Browser.pageScrollboxScroller); let [,, leftWidth, rightWidth] = Browser.computeSidebarVisibility(); - let shouldHideSidebars = Browser.controlsPosition ? Browser.controlsPosition.hideSidebars : true; - Browser.controlsPosition = { x: x1, y: y2, hideSidebars: shouldHideSidebars, + // hiddenSidebars counts how many times resizeHandler has called hideSidebars + let hiddenSidebars = Browser.controlsPosition ? Browser.controlsPosition.hiddenSidebars : 0; + Browser.controlsPosition = { x: x1, y: y2, hiddenSidebars: hiddenSidebars, leftSidebar: leftWidth, rightSidebar: rightWidth }; }, true); @@ -276,8 +278,12 @@ var Browser = { ViewableAreaObserver.update(); // Restore the previous scroll position - let restorePosition = Browser.controlsPosition || { hideSidebars: true }; - if (restorePosition.hideSidebars) { + let restorePosition = Browser.controlsPosition || { hiddenSidebars: 0 }; + + // HACK: The first time we hide the sidebars during startup might be too + // early, before layout is completed. Make sure to hide the sidebars on + // the first *two* resize events (bug 691541). + if (restorePosition.hiddenSidebars < 2) { // Since this happens early in the startup process, we need to make sure // the UI has really responded let x = {}, y = {}; @@ -285,7 +291,7 @@ var Browser = { Browser.controlsScrollboxScroller.getPosition(x, y); if (x.value > 0) { // Update the control position data so we are set correctly for the next resize - restorePosition.hideSidebars = false; + restorePosition.hiddenSidebars++; restorePosition.x = x.value; } } else { @@ -1613,7 +1619,7 @@ Browser.WebProgress.prototype = { tab.browser.userTypedValue = ""; tab.browser.appIcon = { href: null, size:-1 }; -#ifdef MOZ_CRASH_REPORTER +#ifdef MOZ_CRASHREPORTER if (CrashReporter.enabled) CrashReporter.annotateCrashReport("URL", spec); #endif diff --git a/mobile/components/SessionStore.js b/mobile/components/SessionStore.js index a2627805a4a4..0d9c74386667 100644 --- a/mobile/components/SessionStore.js +++ b/mobile/components/SessionStore.js @@ -42,7 +42,7 @@ const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -#ifdef MOZ_CRASH_REPORTER +#ifdef MOZ_CRASHREPORTER XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif @@ -578,7 +578,7 @@ SessionStore.prototype = { }, _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) { -#ifdef MOZ_CRASH_REPORTER +#ifdef MOZ_CRASHREPORTER try { let currentURI = aWindow.Browser.selectedBrowser.currentURI.clone(); // if the current URI contains a username/password, remove it diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 68d362ca73da..3c39efd6b5a2 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -234,6 +234,11 @@ nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry, return NS_OK; } +PRInt64 nsZipHandle::SizeOfMapping() +{ + return mLen; +} + nsZipHandle::~nsZipHandle() { if (mMap) { @@ -775,6 +780,14 @@ MOZ_WIN_MEM_TRY_BEGIN MOZ_WIN_MEM_TRY_CATCH(return nsnull) } +//--------------------------------------------- +// nsZipArchive::SizeOfMapping +//--------------------------------------------- +PRInt64 nsZipArchive::SizeOfMapping() +{ + return mFd ? mFd->SizeOfMapping() : 0; +} + //------------------------------------------ // nsZipArchive constructor and destructor //------------------------------------------ diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 871811a0dedd..6c273dc22b5d 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -221,6 +221,12 @@ public: */ const PRUint8* GetData(nsZipItem* aItem); + /** + * Gets the amount of memory taken up by the archive's mapping. + * @return the size + */ + PRInt64 SizeOfMapping(); + private: //--- private members --- @@ -382,6 +388,8 @@ public: NS_METHOD_(nsrefcnt) AddRef(void); NS_METHOD_(nsrefcnt) Release(void); + PRInt64 SizeOfMapping(); + protected: const PRUint8 * mFileData; /* pointer to mmaped file */ PRUint32 mLen; /* length of file and memory mapped area */ diff --git a/modules/libjar/zipwriter/src/nsZipWriter.cpp b/modules/libjar/zipwriter/src/nsZipWriter.cpp index fb80e9e382cb..08d328e07189 100644 --- a/modules/libjar/zipwriter/src/nsZipWriter.cpp +++ b/modules/libjar/zipwriter/src/nsZipWriter.cpp @@ -912,7 +912,7 @@ inline nsresult nsZipWriter::BeginProcessingAddition(nsZipQueueItem* aItem, PRUint32 zipAttributes = ZIP_ATTRS(aItem->mPermissions, ZIP_ATTRS_FILE); - if (aItem->mStream) { + if (aItem->mStream || aItem->mChannel) { nsRefPtr header = new nsZipHeader(); NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); @@ -922,33 +922,23 @@ inline nsresult nsZipWriter::BeginProcessingAddition(nsZipQueueItem* aItem, NS_ENSURE_SUCCESS(rv, rv); nsRefPtr stream = new nsZipDataStream(); + NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY); rv = stream->Init(this, mStream, header, aItem->mCompression); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr pump; - rv = NS_NewInputStreamPump(getter_AddRefs(pump), aItem->mStream, -1, - -1, 0, 0, true); - NS_ENSURE_SUCCESS(rv, rv); + if (aItem->mStream) { + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), aItem->mStream, + -1, -1, 0, 0, true); + NS_ENSURE_SUCCESS(rv, rv); - rv = pump->AsyncRead(stream, nsnull); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; - } - - if (aItem->mChannel) { - nsRefPtr header = new nsZipHeader(); - NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); - - header->Init(aItem->mZipEntry, aItem->mModTime, zipAttributes, - mCDSOffset); - - nsRefPtr stream = new nsZipDataStream(); - NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = stream->Init(this, mStream, header, aItem->mCompression); - NS_ENSURE_SUCCESS(rv, rv); - rv = aItem->mChannel->AsyncOpen(stream, nsnull); - NS_ENSURE_SUCCESS(rv, rv); + rv = pump->AsyncRead(stream, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + rv = aItem->mChannel->AsyncOpen(stream, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + } return NS_OK; } diff --git a/modules/libjar/zipwriter/test/unit/head_zipwriter.js b/modules/libjar/zipwriter/test/unit/head_zipwriter.js index 838c6ca9a4a1..6790754a88f5 100644 --- a/modules/libjar/zipwriter/test/unit/head_zipwriter.js +++ b/modules/libjar/zipwriter/test/unit/head_zipwriter.js @@ -63,6 +63,9 @@ const PR_MSEC_PER_SEC = 1000; const DATA_DIR = "data/"; +var ioSvc = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", "nsIZipWriter"); var ZipReader = Components.Constructor("@mozilla.org/libjar/zip-reader;1", diff --git a/modules/libjar/zipwriter/test/unit/test_asyncadd.js b/modules/libjar/zipwriter/test/unit/test_asyncadd.js index 40e850c922f1..fa5944c4d18f 100644 --- a/modules/libjar/zipwriter/test/unit/test_asyncadd.js +++ b/modules/libjar/zipwriter/test/unit/test_asyncadd.js @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Kris Maglione * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -70,17 +71,20 @@ var observer = { var zipR = new ZipReader(tmpFile); for (var i = 0; i < TESTS.length; i++) { - do_check_true(zipR.hasEntry(TESTS[i].name)); - var source = do_get_file(DATA_DIR + TESTS[i].name); - var entry = zipR.getEntry(TESTS[i].name); - do_check_eq(entry.realSize, TESTS[i].size); - do_check_eq(entry.size, TESTS[i].size); - do_check_eq(entry.CRC32, TESTS[i].crc); - do_check_eq(Math.floor(entry.lastModifiedTime / PR_USEC_PER_SEC), - Math.floor(source.lastModifiedTime / PR_MSEC_PER_SEC)); + for (let method in methods) { + var entryName = method + "/" + TESTS[i].name; + do_check_true(zipR.hasEntry(entryName)); - zipR.test(TESTS[i].name); + var entry = zipR.getEntry(entryName); + do_check_eq(entry.realSize, TESTS[i].size); + do_check_eq(entry.size, TESTS[i].size); + do_check_eq(entry.CRC32, TESTS[i].crc); + do_check_eq(Math.floor(entry.lastModifiedTime / PR_USEC_PER_SEC), + Math.floor(source.lastModifiedTime / PR_MSEC_PER_SEC)); + + zipR.test(entryName); + } } zipR.close(); @@ -88,17 +92,39 @@ var observer = { } }; +var methods = { + file: function method_file(entry, source) + { + zipW.addEntryFile(entry, Ci.nsIZipWriter.COMPRESSION_NONE, source, + true); + }, + channel: function method_channel(entry, source) + { + zipW.addEntryChannel(entry, source.lastModifiedTime * PR_MSEC_PER_SEC, + Ci.nsIZipWriter.COMPRESSION_NONE, + ioSvc.newChannelFromURI(ioSvc.newFileURI(source)), true); + }, + stream: function method_stream(entry, source) + { + zipW.addEntryStream(entry, source.lastModifiedTime * PR_MSEC_PER_SEC, + Ci.nsIZipWriter.COMPRESSION_NONE, + ioSvc.newChannelFromURI(ioSvc.newFileURI(source)).open(), true); + } +} + function run_test() { zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); for (var i = 0; i < TESTS.length; i++) { var source = do_get_file(DATA_DIR+TESTS[i].name); - zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, - true); - size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + - (ZIP_EXTENDED_TIMESTAMP_SIZE * 2) + - (TESTS[i].name.length*2) + TESTS[i].size; + for (let method in methods) { + var entry = method + "/" + TESTS[i].name; + methods[method](entry, source); + size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (ZIP_EXTENDED_TIMESTAMP_SIZE * 2) + + (entry.length*2) + TESTS[i].size; + } } do_test_pending(); zipW.processQueue(observer, null); diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 728fd7c83842..6f73ab32c20a 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -109,8 +109,6 @@ pref("dom.enable_performance", true); // of content viewers to cache based on the amount of available memory. pref("browser.sessionhistory.max_total_viewers", -1); -pref("browser.sessionhistory.optimize_eviction", true); - pref("ui.use_native_colors", true); pref("ui.click_hold_context_menus", false); pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always @@ -3291,6 +3289,7 @@ pref("webgl.verbose", false); pref("webgl.prefer-native-gl", false); pref("webgl.min_capability_mode", false); pref("webgl.disable-extensions", false); +pref("webgl.msaa-level", 2); #ifdef XP_WIN // The default TCP send window on Windows is too small, and autotuning only occurs on receive diff --git a/netwerk/base/src/nsSocketTransportService2.cpp b/netwerk/base/src/nsSocketTransportService2.cpp index 3bf0affb1edb..1f1f516f6573 100644 --- a/netwerk/base/src/nsSocketTransportService2.cpp +++ b/netwerk/base/src/nsSocketTransportService2.cpp @@ -85,6 +85,7 @@ nsSocketTransportService::nsSocketTransportService() , mActiveCount(0) , mIdleCount(0) , mSendBufferSize(0) + , mProbedMaxCount(false) { #if defined(PR_LOGGING) gSocketTransportLog = PR_NewLogModule("nsSocketTransport"); @@ -719,6 +720,14 @@ nsSocketTransportService::DoPollIteration(bool wait) SOCKET_LOG((" calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount)); +#if defined(XP_WIN) + // 30 active connections is the historic limit before firefox 7's 256. A few + // windows systems have troubles with the higher limit, so actively probe a + // limit the first time we exceed 30. + if ((mActiveCount > 30) && !mProbedMaxCount) + ProbeMaxCount(); +#endif + // Measures seconds spent while blocked on PR_Poll PRUint32 pollInterval; @@ -835,6 +844,73 @@ nsSocketTransportService::GetSendBufferSize(PRInt32 *value) #include #endif +// Right now the only need to do this is on windows. +#if defined(XP_WIN) +void +nsSocketTransportService::ProbeMaxCount() +{ + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + + if (mProbedMaxCount) + return; + mProbedMaxCount = true; + + PRInt32 startedMaxCount = gMaxCount; + + // Allocate and test a PR_Poll up to the gMaxCount number of unconnected + // sockets. See bug 692260 - windows should be able to handle 1000 sockets + // in select() without a problem, but LSPs have been known to balk at lower + // numbers. (64 in the bug). + + // Allocate + struct PRPollDesc pfd[SOCKET_LIMIT_TARGET]; + PRUint32 numAllocated = 0; + + for (PRUint32 index = 0 ; index < gMaxCount; ++index) { + pfd[index].in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT; + pfd[index].out_flags = 0; + pfd[index].fd = PR_OpenTCPSocket(PR_AF_INET); + if (!pfd[index].fd) { + SOCKET_LOG(("Socket Limit Test index %d failed\n", index)); + if (index < SOCKET_LIMIT_MIN) + gMaxCount = SOCKET_LIMIT_MIN; + else + gMaxCount = index; + break; + } + ++numAllocated; + } + + // Test + PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U); + while (gMaxCount <= numAllocated) { + PRInt32 rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0)); + + SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n", + gMaxCount, rv)); + + if (rv >= 0) + break; + + SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n", + gMaxCount, rv, PR_GetError())); + + gMaxCount -= 32; + if (gMaxCount <= SOCKET_LIMIT_MIN) { + gMaxCount = SOCKET_LIMIT_MIN; + break; + } + } + + // Free + for (PRUint32 index = 0 ; index < numAllocated; ++index) + if (pfd[index].fd) + PR_Close(pfd[index].fd); + + SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n", gMaxCount)); +} +#endif // windows + PRStatus nsSocketTransportService::DiscoverMaxCount() { diff --git a/netwerk/base/src/nsSocketTransportService2.h b/netwerk/base/src/nsSocketTransportService2.h index c1b3dd5f46e9..4734229828dd 100644 --- a/netwerk/base/src/nsSocketTransportService2.h +++ b/netwerk/base/src/nsSocketTransportService2.h @@ -205,6 +205,12 @@ private: // Preference Monitor for SendBufferSize nsresult UpdatePrefs(); PRInt32 mSendBufferSize; + + // Socket thread only for dynamically adjusting max socket size +#if defined(XP_WIN) + void ProbeMaxCount(); +#endif + bool mProbedMaxCount; }; extern nsSocketTransportService *gSocketTransportService; diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index 0c5051cc33df..30ac953885bc 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -171,7 +171,8 @@ public: PRInt32 MemoryCacheCapacity(); PRInt32 MemoryCacheMaxEntrySize() { return mMemoryCacheMaxEntrySize; } - static PRUint32 GetSmartCacheSize(const nsAString& cachePath); + static PRUint32 GetSmartCacheSize(const nsAString& cachePath, + PRUint32 currentSize); private: bool PermittedToSmartSize(nsIPrefBranch*, bool firstRun); @@ -200,8 +201,8 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheProfilePrefObserver, nsIObserver) class nsSetSmartSizeEvent: public nsRunnable { public: - nsSetSmartSizeEvent(bool firstRun, PRInt32 smartSize) - : mFirstRun(firstRun) , mSmartSize(smartSize) {} + nsSetSmartSizeEvent(PRInt32 smartSize) + : mSmartSize(smartSize) {} NS_IMETHOD Run() { @@ -226,8 +227,6 @@ public: smartSizeEnabled = false; if (smartSizeEnabled) { nsCacheService::SetDiskCacheCapacity(mSmartSize); - // also set on observer, in case mDiskDevice not init'd yet. - nsCacheService::gService->mObserver->SetDiskCacheCapacity(mSmartSize); rv = branch->SetIntPref(DISK_CACHE_SMART_SIZE_PREF, mSmartSize); if (NS_FAILED(rv)) NS_WARNING("Failed to set smart size pref"); @@ -235,8 +234,7 @@ public: return rv; } -private: - bool mFirstRun; +private: PRInt32 mSmartSize; }; @@ -245,28 +243,25 @@ private: class nsGetSmartSizeEvent: public nsRunnable { public: - nsGetSmartSizeEvent(bool firstRun, const nsAString& cachePath) - : mFirstRun(firstRun) - , mCachePath(cachePath) - , mSmartSize(0) + nsGetSmartSizeEvent(const nsAString& cachePath, PRUint32 currentSize) + : mCachePath(cachePath) + , mCurrentSize(currentSize) {} // Calculates user's disk space available on a background thread and // dispatches this value back to the main thread. NS_IMETHOD Run() { - mSmartSize = - nsCacheProfilePrefObserver::GetSmartCacheSize(mCachePath); - nsCOMPtr event = new nsSetSmartSizeEvent(mFirstRun, - mSmartSize); - NS_DispatchToMainThread(event); + PRUint32 size; + size = nsCacheProfilePrefObserver::GetSmartCacheSize(mCachePath, + mCurrentSize); + NS_DispatchToMainThread(new nsSetSmartSizeEvent(size)); return NS_OK; } -private: - bool mFirstRun; +private: nsString mCachePath; - PRInt32 mSmartSize; + PRUint32 mCurrentSize; }; class nsBlockOnCacheThreadEvent : public nsRunnable { @@ -435,18 +430,7 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, return rv; PRInt32 newCapacity = 0; if (smartSizeEnabled) { - // Dispatch event to update smart size: just keep using old - // value if this fails at any point - if (!mDiskCacheParentDirectory) - return NS_ERROR_NOT_AVAILABLE; // disk cache disabled anyway - nsAutoString cachePath; - rv = mDiskCacheParentDirectory->GetPath(cachePath); - if (NS_FAILED(rv)) - return rv; - // Smart sizing switched on: recalculate the capacity. - nsCOMPtr event = - new nsGetSmartSizeEvent(false, cachePath); - rv = nsCacheService::DispatchToCacheIOThread(event); + nsCacheService::SetDiskSmartSize(); } else { // Smart sizing switched off: use user specified size rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &newCapacity); @@ -559,6 +543,42 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, return NS_OK; } +// Returns default ("smart") size (in KB) of cache, given available disk space +// (also in KB) +static PRUint32 +SmartCacheSize(const PRUint32 availKB) +{ + if (availKB > 100 * 1024 * 1024) + return MAX_CACHE_SIZE; // skip computing if we're over 100 GB + + // Grow/shrink in 10 MB units, deliberately, so that in the common case we + // don't shrink cache and evict items every time we startup (it's important + // that we don't slow down startup benchmarks). + PRUint32 sz10MBs = 0; + PRUint32 avail10MBs = availKB / (1024*10); + + // .5% of space above 25 GB + if (avail10MBs > 2500) { + sz10MBs += (avail10MBs - 2500)*.005; + avail10MBs = 2500; + } + // 1% of space between 7GB -> 25 GB + if (avail10MBs > 700) { + sz10MBs += (avail10MBs - 700)*.01; + avail10MBs = 700; + } + // 5% of space between 500 MB -> 7 GB + if (avail10MBs > 50) { + sz10MBs += (avail10MBs - 50)*.05; + avail10MBs = 50; + } + + // 40% of space up to 500 MB (50 MB min) + sz10MBs += NS_MAX(5, avail10MBs * .4); + + return NS_MIN(MAX_CACHE_SIZE, sz10MBs * 10 * 1024); +} + /* Computes our best guess for the default size of the user's disk cache, * based on the amount of space they have free on their hard drive. * We use a tiered scheme: the more space available, @@ -571,45 +591,24 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, *@return: The size that the user's disk cache should default to, in kBytes. */ PRUint32 -nsCacheProfilePrefObserver::GetSmartCacheSize(const nsAString& cachePath) +nsCacheProfilePrefObserver::GetSmartCacheSize(const nsAString& cachePath, + PRUint32 currentSize) { - // Check for free space on device where cache directory lives - nsresult rv; - nsCOMPtr - cacheDirectory (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); - if (NS_FAILED(rv) || !cacheDirectory) - return DEFAULT_CACHE_SIZE; - rv = cacheDirectory->InitWithPath(cachePath); - if (NS_FAILED(rv)) - return DEFAULT_CACHE_SIZE; - PRInt64 bytesAvailable; - rv = cacheDirectory->GetDiskSpaceAvailable(&bytesAvailable); - if (NS_FAILED(rv)) - return DEFAULT_CACHE_SIZE; - PRInt64 kBytesAvail = bytesAvailable / 1024; - - // 0 MB <= Available < 500 MB: Use between 50MB and 200MB - if (kBytesAvail < DEFAULT_CACHE_SIZE * 2) - return NS_MAX(MIN_CACHE_SIZE, kBytesAvail * 4 / 10); - - // 500MB <= Available < 2.5 GB: Use 250MB - if (kBytesAvail < static_cast(DEFAULT_CACHE_SIZE) * 10) - return DEFAULT_CACHE_SIZE; + // Check for free space on device where cache directory lives + nsresult rv; + nsCOMPtr + cacheDirectory (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_FAILED(rv) || !cacheDirectory) + return DEFAULT_CACHE_SIZE; + rv = cacheDirectory->InitWithPath(cachePath); + if (NS_FAILED(rv)) + return DEFAULT_CACHE_SIZE; + PRInt64 bytesAvailable; + rv = cacheDirectory->GetDiskSpaceAvailable(&bytesAvailable); + if (NS_FAILED(rv)) + return DEFAULT_CACHE_SIZE; - // 2.5 GB <= Available < 5 GB: Use between 250MB and 500MB - if (kBytesAvail < static_cast(DEFAULT_CACHE_SIZE) * 20) - return kBytesAvail / 10; - - // 5 GB <= Available < 50 GB: Use 625MB - if (kBytesAvail < static_cast(DEFAULT_CACHE_SIZE) * 200 ) - return DEFAULT_CACHE_SIZE * 5 / 2; - - // 50 GB <= Available < 75 GB: Use 800MB - if (kBytesAvail < static_cast(DEFAULT_CACHE_SIZE) * 300) - return DEFAULT_CACHE_SIZE / 5 * 16; - - // Use 1 GB - return MAX_CACHE_SIZE; + return SmartCacheSize((bytesAvailable / 1024) + currentSize); } /* Determine if we are permitted to dynamically size the user's disk cache based @@ -733,13 +732,6 @@ nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch) mDiskCacheCapacity = DEFAULT_CACHE_SIZE; } } - nsAutoString cachePath; - rv = mDiskCacheParentDirectory->GetPath(cachePath); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr event = - new nsGetSmartSizeEvent(!!firstSmartSizeRun, cachePath); - nsCacheService::DispatchToCacheIOThread(event); - } } if (firstSmartSizeRun) { @@ -1369,6 +1361,9 @@ nsCacheService::CreateDiskDevice() delete mDiskDevice; mDiskDevice = nsnull; } + + SetDiskSmartSize_Locked(true); + return rv; } @@ -2555,3 +2550,49 @@ nsCacheService::OnEnterExitPrivateBrowsing() gService->mMemoryDevice->EvictEntries(nsnull); } } + +nsresult +nsCacheService::SetDiskSmartSize() +{ + nsCacheServiceAutoLock lock; + + if (!gService) return NS_ERROR_NOT_AVAILABLE; + + return gService->SetDiskSmartSize_Locked(false); +} + +nsresult +nsCacheService::SetDiskSmartSize_Locked(bool checkPref) +{ + nsresult rv; + + if (!mObserver->DiskCacheParentDirectory()) + return NS_ERROR_NOT_AVAILABLE; + + if (!mDiskDevice) + return NS_ERROR_NOT_AVAILABLE; + + if (checkPref) { + nsCOMPtr branch = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (!branch) return NS_ERROR_FAILURE; + + bool smartSizeEnabled; + rv = branch->GetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF, + &smartSizeEnabled); + + if (NS_FAILED(rv) || !smartSizeEnabled) + return NS_ERROR_NOT_AVAILABLE; + } + + nsAutoString cachePath; + rv = mObserver->DiskCacheParentDirectory()->GetPath(cachePath); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr event = + new nsGetSmartSizeEvent(cachePath, mDiskDevice->getCacheSize()); + DispatchToCacheIOThread(event); + } else { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index 702c4c42415c..7ef0aca6d8fc 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -178,6 +178,9 @@ public: static void OnEnterExitPrivateBrowsing(); + // Starts smart cache size computation if disk device is available + static nsresult SetDiskSmartSize(); + nsresult Init(); void Shutdown(); @@ -258,6 +261,8 @@ private: void LogCacheStatistics(); #endif + nsresult SetDiskSmartSize_Locked(bool checkPref); + /** * Data Members */ diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index c79380133531..30c91a468f4a 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -4298,8 +4298,26 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st mListenerContext = 0; } - if (mCacheEntry) + if (mCacheEntry) { + bool asFile = false; + if (mInitedCacheEntry && !mCachedContentIsPartial && + (NS_SUCCEEDED(mStatus) || contentComplete) && + (mCacheAccess & nsICache::ACCESS_WRITE) && + NS_SUCCEEDED(GetCacheAsFile(&asFile)) && asFile) { + // We can allow others access to the cache entry + // because we don't write to the cache anymore. + // CloseCacheEntry may not actually close the cache + // entry immediately because someone (such as XHR2 + // blob response) may hold the token to the cache + // entry. So we mark the cache valid here. + // We also need to check the entry is stored as file + // because we write to the cache asynchronously when + // it isn't stored in the file and it isn't completely + // written to the disk yet. + mCacheEntry->MarkValid(); + } CloseCacheEntry(!contentComplete); + } if (mOfflineCacheEntry) CloseOfflineCacheEntry(); diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index f861035b091e..d24b82b6e7df 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -646,6 +646,16 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, PRUint8 cap LOG(("nsHttpConnectionMgr::AtActiveConnectionLimit [ci=%s caps=%x]\n", ci->HashKey().get(), caps)); + // update maxconns if potentially limited by the max socket count + // this requires a dynamic reduction in the max socket count to a point + // lower than the max-connections pref. + PRUint32 maxSocketCount = gHttpHandler->MaxSocketCount(); + if (mMaxConns > maxSocketCount) { + mMaxConns = maxSocketCount; + LOG(("nsHttpConnectionMgr %p mMaxConns dynamically reduced to %u", + this, mMaxConns)); + } + // If there are more active connections than the global limit, then we're // done. Purging idle connections won't get us below it. if (mNumActiveConns >= mMaxConns) { diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 70d7bea16416..2516e31fe629 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -773,6 +773,24 @@ nsHttpHandler::InitUserAgentComponents() mUserAgentIsDirty = true; } +PRUint32 +nsHttpHandler::MaxSocketCount() +{ + PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce, + nsSocketTransportService::DiscoverMaxCount); + // Don't use the full max count because sockets can be held in + // the persistent connection pool for a long time and that could + // starve other users. + + PRUint32 maxCount = nsSocketTransportService::gMaxCount; + if (maxCount <= 8) + maxCount = 1; + else + maxCount -= 8; + + return maxCount; +} + void nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref) { @@ -837,11 +855,10 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref) if (PREF_CHANGED(HTTP_PREF("max-connections"))) { rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val); if (NS_SUCCEEDED(rv)) { - PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce, - nsSocketTransportService::DiscoverMaxCount); - mMaxConnections = - (PRUint16) NS_CLAMP((PRUint32)val, 1, - nsSocketTransportService::gMaxCount); + + mMaxConnections = (PRUint16) NS_CLAMP((PRUint32)val, + 1, MaxSocketCount()); + if (mConnMgr) mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS, mMaxConnections); diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index 5dc0805049bc..4eb0abae246a 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -108,6 +108,7 @@ public: PRUint8 GetQoSBits() { return mQoSBits; } PRUint16 GetIdleSynTimeout() { return mIdleSynTimeout; } bool FastFallbackToIPv4() { return mFastFallbackToIPv4; } + PRUint32 MaxSocketCount(); bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; } diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 344634bf4066..a97f795ff7d4 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -118,29 +118,26 @@ class CallOnMessageAvailable : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnMessageAvailable(nsIWebSocketListener *aListener, - nsISupports *aContext, - nsCString &aData, - PRInt32 aLen) - : mListener(aListener), - mContext(aContext), + CallOnMessageAvailable(WebSocketChannel *aChannel, + nsCString &aData, + PRInt32 aLen) + : mChannel(aChannel), mData(aData), mLen(aLen) {} NS_SCRIPTABLE NS_IMETHOD Run() { if (mLen < 0) - mListener->OnMessageAvailable(mContext, mData); + mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData); else - mListener->OnBinaryMessageAvailable(mContext, mData); + mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData); return NS_OK; } private: ~CallOnMessageAvailable() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; nsCString mData; PRInt32 mLen; }; @@ -151,24 +148,21 @@ class CallOnStop : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnStop(nsIWebSocketListener *aListener, - nsISupports *aContext, - nsresult aData) - : mListener(aListener), - mContext(aContext), + CallOnStop(WebSocketChannel *aChannel, + nsresult aData) + : mChannel(aChannel), mData(aData) {} NS_SCRIPTABLE NS_IMETHOD Run() { - mListener->OnStop(mContext, mData); + mChannel->mListener->OnStop(mChannel->mContext, mData); return NS_OK; } private: ~CallOnStop() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; nsresult mData; }; NS_IMPL_THREADSAFE_ISUPPORTS1(CallOnStop, nsIRunnable) @@ -178,26 +172,23 @@ class CallOnServerClose : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnServerClose(nsIWebSocketListener *aListener, - nsISupports *aContext, - PRUint16 aCode, - nsCString &aReason) - : mListener(aListener), - mContext(aContext), + CallOnServerClose(WebSocketChannel *aChannel, + PRUint16 aCode, + nsCString &aReason) + : mChannel(aChannel), mCode(aCode), mReason(aReason) {} NS_SCRIPTABLE NS_IMETHOD Run() { - mListener->OnServerClose(mContext, mCode, mReason); + mChannel->mListener->OnServerClose(mChannel->mContext, mCode, mReason); return NS_OK; } private: ~CallOnServerClose() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; PRUint16 mCode; nsCString mReason; }; @@ -208,25 +199,22 @@ class CallAcknowledge : public nsIRunnable public: NS_DECL_ISUPPORTS - CallAcknowledge(nsIWebSocketListener *aListener, - nsISupports *aContext, - PRUint32 aSize) - : mListener(aListener), - mContext(aContext), + CallAcknowledge(WebSocketChannel *aChannel, + PRUint32 aSize) + : mChannel(aChannel), mSize(aSize) {} NS_SCRIPTABLE NS_IMETHOD Run() { LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize)); - mListener->OnAcknowledge(mContext, mSize); + mChannel->mListener->OnAcknowledge(mChannel->mContext, mSize); return NS_OK; } private: ~CallAcknowledge() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; PRUint32 mSize; }; NS_IMPL_THREADSAFE_ISUPPORTS1(CallAcknowledge, nsIRunnable) @@ -236,10 +224,10 @@ class nsPostMessage : public nsIRunnable public: NS_DECL_ISUPPORTS - nsPostMessage(WebSocketChannel *channel, + nsPostMessage(WebSocketChannel *aChannel, nsCString *aData, PRInt32 aDataLen) - : mChannel(channel), + : mChannel(aChannel), mData(aData), mDataLen(aDataLen) {} @@ -935,8 +923,7 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) return NS_ERROR_ILLEGAL_VALUE; } - NS_DispatchToMainThread(new CallOnMessageAvailable(mListener, mContext, - utf8Data, -1)); + NS_DispatchToMainThread(new CallOnMessageAvailable(this, utf8Data, -1)); } } else if (opcode & kControlFrameMask) { // control frames @@ -981,10 +968,10 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) mCloseTimer->Cancel(); mCloseTimer = nsnull; } - if (mListener) - NS_DispatchToMainThread( - new CallOnServerClose(mListener, mContext, - mServerCloseCode, mServerCloseReason)); + if (mListener) { + NS_DispatchToMainThread(new CallOnServerClose(this, mServerCloseCode, + mServerCloseReason)); + } if (mClientClosed) ReleaseSession(); @@ -1019,8 +1006,7 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) LOG(("WebSocketChannel:: binary frame received\n")); if (mListener) { nsCString binaryData((const char *)payload, payloadLength); - NS_DispatchToMainThread(new CallOnMessageAvailable(mListener, mContext, - binaryData, + NS_DispatchToMainThread(new CallOnMessageAvailable(this, binaryData, payloadLength)); } } else if (opcode != kContinuation) { @@ -1489,7 +1475,7 @@ WebSocketChannel::StopSession(nsresult reason) if (!mCalledOnStop) { mCalledOnStop = 1; if (mListener) - NS_DispatchToMainThread(new CallOnStop(mListener, mContext, reason)); + NS_DispatchToMainThread(new CallOnStop(this, reason)); } return; @@ -2202,7 +2188,7 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport *aTransport, nsresult rv; rv = mTransport->SetEventSink(nsnull, nsnull); if (NS_FAILED(rv)) return rv; - rv = mTransport->SetSecurityCallbacks(mCallbacks); + rv = mTransport->SetSecurityCallbacks(this); if (NS_FAILED(rv)) return rv; mRecvdHttpUpgradeTransport = 1; @@ -2520,7 +2506,7 @@ WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream *aStream) } else { if (amtSent == toSend) { if (!mStopped) { - NS_DispatchToMainThread(new CallAcknowledge(mListener, mContext, + NS_DispatchToMainThread(new CallAcknowledge(this, mCurrentOut->Length())); } delete mCurrentOut; diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index 23474e860d63..c00ebef9d99e 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -70,6 +70,10 @@ namespace mozilla { namespace net { class nsPostMessage; class nsWSAdmissionManager; class nsWSCompression; +class CallOnMessageAvailable; +class CallOnStop; +class CallOnServerClose; +class CallAcknowledge; class WebSocketChannel : public BaseWebSocketChannel, public nsIHttpUpgradeListener, @@ -129,6 +133,10 @@ protected: private: friend class nsPostMessage; friend class nsWSAdmissionManager; + friend class CallOnMessageAvailable; + friend class CallOnStop; + friend class CallOnServerClose; + friend class CallAcknowledge; void SendMsgInternal(nsCString *aMsg, PRInt32 datalen); void PrimeNewOutgoingMessage(); diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp index d0c850eeefbb..5e898d3f1095 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp +++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp @@ -216,8 +216,10 @@ WyciwygChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext nsCOMPtr serializable = do_QueryInterface(securityInfo); if (serializable) NS_SerializeToString(serializable, secInfoStr); - else - NS_WARNING("Can't serialize security info"); + else { + NS_ERROR("Can't serialize security info"); + return NS_ERROR_UNEXPECTED; + } } if (mIPCClosed || diff --git a/security/coreconf/SunOS5.mk b/security/coreconf/SunOS5.mk index c3f8e182533d..43b526d9707b 100644 --- a/security/coreconf/SunOS5.mk +++ b/security/coreconf/SunOS5.mk @@ -37,15 +37,6 @@ include $(CORE_DEPTH)/coreconf/UNIX.mk -# -# Temporary define for the Client; to be removed when binary release is used -# -ifdef MOZILLA_CLIENT - ifndef NS_USE_NATIVE - NS_USE_GCC = 1 - endif -endif - # Sun's WorkShop defines v8, v8plus and v9 architectures. # gcc on Solaris defines v8 and v9 "cpus". # gcc's v9 is equivalent to Workshop's v8plus. diff --git a/security/nss/TAG-INFO b/security/nss/TAG-INFO index 6c6bb96eabaa..2713ac36f093 100644 --- a/security/nss/TAG-INFO +++ b/security/nss/TAG-INFO @@ -1 +1 @@ -NSS_3_13_RC0 +NSS_3_13_1_BETA2 diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c index b40d1febbcf4..0c52a647cf78 100644 --- a/security/nss/cmd/lib/secutil.c +++ b/security/nss/cmd/lib/secutil.c @@ -3763,6 +3763,8 @@ SECU_StringToSignatureAlgTag(const char *alg) hashAlgTag = SEC_OID_MD5; } else if (!PL_strcmp(alg, "SHA1")) { hashAlgTag = SEC_OID_SHA1; + } else if (!PL_strcmp(alg, "SHA224")) { + hashAlgTag = SEC_OID_SHA224; } else if (!PL_strcmp(alg, "SHA256")) { hashAlgTag = SEC_OID_SHA256; } else if (!PL_strcmp(alg, "SHA384")) { diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index 5b8fd228cfab..ffd27ad6d2a9 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -550,6 +550,7 @@ seckey_GetKeyType (SECOidTag tag) { * should be handing us a cipher type */ case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: diff --git a/security/nss/lib/cryptohi/secsign.c b/security/nss/lib/cryptohi/secsign.c index 37609b19385d..b24dcfadf093 100644 --- a/security/nss/lib/cryptohi/secsign.c +++ b/security/nss/lib/cryptohi/secsign.c @@ -37,7 +37,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: secsign.c,v 1.26 2011/07/24 13:48:12 wtc%google.com Exp $ */ +/* $Id: secsign.c,v 1.27 2011/10/22 14:35:42 wtc%google.com Exp $ */ #include #include "cryptohi.h" @@ -478,6 +478,8 @@ SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) case SEC_OID_UNKNOWN: /* default for RSA if not specified */ case SEC_OID_SHA1: sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; + case SEC_OID_SHA224: + sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; break; case SEC_OID_SHA256: sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; case SEC_OID_SHA384: @@ -502,6 +504,8 @@ SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ case SEC_OID_SHA1: sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; + case SEC_OID_SHA224: + sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; break; case SEC_OID_SHA256: sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; case SEC_OID_SHA384: diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c index 1edef971a6fb..c7d32adcd75c 100644 --- a/security/nss/lib/cryptohi/secvfy.c +++ b/security/nss/lib/cryptohi/secvfy.c @@ -37,7 +37,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: secvfy.c,v 1.24 2010/06/23 02:13:56 wtc%google.com Exp $ */ +/* $Id: secvfy.c,v 1.25 2011/10/22 14:35:42 wtc%google.com Exp $ */ #include #include "cryptohi.h" @@ -241,6 +241,10 @@ sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ break; + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: + *hashalg = SEC_OID_SHA224; + break; case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_SHA256; @@ -276,9 +280,7 @@ sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, if (len < 28) { /* 28 bytes == 224 bits */ *hashalg = SEC_OID_SHA1; } else if (len < 32) { /* 32 bytes == 256 bits */ - /* SHA 224 not supported in NSS */ - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); - return SECFailure; + *hashalg = SEC_OID_SHA224; } else if (len < 48) { /* 48 bytes == 384 bits */ *hashalg = SEC_OID_SHA256; } else if (len < 64) { /* 48 bytes == 512 bits */ @@ -323,6 +325,7 @@ sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: @@ -344,6 +347,7 @@ sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, *encalg = SEC_OID_MISSI_DSS; break; case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: diff --git a/security/nss/lib/nss/nss.h b/security/nss/lib/nss/nss.h index 9495a41292e2..4066aa3f066d 100644 --- a/security/nss/lib/nss/nss.h +++ b/security/nss/lib/nss/nss.h @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: nss.h,v 1.84 2011/10/04 22:56:31 wtc%google.com Exp $ */ +/* $Id: nss.h,v 1.85 2011/10/14 00:16:09 wtc%google.com Exp $ */ #ifndef __nss_h_ #define __nss_h_ @@ -66,12 +66,12 @@ * The format of the version string should be * ".[.[.]][ ][ ]" */ -#define NSS_VERSION "3.13.0.0" _NSS_ECC_STRING _NSS_CUSTOMIZED +#define NSS_VERSION "3.13.1.0" _NSS_ECC_STRING _NSS_CUSTOMIZED " Beta" #define NSS_VMAJOR 3 #define NSS_VMINOR 13 -#define NSS_VPATCH 0 +#define NSS_VPATCH 1 #define NSS_VBUILD 0 -#define NSS_BETA PR_FALSE +#define NSS_BETA PR_TRUE #ifndef RC_INVOKED diff --git a/security/nss/lib/nss/nssinit.c b/security/nss/lib/nss/nssinit.c index 7d8c90df84b6..b2f151d82ecd 100644 --- a/security/nss/lib/nss/nssinit.c +++ b/security/nss/lib/nss/nssinit.c @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: nssinit.c,v 1.112 2011/10/04 02:35:58 emaldona%redhat.com Exp $ */ +/* $Id: nssinit.c,v 1.114 2011/10/18 19:03:31 wtc%google.com Exp $ */ #include #include @@ -540,13 +540,13 @@ nss_doLockInit(void) { nssInitLock = PZ_NewLock(nssILockOther); if (nssInitLock == NULL) { - return (PRStatus) SECFailure; + return PR_FAILURE; } nssInitCondition = PZ_NewCondVar(nssInitLock); if (nssInitCondition == NULL) { - return (PRStatus) SECFailure; + return PR_FAILURE; } - return (PRStatus) SECSuccess; + return PR_SUCCESS; } @@ -577,10 +577,10 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix, return SECSuccess; } - /* make sure our locks are initialized one and only one time */ - rv = PR_CallOnce(&nssInitOnce, nss_doLockInit); - if (rv != SECSuccess) { - return rv; + /* make sure our lock and condition variable are initialized one and only + * one time */ + if (PR_CallOnce(&nssInitOnce, nss_doLockInit) != PR_SUCCESS) { + return SECFailure; } /* @@ -597,7 +597,6 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix, /* once we've completed basic initialization, we can allow more than * one process initialize NSS at a time. */ } - /* get the current value */ nssIsInInit++; PZ_Unlock(nssInitLock); @@ -761,6 +760,11 @@ loser: PR_smprintf_free(configStrings); } } + PZ_Lock(nssInitLock); + nssIsInInit--; + /* We failed to init, allow one to move forward */ + PZ_NotifyCondVar(nssInitCondition); + PZ_Unlock(nssInitLock); return SECFailure; } diff --git a/security/nss/lib/pk11wrap/pk11mech.c b/security/nss/lib/pk11wrap/pk11mech.c index f12102720de8..4a916a4c4002 100644 --- a/security/nss/lib/pk11wrap/pk11mech.c +++ b/security/nss/lib/pk11wrap/pk11mech.c @@ -563,6 +563,7 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size) case CKM_MD2_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: + case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: @@ -596,6 +597,8 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size) return CKM_SSL3_PRE_MASTER_KEY_GEN; case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: case CKM_SHA384_HMAC: diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index 65d807d0f30a..09aa5b654ff5 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -59,7 +59,7 @@ /* * This array helps parsing between names, mechanisms, and flags. * to make the config files understand more entries, add them - * to this table. (NOTE: we need function to export this table and it's size) + * to this table. (NOTE: we need function to export this table and its size) */ PK11DefaultArrayEntry PK11_DefaultArray[] = { { "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS }, @@ -73,6 +73,7 @@ PK11DefaultArrayEntry PK11_DefaultArray[] = { { "SEED", SECMOD_SEED_FLAG, CKM_SEED_CBC }, { "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC }, { "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 }, +/* { "SHA224", SECMOD_SHA256_FLAG, CKM_SHA224 }, */ { "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 }, /* { "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */ { "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 }, @@ -857,6 +858,7 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type) return &pk11_rc5SlotList; case CKM_SHA_1: return &pk11_sha1SlotList; + case CKM_SHA224: case CKM_SHA256: return &pk11_sha256SlotList; case CKM_SHA384: @@ -2024,6 +2026,7 @@ PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int mech_count, void *wincx) for (i=0; i < mech_count; i++) { if ((type[i] != CKM_FAKE_RANDOM) && (type[i] != CKM_SHA_1) && + (type[i] != CKM_SHA224) && (type[i] != CKM_SHA256) && (type[i] != CKM_SHA384) && (type[i] != CKM_SHA512) && diff --git a/security/nss/lib/pkcs12/p12local.c b/security/nss/lib/pkcs12/p12local.c index a2221504b80c..4a0b55b330af 100644 --- a/security/nss/lib/pkcs12/p12local.c +++ b/security/nss/lib/pkcs12/p12local.c @@ -62,6 +62,8 @@ sec_pkcs12_algtag_to_mech(SECOidTag algtag) return CKM_MD5_HMAC; case SEC_OID_SHA1: return CKM_SHA_1_HMAC; + case SEC_OID_SHA224: + return CKM_SHA224_HMAC; case SEC_OID_SHA256: return CKM_SHA256_HMAC; case SEC_OID_SHA384: diff --git a/security/nss/lib/softoken/rsawrapr.c b/security/nss/lib/softoken/rsawrapr.c index 9eec7e118821..91a214f11eb2 100644 --- a/security/nss/lib/softoken/rsawrapr.c +++ b/security/nss/lib/softoken/rsawrapr.c @@ -38,7 +38,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: rsawrapr.c,v 1.18 2011/10/04 22:05:53 wtc%google.com Exp $ */ +/* $Id: rsawrapr.c,v 1.19 2011/10/22 14:35:43 wtc%google.com Exp $ */ #include "blapi.h" #include "softoken.h" @@ -1169,11 +1169,13 @@ emsa_pss_verify(const unsigned char *mHash, static HASH_HashType GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech) { - /* TODO(wtc): add SHA-224. */ switch (mech) { case CKM_SHA_1: case CKG_MGF1_SHA1: return HASH_AlgSHA1; + case CKM_SHA224: + case CKG_MGF1_SHA224: + return HASH_AlgSHA224; case CKM_SHA256: case CKG_MGF1_SHA256: return HASH_AlgSHA256; diff --git a/security/nss/lib/softoken/softkver.h b/security/nss/lib/softoken/softkver.h index a9a015ec4c42..84d1f66d0ed6 100644 --- a/security/nss/lib/softoken/softkver.h +++ b/security/nss/lib/softoken/softkver.h @@ -57,11 +57,11 @@ * The format of the version string should be * ".[.[.]][ ][ ]" */ -#define SOFTOKEN_VERSION "3.13.0.0" SOFTOKEN_ECC_STRING +#define SOFTOKEN_VERSION "3.13.1.0" SOFTOKEN_ECC_STRING " Beta" #define SOFTOKEN_VMAJOR 3 #define SOFTOKEN_VMINOR 13 -#define SOFTOKEN_VPATCH 0 +#define SOFTOKEN_VPATCH 1 #define SOFTOKEN_VBUILD 0 -#define SOFTOKEN_BETA PR_FALSE +#define SOFTOKEN_BETA PR_TRUE #endif /* _SOFTKVER_H_ */ diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index 778c7ab3d83c..ac2059fa7d1c 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -40,7 +40,7 @@ * ***** END LICENSE BLOCK ***** */ /* ECC code moved here from ssl3con.c */ -/* $Id: ssl3ecc.c,v 1.24 2010/03/15 08:03:14 nelson%bolyard.com Exp $ */ +/* $Id: ssl3ecc.c,v 1.25 2011/10/22 14:35:44 wtc%google.com Exp $ */ #include "nss.h" #include "cert.h" @@ -968,6 +968,7 @@ ssl3_FilterECCipherSuitesByServerCerts(sslSocket * ss) case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: diff --git a/security/nss/lib/ssl/sslerrstrs.c b/security/nss/lib/ssl/sslerrstrs.c index 182a2bfd6f58..a06f99ed908c 100644 --- a/security/nss/lib/ssl/sslerrstrs.c +++ b/security/nss/lib/ssl/sslerrstrs.c @@ -38,7 +38,6 @@ #include "prinit.h" #include "nssutil.h" #include "ssl.h" -#include "sslerrstrs.h" #define ER3(name, value, str) {#name, str}, @@ -59,8 +58,9 @@ ssl_InitializePRErrorTableOnce(void) { static PRCallOnceType once; -PRStatus +SECStatus ssl_InitializePRErrorTable(void) { - return PR_CallOnce(&once, ssl_InitializePRErrorTableOnce); + return (PR_SUCCESS == PR_CallOnce(&once, ssl_InitializePRErrorTableOnce)) + ? SECSuccess : SECFailure; } diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 6b49486ac0cc..bdbb46a76e4f 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -39,7 +39,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslimpl.h,v 1.83 2011/10/01 03:59:54 bsmith%mozilla.com Exp $ */ +/* $Id: sslimpl.h,v 1.84 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */ #ifndef __sslimpl_h_ #define __sslimpl_h_ @@ -1151,6 +1151,10 @@ extern sslSessionIDUncacheFunc ssl_sid_uncache; SEC_BEGIN_PROTOS +/* Internal initialization and installation of the SSL error tables */ +extern SECStatus ssl_Init(void); +extern SECStatus ssl_InitializePRErrorTable(void); + /* Implementation of ops for default (non socks, non secure) case */ extern int ssl_DefConnect(sslSocket *ss, const PRNetAddr *addr); extern PRFileDesc *ssl_DefAccept(sslSocket *ss, PRNetAddr *addr); diff --git a/security/nss/lib/ssl/sslinit.c b/security/nss/lib/ssl/sslinit.c index 4ba8e84dc104..bd75bbfcea3a 100644 --- a/security/nss/lib/ssl/sslinit.c +++ b/security/nss/lib/ssl/sslinit.c @@ -36,14 +36,14 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslinit.c,v 1.1 2011/08/17 14:41:05 emaldona%redhat.com Exp $ */ +/* $Id: sslinit.c,v 1.2 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */ #include "prtypes.h" #include "prinit.h" #include "seccomon.h" #include "secerr.h" #include "ssl.h" -#include "sslerrstrs.h" +#include "sslimpl.h" static int ssl_inited = 0; @@ -51,8 +51,9 @@ SECStatus ssl_Init(void) { if (!ssl_inited) { - if (ssl_InitializePRErrorTable() == PR_FAILURE) { - return (SEC_ERROR_NO_MEMORY); + if (ssl_InitializePRErrorTable() != SECSuccess) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return (SECFailure); } ssl_inited = 1; } diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 9c07337b36da..9de8d2c0f05d 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -36,7 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslsnce.c,v 1.58 2011/10/01 00:11:02 wtc%google.com Exp $ */ +/* $Id: sslsnce.c,v 1.59 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */ /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server * cache sids! @@ -83,7 +83,6 @@ #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" -#include "sslutil.h" #include "pk11func.h" #include "base64.h" #include "keyhi.h" diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 4ac8ae2193a2..2e6f9ed229c6 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -40,14 +40,13 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -/* $Id: sslsock.c,v 1.74 2011/10/06 22:42:34 wtc%google.com Exp $ */ +/* $Id: sslsock.c,v 1.75 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */ #include "seccomon.h" #include "cert.h" #include "keyhi.h" #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" -#include "sslutil.h" #include "nspr.h" #include "private/pprio.h" #include "blapi.h" diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h index bd5b4dd8cf36..5877d87eb677 100644 --- a/security/nss/lib/util/nssutil.h +++ b/security/nss/lib/util/nssutil.h @@ -51,12 +51,12 @@ * The format of the version string should be * ".[.[.]][ ]" */ -#define NSSUTIL_VERSION "3.13.0.0" +#define NSSUTIL_VERSION "3.13.1.0 Beta" #define NSSUTIL_VMAJOR 3 #define NSSUTIL_VMINOR 13 -#define NSSUTIL_VPATCH 0 +#define NSSUTIL_VPATCH 1 #define NSSUTIL_VBUILD 0 -#define NSSUTIL_BETA PR_FALSE +#define NSSUTIL_BETA PR_TRUE SEC_BEGIN_PROTOS diff --git a/security/nss/lib/util/secalgid.c b/security/nss/lib/util/secalgid.c index dc6c56396d28..316c9f5aaf7d 100644 --- a/security/nss/lib/util/secalgid.c +++ b/security/nss/lib/util/secalgid.c @@ -70,6 +70,7 @@ SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *id, SECOidTag which, case SEC_OID_MD4: case SEC_OID_MD5: case SEC_OID_SHA1: + case SEC_OID_SHA224: case SEC_OID_SHA256: case SEC_OID_SHA384: case SEC_OID_SHA512: @@ -78,6 +79,7 @@ SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *id, SECOidTag which, case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: diff --git a/services/sync/modules/policies.js b/services/sync/modules/policies.js index 8b8af9838c49..89655ecebb6c 100644 --- a/services/sync/modules/policies.js +++ b/services/sync/modules/policies.js @@ -72,16 +72,26 @@ let SyncScheduler = { this.idle = false; this.hasIncomingItems = false; - this.numClients = 0; - this.nextSync = 0, - this.syncInterval = this.singleDeviceInterval; - this.syncThreshold = SINGLE_USER_THRESHOLD; + this.clearSyncTriggers(); }, + // nextSync is in milliseconds, but prefs can't hold that much + get nextSync() Svc.Prefs.get("nextSync", 0) * 1000, + set nextSync(value) Svc.Prefs.set("nextSync", Math.floor(value / 1000)), + + get syncInterval() Svc.Prefs.get("syncInterval", this.singleDeviceInterval), + set syncInterval(value) Svc.Prefs.set("syncInterval", value), + + get syncThreshold() Svc.Prefs.get("syncThreshold", SINGLE_USER_THRESHOLD), + set syncThreshold(value) Svc.Prefs.set("syncThreshold", value), + get globalScore() Svc.Prefs.get("globalScore", 0), set globalScore(value) Svc.Prefs.set("globalScore", value), + get numClients() Svc.Prefs.get("numClients", 0), + set numClients(value) Svc.Prefs.set("numClients", value), + init: function init() { this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")]; this.setDefaults(); @@ -103,7 +113,6 @@ let SyncScheduler = { if (Status.checkSetup() == STATUS_OK) { Svc.Idle.addIdleObserver(this, Svc.Prefs.get("scheduler.idleTime")); } - }, observe: function observe(subject, topic, data) { @@ -357,25 +366,34 @@ let SyncScheduler = { // Ensure the interval is set to no less than the backoff. if (Status.backoffInterval && interval < Status.backoffInterval) { + this._log.trace("Requested interval " + interval + + " ms is smaller than the backoff interval. " + + "Using backoff interval " + + Status.backoffInterval + " ms instead."); interval = Status.backoffInterval; } if (this.nextSync != 0) { - // There's already a sync scheduled. Don't reschedule if that's already - // going to happen sooner than requested. + // There's already a sync scheduled. Don't reschedule if there's already + // a timer scheduled for sooner than requested. let currentInterval = this.nextSync - Date.now(); - if (currentInterval < interval) { + this._log.trace("There's already a sync scheduled in " + + currentInterval + " ms."); + if (currentInterval < interval && this.syncTimer) { + this._log.trace("Ignoring scheduling request for next sync in " + + interval + " ms."); return; } } - // Start the sync right away if we're already late + // Start the sync right away if we're already late. if (interval <= 0) { + this._log.trace("Requested sync should happen right away."); this.syncIfMPUnlocked(); return; } - this._log.trace("Next sync in " + Math.ceil(interval / 1000) + " sec."); + this._log.debug("Next sync in " + interval + " ms."); Utils.namedTimer(this.syncIfMPUnlocked, interval, this, "syncTimer"); // Save the next sync time in-case sync is disabled (logout/offline/etc.) @@ -389,12 +407,12 @@ let SyncScheduler = { */ scheduleAtInterval: function scheduleAtInterval(minimumInterval) { let interval = Utils.calculateBackoff(this._syncErrors, MINIMUM_BACKOFF_INTERVAL); - if (minimumInterval) + if (minimumInterval) { interval = Math.max(minimumInterval, interval); + } - let d = new Date(Date.now() + interval); - this._log.config("Starting backoff, next sync at:" + d.toString()); - + this._log.debug("Starting client-initiated backoff. Next sync in " + + interval + " ms."); this.scheduleNextSync(interval); }, @@ -414,7 +432,10 @@ let SyncScheduler = { autoConnect: function autoConnect() { if (Weave.Service._checkSetup() == STATUS_OK && !Weave.Service._checkSync()) { - Utils.nextTick(Weave.Service.sync, Weave.Service); + // Schedule a sync based on when a previous sync was scheduled. + // scheduleNextSync() will do the right thing if that time lies in + // the past. + this.scheduleNextSync(this.nextSync - Date.now()); } // Once autoConnect is called we no longer need _autoTimer. diff --git a/services/sync/modules/status.js b/services/sync/modules/status.js index eb3f94a61ed9..49349e9eaa28 100644 --- a/services/sync/modules/status.js +++ b/services/sync/modules/status.js @@ -17,6 +17,7 @@ * * Contributor(s): * Edward Lee (original author) +* Richard Newman * * Alternatively, the contents of this file may be used under the terms of either * the GNU General Public License Version 2 or later (the "GPL"), or the GNU @@ -40,36 +41,71 @@ const Cr = Components.results; const Cu = Components.utils; Cu.import("resource://services-sync/constants.js"); +Cu.import("resource://services-sync/log4moz.js"); +Cu.import("resource://gre/modules/Services.jsm"); let Status = { + _log: Log4Moz.repository.getLogger("Sync.Status"), ready: false, - get login() this._login, + get service() { + return this._service; + }, + + set service(code) { + this._log.debug("Status.service: " + this._service + " => " + code); + this._service = code; + }, + + get login() { + return this._login; + }, + set login(code) { + this._log.debug("Status.login: " + this._login + " => " + code); this._login = code; if (code == LOGIN_FAILED_NO_USERNAME || code == LOGIN_FAILED_NO_PASSWORD || - code == LOGIN_FAILED_NO_PASSPHRASE) + code == LOGIN_FAILED_NO_PASSPHRASE) { this.service = CLIENT_NOT_CONFIGURED; - else if (code != LOGIN_SUCCEEDED) + } else if (code != LOGIN_SUCCEEDED) { this.service = LOGIN_FAILED; - else + } else { this.service = STATUS_OK; + } + }, + + get sync() { + return this._sync; }, - get sync() this._sync, set sync(code) { + this._log.debug("Status.sync: " + this._sync + " => " + code); this._sync = code; this.service = code == SYNC_SUCCEEDED ? STATUS_OK : SYNC_FAILED; }, - get engines() this._engines, + get engines() { + return this._engines; + }, + set engines([name, code]) { + this._log.debug("Status for engine " + name + ": " + code); this._engines[name] = code; - if (code != ENGINE_SUCCEEDED) + if (code != ENGINE_SUCCEEDED) { this.service = SYNC_FAILED_PARTIAL; + } + }, + + // Implement toString because adding a logger introduces a cyclic object + // value, so we can't trivially debug-print Status as JSON. + toString: function toString() { + return ""; }, checkSetup: function checkSetup() { @@ -92,8 +128,9 @@ let Status = { Cu.import("resource://services-sync/record.js"); if (!Utils.mpLocked()) { let id = ID.get("WeaveID"); - if (!id) + if (!id) { id = ID.set("WeaveID", new Identity(PWDMGR_PASSWORD_REALM, username)); + } if (!id.password) { Status.login = LOGIN_FAILED_NO_PASSWORD; @@ -101,9 +138,10 @@ let Status = { } id = ID.get("WeaveCryptoID"); - if (!id) + if (!id) { id = ID.set("WeaveCryptoID", new SyncKeyBundle(PWDMGR_PASSPHRASE_REALM, username)); + } if (!id.keyStr) { Status.login = LOGIN_FAILED_NO_PASSPHRASE; @@ -118,15 +156,27 @@ let Status = { this.backoffInterval = 0; this.minimumNextSync = 0; }, + resetSync: function resetSync() { + // Logger setup. + let logPref = PREFS_BRANCH + "log.logger.status"; + let logLevel = "Trace"; + try { + logLevel = Services.prefs.getCharPref(logPref); + } catch (ex) { + // Use default. + } + this._log.level = Log4Moz.Level[logLevel]; + + this._log.info("Resetting Status."); this.service = STATUS_OK; this._login = LOGIN_SUCCEEDED; this._sync = SYNC_SUCCEEDED; this._engines = {}; this.partial = false; - }, + } }; -// Initialize various status values +// Initialize various status values. Status.resetBackoff(); Status.resetSync(); diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index 4348743a9358..56e715fc17ef 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -9,10 +9,10 @@ pref("services.sync.syncKeyHelpURL", "https://services.mozilla.com/help/synckey" pref("services.sync.lastversion", "firstrun"); pref("services.sync.sendVersionInfo", true); -pref("services.sync.scheduler.singleDeviceInterval", 3600); // 1 hour +pref("services.sync.scheduler.singleDeviceInterval", 86400); // 1 day pref("services.sync.scheduler.idleInterval", 3600); // 1 hour -pref("services.sync.scheduler.activeInterval", 300); // 5 minutes -pref("services.sync.scheduler.immediateInterval", 60); // 1 minute +pref("services.sync.scheduler.activeInterval", 600); // 10 minutes +pref("services.sync.scheduler.immediateInterval", 90); // 1.5 minutes pref("services.sync.scheduler.idleTime", 300); // 5 minutes pref("services.sync.errorhandler.networkFailureReportTimeout", 604800); // 1 week @@ -38,6 +38,7 @@ pref("services.sync.log.appender.file.logOnSuccess", false); pref("services.sync.log.appender.file.maxErrorAge", 864000); // 10 days pref("services.sync.log.rootLogger", "Debug"); pref("services.sync.log.logger.service.main", "Debug"); +pref("services.sync.log.logger.status", "Debug"); pref("services.sync.log.logger.authenticator", "Debug"); pref("services.sync.log.logger.network.resources", "Debug"); pref("services.sync.log.logger.service.jpakeclient", "Debug"); diff --git a/services/sync/tests/unit/head_http_server.js b/services/sync/tests/unit/head_http_server.js index 29c601a925b9..9b72018c0485 100644 --- a/services/sync/tests/unit/head_http_server.js +++ b/services/sync/tests/unit/head_http_server.js @@ -699,6 +699,27 @@ SyncServer.prototype = { return wbo; }, + /** + * Delete all of the collections for the named user. + * + * @param username + * The name of the affected user. + * + * @return a timestamp. + */ + deleteCollections: function deleteCollections(username) { + if (!(username in this.users)) { + throw new Error("Unknown user."); + } + let userCollections = this.users[username].collections; + for each (let [name, coll] in Iterator(userCollections)) { + this._log.trace("Bulk deleting " + name + " for " + username + "..."); + coll.delete({}); + } + this.users[username].collections = {}; + return this.timestamp(); + }, + /** * Simple accessor to allow collective binding and abbreviation of a bunch of * methods. Yay! @@ -716,11 +737,13 @@ SyncServer.prototype = { let modified = function (collectionName) { return collection(collectionName).timestamp; } + let deleteCollections = this.deleteCollections.bind(this, username); return { - collection: collection, - createCollection: createCollection, - createContents: createContents, - modified: modified + collection: collection, + createCollection: createCollection, + createContents: createContents, + deleteCollections: deleteCollections, + modified: modified }; }, @@ -741,9 +764,9 @@ SyncServer.prototype = { * server code. * * Path: [all, version, username, first, rest] - * Storage: [all, collection, id?] + * Storage: [all, collection?, id?] */ - pathRE: /^\/([0-9]+(?:\.[0-9]+)?)\/([-._a-zA-Z0-9]+)\/([^\/]+)\/(.*)$/, + pathRE: /^\/([0-9]+(?:\.[0-9]+)?)\/([-._a-zA-Z0-9]+)(?:\/([^\/]+)(?:\/(.+))?)?$/, storageRE: /^([-_a-zA-Z0-9]+)(?:\/([-_a-zA-Z0-9]+)\/?)?$/, defaultHeaders: {}, @@ -815,6 +838,25 @@ SyncServer.prototype = { */ toplevelHandlers: { "storage": function handleStorage(handler, req, resp, version, username, rest) { + let respond = this.respond.bind(this, req, resp); + if (!rest || !rest.length) { + this._log.debug("SyncServer: top-level storage " + + req.method + " request."); + + // TODO: verify if this is spec-compliant. + if (req.method != "DELETE") { + respond(405, "Method Not Allowed", "[]", {"Allow": "DELETE"}); + return; + } + + // Delete all collections and track the timestamp for the response. + let timestamp = this.user(username).deleteCollections(); + + // Return timestamp and OK for deletion. + respond(200, "OK", JSON.stringify(timestamp)); + return; + } + let match = this.storageRE.exec(rest); if (!match) { this._log.warn("SyncServer: Unknown storage operation " + rest); @@ -822,10 +864,13 @@ SyncServer.prototype = { } let [all, collection, wboID] = match; let coll = this.getCollection(username, collection); - let respond = this.respond.bind(this, req, resp); switch (req.method) { case "GET": if (!coll) { + if (wboID) { + respond(404, "Not found", "Not found"); + return; + } // *cries inside*: Bug 687299. respond(200, "OK", "[]"); return; @@ -850,9 +895,9 @@ SyncServer.prototype = { let wbo = coll.wbo(wboID); if (wbo) { wbo.delete(); + this.callback.onItemDeleted(username, collection, wboID); } respond(200, "OK", "{}"); - this.callback.onItemDeleted(username, collectin, wboID); return; } coll.collectionHandler(req, resp); diff --git a/services/sync/tests/unit/test_errorhandler_filelog.js b/services/sync/tests/unit/test_errorhandler_filelog.js index 57836211f276..305cce76798e 100644 --- a/services/sync/tests/unit/test_errorhandler_filelog.js +++ b/services/sync/tests/unit/test_errorhandler_filelog.js @@ -2,6 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ Cu.import("resource://services-sync/service.js"); +Cu.import("resource://services-sync/policies.js"); Cu.import("resource://services-sync/util.js"); Cu.import("resource://services-sync/log4moz.js"); @@ -15,15 +16,23 @@ const PROLONGED_ERROR_DURATION = (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000; function setLastSync(lastSyncValue) { - Svc.Prefs.set("lastSync", (new Date(Date.now() - - lastSyncValue)).toString()); + Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString()); } function run_test() { + initTestLogging("Trace"); + + Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.SyncScheduler").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.ErrorHandler").level = Log4Moz.Level.Trace; + run_next_test(); } add_test(function test_noOutput() { + // Ensure that the log appender won't print anything. + ErrorHandler._logAppender.level = Log4Moz.Level.Fatal + 1; + // Clear log output from startup. Svc.Prefs.set("log.appender.file.logOnSuccess", false); Svc.Obs.notify("weave:service:sync:finish"); @@ -34,6 +43,7 @@ add_test(function test_noOutput() { Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + ErrorHandler._logAppender.level = Log4Moz.Level.Trace; Svc.Prefs.resetBranch(""); run_next_test(); }); diff --git a/services/sync/tests/unit/test_httpd_sync_server.js b/services/sync/tests/unit/test_httpd_sync_server.js index d95f68029a8b..d2bada235109 100644 --- a/services/sync/tests/unit/test_httpd_sync_server.js +++ b/services/sync/tests/unit/test_httpd_sync_server.js @@ -1,28 +1,61 @@ function run_test() { + Log4Moz.repository.getLogger("Sync.Test.Server").level = Log4Moz.Level.Trace; + initTestLogging(); run_next_test(); } add_test(function test_creation() { // Explicit callback for this one. - let s = new SyncServer({ + let server = new SyncServer({ __proto__: SyncServerCallback, }); - do_check_true(!!s); // Just so we have a check. - s.start(null, function () { - _("Started on " + s.port); - s.stop(run_next_test); + do_check_true(!!server); // Just so we have a check. + server.start(null, function () { + _("Started on " + server.port); + server.stop(run_next_test); }); }); add_test(function test_url_parsing() { - let s = new SyncServer(); - let parts = s.pathRE.exec("/1.1/johnsmith/storage/crypto/keys"); + let server = new SyncServer(); + + // Check that we can parse a WBO URI. + let parts = server.pathRE.exec("/1.1/johnsmith/storage/crypto/keys"); let [all, version, username, first, rest] = parts; + do_check_eq(all, "/1.1/johnsmith/storage/crypto/keys"); do_check_eq(version, "1.1"); do_check_eq(username, "johnsmith"); do_check_eq(first, "storage"); do_check_eq(rest, "crypto/keys"); - do_check_eq(null, s.pathRE.exec("/nothing/else")); + do_check_eq(null, server.pathRE.exec("/nothing/else")); + + // Check that we can parse a collection URI. + parts = server.pathRE.exec("/1.1/johnsmith/storage/crypto"); + let [all, version, username, first, rest] = parts; + do_check_eq(all, "/1.1/johnsmith/storage/crypto"); + do_check_eq(version, "1.1"); + do_check_eq(username, "johnsmith"); + do_check_eq(first, "storage"); + do_check_eq(rest, "crypto"); + + // We don't allow trailing slash on storage URI. + parts = server.pathRE.exec("/1.1/johnsmith/storage/"); + do_check_eq(parts, undefined); + + // storage alone is a valid request. + parts = server.pathRE.exec("/1.1/johnsmith/storage"); + let [all, version, username, first, rest] = parts; + do_check_eq(all, "/1.1/johnsmith/storage"); + do_check_eq(version, "1.1"); + do_check_eq(username, "johnsmith"); + do_check_eq(first, "storage"); + do_check_eq(rest, undefined); + + parts = server.storageRE.exec("storage"); + let [all, storage, collection, id] = parts; + do_check_eq(all, "storage"); + do_check_eq(collection, undefined); + run_next_test(); }); @@ -35,19 +68,19 @@ function localRequest(path) { } add_test(function test_basic_http() { - let s = new SyncServer(); - s.registerUser("john", "password"); - do_check_true(s.userExists("john")); - s.start(8080, function () { - _("Started on " + s.port); - do_check_eq(s.port, 8080); + let server = new SyncServer(); + server.registerUser("john", "password"); + do_check_true(server.userExists("john")); + server.start(8080, function () { + _("Started on " + server.port); + do_check_eq(server.port, 8080); Utils.nextTick(function () { let req = localRequest("/1.1/john/storage/crypto/keys"); _("req is " + req); req.get(function (err) { do_check_eq(null, err); Utils.nextTick(function () { - s.stop(run_next_test); + server.stop(run_next_test); }); }); }); @@ -55,7 +88,7 @@ add_test(function test_basic_http() { }); add_test(function test_info_collections() { - let s = new SyncServer({ + let server = new SyncServer({ __proto__: SyncServerCallback }); function responseHasCorrectHeaders(r) { @@ -64,9 +97,9 @@ add_test(function test_info_collections() { do_check_true("x-weave-timestamp" in r.headers); } - s.registerUser("john", "password"); - s.start(8080, function () { - do_check_eq(s.port, 8080); + server.registerUser("john", "password"); + server.start(8080, function () { + do_check_eq(server.port, 8080); Utils.nextTick(function () { let req = localRequest("/1.1/john/info/collections"); req.get(function (err) { @@ -87,14 +120,14 @@ add_test(function test_info_collections() { req.get(function (err) { do_check_eq(null, err); responseHasCorrectHeaders(this.response); - let expectedColl = s.getCollection("john", "crypto"); + let expectedColl = server.getCollection("john", "crypto"); do_check_true(!!expectedColl); let modified = expectedColl.timestamp; do_check_true(modified > 0); do_check_eq(putResponseBody, modified); do_check_eq(JSON.parse(this.response.body).crypto, modified); Utils.nextTick(function () { - s.stop(run_next_test); + server.stop(run_next_test); }); }); } @@ -109,14 +142,16 @@ add_test(function test_info_collections() { add_test(function test_storage_request() { let keysURL = "/1.1/john/storage/crypto/keys?foo=bar"; let foosURL = "/1.1/john/storage/crypto/foos"; - let s = new SyncServer(); - let creation = s.timestamp(); - s.registerUser("john", "password"); + let storageURL = "/1.1/john/storage"; - s.createContents("john", { + let server = new SyncServer(); + let creation = server.timestamp(); + server.registerUser("john", "password"); + + server.createContents("john", { crypto: {foos: {foo: "bar"}} }); - let coll = s.user("john").collection("crypto"); + let coll = server.user("john").collection("crypto"); do_check_true(!!coll); _("We're tracking timestamps."); @@ -145,24 +180,92 @@ add_test(function test_storage_request() { Utils.nextTick(next); }); } - s.start(8080, function () { - retrieveWBONotExists( - retrieveWBOExists.bind(this, function () { - s.stop(run_next_test); - }) - ); - }); + function deleteWBONotExists(next) { + let req = localRequest(keysURL); + server.callback.onItemDeleted = function (username, collection, wboID) { + do_throw("onItemDeleted should not have been called."); + }; + + req.delete(function (err) { + _("Body is " + this.response.body); + _("Modified is " + this.response.newModified); + do_check_eq(this.response.status, 200); + delete server.callback.onItemDeleted; + Utils.nextTick(next); + }); + } + function deleteWBOExists(next) { + let req = localRequest(foosURL); + server.callback.onItemDeleted = function (username, collection, wboID) { + _("onItemDeleted called for " + collection + "/" + wboID); + delete server.callback.onItemDeleted; + do_check_eq(username, "john"); + do_check_eq(collection, "crypto"); + do_check_eq(wboID, "foos"); + Utils.nextTick(next); + }; + + req.delete(function (err) { + _("Body is " + this.response.body); + _("Modified is " + this.response.newModified); + do_check_eq(this.response.status, 200); + }); + } + function deleteStorage(next) { + _("Testing DELETE on /storage."); + let now = server.timestamp(); + _("Timestamp: " + now); + let req = localRequest(storageURL); + req.delete(function (err) { + _("Body is " + this.response.body); + _("Modified is " + this.response.newModified); + let parsedBody = JSON.parse(this.response.body); + do_check_true(parsedBody >= now); + do_check_empty(server.users["john"].collections); + Utils.nextTick(next); + }); + } + function getStorageFails(next) { + _("Testing that GET on /storage fails."); + let req = localRequest(storageURL); + req.get(function (err) { + do_check_eq(this.response.status, 405); + do_check_eq(this.response.headers["allow"], "DELETE"); + Utils.nextTick(next); + }); + } + function getMissingCollectionWBO(next) { + _("Testing that fetching a WBO from an on-existent collection 404s."); + let req = localRequest(storageURL + "/foobar/baz"); + req.get(function (err) { + do_check_eq(this.response.status, 404); + Utils.nextTick(next); + }); + } + + server.start(8080, + Async.chain( + retrieveWBONotExists, + retrieveWBOExists, + deleteWBOExists, + deleteWBONotExists, + getStorageFails, + getMissingCollectionWBO, + deleteStorage, + server.stop.bind(server), + run_next_test + )); }); add_test(function test_x_weave_records() { - let s = new SyncServer(); - s.registerUser("john", "password"); + let server = new SyncServer(); + server.registerUser("john", "password"); - s.createContents("john", { + server.createContents("john", { crypto: {foos: {foo: "bar"}, bars: {foo: "baz"}} }); - s.start(8080, function () { + server.start(8080, function () { let wbo = localRequest("/1.1/john/storage/crypto/foos"); wbo.get(function (err) { // WBO fetches don't have one. @@ -171,7 +274,7 @@ add_test(function test_x_weave_records() { col.get(function (err) { // Collection fetches do. do_check_eq(this.response.headers["x-weave-records"], "2"); - s.stop(run_next_test); + server.stop(run_next_test); }); }); }); diff --git a/services/sync/tests/unit/test_service_detect_upgrade.js b/services/sync/tests/unit/test_service_detect_upgrade.js index 32b54cd732fd..b120e6a90d18 100644 --- a/services/sync/tests/unit/test_service_detect_upgrade.js +++ b/services/sync/tests/unit/test_service_detect_upgrade.js @@ -283,7 +283,7 @@ add_test(function v5_upgrade() { catch (e) { _("Exception: " + e); } - _("Status: " + JSON.stringify(Status)); + _("Status: " + Status); do_check_false(Weave.Service.isLoggedIn); do_check_eq(VERSION_OUT_OF_DATE, Status.sync); diff --git a/services/sync/tests/unit/test_syncscheduler.js b/services/sync/tests/unit/test_syncscheduler.js index c33149d1a2ea..ec5b93824226 100644 --- a/services/sync/tests/unit/test_syncscheduler.js +++ b/services/sync/tests/unit/test_syncscheduler.js @@ -60,6 +60,34 @@ function setUp() { return serverKeys.upload(Service.cryptoKeysURL).success; } +function cleanUpAndGo(server) { + Utils.nextTick(function () { + Service.startOver(); + if (server) { + server.stop(run_next_test); + } else { + run_next_test(); + } + }); +} + +let timer; +function waitForZeroTimer(callback) { + // First wait >100ms (nsITimers can take up to that much time to fire, so + // we can account for the timer in delayedAutoconnect) and then two event + // loop ticks (to account for the Utils.nextTick() in autoConnect). + let ticks = 2; + function wait() { + if (ticks) { + ticks -= 1; + Utils.nextTick(wait); + return; + } + callback(); + } + timer = Utils.namedTimer(wait, 150, {}, "timer"); +} + function run_test() { initTestLogging("Trace"); @@ -77,6 +105,26 @@ add_test(function test_prefAttributes() { const SCORE = 2718; const TIMESTAMP1 = 1275493471649; + _("The 'nextSync' attribute stores a millisecond timestamp rounded down to the nearest second."); + do_check_eq(SyncScheduler.nextSync, 0); + SyncScheduler.nextSync = TIMESTAMP1; + do_check_eq(SyncScheduler.nextSync, Math.floor(TIMESTAMP1 / 1000) * 1000); + + _("'syncInterval' defaults to singleDeviceInterval."); + do_check_eq(Svc.Prefs.get('syncInterval'), undefined); + do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval); + + _("'syncInterval' corresponds to a preference setting."); + SyncScheduler.syncInterval = INTERVAL; + do_check_eq(SyncScheduler.syncInterval, INTERVAL); + do_check_eq(Svc.Prefs.get('syncInterval'), INTERVAL); + + _("'syncThreshold' corresponds to preference, defaults to SINGLE_USER_THRESHOLD"); + do_check_eq(Svc.Prefs.get('syncThreshold'), undefined); + do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD); + SyncScheduler.syncThreshold = THRESHOLD; + do_check_eq(SyncScheduler.syncThreshold, THRESHOLD); + _("'globalScore' corresponds to preference, defaults to zero."); do_check_eq(Svc.Prefs.get('globalScore'), undefined); do_check_eq(SyncScheduler.globalScore, 0); @@ -137,10 +185,7 @@ add_test(function test_updateClientMode() { do_check_false(SyncScheduler.numClients > 1); do_check_false(SyncScheduler.idle); - Svc.Prefs.resetBranch(""); - SyncScheduler.setDefaults(); - Clients.resetClient(); - run_next_test(); + cleanUpAndGo(); }); add_test(function test_masterpassword_locked_retry_interval() { @@ -176,8 +221,7 @@ add_test(function test_masterpassword_locked_retry_interval() { Service.verifyLogin = Service._verifyLogin; SyncScheduler.scheduleAtInterval = SyncScheduler._scheduleAtInterval; - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_calculateBackoff() { @@ -197,14 +241,23 @@ add_test(function test_calculateBackoff() { do_check_eq(backoffInterval, MAXIMUM_BACKOFF_INTERVAL + 10); - Status.backoffInterval = 0; - Svc.Prefs.resetBranch(""); - SyncScheduler.setDefaults(); - Clients.resetClient(); - run_next_test(); + cleanUpAndGo(); }); -add_test(function test_scheduleNextSync_noBackoff() { +add_test(function test_scheduleNextSync_nowOrPast() { + Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() { + Svc.Obs.remove("weave:service:sync:finish", onSyncFinish); + cleanUpAndGo(server); + }); + + let server = sync_httpd_setup(); + setUp(); + + // We're late for a sync... + SyncScheduler.scheduleNextSync(-1); +}); + +add_test(function test_scheduleNextSync_future_noBackoff() { _("scheduleNextSync() uses the current syncInterval if no interval is provided."); // Test backoffInterval is 0 as expected. do_check_eq(Status.backoffInterval, 0); @@ -250,15 +303,14 @@ add_test(function test_scheduleNextSync_noBackoff() { do_check_true(SyncScheduler.nextSync <= Date.now() + 1); do_check_eq(SyncScheduler.syncTimer.delay, 1); - SyncScheduler.syncTimer.clear(); - Service.startOver(); - run_next_test(); + cleanUpAndGo(); }); -add_test(function test_scheduleNextSync_backoff() { +add_test(function test_scheduleNextSync_future_backoff() { _("scheduleNextSync() will honour backoff in all scheduling requests."); - Status.backoffInterval = 7337000; - do_check_true(Status.backoffInterval > SyncScheduler.syncInterval); + // Let's take a backoff interval that's bigger than the default sync interval. + const BACKOFF = 7337; + Status.backoffInterval = SyncScheduler.syncInterval + BACKOFF; _("Test setting sync interval when nextSync == 0"); SyncScheduler.nextSync = 0; @@ -296,14 +348,12 @@ add_test(function test_scheduleNextSync_backoff() { do_check_true(SyncScheduler.nextSync <= Date.now() + requestedInterval); do_check_eq(SyncScheduler.syncTimer.delay, requestedInterval); - // Request a sync at the smallest possible number. + // Request a sync at the smallest possible interval (0 triggers now). SyncScheduler.scheduleNextSync(1); do_check_true(SyncScheduler.nextSync <= Date.now() + Status.backoffInterval); do_check_eq(SyncScheduler.syncTimer.delay, Status.backoffInterval); - SyncScheduler.syncTimer.clear(); - Service.startOver(); - run_next_test(); + cleanUpAndGo(); }); add_test(function test_handleSyncError() { @@ -361,8 +411,7 @@ add_test(function test_handleSyncError() { do_check_true(Status.enforceBackoff); SyncScheduler.syncTimer.clear(); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_client_sync_finish_updateClientMode() { @@ -396,16 +445,15 @@ add_test(function test_client_sync_finish_updateClientMode() { do_check_false(SyncScheduler.numClients > 1); do_check_false(SyncScheduler.idle); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); -add_test(function test_autoconnect() { +add_test(function test_autoconnect_nextSync_past() { + // nextSync will be 0 by default, so it's way in the past. + Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() { Svc.Obs.remove("weave:service:sync:finish", onSyncFinish); - - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); let server = sync_httpd_setup(); @@ -414,6 +462,33 @@ add_test(function test_autoconnect() { SyncScheduler.delayedAutoConnect(0); }); +add_test(function test_autoconnect_nextSync_future() { + let previousSync = Date.now() + SyncScheduler.syncInterval / 2; + SyncScheduler.nextSync = previousSync; + // nextSync rounds to the nearest second. + let expectedSync = SyncScheduler.nextSync; + let expectedInterval = expectedSync - Date.now() - 1000; + + // Ensure we don't actually try to sync (or log in for that matter). + function onLoginStart() { + do_throw("Should not get here!"); + } + Svc.Obs.add("weave:service:login:start", onLoginStart); + + waitForZeroTimer(function () { + do_check_eq(SyncScheduler.nextSync, expectedSync); + do_check_true(SyncScheduler.syncTimer.delay >= expectedInterval); + + Svc.Obs.remove("weave:service:login:start", onLoginStart); + cleanUpAndGo(); + }); + + Service.username = "johndoe"; + Service.password = "ilovejane"; + Service.passphrase = "abcdeabcdeabcdeabcdeabcdea"; + SyncScheduler.delayedAutoConnect(0); +}); + add_test(function test_autoconnect_mp_locked() { let server = sync_httpd_setup(); setUp(); @@ -425,6 +500,7 @@ add_test(function test_autoconnect_mp_locked() { let origPP = Service.__lookupGetter__("passphrase"); delete Service.passphrase; Service.__defineGetter__("passphrase", function() { + _("Faking Master Password entry cancelation."); throw "User canceled Master Password entry"; }); @@ -439,15 +515,13 @@ add_test(function test_autoconnect_mp_locked() { delete Service.passphrase; Service.__defineGetter__("passphrase", origPP); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); }); SyncScheduler.delayedAutoConnect(0); }); -let timer; add_test(function test_no_autoconnect_during_wizard() { let server = sync_httpd_setup(); setUp(); @@ -461,22 +535,10 @@ add_test(function test_no_autoconnect_during_wizard() { } Svc.Obs.add("weave:service:login:start", onLoginStart); - // First wait >100ms (nsITimers can take up to that much time to fire, so - // we can account for the timer in delayedAutoconnect) and then two event - // loop ticks (to account for the Utils.nextTick() in autoConnect). - let ticks = 2; - function wait() { - if (ticks) { - ticks -= 1; - Utils.nextTick(wait); - return; - } + waitForZeroTimer(function () { Svc.Obs.remove("weave:service:login:start", onLoginStart); - - Service.startOver(); - server.stop(run_next_test); - } - timer = Utils.namedTimer(wait, 150, {}, "timer"); + cleanUpAndGo(server); + }); SyncScheduler.delayedAutoConnect(0); }); @@ -490,25 +552,14 @@ add_test(function test_no_autoconnect_status_not_ok() { } Svc.Obs.add("weave:service:login:start", onLoginStart); - // First wait >100ms (nsITimers can take up to that much time to fire, so - // we can account for the timer in delayedAutoconnect) and then two event - // loop ticks (to account for the Utils.nextTick() in autoConnect). - let ticks = 2; - function wait() { - if (ticks) { - ticks -= 1; - Utils.nextTick(wait); - return; - } + waitForZeroTimer(function () { Svc.Obs.remove("weave:service:login:start", onLoginStart); do_check_eq(Status.service, CLIENT_NOT_CONFIGURED); do_check_eq(Status.login, LOGIN_FAILED_NO_USERNAME); - - Service.startOver(); - server.stop(run_next_test); - } - timer = Utils.namedTimer(wait, 150, {}, "timer"); + + cleanUpAndGo(server); + }); SyncScheduler.delayedAutoConnect(0); }); @@ -516,9 +567,7 @@ add_test(function test_no_autoconnect_status_not_ok() { add_test(function test_autoconnectDelay_pref() { Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() { Svc.Obs.remove("weave:service:sync:finish", onSyncFinish); - - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); Svc.Prefs.set("autoconnectDelay", 1); @@ -550,8 +599,7 @@ add_test(function test_idle_adjustSyncInterval() { do_check_eq(SyncScheduler.idle, true); do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval); - SyncScheduler.setDefaults(); - run_next_test(); + cleanUpAndGo(); }); add_test(function test_back_triggersSync() { @@ -568,9 +616,7 @@ add_test(function test_back_triggersSync() { // succeed. We just want to ensure that it was attempted. Svc.Obs.add("weave:service:login:error", function onLoginError() { Svc.Obs.remove("weave:service:login:error", onLoginError); - SyncScheduler.syncTimer.clear(); - SyncScheduler.setDefaults(); - run_next_test(); + cleanUpAndGo(); }); // Send a 'back' event to trigger sync soonish. @@ -582,7 +628,8 @@ add_test(function test_back_triggersSync_observesBackoff() { do_check_false(SyncScheduler.idle); // Set up: Set backoff, define 2 clients and put the system in idle. - Status.backoffInterval = 7337000; + const BACKOFF = 7337; + Status.backoffInterval = SyncScheduler.idleInterval + BACKOFF; SyncScheduler.numClients = 2; SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime")); do_check_eq(SyncScheduler.idle, true); @@ -598,9 +645,7 @@ add_test(function test_back_triggersSync_observesBackoff() { do_check_true(SyncScheduler.nextSync <= Date.now() + Status.backoffInterval); do_check_eq(SyncScheduler.syncTimer.delay, Status.backoffInterval); - SyncScheduler.syncTimer.clear(); - SyncScheduler.setDefaults(); - run_next_test(); + cleanUpAndGo(); }, IDLE_OBSERVER_BACK_DELAY * 1.5, {}, "timer"); // Send a 'back' event to try to trigger sync soonish. @@ -629,8 +674,7 @@ add_test(function test_back_debouncing() { timer = Utils.namedTimer(function () { Svc.Obs.remove("weave:service:login:start", onLoginStart); - SyncScheduler.setDefaults(); - run_next_test(); + cleanUpAndGo(); }, IDLE_OBSERVER_BACK_DELAY * 1.5, {}, "timer"); }); @@ -646,10 +690,7 @@ add_test(function test_no_sync_node() { do_check_eq(Status.sync, NO_SYNC_NODE_FOUND); do_check_eq(SyncScheduler.syncTimer.delay, NO_SYNC_NODE_INTERVAL); - // Clean up. - Service.startOver(); - Status.resetSync(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_sync_failed_partial_500s() { @@ -676,9 +717,7 @@ add_test(function test_sync_failed_partial_500s() { do_check_true(SyncScheduler.nextSync <= (Date.now() + maxInterval)); do_check_true(SyncScheduler.syncTimer.delay <= maxInterval); - Status.resetSync(); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_sync_failed_partial_400s() { @@ -708,9 +747,7 @@ add_test(function test_sync_failed_partial_400s() { do_check_true(SyncScheduler.nextSync <= (Date.now() + SyncScheduler.activeInterval)); do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval); - Status.resetSync(); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_sync_X_Weave_Backoff() { @@ -765,8 +802,7 @@ add_test(function test_sync_X_Weave_Backoff() { do_check_true(SyncScheduler.nextSync >= Date.now() + minimumExpectedDelay); do_check_true(SyncScheduler.syncTimer.delay >= minimumExpectedDelay); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); add_test(function test_sync_503_Retry_After() { @@ -825,6 +861,5 @@ add_test(function test_sync_503_Retry_After() { do_check_true(SyncScheduler.nextSync >= Date.now() + minimumExpectedDelay); do_check_true(SyncScheduler.syncTimer.delay >= minimumExpectedDelay); - Service.startOver(); - server.stop(run_next_test); + cleanUpAndGo(server); }); diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp index f36bdd778309..285264e6e86d 100644 --- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -49,6 +49,7 @@ #include "nsIClassInfo.h" #include "nsIFile.h" #include "nsILocalFile.h" +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIOutputStream.h" @@ -81,6 +82,22 @@ #define SC_WORDSIZE "8" #endif +static PRInt64 +GetStartupCacheSize() +{ + mozilla::scache::StartupCache* sc = mozilla::scache::StartupCache::GetSingleton(); + return sc ? sc->SizeOfMapping() : 0; +} + +NS_MEMORY_REPORTER_IMPLEMENT(StartupCache, + "explicit/startup-cache", + KIND_NONHEAP, + nsIMemoryReporter::UNITS_BYTES, + GetStartupCacheSize, + "Memory used to hold the startup cache. This " + "memory is backed by a file and is likely to be " + "swapped out shortly after start-up.") + namespace mozilla { namespace scache { @@ -120,7 +137,8 @@ StartupCache* StartupCache::gStartupCache; bool StartupCache::gShutdownInitiated; StartupCache::StartupCache() - : mArchive(NULL), mStartupWriteInitiated(false), mWriteThread(NULL) {} + : mArchive(NULL), mStartupWriteInitiated(false), mWriteThread(NULL), + mMemoryReporter(nsnull) { } StartupCache::~StartupCache() { @@ -134,6 +152,8 @@ StartupCache::~StartupCache() WaitOnWriteThread(); WriteToDisk(); gStartupCache = nsnull; + (void)::NS_UnregisterMemoryReporter(mMemoryReporter); + mMemoryReporter = nsnull; } nsresult @@ -206,6 +226,10 @@ StartupCache::Init() NS_WARNING("Failed to load startupcache file correctly, removing!"); InvalidateCache(); } + + mMemoryReporter = new NS_MEMORY_REPORTER_NAME(StartupCache); + (void)::NS_RegisterMemoryReporter(mMemoryReporter); + return NS_OK; } @@ -308,6 +332,12 @@ StartupCache::PutBuffer(const char* id, const char* inbuf, PRUint32 len) return ResetStartupWriteTimer(); } +PRInt64 +StartupCache::SizeOfMapping() +{ + return mArchive ? mArchive->SizeOfMapping() : 0; +} + struct CacheWriteHolder { nsCOMPtr writer; diff --git a/startupcache/StartupCache.h b/startupcache/StartupCache.h index 5f16c85546ef..d737d43c1b45 100644 --- a/startupcache/StartupCache.h +++ b/startupcache/StartupCache.h @@ -95,6 +95,8 @@ * provide some convenience in writing out data. */ +class nsIMemoryReporter; + namespace mozilla { namespace scache { @@ -148,6 +150,8 @@ public: static StartupCache* GetSingleton(); static void DeleteSingleton(); + PRInt64 SizeOfMapping(); + private: StartupCache(); ~StartupCache(); @@ -178,6 +182,8 @@ private: #ifdef DEBUG nsTHashtable mWriteObjectMap; #endif + + nsIMemoryReporter* mMemoryReporter; }; // This debug outputstream attempts to detect if clients are writing multiple diff --git a/storage/src/mozStorageAsyncStatementExecution.cpp b/storage/src/mozStorageAsyncStatementExecution.cpp index 257dbbee1a3d..667f699b8b28 100644 --- a/storage/src/mozStorageAsyncStatementExecution.cpp +++ b/storage/src/mozStorageAsyncStatementExecution.cpp @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * David Rajchenbach-Teller (added Telemetry) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -38,7 +39,6 @@ * ***** END LICENSE BLOCK ***** */ #include "nsAutoPtr.h" -#include "prtime.h" #include "sqlite3.h" @@ -53,6 +53,8 @@ #include "mozStorageStatementData.h" #include "mozStorageAsyncStatementExecution.h" +#include "mozilla/Telemetry.h" + namespace mozilla { namespace storage { @@ -235,6 +237,7 @@ AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements, , mCancelRequested(false) , mMutex(aConnection->sharedAsyncExecutionMutex) , mDBMutex(aConnection->sharedDBMutex) + , mRequestStartDate(TimeStamp::Now()) { (void)mStatements.SwapElements(aStatements); NS_ASSERTION(mStatements.Length(), "We weren't given any statements!"); @@ -357,7 +360,7 @@ bool AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) { mMutex.AssertNotCurrentThreadOwns(); - + Telemetry::AutoTimer finallySendExecutionDuration(mRequestStartDate); while (true) { // lock the sqlite mutex so sqlite3_errmsg cannot change SQLiteMutexAutoLock lockedScope(mDBMutex); @@ -365,11 +368,17 @@ AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) int rc = stepStmt(aStatement); // Stop if we have no more results. if (rc == SQLITE_DONE) + { + Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, true); return false; + } // If we got results, we can return now. if (rc == SQLITE_ROW) + { + Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, true); return true; + } // Some errors are not fatal, and we can handle them and continue. if (rc == SQLITE_BUSY) { @@ -383,6 +392,7 @@ AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement) // Set an error state. mState = ERROR; + Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, false); // Construct the error message before giving up the mutex (which we cannot // hold during the call to notifyError). diff --git a/storage/src/mozStorageAsyncStatementExecution.h b/storage/src/mozStorageAsyncStatementExecution.h index 83c22d7971ae..64dd786ad25a 100644 --- a/storage/src/mozStorageAsyncStatementExecution.h +++ b/storage/src/mozStorageAsyncStatementExecution.h @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * David Rajchenbach-Teller (added Telemetry) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -253,6 +254,13 @@ private: * about the error message, the user gets reliable error messages. */ SQLiteMutex &mDBMutex; + + /** + * The instant at which the request was started. + * + * Used by telemetry. + */ + TimeStamp mRequestStartDate; }; } // namespace storage diff --git a/testing/mochitest/chrome/Makefile.in b/testing/mochitest/chrome/Makefile.in index 029fd045a4b2..e7018f2831f7 100644 --- a/testing/mochitest/chrome/Makefile.in +++ b/testing/mochitest/chrome/Makefile.in @@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk _STATIC_FILES = test_sample.xul \ test_sanityChromeUtils.xul \ + test_sanityPluginUtils.html \ # Disabled until bug 652494 is resolved. # test_sanityException.xul \ # test_sanityException2.xul \ diff --git a/testing/mochitest/tests/test_sanityPluginUtils.html b/testing/mochitest/chrome/test_sanityPluginUtils.html similarity index 77% rename from testing/mochitest/tests/test_sanityPluginUtils.html rename to testing/mochitest/chrome/test_sanityPluginUtils.html index f23f70a3e5d2..b236c87090b8 100644 --- a/testing/mochitest/tests/test_sanityPluginUtils.html +++ b/testing/mochitest/chrome/test_sanityPluginUtils.html @@ -1,16 +1,15 @@ - Profiling test suite for PluginUtils - + - - + + diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index 3082e27cd133..64aac8246335 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -18,7 +18,6 @@ mochikit.jar: content/tests/SimpleTest/ChromeUtils.js (tests/SimpleTest/ChromeUtils.js) content/tests/SimpleTest/MozillaLogger.js (tests/SimpleTest/MozillaLogger.js) content/tests/SimpleTest/LogController.js (tests/SimpleTest/LogController.js) - content/tests/SimpleTest/PluginUtils.js (tests/SimpleTest/PluginUtils.js) content/tests/SimpleTest/setup.js (tests/SimpleTest/setup.js) content/tests/SimpleTest/SimpleTest.js (tests/SimpleTest/SimpleTest.js) content/tests/SimpleTest/test.css (tests/SimpleTest/test.css) diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 7e92d663afef..3fc079128c77 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -815,7 +815,7 @@ overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/brows options.profilePath, "mochikit@mozilla.org") # Write chrome.manifest. - with open(os.path.join(options.profilePath, "extensions", "mochikit@mozilla.org", "chrome.manifest"), "a") as mfile: + with open(os.path.join(options.profilePath, "extensions", "staged", "mochikit@mozilla.org", "chrome.manifest"), "a") as mfile: mfile.write(chrome) def copyTestsJarToProfile(self, options): diff --git a/testing/mochitest/specialpowers/content/specialpowers.js b/testing/mochitest/specialpowers/content/specialpowers.js index 2646b54c0ee7..b2805de9d35d 100644 --- a/testing/mochitest/specialpowers/content/specialpowers.js +++ b/testing/mochitest/specialpowers/content/specialpowers.js @@ -127,8 +127,9 @@ function attachSpecialPowersToWindow(aWindow) { (aWindow.parent !== null) && (aWindow.parent !== undefined) && (aWindow.parent.wrappedJSObject.SpecialPowers) && - !(aWindow.wrappedJSObject.SpecialPowers)) { - aWindow.wrappedJSObject.SpecialPowers = aWindow.parent.SpecialPowers; + !(aWindow.wrappedJSObject.SpecialPowers) && + aWindow.location.hostname == aWindow.parent.location.hostname) { + aWindow.wrappedJSObject.SpecialPowers = aWindow.parent.wrappedJSObject.SpecialPowers; } else if ((aWindow !== null) && (aWindow !== undefined) && diff --git a/testing/mochitest/tests/Makefile.in b/testing/mochitest/tests/Makefile.in index 254d30c62a8a..2e110a83e9b7 100644 --- a/testing/mochitest/tests/Makefile.in +++ b/testing/mochitest/tests/Makefile.in @@ -64,7 +64,7 @@ _TEST_FILES = \ ifneq ($(OS_TARGET),Android) # Disabled on Android for permaorange, see bug 688052 - _TEST_FILES += test_sanityPluginUtils.html \ + _TEST_FILES += \ test_sanityEventUtils.html \ test_sanitySimpletest.html endif diff --git a/testing/mochitest/tests/SimpleTest/ChromeUtils.js b/testing/mochitest/tests/SimpleTest/ChromeUtils.js index 73a1a544f4ab..41e53257dbcc 100644 --- a/testing/mochitest/tests/SimpleTest/ChromeUtils.js +++ b/testing/mochitest/tests/SimpleTest/ChromeUtils.js @@ -275,4 +275,32 @@ function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, } finally { ds.endDragSession(true); } -} +}; + +var PluginUtils = +{ + withTestPlugin : function(callback) + { + if (typeof Components == "undefined") + { + todo(false, "Not a Mozilla-based browser"); + return false; + } + + var ph = Components.classes["@mozilla.org/plugin/host;1"] + .getService(Components.interfaces.nsIPluginHost); + var tags = ph.getPluginTags(); + + // Find the test plugin + for (var i = 0; i < tags.length; i++) + { + if (tags[i].name == "Test Plug-in") + { + callback(tags[i]); + return true; + } + } + todo(false, "Need a test plugin on this platform"); + return false; + } +}; diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js index 4c542e487539..91d0f2fd9c46 100644 --- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -44,9 +44,6 @@ function sendMouseEvent(aEvent, aTarget, aWindow) { aTarget = aWindow.document.getElementById(aTarget); } - // For events to trigger the UA's default actions they need to be "trusted" - netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite'); - var event = aWindow.document.createEvent('MouseEvent'); var typeArg = aEvent.type; @@ -72,7 +69,7 @@ function sendMouseEvent(aEvent, aTarget, aWindow) { ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, buttonArg, relatedTargetArg); - aTarget.dispatchEvent(event); + SpecialPowers.dispatchEvent(aWindow, aTarget, event); } /** @@ -145,14 +142,11 @@ function __doEventDispatch(aTarget, aCharCode, aKeyCode, aHasShift) { aTarget = "target"; } - // Make our events trusted - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var event = document.createEvent("KeyEvents"); event.initKeyEvent("keydown", true, true, document.defaultView, false, false, aHasShift, false, aKeyCode, 0); - var accepted = $(aTarget).dispatchEvent(event); + var accepted = SpecialPowers.dispatchEvent(window, aTarget, event); // Preventing the default keydown action also prevents the default // keypress action. @@ -169,14 +163,14 @@ function __doEventDispatch(aTarget, aCharCode, aKeyCode, aHasShift) { if (!accepted) { event.preventDefault(); } - accepted = $(aTarget).dispatchEvent(event); + accepted = SpecialPowers.dispatchEvent(window, aTarget, event); // Always send keyup var event = document.createEvent("KeyEvents"); event.initKeyEvent("keyup", true, true, document.defaultView, false, false, aHasShift, false, aKeyCode, 0); - $(aTarget).dispatchEvent(event); + SpecialPowers.dispatchEvent(window, aTarget, event); return accepted; } diff --git a/testing/mochitest/tests/SimpleTest/Makefile.in b/testing/mochitest/tests/SimpleTest/Makefile.in index 2900692b7606..87502e97b66a 100644 --- a/testing/mochitest/tests/SimpleTest/Makefile.in +++ b/testing/mochitest/tests/SimpleTest/Makefile.in @@ -51,7 +51,6 @@ _SIMPLETEST_FILES = MozillaLogger.js \ EventUtils.js \ ChromeUtils.js \ WindowSnapshot.js \ - PluginUtils.js \ specialpowersAPI.js \ SpecialPowersObserverAPI.js \ $(DEPTH)/toolkit/content/tests/browser/common/mockObjects.js \ diff --git a/testing/mochitest/tests/SimpleTest/PluginUtils.js b/testing/mochitest/tests/SimpleTest/PluginUtils.js deleted file mode 100644 index d6535759e091..000000000000 --- a/testing/mochitest/tests/SimpleTest/PluginUtils.js +++ /dev/null @@ -1,28 +0,0 @@ -var PluginUtils = -{ - withTestPlugin : function(callback) - { - if (typeof Components == "undefined") - { - todo(false, "Not a Mozilla-based browser"); - return false; - } - - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var ph = Components.classes["@mozilla.org/plugin/host;1"] - .getService(Components.interfaces.nsIPluginHost); - var tags = ph.getPluginTags(); - - // Find the test plugin - for (var i = 0; i < tags.length; i++) - { - if (tags[i].name == "Test Plug-in") - { - callback(tags[i]); - return true; - } - } - todo(false, "Need a test plugin on this platform"); - return false; - } -}; diff --git a/testing/mochitest/tests/SimpleTest/specialpowersAPI.js b/testing/mochitest/tests/SimpleTest/specialpowersAPI.js index b662ed8c5b46..592c43365898 100644 --- a/testing/mochitest/tests/SimpleTest/specialpowersAPI.js +++ b/testing/mochitest/tests/SimpleTest/specialpowersAPI.js @@ -723,5 +723,15 @@ SpecialPowersAPI.prototype = { registerFactory); return {'cid':cid, 'originalFactory':oldFactory}; }, + + _getElement: function(aWindow, id) { + return ((typeof(id) == "string") ? + aWindow.document.getElementById(id) : id); + }, + + dispatchEvent: function(aWindow, target, event) { + var el = this._getElement(aWindow, target); + return el.dispatchEvent(event); + }, }; diff --git a/testing/tps/tps/testrunner.py b/testing/tps/tps/testrunner.py index 46cfef2d9809..046ed635f290 100644 --- a/testing/tps/tps/testrunner.py +++ b/testing/tps/tps/testrunner.py @@ -103,7 +103,10 @@ class TPSTestRunner(object): 'services.sync.log.appender.console': 'Trace', 'services.sync.log.appender.debugLog.enabled': True, 'browser.dom.window.dump.enabled': True, - 'extensions.checkCompatibility.4.0': False, + # Allow installing extensions dropped into the profile folder + 'extensions.autoDisableScopes': 10, + # Don't open a dialog to show available add-on updates + 'extensions.update.notifyUser' : False, } syncVerRe = re.compile( r"Sync version: (?P.*)\n") diff --git a/toolkit/components/places/nsPlacesExpiration.js b/toolkit/components/places/nsPlacesExpiration.js index 0bc8c02ed45e..ce1d56afc7d6 100644 --- a/toolkit/components/places/nsPlacesExpiration.js +++ b/toolkit/components/places/nsPlacesExpiration.js @@ -155,6 +155,10 @@ const SHUTDOWN_WITH_RECENT_CLEARHISTORY_TIMEOUT_SECONDS = 10; // should be analyzed again. const ANALYZE_PAGES_THRESHOLD = 100; +// If the number of pages over history limit is greater than this threshold, +// expiration will be more aggressive, to bring back history to a saner size. +const OVERLIMIT_PAGES_THRESHOLD = 1000; + const USECS_PER_DAY = 86400000000; const ANNOS_EXPIRE_POLICIES = [ { bind: "expire_days", @@ -631,16 +635,21 @@ nsPlacesExpiration.prototype = { { // Check if we are over history capacity, if so visits must be expired. this._getPagesStats((function onPagesCount(aPagesCount, aStatsCount) { - this._overLimit = aPagesCount > this._urisLimit; - let action = this._overLimit ? ACTION.TIMED_OVERLIMIT : ACTION.TIMED; + let overLimitPages = aPagesCount - this._urisLimit; + this._overLimit = overLimitPages > 0; + let action = this._overLimit ? ACTION.TIMED_OVERLIMIT : ACTION.TIMED; // If the number of pages changed significantly from the last ANALYZE // update SQLite statistics. if (Math.abs(aPagesCount - aStatsCount) >= ANALYZE_PAGES_THRESHOLD) { action = action | ACTION.TIMED_ANALYZE; } - this._expireWithActionAndLimit(action, LIMIT.SMALL); + // Adapt expiration aggressivity to the number of pages over the limit. + let limit = overLimitPages > OVERLIMIT_PAGES_THRESHOLD ? LIMIT.LARGE + : LIMIT.SMALL; + + this._expireWithActionAndLimit(action, limit); }).bind(this)); }, diff --git a/toolkit/components/remote/nsGTKRemoteService.cpp b/toolkit/components/remote/nsGTKRemoteService.cpp index 29fdac31df86..4c8c3c3026ea 100644 --- a/toolkit/components/remote/nsGTKRemoteService.cpp +++ b/toolkit/components/remote/nsGTKRemoteService.cpp @@ -113,24 +113,6 @@ static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow) return mainWidget; } -static nsGTKToolkit* GetGTKToolkit() -{ - nsCOMPtr svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID); - if (!svc) - return nsnull; - nsCOMPtr window; - svc->GetHiddenDOMWindow(getter_AddRefs(window)); - if (!window) - return nsnull; - nsIWidget* widget = GetMainWidget(window); - if (!widget) - return nsnull; - nsIToolkit* toolkit = widget->GetToolkit(); - if (!toolkit) - return nsnull; - return static_cast(toolkit); -} - NS_IMETHODIMP nsGTKRemoteService::RegisterWindow(nsIDOMWindow* aWindow) { @@ -187,7 +169,7 @@ nsGTKRemoteService::Shutdown() void nsGTKRemoteService::SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID, PRUint32 aTimestamp) { - nsGTKToolkit* toolkit = GetGTKToolkit(); + nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); if (!toolkit) return; if (!aDesktopStartupID.IsEmpty()) { diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 69e7a9f9dcf2..28078357142e 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -1005,8 +1005,9 @@ function Engine(aLocation, aSourceDataType, aIsReadOnly) { } Engine.prototype = { - // The engine's alias. - _alias: null, + // The engine's alias (can be null). Initialized to |undefined| to indicate + // not-initialized-from-engineMetadataService. + _alias: undefined, // The data describing the engine. Is either an array of bytes, for Sherlock // files, or an XML document element, for XML plugins. _data: null, @@ -2201,7 +2202,7 @@ Engine.prototype = { // nsISearchEngine get alias() { - if (this._alias === null) + if (this._alias === undefined) this._alias = engineMetadataService.getAttr(this, "alias"); return this._alias; diff --git a/toolkit/components/telemetry/Telemetry.h b/toolkit/components/telemetry/Telemetry.h index f49fdd6b129c..609574cc1459 100644 --- a/toolkit/components/telemetry/Telemetry.h +++ b/toolkit/components/telemetry/Telemetry.h @@ -83,8 +83,8 @@ base::Histogram* GetHistogramById(ID id); template class AutoTimer { public: - AutoTimer(MOZILLA_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : start(TimeStamp::Now()) + AutoTimer(TimeStamp aStart = TimeStamp::Now() MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) + : start(aStart) { MOZILLA_GUARD_OBJECT_NOTIFIER_INIT; } diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 601ddd498c6f..61c866dd87b4 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -84,6 +84,9 @@ HISTOGRAM(MEMORY_STORAGE_SQLITE, 1024, 512 * 1024, 50, EXPONENTIAL, "Memory used HISTOGRAM(MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Memory used for uncompressed, in-use content images (KB)") HISTOGRAM(MEMORY_HEAP_ALLOCATED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Heap memory allocated (KB)") HISTOGRAM(MEMORY_EXPLICIT, 1024, 1024 * 1024, 50, EXPONENTIAL, "Explicit memory allocations (KB)") +#if defined(XP_MACOSX) +HISTOGRAM(MEMORY_FREE_PURGED_PAGES_MS, 1, 1024, 10, EXPONENTIAL, "Time(ms) to purge MADV_FREE'd heap pages.") +#endif #if defined(XP_WIN) HISTOGRAM(EARLY_GLUESTARTUP_READ_OPS, 1, 100, 12, LINEAR, "ProcessIoCounters.ReadOperationCount before glue startup") HISTOGRAM(EARLY_GLUESTARTUP_READ_TRANSFER, 1, 50 * 1024, 12, EXPONENTIAL, "ProcessIoCounters.ReadTransferCount before glue startup (KB)") @@ -193,6 +196,8 @@ HISTOGRAM(MOZ_SQLITE_PLACES_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes)" HISTOGRAM(MOZ_SQLITE_COOKIES_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes)") HISTOGRAM(MOZ_SQLITE_URLCLASSIFIER_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes)") HISTOGRAM(MOZ_SQLITE_OTHER_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes)") +HISTOGRAM(MOZ_STORAGE_ASYNC_REQUESTS_MS, 1, 32768, 20, EXPONENTIAL, "mozStorage async requests completion (ms)") +HISTOGRAM(MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, 0, 1, 2, BOOLEAN, "mozStorage async requests success") HISTOGRAM(STARTUP_MEASUREMENT_ERRORS, 1, 4, 5, LINEAR, "Flags errors in startup calculation()") HISTOGRAM(NETWORK_DISK_CACHE_OPEN, 1, 10000, 10, EXPONENTIAL, "Time spent opening disk cache (ms)") HISTOGRAM(NETWORK_DISK_CACHE_TRASHRENAME, 1, 10000, 10, EXPONENTIAL, "Time spent renaming bad Cache to Cache.Trash (ms)") @@ -235,3 +240,5 @@ HISTOGRAM(THUNDERBIRD_INDEXING_RATE_MSG_PER_S, 1, 100, 20, LINEAR, "Gloda: index #endif HISTOGRAM(INNERWINDOWS_WITH_MUTATION_LISTENERS, 0, 1, 2, BOOLEAN, "Deleted or to-be-reused innerwindow which has had mutation event listeners.") +HISTOGRAM(XUL_REFLOW_MS, 1, 3000, 10, EXPONENTIAL, "xul reflows") +HISTOGRAM(XUL_INITIAL_FRAME_CONSTRUCTION, 1, 3000, 10, EXPONENTIAL, "initial xul frame construction") diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index d86a297665d0..5eca67c92c35 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -40,6 +40,7 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/LightweightThemeManager.jsm"); // When modifying the payload in incompatible ways, please bump this version number const PAYLOAD_VERSION = 1; @@ -75,9 +76,12 @@ function getLocale() { getSelectedLocale('global'); } -XPCOMUtils.defineLazyGetter(this, "Telemetry", function () { - return Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); -}); +XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", + "@mozilla.org/base/telemetry;1", + "nsITelemetry"); +XPCOMUtils.defineLazyServiceGetter(this, "idleService", + "@mozilla.org/widget/idleservice;1", + "nsIIdleService"); /** * Returns a set of histograms that can be converted into JSON @@ -188,8 +192,7 @@ function getMetadata(reason) { * @return simple measurements as a dictionary. */ function getSimpleMeasurements() { - let si = Cc["@mozilla.org/toolkit/app-startup;1"]. - getService(Ci.nsIAppStartup).getStartupInfo(); + let si = Services.startup.getStartupInfo(); var ret = { // uptime in minutes @@ -203,6 +206,7 @@ function getSimpleMeasurements() { ret[field] = si[field] - si.process } } + ret.startupInterrupted = new Number(Services.startup.interrupted); ret.js = Cc["@mozilla.org/js/xpc/XPConnect;1"] .getService(Ci.nsIJSEngineTelemetryStats) @@ -227,6 +231,54 @@ TelemetryPing.prototype = { h.add(val); }, + /** + * Descriptive metadata + * + * @param reason + * The reason for the telemetry ping, this will be included in the + * returned metadata, + * @return The metadata as a JS object + */ + getMetadata: function getMetadata(reason) { + let ai = Services.appinfo; + let ret = { + reason: reason, + OS: ai.OS, + appID: ai.ID, + appVersion: ai.version, + appName: ai.name, + appBuildID: ai.appBuildID, + platformBuildID: ai.platformBuildID, + }; + + // sysinfo fields are not always available, get what we can. + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); + let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware"]; + for each (let field in fields) { + let value; + try { + value = sysInfo.getProperty(field); + } catch (e) { + continue + } + if (field == "memsize") { + // Send RAM size in megabytes. Rounding because sysinfo doesn't + // always provide RAM in multiples of 1024. + value = Math.round(value / 1024 / 1024) + } + ret[field] = value + } + + let theme = LightweightThemeManager.currentTheme; + if (theme) + ret.persona = theme.id; + + if (this._addons) + ret.addons = this._addons; + + return ret; + }, + /** * Pull values from about:memory into corresponding histograms */ @@ -293,10 +345,11 @@ TelemetryPing.prototype = { this.gatherMemory(); let payload = { ver: PAYLOAD_VERSION, - info: getMetadata(reason), + info: this.getMetadata(reason), simpleMeasurements: getSimpleMeasurements(), histograms: getHistograms() }; + let isTestPing = (reason == "test-ping"); // Generate a unique id once per session so the server can cope with duplicate submissions. // Use a deterministic url for testing. @@ -346,7 +399,7 @@ TelemetryPing.prototype = { Services.obs.removeObserver(this, "idle-daily"); Services.obs.removeObserver(this, "cycle-collector-begin"); if (this._isIdleObserver) { - idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS); + idleService.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS); this._isIdleObserver = false; } }, @@ -402,6 +455,9 @@ TelemetryPing.prototype = { var server = this._server; switch (aTopic) { + case "Add-ons": + this._addons = aData; + break; case "profile-after-change": this.setup(); break; @@ -431,7 +487,7 @@ TelemetryPing.prototype = { // Notify that data should be gathered now, since ping will happen soon. Services.obs.notifyObservers(null, "gather-telemetry", null); // The ping happens at the first idle of length IDLE_TIMEOUT_SECONDS. - idle.addIdleObserver(this, IDLE_TIMEOUT_SECONDS); + idleService.addIdleObserver(this, IDLE_TIMEOUT_SECONDS); this._isIdleObserver = true; }).bind(this), Ci.nsIThread.DISPATCH_NORMAL); break; @@ -440,7 +496,7 @@ TelemetryPing.prototype = { // fall through case "idle": if (this._isIdleObserver) { - idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS); + idleService.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS); this._isIdleObserver = false; } this.send(aTopic == "idle" ? "idle-daily" : aTopic, server); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js index 95f7cb0c7035..4ba4d31e3a77 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js @@ -10,6 +10,7 @@ do_load_httpd_js(); Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/LightweightThemeManager.jsm"); const PATH = "/submit/telemetry/test-ping"; const SERVER = "http://localhost:4444"; @@ -21,6 +22,7 @@ const BinaryInputStream = Components.Constructor( "setInputStream"); var httpserver = new nsHttpServer(); +var gFinished = false; function telemetry_ping () { const TelemetryPing = Cc["@mozilla.org/base/telemetry-ping;1"].getService(Ci.nsIObserver); @@ -43,34 +45,20 @@ function telemetryObserver(aSubject, aTopic, aData) { httpserver.registerPathHandler(PATH, checkHistograms); const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); Telemetry.newHistogram(IGNORE_HISTOGRAM, 1, 2, 3, Telemetry.HISTOGRAM_BOOLEAN); + Services.startup.interrupted = true; telemetry_ping(); } -function run_test() { - createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); - Services.obs.addObserver(nonexistentServerObserver, "telemetry-test-xhr-complete", false); - telemetry_ping(); - // spin the event loop - do_test_pending(); -} - -function readBytesFromInputStream(inputStream, count) { - if (!count) { - count = inputStream.available(); - } - return new BinaryInputStream(inputStream).readBytes(count); -} - function checkHistograms(request, response) { // do not need the http server anymore httpserver.stop(do_test_finished); - let s = request.bodyInputStream + let s = request.bodyInputStream; let payload = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON) - .decode(readBytesFromInputStream(s)) + .decodeFromStream(s, s.available()); do_check_eq(request.getHeader("content-type"), "application/json; charset=UTF-8"); do_check_true(payload.simpleMeasurements.uptime >= 0) - + do_check_true(payload.simpleMeasurements.startupInterrupted === 1); // get rid of the non-deterministic field const expected_info = { reason: "test-ping", @@ -102,6 +90,7 @@ function checkHistograms(request, response) { let tc = payload.histograms[TELEMETRY_SUCCESS] do_check_eq(uneval(tc), uneval(expected_tc)); + gFinished = true; } // copied from toolkit/mozapps/extensions/test/xpcshell/head_addons.js @@ -152,3 +141,34 @@ function createAppInfo(id, name, version, platformVersion) { registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", XULAPPINFO_CONTRACTID, XULAppInfoFactory); } + +function dummyTheme(id) { + return { + id: id, + name: Math.random().toString(), + headerURL: "http://lwttest.invalid/a.png", + footerURL: "http://lwttest.invalid/b.png", + textcolor: Math.random().toString(), + accentcolor: Math.random().toString() + }; +} + +function run_test() { + // Addon manager needs a profile directory + do_get_profile(); + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + // try to make LightweightThemeManager do stuff + let gInternalManager = Cc["@mozilla.org/addons/integration;1"] + .getService(Ci.nsIObserver) + .QueryInterface(Ci.nsITimerCallback); + + gInternalManager.observe(null, "addons-startup", null); + LightweightThemeManager.currentTheme = dummyTheme("1234"); + + Services.obs.addObserver(nonexistentServerObserver, "telemetry-test-xhr-complete", false); + telemetry_ping(); + // spin the event loop + do_test_pending(); + // ensure that test runs to completion + do_register_cleanup(function () do_check_true(gFinished)) + } diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 0270a6acdab0..860093fca194 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -1430,7 +1430,7 @@ nsUrlClassifierDBService::CheckClean(const nsACString &spec, rv = KeyedHash(fragkey, hostprefix, prefixkey, &codedkey); NS_ENSURE_SUCCESS(rv, rv); - bool found; + bool found = false; bool ready = false; /* opportunistic probe */ rv = mPrefixSet->Probe(codedkey, prefixkey, &ready, &found); NS_ENSURE_SUCCESS(rv, rv); diff --git a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp index d7a15eea8d57..0196ac760541 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp @@ -278,6 +278,8 @@ nsUrlClassifierPrefixSet::Probe(PRUint32 aPrefix, PRUint32 aKey, { MutexAutoLock lock(mPrefixSetLock); + *aFound = false; + // We might have raced here with a LoadPrefixSet call, // loading a saved PrefixSet with another key than the one used to probe us. // This must occur exactly between the GetKey call and the Probe call. diff --git a/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js b/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js index b7d625c12c74..4f400f1592de 100644 --- a/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js +++ b/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js @@ -25,7 +25,7 @@ function test() function onKey(aEvent) { - if (aEvent.target != root) { + if (aEvent.target != root && aEvent.target != root.ownerDocument.body) { ok(false, "unknown target: " + aEvent.target.tagName); return; } diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 27b1e8d57b5b..37cab6e258fa 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -921,11 +921,12 @@ // area and can therefore be scrolled for (this._scrollable = event.originalTarget; this._scrollable; this._scrollable = this._scrollable.parentNode) { - // do not use overflow based autoscroll for Elements - // or non-html elements such as svg or Document nodes + // do not use overflow based autoscroll for and + // Elements or non-html elements such as svg or Document nodes // also make sure to skip select elements that are not multiline if (!(this._scrollable instanceof HTMLElement) || (this._scrollable instanceof HTMLHtmlElement) || + (this._scrollable instanceof HTMLBodyElement) || ((this._scrollable instanceof HTMLSelectElement) && !this._scrollable.multiple)) { continue; } diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index e501b737a456..06e0667c984c 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -201,57 +201,66 @@ diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 2ee223b5bc90..8dbf8b995335 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -38,7 +38,8 @@ * ***** END LICENSE BLOCK ***** */ #include "mozilla/dom/CrashReporterChild.h" - +#include "mozilla/Services.h" +#include "nsIObserverService.h" #include "mozilla/Util.h" #include "nsXULAppAPI.h" @@ -1551,7 +1552,21 @@ nsresult GetSubmitReports(bool* aSubmitReports) nsresult SetSubmitReports(bool aSubmitReports) { - return PrefSubmitReports(&aSubmitReports, true); + nsresult rv; + + nsCOMPtr obsServ = + mozilla::services::GetObserverService(); + if (!obsServ) { + return NS_ERROR_FAILURE; + } + + rv = PrefSubmitReports(&aSubmitReports, true); + if (NS_FAILED(rv)) { + return rv; + } + + obsServ->NotifyObservers(nsnull, "submit-reports-pref-changed", nsnull); + return NS_OK; } // The "pending" dir is Crash Reports/pending, from which minidumps diff --git a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties index b78faef1b8c1..b7203dd995ab 100644 --- a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties +++ b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties @@ -1,166 +1,3 @@ -typeError=Error: -typeWarning=Warning: -typeNetwork=Network: -typeException=Exception: -typeCssParser=CSS Parser: -typeStrict=Strict Warning: -msgCategory=Category: -errLine=Line: %S -btnHide=Hide -btnPrefs=Preferences -categoryPage=Page: -categoryConsole=Console: -btnMutation=DOM Mutation -tipMutation=Toggle DOM Mutation event logging -btnPageNet=Net -tipPageNet=Log network access -btnPageCSS=CSS -tipPageCSS=Log CSS parsing errors -btnPageJS=JS -tipPageJS=Log JavaScript exceptions -# LOCALIZATION NOTE (btnPageWebDeveloper): -# -# This is used as the text of the "Web Developer" button on the toolbar. It -# shows or hides messages that the web developer inserted on the page for -# debugging purposes, using calls such console.log() and console.error(). You -# may wish to localize this as "Page" if that is clearer in your locale. See -# bug 601667 for more information. -btnPageWebDeveloper=Web Developer -# LOCALIZATION NOTE (tipPageWebDeveloper): -# -# This is used as the text of the tool tip for the "Web Developer" button on -# the toolbar. -tipPageWebDeveloper=Log messages sent to the "console" object -btnConsoleErrors=Errors -tipConsoleErrors=Log calls to console.error() -btnConsoleInfo=Info -tipConsoleInfo=Log calls to console.info() -btnConsoleWarnings=Warnings -tipConsoleWarnings=Log calls to console.warn() -btnConsoleLog=Log -tipConsoleLog=Log calls to console.log() -btnGlobal=Global Messages -tipGlobal=Toggle Global Message logging -localConsole=Local Console -clearConsoleCmd.label=Clear Console -clearConsoleCmd.accesskey=e -# LOCALIZATION NOTE (btnClear): -# -# This is used as the text of the "Clear" button for the toolbar. It clears the -# contents of the console. -btnClear=Clear -stringFilter=Filter -close.button=Close -close.accesskey=C -update.button=Update -update.accesskey=U -# LOCALIZATION NOTE FOR `jsPropertyTitle` AND `jsPropertyInspectTitle`: -# -# The "PropertyPanel" is used to display a JS object to the user. -# If it is clear which object is being inspected (e.g., window, document object) -# the title of the panel is based on the `jsPropertyInspectTitle` string. -# If it isn't clear which object is being inspected, the `jsPropertyTitle` string -# gets used. This can be the case when the user logs an object to the WebConsole -# output using the console.log(aObjectToInspect) method. -# -# You can find a screenshot of the PropertyPanel here: -# https://bug585030.bugzilla.mozilla.org/attachment.cgi?id=464034 -jsPropertyTitle=Object Inspector -# LOCALIZATION NOTE (jsPropertyInspectTitle): -# -# The %S is replaced by the evaluated code the user clicked on in the console. -# -# Example: The user executed `window.document` in the WebConsole. The `document` -# object is written to the output. If the user clicks on the `document` output -# in the console, a PropertyPanel will show up. The title of the PropertyPanel -# is set to `Inspect: window.document` because the clicked `document` object was -# evaluated based on the `window.document` string. -jsPropertyInspectTitle=Inspect: %S -saveBodies.label=Log Request and Response Bodies -saveBodies.accesskey=L -copyCmd.label=Copy -copyCmd.accesskey=C -selectAllCmd.label=Select All -selectAllCmd.accesskey=A -# LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock), -# %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds. -timestampFormat=%02S:%02S:%02S.%03S - -helperFuncUnsupportedTypeError=Can't call pprint on this type of object. -NetworkPanel.label=Inspect Network Request -# LOCALIZATION NOTE (NetworkPanel.deltaDurationMS): -# -# This string is used to show the duration between two network events (e.g -# request and respones header or response header and response body). -NetworkPanel.durationMS=%Sms -# LOCALIZATION NOTE (NetworkPanel.imageSizeDeltaDurationMS): -# This string is used to show the duration between the response header and the -# response body event. It also shows the size of the received or cached image. -# -# The first %S is replace by the width of the inspected image. -# The second %S is replaced by the height of the inspected image. -# The third %S is replaced by the duration between the response header and the -# response body event. -NetworkPanel.imageSizeDeltaDurationMS=%Sx%Spx, Δ%Sms -# LOCALIZATION NOTE (NetworkPanel.responseBodyUnableToDisplay.content): -# -# This string is displayed within the response body section of the NetworkPanel -# if the content type of the network request can't be displayed in the -# NetworkPanel. E.g. any kind of text is easy to display, but some audio or -# flash data received from the server can't be displayed. -# -# The %S is replaced by the content type, that can't be displayed, examples are -# o application/x-shockwave-flash -# o music/crescendo -NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S" -ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page. - -# LOCALIZATION NOTE (inspectStyle.nullObjectPassed): -# This message is returned when a null object is passed in to inspectstyle() -inspectStyle.nullObjectPassed=Object is null - -# LOCALIZATION NOTE (inspectStyle.mustBeDomNode): -# This message is returned when a non-DOM node is passed in to inspectstyle() -inspectStyle.mustBeDomNode=Object must be a valid DOM node - -# LOCALIZATION NOTE (inspectStyle.nodeHasNoStyleProps): -# This message is returned when an unstyleable object is passed in to inspectstyle() -inspectStyle.nodeHasNoStyleProps=Object cannot be styled - -# LOCALIZATION NOTE (inspectStyle.styleInspectorNotEnabled): -# This message is returned when devtools.styleinspector.enabled is not set to -# true -inspectStyle.styleInspectorNotEnabled=The style inspector is not enabled. Please set the option devtools.styleinspector.enabled to true in about:config to use this command. - -# LOCALIZATION NOTE (webConsolePosition): The label shown for the menu which -# allows the user to toggle between the Web Console positioning types. -webConsolePosition=Position - -# LOCALIZATION NOTE (webConsolePositionTooltip): The tooltip shown when the user -# hovers the Position button in the Web Console toolbar. -webConsolePositionTooltip=Position the Web Console above or below the document - -# LOCALIZATION NOTE (webConsolePositionAbove): When this option is selected the -# Web Console interface is displayed above the web page. -webConsolePositionAbove=Above - -# LOCALIZATION NOTE (webConsolePositionBelow): When this option is selected the -# Web Console interface is displayed below the web page. -webConsolePositionBelow=Below - -# LOCALIZATION NOTE (webConsolePositionWindow): When this option is selected the -# Web Console interface is displayed in a floating panel. -webConsolePositionWindow=Window - -# LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating -# panel title, followed by the web page URL. -# For RTL languages you need to set the LRM in the string to give the URL -# the correct direction. -webConsoleWindowTitleAndURL=Web Console - %S - -# LOCALIZATION NOTE (Autocomplete.label): -# The autocomplete popup panel label/title. -Autocomplete.label=Autocomplete popup # LOCALIZATION NOTE (stacktrace.anonymousFunction): # This string is used to display JavaScript functions that have no given name - diff --git a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd index 8673940c5f20..6382171db051 100644 --- a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd @@ -34,8 +34,8 @@ - - + + diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn index 8517c63e8af4..4ff575a95d92 100644 --- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -37,7 +37,6 @@ + locale/@AB_CD@/global/finddialog.properties (%chrome/global/finddialog.properties) locale/@AB_CD@/global/globalKeys.dtd (%chrome/global/globalKeys.dtd) + locale/@AB_CD@/global/headsUpDisplay.properties (%chrome/global/headsUpDisplay.properties) -+ locale/@AB_CD@/global/webConsole.dtd (%chrome/global/webConsole.dtd) + locale/@AB_CD@/global/intl.css (%chrome/global/intl.css) + locale/@AB_CD@/global/intl.properties (%chrome/global/intl.properties) + locale/@AB_CD@/global/keys.properties (%chrome/global/keys.properties) diff --git a/toolkit/mozapps/extensions/AddonRepository.jsm b/toolkit/mozapps/extensions/AddonRepository.jsm index 826ce24278b4..1f6b4d9e01c1 100644 --- a/toolkit/mozapps/extensions/AddonRepository.jsm +++ b/toolkit/mozapps/extensions/AddonRepository.jsm @@ -60,6 +60,15 @@ const PREF_GETADDONS_GETRECOMMENDED = "extensions.getAddons.recommended.url const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL"; const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url"; +const PREF_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility"; +#ifdef MOZ_COMPATIBILITY_NIGHTLY +const PREF_CHECK_COMPATIBILITY = PREF_CHECK_COMPATIBILITY_BASE + + ".nightly"; +#else +const PREF_CHECK_COMPATIBILITY = PREF_CHECK_COMPATIBILITY_BASE + "." + + Services.appinfo.version.replace(BRANCH_REGEXP, "$1"); +#endif + const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; const API_VERSION = "1.5"; @@ -810,13 +819,23 @@ var AddonRepository = { * The callback to pass results to */ searchAddons: function(aSearchTerms, aMaxResults, aCallback) { - let url = this._formatURLPref(PREF_GETADDONS_GETSEARCHRESULTS, { + let substitutions = { API_VERSION : API_VERSION, TERMS : encodeURIComponent(aSearchTerms), // Get twice as many results to account for potential filtering MAX_RESULTS : 2 * aMaxResults - }); + }; + + let checkCompatibility = true; + try { + checkCompatibility = Services.prefs.getBoolPref(PREF_CHECK_COMPATIBILITY); + } catch(e) { } + + if (!checkCompatibility) + substitutions.VERSION = ""; + + let url = this._formatURLPref(PREF_GETADDONS_GETSEARCHRESULTS, substitutions); let self = this; function handleResults(aElements, aTotalResults) { @@ -1079,17 +1098,26 @@ var AddonRepository = { _parseAddons: function(aElements, aTotalResults, aSkip) { let self = this; let results = []; + + let checkCompatibility = true; + try { + checkCompatibility = Services.prefs.getBoolPref(PREF_CHECK_COMPATIBILITY); + } catch(e) { } + + function isSameApplication(aAppNode) { + return self._getTextContent(aAppNode) == Services.appinfo.ID; + } + for (let i = 0; i < aElements.length && results.length < this._maxResults; i++) { let element = aElements[i]; - // Ignore add-ons not compatible with this Application let tags = this._getUniqueDescendant(element, "compatible_applications"); if (tags == null) continue; let applications = tags.getElementsByTagName("appID"); let compatible = Array.some(applications, function(aAppNode) { - if (self._getTextContent(aAppNode) != Services.appinfo.ID) + if (!isSameApplication(aAppNode)) return false; let parent = aAppNode.parentNode; @@ -1103,8 +1131,14 @@ var AddonRepository = { Services.vc.compare(currentVersion, maxVersion) <= 0); }); - if (!compatible) - continue; + // Ignore add-ons not compatible with this Application + if (!compatible) { + if (checkCompatibility) + continue; + + if (!Array.some(applications, isSameApplication)) + continue; + } // Add-on meets all requirements, so parse out data let result = this._parseAddon(element, aSkip); @@ -1125,6 +1159,8 @@ var AddonRepository = { if (!result.xpiURL && !result.addon.purchaseURL) continue; + result.addon.isCompatible = compatible; + results.push(result); // Ignore this add-on from now on by adding it to the skip array aSkip.ids.push(result.addon.id); diff --git a/toolkit/mozapps/extensions/LightweightThemeManager.jsm b/toolkit/mozapps/extensions/LightweightThemeManager.jsm index 63ac4db23635..29b29be6b797 100644 --- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm +++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm @@ -556,6 +556,10 @@ AddonWrapper.prototype = { return AddonManager.SCOPE_PROFILE; }, + get foreignInstall() { + return false; + }, + // Lightweight themes are always compatible isCompatibleWith: function(appVersion, platformVersion) { return true; diff --git a/toolkit/mozapps/extensions/PluginProvider.jsm b/toolkit/mozapps/extensions/PluginProvider.jsm index e69efc10243d..6545a9fcb832 100644 --- a/toolkit/mozapps/extensions/PluginProvider.jsm +++ b/toolkit/mozapps/extensions/PluginProvider.jsm @@ -339,6 +339,10 @@ PluginWrapper.prototype = { return true; }, + get foreignInstall() { + return true; + }, + isCompatibleWith: function(aAppVerison, aPlatformVersion) { return true; }, diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 33aa184825a0..16482e1f2f18 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -122,7 +122,7 @@ const TOOLKIT_ID = "toolkit@mozilla.org"; const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; -const DB_SCHEMA = 5; +const DB_SCHEMA = 6; const REQ_VERSION = 2; #ifdef MOZ_COMPATIBILITY_NIGHTLY @@ -146,7 +146,7 @@ const DB_METADATA = ["installDate", "updateDate", "size", "sourceURI", "releaseNotesURI", "applyBackgroundUpdates"]; const DB_BOOL_METADATA = ["visible", "active", "userDisabled", "appDisabled", "pendingUninstall", "bootstrap", "skinnable", - "softDisabled"]; + "softDisabled", "foreignInstall"]; const BOOTSTRAP_REASONS = { APP_STARTUP : 1, @@ -1762,6 +1762,9 @@ var XPIProvider = { Services.appinfo.annotateCrashReport("Add-ons", data); } catch (e) { } + + const TelemetryPing = Cc["@mozilla.org/base/telemetry-ping;1"].getService(Ci.nsIObserver); + TelemetryPing.observe(null, "Add-ons", data); }, /** @@ -2550,16 +2553,23 @@ var XPIProvider = { LOG("New add-on " + aId + " installed in " + aInstallLocation.name); let newAddon = null; + let sameVersion = false; // Check the updated manifests lists for the install location, If there // is no manifest for the add-on ID then newAddon will be undefined if (aInstallLocation.name in aManifests) newAddon = aManifests[aInstallLocation.name][aId]; try { - // Otherwise load the manifest from the add-on + // Otherwise the add-on has appeared in the install location. if (!newAddon) { + // Load the manifest from the add-on. let file = aInstallLocation.getLocationForID(aId); newAddon = loadManifestFromFile(file); + + // The default theme is never a foreign install + if (newAddon.type != "theme" || newAddon.internalName != XPIProvider.defaultSkin) + newAddon.foreignInstall = true; + } // The add-on in the manifest should match the add-on ID. if (newAddon.id != aId) @@ -2583,9 +2593,10 @@ var XPIProvider = { newAddon.installDate = aAddonState.mtime; newAddon.updateDate = aAddonState.mtime; - // Check if the add-on is in a scope where add-ons should install disabled + // Check if the add-on is a foreign install and is in a scope where + // add-ons that were dropped in should default to disabled. let disablingScopes = Prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0); - if (aInstallLocation.scope & disablingScopes) + if (newAddon.foreignInstall && aInstallLocation.scope & disablingScopes) newAddon.userDisabled = true; // If there is migration data then apply it. @@ -2599,12 +2610,21 @@ var XPIProvider = { newAddon.installDate = aMigrateData.installDate; if ("softDisabled" in aMigrateData) newAddon.softDisabled = aMigrateData.softDisabled; + if ("applyBackgroundUpdates" in aMigrateData) + newAddon.applyBackgroundUpdates = aMigrateData.applyBackgroundUpdates; + if ("sourceURI" in aMigrateData) + newAddon.sourceURI = aMigrateData.sourceURI; + if ("releaseNotesURI" in aMigrateData) + newAddon.releaseNotesURI = aMigrateData.releaseNotesURI; + if ("foreignInstall" in aMigrateData) + newAddon.foreignInstall = aMigrateData.foreignInstall; // Some properties should only be migrated if the add-on hasn't changed. // The version property isn't a perfect check for this but covers the // vast majority of cases. if (aMigrateData.version == newAddon.version) { LOG("Migrating compatibility info"); + sameVersion = true; if ("targetApplications" in aMigrateData) newAddon.applyCompatibilityUpdate(aMigrateData, true); } @@ -2682,6 +2702,11 @@ var XPIProvider = { let oldBootstrap = oldBootstrappedAddons[newAddon.id]; XPIProvider.bootstrappedAddons[newAddon.id] = oldBootstrap; + // If the old version is the same as the new version, don't call + // uninstall and install methods. + if (sameVersion) + return false; + installReason = Services.vc.compare(oldBootstrap.version, newAddon.version) < 0 ? BOOTSTRAP_REASONS.ADDON_UPGRADE : BOOTSTRAP_REASONS.ADDON_DOWNGRADE; @@ -3552,30 +3577,39 @@ var XPIProvider = { if (Services.appinfo.inSafeMode) return; - // Load the scope if it hasn't already been loaded - if (!(aId in this.bootstrapScopes)) - this.loadBootstrapScope(aId, aFile, aVersion, aType); + if (aMethod == "startup") + Components.manager.addBootstrappedManifestLocation(aFile); - if (!(aMethod in this.bootstrapScopes[aId])) { - WARN("Add-on " + aId + " is missing bootstrap method " + aMethod); - return; - } - - let params = { - id: aId, - version: aVersion, - installPath: aFile.clone(), - resourceURI: getURIForResourceInFile(aFile, "") - }; - - LOG("Calling bootstrap method " + aMethod + " on " + aId + " version " + - aVersion); try { - this.bootstrapScopes[aId][aMethod](params, aReason); + // Load the scope if it hasn't already been loaded + if (!(aId in this.bootstrapScopes)) + this.loadBootstrapScope(aId, aFile, aVersion, aType); + + if (!(aMethod in this.bootstrapScopes[aId])) { + WARN("Add-on " + aId + " is missing bootstrap method " + aMethod); + return; + } + + let params = { + id: aId, + version: aVersion, + installPath: aFile.clone(), + resourceURI: getURIForResourceInFile(aFile, "") + }; + + LOG("Calling bootstrap method " + aMethod + " on " + aId + " version " + + aVersion); + try { + this.bootstrapScopes[aId][aMethod](params, aReason); + } + catch (e) { + WARN("Exception running bootstrap method " + aMethod + " on " + + aId, e); + } } - catch (e) { - WARN("Exception running bootstrap method " + aMethod + " on " + - aId, e); + finally { + if (aMethod == "shutdown") + Components.manager.removeBootstrappedManifestLocation(aFile); } }, @@ -3845,7 +3879,8 @@ const FIELDS_ADDON = "internal_id, id, location, version, type, internalName, " "iconURL, icon64URL, defaultLocale, visible, active, " + "userDisabled, appDisabled, pendingUninstall, descriptor, " + "installDate, updateDate, applyBackgroundUpdates, bootstrap, " + - "skinnable, size, sourceURI, releaseNotesURI, softDisabled"; + "skinnable, size, sourceURI, releaseNotesURI, softDisabled, " + + "foreignInstall"; /** * A helper function to log an SQL error. @@ -3990,7 +4025,8 @@ var XPIDatabase = { ":userDisabled, :appDisabled, :pendingUninstall, " + ":descriptor, :installDate, :updateDate, " + ":applyBackgroundUpdates, :bootstrap, :skinnable, " + - ":size, :sourceURI, :releaseNotesURI, :softDisabled)", + ":size, :sourceURI, :releaseNotesURI, :softDisabled, " + + ":foreignInstall)", addAddonMetadata_addon_locale: "INSERT INTO addon_locale VALUES " + "(:internal_id, :name, :locale)", addAddonMetadata_locale: "INSERT INTO locale (name, description, creator, " + @@ -4357,7 +4393,14 @@ var XPIDatabase = { // and future versions of the schema var sql = []; sql.push("SELECT internal_id, id, location, userDisabled, " + - "softDisabled, installDate, version FROM addon"); + "softDisabled, installDate, version, applyBackgroundUpdates, " + + "sourceURI, releaseNotesURI, foreignInstall FROM addon"); + sql.push("SELECT internal_id, id, location, userDisabled, " + + "softDisabled, installDate, version, applyBackgroundUpdates, " + + "sourceURI, releaseNotesURI FROM addon"); + sql.push("SELECT internal_id, id, location, userDisabled, " + + "installDate, version, applyBackgroundUpdates, " + + "sourceURI, releaseNotesURI FROM addon"); sql.push("SELECT internal_id, id, location, userDisabled, installDate, " + "version FROM addon"); @@ -4388,6 +4431,14 @@ var XPIDatabase = { if ("softDisabled" in row) migrateData[row.location][row.id].softDisabled = row.softDisabled == 1; + if ("applyBackgroundUpdates" in row) + migrateData[row.location][row.id].applyBackgroundUpdates = row.applyBackgroundUpdates == 1; + if ("sourceURI" in row) + migrateData[row.location][row.id].sourceURI = row.sourceURI; + if ("releaseNotesURI" in row) + migrateData[row.location][row.id].releaseNotesURI = row.releaseNotesURI; + if ("foreignInstall" in row) + migrateData[row.location][row.id].foreignInstall = row.foreignInstall; } var taStmt = this.connection.createStatement("SELECT id, minVersion, " + @@ -4508,6 +4559,7 @@ var XPIDatabase = { "bootstrap INTEGER, skinnable INTEGER, " + "size INTEGER, sourceURI TEXT, " + "releaseNotesURI TEXT, softDisabled INTEGER, " + + "foreignInstall INTEGER, " + "UNIQUE (id, location)"); this.connection.createTable("targetApplication", "addon_internal_id INTEGER, " + @@ -5182,6 +5234,7 @@ var XPIDatabase = { this.removeAddonMetadata(aOldAddon); aNewAddon.installDate = aOldAddon.installDate; aNewAddon.applyBackgroundUpdates = aOldAddon.applyBackgroundUpdates; + aNewAddon.foreignInstall = aOldAddon.foreignInstall; aNewAddon.active = (aNewAddon.visible && !aNewAddon.userDisabled && !aNewAddon.appDisabled) this.addAddonMetadata(aNewAddon, aDescriptor); @@ -6797,6 +6850,7 @@ AddonInternal.prototype = { softDisabled: false, sourceURI: null, releaseNotesURI: null, + foreignInstall: false, get selectedLocale() { if (this._selectedLocale) @@ -7069,7 +7123,7 @@ function AddonWrapper(aAddon) { ["id", "version", "type", "isCompatible", "isPlatformCompatible", "providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled", - "softDisabled", "skinnable", "size"].forEach(function(aProp) { + "softDisabled", "skinnable", "size", "foreignInstall"].forEach(function(aProp) { this.__defineGetter__(aProp, function() aAddon[aProp]); }, this); diff --git a/toolkit/mozapps/extensions/content/selectAddons.js b/toolkit/mozapps/extensions/content/selectAddons.js index c4e4fffb72cc..508e0e080222 100644 --- a/toolkit/mozapps/extensions/content/selectAddons.js +++ b/toolkit/mozapps/extensions/content/selectAddons.js @@ -80,13 +80,7 @@ function isAddonDistroInstalled(aID) { } function orderForScope(aScope) { - switch (aScope) { - case AddonManager.SCOPE_PROFILE: - case AddonManager.SCOPE_APPLICATION: - return 1; - default: - return 0; - } + return aScope == AddonManager.SCOPE_PROFILE ? 1 : 0; } var gAddons = {}; diff --git a/toolkit/mozapps/extensions/content/selectAddons.xml b/toolkit/mozapps/extensions/content/selectAddons.xml index 2b93a7ec27a2..f08eb273d464 100644 --- a/toolkit/mozapps/extensions/content/selectAddons.xml +++ b/toolkit/mozapps/extensions/content/selectAddons.xml @@ -119,20 +119,15 @@ this.setAttribute("name", aAddon.name); this.setAttribute("type", aAddon.type); - // User and application installed add-ons default to staying enabled, + // User and bundled add-ons default to staying enabled, // others default to disabled. - let scope = aAddon.scope; - if (aDistroInstalled) - scope = AddonManager.SCOPE_APPLICATION; - - switch (scope) { + switch (aAddon.scope) { case AddonManager.SCOPE_PROFILE: this._keep.checked = !aAddon.userDisabled; - this.setAttribute("source", this._strings.getString("source.profile")); - break; - case AddonManager.SCOPE_APPLICATION: - this._keep.checked = !aAddon.userDisabled; - this.setAttribute("source", this._strings.getString("source.bundled")); + if (aDistroInstalled) + this.setAttribute("source", this._strings.getString("source.bundled")); + else + this.setAttribute("source", this._strings.getString("source.profile")); break; default: this._keep.checked = false; diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest new file mode 100644 index 000000000000..17d5c99ec45e --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest @@ -0,0 +1 @@ +content bug675371 . diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf b/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf new file mode 100644 index 000000000000..ca2881e5ac18 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf @@ -0,0 +1,24 @@ + + + + + + bug675371@tests.mozilla.org + 1.0 + true + + + Bug 675371 Test + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js b/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js new file mode 100644 index 000000000000..ae74c174d80a --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js @@ -0,0 +1 @@ +active = true; diff --git a/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf b/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf new file mode 100644 index 000000000000..5924982f72ce --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf @@ -0,0 +1,23 @@ + + + + + + addon6@tests.mozilla.org + 2.0 + + + Test 6 + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_migrate4_7/install.rdf b/toolkit/mozapps/extensions/test/addons/test_migrate4_7/install.rdf new file mode 100644 index 000000000000..072751cf2673 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_migrate4_7/install.rdf @@ -0,0 +1,23 @@ + + + + + + addon7@tests.mozilla.org + 1.0 + + + Test 7 + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/browser/browser_searching.js b/toolkit/mozapps/extensions/test/browser/browser_searching.js index 960d8b4225a5..4588543f227b 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_searching.js +++ b/toolkit/mozapps/extensions/test/browser/browser_searching.js @@ -589,6 +589,22 @@ add_test(function() { }); }); +// Tests that incompatible add-ons are shown with a warning if compatibility checking is disabled +add_test(function() { + Services.prefs.setBoolPref("extensions.checkCompatibility.nightly", false); + search("incompatible", false, function() { + var item = get_addon_item("remote5"); + is_element_visible(item, "Incompatible addon should be visible"); + is(item.getAttribute("notification"), "warning", "Compatibility warning should be shown"); + + var item = get_addon_item("remote6"); + is(item, null, "Addon incompatible with the product should not be visible"); + + Services.prefs.clearUserPref("extensions.checkCompatibility.nightly"); + run_next_test(); + }); +}); + // Tests that restarting the manager doesn't change search results add_test(function() { restart_manager(gManagerWindow, null, function(aWindow) { diff --git a/toolkit/mozapps/extensions/test/browser/browser_searching.xml b/toolkit/mozapps/extensions/test/browser/browser_searching.xml index 198013b5b3ee..b050443b3dc2 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_searching.xml +++ b/toolkit/mozapps/extensions/test/browser/browser_searching.xml @@ -186,5 +186,61 @@ ALL http://example.com/remote4.xpi + + PASS - i + Extension + remote5@tests.mozilla.org + 6.0 + + + Test Creator + http://example.com/creator.html + + + Public + Incompatible test + Test description + + + Firefox + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + 0 + 1 + + + SeaMonkey + {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} + 0 + 1 + + + ALL + http://example.com/addon1.xpi + + + FAIL - j + Extension + remote6@tests.mozilla.org + 6.0 + + + Test Creator + http://example.com/creator.html + + + Public + Incompatible test + Test description + + + Fake Product + fakeproduct@mozilla.org + 0 + 1 + + + ALL + http://example.com/addon1.xpi + diff --git a/toolkit/mozapps/extensions/test/browser/browser_select_selection.js b/toolkit/mozapps/extensions/test/browser/browser_select_selection.js index 92943113b136..7c277bdc70b3 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_select_selection.js +++ b/toolkit/mozapps/extensions/test/browser/browser_select_selection.js @@ -11,15 +11,16 @@ const PROFILE = AddonManager.SCOPE_PROFILE; const USER = AddonManager.SCOPE_USER; const APP = AddonManager.SCOPE_APPLICATION; const SYSTEM = AddonManager.SCOPE_SYSTEM; +const DIST = -1; // The matrix of testcases for the selection part of the UI // Note that the isActive flag has the value it had when the previous version // of the application ran with this add-on. var ADDONS = [ //userDisabled wasAppDisabled isAppDisabled isActive hasUpdate autoUpdate scope defaultKeep position keepString disableString - [false, true, false, false, false, true, PROFILE, true, 38, "enabled", ""], // 0 - [false, true, false, false, true, true, PROFILE, true, 39, "enabled", ""], // 1 - [false, true, false, false, true, false, PROFILE, true, 48, "unneededupdate", ""], // 2 + [false, true, false, false, false, true, PROFILE, true, 42, "enabled", ""], // 0 + [false, true, false, false, true, true, PROFILE, true, 43, "enabled", ""], // 1 + [false, true, false, false, true, false, PROFILE, true, 52, "unneededupdate", ""], // 2 [false, false, false, true, false, true, PROFILE, true, 53, "", "disabled"], // 3 [false, false, false, true, true, true, PROFILE, true, 54, "", "disabled"], // 4 [false, false, false, true, true, false, PROFILE, true, 55, "unneededupdate", "disabled"], // 5 @@ -27,17 +28,17 @@ var ADDONS = [ [false, true, true, false, true, true, PROFILE, true, 57, "autoupdate", ""], // 7 [false, true, true, false, true, false, PROFILE, true, 58, "neededupdate", ""], // 8 [false, false, true, true, false, true, PROFILE, true, 59, "incompatible", "disabled"], // 9 - [false, true, true, true, true, true, PROFILE, true, 40, "autoupdate", "disabled"], // 10 - [false, true, true, true, true, false, PROFILE, true, 41, "neededupdate", "disabled"], // 11 - [true, false, false, false, false, true, PROFILE, false, 42, "enabled", ""], // 12 - [true, false, false, false, true, true, PROFILE, false, 43, "enabled", ""], // 13 - [true, false, false, false, true, false, PROFILE, false, 44, "unneededupdate", ""], // 14 + [false, true, true, true, true, true, PROFILE, true, 44, "autoupdate", "disabled"], // 10 + [false, true, true, true, true, false, PROFILE, true, 45, "neededupdate", "disabled"], // 11 + [true, false, false, false, false, true, PROFILE, false, 46, "enabled", ""], // 12 + [true, false, false, false, true, true, PROFILE, false, 47, "enabled", ""], // 13 + [true, false, false, false, true, false, PROFILE, false, 48, "unneededupdate", ""], // 14 // userDisabled and isActive cannot be true on startup - [true, true, true, false, false, true, PROFILE, false, 45, "incompatible", ""], // 15 - [true, true, true, false, true, true, PROFILE, false, 46, "autoupdate", ""], // 16 - [true, true, true, false, true, false, PROFILE, false, 47, "neededupdate", ""], // 17 + [true, true, true, false, false, true, PROFILE, false, 49, "incompatible", ""], // 15 + [true, true, true, false, true, true, PROFILE, false, 50, "autoupdate", ""], // 16 + [true, true, true, false, true, false, PROFILE, false, 51, "neededupdate", ""], // 17 // userDisabled and isActive cannot be true on startup @@ -50,10 +51,10 @@ var ADDONS = [ [true, true, false, false, true, false, SYSTEM, false, 5, "enabled", ""], // 23 [false, true, true, true, true, false, SYSTEM, false, 6, "incompatible", "disabled"], // 24 [true, true, true, false, true, false, SYSTEM, false, 7, "incompatible", ""], // 25 - [false, false, false, true, true, false, APP, true, 49, "", "disabled"], // 26 - [true, true, false, false, true, false, APP, false, 50, "enabled", ""], // 27 - [false, true, true, true, true, false, APP, true, 51, "incompatible", "disabled"], // 28 - [true, true, true, false, true, false, APP, false, 52, "incompatible", ""], // 29 + [false, false, false, true, true, false, APP, false, 8, "", "disabled"], // 26 + [true, true, false, false, true, false, APP, false, 9, "enabled", ""], // 27 + [false, true, true, true, true, false, APP, false, 10, "incompatible", "disabled"], // 28 + [true, true, true, false, true, false, APP, false, 11, "incompatible", ""], // 29 ]; function waitForView(aView, aCallback) { @@ -78,10 +79,10 @@ function getSourceString(aSource) { var strings = Services.strings.createBundle("chrome://mozapps/locale/extensions/selectAddons.properties"); switch (aSource) { - case APP: - return strings.GetStringFromName("source.bundled"); case PROFILE: return strings.GetStringFromName("source.profile"); + case DIST: + return strings.GetStringFromName("source.bundled"); default: return strings.GetStringFromName("source.other"); } @@ -232,7 +233,7 @@ add_test(function selection_test() { if (id == 3 || id == 12 || id == 15) { // Distro Installed To Profile - is(source.textContent, getSourceString(APP), "Source message should have the right text for Distributed Addons"); + is(source.textContent, getSourceString(DIST), "Source message should have the right text for Distributed Addons"); } else { is(source.textContent, getSourceString(addon[6]), "Source message should have the right text"); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf b/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf new file mode 100644 index 000000000000..88e42267f392 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf @@ -0,0 +1,46 @@ + + + + + + + +
  • + + 2.0 + + + xpcshell@tests.mozilla.org + 0 + 2 + + + +
  • +
    +
    +
    + + + + +
  • + + 2.0 + + + xpcshell@tests.mozilla.org + 0 + 2 + http://localhost:4444/addons/test_migrate4_6.xpi + http://example.com/updateInfo.xhtml + + + +
  • +
    +
    +
    + +
    diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js b/toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js index 61b34ba62f97..f591509fdc4d 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js @@ -100,8 +100,11 @@ function run_test_1() { do_check_false(a4.isActive); do_check_false(isExtensionInAddonsList(profileDir, addon4.id)); - // Prepare the add-on update - installAllFiles([do_get_addon("test_bug659772")], function() { + // Prepare the add-on update, and a bootstrapped addon (bug 693714) + installAllFiles([ + do_get_addon("test_bug659772"), + do_get_addon("test_bootstrap1_1") + ], function() { shutdownManager(); // Make it look like the next time the app is started it has a new DB schema @@ -142,6 +145,9 @@ function run_test_1() { converter.close(); stream.close(); + Services.prefs.clearUserPref("bootstraptest.install_reason"); + Services.prefs.clearUserPref("bootstraptest.uninstall_reason"); + startupManager(false); AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", @@ -179,6 +185,10 @@ function run_test_1() { do_check_false(a4.isActive); do_check_false(isExtensionInAddonsList(profileDir, addon4.id)); + // Check that install and uninstall haven't been called on the bootstrapped adddon + do_check_false(Services.prefs.prefHasUserValue("bootstraptest.install_reason")); + do_check_false(Services.prefs.prefHasUserValue("bootstraptest.uninstall_reason")); + a1.uninstall(); a2.uninstall(); a3.uninstall(); @@ -235,8 +245,11 @@ function run_test_2() { do_check_false(a4.isActive); do_check_false(isExtensionInAddonsList(profileDir, addon4.id)); - // Prepare the add-on update - installAllFiles([do_get_addon("test_bug659772")], function() { + // Prepare the add-on update, and a bootstrapped addon (bug 693714) + installAllFiles([ + do_get_addon("test_bug659772"), + do_get_addon("test_bootstrap1_1") + ], function() { shutdownManager(); // Make it look like the next time the app is started it has a new DB schema @@ -277,6 +290,9 @@ function run_test_2() { converter.close(); stream.close(); + Services.prefs.clearUserPref("bootstraptest.install_reason"); + Services.prefs.clearUserPref("bootstraptest.uninstall_reason"); + gAppInfo.version = "2"; startupManager(true); @@ -315,6 +331,10 @@ function run_test_2() { do_check_true(a4.isActive); do_check_true(isExtensionInAddonsList(profileDir, addon4.id)); + // Check that install and uninstall haven't been called on the bootstrapped adddon + do_check_false(Services.prefs.prefHasUserValue("bootstraptest.install_reason")); + do_check_false(Services.prefs.prefHasUserValue("bootstraptest.uninstall_reason")); + a1.uninstall(); a2.uninstall(); a3.uninstall(); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js b/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js new file mode 100644 index 000000000000..270825f58c92 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js @@ -0,0 +1,91 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function run_test() { + do_test_pending(); + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + startupManager(); + + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bug675371"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], check_test); + install.install(); + }); +} + +function check_test() { + AddonManager.getAddonByID("bug675371@tests.mozilla.org", function(addon) { + do_check_neq(addon, null); + do_check_true(addon.isActive); + + // Tests that chrome.manifest is registered when the addon is installed. + var target = { active: false }; + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_check_true(target.active); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onDisabling", false], + "onDisabled" + ] + }); + + // Tests that chrome.manifest is unregistered when the addon is disabled. + addon.userDisabled = true; + target.active = false; + try { + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_throw("Chrome file should not have been found"); + } catch (e) { + do_check_false(target.active); + } + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onEnabling", false], + "onEnabled" + ] + }); + + // Tests that chrome.manifest is registered when the addon is enabled. + addon.userDisabled = false; + target.active = false; + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_check_true(target.active); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onUninstalling", false], + "onUninstalled" + ] + }); + + // Tests that chrome.manifest is unregistered when the addon is uninstalled. + addon.uninstall(); + target.active = false; + try { + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_throw("Chrome file should not have been found"); + } catch (e) { + do_check_false(target.active); + } + + do_test_finished(); + }); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js b/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js index 4f574629e5ad..13e809558a99 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js @@ -89,6 +89,7 @@ function run_test_1() { do_check_eq(a1.version, "1.0"); do_check_true(a1.isActive); do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE); + do_check_false(a1.foreignInstall); run_test_2(); }); @@ -122,6 +123,7 @@ function run_test_3() { do_check_eq(a1.version, "2.0"); do_check_true(a1.isActive); do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE); + do_check_false(a1.foreignInstall); run_test_4(); }); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_install.js index a31c89f1d153..36ee5797a84f 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_install.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_install.js @@ -163,6 +163,7 @@ function check_test_1() { do_check_true(do_get_addon("test_install1").exists()); do_check_in_crash_annotation(a1.id, a1.version); do_check_eq(a1.size, ADDON1_SIZE); + do_check_false(a1.foreignInstall); do_check_eq(a1.sourceURI.spec, Services.io.newFileURI(do_get_addon("test_install1")).spec); @@ -382,6 +383,7 @@ function check_test_5(install) { do_check_in_crash_annotation(a2.id, a2.version); do_check_eq(a2.sourceURI.spec, "http://localhost:4444/addons/test_install2_2.xpi"); + do_check_false(a2.foreignInstall); do_check_eq(a2.installDate.getTime(), gInstallDate); // Update date should be later (or the same if this test is too fast) diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js index 2769fb03e79f..50c91c8059e2 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Checks that we migrate data from previous versions of the database +// Checks that we migrate data from the old rdf style database var addon1 = { id: "addon1@tests.mozilla.org", diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js index efeac14f3752..9f15f1672996 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js @@ -177,7 +177,6 @@ function run_test() { do_check_false(a5.userDisabled); do_check_false(a5.appDisabled); do_check_true(a5.isActive); - do_test_finished(); // addon6 was disabled and compatible but a new version has been installed // since, it should still be disabled but should be incompatible do_check_neq(a6, null); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js index 25aae35aafda..095026da8bd0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Checks that we migrate data from previous versions of the database. This +// Checks that we migrate data from the old extensions.rdf database. This // matches test_migrate1.js however it runs with a lightweight theme selected // so the themes should appear disabled. diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js new file mode 100644 index 000000000000..39d4a7013e71 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js @@ -0,0 +1,243 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Checks that we migrate data from a previous version of the sqlite database + +// The test extension uses an insecure update url. +Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false); + +var addon1 = { + id: "addon1@tests.mozilla.org", + version: "1.0", + name: "Test 1", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon2 = { + id: "addon2@tests.mozilla.org", + version: "2.0", + name: "Test 2", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon3 = { + id: "addon3@tests.mozilla.org", + version: "2.0", + name: "Test 3", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon4 = { + id: "addon4@tests.mozilla.org", + version: "2.0", + name: "Test 4", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon5 = { + id: "addon5@tests.mozilla.org", + version: "2.0", + name: "Test 5", + updateURL: "http://localhost:4444/data/test_migrate4.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "0", + maxVersion: "1" + }] +}; + +var addon6 = { + id: "addon6@tests.mozilla.org", + version: "1.0", + name: "Test 6", + updateURL: "http://localhost:4444/data/test_migrate4.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "0", + maxVersion: "1" + }] +}; + +const profileDir = gProfD.clone(); +profileDir.append("extensions"); + +do_load_httpd_js(); +var testserver; + +function prepare_profile() { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + + // Create and configure the HTTP server. + testserver = new nsHttpServer(); + testserver.registerDirectory("/data/", do_get_file("data")); + testserver.registerDirectory("/addons/", do_get_file("addons")); + testserver.start(4444); + + writeInstallRDFForExtension(addon1, profileDir); + writeInstallRDFForExtension(addon2, profileDir); + writeInstallRDFForExtension(addon3, profileDir); + writeInstallRDFForExtension(addon4, profileDir); + writeInstallRDFForExtension(addon5, profileDir); + writeInstallRDFForExtension(addon6, profileDir); + + startupManager(); + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a2.userDisabled = true; + a2.applyBackgroundUpdates = false; + a4.userDisabled = true; + a6.userDisabled = true; + + a6.findUpdates({ + onUpdateAvailable: function(aAddon, aInstall6) { + AddonManager.getInstallForURL("http://localhost:4444/addons/test_migrate4_7.xpi", function(aInstall7) { + completeAllInstalls([aInstall6, aInstall7], function() { + restartManager(); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a3.userDisabled = true; + a4.userDisabled = false; + + a5.findUpdates({ + onUpdateFinished: function() { + shutdownManager(); + + perform_migration(); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); + }); + }, "application/x-xpinstall"); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); +} + +function perform_migration() { + let dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + let db = AM_Cc["@mozilla.org/storage/service;1"]. + getService(AM_Ci.mozIStorageService). + openDatabase(dbfile); + db.schemaVersion = 1; + Services.prefs.setIntPref("extensions.databaseSchema", 1); + db.close(); + + gAppInfo.version = "2" + startupManager(true); + test_results(); +} + +function test_results() { + check_startup_changes("installed", []); + check_startup_changes("updated", []); + check_startup_changes("uninstalled", []); + check_startup_changes("disabled", []); + check_startup_changes("enabled", []); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org", + "addon7@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6, a7]) { + // addon1 was enabled + do_check_neq(a1, null); + do_check_false(a1.userDisabled); + do_check_false(a1.appDisabled); + do_check_true(a1.isActive); + do_check_true(a1.applyBackgroundUpdates); + do_check_true(a1.foreignInstall); + + // addon2 was disabled + do_check_neq(a2, null); + do_check_true(a2.userDisabled); + do_check_false(a2.appDisabled); + do_check_false(a2.isActive); + do_check_false(a2.applyBackgroundUpdates); + do_check_true(a2.foreignInstall); + + // addon3 was pending-disable in the database + do_check_neq(a3, null); + do_check_true(a3.userDisabled); + do_check_false(a3.appDisabled); + do_check_false(a3.isActive); + do_check_true(a3.applyBackgroundUpdates); + do_check_true(a3.foreignInstall); + + // addon4 was pending-enable in the database + do_check_neq(a4, null); + do_check_false(a4.userDisabled); + do_check_false(a4.appDisabled); + do_check_true(a4.isActive); + do_check_true(a4.applyBackgroundUpdates); + do_check_true(a4.foreignInstall); + + // addon5 was enabled in the database but needed a compatibiltiy update + do_check_neq(a5, null); + do_check_false(a5.userDisabled); + do_check_false(a5.appDisabled); + do_check_true(a5.isActive); + do_check_true(a5.applyBackgroundUpdates); + do_check_true(a5.foreignInstall); + + // addon6 was disabled and compatible but a new version has been installed + do_check_neq(a6, null); + do_check_eq(a6.version, "2.0"); + do_check_true(a6.userDisabled); + do_check_false(a6.appDisabled); + do_check_false(a6.isActive); + do_check_true(a6.applyBackgroundUpdates); + do_check_true(a6.foreignInstall); + do_check_eq(a6.sourceURI.spec, "http://localhost:4444/addons/test_migrate4_6.xpi"); + do_check_eq(a6.releaseNotesURI.spec, "http://example.com/updateInfo.xhtml"); + + // addon7 was installed manually + do_check_neq(a7, null); + do_check_eq(a7.version, "1.0"); + do_check_false(a7.userDisabled); + do_check_false(a7.appDisabled); + do_check_true(a7.isActive); + do_check_true(a7.applyBackgroundUpdates); + do_check_false(a7.foreignInstall); + do_check_eq(a7.sourceURI.spec, "http://localhost:4444/addons/test_migrate4_7.xpi"); + do_check_eq(a7.releaseNotesURI, null); + testserver.stop(do_test_finished); + }); +} + +function run_test() { + do_test_pending(); + + prepare_profile(); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js index 856362b90e90..71f41b6775f8 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js @@ -202,6 +202,7 @@ function run_test_1() { do_check_in_crash_annotation(addon1.id, addon1.version); do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE); do_check_eq(a1.sourceURI, null); + do_check_true(a1.foreignInstall); do_check_neq(a2, null); do_check_eq(a2.id, "addon2@tests.mozilla.org"); @@ -213,6 +214,7 @@ function run_test_1() { do_check_in_crash_annotation(addon2.id, addon2.version); do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE); do_check_eq(a2.sourceURI, null); + do_check_true(a2.foreignInstall); do_check_neq(a3, null); do_check_eq(a3.id, "addon3@tests.mozilla.org"); @@ -224,6 +226,7 @@ function run_test_1() { do_check_in_crash_annotation(addon3.id, addon3.version); do_check_eq(a3.scope, AddonManager.SCOPE_PROFILE); do_check_eq(a3.sourceURI, null); + do_check_true(a3.foreignInstall); do_check_eq(a4, null); do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org")); @@ -297,6 +300,7 @@ function run_test_2() { do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE)); do_check_in_crash_annotation(addon1.id, a1.version); do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE); + do_check_true(a1.foreignInstall); do_check_neq(a2, null); do_check_eq(a2.id, "addon2@tests.mozilla.org"); @@ -308,6 +312,7 @@ function run_test_2() { do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE)); do_check_in_crash_annotation(addon2.id, a2.version); do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE); + do_check_true(a2.foreignInstall); do_check_eq(a3, null); do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org")); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_theme.js b/toolkit/mozapps/extensions/test/xpcshell/test_theme.js index 5cb3bb049dd4..971f410159f5 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_theme.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_theme.js @@ -94,12 +94,14 @@ function run_test() { function([d, t1, t2]) { do_check_neq(d, null); do_check_false(d.skinnable); + do_check_false(d.foreignInstall); do_check_neq(t1, null); do_check_false(t1.userDisabled); do_check_false(t1.appDisabled); do_check_true(t1.isActive); do_check_true(t1.skinnable); + do_check_true(t1.foreignInstall); do_check_eq(t1.screenshots, null); do_check_true(isThemeInAddonsList(profileDir, t1.id)); do_check_false(hasFlag(t1.permissions, AddonManager.PERM_CAN_DISABLE)); @@ -112,6 +114,7 @@ function run_test() { do_check_false(t2.appDisabled); do_check_false(t2.isActive); do_check_false(t2.skinnable); + do_check_true(t2.foreignInstall); do_check_eq(t2.screenshots, null); do_check_false(isThemeInAddonsList(profileDir, t2.id)); do_check_false(hasFlag(t2.permissions, AddonManager.PERM_CAN_DISABLE)); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_update.js b/toolkit/mozapps/extensions/test/xpcshell/test_update.js index afdfdae75e1c..f39908e06b2a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_update.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_update.js @@ -90,6 +90,7 @@ function run_test_1() { do_check_eq(a1.version, "1.0"); do_check_eq(a1.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT); do_check_eq(a1.releaseNotesURI, null); + do_check_true(a1.foreignInstall); a1.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT; @@ -219,6 +220,7 @@ function check_test_2() { do_check_true(isExtensionInAddonsList(profileDir, a1.id)); do_check_eq(a1.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DISABLE); do_check_eq(a1.releaseNotesURI.spec, "http://example.com/updateInfo.xhtml"); + do_check_true(a1.foreignInstall); a1.uninstall(); restartManager(); diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index c3b57d04644f..9266062b5d7c 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -117,6 +117,7 @@ fail-if = os == "android" [test_bug620837.js] [test_bug655254.js] [test_bug659772.js] +[test_bug675371.js] [test_cacheflush.js] [test_checkcompatibility.js] [test_corrupt.js] @@ -158,6 +159,7 @@ skip-if = os == "android" [test_migrate1.js] [test_migrate2.js] [test_migrate3.js] +[test_migrate4.js] [test_migrateAddonRepository.js] [test_permissions.js] [test_plugins.js] diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index c3507d86cc96..8cc5587582af 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -68,15 +68,17 @@ &managePlugins; - - &report.please; + + &reloadPlugin.pre;&reloadPlugin.middle;&reloadPlugin.post; + + + &report.checkbox; + &report.submitting; &report.submitted; &report.disabled; &report.failed; &report.unavailable; - - &reloadPlugin.pre;&reloadPlugin.middle;&reloadPlugin.post; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index 3039718671ed..38076ab3c540 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -55,19 +55,14 @@ html|applet:not([height]), html|applet[height=""] { } .submitStatus[status="noReport"] .msgNoCrashReport, -.submitStatus[status="please"] .msgPleaseSubmit, .submitStatus[status="noSubmit"] .msgNotSubmitted, .submitStatus[status="submitting"] .msgSubmitting, .submitStatus[status="success"] .msgSubmitted, .submitStatus[status="failed"] .msgSubmitFailed, -.submitStatus[status]:not([status="please"]) .msgReload { +.submitStatus[status="please"] .msgSubmitPlease, +.submitStatus .msgReload { display: block; } -.submitStatus[status="please"] .msgReload { - /* Take up space when invisible, so stuff doesn't shift upon reveal. */ - display: block; - visibility: hidden; -} .helpIcon { cursor: pointer; diff --git a/toolkit/system/dbus/nsNetworkManagerListener.cpp b/toolkit/system/dbus/nsNetworkManagerListener.cpp index c557a21f7109..b877ae67e30d 100644 --- a/toolkit/system/dbus/nsNetworkManagerListener.cpp +++ b/toolkit/system/dbus/nsNetworkManagerListener.cpp @@ -52,15 +52,13 @@ #define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" #define NM_DBUS_PATH "/org/freedesktop/NetworkManager" #define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" -#define NM_DBUS_SIGNAL_STATE_CHANGE "StateChange" -typedef enum NMState -{ - NM_STATE_UNKNOWN = 0, - NM_STATE_ASLEEP, - NM_STATE_CONNECTING, - NM_STATE_CONNECTED, - NM_STATE_DISCONNECTED -} NMState; +#define NM_DBUS_SIGNAL_STATE_CHANGE "StateChange" /* Deprecated in 0.7.x */ +#define NM_DBUS_SIGNAL_STATE_CHANGED "StateChanged" + +#define NM_STATE_CONNECTED_OLD 3 /* Before NM 0.9.0 */ +#define NM_STATE_CONNECTED_LOCAL 50 +#define NM_STATE_CONNECTED_SITE 60 +#define NM_STATE_CONNECTED_GLOBAL 70 nsNetworkManagerListener::nsNetworkManagerListener() : mLinkUp(true), mNetworkManagerActive(false), @@ -185,7 +183,9 @@ nsNetworkManagerListener::UnregisterWithConnection(DBusConnection* connection) { bool nsNetworkManagerListener::HandleMessage(DBusMessage* message) { if (dbus_message_is_signal(message, NM_DBUS_INTERFACE, - NM_DBUS_SIGNAL_STATE_CHANGE)) { + NM_DBUS_SIGNAL_STATE_CHANGE) || + dbus_message_is_signal(message, NM_DBUS_INTERFACE, + NM_DBUS_SIGNAL_STATE_CHANGED)) { UpdateNetworkStatus(message); return true; } @@ -202,7 +202,10 @@ nsNetworkManagerListener::UpdateNetworkStatus(DBusMessage* msg) { mNetworkManagerActive = true; bool wasUp = mLinkUp; - mLinkUp = result == NM_STATE_CONNECTED; + mLinkUp = result == NM_STATE_CONNECTED_OLD || + result == NM_STATE_CONNECTED_LOCAL || + result == NM_STATE_CONNECTED_SITE || + result == NM_STATE_CONNECTED_GLOBAL; if (wasUp == mLinkUp) return; diff --git a/toolkit/themes/gnomestripe/global/inContentUI.css b/toolkit/themes/gnomestripe/global/inContentUI.css index b4f0e2f91f93..88218f146108 100644 --- a/toolkit/themes/gnomestripe/global/inContentUI.css +++ b/toolkit/themes/gnomestripe/global/inContentUI.css @@ -20,6 +20,7 @@ * * Contributor(s): * Blair McBride + * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,11 +36,16 @@ * * ***** END LICENSE BLOCK ***** */ +/* + * The default namespace for this file is XUL. Be sure to prefix rules that + * are applicable to both XUL and HTML with '*|'. + */ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); /* Page background */ -:root { +*|*:root { -moz-appearance: none; padding: 18px; background-color: Window; @@ -48,8 +54,12 @@ color: WindowText; } +html|html { + font: message-box; +} + /* Content */ -.main-content { +*|*.main-content { /* Needed to allow the radius to clip the inner content, see bug 595656 */ /* Disabled because of bug 623615 overflow: hidden; diff --git a/toolkit/themes/pinstripe/global/inContentUI.css b/toolkit/themes/pinstripe/global/inContentUI.css index 55919200843d..38d41b538311 100644 --- a/toolkit/themes/pinstripe/global/inContentUI.css +++ b/toolkit/themes/pinstripe/global/inContentUI.css @@ -20,6 +20,7 @@ * * Contributor(s): * Blair McBride + * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,11 +38,15 @@ %include shared.inc +/* + * The default namespace for this file is XUL. Be sure to prefix rules that + * are applicable to both XUL and HTML with '*|'. + */ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); @namespace html url("http://www.w3.org/1999/xhtml"); /* Page background */ -:root { +*|*:root { -moz-appearance: none; padding: 18px; background-image: /* Texture */ @@ -50,8 +55,12 @@ -moz-linear-gradient(top, #ADB5C2, #BFC6D1); } +html|html { + font: message-box; +} + /* Content */ -.main-content { +*|*.main-content { /* Needed to allow the radius to clip the inner content, see bug 595656 */ /* Disabled because of bug 623615 overflow: hidden; @@ -62,7 +71,7 @@ } /* Buttons */ -button, +*|button, menulist, colorpicker[type="button"] { -moz-appearance: none; @@ -84,6 +93,7 @@ colorpicker[type="button"]:-moz-focusring:not([open="true"]) > .colorpicker-butt outline: 1px dotted #252F3B; } +html|button[disabled], button[disabled="true"], menulist[disabled="true"], colorpicker[type="button"][disabled="true"] { @@ -91,6 +101,7 @@ colorpicker[type="button"][disabled="true"] { color: #505050; } +html|button:not([disabled]):active:hover, button:not([disabled="true"]):active:hover, menulist[open="true"]:not([disabled="true"]), colorpicker[type="button"][open="true"]:not([disabled="true"]) { diff --git a/toolkit/themes/pinstripe/global/media/videocontrols.css b/toolkit/themes/pinstripe/global/media/videocontrols.css index 66d2549a5f42..101a33c4c45c 100644 --- a/toolkit/themes/pinstripe/global/media/videocontrols.css +++ b/toolkit/themes/pinstripe/global/media/videocontrols.css @@ -182,8 +182,13 @@ } /* Statistics formatting */ +html|*.statsDiv { + position: relative; +} html|td { - padding: 2px; + height: 1em; + max-height: 1em; + padding: 0 2px; } html|table { font-family: Helvetica, Ariel, sans-serif; @@ -194,9 +199,11 @@ html|table { 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - width: 100%; + min-width: 100%; background: rgba(68,68,68,.7); table-layout: fixed; + border-collapse: collapse; + position: absolute; } /* CSS Transitions */ diff --git a/toolkit/themes/winstripe/global/inContentUI.css b/toolkit/themes/winstripe/global/inContentUI.css index 159f88791761..e7157849b187 100644 --- a/toolkit/themes/winstripe/global/inContentUI.css +++ b/toolkit/themes/winstripe/global/inContentUI.css @@ -20,6 +20,7 @@ * * Contributor(s): * Blair McBride + * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,10 +36,15 @@ * * ***** END LICENSE BLOCK ***** */ +/* + * The default namespace for this file is XUL. Be sure to prefix rules that + * are applicable to both XUL and HTML with '*|'. + */ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); /* Page background */ -:root { +*|*:root { -moz-appearance: none; padding: 18px; background-repeat: repeat; @@ -50,9 +56,13 @@ url("chrome://global/skin/inContentUI/background-texture.png"); } +html|html { + font: message-box; +} + %ifdef WINSTRIPE_AERO @media all and (-moz-windows-default-theme) { - :root { + *|*:root { color: #000; background-color: #CCD9EA; background-image: /* Fade-out texture at the top */ @@ -63,7 +73,7 @@ } @media all and (-moz-windows-compositor) { - :root { + *|*:root { color: #000; /* Blame shorlander for this monstrosity. */ background-image: /* Fade-out texture and light beams at the top */ @@ -93,7 +103,7 @@ %endif /* Content */ -.main-content { +*|*.main-content { /* Needed to allow the radius to clip the inner content, see bug 595656 */ /* Disabled because of bug 623615 overflow: hidden; @@ -109,7 +119,7 @@ %ifdef WINSTRIPE_AERO @media all and (-moz-windows-compositor) { /* Buttons */ - button, + *|button, menulist, colorpicker[type="button"] { -moz-appearance: none; @@ -133,6 +143,7 @@ outline: 1px dotted ThreeDDarkShadow; } + html|button[disabled], button[disabled="true"], menulist[disabled="true"], colorpicker[type="button"][disabled="true"] { @@ -144,6 +155,7 @@ color: #505050; } + html|button:not([disabled]):active:hover, button:not([disabled="true"]):active:hover, menulist[open="true"]:not([disabled="true"]), colorpicker[type="button"][open="true"]:not([disabled="true"]) { diff --git a/toolkit/themes/winstripe/global/media/videocontrols.css b/toolkit/themes/winstripe/global/media/videocontrols.css index ee5f96873b8b..6cbdf149f677 100644 --- a/toolkit/themes/winstripe/global/media/videocontrols.css +++ b/toolkit/themes/winstripe/global/media/videocontrols.css @@ -191,8 +191,13 @@ } /* Statistics formatting */ +html|*.statsDiv { + position: relative; +} html|td { - padding: 2px; + height: 1em; + max-height: 1em; + padding: 0 2px; } html|table { font-family: Helvetica, Ariel, sans-serif; @@ -203,9 +208,11 @@ html|table { 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - width: 100%; + min-width: 100%; background: rgba(68,68,68,.7); table-layout: fixed; + border-collapse: collapse; + position: absolute; } /* CSS Transitions */ diff --git a/toolkit/xre/glxtest.cpp b/toolkit/xre/glxtest.cpp index d82b05efacab..de9e1776018a 100644 --- a/toolkit/xre/glxtest.cpp +++ b/toolkit/xre/glxtest.cpp @@ -111,7 +111,11 @@ x_error_handler(Display *, XErrorEvent *ev) static void glxtest() { ///// Open libGL and load needed symbols ///// +#ifdef __OpenBSD__ + void *libgl = dlopen("libGL.so", RTLD_LAZY); +#else void *libgl = dlopen("libGL.so.1", RTLD_LAZY); +#endif if (!libgl) fatal_error("Unable to load libGL.so.1"); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index ebdd7b9f1448..c46ce7c88da2 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -71,6 +71,9 @@ #include "MacLaunchHelper.h" #include "MacApplicationDelegate.h" #include "MacAutoreleasePool.h" +// these are needed for sysctl +#include +#include #endif #ifdef XP_OS2 @@ -2436,39 +2439,6 @@ static PRFuncPtr FindFunction(const char* aName) return result; } -static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow) -{ - // get the native window for this instance - nsCOMPtr window(do_QueryInterface(aWindow)); - NS_ENSURE_TRUE(window, nsnull); - - nsCOMPtr baseWindow - (do_QueryInterface(window->GetDocShell())); - NS_ENSURE_TRUE(baseWindow, nsnull); - - nsCOMPtr mainWidget; - baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); - return mainWidget; -} - -static nsGTKToolkit* GetGTKToolkit() -{ - nsCOMPtr svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID); - if (!svc) - return nsnull; - nsCOMPtr window; - svc->GetHiddenDOMWindow(getter_AddRefs(window)); - if (!window) - return nsnull; - nsIWidget* widget = GetMainWidget(window); - if (!widget) - return nsnull; - nsIToolkit* toolkit = widget->GetToolkit(); - if (!toolkit) - return nsnull; - return static_cast(toolkit); -} - static void MOZ_gdk_display_close(GdkDisplay *display) { // XXX wallpaper for bug 417163: don't close the Display if we're using the @@ -2655,6 +2625,8 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) NS_BREAK(); #endif + TriggerQuirks(); + // see bug 639842 // it's very important to fire this process BEFORE we set up error handling. // indeed, this process is expected to be crashy, and we don't want the user to see its crashes. @@ -3496,7 +3468,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) NS_ENSURE_SUCCESS(rv, 1); #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2) - nsRefPtr toolkit = GetGTKToolkit(); + nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); if (toolkit && !desktopStartupID.IsEmpty()) { toolkit->SetDesktopStartupID(desktopStartupID); } @@ -3787,3 +3759,48 @@ SetupErrorHandling(const char* progname) fpsetmask(0); #endif } + +void +TriggerQuirks() +{ +#if defined(XP_MACOSX) + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + // we won't support versions greater than 10.7.99 + char release[sizeof("10.7.99")]; + size_t len = sizeof(release); + // sysctl will return ENOMEM if the release string is longer than sizeof(release) + int ret = sysctl(mib, 2, release, &len, NULL, 0); + // we only want to trigger this on OS X 10.6, on versions 10.6.8 or newer + // Darwin version 10 corresponds to OS X version 10.6, version 11 is 10.7 + // http://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history + if (ret == 0 && NS_CompareVersions(release, "10.8.0") >= 0 && NS_CompareVersions(release, "11") < 0) { + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if (mainBundle) { + CFRetain(mainBundle); + + CFStringRef bundleID = CFBundleGetIdentifier(mainBundle); + if (bundleID) { + CFRetain(bundleID); + + CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle); + CFDictionarySetValue(dict, CFSTR("CFBundleIdentifier"), CFSTR("org.mozilla.firefox")); + + // Calling Gestalt will trigger a load of the quirks table for org.mozilla.firefox + SInt32 major; + ::Gestalt(gestaltSystemVersionMajor, &major); + + // restore the original id + dict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle); + CFDictionarySetValue(dict, CFSTR("CFBundleIdentifier"), bundleID); + + CFRelease(bundleID); + } + CFRelease(mainBundle); + } + } +#endif +} + diff --git a/toolkit/xre/nsAppRunner.h b/toolkit/xre/nsAppRunner.h index 63d2a65316a9..b294ce019ea8 100644 --- a/toolkit/xre/nsAppRunner.h +++ b/toolkit/xre/nsAppRunner.h @@ -194,4 +194,5 @@ extern GeckoProcessType sChildProcessType; */ void SetupErrorHandling(const char* progname); +void TriggerQuirks(); #endif // nsAppRunner_h__ diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 9d3e2e5e5377..9d4172d4b285 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -314,6 +314,8 @@ XRE_InitChildProcess(int aArgc, NS_ENSURE_ARG_POINTER(aArgv); NS_ENSURE_ARG_POINTER(aArgv[0]); + TriggerQuirks(); + sChildProcessType = aProcess; // Complete 'task_t' exchange for Mac OS X. This structure has the same size diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index 54c092effbdd..aec54835bf48 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -148,59 +148,6 @@ typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICO static LdrLoadDll_func stub_LdrLoadDll = 0; -namespace { - -template -struct RVAMap { - RVAMap(HANDLE map, unsigned offset) { - mMappedView = reinterpret_cast - (::MapViewOfFile(map, FILE_MAP_READ, 0, offset, sizeof(T))); - } - ~RVAMap() { - if (mMappedView) { - ::UnmapViewOfFile(mMappedView); - } - } - operator const T*() const { return mMappedView; } - const T* operator->() const { return mMappedView; } -private: - const T* mMappedView; -}; - -void -ForceASLR(const wchar_t* path) -{ - HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, - NULL); - if (file != INVALID_HANDLE_VALUE) { - HANDLE map = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); - if (map) { - RVAMap peHeader(map, 0); - if (peHeader) { - RVAMap ntHeader(map, peHeader->e_lfanew); - if (ntHeader) { - // If we're dealing with a DLL which has code inside it, but does not have the - // ASLR bit set, allocate a page at its base address. - if (((ntHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) && - (ntHeader->OptionalHeader.SizeOfCode > 0)) { - void* page = ::VirtualAlloc((LPVOID)ntHeader->OptionalHeader.ImageBase, 1, - MEM_RESERVE, PAGE_NOACCESS); - // Note that we will leak this page, but it's ok since it's just one page in - // the virtual address space, with no physical page backing it. - - // We're done at this point! - } - } - } - ::CloseHandle(map); - } - ::CloseHandle(file); - } -} - -} - static NTSTATUS NTAPI patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle) { @@ -210,32 +157,9 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam wchar_t *dll_part; DllBlockInfo *info; - // In Windows 8, the first parameter seems to be used for more than just the - // path name. For example, its numerical value can be 1. Passing a non-valid - // pointer to SearchPathW will cause a crash, so we need to check to see if we - // are handed a valid pointer, and otherwise just pass NULL to SearchPathW. - PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath; - int len = moduleFileName->Length / 2; wchar_t *fname = moduleFileName->Buffer; - // figure out the length of the string that we need - DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL); - if (pathlen == 0) { - // uh, we couldn't find the DLL at all, so... - printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName); - return STATUS_DLL_NOT_FOUND; - } - - nsAutoArrayPtr full_fname(new wchar_t[pathlen+1]); - if (!full_fname) { - // couldn't allocate memory? - return STATUS_DLL_NOT_FOUND; - } - - // now actually grab it - SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL); - // The filename isn't guaranteed to be null terminated, but in practice // it always will be; ensure that this is so, and bail if not. // This is done instead of the more robust approach because of bug 527122, @@ -311,6 +235,29 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam #endif if (info->maxVersion != ALL_VERSIONS) { + // In Windows 8, the first parameter seems to be used for more than just the + // path name. For example, its numerical value can be 1. Passing a non-valid + // pointer to SearchPathW will cause a crash, so we need to check to see if we + // are handed a valid pointer, and otherwise just pass NULL to SearchPathW. + PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath; + + // figure out the length of the string that we need + DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL); + if (pathlen == 0) { + // uh, we couldn't find the DLL at all, so... + printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName); + return STATUS_DLL_NOT_FOUND; + } + + wchar_t *full_fname = (wchar_t*) malloc(sizeof(wchar_t)*(pathlen+1)); + if (!full_fname) { + // couldn't allocate memory? + return STATUS_DLL_NOT_FOUND; + } + + // now actually grab it + SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL); + DWORD zero; DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero); @@ -334,6 +281,8 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam load_ok = true; } } + + free(full_fname); } if (!load_ok) { @@ -349,8 +298,6 @@ continue_loading: NS_SetHasLoadedNewDLLs(); - ForceASLR(full_fname); - return stub_LdrLoadDll(filePath, flags, moduleFileName, handle); } diff --git a/view/public/nsIView.h b/view/public/nsIView.h index 02dd1d67ac41..0c1fc9575f08 100644 --- a/view/public/nsIView.h +++ b/view/public/nsIView.h @@ -62,14 +62,8 @@ enum nsViewVisibility { }; #define NS_IVIEW_IID \ - { 0xe0a3b0ee, 0x8d0f, 0x4dcb, \ - { 0x89, 0x04, 0x81, 0x2d, 0xfd, 0x90, 0x00, 0x73 } } - -// Public view flags are defined in this file -#define NS_VIEW_FLAGS_PUBLIC 0x00FF -// Private view flags are private to the view module, -// and are defined in nsView.h -#define NS_VIEW_FLAGS_PRIVATE 0xFF00 + { 0x7caf32d2, 0xd82a, 0x4b9f, \ + { 0x84, 0xc1, 0xbd, 0x20, 0xeb, 0x5c, 0x78, 0x55 } } // Public view flags @@ -84,15 +78,6 @@ enum nsViewVisibility { // is z-index:auto also #define NS_VIEW_FLAG_TOPMOST 0x0010 -struct nsViewZIndex { - bool mIsAuto; - PRInt32 mZIndex; - bool mIsTopmost; - - nsViewZIndex(bool aIsAuto, PRInt32 aZIndex, bool aIsTopmost) - : mIsAuto(aIsAuto), mZIndex(aZIndex), mIsTopmost(aIsTopmost) {} -}; - //---------------------------------------------------------------------- /** @@ -234,19 +219,6 @@ public: */ nsViewVisibility GetVisibility() const { return mVis; } - /** - * Called to query the z-index of a view. - * The z-index is relative to all siblings of the view. - * @result mZIndex: explicit z-index value or 0 if none is set - * mIsAuto: true if the view is zindex:auto - * mIsTopMost: used when this view is zindex:auto - * true if the view is topmost when compared - * with another z-index:auto view - */ - nsViewZIndex GetZIndex() const { return nsViewZIndex((mVFlags & NS_VIEW_FLAG_AUTO_ZINDEX) != 0, - mZIndex, - (mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); } - /** * Get whether the view "floats" above all other views, * which tells the compositor not to consider higher views in diff --git a/view/public/nsIViewManager.h b/view/public/nsIViewManager.h index 51084008ce24..4dea219f1476 100644 --- a/view/public/nsIViewManager.h +++ b/view/public/nsIViewManager.h @@ -405,7 +405,4 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID) // synchronously updates the window(s) right away before returning #define NS_VMREFRESH_IMMEDIATE 0x0002 -//animate scroll operation -#define NS_VMREFRESH_SMOOTHSCROLL 0x0008 - #endif // nsIViewManager_h___ diff --git a/view/public/nsIViewObserver.h b/view/public/nsIViewObserver.h index 3e9dd66d2931..660958d09813 100644 --- a/view/public/nsIViewObserver.h +++ b/view/public/nsIViewObserver.h @@ -50,8 +50,8 @@ class nsRegion; class nsIntRegion; #define NS_IVIEWOBSERVER_IID \ - { 0xdc283a18, 0x61cb, 0x468c, \ - { 0x8d, 0xb8, 0x9b, 0x81, 0xf7, 0xc9, 0x33, 0x25 } } + { 0xac6eec35, 0x65d2, 0x4fe8, \ + { 0xa1, 0x37, 0x1a, 0xc3, 0xf6, 0x51, 0x52, 0x56 } } class nsIViewObserver : public nsISupports { @@ -145,6 +145,11 @@ public: */ NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView) = 0; + /** + * Returns true if the view observer is visible in some way. Otherwise false. + */ + NS_IMETHOD_(bool) IsVisible() = 0; + }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewObserver, NS_IVIEWOBSERVER_IID) diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index 48f812a69ad8..292e8a13350b 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -360,16 +360,6 @@ void nsIView::SetInvalidationDimensions(const nsRect* aRect) return Impl()->SetInvalidationDimensions(aRect); } -void nsView::SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY) -{ - mDimBounds.x += aX - mPosX; - mDimBounds.y += aY - mPosY; - mPosX = aX; - mPosY = aY; - - ResetWidgetBounds(false, true, false); -} - void nsView::ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize) { if (mWindow) { @@ -747,7 +737,7 @@ nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData, // XXX: using aForceUseIWidgetParent=true to preserve previous // semantics. It's not clear that it's actually needed. mWindow = parentWidget->CreateChild(trect, ::HandleEvent, - dx, nsnull, aWidgetInitData, + dx, aWidgetInitData, true).get(); if (!mWindow) { return NS_ERROR_FAILURE; @@ -779,7 +769,7 @@ nsresult nsView::CreateWidgetForParent(nsIWidget* aParentWidget, mWindow = aParentWidget->CreateChild(trect, ::HandleEvent, - dx, nsnull, aWidgetInitData).get(); + dx, aWidgetInitData).get(); if (!mWindow) { return NS_ERROR_FAILURE; } @@ -812,7 +802,7 @@ nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData, // XXX: using aForceUseIWidgetParent=true to preserve previous // semantics. It's not clear that it's actually needed. mWindow = aParentWidget->CreateChild(trect, ::HandleEvent, - dx, nsnull, aWidgetInitData, + dx, aWidgetInitData, true).get(); } else { @@ -826,7 +816,7 @@ nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData, mWindow = nearestParent->CreateChild(trect, ::HandleEvent, - dx, nsnull, aWidgetInitData).get(); + dx, aWidgetInitData).get(); } if (!mWindow) { return NS_ERROR_FAILURE; diff --git a/view/src/nsView.h b/view/src/nsView.h index afbb255322d8..b76579fa1aa5 100644 --- a/view/src/nsView.h +++ b/view/src/nsView.h @@ -182,7 +182,6 @@ public: bool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); } void ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize); - void SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY); void AssertNoWindow(); void NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible); diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 65318b961a53..0dc700a54158 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -265,7 +265,7 @@ void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight) NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight) { if (mRootView) { - if (mRootView->IsEffectivelyVisible()) { + if (mRootView->IsEffectivelyVisible() && mObserver && mObserver->IsVisible()) { if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && mDelayedResize != nsSize(aWidth, aHeight)) { // We have a delayed resize; that now obsolete size may already have @@ -353,8 +353,7 @@ nsIView* nsIViewManager::GetDisplayRootFor(nsIView* aView) rendering. */ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget, - const nsIntRegion& aRegion, - PRUint32 aUpdateFlags) + const nsIntRegion& aRegion) { NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch"); NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager"); @@ -397,7 +396,7 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget, // Unset this flag first, since if aUpdateFlags includes NS_VMREFRESH_IMMEDIATE // we'll reenter this code from the UpdateAllViews call. RootViewManager()->mRecursiveRefreshPending = false; - UpdateAllViews(aUpdateFlags); + UpdateAllViews(0); } } @@ -828,7 +827,8 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, ? vm->mRootView->GetParent()->GetViewManager() : nsnull) { if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && - vm->mRootView->IsEffectivelyVisible()) { + vm->mRootView->IsEffectivelyVisible() && + mObserver && mObserver->IsVisible()) { vm->FlushDelayedResize(true); // Paint later. @@ -885,8 +885,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, } if (view && aEvent->message == NS_PAINT) { - Refresh(view, event->widget, - event->region, NS_VMREFRESH_DOUBLE_BUFFER); + Refresh(view, event->widget, event->region); } } } else if (aEvent->message == NS_PAINT) { diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index 0c86d7e37a4b..541ca8acdea8 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -174,8 +174,7 @@ private: void TriggerRefresh(PRUint32 aUpdateFlags); // aView is the view for aWidget and aRegion is relative to aWidget. - void Refresh(nsView *aView, nsIWidget *aWidget, - const nsIntRegion& aRegion, PRUint32 aUpdateFlags); + void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion); // aRootView is the view for aWidget, aRegion is relative to aRootView, and // aIntRegion is relative to aWidget. void RenderViews(nsView *aRootView, nsIWidget *aWidget, @@ -297,9 +296,6 @@ private: void PostInvalidateEvent(); }; -//when the refresh happens, should it be double buffered? -#define NS_VMREFRESH_DOUBLE_BUFFER 0x0001 - class nsInvalidateEvent : public nsRunnable { public: nsInvalidateEvent(class nsViewManager *vm) : mViewManager(vm) { diff --git a/widget/public/LookAndFeel.h b/widget/public/LookAndFeel.h index 08a34c31da47..aae3b28ca56f 100644 --- a/widget/public/LookAndFeel.h +++ b/widget/public/LookAndFeel.h @@ -457,7 +457,7 @@ public: static nscolor GetColor(ColorID aID, nscolor aDefault = NS_RGB(0, 0, 0)) { - nscolor result; + nscolor result = NS_RGB(0, 0, 0); if (NS_FAILED(GetColor(aID, &result))) { return aDefault; } diff --git a/widget/public/Makefile.in b/widget/public/Makefile.in index 33756e3f2593..a70e65a88576 100644 --- a/widget/public/Makefile.in +++ b/widget/public/Makefile.in @@ -105,7 +105,6 @@ endif XPIDLSRCS = \ nsIAppShell.idl \ nsIFilePicker.idl \ - nsIToolkit.idl \ nsISound.idl \ nsITransferable.idl \ nsIClipboardDragDropHooks.idl \ diff --git a/widget/public/nsIToolkit.idl b/widget/public/nsIToolkit.idl deleted file mode 100644 index 7ffea834833f..000000000000 --- a/widget/public/nsIToolkit.idl +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla browser. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Stuart Parmenter - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsISupports.idl" - -%{ C++ -#include "prthread.h" -%} - -[ptr] native PRThread(PRThread); - - -[uuid(18032BD0-B265-11d1-AA2A-000000000000)] -interface nsIToolkit : nsISupports -{ - /** - * Initialize this toolkit with aThread. - * @param aThread The thread passed in runs the message pump. - * NULL can be passed in, in which case a new thread gets created - * and a message pump will run in that thread - * - */ - void Init(in PRThread aThread); - -}; - - -%{ C++ -extern NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult); -%} diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index 13da907c30de..87961269835d 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -57,7 +57,6 @@ #include "nsXULAppAPI.h" // forward declarations -class nsIToolkit; class nsFontMetrics; class nsRenderingContext; class nsDeviceContext; @@ -120,8 +119,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event); #endif #define NS_IWIDGET_IID \ - { 0x64e1ee3d, 0xe0f2, 0x4ace, \ - { 0x91, 0xb7, 0xdc, 0xd1, 0xbe, 0x69, 0xb6, 0xe6 } } + { 0x712b07a4, 0x4344, 0x4404, \ + { 0xaf, 0x85, 0x63, 0x3d, 0x68, 0x0b, 0x21, 0xb0 } } /* * Window shadow styles @@ -325,7 +324,6 @@ class nsIWidget : public nsISupports { * @param aRect the widget dimension * @param aHandleEventFunction the event handler callback function * @param aContext - * @param aToolkit * @param aInitData data that is used for widget initialization * */ @@ -334,7 +332,6 @@ class nsIWidget : public nsISupports { const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, nsWidgetInitData *aInitData = nsnull) = 0; /** @@ -356,8 +353,7 @@ class nsIWidget : public nsISupports { virtual already_AddRefed CreateChild(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, - nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, + nsDeviceContext *aContext, nsWidgetInitData *aInitData = nsnull, bool aForceUseIWidgetParent = false) = 0; @@ -885,16 +881,6 @@ class nsIWidget : public nsISupports { NS_IMETHOD Update() = 0; - /** - * Return the widget's toolkit - * - * An AddRef has NOT been done for the caller. - * - * @return the toolkit this widget was created in. See nsToolkit. - */ - - virtual nsIToolkit* GetToolkit() = 0; - enum LayerManagerPersistence { LAYER_MANAGER_CURRENT = 0, diff --git a/widget/src/android/Makefile.in b/widget/src/android/Makefile.in index 449ffe1fc901..5c89001c5fa9 100644 --- a/widget/src/android/Makefile.in +++ b/widget/src/android/Makefile.in @@ -55,7 +55,6 @@ CPPSRCS = \ GfxInfo.cpp \ nsWidgetFactory.cpp \ nsAppShell.cpp \ - nsToolkit.cpp \ AndroidJavaWrappers.cpp \ AndroidBridge.cpp \ AndroidJNI.cpp \ diff --git a/widget/src/android/nsToolkit.cpp b/widget/src/android/nsToolkit.cpp deleted file mode 100644 index 3535373d32ae..000000000000 --- a/widget/src/android/nsToolkit.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Mozilla Foundation - * Portions created by the Initial Developer are Copyright (C) 2009-2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Vladimir Vukicevic - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsToolkit.h" -#include "nsGUIEvent.h" -#include "nsGkAtoms.h" - -NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) - -// why do we have this? -static PRUintn gToolkitTLSIndex = 0; - -nsToolkit::nsToolkit() -{ - MOZ_COUNT_CTOR(nsToolkit); -} - -nsToolkit::~nsToolkit() -{ - MOZ_COUNT_DTOR(nsToolkit); - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); -} - -NS_IMETHODIMP -nsToolkit::Init(PRThread *aThread) -{ - return NS_OK; -} - -NS_METHOD -NS_GetCurrentToolkit(nsIToolkit* *aResult) -{ - nsCOMPtr toolkit = nsnull; - nsresult rv = NS_OK; - PRStatus status; - - if (gToolkitTLSIndex == 0) { - status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) - rv = NS_ERROR_FAILURE; - } - - if (NS_FAILED(rv)) - return rv; - - toolkit = (nsIToolkit*) PR_GetThreadPrivate(gToolkitTLSIndex); - if (!toolkit) { - toolkit = new nsToolkit(); - - if (toolkit) { - toolkit->Init(PR_GetCurrentThread()); - - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit.get()); - } else { - rv = NS_ERROR_OUT_OF_MEMORY; - } - } - - NS_IF_ADDREF(*aResult = toolkit); - - return rv; -} diff --git a/widget/src/android/nsWidgetFactory.cpp b/widget/src/android/nsWidgetFactory.cpp index 5b9fc268d2ae..875fc9297bc7 100644 --- a/widget/src/android/nsWidgetFactory.cpp +++ b/widget/src/android/nsWidgetFactory.cpp @@ -41,7 +41,6 @@ #include "nsCOMPtr.h" #include "nsWidgetsCID.h" #include "nsAppShell.h" -#include "nsToolkit.h" #include "nsWindow.h" #include "nsLookAndFeel.h" @@ -61,7 +60,6 @@ #include "nsFilePickerProxy.h" #include "nsXULAppAPI.h" -NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit) NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerAndroid) NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceAndroid) @@ -100,7 +98,6 @@ nsFilePickerConstructor(nsISupports *aOuter, REFNSIID aIID, return picker->QueryInterface(aIID, aResult); } -NS_DEFINE_NAMED_CID(NS_TOOLKIT_CID); NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); NS_DEFINE_NAMED_CID(NS_WINDOW_CID); NS_DEFINE_NAMED_CID(NS_CHILD_CID); @@ -121,7 +118,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_WINDOW_CID, false, NULL, nsWindowConstructor }, { &kNS_CHILD_CID, false, NULL, nsWindowConstructor }, { &kNS_APPSHELL_CID, false, NULL, nsAppShellConstructor }, - { &kNS_TOOLKIT_CID, false, NULL, nsToolkitConstructor }, { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerAndroidConstructor }, { &kNS_IDLE_SERVICE_CID, false, NULL, nsIdleServiceAndroidConstructor }, { &kNS_TRANSFERABLE_CID, false, NULL, nsTransferableConstructor }, @@ -141,7 +137,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widgets/window/android;1", &kNS_WINDOW_CID }, { "@mozilla.org/widgets/child_window/android;1", &kNS_CHILD_CID }, { "@mozilla.org/widget/appshell/android;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/widget/toolkit/android;1", &kNS_TOOLKIT_CID }, { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID }, diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index dd462c1f7e58..56f0882c8290 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -202,7 +202,6 @@ nsWindow::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { ALOG("nsWindow[%p]::Create %p [%d %d %d %d]", (void*)this, (void*)aParent, aRect.x, aRect.y, aRect.width, aRect.height); @@ -230,8 +229,7 @@ nsWindow::Create(nsIWidget *aParent, mBounds.height = gAndroidBounds.height; } - BaseCreate(nsnull, mBounds, aHandleEventFunction, aContext, - aToolkit, aInitData); + BaseCreate(nsnull, mBounds, aHandleEventFunction, aContext, aInitData); NS_ASSERTION(IsTopLevel() || parent, "non top level windowdoesn't have a parent!"); diff --git a/widget/src/android/nsWindow.h b/widget/src/android/nsWindow.h index 57d3c36f60e1..7a3fd00a0672 100644 --- a/widget/src/android/nsWindow.h +++ b/widget/src/android/nsWindow.h @@ -87,7 +87,6 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData); NS_IMETHOD Destroy(void); NS_IMETHOD ConfigureChildren(const nsTArray&); diff --git a/widget/src/build/nsWinWidgetFactory.cpp b/widget/src/build/nsWinWidgetFactory.cpp index b3a52287722c..42150feb725a 100644 --- a/widget/src/build/nsWinWidgetFactory.cpp +++ b/widget/src/build/nsWinWidgetFactory.cpp @@ -52,12 +52,12 @@ #include "nsNativeThemeWin.h" #include "nsScreenManagerWin.h" #include "nsSound.h" -#include "nsToolkit.h" #include "nsWindow.h" #include "WinTaskbar.h" #include "JumpListBuilder.h" #include "JumpListItem.h" #include "GfxInfo.h" +#include "nsToolkit.h" // Drag & Drop, Clipboard @@ -80,7 +80,6 @@ using namespace mozilla::widget; NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(ChildWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit) NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerWin) NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceWin) NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard) @@ -119,7 +118,6 @@ NS_DEFINE_NAMED_CID(NS_WINDOW_CID); NS_DEFINE_NAMED_CID(NS_CHILD_CID); NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); -NS_DEFINE_NAMED_CID(NS_TOOLKIT_CID); NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); NS_DEFINE_NAMED_CID(NS_GFXINFO_CID); NS_DEFINE_NAMED_CID(NS_THEMERENDERER_CID); @@ -155,7 +153,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_CHILD_CID, false, NULL, ChildWindowConstructor }, { &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor }, { &kNS_APPSHELL_CID, false, NULL, nsAppShellConstructor }, - { &kNS_TOOLKIT_CID, false, NULL, nsToolkitConstructor }, { &kNS_SCREENMANAGER_CID, false, NULL, nsScreenManagerWinConstructor }, { &kNS_GFXINFO_CID, false, NULL, GfxInfoConstructor }, { &kNS_THEMERENDERER_CID, false, NULL, NS_NewNativeTheme }, @@ -189,7 +186,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widgets/child_window/win;1", &kNS_CHILD_CID }, { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID }, { "@mozilla.org/widget/appshell/win;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/widget/toolkit/win;1", &kNS_TOOLKIT_CID }, { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID }, { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, @@ -222,6 +218,7 @@ static void nsWidgetWindowsModuleDtor() { nsLookAndFeel::Shutdown(); + nsToolkit::Shutdown(); nsAppShellShutdown(); } diff --git a/widget/src/cocoa/nsChildView.h b/widget/src/cocoa/nsChildView.h index ab8edb1ebdfd..2e7921b6afe8 100644 --- a/widget/src/cocoa/nsChildView.h +++ b/widget/src/cocoa/nsChildView.h @@ -396,7 +396,6 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, nsWidgetInitData *aInitData = nsnull); NS_IMETHOD Destroy(); diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 1c0b53a7ebee..eb71c3080a90 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -294,7 +294,6 @@ nsresult nsChildView::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -325,8 +324,10 @@ nsresult nsChildView::Create(nsIWidget *aParent, mBounds = aRect; - BaseCreate(aParent, aRect, aHandleEventFunction, - aContext, aToolkit, aInitData); + // Ensure that the toolkit is created. + nsToolkit::GetToolkit(); + + BaseCreate(aParent, aRect, aHandleEventFunction, aContext, aInitData); // inherit things from the parent view and create our parallel // NSView in the Cocoa display system diff --git a/widget/src/cocoa/nsCocoaWindow.h b/widget/src/cocoa/nsCocoaWindow.h index 4ea6fbcc6f9b..b53934b26ae9 100644 --- a/widget/src/cocoa/nsCocoaWindow.h +++ b/widget/src/cocoa/nsCocoaWindow.h @@ -216,7 +216,6 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, nsWidgetInitData *aInitData = nsnull); NS_IMETHOD Destroy(); @@ -307,8 +306,7 @@ protected: bool aRectIsFrameRect); nsresult CreatePopupContentView(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, - nsDeviceContext *aContext, - nsIToolkit *aToolkit); + nsDeviceContext *aContext); void DestroyNativeWindow(); void AdjustWindowShadow(); void SetUpWindowFilter(); diff --git a/widget/src/cocoa/nsCocoaWindow.mm b/widget/src/cocoa/nsCocoaWindow.mm index 2e0bb28a2747..6093256346b4 100644 --- a/widget/src/cocoa/nsCocoaWindow.mm +++ b/widget/src/cocoa/nsCocoaWindow.mm @@ -246,7 +246,6 @@ nsresult nsCocoaWindow::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -283,8 +282,11 @@ nsresult nsCocoaWindow::Create(nsIWidget *aParent, mWindowType = eWindowType_toplevel; mBorderStyle = eBorderStyle_default; + // Ensure that the toolkit is created. + nsToolkit::GetToolkit(); + Inherited::BaseCreate(aParent, newBounds, aHandleEventFunction, aContext, - aToolkit, aInitData); + aInitData); mParent = aParent; @@ -300,7 +302,7 @@ nsresult nsCocoaWindow::Create(nsIWidget *aParent, if (aInitData->mIsDragPopup) { [mWindow setIgnoresMouseEvents:YES]; } - return CreatePopupContentView(newBounds, aHandleEventFunction, aContext, aToolkit); + return CreatePopupContentView(newBounds, aHandleEventFunction, aContext); } return NS_OK; @@ -477,8 +479,7 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect, NS_IMETHODIMP nsCocoaWindow::CreatePopupContentView(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, - nsDeviceContext *aContext, - nsIToolkit *aToolkit) + nsDeviceContext *aContext) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -491,7 +492,7 @@ NS_IMETHODIMP nsCocoaWindow::CreatePopupContentView(const nsIntRect &aRect, nsIWidget* thisAsWidget = static_cast(this); mPopupContentView->Create(thisAsWidget, nsnull, aRect, aHandleEventFunction, - aContext, aToolkit, nsnull); + aContext, nsnull); ChildView* newContentView = (ChildView*)mPopupContentView->GetNativeData(NS_NATIVE_WIDGET); [mWindow setContentView:newContentView]; diff --git a/widget/src/cocoa/nsToolkit.h b/widget/src/cocoa/nsToolkit.h index 4bf190ec1844..2d2384f37697 100644 --- a/widget/src/cocoa/nsToolkit.h +++ b/widget/src/cocoa/nsToolkit.h @@ -39,7 +39,7 @@ #ifndef nsToolkit_h_ #define nsToolkit_h_ -#include "nsIToolkit.h" +#include "nscore.h" #import #import @@ -50,14 +50,18 @@ #define MAC_OS_X_VERSION_10_6_HEX 0x00001060 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070 -class nsToolkit : public nsIToolkit +class nsToolkit { public: nsToolkit(); virtual ~nsToolkit(); - NS_DECL_ISUPPORTS - NS_DECL_NSITOOLKIT + static nsToolkit* GetToolkit(); + + static void Shutdown() { + delete gToolkit; + gToolkit = nsnull; + } static PRInt32 OSXVersion(); static bool OnSnowLeopardOrLater(); @@ -78,7 +82,7 @@ protected: protected: - bool mInited; + static nsToolkit* gToolkit; CFRunLoopSourceRef mSleepWakeNotificationRLS; io_object_t mPowerNotifier; @@ -87,6 +91,4 @@ protected: CFRunLoopSourceRef mEventTapRLS; }; -extern nsToolkit* NS_CreateToolkitInstance(); - #endif // nsToolkit_h_ diff --git a/widget/src/cocoa/nsToolkit.mm b/widget/src/cocoa/nsToolkit.mm index 1667413eb95d..f644dfffc5d3 100644 --- a/widget/src/cocoa/nsToolkit.mm +++ b/widget/src/cocoa/nsToolkit.mm @@ -80,17 +80,15 @@ extern nsIWidget * gRollupWidget; static io_connect_t gRootPort = MACH_PORT_NULL; -// Static thread local storage index of the Toolkit -// object associated with a given thread... -static PRUintn gToolkitTLSIndex = 0; +nsToolkit* nsToolkit::gToolkit = nsnull; nsToolkit::nsToolkit() -: mInited(false) -, mSleepWakeNotificationRLS(nsnull) +: mSleepWakeNotificationRLS(nsnull) , mEventTapPort(nsnull) , mEventTapRLS(nsnull) { - MOZ_COUNT_CTOR(nsToolkit); + RegisterForSleepWakeNotifcations(); + RegisterForAllProcessMouseEvents(); } nsToolkit::~nsToolkit() @@ -98,26 +96,6 @@ nsToolkit::~nsToolkit() MOZ_COUNT_DTOR(nsToolkit); RemoveSleepWakeNotifcations(); UnregisterAllProcessMouseEventHandlers(); - // Remove the TLS reference to the toolkit... - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); -} - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsToolkit, nsIToolkit); - -NS_IMETHODIMP -nsToolkit::Init(PRThread * aThread) -{ - mInited = true; - - RegisterForSleepWakeNotifcations(); - RegisterForAllProcessMouseEvents(); - - return NS_OK; -} - -nsToolkit* NS_CreateToolkitInstance() -{ - return new nsToolkit(); } void @@ -319,44 +297,20 @@ nsToolkit::UnregisterAllProcessMouseEventHandlers() NS_OBJC_END_TRY_ABORT_BLOCK; } -// Return the nsIToolkit for the current thread. If a toolkit does not -// yet exist, then one will be created... -NS_IMETHODIMP NS_GetCurrentToolkit(nsIToolkit* *aResult) +// Return the nsToolkit instance. If a toolkit does not yet exist, then one +// will be created. +// static +nsToolkit* nsToolkit::GetToolkit() { - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; - NS_ENSURE_ARG_POINTER(aResult); - *aResult = nsnull; - - // Create the TLS index the first time through... - if (gToolkitTLSIndex == 0) { - PRStatus status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) - return NS_ERROR_FAILURE; + if (!gToolkit) { + gToolkit = new nsToolkit(); } - - // Create a new toolkit for this thread... - nsToolkit* toolkit = (nsToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); - if (!toolkit) { - toolkit = NS_CreateToolkitInstance(); - if (!toolkit) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(toolkit); - toolkit->Init(PR_GetCurrentThread()); - // - // The reference stored in the TLS is weak. It is removed in the - // nsToolkit destructor... - // - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); - } - else { - NS_ADDREF(toolkit); - } - *aResult = toolkit; - return NS_OK; - NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; + return gToolkit; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsnull); } PRInt32 nsToolkit::OSXVersion() diff --git a/widget/src/cocoa/nsWidgetFactory.mm b/widget/src/cocoa/nsWidgetFactory.mm index f711ea17274d..5a7e89bbeb7c 100644 --- a/widget/src/cocoa/nsWidgetFactory.mm +++ b/widget/src/cocoa/nsWidgetFactory.mm @@ -42,7 +42,6 @@ #include "nsWidgetsCID.h" -#include "nsToolkit.h" #include "nsChildView.h" #include "nsCocoaWindow.h" #include "nsAppShell.h" @@ -54,6 +53,7 @@ #include "nsTransferable.h" #include "nsHTMLFormatConverter.h" #include "nsDragService.h" +#include "nsToolkit.h" #include "nsLookAndFeel.h" @@ -69,7 +69,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsCocoaWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildView) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound) NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter) @@ -112,7 +111,6 @@ NS_DEFINE_NAMED_CID(NS_POPUP_CID); NS_DEFINE_NAMED_CID(NS_CHILD_CID); NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); -NS_DEFINE_NAMED_CID(NS_TOOLKIT_CID); NS_DEFINE_NAMED_CID(NS_SOUND_CID); NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID); NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID); @@ -139,7 +137,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_CHILD_CID, false, NULL, nsChildViewConstructor }, { &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor }, { &kNS_APPSHELL_CID, false, NULL, nsAppShellConstructor }, - { &kNS_TOOLKIT_CID, false, NULL, nsToolkitConstructor }, { &kNS_SOUND_CID, false, NULL, nsSoundConstructor }, { &kNS_TRANSFERABLE_CID, false, NULL, nsTransferableConstructor }, { &kNS_HTMLFORMATCONVERTER_CID, false, NULL, nsHTMLFormatConverterConstructor }, @@ -167,7 +164,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widgets/childwindow/mac;1", &kNS_CHILD_CID }, { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID }, { "@mozilla.org/widget/appshell/mac;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/widget/toolkit/mac;1", &kNS_TOOLKIT_CID }, { "@mozilla.org/sound;1", &kNS_SOUND_CID }, { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID }, { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, @@ -193,6 +189,7 @@ static void nsWidgetCocoaModuleDtor() { nsLookAndFeel::Shutdown(); + nsToolkit::Shutdown(); nsAppShellShutdown(); } diff --git a/widget/src/gtk2/nsGTKToolkit.h b/widget/src/gtk2/nsGTKToolkit.h index 713b8713d724..c6f5ef348bdc 100644 --- a/widget/src/gtk2/nsGTKToolkit.h +++ b/widget/src/gtk2/nsGTKToolkit.h @@ -40,7 +40,6 @@ #ifndef GTKTOOLKIT_H #define GTKTOOLKIT_H -#include "nsIToolkit.h" #include "nsString.h" #include @@ -50,15 +49,18 @@ * execute within the same thread that created the widget under Win32. */ -class nsGTKToolkit : public nsIToolkit +class nsGTKToolkit { public: nsGTKToolkit(); virtual ~nsGTKToolkit(); - NS_DECL_ISUPPORTS + static nsGTKToolkit* GetToolkit(); - NS_IMETHOD Init(PRThread *aThread); + static void Shutdown() { + delete gToolkit; + gToolkit = nsnull; + } void CreateSharedGC(void); GdkGC *GetSharedGC(void); @@ -79,6 +81,8 @@ public: PRUint32 GetFocusTimestamp() { return mFocusTimestamp; } private: + static nsGTKToolkit* gToolkit; + GdkGC *mSharedGC; nsCString mDesktopStartupID; PRUint32 mFocusTimestamp; diff --git a/widget/src/gtk2/nsToolkit.cpp b/widget/src/gtk2/nsToolkit.cpp index 778be8f83fde..edc3fac20430 100644 --- a/widget/src/gtk2/nsToolkit.cpp +++ b/widget/src/gtk2/nsToolkit.cpp @@ -40,11 +40,7 @@ #include "nscore.h" // needed for 'nsnull' #include "nsGTKToolkit.h" -// -// Static thread local storage index of the Toolkit -// object associated with a given thread... -// -static PRUintn gToolkitTLSIndex = 0; +nsGTKToolkit* nsGTKToolkit::gToolkit = nsnull; //------------------------------------------------------------------------- // @@ -52,9 +48,9 @@ static PRUintn gToolkitTLSIndex = 0; // //------------------------------------------------------------------------- nsGTKToolkit::nsGTKToolkit() + : mSharedGC(nsnull), mFocusTimestamp(0) { - mSharedGC = nsnull; - mFocusTimestamp = 0; + CreateSharedGC(); } //------------------------------------------------------------------------- @@ -67,19 +63,8 @@ nsGTKToolkit::~nsGTKToolkit() if (mSharedGC) { g_object_unref(mSharedGC); } - - // Remove the TLS reference to the toolkit... - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); } -//------------------------------------------------------------------------- -// -// nsISupports implementation macro -// -//------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS1(nsGTKToolkit, nsIToolkit) - void nsGTKToolkit::CreateSharedGC(void) { GdkPixmap *pixmap; @@ -97,64 +82,15 @@ GdkGC *nsGTKToolkit::GetSharedGC(void) return (GdkGC *)g_object_ref(mSharedGC); } -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -NS_IMETHODIMP nsGTKToolkit::Init(PRThread *aThread) +//------------------------------------------------------------------------------- +// Return the toolkit. If a toolkit does not yet exist, then one will be created. +//------------------------------------------------------------------------------- +// static +nsGTKToolkit* nsGTKToolkit::GetToolkit() { - CreateSharedGC(); - return NS_OK; -} - - -//------------------------------------------------------------------------- -// -// Return the nsIToolkit for the current thread. If a toolkit does not -// yet exist, then one will be created... -// -//------------------------------------------------------------------------- -NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) -{ - nsIToolkit* toolkit = nsnull; - nsresult rv = NS_OK; - PRStatus status; - - // Create the TLS index the first time through... - if (0 == gToolkitTLSIndex) { - status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) { - rv = NS_ERROR_FAILURE; - } + if (!gToolkit) { + gToolkit = new nsGTKToolkit(); } - - if (NS_SUCCEEDED(rv)) { - toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); - - // - // Create a new toolkit for this thread... - // - if (!toolkit) { - toolkit = new nsGTKToolkit(); - - if (!toolkit) { - rv = NS_ERROR_OUT_OF_MEMORY; - } else { - NS_ADDREF(toolkit); - toolkit->Init(PR_GetCurrentThread()); - // - // The reference stored in the TLS is weak. It is - // removed in the nsToolkit destructor... - // - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); - } - } else { - NS_ADDREF(toolkit); - } - *aResult = toolkit; - } - - return rv; + + return gToolkit; } - - diff --git a/widget/src/gtk2/nsWidgetFactory.cpp b/widget/src/gtk2/nsWidgetFactory.cpp index 6fdabd936bd5..a8b3588c8e4d 100644 --- a/widget/src/gtk2/nsWidgetFactory.cpp +++ b/widget/src/gtk2/nsWidgetFactory.cpp @@ -55,6 +55,7 @@ #include "nsBidiKeyboard.h" #include "nsNativeKeyBindings.h" #include "nsScreenManagerGtk.h" +#include "nsGTKToolkit.h" #ifdef NS_PRINTING #include "nsPrintOptionsGTK.h" @@ -339,6 +340,7 @@ nsWidgetGtk2ModuleDtor() nsFilePicker::Shutdown(); nsSound::Shutdown(); nsWindow::ReleaseGlobals(); + nsGTKToolkit::Shutdown(); nsAppShellShutdown(); } diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp index d0d180a8474e..2fd6f64914b1 100644 --- a/widget/src/gtk2/nsWindow.cpp +++ b/widget/src/gtk2/nsWindow.cpp @@ -1407,13 +1407,10 @@ typedef void (* SetUserTimeFunc)(GdkWindow* aWindow, guint32 aTimestamp); static void SetUserTimeAndStartupIDForActivatedWindow(GtkWidget* aWindow) { - nsCOMPtr toolkit; - NS_GetCurrentToolkit(getter_AddRefs(toolkit)); - if (!toolkit) + nsGTKToolkit* GTKToolkit = nsGTKToolkit::GetToolkit(); + if (!GTKToolkit) return; - nsGTKToolkit* GTKToolkit = static_cast - (static_cast(toolkit)); nsCAutoString desktopStartupID; GTKToolkit->GetDesktopStartupID(&desktopStartupID); if (desktopStartupID.IsEmpty()) { @@ -1744,8 +1741,9 @@ nsWindow::GetNativeData(PRUint32 aDataType) case NS_NATIVE_GRAPHIC: { #if defined(MOZ_WIDGET_GTK2) - NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC"); - return (void *)static_cast(mToolkit)->GetSharedGC(); + nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); + NS_ASSERTION(nsnull != toolkit, "NULL toolkit, unable to get a GC"); + return toolkit->GetSharedGC(); #else return nsnull; #endif @@ -3880,7 +3878,6 @@ nsWindow::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { // only set the base parent if we're going to be a dialog or a @@ -3893,9 +3890,11 @@ nsWindow::Create(nsIWidget *aParent, NS_ASSERTION(!mWindowGroup, "already have window group (leaking it)"); + // Ensure that the toolkit is created. + nsGTKToolkit::GetToolkit(); + // initialize all the common bits of this class - BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, - aToolkit, aInitData); + BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, aInitData); // Do we need to listen for resizes? bool listenForResizes = false;; diff --git a/widget/src/gtk2/nsWindow.h b/widget/src/gtk2/nsWindow.h index 17afae40833e..a72eca757d45 100644 --- a/widget/src/gtk2/nsWindow.h +++ b/widget/src/gtk2/nsWindow.h @@ -138,7 +138,6 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData); NS_IMETHOD Destroy(void); virtual nsIWidget *GetParent(); diff --git a/widget/src/os2/Makefile.in b/widget/src/os2/Makefile.in index 13a62f8b2e5a..a17378267149 100644 --- a/widget/src/os2/Makefile.in +++ b/widget/src/os2/Makefile.in @@ -62,7 +62,6 @@ CPPSRCS = \ nsOS2Uni.cpp \ nsPrintOS2.cpp \ nsSound.cpp \ - nsToolkit.cpp \ nsWidgetFactory.cpp \ nsWindow.cpp \ nsDragService.cpp \ diff --git a/widget/src/os2/nsToolkit.cpp b/widget/src/os2/nsToolkit.cpp deleted file mode 100644 index 4366dcc69c87..000000000000 --- a/widget/src/os2/nsToolkit.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * John Fairhurst - * Pierre Phaneuf - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsToolkit.h" - -NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) - -// -// Static thread local storage index of the Toolkit -// object associated with a given thread... -// -static PRUintn gToolkitTLSIndex = 0; - -//------------------------------------------------------------------------- -// -// constructor -// -//------------------------------------------------------------------------- -nsToolkit::nsToolkit() -{ - MOZ_COUNT_CTOR(nsToolkit); -} - - -//------------------------------------------------------------------------- -// -// destructor -// -//------------------------------------------------------------------------- -nsToolkit::~nsToolkit() -{ - MOZ_COUNT_DTOR(nsToolkit); - // Remove the TLS reference to the toolkit... - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); -} - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -NS_METHOD nsToolkit::Init(PRThread *aThread) -{ - NS_ASSERTION(aThread, "Can only initialize toolkit on the current thread"); - return NS_OK; -} - -//------------------------------------------------------------------------- -// -// Return the nsIToolkit for the current thread. If a toolkit does not -// yet exist, then one will be created... -// -//------------------------------------------------------------------------- -NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) -{ - nsIToolkit* toolkit = nsnull; - nsresult rv = NS_OK; - PRStatus status; - - // Create the TLS index the first time through... - if (0 == gToolkitTLSIndex) { - status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) { - rv = NS_ERROR_FAILURE; - } - } - - if (NS_SUCCEEDED(rv)) { - toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); - - // - // Create a new toolkit for this thread... - // - if (!toolkit) { - toolkit = new nsToolkit(); - - if (!toolkit) { - rv = NS_ERROR_OUT_OF_MEMORY; - } else { - NS_ADDREF(toolkit); - toolkit->Init(PR_GetCurrentThread()); - // - // The reference stored in the TLS is weak. It is removed in the - // nsToolkit destructor... - // - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); - } - } else { - NS_ADDREF(toolkit); - } - *aResult = toolkit; - } - - return rv; -} diff --git a/widget/src/os2/nsWidgetFactory.cpp b/widget/src/os2/nsWidgetFactory.cpp index 92c0f11281e7..45653ceb4502 100644 --- a/widget/src/os2/nsWidgetFactory.cpp +++ b/widget/src/os2/nsWidgetFactory.cpp @@ -69,7 +69,6 @@ #include "nsFilePicker.h" #include "nsLookAndFeel.h" #include "nsSound.h" -#include "nsToolkit.h" // Drag & Drop, Clipboard #include "nsClipboard.h" @@ -94,7 +93,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper) NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker) NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit) NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService) @@ -115,7 +113,6 @@ NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID); NS_DEFINE_NAMED_CID(NS_DRAGSERVICE_CID); NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID); NS_DEFINE_NAMED_CID(NS_SOUND_CID); -NS_DEFINE_NAMED_CID(NS_TOOLKIT_CID); NS_DEFINE_NAMED_CID(NS_WINDOW_CID); NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID); NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID); @@ -137,7 +134,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_DRAGSERVICE_CID, false, NULL, nsDragServiceConstructor }, { &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor }, { &kNS_SOUND_CID, false, NULL, nsSoundConstructor }, - { &kNS_TOOLKIT_CID, false, NULL, nsToolkitConstructor }, { &kNS_WINDOW_CID, false, NULL, nsWindowConstructor }, { &kNS_TRANSFERABLE_CID, false, NULL, nsTransferableConstructor }, { &kNS_HTMLFORMATCONVERTER_CID, false, NULL, nsHTMLFormatConverterConstructor }, @@ -160,7 +156,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID }, { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID }, { "@mozilla.org/sound;1", &kNS_SOUND_CID }, - { "@mozilla.org/widget/toolkit/os2;1", &kNS_TOOLKIT_CID }, { "@mozilla.org/widget/window/os2;1", &kNS_WINDOW_CID }, { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID }, { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, diff --git a/widget/src/os2/nsWindow.cpp b/widget/src/os2/nsWindow.cpp index a50c8ec50388..dbea32f532fc 100644 --- a/widget/src/os2/nsWindow.cpp +++ b/widget/src/os2/nsWindow.cpp @@ -79,7 +79,6 @@ #include "nsIScreenManager.h" #include "nsOS2Uni.h" #include "nsTHashtable.h" -#include "nsToolkit.h" #include "nsGkAtoms.h" #include "wdgtos2rc.h" @@ -336,7 +335,6 @@ NS_METHOD nsWindow::Create(nsIWidget* aParent, const nsIntRect& aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext* aContext, - nsIToolkit* aToolkit, nsWidgetInitData* aInitData) { mWindowState = nsWindowState_eInCreate; @@ -359,9 +357,7 @@ NS_METHOD nsWindow::Create(nsIWidget* aParent, } } - BaseCreate(aParent, aRect, aHandleEventFunction, - aContext, aToolkit, aInitData); - + BaseCreate(aParent, aRect, aHandleEventFunction, aContext, aInitData); #ifdef DEBUG_FOCUS mWindowIdentifier = currentWindowIdentifier; @@ -1921,7 +1917,7 @@ void nsWindow::OnDestroy() SetNSWindowPtr(mWnd, 0); mWnd = 0; - // release references to context, toolkit, appshell, children + // release references to context and children nsBaseWidget::OnDestroy(); // dispatching of the event may cause the reference count to drop to 0 diff --git a/widget/src/os2/nsWindow.h b/widget/src/os2/nsWindow.h index 5a2cfd1bb2d6..f240d8f8c9ed 100644 --- a/widget/src/os2/nsWindow.h +++ b/widget/src/os2/nsWindow.h @@ -166,7 +166,6 @@ public: const nsIntRect& aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext* aContext, - nsIToolkit* aToolkit = nsnull, nsWidgetInitData* aInitData = nsnull); NS_IMETHOD Destroy(); virtual nsIWidget* GetParent(); diff --git a/widget/src/qt/Makefile.in b/widget/src/qt/Makefile.in index 4d4339f6eb5c..d77efa8eb7d3 100644 --- a/widget/src/qt/Makefile.in +++ b/widget/src/qt/Makefile.in @@ -71,7 +71,6 @@ CPPSRCS += \ nsWidgetFactory.cpp \ nsWindow.cpp \ nsLookAndFeel.cpp \ - nsToolkit.cpp \ nsScreenQt.cpp \ nsScreenManagerQt.cpp \ nsQtKeyUtils.cpp \ diff --git a/widget/src/qt/nsToolkit.cpp b/widget/src/qt/nsToolkit.cpp deleted file mode 100644 index f823b632d206..000000000000 --- a/widget/src/qt/nsToolkit.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Lars Knoll - * Zack Rusin - * John C. Griggs - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsToolkit.h" - -#include "nscore.h" // needed for 'nsnull' - -#include "nsGUIEvent.h" - -// Static thread local storage index of the Toolkit -// object associated with a given thread... -static PRUintn gToolkitTLSIndex = 0; - -//------------------------------------------------------------------------- -// constructor -//------------------------------------------------------------------------- -nsToolkit::nsToolkit() -{ - MOZ_COUNT_CTOR(nsToolkit); -} - -//------------------------------------------------------------------------- -// destructor -//------------------------------------------------------------------------- -nsToolkit::~nsToolkit() -{ - MOZ_COUNT_DTOR(nsToolkit); - // Remove the TLS reference to the toolkit... - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); -} - -//------------------------------------------------------------------------- -// nsISupports implementation macro -//------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) - -//------------------------------------------------------------------------- -NS_IMETHODIMP nsToolkit::Init(PRThread *aThread) -{ - return NS_OK; -} - -//------------------------------------------------------------------------- -// Return the nsIToolkit for the current thread. If a toolkit does not -// yet exist, then one will be created... -//------------------------------------------------------------------------- -NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) -{ - nsIToolkit* toolkit = nsnull; - nsresult rv = NS_OK; - PRStatus status; - - // Create the TLS index the first time through... - if (0 == gToolkitTLSIndex) { - status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) { - rv = NS_ERROR_FAILURE; - } - } - if (NS_SUCCEEDED(rv)) { - toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); - - // Create a new toolkit for this thread... - if (!toolkit) { - toolkit = new nsToolkit(); - - if (!toolkit) { - rv = NS_ERROR_OUT_OF_MEMORY; - } - else { - NS_ADDREF(toolkit); - toolkit->Init(PR_GetCurrentThread()); - - // The reference stored in the TLS is weak. It is removed in the - // nsToolkit destructor... - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); - } - } - else { - NS_ADDREF(toolkit); - } - *aResult = toolkit; - } - return rv; -} - -void nsToolkit::CreateSharedGC(void) -{ - if (mSharedGC) - return; - - mSharedGC = new QPixmap(); -} - -Qt::HANDLE -nsToolkit::GetSharedGC(void) -{ - // FIXME Not sure -#ifdef MOZ_X11 - return mSharedGC->handle(); -#else - return 0; -#endif -} diff --git a/widget/src/qt/nsToolkit.h b/widget/src/qt/nsToolkit.h deleted file mode 100644 index d67d108e431c..000000000000 --- a/widget/src/qt/nsToolkit.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * John C. Griggs - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#ifndef nsToolkit_h__ -#define nsToolkit_h__ - -#include - -#include "nsIToolkit.h" -#include "nsString.h" - -/** - * Wrapper around the thread running the message pump. - * The toolkit abstraction is necessary because the message pump must - * execute within the same thread that created the widget under Win32. - */ -class nsToolkit : public nsIToolkit -{ -public: - nsToolkit(); - virtual ~nsToolkit(); - - void CreateSharedGC(void); - Qt::HANDLE GetSharedGC(void); - - /** - * Get/set our value of DESKTOP_STARTUP_ID. When non-empty, this is applied - * to the next toplevel window to be shown or focused (and then immediately - * cleared). - */ - void SetDesktopStartupID(const nsACString& aID) { mDesktopStartupID = aID; } - void GetDesktopStartupID(nsACString* aID) { *aID = mDesktopStartupID; } - - /** - * Get/set the timestamp value to be used, if non-zero, to focus the - * next top-level window to be shown or focused (upon which it is cleared). - */ - void SetFocusTimestamp(PRUint32 aTimestamp) { mFocusTimestamp = aTimestamp; } - PRUint32 GetFocusTimestamp() { return mFocusTimestamp; } - - NS_DECL_ISUPPORTS - NS_IMETHOD Init(PRThread *aThread); - -private: - nsCString mDesktopStartupID; - PRUint32 mFocusTimestamp; - QPixmap *mSharedGC; -}; - -#endif // nsToolkit_h__ diff --git a/widget/src/qt/nsWidgetFactory.cpp b/widget/src/qt/nsWidgetFactory.cpp index a67601aabbfd..00f70fb578bc 100644 --- a/widget/src/qt/nsWidgetFactory.cpp +++ b/widget/src/qt/nsWidgetFactory.cpp @@ -47,7 +47,6 @@ #include "nsCOMPtr.h" #include "nsWidgetsCID.h" -#include "nsToolkit.h" #include "nsHTMLFormatConverter.h" #include "nsTransferable.h" #include "nsLookAndFeel.h" @@ -80,7 +79,6 @@ extern bool gDisableNativeTheme; NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildWindow) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPopupWindow) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable) NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerQt) @@ -168,7 +166,6 @@ NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); NS_DEFINE_NAMED_CID(NS_THEMERENDERER_CID); NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID); NS_DEFINE_NAMED_CID(NS_POPUP_CID); -NS_DEFINE_NAMED_CID(NS_TOOLKIT_CID); #ifdef NS_PRINTING NS_DEFINE_NAMED_CID(NS_PRINTSETTINGSSERVICE_CID); NS_DEFINE_NAMED_CID(NS_PRINTER_ENUMERATOR_CID); @@ -197,7 +194,6 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = { { &kNS_THEMERENDERER_CID, false, NULL, nsNativeThemeQtConstructor }, { &kNS_IDLE_SERVICE_CID, false, NULL, nsIdleServiceQtConstructor }, { &kNS_POPUP_CID, false, NULL, nsPopupWindowConstructor }, - { &kNS_TOOLKIT_CID, false, NULL, nsToolkitConstructor }, #ifdef NS_PRINTING { &kNS_PRINTSETTINGSSERVICE_CID, false, NULL, nsPrintOptionsQtConstructor }, { &kNS_PRINTER_ENUMERATOR_CID, false, NULL, nsPrinterEnumeratorQtConstructor }, @@ -227,7 +223,6 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID }, { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, { "@mozilla.org/widgets/popup_window/qt;1", &kNS_POPUP_CID }, - { "@mozilla.org/widget/toolkit/qt;1", &kNS_TOOLKIT_CID }, #ifdef NS_PRINTING { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID }, { "@mozilla.org/gfx/printerenumerator;1", &kNS_PRINTER_ENUMERATOR_CID }, diff --git a/widget/src/qt/nsWindow.cpp b/widget/src/qt/nsWindow.cpp index a99bf5fcd4d5..4d68d4dfad00 100644 --- a/widget/src/qt/nsWindow.cpp +++ b/widget/src/qt/nsWindow.cpp @@ -95,7 +95,6 @@ using namespace QtMobility; #include "mozqorientationsensorfilter.h" #endif -#include "nsToolkit.h" #include "nsIdleService.h" #include "nsRenderingContext.h" #include "nsIRollupListener.h" @@ -824,8 +823,7 @@ nsWindow::GetNativeData(PRUint32 aDataType) break; case NS_NATIVE_GRAPHIC: { - NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC"); - return (void *)static_cast(mToolkit)->GetSharedGC(); + return nsnull; break; } @@ -2255,7 +2253,6 @@ nsWindow::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { // only set the base parent if we're not going to be a dialog or a @@ -2273,8 +2270,7 @@ nsWindow::Create(nsIWidget *aParent, } // initialize all the common bits of this class - BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, - aToolkit, aInitData); + BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, aInitData); // and do our common creation mParent = aParent; @@ -2310,7 +2306,6 @@ already_AddRefed nsWindow::CreateChild(const nsIntRect& aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext* aContext, - nsIToolkit* aToolkit, nsWidgetInitData* aInitData, bool /*aForceUseIWidgetParent*/) { @@ -2318,7 +2313,6 @@ nsWindow::CreateChild(const nsIntRect& aRect, return nsBaseWidget::CreateChild(aRect, aHandleEventFunction, aContext, - aToolkit, aInitData, true); // Force parent } @@ -3124,7 +3118,7 @@ nsWindow::OnDestroy(void) mOnDestroyCalled = true; - // release references to children, device context, toolkit + app shell + // release references to children and device context nsBaseWidget::OnDestroy(); // let go of our parent diff --git a/widget/src/qt/nsWindow.h b/widget/src/qt/nsWindow.h index a35fa9cb4a95..e05878f73ce8 100644 --- a/widget/src/qt/nsWindow.h +++ b/widget/src/qt/nsWindow.h @@ -128,14 +128,12 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData); virtual already_AddRefed CreateChild(const nsIntRect& aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext* aContext, - nsIToolkit* aToolkit = nsnull, nsWidgetInitData* aInitData = nsnull, bool aForceUseIWidgetParent = true); diff --git a/widget/src/windows/nsDataObj.h b/widget/src/windows/nsDataObj.h index f974b7bc62be..6ca4cd1061f0 100644 --- a/widget/src/windows/nsDataObj.h +++ b/widget/src/windows/nsDataObj.h @@ -44,6 +44,7 @@ #include #endif #include +#include #include "nsCOMPtr.h" #include "nsString.h" @@ -55,6 +56,13 @@ #include "nsCOMArray.h" #include "nsITimer.h" +// The SDK shipping with VC11 has renamed IAsyncOperation to +// IDataObjectAsyncCapability. We try to detect this, and rename this in our +// code too to make sure that we pick the correct name when building. +#ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__ +#define IAsyncOperation IDataObjectAsyncCapability +#define IID_IAsyncOperation IID_IDataObjectAsyncCapability +#else // XXX for older version of PSDK where IAsyncOperation and related stuff is not available // but thisdefine should be removed when parocles config is updated #ifndef __IAsyncOperation_INTERFACE_DEFINED__ @@ -78,6 +86,7 @@ IAsyncOperation : public IUnknown #endif #endif // __IAsyncOperation_INTERFACE_DEFINED__ +#endif // __IDataObjectAsyncCapability_INTERFACE_DEFINED__ /* * CFSTR_SHELLURL is deprecated and doesn't have a Unicode version. diff --git a/widget/src/windows/nsIMM32Handler.cpp b/widget/src/windows/nsIMM32Handler.cpp index a6b8d4786ffe..b978286dfa38 100644 --- a/widget/src/windows/nsIMM32Handler.cpp +++ b/widget/src/windows/nsIMM32Handler.cpp @@ -2066,7 +2066,8 @@ nsIMM32Handler::ResolveIMECaretPos(nsIWidget* aReferenceWidget, bool nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction) { - if (!sWM_MSIME_MOUSE || !mIsComposing) { + if (!sWM_MSIME_MOUSE || !mIsComposing || + !ShouldDrawCompositionStringOurselves()) { return false; } @@ -2090,8 +2091,18 @@ nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction) ResolveIMECaretPos(aWindow, cursorRect, aWindow->GetTopLevelWindow(false), cursorInTopLevel); PRInt32 cursorXInChar = cursorInTopLevel.x - charAtPt.mReply.mRect.x; - int positioning = cursorXInChar * 4 / charAtPt.mReply.mRect.width; - positioning = (positioning + 2) % 4; + // The event might hit to zero-width character, see bug 694913. + // The reason might be: + // * There are some zero-width characters are actually. + // * font-size is specified zero. + // But nobody reproduced this bug actually... + // We should assume that user clicked on right most of the zero-width + // character in such case. + int positioning = 1; + if (charAtPt.mReply.mRect.width > 0) { + positioning = cursorXInChar * 4 / charAtPt.mReply.mRect.width; + positioning = (positioning + 2) % 4; + } int offset = charAtPt.mReply.mOffset - mCompositionStart; if (positioning < 2) { diff --git a/widget/src/windows/nsToolkit.cpp b/widget/src/windows/nsToolkit.cpp index 173ab0a1eb3d..4792f9b2e8f0 100644 --- a/widget/src/windows/nsToolkit.cpp +++ b/widget/src/windows/nsToolkit.cpp @@ -53,14 +53,7 @@ // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN #include -NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit) - -// -// Static thread local storage index of the Toolkit -// object associated with a given thread... -// -static PRUintn gToolkitTLSIndex = 0; - +nsToolkit* nsToolkit::gToolkit = nsnull; HINSTANCE nsToolkit::mDllInstance = 0; bool nsToolkit::mIsWinXP = false; @@ -125,6 +118,22 @@ nsToolkit::nsToolkit() #endif gMouseTrailer = new MouseTrailer(); + + // Store the thread ID of the thread containing the message pump. + // If no thread is provided create one + PRThread* thread = PR_GetCurrentThread(); + if (NULL != thread) { + CreateInternalWindow(thread); + } else { + // create a thread where the message pump will run + CreateUIThread(); + } + + mD3D9Timer = do_CreateInstance("@mozilla.org/timer;1"); + mD3D9Timer->InitWithFuncCallback(::StartAllowingD3D9, + NULL, + kD3DUsageDelay, + nsITimer::TYPE_ONE_SHOT); } @@ -142,18 +151,11 @@ nsToolkit::~nsToolkit() ::DestroyWindow(mDispatchWnd); mDispatchWnd = NULL; - // Remove the TLS reference to the toolkit... - PR_SetThreadPrivate(gToolkitTLSIndex, nsnull); - if (gMouseTrailer) { gMouseTrailer->DestroyTimer(); delete gMouseTrailer; gMouseTrailer = nsnull; } - -#if defined (MOZ_STATIC_COMPONENT_LIBS) - nsToolkit::Shutdown(); -#endif } void @@ -185,18 +187,21 @@ nsToolkit::Startup(HMODULE hModule) void nsToolkit::Shutdown() { +#if defined (MOZ_STATIC_COMPONENT_LIBS) // Crashes on certain XP machines/profiles - see bug 448104 for details //nsUXThemeData::Teardown(); //VERIFY(::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance)); ::UnregisterClassW(L"nsToolkitClass", nsToolkit::mDllInstance); +#endif + + delete gToolkit; + gToolkit = nsnull; } void nsToolkit::StartAllowingD3D9() { - nsRefPtr toolkit; - NS_GetCurrentToolkit(getter_AddRefs(toolkit)); - static_cast(toolkit.get())->mD3D9Timer->Cancel(); + nsToolkit::GetToolkit()->mD3D9Timer->Cancel(); nsWindow::StartAllowingD3D9(false); } @@ -264,30 +269,6 @@ void nsToolkit::CreateUIThread() } -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -NS_METHOD nsToolkit::Init(PRThread *aThread) -{ - // Store the thread ID of the thread containing the message pump. - // If no thread is provided create one - if (NULL != aThread) { - CreateInternalWindow(aThread); - } else { - // create a thread where the message pump will run - CreateUIThread(); - } - - mD3D9Timer = do_CreateInstance("@mozilla.org/timer;1"); - mD3D9Timer->InitWithFuncCallback(::StartAllowingD3D9, - NULL, - kD3DUsageDelay, - nsITimer::TYPE_ONE_SHOT); - - return NS_OK; -} - //------------------------------------------------------------------------- // // nsToolkit WindowProc. Used to call methods on the "main GUI thread"... @@ -319,51 +300,18 @@ LRESULT CALLBACK nsToolkit::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, //------------------------------------------------------------------------- // -// Return the nsIToolkit for the current thread. If a toolkit does not +// Return the nsToolkit for the current thread. If a toolkit does not // yet exist, then one will be created... // //------------------------------------------------------------------------- -NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) +// static +nsToolkit* nsToolkit::GetToolkit() { - nsIToolkit* toolkit = nsnull; - nsresult rv = NS_OK; - PRStatus status; - - // Create the TLS index the first time through... - if (0 == gToolkitTLSIndex) { - status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); - if (PR_FAILURE == status) { - rv = NS_ERROR_FAILURE; - } + if (!gToolkit) { + gToolkit = new nsToolkit(); } - if (NS_SUCCEEDED(rv)) { - toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); - - // - // Create a new toolkit for this thread... - // - if (!toolkit) { - toolkit = new nsToolkit(); - - if (!toolkit) { - rv = NS_ERROR_OUT_OF_MEMORY; - } else { - NS_ADDREF(toolkit); - toolkit->Init(PR_GetCurrentThread()); - // - // The reference stored in the TLS is weak. It is removed in the - // nsToolkit destructor... - // - PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); - } - } else { - NS_ADDREF(toolkit); - } - *aResult = toolkit; - } - - return rv; + return gToolkit; } diff --git a/widget/src/windows/nsToolkit.h b/widget/src/windows/nsToolkit.h index e326dab5f3c8..9838c44fe2d9 100644 --- a/widget/src/windows/nsToolkit.h +++ b/widget/src/windows/nsToolkit.h @@ -40,7 +40,6 @@ #define TOOLKIT_H #include "nsdefs.h" -#include "nsIToolkit.h" #include "nsITimer.h" #include "nsCOMPtr.h" @@ -73,15 +72,11 @@ class MouseTrailer; * execute within the same thread that created the widget under Win32. */ -class nsToolkit : public nsIToolkit +class nsToolkit { public: - - NS_DECL_ISUPPORTS - nsToolkit(); - NS_IMETHOD Init(PRThread *aThread); void CreateInternalWindow(PRThread *aThread); private: @@ -89,6 +84,9 @@ private: void CreateUIThread(void); public: + + static nsToolkit* GetToolkit(); + // Window procedure for the internal window static LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, @@ -96,6 +94,8 @@ public: LPARAM lParam); protected: + static nsToolkit* gToolkit; + // Handle of the window used to receive dispatch messages. HWND mDispatchWnd; // Thread Id of the "main" Gui thread. @@ -115,8 +115,6 @@ public: static MouseTrailer *gMouseTrailer; }; -class nsWindow; - /** * Makes sure exit/enter mouse messages are always dispatched. * In the case where the mouse has exited the outer most window the diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index d35d14a0a7df..d1222c71fec9 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -178,7 +178,6 @@ #include "nsNativeDragTarget.h" #include // needed for WIN32_LEAN_AND_MEAN #include -#include #include #if defined(ACCESSIBILITY) @@ -506,7 +505,6 @@ nsWindow::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { nsWidgetInitData defaultInitData; @@ -523,7 +521,10 @@ nsWindow::Create(nsIWidget *aParent, mIsTopWidgetWindow = (nsnull == baseParent); mBounds = aRect; - BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, aToolkit, aInitData); + // Ensure that the toolkit is created. + nsToolkit::GetToolkit(); + + BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, aInitData); HWND parent; if (aParent) { // has a nsIWidget parent diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index ece564fb32f6..7de435fe90be 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -114,7 +114,6 @@ public: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, nsWidgetInitData *aInitData = nsnull); NS_IMETHOD Destroy(); NS_IMETHOD SetParent(nsIWidget *aNewParent); diff --git a/widget/src/xpwidgets/Makefile.in b/widget/src/xpwidgets/Makefile.in index 340f2c31c237..5612a0133d10 100644 --- a/widget/src/xpwidgets/Makefile.in +++ b/widget/src/xpwidgets/Makefile.in @@ -49,7 +49,6 @@ LIBXUL_LIBRARY = 1 DEFINES += \ -D_IMPL_NS_WIDGET \ - -DUSE_TLS_FOR_TOOLKIT \ -DNO_NSPR_10_SUPPORT=1 \ $(NULL) diff --git a/widget/src/xpwidgets/PuppetWidget.cpp b/widget/src/xpwidgets/PuppetWidget.cpp index b3106b9fd1e1..9b6aa7a1a1fc 100644 --- a/widget/src/xpwidgets/PuppetWidget.cpp +++ b/widget/src/xpwidgets/PuppetWidget.cpp @@ -112,13 +112,11 @@ PuppetWidget::Create(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { NS_ABORT_IF_FALSE(!aNativeParent, "got a non-Puppet native parent"); - BaseCreate(nsnull, aRect, aHandleEventFunction, aContext, - aToolkit, aInitData); + BaseCreate(nsnull, aRect, aHandleEventFunction, aContext, aInitData); mBounds = aRect; mEnabled = true; @@ -151,7 +149,6 @@ already_AddRefed PuppetWidget::CreateChild(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData, bool aForceUseIWidgetParent) { @@ -160,8 +157,7 @@ PuppetWidget::CreateChild(const nsIntRect &aRect, return ((widget && NS_SUCCEEDED(widget->Create(isPopup ? nsnull: this, nsnull, aRect, aHandleEventFunction, - aContext, aToolkit, - aInitData))) ? + aContext, aInitData))) ? widget.forget() : nsnull); } diff --git a/widget/src/xpwidgets/PuppetWidget.h b/widget/src/xpwidgets/PuppetWidget.h index 983984e34329..e1cca43285a7 100644 --- a/widget/src/xpwidgets/PuppetWidget.h +++ b/widget/src/xpwidgets/PuppetWidget.h @@ -74,15 +74,13 @@ public: nsNativeWidget aNativeParent, const nsIntRect& aRect, EVENT_CALLBACK aHandleEventFunction, - nsDeviceContext* aContext, - nsIToolkit* aToolkit = nsnull, + nsDeviceContext* aContext, nsWidgetInitData* aInitData = nsnull); virtual already_AddRefed CreateChild(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, - nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, + nsDeviceContext *aContext, nsWidgetInitData *aInitData = nsnull, bool aForceUseIWidgetParent = false); diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index bb108f32ba2f..a0639ea38879 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -104,7 +104,6 @@ nsBaseWidget::nsBaseWidget() , mEventCallback(nsnull) , mViewCallback(nsnull) , mContext(nsnull) -, mToolkit(nsnull) , mCursor(eCursor_standard) , mWindowType(eWindowType_child) , mBorderStyle(eBorderStyle_none) @@ -150,7 +149,6 @@ nsBaseWidget::~nsBaseWidget() printf("WIDGETS- = %d\n", gNumWidgets); #endif - NS_IF_RELEASE(mToolkit); NS_IF_RELEASE(mContext); delete mOriginalBounds; } @@ -165,42 +163,8 @@ void nsBaseWidget::BaseCreate(nsIWidget *aParent, const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { - if (nsnull == mToolkit) { - if (nsnull != aToolkit) { - mToolkit = (nsIToolkit*)aToolkit; - NS_ADDREF(mToolkit); - } - else { - if (nsnull != aParent) { - mToolkit = aParent->GetToolkit(); - NS_IF_ADDREF(mToolkit); - } - // it's some top level window with no toolkit passed in. - // Create a default toolkit with the current thread -#if !defined(USE_TLS_FOR_TOOLKIT) - else { - static NS_DEFINE_CID(kToolkitCID, NS_TOOLKIT_CID); - - nsresult res; - res = CallCreateInstance(kToolkitCID, &mToolkit); - NS_ASSERTION(NS_SUCCEEDED(res), "Can not create a toolkit in nsBaseWidget::Create"); - if (mToolkit) - mToolkit->Init(PR_GetCurrentThread()); - } -#else /* USE_TLS_FOR_TOOLKIT */ - else { - nsresult rv; - - rv = NS_GetCurrentToolkit(&mToolkit); - } -#endif /* USE_TLS_FOR_TOOLKIT */ - } - - } - // save the event callback function mEventCallback = aHandleEventFunction; @@ -253,7 +217,6 @@ already_AddRefed nsBaseWidget::CreateChild(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData, bool aForceUseIWidgetParent) { @@ -280,8 +243,7 @@ nsBaseWidget::CreateChild(const nsIntRect &aRect, if (widget && NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect, aHandleEventFunction, - aContext, aToolkit, - aInitData))) { + aContext, aInitData))) { return widget.forget(); } @@ -903,17 +865,6 @@ BasicLayerManager* nsBaseWidget::CreateBasicLayerManager() return new BasicShadowLayerManager(this); } -//------------------------------------------------------------------------- -// -// Return the toolkit this widget was created on -// -//------------------------------------------------------------------------- -nsIToolkit* nsBaseWidget::GetToolkit() -{ - return mToolkit; -} - - //------------------------------------------------------------------------- // // Return the used device context @@ -944,9 +895,8 @@ gfxASurface *nsBaseWidget::GetThebesSurface() //------------------------------------------------------------------------- void nsBaseWidget::OnDestroy() { - // release references to device context, toolkit, and app shell + // release references to device context and app shell NS_IF_RELEASE(mContext); - NS_IF_RELEASE(mToolkit); } NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType) diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index abee83dd1aad..8d685fec8859 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -40,7 +40,6 @@ #include "nsRect.h" #include "nsIWidget.h" #include "nsWidgetsCID.h" -#include "nsIToolkit.h" #include "nsILocalFile.h" #include "nsString.h" #include "nsCOMPtr.h" @@ -113,7 +112,6 @@ public: NS_IMETHOD HideWindowChrome(bool aShouldHide); NS_IMETHOD MakeFullScreen(bool aFullScreen); virtual nsDeviceContext* GetDeviceContext(); - virtual nsIToolkit* GetToolkit(); virtual LayerManager* GetLayerManager(PLayersChild* aShadowManager = nsnull, LayersBackend aBackendHint = LayerManager::LAYERS_NONE, LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, @@ -165,7 +163,6 @@ public: CreateChild(const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit = nsnull, nsWidgetInitData *aInitData = nsnull, bool aForceUseIWidgetParent = false); NS_IMETHOD AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction, nsDeviceContext *aContext); @@ -234,7 +231,6 @@ protected: const nsIntRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsDeviceContext *aContext, - nsIToolkit *aToolkit, nsWidgetInitData *aInitData); virtual nsIContent* GetLastRollup() @@ -274,7 +270,6 @@ protected: EVENT_CALLBACK mEventCallback; EVENT_CALLBACK mViewCallback; nsDeviceContext* mContext; - nsIToolkit* mToolkit; nsRefPtr mLayerManager; nsRefPtr mBasicLayerManager; nscolor mBackground; diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 3a0b548cb231..87b708b94822 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -42,6 +42,27 @@ #include "nsMemoryReporterManager.h" #include "nsArrayEnumerator.h" #include "nsISimpleEnumerator.h" +#include "mozilla/Telemetry.h" + +using namespace mozilla; + +#if defined(MOZ_MEMORY) +# if defined(XP_WIN) || defined(SOLARIS) || defined(ANDROID) || defined(XP_MACOSX) +# define HAVE_JEMALLOC_STATS 1 +# include "jemalloc.h" +# elif defined(XP_LINUX) +# define HAVE_JEMALLOC_STATS 1 +# include "jemalloc_types.h" +// jemalloc is directly linked into firefox-bin; libxul doesn't link +// with it. So if we tried to use jemalloc_stats directly here, it +// wouldn't be defined. Instead, we don't include the jemalloc header +// and weakly link against jemalloc_stats. +extern "C" { +extern void jemalloc_stats(jemalloc_stats_t* stats) + NS_VISIBILITY_DEFAULT __attribute__((weak)); +} +# endif // XP_LINUX +#endif // MOZ_MEMORY #if defined(XP_LINUX) || defined(XP_MACOSX) @@ -84,7 +105,7 @@ static PRInt64 GetProcSelfStatmField(int n) NS_ASSERTION(n < MAX_FIELD, "bad field number"); FILE *f = fopen("/proc/self/statm", "r"); if (f) { - int nread = fscanf(f, "%lu %lu", &fields[0], &fields[1]); + int nread = fscanf(f, "%zu %zu", &fields[0], &fields[1]); fclose(f); return (PRInt64) ((nread == MAX_FIELD) ? fields[n]*getpagesize() : -1); } @@ -125,6 +146,20 @@ static PRInt64 GetVsize() static PRInt64 GetResident() { +#ifdef HAVE_JEMALLOC_STATS + // If we're using jemalloc on Mac, we need to instruct jemalloc to purge + // the pages it has madvise(MADV_FREE)'d before we read our RSS. The OS + // will take away MADV_FREE'd pages when there's memory pressure, so they + // shouldn't count against our RSS. + // + // Purging these pages shouldn't take more than 10ms or so, but we want to + // keep an eye on it since GetResident() is called on each Telemetry ping. + { + Telemetry::AutoTimer timer; + jemalloc_purge_freed_pages(); + } +#endif + task_basic_info ti; return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.resident_size : -1); } @@ -255,24 +290,6 @@ NS_MEMORY_REPORTER_IMPLEMENT(Resident, ** at least -- on OSX, there are sometimes other zones in use). **/ -#if defined(MOZ_MEMORY) -# if defined(XP_WIN) || defined(SOLARIS) || defined(ANDROID) || defined(XP_MACOSX) -# define HAVE_JEMALLOC_STATS 1 -# include "jemalloc.h" -# elif defined(XP_LINUX) -# define HAVE_JEMALLOC_STATS 1 -# include "jemalloc_types.h" -// jemalloc is directly linked into firefox-bin; libxul doesn't link -// with it. So if we tried to use jemalloc_stats directly here, it -// wouldn't be defined. Instead, we don't include the jemalloc header -// and weakly link against jemalloc_stats. -extern "C" { -extern void jemalloc_stats(jemalloc_stats_t* stats) - NS_VISIBILITY_DEFAULT __attribute__((weak)); -} -# endif // XP_LINUX -#endif // MOZ_MEMORY - #if HAVE_JEMALLOC_STATS static PRInt64 GetHeapUnallocated() diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 60abd8944d90..290a25616245 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -144,6 +144,39 @@ struct nsTArray_SafeElementAtHelper } }; +// E is the base type that the smart pointer is templated over; the +// smart pointer can act as E*. +template +struct nsTArray_SafeElementAtSmartPtrHelper +{ + typedef E* elem_type; + typedef PRUint32 index_type; + + elem_type SafeElementAt(index_type i) { + return static_cast (this)->SafeElementAt(i, nsnull); + } + + const elem_type SafeElementAt(index_type i) const { + return static_cast (this)->SafeElementAt(i, nsnull); + } +}; + +template class nsCOMPtr; + +template +struct nsTArray_SafeElementAtHelper, Derived> : + public nsTArray_SafeElementAtSmartPtrHelper +{ +}; + +template class nsRefPtr; + +template +struct nsTArray_SafeElementAtHelper, Derived> : + public nsTArray_SafeElementAtSmartPtrHelper +{ +}; + // // This class serves as a base class for nsTArray. It shouldn't be used // directly. It holds common implementation code that does not depend on the diff --git a/xpcom/io/nsLocalFileOS2.cpp b/xpcom/io/nsLocalFileOS2.cpp index 8a108c5f6ee9..2a09bf1cb39b 100644 --- a/xpcom/io/nsLocalFileOS2.cpp +++ b/xpcom/io/nsLocalFileOS2.cpp @@ -1557,6 +1557,8 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, bool move) nsCOMPtr targetIterator; rv = target->GetDirectoryEntries(getter_AddRefs(targetIterator)); + if (NS_FAILED(rv)) + return rv; bool more; targetIterator->HasMoreElements(&more); diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 41ac0ab0aa04..8e368bdad8f7 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -1650,6 +1650,8 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow nsCOMPtr targetIterator; rv = target->GetDirectoryEntries(getter_AddRefs(targetIterator)); + if (NS_FAILED(rv)) + return rv; bool more; targetIterator->HasMoreElements(&more); @@ -2815,7 +2817,7 @@ nsLocalFile::RevealUsingShell() } const ITEMIDLIST* selection[] = { dir }; - UINT count = PR_ARRAY_SIZE(selection); + UINT count = ArrayLength(selection); //Perform the open of the directory. hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0); @@ -2844,7 +2846,7 @@ nsLocalFile::RevealUsingShell() } const ITEMIDLIST* selection[] = { item }; - UINT count = PR_ARRAY_SIZE(selection); + UINT count = ArrayLength(selection); //Perform the selection of the file. hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0); diff --git a/xpfe/appshell/src/nsWebShellWindow.cpp b/xpfe/appshell/src/nsWebShellWindow.cpp index 6bfaf6af34b8..cf96a89ac324 100644 --- a/xpfe/appshell/src/nsWebShellWindow.cpp +++ b/xpfe/appshell/src/nsWebShellWindow.cpp @@ -205,7 +205,6 @@ nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent, r, // Widget dimensions nsWebShellWindow::HandleEvent, // Event handler function nsnull, // Device context - nsnull, // nsIToolkit &widgetInitData); // Widget initialization data mWindow->GetClientBounds(r); // Match the default background color of content. Important on windows diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index 79a1269f0fa3..b8bed2e54980 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -38,6 +38,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/Util.h" + #include "jscntxt.h" #include "nscore.h" #include "plstr.h" @@ -52,6 +54,8 @@ #include "nsICryptoHash.h" #include "nsIX509Cert.h" +using namespace mozilla; + // // nsXPITriggerItem // @@ -246,7 +250,7 @@ XPITriggerEvent::Run() // Build arguments into rooted jsval array jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); + js::AutoArrayRooter tvr(cx, ArrayLength(args), args); // args[0] is the URL JSString *str = JS_NewUCStringCopyZ(cx, reinterpret_cast(URL.get()));