author | Kartikaya Gupta <kgupta@mozilla.com> |
Tue, 28 Feb 2012 14:37:26 -0500 | |
changeset 89292 | 5dc30efb809060dee6be95288da4402c05b2aac2 |
parent 89291 | 726cd11889e6af5b64ddb55db9e467d3d575a528 (current diff) |
parent 87990 | 30b4f99a137c72345bb0401fa1970598687d80c7 (diff) |
child 89293 | 9320f23871a1bafce28986b4dcfa3472af501b16 |
push id | 7119 |
push user | eakhgari@mozilla.com |
push date | Wed, 14 Mar 2012 17:40:57 +0000 |
treeherder | mozilla-inbound@10d7baa4aff0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 13.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -866,20 +866,21 @@ refChildCB(AtkObject *aAtkObj, gint aChi return nsnull; AtkObject* childAtkObj = nsAccessibleWrap::GetAtkObject(accChild); NS_ASSERTION(childAtkObj, "Fail to get AtkObj"); if (!childAtkObj) return nsnull; g_object_ref(childAtkObj); - - //this will addref parent + + if (aAtkObj != childAtkObj->accessible_parent) atk_object_set_parent(childAtkObj, aAtkObj); - return childAtkObj; + + return childAtkObj; } gint getIndexInParentCB(AtkObject *aAtkObj) { // We don't use nsIAccessible::GetIndexInParent() because // for ATK we don't want to include text leaf nodes as children nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
--- a/accessible/src/base/StyleInfo.cpp +++ b/accessible/src/base/StyleInfo.cpp @@ -105,8 +105,21 @@ void StyleInfo::Margin(css::Side aSide, nsAString& aValue) { aValue.Truncate(); nscoord coordVal = mElement->GetPrimaryFrame()->GetUsedMargin().Side(aSide); aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal)); aValue.AppendLiteral("px"); } + +void +StyleInfo::Format(const nscolor& aValue, nsString& aFormattedValue) +{ + // Combine the string like rgb(R, G, B) from nscolor. + aFormattedValue.AppendLiteral("rgb("); + aFormattedValue.AppendInt(NS_GET_R(aValue)); + aFormattedValue.AppendLiteral(", "); + aFormattedValue.AppendInt(NS_GET_G(aValue)); + aFormattedValue.AppendLiteral(", "); + aFormattedValue.AppendInt(NS_GET_B(aValue)); + aFormattedValue.Append(')'); +}
--- a/accessible/src/base/StyleInfo.h +++ b/accessible/src/base/StyleInfo.h @@ -55,16 +55,18 @@ public: void Display(nsAString& aValue); void TextAlign(nsAString& aValue); void TextIndent(nsAString& aValue); void MarginLeft(nsAString& aValue) { Margin(css::eSideLeft, aValue); } void MarginRight(nsAString& aValue) { Margin(css::eSideRight, aValue); } void MarginTop(nsAString& aValue) { Margin(css::eSideTop, aValue); } void MarginBottom(nsAString& aValue) { Margin(css::eSideBottom, aValue); } + static void Format(const nscolor& aValue, nsString& aFormattedValue); + private: StyleInfo() MOZ_DELETE; StyleInfo(const StyleInfo&) MOZ_DELETE; StyleInfo& operator = (const StyleInfo&) MOZ_DELETE; void Margin(css::Side aSide, nsAString& aValue); dom::Element* mElement;
--- a/accessible/src/base/nsAccDocManager.cpp +++ b/accessible/src/base/nsAccDocManager.cpp @@ -359,19 +359,19 @@ nsDocAccessible* nsAccDocManager::CreateDocOrRootAccessible(nsIDocument *aDocument) { // Ignore temporary, hiding, resource documents and documents without // docshell. if (aDocument->IsInitialDocument() || !aDocument->IsVisible() || aDocument->IsResourceDoc() || !aDocument->IsActive()) return nsnull; - // Ignore documents without presshell. - nsIPresShell *presShell = aDocument->GetShell(); - if (!presShell) + // Ignore documents without presshell and not having root frame. + nsIPresShell* presShell = aDocument->GetShell(); + if (!presShell || !presShell->GetRootFrame()) return nsnull; // Do not create document accessible until role content is loaded, otherwise // we get accessible document with wrong role. nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument); if (!rootElm) return nsnull;
--- a/accessible/src/base/nsTextAttrs.cpp +++ b/accessible/src/base/nsTextAttrs.cpp @@ -36,22 +36,26 @@ * * ***** END LICENSE BLOCK ***** */ #include "nsTextAttrs.h" #include "nsAccUtils.h" #include "nsCoreUtils.h" #include "nsHyperTextAccessibleWrap.h" +#include "StyleInfo.h" #include "gfxFont.h" #include "gfxUserFontSet.h" #include "nsFontMetrics.h" #include "nsLayoutUtils.h" +using namespace mozilla; +using namespace mozilla::a11y; + //////////////////////////////////////////////////////////////////////////////// // Constants and structures /** * Item of the gCSSTextAttrsMap map. */ struct nsCSSTextAttrMapItem { @@ -65,17 +69,16 @@ struct nsCSSTextAttrMapItem * The map of CSS properties to text attributes. */ const char* const kAnyValue = nsnull; const char* const kCopyValue = nsnull; static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = { // CSS name CSS value Attribute name Attribute value - { "color", kAnyValue, &nsGkAtoms::color, kCopyValue }, { "font-family", kAnyValue, &nsGkAtoms::font_family, kCopyValue }, { "font-style", kAnyValue, &nsGkAtoms::font_style, kCopyValue }, { "text-decoration", "line-through", &nsGkAtoms::textLineThroughStyle, "solid" }, { "text-decoration", "underline", &nsGkAtoms::textUnderlineStyle, "solid" }, { "vertical-align", kAnyValue, &nsGkAtoms::textPosition, kCopyValue } }; //////////////////////////////////////////////////////////////////////////////// @@ -149,44 +152,44 @@ nsTextAttrsMgr::GetAttributes(nsIPersist } nsTArray<nsITextAttr*> textAttrArray(10); // "language" text attribute nsLangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&langTextAttr)); - // "color" text attribute - nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm); - textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr)); - // "font-family" text attribute - nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm); + nsCSSTextAttr fontFamilyTextAttr(0, hyperTextElm, offsetElm); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontFamilyTextAttr)); // "font-style" text attribute - nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm); + nsCSSTextAttr fontStyleTextAttr(1, hyperTextElm, offsetElm); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontStyleTextAttr)); // "text-line-through-style" text attribute - nsCSSTextAttr lineThroughTextAttr(3, hyperTextElm, offsetElm); + nsCSSTextAttr lineThroughTextAttr(2, hyperTextElm, offsetElm); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&lineThroughTextAttr)); // "text-underline-style" text attribute - nsCSSTextAttr underlineTextAttr(4, hyperTextElm, offsetElm); + nsCSSTextAttr underlineTextAttr(3, hyperTextElm, offsetElm); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&underlineTextAttr)); // "text-position" text attribute - nsCSSTextAttr posTextAttr(5, hyperTextElm, offsetElm); + nsCSSTextAttr posTextAttr(4, hyperTextElm, offsetElm); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&posTextAttr)); // "background-color" text attribute nsBGColorTextAttr bgColorTextAttr(rootFrame, frame); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&bgColorTextAttr)); + // "color" text attribute + ColorTextAttr colorTextAttr(rootFrame, frame); + textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr)); + // "font-size" text attribute nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontSizeTextAttr)); // "font-weight" text attribute nsFontWeightTextAttr fontWeightTextAttr(rootFrame, frame); textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontWeightTextAttr)); @@ -358,17 +361,17 @@ nsCSSTextAttr::Format(const nsAutoString if (attrValue != kCopyValue) AppendASCIItoUTF16(attrValue, aFormattedValue); else aFormattedValue = aValue; } //////////////////////////////////////////////////////////////////////////////// -// nsBackgroundTextAttr +// nsBGColorTextAttr //////////////////////////////////////////////////////////////////////////////// nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) : nsTextAttr<nscolor>(aFrame == nsnull), mRootFrame(aRootFrame) { mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue); if (aFrame) mIsDefined = GetColor(aFrame, &mNativeValue); @@ -382,26 +385,18 @@ nsBGColorTextAttr::GetValueFor(nsIConten return false; return GetColor(frame, aValue); } void nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue) { - // Combine the string like rgb(R, G, B) from nscolor. nsAutoString value; - value.AppendLiteral("rgb("); - value.AppendInt(NS_GET_R(aValue)); - value.AppendLiteral(", "); - value.AppendInt(NS_GET_G(aValue)); - value.AppendLiteral(", "); - value.AppendInt(NS_GET_B(aValue)); - value.Append(')'); - + StyleInfo::Format(aValue, value); aFormattedValue = value; } bool nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor) { const nsStyleBackground *styleBackground = aFrame->GetStyleBackground(); @@ -422,16 +417,53 @@ nsBGColorTextAttr::GetColor(nsIFrame *aF if (parentFrame == mRootFrame) return false; return GetColor(parentFrame, aColor); } //////////////////////////////////////////////////////////////////////////////// +// ColorTextAttr +//////////////////////////////////////////////////////////////////////////////// + +ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) : + nsTextAttr<nscolor>(!aFrame) +{ + mRootNativeValue = aRootFrame->GetStyleColor()->mColor; + mIsRootDefined = true; + + if (aFrame) { + mNativeValue = aFrame->GetStyleColor()->mColor; + mIsDefined = true; + } +} + +bool +ColorTextAttr::GetValueFor(nsIContent* aContent, nscolor* aValue) +{ + nsIFrame* frame = aContent->GetPrimaryFrame(); + if (frame) { + *aValue = frame->GetStyleColor()->mColor; + return true; + } + + return false; +} + +void +ColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue) +{ + nsAutoString value; + StyleInfo::Format(aValue, value); + aFormattedValue = value; +} + + +//////////////////////////////////////////////////////////////////////////////// // nsFontSizeTextAttr //////////////////////////////////////////////////////////////////////////////// nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) : nsTextAttr<nscoord>(aFrame == nsnull) { mDC = aRootFrame->PresContext()->DeviceContext();
--- a/accessible/src/base/nsTextAttrs.h +++ b/accessible/src/base/nsTextAttrs.h @@ -303,16 +303,35 @@ protected: private: bool GetColor(nsIFrame *aFrame, nscolor *aColor); nsIFrame *mRootFrame; }; /** + * Class is used for the work with 'color' text attribute in nsTextAttrsMgr + * class. + */ +class ColorTextAttr : public nsTextAttr<nscolor> +{ +public: + ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame); + + // nsITextAttr + virtual nsIAtom* GetName() const { return nsGkAtoms::color; } + +protected: + // nsTextAttr + virtual bool GetValueFor(nsIContent* aContent, nscolor* aValue); + virtual void Format(const nscolor& aValue, nsAString& aFormattedValue); +}; + + +/** * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr * class. */ class nsFontSizeTextAttr : public nsTextAttr<nscoord> { public: nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
--- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -187,16 +187,17 @@ @BINPATH@/components/fastfind.xpt @BINPATH@/components/feeds.xpt #ifdef MOZ_GTK2 @BINPATH@/components/filepicker.xpt #endif @BINPATH@/components/find.xpt @BINPATH@/components/fuel.xpt @BINPATH@/components/gfx.xpt +@BINPATH@/components/html5.xpt @BINPATH@/components/htmlparser.xpt @BINPATH@/components/imglib2.xpt @BINPATH@/components/imgicon.xpt @BINPATH@/components/inspector.xpt @BINPATH@/components/intl.xpt @BINPATH@/components/jar.xpt @BINPATH@/components/jetpack.xpt @BINPATH@/components/jsdservice.xpt
--- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -1676,21 +1676,26 @@ SessionStoreService.prototype = { if (groupsData.totalNumber > 1) return [false, false]; } // Step 2 of processing: // If we're still here, then the window is usable. Look at the open tabs in // comparison to home pages. If all the tabs are home pages then we'll end // up overwriting all of them. Otherwise we'll just close the tabs that - // match home pages. - let homePages = aWindow.gHomeButton.getHomePage().split("|"); + // match home pages. Tabs with the about:blank URI will always be + // overwritten. + let homePages = ["about:blank"]; let removableTabs = []; let tabbrowser = aWindow.gBrowser; let normalTabsLen = tabbrowser.tabs.length - tabbrowser._numPinnedTabs; + let startupPref = this._prefBranch.getIntPref("startup.page"); + if (startupPref == 1) + homePages = homePages.concat(aWindow.gHomeButton.getHomePage().split("|")); + for (let i = tabbrowser._numPinnedTabs; i < tabbrowser.tabs.length; i++) { let tab = tabbrowser.tabs[i]; if (homePages.indexOf(tab.linkedBrowser.currentURI.spec) != -1) { removableTabs.push(tab); } } if (tabbrowser.tabs.length == removableTabs.length) {
--- a/browser/config/mozconfigs/linux32/debug +++ b/browser/config/mozconfigs/linux32/debug @@ -1,10 +1,11 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar . $topsrcdir/build/unix/mozconfig.linux # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux32/nightly +++ b/browser/config/mozconfigs/linux32/nightly @@ -1,11 +1,12 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics . $topsrcdir/build/unix/mozconfig.linux # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat
--- a/browser/config/mozconfigs/linux64/debug +++ b/browser/config/mozconfigs/linux64/debug @@ -1,10 +1,11 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar . $topsrcdir/build/unix/mozconfig.linux # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux64/nightly +++ b/browser/config/mozconfigs/linux64/nightly @@ -1,11 +1,12 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics . $topsrcdir/build/unix/mozconfig.linux # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat
--- a/browser/config/mozconfigs/macosx-lion-universal/nightly +++ b/browser/config/mozconfigs/macosx-lion-universal/nightly @@ -2,16 +2,17 @@ # Universal builds override the default of browser (bug 575283 comment 29) ac_add_options --enable-application=browser ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs ac_add_options --disable-install-strip +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx-universal/nightly +++ b/browser/config/mozconfigs/macosx-universal/nightly @@ -2,16 +2,17 @@ # Universal builds override the default of browser (bug 575283 comment 29) ac_add_options --enable-application=browser ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs ac_add_options --disable-install-strip +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx32-lion/debug +++ b/browser/config/mozconfigs/macosx32-lion/debug @@ -1,11 +1,12 @@ . $topsrcdir/build/macosx/mozconfig.leopard ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j12" # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx32/debug +++ b/browser/config/mozconfigs/macosx32/debug @@ -1,11 +1,12 @@ . $topsrcdir/build/macosx/mozconfig.leopard ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j4" # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx64-lion/debug +++ b/browser/config/mozconfigs/macosx64-lion/debug @@ -1,13 +1,14 @@ . $topsrcdir/build/macosx/common ac_add_options --enable-debug ac_add_options --enable-trace-malloc ac_add_options --enable-accessibility +ac_add_options --enable-signmar # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j12" # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx64/debug +++ b/browser/config/mozconfigs/macosx64/debug @@ -1,13 +1,14 @@ . $topsrcdir/build/macosx/common ac_add_options --enable-debug ac_add_options --enable-trace-malloc ac_add_options --enable-accessibility +ac_add_options --enable-signmar # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j4" # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/win32/debug +++ b/browser/config/mozconfigs/win32/debug @@ -1,9 +1,10 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 mk_add_options MOZ_MAKE_FLAGS=-j1 . $topsrcdir/browser/config/mozconfigs/win32/vs2010-mozconfig
--- a/browser/config/mozconfigs/win32/nightly +++ b/browser/config/mozconfigs/win32/nightly @@ -1,14 +1,15 @@ # for pgo mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py' ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-jemalloc +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/win64/debug +++ b/browser/config/mozconfigs/win64/debug @@ -1,10 +1,11 @@ ac_add_options --target=x86_64-pc-mingw32 ac_add_options --host=x86_64-pc-mingw32 ac_add_options --enable-debug ac_add_options --enable-trace-malloc +ac_add_options --enable-signmar # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 mk_add_options MOZ_MAKE_FLAGS=-j1
--- a/browser/config/mozconfigs/win64/nightly +++ b/browser/config/mozconfigs/win64/nightly @@ -2,16 +2,17 @@ ac_add_options --target=x86_64-pc-mingw3 ac_add_options --host=x86_64-pc-mingw32 # for pgo mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py' ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-jemalloc +ac_add_options --enable-signmar # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -70,16 +70,18 @@ const DEVTOOLS_CHROME_ENABLED = "devtool const BUTTON_POSITION_SAVE = 0; const BUTTON_POSITION_CANCEL = 1; const BUTTON_POSITION_DONT_SAVE = 2; /** * The scratchpad object handles the Scratchpad window functionality. */ var Scratchpad = { + _initialWindowTitle: document.title, + /** * The script execution context. This tells Scratchpad in which context the * script shall execute. * * Possible values: * - SCRATCHPAD_CONTEXT_CONTENT to execute code in the context of the current * tab content window object. * - SCRATCHPAD_CONTEXT_BROWSER to execute code in the context of the @@ -146,50 +148,67 @@ var Scratchpad = { /** * Set the filename in the scratchpad UI and object * * @param string aFilename * The new filename */ setFilename: function SP_setFilename(aFilename) { - document.title = this.filename = aFilename; + this.filename = aFilename; + this._updateTitle(); + }, + + /** + * Update the Scratchpad window title based on the current state. + * @private + */ + _updateTitle: function SP__updateTitle() + { + if (this.filename) { + document.title = (this.editor && this.editor.dirty ? "*" : "") + + this.filename; + } else { + document.title = this._initialWindowTitle; + } }, /** * Get the current state of the scratchpad. Called by the * Scratchpad Manager for session storing. * * @return object * An object with 3 properties: filename, text, and * executionContext. */ getState: function SP_getState() { return { filename: this.filename, text: this.getText(), executionContext: this.executionContext, - saved: this.saved + saved: !this.editor.dirty, }; }, /** * Set the filename and execution context using the given state. Called * when scratchpad is being restored from a previous session. * * @param object aState * An object with filename and executionContext properties. */ setState: function SP_getState(aState) { if (aState.filename) { this.setFilename(aState.filename); } - this.saved = aState.saved; + if (this.editor) { + this.editor.dirty = !aState.saved; + } if (aState.executionContext == SCRATCHPAD_CONTEXT_BROWSER) { this.setBrowserContext(); } else { this.setContentContext(); } }, @@ -633,17 +652,17 @@ var Scratchpad = { openFile: function SP_openFile() { let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); fp.init(window, this.strings.GetStringFromName("openFile.title"), Ci.nsIFilePicker.modeOpen); fp.defaultString = ""; if (fp.show() != Ci.nsIFilePicker.returnCancel) { this.setFilename(fp.file.path); - this.importFromFile(fp.file, false, this.onTextSaved.bind(this)); + this.importFromFile(fp.file, false); } }, /** * Save the textbox content to the currently open file. * * @param function aCallback * Optional function you want to call when file is saved @@ -653,17 +672,19 @@ var Scratchpad = { if (!this.filename) { return this.saveFileAs(aCallback); } let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); file.initWithPath(this.filename); this.exportToFile(file, true, false, function(aStatus) { - this.onTextSaved(); + if (Components.isSuccessCode(aStatus)) { + this.editor.dirty = false; + } if (aCallback) { aCallback(aStatus); } }); }, /** * Save the textbox content to a new file. @@ -676,17 +697,19 @@ var Scratchpad = { let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); fp.init(window, this.strings.GetStringFromName("saveFileAs"), Ci.nsIFilePicker.modeSave); fp.defaultString = "scratchpad.js"; if (fp.show() != Ci.nsIFilePicker.returnCancel) { this.setFilename(fp.file.path); this.exportToFile(fp.file, true, false, function(aStatus) { - this.onTextSaved(); + if (Components.isSuccessCode(aStatus)) { + this.editor.dirty = false; + } if (aCallback) { aCallback(aStatus); } }); } }, /** @@ -778,67 +801,69 @@ var Scratchpad = { * * @param nsIDOMEvent aEvent */ onLoad: function SP_onLoad(aEvent) { if (aEvent.target != document) { return; } - let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED); if (chrome) { let environmentMenu = document.getElementById("sp-environment-menu"); let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole"); let chromeContextCommand = document.getElementById("sp-cmd-browserContext"); environmentMenu.removeAttribute("hidden"); chromeContextCommand.removeAttribute("disabled"); errorConsoleCommand.removeAttribute("disabled"); } + let state = null; let initialText = this.strings.GetStringFromName("scratchpadIntro"); if ("arguments" in window && window.arguments[0] instanceof Ci.nsIDialogParamBlock) { - let state = JSON.parse(window.arguments[0].GetString(0)); + state = JSON.parse(window.arguments[0].GetString(0)); this.setState(state); initialText = state.text; } this.editor = new SourceEditor(); let config = { mode: SourceEditor.MODES.JAVASCRIPT, showLineNumbers: true, initialText: initialText, + contextMenu: "scratchpad-text-popup", }; let editorPlaceholder = document.getElementById("scratchpad-editor"); - this.editor.init(editorPlaceholder, config, this.onEditorLoad.bind(this)); + this.editor.init(editorPlaceholder, config, + this._onEditorLoad.bind(this, state)); }, /** * The load event handler for the source editor. This method does post-load * editor initialization. + * + * @private + * @param object aState + * The initial Scratchpad state object. */ - onEditorLoad: function SP_onEditorLoad() + _onEditorLoad: function SP__onEditorLoad(aState) { - this.editor.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU, - this.onContextMenu); + this.editor.addEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, + this._onDirtyChanged); this.editor.focus(); this.editor.setCaretOffset(this.editor.getCharCount()); + if (aState) { + this.editor.dirty = !aState.saved; + } this.initialized = true; - if (this.filename && !this.saved) { - this.onTextChanged(); - } - else if (this.filename && this.saved) { - this.onTextSaved(); - } - this._triggerObservers("Ready"); }, /** * Insert text at the current caret location. * * @param string aText * The text you want to insert. @@ -846,46 +871,27 @@ var Scratchpad = { insertTextAtCaret: function SP_insertTextAtCaret(aText) { let caretOffset = this.editor.getCaretOffset(); this.setText(aText, caretOffset, caretOffset); this.editor.setCaretOffset(caretOffset + aText.length); }, /** - * The contextmenu event handler for the source editor. This method opens the - * Scratchpad context menu popup at the pointer location. + * The Source Editor DirtyChanged event handler. This function updates the + * Scratchpad window title to show an asterisk when there are unsaved changes. * + * @private + * @see SourceEditor.EVENTS.DIRTY_CHANGED * @param object aEvent - * An event object coming from the SourceEditor. This object needs to - * hold the screenX and screenY properties. + * The DirtyChanged event object. */ - onContextMenu: function SP_onContextMenu(aEvent) + _onDirtyChanged: function SP__onDirtyChanged(aEvent) { - let menu = document.getElementById("scratchpad-text-popup"); - if (menu.state == "closed") { - menu.openPopupAtScreen(aEvent.screenX, aEvent.screenY, true); - } - }, - - /** - * The popupshowing event handler for the Edit menu. This method updates the - * enabled/disabled state of the Undo and Redo commands, based on the editor - * state such that the menu items render correctly for the user when the menu - * shows. - */ - onEditPopupShowing: function SP_onEditPopupShowing() - { - goUpdateGlobalEditMenuItems(); - - let undo = document.getElementById("sp-cmd-undo"); - undo.setAttribute("disabled", !this.editor.canUndo()); - - let redo = document.getElementById("sp-cmd-redo"); - redo.setAttribute("disabled", !this.editor.canRedo()); + Scratchpad._updateTitle(); }, /** * Undo the last action of the user. */ undo: function SP_undo() { this.editor.undo(); @@ -895,123 +901,133 @@ var Scratchpad = { * Redo the previously undone action. */ redo: function SP_redo() { this.editor.redo(); }, /** - * This method adds a listener to the editor for text changes. Called when - * a scratchpad is saved, opened from file, or restored from a saved file. - */ - onTextSaved: function SP_onTextSaved(aStatus) - { - if (aStatus && !Components.isSuccessCode(aStatus)) { - return; - } - if (!document || !this.initialized) { - return; // file saved to disk after window has closed - } - document.title = document.title.replace(/^\*/, ""); - this.saved = true; - this.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, - this.onTextChanged); - }, - - /** - * The scratchpad handler for editor text change events. This handler - * indicates that there are unsaved changes in the UI. - */ - onTextChanged: function SP_onTextChanged() - { - document.title = "*" + document.title; - Scratchpad.saved = false; - Scratchpad.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, - Scratchpad.onTextChanged); - }, - - /** * The Scratchpad window unload event handler. This method unloads/destroys * the source editor. * * @param nsIDOMEvent aEvent */ onUnload: function SP_onUnload(aEvent) { if (aEvent.target != document) { return; } this.resetContext(); - this.editor.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU, - this.onContextMenu); + this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, + this._onDirtyChanged); this.editor.destroy(); this.editor = null; this.initialized = false; }, /** * Prompt to save scratchpad if it has unsaved changes. * * @param function aCallback - * Optional function you want to call when file is saved + * Optional function you want to call when file is saved. The callback + * receives three arguments: + * - toClose (boolean) - tells if the window should be closed. + * - saved (boolen) - tells if the file has been saved. + * - status (number) - the file save status result (if the file was + * saved). * @return boolean * Whether the window should be closed */ promptSave: function SP_promptSave(aCallback) { - if (this.filename && !this.saved) { + if (this.filename && this.editor.dirty) { let ps = Services.prompt; let flags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_SAVE + ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL + ps.BUTTON_POS_2 * ps.BUTTON_TITLE_DONT_SAVE; let button = ps.confirmEx(window, this.strings.GetStringFromName("confirmClose.title"), this.strings.GetStringFromName("confirmClose"), flags, null, null, null, null, {}); if (button == BUTTON_POSITION_CANCEL) { + if (aCallback) { + aCallback(false, false); + } return false; } + if (button == BUTTON_POSITION_SAVE) { - this.saveFile(aCallback); + this.saveFile(function(aStatus) { + if (aCallback) { + aCallback(true, true, aStatus); + } + }); + return true; } } + + if (aCallback) { + aCallback(true, false); + } return true; }, /** * Handler for window close event. Prompts to save scratchpad if * there are unsaved changes. * * @param nsIDOMEvent aEvent */ onClose: function SP_onClose(aEvent) { - let toClose = this.promptSave(); - if (!toClose) { - aEvent.preventDefault(); + if (this._skipClosePrompt) { + return; } + + this.promptSave(function(aShouldClose, aSaved, aStatus) { + let shouldClose = aShouldClose; + if (aSaved && !Components.isSuccessCode(aStatus)) { + shouldClose = false; + } + + if (shouldClose) { + this._skipClosePrompt = true; + window.close(); + } + }.bind(this)); + aEvent.preventDefault(); }, /** * Close the scratchpad window. Prompts before closing if the scratchpad * has unsaved changes. * * @param function aCallback * Optional function you want to call when file is saved */ close: function SP_close(aCallback) { - let toClose = this.promptSave(aCallback); - if (toClose) { - window.close(); - } + this.promptSave(function(aShouldClose, aSaved, aStatus) { + let shouldClose = aShouldClose; + if (aSaved && !Components.isSuccessCode(aStatus)) { + shouldClose = false; + } + + if (shouldClose) { + this._skipClosePrompt = true; + window.close(); + } + if (aCallback) { + aCallback(); + } + }.bind(this)); }, _observers: [], /** * Add an observer for Scratchpad events. * * The observer implements IScratchpadObserver := {
--- a/browser/devtools/scratchpad/scratchpad.xul +++ b/browser/devtools/scratchpad/scratchpad.xul @@ -76,21 +76,21 @@ <command id="sp-cmd-run" oncommand="Scratchpad.run();"/> <command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/> <command id="sp-cmd-display" oncommand="Scratchpad.display();"/> <command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/> <command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/> <command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/> <command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/> <command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/> - <command id="sp-cmd-undo" oncommand="Scratchpad.undo();" disabled="true"/> - <command id="sp-cmd-redo" oncommand="Scratchpad.redo();" disabled="true"/> <command id="sp-cmd-documentationLink" oncommand="Scratchpad.openDocumentationPage();"/> </commandset> +<keyset id="sourceEditorKeys"/> + <keyset id="sp-keyset"> <key id="sp-key-window" key="&newWindowCmd.commandkey;" command="sp-cmd-newWindow" modifiers="accel"/> <key id="sp-key-open" key="&openFileCmd.commandkey;" command="sp-cmd-openFile" @@ -118,19 +118,19 @@ <key id="key_copy" key="©Cmd.key;" modifiers="accel"/> <key id="key_paste" key="&pasteCmd.key;" modifiers="accel"/> <key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/> <key id="key_undo" key="&undoCmd.key;" modifiers="accel" - oncommand="Scratchpad.undo();"/> + command="se-cmd-undo"/> <key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift" - oncommand="Scratchpad.redo();"/> + command="se-cmd-redo"/> <key id="sp-key-run" key="&run.key;" command="sp-cmd-run" modifiers="accel"/> <key id="sp-key-inspect" key="&inspect.key;" command="sp-cmd-inspect" modifiers="accel"/> @@ -163,20 +163,16 @@ <key id="key_findAgain" keycode="VK_F3" command="cmd_findAgain"/> <key id="key_findPrevious" keycode="VK_F3" command="cmd_findPrevious" modifiers="shift"/> #endif - <key id="key_gotoLine" - key="&gotoLineCmd.key;" - command="cmd_gotoLine" - modifiers="accel"/> <key id="key_openHelp" keycode="VK_F1" command="sp-cmd-documentationLink"/> </keyset> <menubar id="sp-menubar"> <menu id="sp-file-menu" label="&fileMenu.label;" @@ -218,27 +214,27 @@ accesskey="&closeCmd.accesskey;" command="sp-cmd-close"/> </menupopup> </menu> <menu id="sp-edit-menu" label="&editMenu.label;" accesskey="&editMenu.accesskey;"> <menupopup id="sp-menu_editpopup" - onpopupshowing="Scratchpad.onEditPopupShowing()"> + onpopupshowing="goUpdateGlobalEditMenuItems()"> <menuitem id="sp-menu-undo" label="&undoCmd.label;" key="key_undo" accesskey="&undoCmd.accesskey;" - command="sp-cmd-undo"/> + command="se-cmd-undo"/> <menuitem id="sp-menu-redo" label="&redoCmd.label;" key="key_redo" accesskey="&redoCmd.accesskey;" - command="sp-cmd-redo"/> + command="se-cmd-redo"/> <menuseparator/> <menuitem id="sp-menu-cut" label="&cutCmd.label;" key="key_cut" accesskey="&cutCmd.accesskey;" command="cmd_cut"/> <menuitem id="sp-menu-copy" label="©Cmd.label;"
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_653427_confirm_close.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_653427_confirm_close.js @@ -41,94 +41,92 @@ function test() testSavedFile(); content.location = "data:text/html,<p>test scratchpad save file prompt on closing"; } function testNew() { openScratchpad(function(win) { - win.Scratchpad.close(); - ok(win.closed, "new scratchpad window should close without prompting") - done(); + win.Scratchpad.close(function() { + ok(win.closed, "new scratchpad window should close without prompting") + done(); + }); }, {noFocus: true}); } function testSavedFile() { openScratchpad(function(win) { win.Scratchpad.filename = "test.js"; - win.Scratchpad.saved = true; - win.Scratchpad.close(); - - ok(win.closed, "scratchpad from file with no changes should close") - done(); + win.Scratchpad.editor.dirty = false; + win.Scratchpad.close(function() { + ok(win.closed, "scratchpad from file with no changes should close") + done(); + }); }, {noFocus: true}); } function testUnsaved() { testUnsavedFileCancel(); testUnsavedFileSave(); testUnsavedFileDontSave(); } function testUnsavedFileCancel() { openScratchpad(function(win) { - win.Scratchpad.filename = "test.js"; - win.Scratchpad.saved = false; + win.Scratchpad.setFilename("test.js"); + win.Scratchpad.editor.dirty = true; promptButton = win.BUTTON_POSITION_CANCEL; - win.Scratchpad.close(); - - ok(!win.closed, "cancelling dialog shouldn't close scratchpad"); - - win.close(); - done(); + win.Scratchpad.close(function() { + ok(!win.closed, "cancelling dialog shouldn't close scratchpad"); + win.close(); + done(); + }); }, {noFocus: true}); } function testUnsavedFileSave() { openScratchpad(function(win) { win.Scratchpad.importFromFile(gFile, true, function(status, content) { - win.Scratchpad.filename = gFile.path; - win.Scratchpad.onTextSaved(); + win.Scratchpad.setFilename(gFile.path); let text = "new text"; win.Scratchpad.setText(text); promptButton = win.BUTTON_POSITION_SAVE; win.Scratchpad.close(function() { + ok(win.closed, 'pressing "Save" in dialog should close scratchpad'); readFile(gFile, function(savedContent) { is(savedContent, text, 'prompted "Save" worked when closing scratchpad'); done(); }); }); - - ok(win.closed, 'pressing "Save" in dialog should close scratchpad'); }); }, {noFocus: true}); } function testUnsavedFileDontSave() { openScratchpad(function(win) { - win.Scratchpad.filename = gFile.path; - win.Scratchpad.saved = false; + win.Scratchpad.setFilename(gFile.path); + win.Scratchpad.editor.dirty = true; promptButton = win.BUTTON_POSITION_DONT_SAVE; - win.Scratchpad.close(); - - ok(win.closed, 'pressing "Don\'t Save" in dialog should close scratchpad'); - done(); + win.Scratchpad.close(function() { + ok(win.closed, 'pressing "Don\'t Save" in dialog should close scratchpad'); + done(); + }); }, {noFocus: true}); } function cleanup() { Services.prompt = oldPrompt; gFile.remove(false); gFile = null;
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_669612_unsaved.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_669612_unsaved.js @@ -1,74 +1,67 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // only finish() when correct number of tests are done -const expected = 5; +const expected = 4; var count = 0; function done() { if (++count == expected) { finish(); } } var ScratchpadManager = Scratchpad.ScratchpadManager; function test() { waitForExplicitFinish(); testListeners(); - testErrorStatus(); testRestoreNotFromFile(); testRestoreFromFileSaved(); testRestoreFromFileUnsaved(); content.location = "data:text/html,<p>test star* UI for unsaved file changes"; } function testListeners() { openScratchpad(function(aWin, aScratchpad) { aScratchpad.setText("new text"); ok(!isStar(aWin), "no star if scratchpad isn't from a file"); - aScratchpad.onTextSaved(); + aScratchpad.editor.dirty = false; ok(!isStar(aWin), "no star before changing text"); + aScratchpad.setFilename("foo.js"); aScratchpad.setText("new text2"); ok(isStar(aWin), "shows star if scratchpad text changes"); - aScratchpad.onTextSaved(); + aScratchpad.editor.dirty = false; ok(!isStar(aWin), "no star if scratchpad was just saved"); + aScratchpad.setText("new text3"); + ok(isStar(aWin), "shows star if scratchpad has more changes"); + aScratchpad.undo(); - ok(isStar(aWin), "star if scratchpad undo"); + ok(!isStar(aWin), "no star if scratchpad undo to save point"); + + aScratchpad.undo(); + ok(isStar(aWin), "star if scratchpad undo past save point"); aWin.close(); done(); }, {noFocus: true}); } -function testErrorStatus() -{ - openScratchpad(function(aWin, aScratchpad) { - aScratchpad.onTextSaved(Components.results.NS_ERROR_FAILURE); - aScratchpad.setText("new text"); - ok(!isStar(aWin), "no star if file save failed"); - - aWin.close(); - done(); - }, {noFocus: true}); -} - - function testRestoreNotFromFile() { let session = [{ text: "test1", executionContext: 1 }]; let [win] = ScratchpadManager.restoreSession(session);
--- a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js @@ -27,18 +27,16 @@ function runTests() "sp-menu-save": "saveFile", "sp-menu-saveas": "saveFileAs", "sp-text-run": "run", "sp-text-inspect": "inspect", "sp-text-display": "display", "sp-text-resetContext": "resetContext", "sp-menu-content": "setContentContext", "sp-menu-browser": "setBrowserContext", - "sp-menu-undo": "undo", - "sp-menu-redo": "redo", }; let lastMethodCalled = null; sp.__noSuchMethod__ = function(aMethodName) { lastMethodCalled = aMethodName; }; for (let id in methodsAndItems) {
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm +++ b/browser/devtools/sourceeditor/source-editor-orion.jsm @@ -141,16 +141,18 @@ function SourceEditor() { // Update the SourceEditor defaults from user preferences. SourceEditor.DEFAULTS.tabSize = Services.prefs.getIntPref(SourceEditor.PREFS.TAB_SIZE); SourceEditor.DEFAULTS.expandTab = Services.prefs.getBoolPref(SourceEditor.PREFS.EXPAND_TAB); this._onOrionSelection = this._onOrionSelection.bind(this); + this._onTextChanged = this._onTextChanged.bind(this); + this._onOrionContextMenu = this._onOrionContextMenu.bind(this); this._eventTarget = {}; this._eventListenersQueue = []; this.ui = new SourceEditorUI(this); } SourceEditor.prototype = { _view: null, @@ -167,16 +169,18 @@ SourceEditor.prototype = { _currentLineAnnotation: null, _primarySelectionTimeout: null, _mode: null, _expandTab: null, _tabSize: null, _iframeWindow: null, _eventTarget: null, _eventListenersQueue: null, + _contextMenu: null, + _dirty: false, /** * The Source Editor user interface manager. * @type object * An instance of the SourceEditorUI. */ ui: null, @@ -274,17 +278,31 @@ SourceEditor.prototype = { let onOrionLoad = function() { this._view.removeEventListener("Load", onOrionLoad); this._onOrionLoad(); }.bind(this); this._view.addEventListener("Load", onOrionLoad); if (config.highlightCurrentLine || Services.appinfo.OS == "Linux") { - this._view.addEventListener("Selection", this._onOrionSelection); + this.addEventListener(SourceEditor.EVENTS.SELECTION, + this._onOrionSelection); + } + this.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, + this._onTextChanged); + + if (typeof config.contextMenu == "string") { + let chromeDocument = this.parentElement.ownerDocument; + this._contextMenu = chromeDocument.getElementById(config.contextMenu); + } else if (typeof config.contextMenu == "object" ) { + this._contextMenu = config._contextMenu; + } + if (this._contextMenu) { + this.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU, + this._onOrionContextMenu); } let KeyBinding = window.require("orion/textview/keyBinding").KeyBinding; let TextDND = window.require("orion/textview/textDND").TextDND; let Rulers = window.require("orion/textview/rulers"); let LineNumberRuler = Rulers.LineNumberRuler; let AnnotationRuler = Rulers.AnnotationRuler; let OverviewRuler = Rulers.OverviewRuler; @@ -583,16 +601,54 @@ SourceEditor.prototype = { } this._primarySelectionTimeout = window.setTimeout(this._updatePrimarySelection.bind(this), PRIMARY_SELECTION_DELAY); } }, /** + * The TextChanged event handler which tracks the dirty state of the editor. + * + * @see SourceEditor.EVENTS.TEXT_CHANGED + * @see SourceEditor.EVENTS.DIRTY_CHANGED + * @see SourceEditor.dirty + * @private + */ + _onTextChanged: function SE__onTextChanged() + { + this._updateDirty(); + }, + + /** + * The Orion contextmenu event handler. This method opens the default or + * the custom context menu popup at the pointer location. + * + * @param object aEvent + * The contextmenu event object coming from Orion. This object should + * hold the screenX and screenY properties. + */ + _onOrionContextMenu: function SE__onOrionContextMenu(aEvent) + { + if (this._contextMenu.state == "closed") { + this._contextMenu.openPopupAtScreen(aEvent.screenX || 0, + aEvent.screenY || 0, true); + } + }, + + /** + * Update the dirty state of the editor based on the undo stack. + * @private + */ + _updateDirty: function SE__updateDirty() + { + this.dirty = !this._undoStack.isClean(); + }, + + /** * Update the X11 PRIMARY buffer to hold the current selection. * @private */ _updatePrimarySelection: function SE__updatePrimarySelection() { this._primarySelectionTimeout = null; let text = this.getSelectedText(); @@ -861,28 +917,38 @@ SourceEditor.prototype = { this._eventTarget.removeEventListener(aEventType, aCallback); } else { this._eventListenersQueue.push(["remove", aEventType, aCallback]); } }, /** * Undo a change in the editor. + * + * @return boolean + * True if there was a change undone, false otherwise. */ undo: function SE_undo() { - return this._undoStack.undo(); + let result = this._undoStack.undo(); + this.ui._onUndoRedo(); + return result; }, /** * Redo a change in the editor. + * + * @return boolean + * True if there was a change redone, false otherwise. */ redo: function SE_redo() { - return this._undoStack.redo(); + let result = this._undoStack.redo(); + this.ui._onUndoRedo(); + return result; }, /** * Check if there are changes that can be undone. * * @return boolean * True if there are changes that can be undone, false otherwise. */ @@ -898,21 +964,64 @@ SourceEditor.prototype = { * True if there are changes that can be repeated, false otherwise. */ canRedo: function SE_canRedo() { return this._undoStack.canRedo(); }, /** - * Reset the Undo stack + * Reset the Undo stack. */ resetUndo: function SE_resetUndo() { this._undoStack.reset(); + this._updateDirty(); + this.ui._onUndoRedo(); + }, + + /** + * Set the "dirty" state of the editor. Set this to false when you save the + * text being edited. The dirty state will become true once the user makes + * changes to the text. + * + * @param boolean aNewValue + * The new dirty state: true if the text is not saved, false if you + * just saved the text. + */ + set dirty(aNewValue) + { + if (aNewValue == this._dirty) { + return; + } + + let event = { + type: SourceEditor.EVENTS.DIRTY_CHANGED, + oldValue: this._dirty, + newValue: aNewValue, + }; + + this._dirty = aNewValue; + if (!this._dirty && !this._undoStack.isClean()) { + this._undoStack.markClean(); + } + this._dispatchEvent(event); + }, + + /** + * Get the editor "dirty" state. This tells if the text is considered saved or + * not. + * + * @see SourceEditor.EVENTS.DIRTY_CHANGED + * @return boolean + * True if there are changes which are not saved, false otherwise. + */ + get dirty() + { + return this._dirty; }, /** * Start a compound change in the editor. Compound changes are grouped into * only one change that you can undo later, after you invoke * endCompoundChange(). */ startCompoundChange: function SE_startCompoundChange() @@ -1321,20 +1430,32 @@ SourceEditor.prototype = { }, /** * Destroy/uninitialize the editor. */ destroy: function SE_destroy() { if (this._config.highlightCurrentLine || Services.appinfo.OS == "Linux") { - this._view.removeEventListener("Selection", this._onOrionSelection); + this.removeEventListener(SourceEditor.EVENTS.SELECTION, + this._onOrionSelection); } this._onOrionSelection = null; + this.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, + this._onTextChanged); + this._onTextChanged = null; + + if (this._contextMenu) { + this.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU, + this._onOrionContextMenu); + this._contextMenu = null; + } + this._onOrionContextMenu = null; + if (this._primarySelectionTimeout) { let window = this.parentElement.ownerDocument.defaultView; window.clearTimeout(this._primarySelectionTimeout); this._primarySelectionTimeout = null; } this._view.destroy(); this.ui.destroy();
--- a/browser/devtools/sourceeditor/source-editor-overlay.xul +++ b/browser/devtools/sourceeditor/source-editor-overlay.xul @@ -30,18 +30,85 @@ - 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 ***** --> - +<!DOCTYPE overlay SYSTEM "chrome://browser/locale/devtools/sourceeditor.dtd"> <overlay id="sourceEditorOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + <!-- This Source Editor overlay requires the editMenuOverlay.xul to be loaded. + The globalOverlay.js script is also required in the XUL document where + the source-editor-overlay.xul is loaded. --> + <commandset id="sourceEditorCommands"> <command id="cmd_find" oncommand="goDoCommand('cmd_find')"/> <command id="cmd_findAgain" oncommand="goDoCommand('cmd_findAgain')" disabled="true"/> <command id="cmd_findPrevious" oncommand="goDoCommand('cmd_findPrevious')" disabled="true"/> <command id="cmd_gotoLine" oncommand="goDoCommand('cmd_gotoLine')"/> + <command id="se-cmd-undo" oncommand="goDoCommand('se-cmd-undo')" disabled="true"/> + <command id="se-cmd-redo" oncommand="goDoCommand('se-cmd-redo')" disabled="true"/> </commandset> + + <keyset id="sourceEditorKeys"> + <key id="key_gotoLine" + key="&gotoLineCmd.key;" + command="cmd_gotoLine" + modifiers="accel"/> + </keyset> + + <menupopup id="sourceEditorContextMenu" + onpopupshowing="goUpdateGlobalEditMenuItems()"> + <menuitem id="se-menu-undo" + label="&undoCmd.label;" + key="key_undo" + accesskey="&undoCmd.accesskey;" + command="se-cmd-undo"/> + <menuseparator/> + <menuitem id="se-menu-cut" + label="&cutCmd.label;" + key="key_cut" + accesskey="&cutCmd.accesskey;" + command="cmd_cut"/> + <menuitem id="se-menu-copy" + label="©Cmd.label;" + key="key_copy" + accesskey="©Cmd.accesskey;" + command="cmd_copy"/> + <menuitem id="se-menu-paste" + label="&pasteCmd.label;" + key="key_paste" + accesskey="&pasteCmd.accesskey;" + command="cmd_paste"/> + <menuitem id="se-menu-delete" + label="&deleteCmd.label;" + key="key_delete" + accesskey="&deleteCmd.accesskey;" + command="cmd_delete"/> + <menuseparator/> + <menuitem id="se-menu-selectAll" + label="&selectAllCmd.label;" + key="key_selectAll" + accesskey="&selectAllCmd.accesskey;" + command="cmd_selectAll"/> + <menuseparator/> + <menuitem id="se-menu-find" + label="&findCmd.label;" + accesskey="&findCmd.accesskey;" + key="key_find" + command="cmd_find"/> + <menuitem id="se-menu-findAgain" + label="&findAgainCmd.label;" + accesskey="&findAgainCmd.accesskey;" + key="key_findAgain" + command="cmd_findAgain"/> + <menuseparator/> + <menuitem id="se-menu-gotoLine" + label="&gotoLineCmd.label;" + accesskey="&gotoLineCmd.accesskey;" + key="key_gotoLine" + command="cmd_gotoLine"/> + </menupopup> </overlay>
--- a/browser/devtools/sourceeditor/source-editor-ui.jsm +++ b/browser/devtools/sourceeditor/source-editor-ui.jsm @@ -45,16 +45,17 @@ Cu.import("resource://gre/modules/Servic var EXPORTED_SYMBOLS = ["SourceEditorUI"]; /** * The Source Editor component user interface. */ function SourceEditorUI(aEditor) { this.editor = aEditor; + this._onDirtyChanged = this._onDirtyChanged.bind(this); } SourceEditorUI.prototype = { /** * Initialize the user interface. This is called by the SourceEditor.init() * method. */ init: function SEU_init() @@ -67,16 +68,18 @@ SourceEditorUI.prototype = { * initialization and it is ready for usage. Currently this code sets up the * nsIController. */ onReady: function SEU_onReady() { if (this._ownerWindow.controllers) { this._controller = new SourceEditorController(this.editor); this._ownerWindow.controllers.insertControllerAt(0, this._controller); + this.editor.addEventListener(this.editor.EVENTS.DIRTY_CHANGED, + this._onDirtyChanged); } }, /** * The "go to line" command UI. This displays a prompt that allows the user to * input the line number to jump to. */ gotoLine: function SEU_gotoLine() @@ -173,21 +176,49 @@ SourceEditorUI.prototype = { if (this._ownerWindow.goUpdateCommand) { this._ownerWindow.goUpdateCommand("cmd_findAgain"); this._ownerWindow.goUpdateCommand("cmd_findPrevious"); } }, /** + * This is executed after each undo/redo operation. + * @private + */ + _onUndoRedo: function SEU__onUndoRedo() + { + if (this._ownerWindow.goUpdateCommand) { + this._ownerWindow.goUpdateCommand("se-cmd-undo"); + this._ownerWindow.goUpdateCommand("se-cmd-redo"); + } + }, + + /** + * The DirtyChanged event handler for the editor. This tracks the editor state + * changes to make sure the Source Editor overlay Undo/Redo commands are kept + * up to date. + * @private + */ + _onDirtyChanged: function SEU__onDirtyChanged() + { + this._onUndoRedo(); + }, + + /** * Destroy the SourceEditorUI instance. This is called by the * SourceEditor.destroy() method. */ destroy: function SEU_destroy() { + if (this._ownerWindow.controllers) { + this.editor.removeEventListener(this.editor.EVENTS.DIRTY_CHANGED, + this._onDirtyChanged); + } + this._ownerWindow = null; this.editor = null; this._controller = null; }, }; /** * The Source Editor nsIController implements features that need to be available @@ -215,16 +246,18 @@ SourceEditorController.prototype = { { let result; switch (aCommand) { case "cmd_find": case "cmd_findAgain": case "cmd_findPrevious": case "cmd_gotoLine": + case "se-cmd-undo": + case "se-cmd-redo": result = true; break; default: result = false; break; } return result; @@ -246,16 +279,22 @@ SourceEditorController.prototype = { case "cmd_find": case "cmd_gotoLine": result = true; break; case "cmd_findAgain": case "cmd_findPrevious": result = this._editor.lastFind && this._editor.lastFind.lastFound != -1; break; + case "se-cmd-undo": + result = this._editor.canUndo(); + break; + case "se-cmd-redo": + result = this._editor.canRedo(); + break; default: result = false; break; } return result; }, @@ -276,13 +315,19 @@ SourceEditorController.prototype = { this._editor.ui.findNext(); break; case "cmd_findPrevious": this._editor.ui.findPrevious(); break; case "cmd_gotoLine": this._editor.ui.gotoLine(); break; + case "se-cmd-undo": + this._editor.undo(); + break; + case "se-cmd-redo": + this._editor.redo(); + break; } }, onEvent: function() { } };
--- a/browser/devtools/sourceeditor/source-editor.jsm +++ b/browser/devtools/sourceeditor/source-editor.jsm @@ -194,16 +194,32 @@ SourceEditor.DEFAULTS = { * - accel - boolean for the Accel key (Cmd on Macs, Ctrl on Linux/Windows). * - shift - boolean for the Shift key. * - alt - boolean for the Alt key. * - callback - optional function to invoke, if the action is not predefined * in the editor. * @type array */ keys: null, + + /** + * The editor context menu you want to display when the user right-clicks + * within the editor. This property can be: + * - a string that tells the ID of the xul:menupopup you want. This needs to + * be available within the editor parentElement.ownerDocument. + * - an nsIDOMElement object reference pointing to the xul:menupopup you + * want to open when the contextmenu event is fired. + * + * Set this property to a falsey value to disable the default context menu. + * + * @see SourceEditor.EVENTS.CONTEXT_MENU for more control over the contextmenu + * event. + * @type string|nsIDOMElement + */ + contextMenu: "sourceEditorContextMenu", }; /** * Known editor events you can listen for. */ SourceEditor.EVENTS = { /** * The contextmenu event is fired when the editor context menu is invoked. The @@ -211,16 +227,18 @@ SourceEditor.EVENTS = { * - x - the pointer location on the x axis, relative to the document the * user is editing. * - y - the pointer location on the y axis, relative to the document the * user is editing. * - screenX - the pointer location on the x axis, relative to the screen. * This value comes from the DOM contextmenu event.screenX property. * - screenY - the pointer location on the y axis, relative to the screen. * This value comes from the DOM contextmenu event.screenY property. + * + * @see SourceEditor.DEFAULTS.contextMenu */ CONTEXT_MENU: "ContextMenu", /** * The TextChanged event is fired when the editor content changes. The event * object properties: * - start - the character offset in the document where the change has * occured. @@ -277,16 +295,25 @@ SourceEditor.EVENTS = { * a breakpoint is removed - either through API use or through the editor UI. * Event object properties: * - added - array that holds the new breakpoints. * - removed - array that holds the breakpoints that have been removed. * Each object in the added/removed arrays holds two properties: line and * condition. */ BREAKPOINT_CHANGE: "BreakpointChange", + + /** + * The DirtyChanged event is fired when the dirty state of the editor is + * changed. The dirty state of the editor tells if the are text changes that + * have not been saved yet. Event object properties: oldValue and newValue. + * Both are booleans telling the old dirty state and the new state, + * respectively. + */ + DIRTY_CHANGED: "DirtyChanged", }; /** * Extend a destination object with properties from a source object. * * @param object aDestination * @param object aSource */ @@ -298,16 +325,22 @@ function extend(aDestination, aSource) } } } /** * Add methods common to all components. */ extend(SourceEditor.prototype, { + // Expose the static constants on the SourceEditor instances. + EVENTS: SourceEditor.EVENTS, + MODES: SourceEditor.MODES, + THEMES: SourceEditor.THEMES, + DEFAULTS: SourceEditor.DEFAULTS, + _lastFind: null, /** * Find a string in the editor. * * @param string aString * The string you want to search for. If |aString| is not given the * currently selected text is used.
--- a/browser/devtools/sourceeditor/test/Makefile.in +++ b/browser/devtools/sourceeditor/test/Makefile.in @@ -53,12 +53,13 @@ include $(topsrcdir)/config/rules.mk browser_bug684546_reset_undo.js \ browser_bug695035_middle_click_paste.js \ browser_bug687160_line_api.js \ browser_bug650345_find.js \ browser_bug703692_focus_blur.js \ browser_bug725388_mouse_events.js \ browser_bug707987_debugger_breakpoints.js \ browser_bug712982_line_ruler_click.js \ + browser_bug700893_dirty_state.js \ head.js \ libs:: $(_BROWSER_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/browser/devtools/sourceeditor/test/browser_bug700893_dirty_state.js @@ -0,0 +1,94 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function test() { + + let temp = {}; + Cu.import("resource:///modules/source-editor.jsm", temp); + let SourceEditor = temp.SourceEditor; + + let component = Services.prefs.getCharPref(SourceEditor.PREFS.COMPONENT); + if (component == "textarea") { + ok(true, "skip test for bug 700893: only applicable for non-textarea components"); + return; + } + + waitForExplicitFinish(); + + let editor; + + const windowUrl = "data:text/xml,<?xml version='1.0'?>" + + "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" + + " title='test for bug 700893' width='600' height='500'><hbox flex='1'/></window>"; + const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; + + let testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null); + testWin.addEventListener("load", function onWindowLoad() { + testWin.removeEventListener("load", onWindowLoad, false); + waitForFocus(initEditor, testWin); + }, false); + + function initEditor() + { + let hbox = testWin.document.querySelector("hbox"); + editor = new SourceEditor(); + editor.init(hbox, {initialText: "foobar"}, editorLoaded); + } + + function editorLoaded() + { + editor.focus(); + + is(editor.dirty, false, "editory is not dirty"); + + let event = null; + let eventHandler = function(aEvent) { + event = aEvent; + }; + editor.addEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, eventHandler); + + editor.setText("omg"); + + is(editor.dirty, true, "editor is dirty"); + ok(event, "DirtyChanged event fired") + is(event.oldValue, false, "event.oldValue is correct"); + is(event.newValue, true, "event.newValue is correct"); + + event = null; + editor.setText("foo 2"); + ok(!event, "no DirtyChanged event fired"); + + editor.dirty = false; + + is(editor.dirty, false, "editor marked as clean"); + ok(event, "DirtyChanged event fired") + is(event.oldValue, true, "event.oldValue is correct"); + is(event.newValue, false, "event.newValue is correct"); + + event = null; + editor.setText("foo 3"); + + is(editor.dirty, true, "editor is dirty after changes"); + ok(event, "DirtyChanged event fired") + is(event.oldValue, false, "event.oldValue is correct"); + is(event.newValue, true, "event.newValue is correct"); + + editor.undo(); + is(editor.dirty, false, "editor is not dirty after undo"); + ok(event, "DirtyChanged event fired") + is(event.oldValue, true, "event.oldValue is correct"); + is(event.newValue, false, "event.newValue is correct"); + + editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, eventHandler); + + editor.destroy(); + + testWin.close(); + testWin = editor = null; + + waitForFocus(finish, window); + } +}
--- a/browser/devtools/styleeditor/styleeditor.xul +++ b/browser/devtools/styleeditor/styleeditor.xul @@ -40,29 +40,39 @@ %styleEditorDTD; ]> <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/splitview.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/styleeditor.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/devtools/styleeditor.css" type="text/css"?> +<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?> +<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?> <xul:window xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns="http://www.w3.org/1999/xhtml" id="style-editor-chrome-window" title="&window.title;" windowtype="Tools:StyleEditor" width="800" height="280" persist="screenX screenY width height sizemode"> <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/> +<xul:popupset id="style-editor-popups"> + <xul:menupopup id="sourceEditorContextMenu"/> +</xul:popupset> + +<xul:commandset id="editMenuCommands"/> +<xul:commandset id="sourceEditorCommands"/> <xul:commandset id="style-editor-commandset"> <xul:command id="style-editor-cmd-close" oncommand="window.close();"/> </xul:commandset> +<xul:keyset id="editMenuKeys"/> +<xul:keyset id="sourceEditorKeys"/> <xul:keyset id="style-editor-keyset"> <xul:key id="style-editor-key-close" key="&closeCmd.key;" command="style-editor-cmd-close" modifiers="accel"/> </xul:keyset> <xul:box id="style-editor-chrome" class="splitview-root loading">
--- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -185,16 +185,17 @@ @BINPATH@/components/fastfind.xpt @BINPATH@/components/feeds.xpt #ifdef MOZ_GTK2 @BINPATH@/components/filepicker.xpt #endif @BINPATH@/components/find.xpt @BINPATH@/components/fuel.xpt @BINPATH@/components/gfx.xpt +@BINPATH@/components/html5.xpt @BINPATH@/components/htmlparser.xpt @BINPATH@/components/imglib2.xpt @BINPATH@/components/imgicon.xpt @BINPATH@/components/inspector.xpt @BINPATH@/components/intl.xpt @BINPATH@/components/jar.xpt @BINPATH@/components/jsdservice.xpt @BINPATH@/components/jsdebugger.xpt
--- a/browser/installer/removed-files.in +++ b/browser/installer/removed-files.in @@ -1186,16 +1186,17 @@ xpicleanup@BIN_SUFFIX@ components/exthelper.xpt components/fastfind.xpt components/feeds.xpt components/find.xpt components/firefox.xpt components/fuel.xpt components/gfx.xpt components/gksvgrenderer.xpt + components/html5.xpt components/htmlparser.xpt components/imgicon.xpt components/imglib2.xpt components/inspector.xpt components/intl.xpt components/jar.xpt components/jsconsole.xpt components/jsdservice.xpt
new file mode 100644 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/devtools/sourceeditor.dtd @@ -0,0 +1,32 @@ +<!-- LOCALIZATION NOTE : FILE This file contains the Source Editor component + - strings. The source editor component is used within the Scratchpad and + - Style Editor tools. --> + +<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys --> + +<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to + - keep it in English, or another language commonly spoken among web developers. + - You want to make that choice consistent across the developer tools. + - A good criteria is the language in which you'd find the best + - documentation on web development on the web. --> + +<!ENTITY undoCmd.label "Undo"> +<!ENTITY undoCmd.accesskey "U"> +<!ENTITY cutCmd.label "Cut"> +<!ENTITY cutCmd.accesskey "t"> +<!ENTITY copyCmd.label "Copy"> +<!ENTITY copyCmd.accesskey "C"> +<!ENTITY pasteCmd.label "Paste"> +<!ENTITY pasteCmd.accesskey "P"> +<!ENTITY deleteCmd.label "Delete"> +<!ENTITY deleteCmd.accesskey "D"> +<!ENTITY selectAllCmd.label "Select All"> +<!ENTITY selectAllCmd.accesskey "A"> +<!ENTITY findCmd.label "Find…"> +<!ENTITY findCmd.accesskey "F"> +<!ENTITY findAgainCmd.label "Find Again…"> +<!ENTITY findAgainCmd.accesskey "g"> +<!ENTITY gotoLineCmd.label "Jump to line…"> +<!ENTITY gotoLineCmd.key "J"> +<!ENTITY gotoLineCmd.accesskey "J"> +
--- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -25,16 +25,17 @@ locale/browser/devtools/scratchpad.properties (%chrome/browser/devtools/scratchpad.properties) locale/browser/devtools/scratchpad.dtd (%chrome/browser/devtools/scratchpad.dtd) locale/browser/devtools/styleeditor.properties (%chrome/browser/devtools/styleeditor.properties) locale/browser/devtools/styleeditor.dtd (%chrome/browser/devtools/styleeditor.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/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties) + locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd) locale/browser/newTab.dtd (%chrome/browser/newTab.dtd) locale/browser/newTab.properties (%chrome/browser/newTab.properties) locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd) locale/browser/openLocation.properties (%chrome/browser/openLocation.properties) * locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd) locale/browser/pageInfo.properties (%chrome/browser/pageInfo.properties) locale/browser/quitDialog.properties (%chrome/browser/quitDialog.properties) * locale/browser/safeMode.dtd (%chrome/browser/safeMode.dtd)
--- a/browser/themes/gnomestripe/preferences/preferences.css +++ b/browser/themes/gnomestripe/preferences/preferences.css @@ -176,13 +176,9 @@ radio[pane=paneSync] { list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); } #syncAddDeviceLabel { margin-top: 1em; margin-bottom: 1em; } -#syncEnginesList { - height: 10em; -} - %endif
--- a/browser/themes/pinstripe/preferences/preferences.css +++ b/browser/themes/pinstripe/preferences/preferences.css @@ -234,13 +234,9 @@ caption { list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); } #syncAddDeviceLabel { margin-top: 1em; margin-bottom: 1em; } -#syncEnginesList { - height: 10em; -} - %endif
--- a/browser/themes/winstripe/preferences/preferences.css +++ b/browser/themes/winstripe/preferences/preferences.css @@ -164,15 +164,11 @@ radio[pane=paneSync] { #accountCaptionImage { list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); } #syncAddDeviceLabel { margin-top: 1em; margin-bottom: 1em; - } - -#syncEnginesList { - height: 11em; } %endif
--- a/build/unix/build-toolchain/build-gcc.py +++ b/build/unix/build-toolchain/build-gcc.py @@ -94,16 +94,43 @@ def build_linux_headers_aux(inst_dir): "headers_install"]) shutil.move(linux_source_dir + "/dest", inst_dir) def build_linux_headers(inst_dir): def f(): build_linux_headers_aux(inst_dir) with_env({"PATH" : aux_inst_dir + "/bin:%s" % os.environ["PATH"]}, f) +def build_gcc(stage_dir, is_stage_one): + gcc_build_dir = stage_dir + '/gcc' + tool_inst_dir = stage_dir + '/inst' + lib_inst_dir = stage_dir + '/libinst' + gcc_configure_args = ["--prefix=%s" % tool_inst_dir, + "--enable-__cxa_atexit", + "--with-gmp=%s" % lib_inst_dir, + "--with-mpfr=%s" % lib_inst_dir, + "--with-mpc=%s" % lib_inst_dir, + "--enable-languages=c,c++", + "--disable-multilib", + "--disable-bootstrap"] + if is_stage_one: + # We build the stage1 gcc without shared libraries. Otherwise its + # libgcc.so would depend on the system libc.so, which causes problems + # when it tries to use that libgcc.so and the libc we are about to + # build. + gcc_configure_args.append("--disable-shared") + + build_package(gcc_source_dir, gcc_build_dir, gcc_configure_args) + + if is_stage_one: + # The glibc build system uses -lgcc_eh, but at least in this setup + # libgcc.a has all it needs. + d = tool_inst_dir + "/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/" + os.symlink(d + "libgcc.a", d + "libgcc_eh.a") + def build_one_stage(env, stage_dir, is_stage_one): def f(): build_one_stage_aux(stage_dir, is_stage_one) with_env(env, f) def build_one_stage_aux(stage_dir, is_stage_one): os.mkdir(stage_dir) @@ -124,43 +151,28 @@ def build_one_stage_aux(stage_dir, is_st tool_inst_dir = stage_dir + '/inst' build_linux_headers(tool_inst_dir) binutils_build_dir = stage_dir + '/binutils' build_package(binutils_source_dir, binutils_build_dir, ["--prefix=%s" % tool_inst_dir]) - gcc_build_dir = stage_dir + '/gcc' - gcc_configure_args = ["--prefix=%s" % tool_inst_dir, - "--enable-__cxa_atexit", - "--with-gmp=%s" % lib_inst_dir, - "--with-mpfr=%s" % lib_inst_dir, - "--with-mpc=%s" % lib_inst_dir, - "--enable-languages=c,c++", - "--disable-multilib", - "--disable-bootstrap"] + # During stage one we have to build gcc first, this glibc doesn't even + # build with gcc 4.6. During stage two, we have to build glibc first. + # The problem is that libstdc++ is built with xgcc and if glibc has + # not been built yet xgcc will use the system one. if is_stage_one: - # We build the stage1 gcc without shared libraries. Otherwise its - # libgcc.so would depend on the system libc.so, which causes problems - # when it tries to use that libgcc.so and the libc we are about to - # build. - gcc_configure_args.append("--disable-shared") - - build_package(gcc_source_dir, gcc_build_dir, gcc_configure_args) - - if is_stage_one: - # The glibc build system uses -lgcc_eh, but at least in this setup - # libgcc.a has all it needs. - d = tool_inst_dir + "/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/" - os.symlink(d + "libgcc.a", d + "libgcc_eh.a") - - build_glibc({"CC" : tool_inst_dir + "/bin/gcc", - "CXX" : tool_inst_dir + "/bin/g++"}, - stage_dir, tool_inst_dir) + build_gcc(stage_dir, is_stage_one) + build_glibc({"CC" : tool_inst_dir + "/bin/gcc", + "CXX" : tool_inst_dir + "/bin/g++"}, + stage_dir, tool_inst_dir) + else: + build_glibc({}, stage_dir, tool_inst_dir) + build_gcc(stage_dir, is_stage_one) def build_tar_package(tar, name, base, directory): name = os.path.realpath(name) run_in(base, [tar, "-cf", name, "--mtime=2012-01-01", "--owner=root", directory]) ##############################################
--- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -138,16 +138,17 @@ ENABLE_TESTS = @ENABLE_TESTS@ IBMBIDI = @IBMBIDI@ MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@ ACCESSIBILITY = @ACCESSIBILITY@ MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@ XPCOM_USE_LEA = @XPCOM_USE_LEA@ MOZ_INSTALLER = @MOZ_INSTALLER@ MOZ_MAINTENANCE_SERVICE = @MOZ_MAINTENANCE_SERVICE@ MOZ_VERIFY_MAR_SIGNATURE = @MOZ_VERIFY_MAR_SIGNATURE@ +MOZ_ENABLE_SIGNMAR = @MOZ_ENABLE_SIGNMAR@ MOZ_UPDATER = @MOZ_UPDATER@ MOZ_UPDATE_CHANNEL = @MOZ_UPDATE_CHANNEL@ MOZ_UPDATE_PACKAGING = @MOZ_UPDATE_PACKAGING@ MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@ NS_ENABLE_TSF = @NS_ENABLE_TSF@ MOZ_SPELLCHECK = @MOZ_SPELLCHECK@ MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@ MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
--- a/configure.in +++ b/configure.in @@ -313,17 +313,17 @@ if test -n "$gonkdir" ; then LD="$gonk_toolchain"/bin/"$android_tool_prefix"-ld AR="$gonk_toolchain"/bin/"$android_tool_prefix"-ar RANLIB="$gonk_toolchain"/bin/"$android_tool_prefix"-ranlib STRIP="$gonk_toolchain"/bin/"$android_tool_prefix"-strip STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/" STLPORT_LIBS="-lstlport" - CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -isystem $gonkdir/frameworks/base/opengl/include -isystem $gonkdir/frameworks/base/native/include -isystem $gonkdir/hardware/libhardware/include -isystem $gonkdir/hardware/libhardware_legacy/include -isystem $gonkdir/system/core/include -isystem $gonkdir/bionic -isystem $gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS -isystem $gonkdir/frameworks/base/services/sensorservice" + CPPFLAGS="-DANDROID -I$gonkdir/bionic/libc/include/ -I$gonkdir/bionic/libc/kernel/common -I$gonkdir/bionic/libc/arch-arm/include -I$gonkdir/bionic/libc/kernel/arch-arm -I$gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -I$gonkdir/bionic -I$gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice" CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS" CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS" LIBS="$LIBS $STLPORT_LIBS" dnl Add -llog by default, since we use it all over the place. LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS" dnl prevent cross compile section from using these flags as host flags @@ -6495,16 +6495,33 @@ if test -n "$MOZ_VERIFY_MAR_SIGNATURE"; if test "$OS_ARCH" = "WINNT"; then AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE) else AC_MSG_ERROR([Can only build with --enable-verify-mar with a Windows target]) fi fi dnl ======================================================== +dnl Enable building the signmar program. +dnl This option is much different than the --enable-verify-mar option. +dnl --enable-verify-mar is for enabling the verification check on MAR +dnl files in the updater. The --enable-signmar option is for building +dnl the signmar program. +dnl ======================================================== + +MOZ_ARG_ENABLE_BOOL(sign-mar, +[ --enable-signmar Enable building the signmar program], + MOZ_ENABLE_SIGNMAR=1, + MOZ_ENABLE_SIGNMAR= ) + +if test -n "$MOZ_ENABLE_SIGNMAR"; then + AC_DEFINE(MOZ_ENABLE_SIGNMAR) +fi + +dnl ======================================================== dnl Updater dnl ======================================================== MOZ_ARG_DISABLE_BOOL(updater, [ --disable-updater Disable building of updater], MOZ_UPDATER=, MOZ_UPDATER=1 ) @@ -8596,16 +8613,17 @@ AC_SUBST(MOZ_UNIVERSALCHARDET) AC_SUBST(ACCESSIBILITY) AC_SUBST(MOZ_SPELLCHECK) AC_SUBST(MOZ_JAVA_COMPOSITOR) AC_SUBST(MOZ_ONLY_TOUCH_EVENTS) AC_SUBST(MOZ_USER_DIR) AC_SUBST(MOZ_CRASHREPORTER) AC_SUBST(MOZ_MAINTENANCE_SERVICE) AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE) +AC_SUBST(MOZ_ENABLE_SIGNMAR) AC_SUBST(MOZ_UPDATER) AC_SUBST(MOZ_ANGLE) AC_SUBST(MOZ_DIRECTX_SDK_PATH) AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX) AC_SUBST(MOZ_D3DX9_VERSION) AC_SUBST(MOZ_D3DX9_CAB) AC_SUBST(MOZ_D3DCOMPILER_CAB) AC_SUBST(MOZ_D3DX9_DLL)
--- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1139,22 +1139,44 @@ public: /** * Parse a string into a document using the HTML parser. * Script elements are marked unexecutable. * * @param aSourceBuffer the string to parse as an HTML document * @param aTargetDocument the document object to parse into. Must not have * child nodes. + * @param aScriptingEnabledForNoscriptParsing whether <noscript> is parsed + * as if scripting was enabled * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse * fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too * long and NS_OK otherwise. */ static nsresult ParseDocumentHTML(const nsAString& aSourceBuffer, - nsIDocument* aTargetDocument); + nsIDocument* aTargetDocument, + bool aScriptingEnabledForNoscriptParsing); + + /** + * Converts HTML source to plain text by parsing the source and using the + * plain text serializer on the resulting tree. + * + * @param aSourceBuffer the string to parse as an HTML document + * @param aResultBuffer the string where the plain text result appears; + * may be the same string as aSourceBuffer + * @param aFlags Flags from nsIDocumentEncoder. + * @param aWrapCol Number of columns after which to line wrap; 0 for no + * auto-wrapping + * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse + * fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too + * long and NS_OK otherwise. + */ + static nsresult ConvertToPlainText(const nsAString& aSourceBuffer, + nsAString& aResultBuffer, + PRUint32 aFlags, + PRUint32 aWrapCol); /** * Creates a new XML document, which is marked to be loaded as data. * * @param aNamespaceURI Namespace for the root element to create and insert in * the document. Only used if aQualifiedName is not * empty. * @param aQualifiedName Qualified name for the root element to create and @@ -1936,16 +1958,42 @@ public: * comma-separated list of URIs. Return true if the given URI's prepath is * in the list, and false otherwise. * * Comparisons are case-insensitive, and whitespace between elements of the * comma-separated list is ignored. */ static bool URIIsChromeOrInPref(nsIURI *aURI, const char *aPref); + /** + * This will parse aSource, to extract the value of the pseudo attribute + * with the name specified in aName. See + * http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification + * which is used to parse aSource. + * + * @param aSource the string to parse + * @param aName the name of the attribute to get the value for + * @param aValue [out] the value for the attribute with name specified in + * aAttribute. Empty if the attribute isn't present. + * @return true if the attribute exists and was successfully parsed. + * false if the attribute doesn't exist, or has a malformed + * value, such as an unknown or unterminated entity. + */ + static bool GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName, + nsAString& aValue); + + /** + * Returns true if the language name is a version of JavaScript and + * false otherwise + */ + static bool IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags); + + static void SplitMimeType(const nsAString& aValue, nsString& aType, + nsString& aParams); + private: static bool InitializeEventTable(); static nsresult EnsureStringBundle(PropertiesFile aFile); static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory(); static nsresult HoldScriptObject(PRUint32 aLangID, void* aObject);
--- a/content/base/public/nsIDocumentEncoder.idl +++ b/content/base/public/nsIDocumentEncoder.idl @@ -167,17 +167,18 @@ interface nsIDocumentEncoder : nsISuppor /** * Output the content of noscript elements (only for serializing * to plaintext). */ const unsigned long OutputNoScriptContent = (1 << 11); /** * Output the content of noframes elements (only for serializing - * to plaintext). + * to plaintext). (Used only internally in the plain text serializer; + * ignored if passed by the caller.) */ const unsigned long OutputNoFramesContent = (1 << 12); /** * Don't allow any formatting nodes (e.g. <br>, <b>) inside a <pre>. * This is used primarily by mail. XHTML/HTML output only. */ const unsigned long OutputNoFormattingInPre = (1 << 13);
--- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -122,17 +122,16 @@ CPPSRCS = \ nsMappedAttributes.cpp \ nsNameSpaceManager.cpp \ nsNoDataProtocolContentPolicy.cpp \ nsNodeInfo.cpp \ nsNodeInfoManager.cpp \ nsNodeIterator.cpp \ nsNodeUtils.cpp \ nsObjectLoadingContent.cpp \ - nsParserUtils.cpp \ nsPlainTextSerializer.cpp \ nsPropertyTable.cpp \ nsRange.cpp \ nsReferencedElement.cpp \ nsScriptElement.cpp \ nsScriptLoader.cpp \ nsStubDocumentObserver.cpp \ nsStubImageDecoderObserver.cpp \
--- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -75,17 +75,16 @@ #include "nsIApplicationCacheContainer.h" #include "nsIApplicationCacheChannel.h" #include "nsIScriptSecurityManager.h" #include "nsIDOMLoadStatus.h" #include "nsICookieService.h" #include "nsIPrompt.h" #include "nsServiceManagerUtils.h" #include "nsContentUtils.h" -#include "nsParserUtils.h" #include "nsCRT.h" #include "nsEscape.h" #include "nsWeakReference.h" #include "nsUnicharUtils.h" #include "nsNodeInfoManager.h" #include "nsIAppShell.h" #include "nsIWidget.h" #include "nsWidgetsCID.h" @@ -707,17 +706,17 @@ nsContentSink::ProcessStyleLink(nsIConte { if (aAlternate && aTitle.IsEmpty()) { // alternates must have title return without error, for now return NS_OK; } nsAutoString mimeType; nsAutoString params; - nsParserUtils::SplitMimeType(aType, mimeType, params); + nsContentUtils::SplitMimeType(aType, mimeType, params); // see bug 18817 if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) { // Unknown stylesheet language return NS_OK; } nsCOMPtr<nsIURI> url;
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -175,16 +175,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_ #include "BasicLayers.h" #include "nsFocusManager.h" #include "nsTextEditorState.h" #include "nsIPluginHost.h" #include "nsICategoryManager.h" #include "nsIViewManager.h" #include "nsEventStateManager.h" #include "nsIDOMHTMLInputElement.h" +#include "nsParserConstants.h" #ifdef IBMBIDI #include "nsIBidiKeyboard.h" #endif #include "nsCycleCollectionParticipant.h" // for ReportToConsole #include "nsIStringBundle.h" @@ -715,16 +716,195 @@ nsContentUtils::URIIsChromeOrInPref(nsIU if (whitelistItem.Equals(prePath, nsCaseInsensitiveStringComparator())) { return true; } } return false; } +#define SKIP_WHITESPACE(iter, end_iter, end_res) \ + while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ + ++(iter); \ + } \ + if ((iter) == (end_iter)) { \ + return (end_res); \ + } + +#define SKIP_ATTR_NAME(iter, end_iter) \ + while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ + *(iter) != '=') { \ + ++(iter); \ + } + +bool +nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName, + nsAString& aValue) +{ + aValue.Truncate(); + + const PRUnichar *start = aSource.get(); + const PRUnichar *end = start + aSource.Length(); + const PRUnichar *iter; + + while (start != end) { + SKIP_WHITESPACE(start, end, false) + iter = start; + SKIP_ATTR_NAME(iter, end) + + if (start == iter) { + return false; + } + + // Remember the attr name. + const nsDependentSubstring & attrName = Substring(start, iter); + + // Now check whether this is a valid name="value" pair. + start = iter; + SKIP_WHITESPACE(start, end, false) + if (*start != '=') { + // No '=', so this is not a name="value" pair. We don't know + // what it is, and we have no way to handle it. + return false; + } + + // Have to skip the value. + ++start; + SKIP_WHITESPACE(start, end, false) + PRUnichar q = *start; + if (q != kQuote && q != kApostrophe) { + // Not a valid quoted value, so bail. + return false; + } + + ++start; // Point to the first char of the value. + iter = start; + + while (iter != end && *iter != q) { + ++iter; + } + + if (iter == end) { + // Oops, unterminated quoted string. + return false; + } + + // At this point attrName holds the name of the "attribute" and + // the value is between start and iter. + + if (aName->Equals(attrName)) { + nsIParserService* parserService = nsContentUtils::GetParserService(); + NS_ENSURE_TRUE(parserService, false); + + // We'll accumulate as many characters as possible (until we hit either + // the end of the string or the beginning of an entity). Chunks will be + // delimited by start and chunkEnd. + const PRUnichar *chunkEnd = start; + while (chunkEnd != iter) { + if (*chunkEnd == kLessThan) { + aValue.Truncate(); + + return false; + } + + if (*chunkEnd == kAmpersand) { + aValue.Append(start, chunkEnd - start); + + // Point to first character after the ampersand. + ++chunkEnd; + + const PRUnichar *afterEntity; + PRUnichar result[2]; + PRUint32 count = + parserService->DecodeEntity(chunkEnd, iter, &afterEntity, result); + if (count == 0) { + aValue.Truncate(); + + return false; + } + + aValue.Append(result, count); + + // Advance to after the entity and begin a new chunk. + start = chunkEnd = afterEntity; + } + else { + ++chunkEnd; + } + } + + // Append remainder. + aValue.Append(start, iter - start); + + return true; + } + + // Resume scanning after the end of the attribute value (past the quote + // char). + start = iter + 1; + } + + return false; +} + +bool +nsContentUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags) +{ + JSVersion version = JSVERSION_UNKNOWN; + + if (aName.LowerCaseEqualsLiteral("javascript") || + aName.LowerCaseEqualsLiteral("livescript") || + aName.LowerCaseEqualsLiteral("mocha")) { + version = JSVERSION_DEFAULT; + } else if (aName.LowerCaseEqualsLiteral("javascript1.0")) { + version = JSVERSION_1_0; + } else if (aName.LowerCaseEqualsLiteral("javascript1.1")) { + version = JSVERSION_1_1; + } else if (aName.LowerCaseEqualsLiteral("javascript1.2")) { + version = JSVERSION_1_2; + } else if (aName.LowerCaseEqualsLiteral("javascript1.3")) { + version = JSVERSION_1_3; + } else if (aName.LowerCaseEqualsLiteral("javascript1.4")) { + version = JSVERSION_1_4; + } else if (aName.LowerCaseEqualsLiteral("javascript1.5")) { + version = JSVERSION_1_5; + } else if (aName.LowerCaseEqualsLiteral("javascript1.6")) { + version = JSVERSION_1_6; + } else if (aName.LowerCaseEqualsLiteral("javascript1.7")) { + version = JSVERSION_1_7; + } else if (aName.LowerCaseEqualsLiteral("javascript1.8")) { + version = JSVERSION_1_8; + } + + if (version == JSVERSION_UNKNOWN) { + return false; + } + *aFlags = version; + return true; +} + +void +nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, + nsString& aParams) +{ + aType.Truncate(); + aParams.Truncate(); + PRInt32 semiIndex = aValue.FindChar(PRUnichar(';')); + if (-1 != semiIndex) { + aType = Substring(aValue, 0, semiIndex); + aParams = Substring(aValue, semiIndex + 1, + aValue.Length() - (semiIndex + 1)); + aParams.StripWhitespace(); + } + else { + aType = aValue; + } + aType.StripWhitespace(); +} + /** * Access a cached parser service. Don't addref. We need only one * reference to it and this class has that one. */ /* static */ nsIParserService* nsContentUtils::GetParserService() { @@ -3742,31 +3922,33 @@ nsContentUtils::ParseFragmentHTML(const aQuirks, aPreventScriptExecution); return rv; } /* static */ nsresult nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer, - nsIDocument* aTargetDocument) + nsIDocument* aTargetDocument, + bool aScriptingEnabledForNoscriptParsing) { if (nsContentUtils::sFragmentParsingActive) { NS_NOTREACHED("Re-entrant fragment parsing attempted."); return NS_ERROR_DOM_INVALID_STATE_ERR; } mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); nsContentUtils::sFragmentParsingActive = true; if (!sHTMLFragmentParser) { NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser()); // Now sHTMLFragmentParser owns the object } nsresult rv = sHTMLFragmentParser->ParseDocument(aSourceBuffer, - aTargetDocument); + aTargetDocument, + aScriptingEnabledForNoscriptParsing); return rv; } /* static */ nsresult nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer, nsIDocument* aDocument, nsTArray<nsString>& aTagStack, @@ -3807,16 +3989,54 @@ nsContentUtils::ParseFragmentXML(const n rv = sXMLFragmentSink->FinishFragmentParsing(aReturn); sXMLFragmentParser->Reset(); return rv; } +/* static */ +nsresult +nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, + nsAString& aResultBuffer, + PRUint32 aFlags, + PRUint32 aWrapCol) +{ + nsCOMPtr<nsIURI> uri; + NS_NewURI(getter_AddRefs(uri), "about:blank"); + nsCOMPtr<nsIPrincipal> principal = + do_CreateInstance("@mozilla.org/nullprincipal;1"); + nsCOMPtr<nsIDOMDocument> domDocument; + nsresult rv = nsContentUtils::CreateDocument(EmptyString(), + EmptyString(), + nsnull, + uri, + uri, + principal, + nsnull, + DocumentFlavorHTML, + getter_AddRefs(domDocument)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument); + rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document, + !(aFlags & nsIDocumentEncoder::OutputNoScriptContent)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance( + "@mozilla.org/layout/documentEncoder;1?type=text/plain"); + + rv = encoder->Init(domDocument, NS_LITERAL_STRING("text/plain"), aFlags); + NS_ENSURE_SUCCESS(rv, rv); + + encoder->SetWrapColumn(aWrapCol); + + return encoder->EncodeToString(aResultBuffer); +} /* static */ nsresult nsContentUtils::CreateDocument(const nsAString& aNamespaceURI, const nsAString& aQualifiedName, nsIDOMDocumentType* aDoctype, nsIURI* aDocumentURI, nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
--- a/content/base/src/nsCrossSiteListenerProxy.cpp +++ b/content/base/src/nsCrossSiteListenerProxy.cpp @@ -43,17 +43,16 @@ #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" #include "nsIParser.h" #include "nsParserCIID.h" #include "nsICharsetAlias.h" #include "nsMimeTypes.h" #include "nsIStreamConverterService.h" #include "nsStringStream.h" -#include "nsParserUtils.h" #include "nsGkAtoms.h" #include "nsWhitespaceTokenizer.h" #include "nsIChannelEventSink.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsCharSeparatedTokenizer.h" #include "nsAsyncRedirectVerifyHelper.h" #include "prclist.h" #include "prtime.h"
--- a/content/base/src/nsDOMParser.cpp +++ b/content/base/src/nsDOMParser.cpp @@ -97,17 +97,17 @@ nsDOMParser::ParseFromString(const PRUni nsresult rv; if (!nsCRT::strcmp(contentType, "text/html")) { nsCOMPtr<nsIDOMDocument> domDocument; rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument); nsDependentString sourceBuffer(str); - rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document); + rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document, false); NS_ENSURE_SUCCESS(rv, rv); // Keep the XULXBL state, base URL and principal setting in sync with the // XML case if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) { document->ForceEnableXULXBL(); }
--- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2896,16 +2896,24 @@ nsGenericElement::GetAttributeNodeNS(con const nsAString& aLocalName, nsIDOMAttr** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); *aReturn = nsnull; OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS); + return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName, aReturn); +} + +nsresult +nsGenericElement::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMAttr** aReturn) +{ nsCOMPtr<nsIDOMNamedNodeMap> map; nsresult rv = GetAttributes(getter_AddRefs(map)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMNode> node; rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node)); if (NS_SUCCEEDED(rv) && node) { @@ -5203,18 +5211,18 @@ nsGenericElement::SetAttrAndNotify(PRInt } if (aFireMutation) { nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED); nsCOMPtr<nsIDOMAttr> attrNode; nsAutoString ns; nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns); - GetAttributeNodeNS(ns, nsDependentAtomString(aName), - getter_AddRefs(attrNode)); + GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName), + getter_AddRefs(attrNode)); mutation.mRelatedNode = attrNode; mutation.mAttrName = aName; nsAutoString newValue; GetAttr(aNamespaceID, aName, newValue); if (!newValue.IsEmpty()) { mutation.mNewAttrValue = do_GetAtom(newValue); } @@ -5383,18 +5391,18 @@ nsGenericElement::UnsetAttr(PRInt32 aNam NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this); // Grab the attr node if needed before we remove it from the attr map nsCOMPtr<nsIDOMAttr> attrNode; if (hasMutationListeners) { nsAutoString ns; nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns); - GetAttributeNodeNS(ns, nsDependentAtomString(aName), - getter_AddRefs(attrNode)); + GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName), + getter_AddRefs(attrNode)); } // Clear binding to nsIDOMNamedNodeMap nsDOMSlots *slots = GetExistingDOMSlots(); if (slots && slots->mAttributeMap) { slots->mAttributeMap->DropAttribute(aNameSpaceID, aName); }
--- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -789,16 +789,20 @@ protected: nsIFrame* GetStyledFrame(); virtual mozilla::dom::Element* GetNameSpaceElement() { return this; } + nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMAttr** aReturn); + public: // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, // otherwise nsXULElement::nsXULSlots doesn't compile. /** * There are a set of DOM- and scripting-specific instance variables * that may only be instantiated when a content object is accessed * through the DOM. Rather than burn actual slots in the content * objects for each of these instance variables, we put them off
--- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -551,17 +551,17 @@ nsObjectLoadingContent::nsObjectLoadingC , mChannel(nsnull) , mType(eType_Loading) , mInstantiating(false) , mUserDisabled(false) , mSuppressed(false) , mNetworkCreated(true) // If plugins.click_to_play is false, plugins should always play , mShouldPlay(!mozilla::Preferences::GetBool("plugins.click_to_play", false)) - , mSrcStreamLoadInitiated(false) + , mSrcStreamLoading(false) , mFallbackReason(ePluginOtherState) { } nsObjectLoadingContent::~nsObjectLoadingContent() { DestroyImageLoadingContent(); if (mFrameLoader) { @@ -687,18 +687,16 @@ nsObjectLoadingContent::NotifyOwnerDocum // nsIRequestObserver NS_IMETHODIMP nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) { SAMPLE_LABEL("nsObjectLoadingContent", "OnStartRequest"); - mSrcStreamLoadInitiated = true; - if (aRequest != mChannel || !aRequest) { // This is a bit of an edge case - happens when a new load starts before the // previous one got here return NS_BINDING_ABORTED; } AutoNotifier notifier(this, true); @@ -878,17 +876,17 @@ nsObjectLoadingContent::OnStartRequest(n mType = newType; notifier.Notify(); } nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get()); if (!pluginHost) { return NS_ERROR_NOT_AVAILABLE; } - pluginHost->InstantiatePluginForChannel(chan, this, getter_AddRefs(mFinalListener)); + pluginHost->CreateListenerForChannel(chan, this, getter_AddRefs(mFinalListener)); break; } case eType_Loading: NS_NOTREACHED("Should not have a loading type here!"); case eType_Null: // Need to fallback here (instead of using the case below), so that we can // set mFallbackReason without it being overwritten. This is also why we // return early. @@ -901,30 +899,35 @@ nsObjectLoadingContent::OnStartRequest(n mFallbackReason = pluginState; FirePluginError(thisContent, pluginState); } return NS_BINDING_ABORTED; } if (mFinalListener) { mType = newType; + + mSrcStreamLoading = true; rv = mFinalListener->OnStartRequest(aRequest, aContext); - if (NS_FAILED(rv)) { -#ifdef XP_MACOSX - // Shockwave on Mac is special and returns an error here even when it - // handles the content - if (mContentType.EqualsLiteral("application/x-director")) { - rv = NS_OK; // otherwise, the AutoFallback will make us fall back + mSrcStreamLoading = false; + + if (NS_SUCCEEDED(rv)) { + // Plugins need to set up for NPRuntime. + if (mType == eType_Plugin) { + NotifyContentObjectWrapper(); + } + } else { + // Plugins don't fall back if there is an error here. + if (mType == eType_Plugin) { + rv = NS_OK; // this is necessary to avoid auto-fallback return NS_BINDING_ABORTED; } -#endif Fallback(false); - } else if (mType == eType_Plugin) { - NotifyContentObjectWrapper(); } + return rv; } Fallback(false); return NS_BINDING_ABORTED; } NS_IMETHODIMP @@ -2106,12 +2109,11 @@ nsObjectLoadingContent::NotifyContentObj } NS_IMETHODIMP nsObjectLoadingContent::PlayPlugin() { if (!nsContentUtils::IsCallerChrome()) return NS_OK; - mSrcStreamLoadInitiated = false; mShouldPlay = true; return LoadObject(mURI, true, mContentType, true); }
--- a/content/base/src/nsObjectLoadingContent.h +++ b/content/base/src/nsObjectLoadingContent.h @@ -146,17 +146,17 @@ class nsObjectLoadingContent : public ns mNetworkCreated = aNetworkCreated; } // Can flush layout. nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI); void NotifyOwnerDocumentActivityChanged(); - bool SrcStreamLoadInitiated() { return mSrcStreamLoadInitiated; }; + bool SrcStreamLoading() { return mSrcStreamLoading; }; protected: /** * Load the object from the given URI. * @param aURI The URI to load. * @param aNotify If true, nsIDocumentObserver state change notifications * will be sent as needed. * @param aTypeHint MIME Type hint. Overridden by the server unless this @@ -396,19 +396,22 @@ class nsObjectLoadingContent : public ns // created using NS_FROM_PARSER_NETWORK flag. If the element is modified, // it may lose the flag. bool mNetworkCreated : 1; // Used to keep track of whether or not a plugin should be played. // This is used for click-to-play plugins. bool mShouldPlay : 1; - // Used to indicate that a stream for a src/data attribute has been - // initiated so that we don't do it twice. - bool mSrcStreamLoadInitiated; + // Used to track when we might try to instantiate a plugin instance based on + // a src data stream being delivered to this object. When this is true we don't + // want plugin instance instantiation code to attempt to load src data again or + // we'll deliver duplicate streams. Should be cleared when we are not loading + // src data. + bool mSrcStreamLoading; // A specific state that caused us to fallback PluginSupportState mFallbackReason; nsWeakFrame mPrintFrame; nsRefPtr<nsPluginInstanceOwner> mInstanceOwner; };
deleted file mode 100644 --- a/content/base/src/nsParserUtils.cpp +++ /dev/null @@ -1,236 +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 Communicator client 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): - * - * 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 ***** */ - -/* - * Namespace class for some static parsing-related methods. - */ - -#include "nsParserUtils.h" -#include "jsapi.h" -#include "nsReadableUtils.h" -#include "nsCRT.h" -#include "nsContentUtils.h" -#include "nsIParserService.h" -#include "nsParserConstants.h" - -#define SKIP_WHITESPACE(iter, end_iter, end_res) \ - while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ - ++(iter); \ - } \ - if ((iter) == (end_iter)) { \ - return (end_res); \ - } - -#define SKIP_ATTR_NAME(iter, end_iter) \ - while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ - *(iter) != '=') { \ - ++(iter); \ - } - -bool -nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName, - nsAString& aValue) -{ - aValue.Truncate(); - - const PRUnichar *start = aSource.get(); - const PRUnichar *end = start + aSource.Length(); - const PRUnichar *iter; - - while (start != end) { - SKIP_WHITESPACE(start, end, false) - iter = start; - SKIP_ATTR_NAME(iter, end) - - if (start == iter) { - return false; - } - - // Remember the attr name. - const nsDependentSubstring & attrName = Substring(start, iter); - - // Now check whether this is a valid name="value" pair. - start = iter; - SKIP_WHITESPACE(start, end, false) - if (*start != '=') { - // No '=', so this is not a name="value" pair. We don't know - // what it is, and we have no way to handle it. - return false; - } - - // Have to skip the value. - ++start; - SKIP_WHITESPACE(start, end, false) - PRUnichar q = *start; - if (q != kQuote && q != kApostrophe) { - // Not a valid quoted value, so bail. - return false; - } - - ++start; // Point to the first char of the value. - iter = start; - - while (iter != end && *iter != q) { - ++iter; - } - - if (iter == end) { - // Oops, unterminated quoted string. - return false; - } - - // At this point attrName holds the name of the "attribute" and - // the value is between start and iter. - - if (aName->Equals(attrName)) { - nsIParserService* parserService = nsContentUtils::GetParserService(); - NS_ENSURE_TRUE(parserService, false); - - // We'll accumulate as many characters as possible (until we hit either - // the end of the string or the beginning of an entity). Chunks will be - // delimited by start and chunkEnd. - const PRUnichar *chunkEnd = start; - while (chunkEnd != iter) { - if (*chunkEnd == kLessThan) { - aValue.Truncate(); - - return false; - } - - if (*chunkEnd == kAmpersand) { - aValue.Append(start, chunkEnd - start); - - // Point to first character after the ampersand. - ++chunkEnd; - - const PRUnichar *afterEntity; - PRUnichar result[2]; - PRUint32 count = - parserService->DecodeEntity(chunkEnd, iter, &afterEntity, result); - if (count == 0) { - aValue.Truncate(); - - return false; - } - - aValue.Append(result, count); - - // Advance to after the entity and begin a new chunk. - start = chunkEnd = afterEntity; - } - else { - ++chunkEnd; - } - } - - // Append remainder. - aValue.Append(start, iter - start); - - return true; - } - - // Resume scanning after the end of the attribute value (past the quote - // char). - start = iter + 1; - } - - return false; -} - -// Returns true if the language name is a version of JavaScript and -// false otherwise -bool -nsParserUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags) -{ - JSVersion version = JSVERSION_UNKNOWN; - - if (aName.LowerCaseEqualsLiteral("javascript") || - aName.LowerCaseEqualsLiteral("livescript") || - aName.LowerCaseEqualsLiteral("mocha")) { - version = JSVERSION_DEFAULT; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.0")) { - version = JSVERSION_1_0; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.1")) { - version = JSVERSION_1_1; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.2")) { - version = JSVERSION_1_2; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.3")) { - version = JSVERSION_1_3; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.4")) { - version = JSVERSION_1_4; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.5")) { - version = JSVERSION_1_5; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.6")) { - version = JSVERSION_1_6; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.7")) { - version = JSVERSION_1_7; - } - else if (aName.LowerCaseEqualsLiteral("javascript1.8")) { - version = JSVERSION_1_8; - } - if (version == JSVERSION_UNKNOWN) - return false; - *aFlags = version; - return true; -} - -void -nsParserUtils::SplitMimeType(const nsAString& aValue, nsString& aType, - nsString& aParams) -{ - aType.Truncate(); - aParams.Truncate(); - PRInt32 semiIndex = aValue.FindChar(PRUnichar(';')); - if (-1 != semiIndex) { - aType = Substring(aValue, 0, semiIndex); - aParams = Substring(aValue, semiIndex + 1, - aValue.Length() - (semiIndex + 1)); - aParams.StripWhitespace(); - } - else { - aType = aValue; - } - aType.StripWhitespace(); -}
deleted file mode 100644 --- a/content/base/src/nsParserUtils.h +++ /dev/null @@ -1,79 +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 Communicator client 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): - * - * 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 ***** */ - -/* - * Namespace class for some static parsing-related methods. - */ - -#ifndef nsParserUtils_h__ -#define nsParserUtils_h__ - -#include "nsString.h" -class nsIAtom; - -class nsParserUtils { -public: - /** - * This will parse aSource, to extract the value of the pseudo attribute - * with the name specified in aName. See - * http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification - * which is used to parse aSource. - * - * @param aSource the string to parse - * @param aName the name of the attribute to get the value for - * @param aValue [out] the value for the attribute with name specified in - * aAttribute. Empty if the attribute isn't present. - * @return true if the attribute exists and was successfully parsed. - * false if the attribute doesn't exist, or has a malformed - * value, such as an unknown or unterminated entity. - */ - static bool - GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName, - nsAString& aValue); - - static bool - IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags); - - static void - SplitMimeType(const nsAString& aValue, nsString& aType, - nsString& aParams); -}; - -#endif // nsParserUtils_h__ - - -
--- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -39,17 +39,16 @@ /* * A class that handles loading and evaluation of <script> elements. */ #include "jsapi.h" #include "jsfriendapi.h" #include "nsScriptLoader.h" -#include "nsParserUtils.h" #include "nsICharsetConverterManager.h" #include "nsIUnicodeDecoder.h" #include "nsIContent.h" #include "mozilla/dom/Element.h" #include "nsGkAtoms.h" #include "nsNetUtil.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" @@ -504,24 +503,24 @@ nsScriptLoader::ProcessScriptElement(nsI } } else { // no 'type=' element // "language" is a deprecated attribute of HTML, so we check it only for // HTML script elements. if (scriptContent->IsHTML()) { scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language); if (!language.IsEmpty()) { - if (nsParserUtils::IsJavaScriptLanguage(language, &version)) + if (nsContentUtils::IsJavaScriptLanguage(language, &version)) typeID = nsIProgrammingLanguage::JAVASCRIPT; else typeID = nsIProgrammingLanguage::UNKNOWN; // IE, Opera, etc. do not respect language version, so neither should // we at this late date in the browser wars saga. Note that this change // affects HTML but not XUL or SVG (but note also that XUL has its own - // code to check nsParserUtils::IsJavaScriptLanguage -- that's probably + // code to check nsContentUtils::IsJavaScriptLanguage -- that's probably // a separate bug, one we may not be able to fix short of XUL2). See // bug 255895 (https://bugzilla.mozilla.org/show_bug.cgi?id=255895). NS_ASSERTION(JSVERSION_DEFAULT == 0, "We rely on all languages having 0 as a version default"); version = 0; } } }
--- a/content/base/test/TestPlainTextSerializer.cpp +++ b/content/base/test/TestPlainTextSerializer.cpp @@ -32,47 +32,28 @@ * 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 "TestHarness.h" -#include "nsIParser.h" -#include "nsIHTMLToTextSink.h" -#include "nsIParser.h" -#include "nsIContentSink.h" -#include "nsIParserService.h" #include "nsServiceManagerUtils.h" #include "nsStringGlue.h" -#include "nsParserCIID.h" #include "nsIDocumentEncoder.h" #include "nsCRT.h" - -static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); +#include "nsIParserUtils.h" void ConvertBufToPlainText(nsString &aConBuf, int aFlag) { - nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID); - if (parser) { - nsCOMPtr<nsIContentSink> sink; - sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID); - if (sink) { - nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink)); - if (textSink) { - nsAutoString convertedText; - textSink->Initialize(&convertedText, aFlag, 72); - parser->SetContentSink(sink); - parser->Parse(aConBuf, 0, NS_LITERAL_CSTRING("text/html"), true); - aConBuf = convertedText; - } - } - } + nsCOMPtr<nsIParserUtils> utils = + do_GetService(NS_PARSERUTILS_CONTRACTID); + utils->ConvertToPlainText(aConBuf, aFlag, 72, aConBuf); } // Test for ASCII with format=flowed; delsp=yes nsresult TestASCIIWithFlowedDelSp() { nsString test; nsString result;
--- a/content/base/test/chrome/Makefile.in +++ b/content/base/test/chrome/Makefile.in @@ -66,15 +66,16 @@ include $(topsrcdir)/config/rules.mk test_fileconstructor.xul \ fileconstructor_file.png \ test_bug339494.xul \ test_bug357450.xul \ test_bug571390.xul \ test_bug574596.html \ test_bug683852.xul \ test_bug599295.html \ + test_bug650784.html \ $(NULL) libs:: $(_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) libs:: $(_CHROME_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/content/base/test/chrome/test_bug650784.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=650776 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 650776</title> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 650776 **/ + +var c = Components.interfaces.nsIDocumentEncoder; +var s = Components.classes["@mozilla.org/parserutils;1"] + .getService(Components.interfaces.nsIParserUtils); + +is(s.convertToPlainText("foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 1"); +is(s.convertToPlainText("foo foo foo", c.OutputWrap | c.OutputLFLineBreak, 7), "foo foo\nfoo", "Wrong conversion result 2"); +is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 3"); +is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputNoScriptContent, 0), "barfoo", "Wrong conversion result 4"); +is(s.convertToPlainText("foo\u00A0bar", c.OutputPersistNBSP | c.OutputLFLineBreak, 0), "foo\u00A0bar", "Wrong conversion result 5"); +is(s.convertToPlainText("foo\u00A0bar", c.OutputLFLineBreak, 0), "foo bar", "Wrong conversion result 6"); +is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 7"); +// OutputNoFramesContent doesn't actually work, because the flag gets overridden by +// the browser.frames.enabled pref in all cases. +is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputNoFramesContent | c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 8"); +is(s.convertToPlainText("<i>foo</i> <b>bar</b>", c.OutputFormatted | c.OutputLFLineBreak, 0), "/foo/ *bar*\n", "Wrong conversion result 9"); +is(s.convertToPlainText("<p>foo</p> <p>bar</p>", c.OutputLFLineBreak, 0), "foo\n\nbar", "Wrong conversion result 10"); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/content/canvas/crashtests/729116.html @@ -0,0 +1,18 @@ +<html> +<script language=javascript> + +function draw() { + var canv = document.getElementById("canv"); + var ctx = canv.getContext("2d"); + try { + canv.width = 50000; + } catch (e) { } + + ctx.clearRect(0, 0, 10, 10); +} + +</script> +<body onload="draw()"> +<canvas id="canv" width="5" height="5"></canvas> +</body> +</html>
--- a/content/canvas/crashtests/crashtests.list +++ b/content/canvas/crashtests/crashtests.list @@ -1,5 +1,6 @@ load 360293-1.html load 421715-1.html load 553938-1.html load 647480.html load 0px-size-font-667225.html +skip-if(cocoaWidget&&layersGPUAccelerated) load 729116.html # bug 731117
--- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -357,18 +357,16 @@ WebGLContext::SetDimensions(PRInt32 widt gl->ClearSafely(); return NS_OK; } /*** end of early success return cases ***/ - ScopedGfxFeatureReporter reporter("WebGL"); - // At this point we know that the old context is not going to survive, even though we still don't // know if creating the new context will succeed. DestroyResourcesAndContext(); // Get some prefs for some preferred/overriden things NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); bool forceOSMesa = @@ -381,16 +379,18 @@ WebGLContext::SetDimensions(PRInt32 widt #endif bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false); bool disabled = Preferences::GetBool("webgl.disabled", false); bool verbose = Preferences::GetBool("webgl.verbose", false); + ScopedGfxFeatureReporter reporter("WebGL", forceEnabled); + if (disabled) return NS_ERROR_FAILURE; mVerbose = verbose; // We're going to create an entirely new context. If our // generation is not 0 right now (that is, if this isn't the first // context we're creating), we may have to dispatch a context lost
--- a/content/canvas/src/WebGLContextReporter.cpp +++ b/content/canvas/src/WebGLContextReporter.cpp @@ -37,17 +37,17 @@ * ***** END LICENSE BLOCK ***** */ #include "WebGLContext.h" #include "nsIMemoryReporter.h" using namespace mozilla; -class WebGLMemoryMultiReporter : public nsIMemoryMultiReporter +class WebGLMemoryMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter { public: NS_DECL_ISUPPORTS NS_DECL_NSIMEMORYMULTIREPORTER }; NS_IMPL_ISUPPORTS1(WebGLMemoryMultiReporter, nsIMemoryMultiReporter)
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp @@ -1301,16 +1301,20 @@ nsCanvasRenderingContext2DAzure::Initial // will be set to non-null. // In all cases, any usable canvas context will have non-null mTarget. if (target) { mValid = true; mTarget = target; } else { mValid = false; + // Create a dummy target in the hopes that it will help us deal with users + // calling into us after having changed the size where the size resulted + // in an inability to create a correct DrawTarget. + mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8); } mResetLayer = true; // set up the initial canvas defaults mStyleStack.Clear(); mPathBuilder = nsnull; mPath = nsnull;
--- a/content/canvas/test/webgl/test_webgl_conformance_test_suite.html +++ b/content/canvas/test/webgl/test_webgl_conformance_test_suite.html @@ -37,16 +37,18 @@ var OPTIONS = { request.open('GET', url, false); request.send(null); if (request.readyState != 4) { throw error; } return request.responseText; }; +SimpleTest.waitForExplicitFinish(); + function start() { var kIsWindows = false; var kIsMac = false; var kIsLinux = false; if (navigator.platform.indexOf("Win") == 0) kIsWindows = true; else if (navigator.platform.indexOf("Linux") == 0) @@ -57,16 +59,44 @@ function start() { var kIsWindowsVistaOrHigher = false; if (kIsWindows) { // code borrowed from browser/modules/test/browser_taskbar_preview.js netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var version = Components.classes["@mozilla.org/system-info;1"] .getService(Components.interfaces.nsIPropertyBag2) .getProperty("version"); kIsWindowsVistaOrHigher = (parseFloat(version) >= 6.0); + // Workaround for Windows 2000 (driver?) which may crash itself. + if (parseFloat(version) <= 5.0) { + todo(false, "Test disabled on Windows 2000 and older. (To prevent possible system crash.)"); + SimpleTest.finish(); + return; + } + } + + // we currently disable this test on version of Mac OSX older than 10.6, + // due to various weird failures, including one making getRenderbufferParameter tests + // on DEPTH_STENCIL fail + var kDarwinVersion = 0; + if (kIsMac) { + // code borrowed from browser/modules/test/browser_taskbar_preview.js + var is106orHigher = false; + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + kDarwinVersion = parseFloat(Components.classes["@mozilla.org/system-info;1"] + .getService(Components.interfaces.nsIPropertyBag2) + .getProperty("version")); + // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 ! + // Mac OS 10.5 would be Darwin version 9. the |version| string we've got here + // is the Darwin version. + is106orHigher = (kDarwinVersion >= 10.0); + if (!is106orHigher) { + dump("WebGL mochitest disabled on Mac OSX versions older than 10.6\n"); + SimpleTest.finish(); + return; + } } function getEnv(env) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var envsvc = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment); var val = envsvc.get(env); if (val == "") return null; @@ -338,47 +368,28 @@ function start() { return reporter.reportFunc(type, msg, success); }, OPTIONS); testHarness.setTimeoutDelay(20000); // and make it much higher when running under valgrind. window.webglTestHarness = testHarness; } else { var errmsg = "Can't create a WebGL context"; reporter.fullResultsNode.textContent = errmsg; - ok(false, errmsg); + // Workaround for SeaMonkey tinderboxes which don't support WebGL. + if (navigator.userAgent.match(/ SeaMonkey\//)) + todo(false, errmsg + " (This is expected on SeaMonkey (tinderboxes).)"); + else + ok(false, errmsg); dump("WebGL mochitest failed: " + errmsg + "\n"); reporter.finishedTestSuite(); } }; - SimpleTest.waitForExplicitFinish(); SimpleTest.requestLongerTimeout(3); - // we currently disable this test on version of Mac OSX older than 10.6, - // due to various weird failures, including one making getRenderbufferParameter tests - // on DEPTH_STENCIL fail - var kDarwinVersion = 0; - if (kIsMac) { - // code borrowed from browser/modules/test/browser_taskbar_preview.js - var is106orHigher = false; - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - kDarwinVersion = parseFloat(Components.classes["@mozilla.org/system-info;1"] - .getService(Components.interfaces.nsIPropertyBag2) - .getProperty("version")); - // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 ! - // Mac OS 10.5 would be Darwin version 9. the |version| string we've got here - // is the Darwin version. - is106orHigher = (kDarwinVersion >= 10.0); - if (!is106orHigher) { - dump("WebGL mochitest disabled on Mac OSX versions older than 10.6\n"); - SimpleTest.finish(); - return; - } - } - var statusElem = document.getElementById("status"); var statusTextNode = document.createTextNode(''); statusElem.appendChild(statusTextNode); var expectedtofailElem = document.getElementById("expectedtofail"); var expectedtofailTextNode = document.createTextNode(''); expectedtofailElem.appendChild(expectedtofailTextNode); @@ -426,17 +437,17 @@ function start() { var testsSuccessful = []; runTestSuite(); } </script> </head> -<body onload="start()"> +<body onload="start();"> <p id="display"></p> <div id="content" style="display: none"> </div> <table border="2px"> <tr style="height: 500px;"> <td style="width: 500px;"> <iframe id="testframe" scrolling="no" width="500px" height="500px"></iframe>
--- a/content/html/content/src/nsHTMLLinkElement.cpp +++ b/content/html/content/src/nsHTMLLinkElement.cpp @@ -47,17 +47,16 @@ #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsIURL.h" #include "nsNetUtil.h" #include "nsIDocument.h" #include "nsIDOMEvent.h" #include "nsIPrivateDOMEvent.h" #include "nsIDOMEventTarget.h" -#include "nsParserUtils.h" #include "nsContentUtils.h" #include "nsPIDOMWindow.h" #include "nsAsyncDOMEvent.h" #include "Link.h" using namespace mozilla::dom; class nsHTMLLinkElement : public nsGenericHTMLElement, @@ -434,17 +433,17 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsA } GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia); ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE nsAutoString mimeType; nsAutoString notUsed; GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType); - nsParserUtils::SplitMimeType(aType, mimeType, notUsed); + nsContentUtils::SplitMimeType(aType, mimeType, notUsed); if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) { return; } // If we get here we assume that we're loading a css file, so set the // type to 'text/css' aType.AssignLiteral("text/css");
--- a/content/html/content/src/nsHTMLStyleElement.cpp +++ b/content/html/content/src/nsHTMLStyleElement.cpp @@ -42,17 +42,16 @@ #include "nsGkAtoms.h" #include "nsStyleConsts.h" #include "nsIDOMStyleSheet.h" #include "nsIStyleSheet.h" #include "nsStyleLinkElement.h" #include "nsNetUtil.h" #include "nsIDocument.h" #include "nsUnicharUtils.h" -#include "nsParserUtils.h" #include "nsThreadUtils.h" #include "nsContentUtils.h" class nsHTMLStyleElement : public nsGenericHTMLElement, public nsIDOMHTMLStyleElement, public nsStyleLinkElement, public nsStubMutationObserver { @@ -342,17 +341,17 @@ nsHTMLStyleElement::GetStyleSheetInfo(ns GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia); ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType); nsAutoString mimeType; nsAutoString notUsed; - nsParserUtils::SplitMimeType(aType, mimeType, notUsed); + nsContentUtils::SplitMimeType(aType, mimeType, notUsed); if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) { return; } // If we get here we assume that we're loading a css file, so set the // type to 'text/css' aType.AssignLiteral("text/css"); }
--- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -45,17 +45,16 @@ #include "nsContentSink.h" #include "nsCOMPtr.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsIHTMLContentSink.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIParser.h" -#include "nsParserUtils.h" #include "nsScriptLoader.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsIContentViewer.h" #include "nsIMarkupDocumentViewer.h" #include "nsINodeInfo.h" #include "nsHTMLTokens.h" #include "nsIAppShell.h"
--- a/content/mathml/content/src/nsMathMLElement.cpp +++ b/content/mathml/content/src/nsMathMLElement.cpp @@ -141,16 +141,21 @@ nsMathMLElement::ParseAttribute(PRInt32 return aResult.ParseColor(aValue); } } return nsMathMLElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue, aResult); } +static nsGenericElement::MappedAttributeEntry sMtableStyles[] = { + { &nsGkAtoms::width }, + { nsnull } +}; + static nsGenericElement::MappedAttributeEntry sTokenStyles[] = { { &nsGkAtoms::mathsize_ }, { &nsGkAtoms::fontsize_ }, { &nsGkAtoms::color }, { &nsGkAtoms::fontfamily_ }, { nsnull } }; @@ -166,16 +171,20 @@ static nsGenericElement::MappedAttribute { &nsGkAtoms::mathcolor_ }, { &nsGkAtoms::mathbackground_ }, { nsnull } }; bool nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const { + static const MappedAttributeEntry* const mtableMap[] = { + sMtableStyles, + sCommonPresStyles + }; static const MappedAttributeEntry* const tokenMap[] = { sTokenStyles, sCommonPresStyles }; static const MappedAttributeEntry* const mstyleMap[] = { sTokenStyles, sEnvironmentStyles, sCommonPresStyles @@ -189,16 +198,19 @@ nsMathMLElement::IsAttributeMapped(const if (tag == nsGkAtoms::ms_ || tag == nsGkAtoms::mi_ || tag == nsGkAtoms::mn_ || tag == nsGkAtoms::mo_ || tag == nsGkAtoms::mtext_ || tag == nsGkAtoms::mspace_) return FindAttributeDependence(aAttribute, tokenMap); if (tag == nsGkAtoms::mstyle_ || tag == nsGkAtoms::math) return FindAttributeDependence(aAttribute, mstyleMap); + if (tag == nsGkAtoms::mtable_) + return FindAttributeDependence(aAttribute, mtableMap); + if (tag == nsGkAtoms::maction_ || tag == nsGkAtoms::maligngroup_ || tag == nsGkAtoms::malignmark_ || tag == nsGkAtoms::menclose_ || tag == nsGkAtoms::merror_ || tag == nsGkAtoms::mfenced_ || tag == nsGkAtoms::mfrac_ || tag == nsGkAtoms::mover_ || @@ -206,17 +218,16 @@ nsMathMLElement::IsAttributeMapped(const tag == nsGkAtoms::mphantom_ || tag == nsGkAtoms::mprescripts_ || tag == nsGkAtoms::mroot_ || tag == nsGkAtoms::mrow_ || tag == nsGkAtoms::msqrt_ || tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msubsup_ || tag == nsGkAtoms::msup_ || - tag == nsGkAtoms::mtable_ || tag == nsGkAtoms::mtd_ || tag == nsGkAtoms::mtr_ || tag == nsGkAtoms::munder_ || tag == nsGkAtoms::munderover_ || tag == nsGkAtoms::none) { return FindAttributeDependence(aAttribute, commonPresMap); } @@ -454,16 +465,29 @@ nsMathMLElement::MapMathMLAttributesInto } nscolor color; nsCSSValue* colorValue = aData->ValueForColor(); if (value && value->GetColorValue(color) && colorValue->GetUnit() == eCSSUnit_Null) { colorValue->SetColorValue(color); } } + + if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) { + // width: value + nsCSSValue* width = aData->ValueForWidth(); + if (width->GetUnit() == eCSSUnit_Null) { + const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width); + // This does not handle auto and unitless values + if (value && value->Type() == nsAttrValue::eString) { + ParseNumericValue(value->GetStringValue(), *width, 0); + } + } + } + } nsresult nsMathMLElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor) { nsresult rv = nsGenericElement::PreHandleEvent(aVisitor); NS_ENSURE_SUCCESS(rv, rv);
--- a/content/xml/content/src/nsXMLProcessingInstruction.cpp +++ b/content/xml/content/src/nsXMLProcessingInstruction.cpp @@ -34,18 +34,18 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsGenericElement.h" #include "nsGkAtoms.h" #include "nsUnicharUtils.h" #include "nsXMLProcessingInstruction.h" -#include "nsParserUtils.h" #include "nsContentCreatorFunctions.h" +#include "nsContentUtils.h" nsresult NS_NewXMLProcessingInstruction(nsIContent** aInstancePtrResult, nsNodeInfoManager *aNodeInfoManager, const nsAString& aTarget, const nsAString& aData) { NS_PRECONDITION(aNodeInfoManager, "Missing nodeinfo manager"); @@ -124,17 +124,17 @@ nsXMLProcessingInstruction::GetTarget(ns } bool nsXMLProcessingInstruction::GetAttrValue(nsIAtom *aName, nsAString& aValue) { nsAutoString data; GetData(data); - return nsParserUtils::GetQuotedAttributeValue(data, aName, aValue); + return nsContentUtils::GetPseudoAttributeValue(data, aName, aValue); } bool nsXMLProcessingInstruction::IsNodeOfType(PRUint32 aFlags) const { return !(aFlags & ~(eCONTENT | ePROCESSING_INSTRUCTION | eDATA_NODE)); }
--- a/content/xml/content/src/nsXMLStylesheetPI.cpp +++ b/content/xml/content/src/nsXMLStylesheetPI.cpp @@ -40,17 +40,16 @@ #include "nsIDOMStyleSheet.h" #include "nsIDocument.h" #include "nsIStyleSheet.h" #include "nsIURI.h" #include "nsStyleLinkElement.h" #include "nsNetUtil.h" #include "nsXMLProcessingInstruction.h" #include "nsUnicharUtils.h" -#include "nsParserUtils.h" #include "nsGkAtoms.h" #include "nsThreadUtils.h" #include "nsContentUtils.h" class nsXMLStylesheetPI : public nsXMLProcessingInstruction, public nsStyleLinkElement { public: @@ -204,37 +203,39 @@ nsXMLStylesheetPI::GetStyleSheetInfo(nsA // xml-stylesheet PI is special only in prolog if (!nsContentUtils::InProlog(this)) { return; } nsAutoString data; GetData(data); - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::title, aTitle); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::title, aTitle); nsAutoString alternate; - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::alternate, alternate); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::alternate, + alternate); // if alternate, does it have title? if (alternate.EqualsLiteral("yes")) { if (aTitle.IsEmpty()) { // alternates must have title return; } *aIsAlternate = true; } - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::media, aMedia); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::media, aMedia); nsAutoString type; - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type); nsAutoString mimeType, notUsed; - nsParserUtils::SplitMimeType(type, mimeType, notUsed); + nsContentUtils::SplitMimeType(type, mimeType, notUsed); if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) { aType.Assign(type); return; } // If we get here we assume that we're loading a css file, so set the // type to 'text/css' aType.AssignLiteral("text/css");
--- a/content/xml/document/src/nsXMLContentSink.cpp +++ b/content/xml/document/src/nsXMLContentSink.cpp @@ -63,17 +63,16 @@ #include "nsIScriptContext.h" #include "nsINameSpaceManager.h" #include "nsIServiceManager.h" #include "nsIScriptSecurityManager.h" #include "nsIContentViewer.h" #include "prtime.h" #include "prlog.h" #include "prmem.h" -#include "nsParserUtils.h" #include "nsRect.h" #include "nsGenericElement.h" #include "nsIWebNavigation.h" #include "nsIScriptElement.h" #include "nsScriptLoader.h" #include "nsStyleLinkElement.h" #include "nsIImageLoadingContent.h" #include "nsReadableUtils.h" @@ -260,37 +259,37 @@ CheckXSLTParamPI(nsIDOMProcessingInstruc { nsAutoString target, data; aPi->GetTarget(target); // Check for namespace declarations if (target.EqualsLiteral("xslt-param-namespace")) { aPi->GetData(data); nsAutoString prefix, namespaceAttr; - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::prefix, - prefix); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix, + prefix); if (!prefix.IsEmpty() && - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace, - namespaceAttr)) { + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace, + namespaceAttr)) { aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr); } } // Check for actual parameters else if (target.EqualsLiteral("xslt-param")) { aPi->GetData(data); nsAutoString name, namespaceAttr, select, value; - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::name, - name); - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace, - namespaceAttr); - if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::select, select)) { + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name, + name); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace, + namespaceAttr); + if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) { select.SetIsVoid(true); } - if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::value, value)) { + if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) { value.SetIsVoid(true); } if (!name.IsEmpty()) { nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument); aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc); } } } @@ -1335,17 +1334,17 @@ nsXMLContentSink::HandleProcessingInstru } return NS_OK; } } // If it's not a CSS stylesheet PI... nsAutoString type; - nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type); if (mState != eXMLContentSinkState_InProlog || !target.EqualsLiteral("xml-stylesheet") || type.IsEmpty() || type.LowerCaseEqualsLiteral("text/css")) { return DidProcessATokenImpl(); } @@ -1363,26 +1362,28 @@ nsXMLContentSink::HandleProcessingInstru /* static */ bool nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref, nsString &aTitle, nsString &aMedia, bool &aIsAlternate) { // If there was no href, we can't do anything with this PI - if (!nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::href, aHref)) { + if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) { return false; } - nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::title, aTitle); + nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle); - nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::media, aMedia); + nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia); nsAutoString alternate; - nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::alternate, alternate); + nsContentUtils::GetPseudoAttributeValue(aData, + nsGkAtoms::alternate, + alternate); aIsAlternate = alternate.EqualsLiteral("yes"); return true; } NS_IMETHODIMP nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
--- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1363,17 +1363,18 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpa bool hasMutationListeners = aNotify && nsContentUtils::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this); nsCOMPtr<nsIDOMAttr> attrNode; if (hasMutationListeners) { nsAutoString ns; nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns); - GetAttributeNodeNS(ns, nsDependentAtomString(aName), getter_AddRefs(attrNode)); + GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName), + getter_AddRefs(attrNode)); } nsDOMSlots *slots = GetExistingDOMSlots(); if (slots && slots->mAttributeMap) { slots->mAttributeMap->DropAttribute(aNameSpaceID, aName); } // The id-handling code, and in the future possibly other code, need to
--- a/content/xul/document/src/nsXULContentSink.cpp +++ b/content/xul/document/src/nsXULContentSink.cpp @@ -69,17 +69,16 @@ #include "nsIServiceManager.h" #include "nsIURL.h" #include "nsIViewManager.h" #include "nsIXULDocument.h" #include "nsIScriptSecurityManager.h" #include "nsLayoutCID.h" #include "nsNetUtil.h" #include "nsRDFCID.h" -#include "nsParserUtils.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsXULElement.h" #include "prlog.h" #include "prmem.h" #include "nsCRT.h" #include "nsXULPrototypeDocument.h" // XXXbe temporary @@ -1074,17 +1073,17 @@ XULContentSinkImpl::OpenScript(const PRU } } } else if (key.EqualsLiteral("language")) { // Language is deprecated, and the impl in nsScriptLoader ignores the // various version strings anyway. So we make no attempt to support // languages other than JS for language= nsAutoString lang(aAttributes[1]); - if (nsParserUtils::IsJavaScriptLanguage(lang, &version)) { + if (nsContentUtils::IsJavaScriptLanguage(lang, &version)) { langID = nsIProgrammingLanguage::JAVASCRIPT; // Even when JS version < 1.6 is specified, E4X is // turned on in XUL. version = js::VersionSetXML(JSVersion(version), true); } } aAttributes += 2;
--- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -79,17 +79,16 @@ #include "nsITimer.h" #include "nsIDocShell.h" #include "nsGkAtoms.h" #include "nsXMLContentSink.h" #include "nsXULContentSink.h" #include "nsXULContentUtils.h" #include "nsIXULOverlayProvider.h" #include "nsNetUtil.h" -#include "nsParserUtils.h" #include "nsParserCIID.h" #include "nsPIBoxObject.h" #include "nsRDFCID.h" #include "nsILocalStore.h" #include "nsXPIDLString.h" #include "nsPIDOMWindow.h" #include "nsPIWindowRoot.h" #include "nsXULCommandDispatcher.h" @@ -2540,19 +2539,19 @@ nsXULDocument::InsertXULOverlayPI(const if (NS_FAILED(rv)) return rv; // xul-overlay PI is special only in prolog if (!nsContentUtils::InProlog(aPINode)) { return NS_OK; } nsAutoString href; - nsParserUtils::GetQuotedAttributeValue(aProtoPI->mData, - nsGkAtoms::href, - href); + nsContentUtils::GetPseudoAttributeValue(aProtoPI->mData, + nsGkAtoms::href, + href); // If there was no href, we can't do anything with this PI if (href.IsEmpty()) { return NS_OK; } // Add the overlay to our list of overlays that need to be processed. nsCOMPtr<nsIURI> uri;
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7662,37 +7662,40 @@ void nsGlobalWindow::MaybeUpdateTouchSta nsIFocusManager* fm = nsFocusManager::GetFocusManager(); nsCOMPtr<nsIDOMWindow> focusedWindow; fm->GetFocusedWindow(getter_AddRefs(focusedWindow)); if(this == focusedWindow) { UpdateTouchState(); } + + if (mMayHaveTouchEventListener) { + nsCOMPtr<nsIObserverService> observerService = + do_GetService(NS_OBSERVERSERVICE_CONTRACTID); + + if (observerService) { + observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this), + DOM_TOUCH_LISTENER_ADDED, + nsnull); + } + } } void nsGlobalWindow::UpdateTouchState() { FORWARD_TO_INNER_VOID(UpdateTouchState, ()); nsCOMPtr<nsIWidget> mainWidget = GetMainWidget(); - if (!mainWidget) + if (!mainWidget) { return; + } if (mMayHaveTouchEventListener) { mainWidget->RegisterTouchWindow(); - - nsCOMPtr<nsIObserverService> observerService = - do_GetService(NS_OBSERVERSERVICE_CONTRACTID); - - if (observerService) { - observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this), - DOM_TOUCH_LISTENER_ADDED, - nsnull); - } } else { mainWidget->UnregisterTouchWindow(); } } void nsGlobalWindow::EnableDeviceMotionUpdates() {
--- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -927,19 +927,19 @@ nsPluginHost::GetPluginTempDir(nsIFile * NS_ENSURE_SUCCESS(rv, rv); tmpDir.swap(sPluginTempDir); } return sPluginTempDir->Clone(aDir); } -nsresult nsPluginHost::InstantiatePluginForChannel(nsIChannel* aChannel, - nsObjectLoadingContent* aContent, - nsIStreamListener** aListener) +nsresult nsPluginHost::CreateListenerForChannel(nsIChannel* aChannel, + nsObjectLoadingContent* aContent, + nsIStreamListener** aListener) { NS_PRECONDITION(aChannel && aContent, "Invalid arguments to InstantiatePluginForChannel"); nsCOMPtr<nsIURI> uri; nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv)) return rv; @@ -1063,17 +1063,17 @@ nsPluginHost::InstantiateEmbeddedPlugin( nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get()); if (handler) bCanHandleInternally = true; } // if we don't have a MIME type at this point, we still have one more chance by // opening the stream and seeing if the server hands one back if (!aMimeType) { - if (bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) { + if (bCanHandleInternally && !aContent->SrcStreamLoading()) { NewEmbeddedPluginStream(aURL, aContent, nsnull); } return NS_ERROR_FAILURE; } rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; @@ -1091,17 +1091,17 @@ nsPluginHost::InstantiateEmbeddedPlugin( // If we've got a native window, the let the plugin know about it. instanceOwner->CallSetWindow(); // create an initial stream with data // don't make the stream if it's a java applet or we don't have SRC or DATA attribute // no need to check for "data" as it would have been converted to "src" const char *value; bool havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value)); - if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) { + if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoading()) { NewEmbeddedPluginStream(aURL, nsnull, instance.get()); } } // At this point we consider instantiation to be successful. Do not return an error. instanceOwner.forget(aOwner); #ifdef PLUGIN_LOGGING
--- a/dom/plugins/base/nsPluginHost.h +++ b/dom/plugins/base/nsPluginHost.h @@ -108,19 +108,19 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIPLUGINHOST NS_DECL_NSIOBSERVER NS_DECL_NSITIMERCALLBACK nsresult Init(); nsresult Destroy(); nsresult LoadPlugins(); - nsresult InstantiatePluginForChannel(nsIChannel* aChannel, - nsObjectLoadingContent* aContent, - nsIStreamListener** aListener); + nsresult CreateListenerForChannel(nsIChannel* aChannel, + nsObjectLoadingContent* aContent, + nsIStreamListener** aListener); nsresult SetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner); nsresult IsPluginEnabledForType(const char* aMimeType); nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType); nsresult GetPluginCount(PRUint32* aPluginCount); nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray);
--- a/dom/src/geolocation/nsGeoPosition.h +++ b/dom/src/geolocation/nsGeoPosition.h @@ -81,28 +81,28 @@ public: //////////////////////////////////////////////////// // nsGeoPositionCoords //////////////////////////////////////////////////// /** * Simple object that holds a single point in space. */ -class nsGeoPositionCoords : public nsIDOMGeoPositionCoords +class nsGeoPositionCoords MOZ_FINAL : public nsIDOMGeoPositionCoords { public: NS_DECL_ISUPPORTS NS_DECL_NSIDOMGEOPOSITIONCOORDS nsGeoPositionCoords(double aLat, double aLong, double aAlt, double aHError, double aVError, double aHeading, double aSpeed); + ~nsGeoPositionCoords(); private: - ~nsGeoPositionCoords(); const double mLat, mLong, mAlt, mHError, mVError, mHeading, mSpeed; }; //////////////////////////////////////////////////// // nsGeoPosition ////////////////////////////////////////////////////
--- a/dom/src/geolocation/nsGeoPositionIPCSerialiser.h +++ b/dom/src/geolocation/nsGeoPositionIPCSerialiser.h @@ -37,17 +37,17 @@ #ifndef dom_src_geolocation_IPC_serialiser #define dom_src_geolocation_IPC_serialiser #include "IPC/IPCMessageUtils.h" #include "nsGeoPosition.h" #include "nsIDOMGeoPosition.h" typedef nsIDOMGeoPositionAddress *GeoPositionAddress; -typedef nsIDOMGeoPositionCoords *GeoPositionCoords; +typedef nsGeoPositionCoords *GeoPositionCoords; typedef nsIDOMGeoPosition *GeoPosition; namespace IPC { template <> struct ParamTraits<GeoPositionAddress> { typedef GeoPositionAddress paramType; @@ -228,17 +228,17 @@ struct ParamTraits<GeoPosition> if (isNull) return; DOMTimeStamp timeStamp; aParam->GetTimestamp(&timeStamp); WriteParam(aMsg, timeStamp); nsCOMPtr<nsIDOMGeoPositionCoords> coords; aParam->GetCoords(getter_AddRefs(coords)); - GeoPositionCoords simpleCoords = coords.get(); + GeoPositionCoords simpleCoords = static_cast<GeoPositionCoords>(coords.get()); WriteParam(aMsg, simpleCoords); nsCOMPtr<nsIDOMGeoPositionAddress> address; aParam->GetAddress(getter_AddRefs(address)); GeoPositionAddress simpleAddress = address.get(); WriteParam(aMsg, simpleAddress); }
--- a/dom/tests/mochitest/bugs/test_resize_move_windows.html +++ b/dom/tests/mochitest/bugs/test_resize_move_windows.html @@ -257,20 +257,22 @@ function checkChangeIsEnabled(aWindow, a }); }); }); }); }); }); } +SpecialPowers.pushPrefEnv({"set": [["dom.disable_window_move_resize", false]]}, function() { SimpleTest.waitForFocus(function() { if (screen.width <= 200 || screen.height <= 200) { - todo(false, "The screen is too small to run this test."); + todo(false, "The screen needs to be bigger than 200px*200px to run this test."); SimpleTest.finish(); + return; } backValues(); // The current window can't change it's own size and position. checkChangeIsDisabled(window, function() { // We create a window and check that it can change its own size and position. // However, passing size/position parameters to window.open should work. @@ -313,13 +315,14 @@ SimpleTest.waitForFocus(function() { }); }); }, w, false); }); }) }, w, false); }); }); +}); // SpecialPowers.pushPrefEnv() </script> </pre> </body> </html>
--- a/editor/txmgr/tests/TestTXMgr.cpp +++ b/editor/txmgr/tests/TestTXMgr.cpp @@ -787,289 +787,267 @@ quick_test(TestTransactionFactory *facto nsresult result; /******************************************************************* * * Create a transaction manager implementation: * *******************************************************************/ - printf("Create transaction manager instance ... "); - nsCOMPtr<nsITransactionManager> mgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result); if (NS_FAILED(result) || !mgr) { printf("ERROR: Failed to create Transaction Manager instance.\n"); return NS_ERROR_OUT_OF_MEMORY; } - printf("passed\n"); + passed("Create transaction manager instance"); /******************************************************************* * * Call DoTransaction() with a null transaction: * *******************************************************************/ - printf("Call DoTransaction() with null transaction ... "); result = mgr->DoTransaction(0); if (result != NS_ERROR_NULL_POINTER) { printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call DoTransaction() with null transaction"); /******************************************************************* * * Call UndoTransaction() with an empty undo stack: * *******************************************************************/ - printf("Call UndoTransaction() with empty undo stack ... "); result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Undo on empty undo stack failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call UndoTransaction() with empty undo stack"); /******************************************************************* * * Call RedoTransaction() with an empty redo stack: * *******************************************************************/ - printf("Call RedoTransaction() with empty redo stack ... "); result = mgr->RedoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Redo on empty redo stack failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call RedoTransaction() with empty redo stack"); /******************************************************************* * * Call SetMaxTransactionCount(-1) with empty undo and redo stacks: * *******************************************************************/ - printf("Call SetMaxTransactionCount(-1) with empty undo and redo stacks ... "); result = mgr->SetMaxTransactionCount(-1); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call SetMaxTransactionCount(-1) with empty undo and redo stacks"); /******************************************************************* * * Call SetMaxTransactionCount(0) with empty undo and redo stacks: * *******************************************************************/ - printf("Call SetMaxTransactionCount(0) with empty undo and redo stacks ... "); result = mgr->SetMaxTransactionCount(0); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call SetMaxTransactionCount(0) with empty undo and redo stacks"); /******************************************************************* * * Call SetMaxTransactionCount(10) with empty undo and redo stacks: * *******************************************************************/ - printf("Call SetMaxTransactionCount(10) with empty undo and redo stacks ... "); result = mgr->SetMaxTransactionCount(10); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(10) failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call SetMaxTransactionCount(10) with empty undo and redo stacks"); /******************************************************************* * * Call Clear() with empty undo and redo stacks: * *******************************************************************/ - printf("Call Clear() with empty undo and redo stack ... "); - result = mgr->Clear(); if (NS_FAILED(result)) { printf("ERROR: Clear on empty undo and redo stack failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call Clear() with empty undo and redo stack"); PRInt32 numitems; /******************************************************************* * * Call GetNumberOfUndoItems() with an empty undo stack: * *******************************************************************/ - printf("Call GetNumberOfUndoItems() with empty undo stack ... "); result = mgr->GetNumberOfUndoItems(&numitems); if (NS_FAILED(result)) { printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n", result); return result; } if (numitems != 0) { printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Call GetNumberOfUndoItems() with empty undo stack"); /******************************************************************* * * Call GetNumberOfRedoItems() with an empty redo stack: * *******************************************************************/ - printf("Call GetNumberOfRedoItems() with empty redo stack ... "); result = mgr->GetNumberOfRedoItems(&numitems); if (NS_FAILED(result)) { printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n", result); return result; } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Call GetNumberOfRedoItems() with empty redo stack"); nsITransaction *tx; /******************************************************************* * * Call PeekUndoStack() with an empty undo stack: * *******************************************************************/ - printf("Call PeekUndoStack() with empty undo stack ... "); - tx = 0; result = mgr->PeekUndoStack(&tx); TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result); return result; } if (tx != 0) { printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Call PeekUndoStack() with empty undo stack"); /******************************************************************* * * Call PeekRedoStack() with an empty undo stack: * *******************************************************************/ - printf("Call PeekRedoStack() with empty undo stack ... "); - tx = 0; result = mgr->PeekRedoStack(&tx); TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result); return result; } if (tx != 0) { printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Call PeekRedoStack() with empty undo stack"); /******************************************************************* * * Call AddListener() with a null listener pointer: * *******************************************************************/ - printf("Call AddListener() with null listener ... "); - result = mgr->AddListener(0); if (result != NS_ERROR_NULL_POINTER) { printf("ERROR: AddListener() returned unexpected error. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call AddListener() with null listener"); /******************************************************************* * * Call RemoveListener() with a null listener pointer: * *******************************************************************/ - printf("Call RemoveListener() with null listener ... "); - result = mgr->RemoveListener(0); if (result != NS_ERROR_NULL_POINTER) { printf("ERROR: RemoveListener() returned unexpected error. (%d)\n", result); return result; } - printf("passed\n"); + passed("Call RemoveListener() with null listener"); PRInt32 i; TestTransaction *tximpl; nsITransaction *u1, *u2; nsITransaction *r1, *r2; /******************************************************************* * * Test coalescing by executing a transaction that can merge any * command into itself. Then execute 20 transaction. Afterwards, * we should still have the first transaction sitting on the undo * stack. Then clear the undo and redo stacks. * *******************************************************************/ - printf("Test coalescing of transactions ... "); - result = mgr->SetMaxTransactionCount(10); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(10) failed. (%d)\n", result); return result; } @@ -1206,27 +1184,25 @@ quick_test(TestTransactionFactory *facto } result = mgr->Clear(); if (NS_FAILED(result)) { printf("ERROR: Clear() failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Test coalescing of transactions"); /******************************************************************* * * Execute 20 transactions. Afterwards, we should have 10 * transactions on the undo stack: * *******************************************************************/ - printf("Execute 20 transactions ... "); - for (i = 1; i <= 20; i++) { tximpl = factory->create(mgr, NONE_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction %d.\n", i); return NS_ERROR_OUT_OF_MEMORY; } @@ -1270,27 +1246,25 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Execute 20 transactions"); /******************************************************************* * * Execute 20 transient transactions. Afterwards, we should still * have the same 10 transactions on the undo stack: * *******************************************************************/ - printf("Execute 20 transient transactions ... "); - u1 = u2 = r1 = r2 = 0; result = mgr->PeekUndoStack(&u1); TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result); @@ -1382,27 +1356,25 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Execute 20 transient transactions"); /******************************************************************* * * Undo 4 transactions. Afterwards, we should have 6 transactions * on the undo stack, and 4 on the redo stack: * *******************************************************************/ - printf("Undo 4 transactions ... "); - for (i = 1; i <= 4; i++) { result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result); return result; } } @@ -1429,27 +1401,25 @@ quick_test(TestTransactionFactory *facto } if (numitems != 4) { printf("ERROR: GetNumberOfRedoItems() expected 4 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Undo 4 transactions"); /******************************************************************* * * Redo 2 transactions. Afterwards, we should have 8 transactions * on the undo stack, and 2 on the redo stack: * *******************************************************************/ - printf("Redo 2 transactions ... "); - for (i = 1; i <= 2; ++i) { result = mgr->RedoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to redo transaction %d. (%d)\n", i, result); return result; } } @@ -1476,26 +1446,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 2) { printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Redo 2 transactions"); /******************************************************************* * * Execute a new transaction. The redo stack should get pruned! * *******************************************************************/ - printf("Check if new transactions prune the redo stack ... "); - tximpl = factory->create(mgr, NONE_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -1538,26 +1506,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Check if new transactions prune the redo stack"); /******************************************************************* * * Undo 4 transactions then clear the undo and redo stacks. * *******************************************************************/ - printf("Undo 4 transactions then clear the undo and redo stacks ... "); - for (i = 1; i <= 4; ++i) { result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result); return result; } } @@ -1619,26 +1585,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Undo 4 transactions then clear the undo and redo stacks"); /******************************************************************* * * Execute 5 transactions. * *******************************************************************/ - printf("Execute 5 transactions ... "); - for (i = 1; i <= 5; i++) { tximpl = factory->create(mgr, NONE_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction %d.\n", i); return NS_ERROR_OUT_OF_MEMORY; } @@ -1682,26 +1646,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Execute 5 transactions"); /******************************************************************* * * Test transaction DoTransaction() error: * *******************************************************************/ - printf("Test transaction DoTransaction() error ... "); - tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -1793,26 +1755,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction DoTransaction() error"); /******************************************************************* * * Test transaction UndoTransaction() error: * *******************************************************************/ - printf("Test transaction UndoTransaction() error ... "); - tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -1911,26 +1871,24 @@ quick_test(TestTransactionFactory *facto } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction UndoTransaction() error"); /******************************************************************* * * Test transaction RedoTransaction() error: * *******************************************************************/ - printf("Test transaction RedoTransaction() error ... "); - tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -2075,28 +2033,26 @@ quick_test(TestTransactionFactory *facto } if (numitems != 2) { printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction RedoTransaction() error"); /******************************************************************* * * Make sure that setting the transaction manager's max transaction * count to zero, clears both the undo and redo stacks, and executes * all new commands without pushing them on the undo stack! * *******************************************************************/ - printf("Test max transaction count of zero ... "); - result = mgr->SetMaxTransactionCount(0); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result); return result; } result = mgr->GetNumberOfUndoItems(&numitems); @@ -2175,28 +2131,26 @@ quick_test(TestTransactionFactory *facto if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } } - printf("passed\n"); + passed("Test max transaction count of zero"); /******************************************************************* * * Make sure that setting the transaction manager's max transaction * count to something greater than the number of transactions on * both the undo and redo stacks causes no pruning of the stacks: * *******************************************************************/ - printf("Test SetMaxTransactionCount() greater than num stack items ... "); - result = mgr->SetMaxTransactionCount(-1); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result); return result; } // Push 20 transactions on the undo stack: @@ -2368,28 +2322,26 @@ quick_test(TestTransactionFactory *facto } if (numitems != 10) { printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test SetMaxTransactionCount() greater than num stack items"); /******************************************************************* * * Test undo stack pruning by setting the transaction * manager's max transaction count to a number lower than the * number of transactions on both the undo and redo stacks: * *******************************************************************/ - printf("Test SetMaxTransactionCount() pruning undo stack ... "); - u1 = u2 = r1 = r2 = 0; result = mgr->PeekUndoStack(&u1); TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result); @@ -2463,28 +2415,26 @@ quick_test(TestTransactionFactory *facto } if (numitems != 10) { printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test SetMaxTransactionCount() pruning undo stack"); /******************************************************************* * * Test redo stack pruning by setting the transaction * manager's max transaction count to a number lower than the * number of transactions on both the undo and redo stacks: * *******************************************************************/ - printf("Test SetMaxTransactionCount() pruning redo stack ... "); - u1 = u2 = r1 = r2 = 0; result = mgr->PeekUndoStack(&u1); TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result); @@ -2558,27 +2508,25 @@ quick_test(TestTransactionFactory *facto } if (numitems != 5) { printf("ERROR: GetNumberOfRedoItems() expected 5 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test SetMaxTransactionCount() pruning redo stack"); /******************************************************************* * * Release the transaction manager. Any transactions on the undo * and redo stack should automatically be released: * *******************************************************************/ - printf("Release the transaction manager ... "); - result = mgr->SetMaxTransactionCount(-1); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result); return result; } // Push 20 transactions on the undo stack: @@ -2673,35 +2621,33 @@ quick_test(TestTransactionFactory *facto } result = mgr->Clear(); if (NS_FAILED(result)) { printf("ERROR: Clear() failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Release the transaction manager"); /******************************************************************* * * Make sure number of transactions created matches number of * transactions destroyed! * *******************************************************************/ - printf("Number of transactions created and destroyed match ... "); - if (sConstructorCount != sDestructorCount) { printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n", sConstructorCount, sDestructorCount); return NS_ERROR_FAILURE; } - printf("passed\n"); - printf("%d transactions processed during quick test.\n", sConstructorCount); + passed("Number of transactions created and destroyed match"); + passed("%d transactions processed during quick test", sConstructorCount); return NS_OK; } nsresult simple_test() { /******************************************************************* @@ -2769,38 +2715,34 @@ quick_batch_test(TestTransactionFactory nsresult result; /******************************************************************* * * Create a transaction manager implementation: * *******************************************************************/ - printf("Create transaction manager instance ... "); - nsCOMPtr<nsITransactionManager> mgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result); if (NS_FAILED(result) || !mgr) { printf("ERROR: Failed to create Transaction Manager instance.\n"); return NS_ERROR_OUT_OF_MEMORY; } - printf("passed\n"); + passed("Create transaction manager instance"); PRInt32 numitems; /******************************************************************* * * Make sure an unbalanced call to EndBatch() with empty undo stack * throws an error! * *******************************************************************/ - printf("Test unbalanced EndBatch() with empty undo stack ... "); - result = mgr->GetNumberOfUndoItems(&numitems); if (NS_FAILED(result)) { printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n", result); return result; } @@ -2826,28 +2768,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); - + passed("Test unbalanced EndBatch() with empty undo stack"); /******************************************************************* * * Make sure that an empty batch is not added to the undo stack * when it is closed. * *******************************************************************/ - printf("Test empty batch ... "); - result = mgr->GetNumberOfUndoItems(&numitems); if (NS_FAILED(result)) { printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n", result); return result; } @@ -2894,31 +2833,29 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test empty batch"); PRInt32 i; TestTransaction *tximpl; nsITransaction *tx; /******************************************************************* * * Execute 20 transactions. Afterwards, we should have 1 * transaction on the undo stack: * *******************************************************************/ - printf("Execute 20 batched transactions ... "); - result = mgr->BeginBatch(); if (NS_FAILED(result)) { printf("ERROR: BeginBatch() failed. (%d)\n", result); return result; } for (i = 1; i <= 20; i++) { @@ -2976,30 +2913,28 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Execute 20 batched transactions"); nsITransaction *u1, *u2; nsITransaction *r1, *r2; /******************************************************************* * * Execute 20 transient transactions. Afterwards, we should still * have the same transaction on the undo stack: * *******************************************************************/ - printf("Execute 20 batched transient transactions ... "); - u1 = u2 = r1 = r2 = 0; result = mgr->PeekUndoStack(&u1); TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references! if (NS_FAILED(result)) { printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result); @@ -3105,27 +3040,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Execute 20 batched transient transactions"); /******************************************************************* * * Test nested batching. Afterwards, we should have 2 transactions * on the undo stack: * *******************************************************************/ - printf("Test nested batched transactions ... "); - result = mgr->BeginBatch(); if (NS_FAILED(result)) { printf("ERROR: BeginBatch() failed. (%d)\n", result); return result; } tximpl = factory->create(mgr, NONE_FLAG); @@ -3280,27 +3213,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 2) { printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test nested batched transactions"); /******************************************************************* * * Undo 2 batch transactions. Afterwards, we should have 0 * transactions on the undo stack and 2 on the redo stack. * *******************************************************************/ - printf("Undo 2 batch transactions ... "); - for (i = 1; i <= 2; ++i) { result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result); return result; } } @@ -3327,28 +3258,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 2) { printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Undo 2 batch transactions"); /******************************************************************* * * Redo 2 batch transactions. Afterwards, we should have 2 * transactions on the undo stack and 0 on the redo stack. * *******************************************************************/ - - printf("Redo 2 batch transactions ... "); - for (i = 1; i <= 2; ++i) { result = mgr->RedoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result); return result; } } @@ -3375,27 +3303,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Redo 2 batch transactions"); /******************************************************************* * * Call undo. Afterwards, we should have 1 transaction * on the undo stack, and 1 on the redo stack: * *******************************************************************/ - printf("Undo a batched transaction that was redone ... "); - result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction. (%d)\n", result); return result; } result = mgr->GetNumberOfUndoItems(&numitems); @@ -3421,27 +3347,25 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Undo a batched transaction that was redone"); /******************************************************************* * * Make sure an unbalanced call to EndBatch() throws an error and * doesn't affect the undo and redo stacks! * *******************************************************************/ - printf("Test effect of unbalanced EndBatch() on undo and redo stacks ... "); - result = mgr->EndBatch(); if (result != NS_ERROR_FAILURE) { printf("ERROR: EndBatch() returned unexpected status. (%d)\n", result); return result; } result = mgr->GetNumberOfUndoItems(&numitems); @@ -3467,28 +3391,26 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test effect of unbalanced EndBatch() on undo and redo stacks"); /******************************************************************* * * Make sure that an empty batch is not added to the undo stack * when it is closed, and that it does not affect the undo and redo * stacks. * *******************************************************************/ - printf("Test effect of empty batch on undo and redo stacks ... "); - result = mgr->BeginBatch(); if (NS_FAILED(result)) { printf("ERROR: BeginBatch() failed. (%d)\n", result); return result; } result = mgr->GetNumberOfUndoItems(&numitems); @@ -3549,28 +3471,24 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - - printf("passed\n"); - + passed("Test effect of empty batch on undo and redo stacks"); /******************************************************************* * * Execute a new transaction. The redo stack should get pruned! * *******************************************************************/ - printf("Check if new batched transactions prune the redo stack ... "); - result = mgr->BeginBatch(); if (NS_FAILED(result)) { printf("ERROR: BeginBatch() failed. (%d)\n", result); return result; } for (i = 1; i <= 20; i++) { @@ -3656,26 +3574,24 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Check if new batched transactions prune the redo stack"); /******************************************************************* * * Call undo. * *******************************************************************/ - printf("Call undo ... "); - // Move a transaction over to the redo stack, so that we have one // transaction on the undo stack, and one on the redo stack! result = mgr->UndoTransaction(); if (NS_FAILED(result)) { printf("ERROR: Failed to undo transaction. (%d)\n", result); return result; @@ -3704,27 +3620,24 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Call undo"); /******************************************************************* * * Test transaction DoTransaction() error: * *******************************************************************/ - printf("Test transaction DoTransaction() error ... "); - - tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -3830,26 +3743,24 @@ quick_batch_test(TestTransactionFactory } if (numitems != 1) { printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction DoTransaction() error"); /******************************************************************* * * Test transaction UndoTransaction() error: * *******************************************************************/ - printf("Test transaction UndoTransaction() error ... "); - tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -3962,26 +3873,24 @@ quick_batch_test(TestTransactionFactory } if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction UndoTransaction() error"); /******************************************************************* * * Test transaction RedoTransaction() error: * *******************************************************************/ - printf("Test transaction RedoTransaction() error ... "); - tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG); if (!tximpl) { printf("ERROR: Failed to allocate transaction.\n"); return NS_ERROR_OUT_OF_MEMORY; } tx = 0; @@ -4140,28 +4049,26 @@ quick_batch_test(TestTransactionFactory } if (numitems != 2) { printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } - printf("passed\n"); + passed("Test transaction RedoTransaction() error"); /******************************************************************* * * Make sure that setting the transaction manager's max transaction * count to zero, clears both the undo and redo stacks, and executes * all new commands without pushing them on the undo stack! * *******************************************************************/ - printf("Test max transaction count of zero ... "); - result = mgr->SetMaxTransactionCount(0); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result); return result; } result = mgr->GetNumberOfUndoItems(&numitems); @@ -4254,27 +4161,25 @@ quick_batch_test(TestTransactionFactory if (numitems != 0) { printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n", numitems, result); return NS_ERROR_FAILURE; } } - printf("passed\n"); + passed("Test max transaction count of zero"); /******************************************************************* * * Release the transaction manager. Any transactions on the undo * and redo stack should automatically be released: * *******************************************************************/ - printf("Release the transaction manager ... "); - result = mgr->SetMaxTransactionCount(-1); if (NS_FAILED(result)) { printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result); return result; } // Push 20 transactions on the undo stack: @@ -4383,35 +4288,33 @@ quick_batch_test(TestTransactionFactory } result = mgr->Clear(); if (NS_FAILED(result)) { printf("ERROR: Clear() failed. (%d)\n", result); return result; } - printf("passed\n"); + passed("Release the transaction manager"); /******************************************************************* * * Make sure number of transactions created matches number of * transactions destroyed! * *******************************************************************/ - printf("Number of transactions created and destroyed match ... "); - if (sConstructorCount != sDestructorCount) { printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n", sConstructorCount, sDestructorCount); return NS_ERROR_FAILURE; } - printf("passed\n"); - printf("%d transactions processed during quick batch test.\n", + passed("Number of transactions created and destroyed match"); + passed("%d transactions processed during quick batch test", sConstructorCount); return NS_OK; } nsresult simple_batch_test() { @@ -4576,31 +4479,31 @@ stress_test(TestTransactionFactory *fact } } // Trivial feedback not to let the user think the test is stuck. if (NS_UNLIKELY(j % 100 == 0)) printf("%i ", j); } // for, iterations. + printf("passed\n"); + result = mgr->Clear(); if (NS_FAILED(result)) { printf("ERROR: Clear() failed. (%d)\n", result); return result; } if (sConstructorCount != sDestructorCount) { printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n", sConstructorCount, sDestructorCount); return NS_ERROR_FAILURE; } - printf("passed\n"); - - printf("%d transactions processed during stress test.\n", sConstructorCount); + passed("%d transactions processed during stress test", sConstructorCount); return NS_OK; } nsresult simple_stress_test() { /*******************************************************************
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp +++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp @@ -80,16 +80,17 @@ #include "nsIDOMNamedNodeMap.h" #include "nsIDOMNodeList.h" #include "nsIWebProgressListener.h" #include "nsIAuthPrompt.h" #include "nsIPrompt.h" #include "nsISHEntry.h" #include "nsIWebPageDescriptor.h" #include "nsIFormControl.h" +#include "nsContentUtils.h" #include "nsIDOMNodeFilter.h" #include "nsIDOMProcessingInstruction.h" #include "nsIDOMHTMLBodyElement.h" #include "nsIDOMHTMLTableElement.h" #include "nsIDOMHTMLTableRowElement.h" #include "nsIDOMHTMLTableCellElement.h" #include "nsIDOMHTMLAnchorElement.h" @@ -2599,108 +2600,54 @@ nsWebBrowserPersist::EnumCleanupUploadLi { channel->Cancel(NS_BINDING_ABORTED); } UploadData *data = (UploadData *) aData; delete data; // Delete data associated with key return true; } - -bool -nsWebBrowserPersist::GetQuotedAttributeValue( - const nsAString &aSource, const nsAString &aAttribute, nsAString &aValue) -{ - // NOTE: This code was lifted verbatim from nsParserUtils.cpp - aValue.Truncate(); - nsAString::const_iterator start, end; - aSource.BeginReading(start); - aSource.EndReading(end); - nsAString::const_iterator iter(end); - - while (start != end) { - if (FindInReadable(aAttribute, start, iter)) - { - // walk past any whitespace - while (iter != end && nsCRT::IsAsciiSpace(*iter)) - { - ++iter; - } - - if (iter == end) - break; - - // valid name="value" pair? - if (*iter != '=') - { - start = iter; - iter = end; - continue; - } - // move past the = - ++iter; - - while (iter != end && nsCRT::IsAsciiSpace(*iter)) - { - ++iter; - } - - if (iter == end) - break; - - PRUnichar q = *iter; - if (q != '"' && q != '\'') - { - start = iter; - iter = end; - continue; - } - - // point to the first char of the value - ++iter; - start = iter; - if (FindCharInReadable(q, iter, end)) - { - aValue = Substring(start, iter); - return true; - } - - // we've run out of string. Just return... - break; - } - } - return false; -} - nsresult nsWebBrowserPersist::FixupXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, const nsAString &aHref) { NS_ENSURE_ARG_POINTER(aPI); nsresult rv = NS_OK; nsAutoString data; rv = aPI->GetData(data); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); nsAutoString href; - GetQuotedAttributeValue(data, NS_LITERAL_STRING("href"), href); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::href, + href); // Construct and set a new data value for the xml-stylesheet if (!aHref.IsEmpty() && !href.IsEmpty()) { nsAutoString alternate; nsAutoString charset; nsAutoString title; nsAutoString type; nsAutoString media; - GetQuotedAttributeValue(data, NS_LITERAL_STRING("alternate"), alternate); - GetQuotedAttributeValue(data, NS_LITERAL_STRING("charset"), charset); - GetQuotedAttributeValue(data, NS_LITERAL_STRING("title"), title); - GetQuotedAttributeValue(data, NS_LITERAL_STRING("type"), type); - GetQuotedAttributeValue(data, NS_LITERAL_STRING("media"), media); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::alternate, + alternate); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::charset, + charset); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::title, + title); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::type, + type); + nsContentUtils::GetPseudoAttributeValue(data, + nsGkAtoms::media, + media); NS_NAMED_LITERAL_STRING(kCloseAttr, "\" "); nsAutoString newData; newData += NS_LITERAL_STRING("href=\"") + aHref + kCloseAttr; if (!title.IsEmpty()) { newData += NS_LITERAL_STRING("title=\"") + title + kCloseAttr; } @@ -2731,17 +2678,17 @@ nsresult nsWebBrowserPersist::GetXMLStyl { NS_ENSURE_ARG_POINTER(aPI); nsresult rv = NS_OK; nsAutoString data; rv = aPI->GetData(data); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); - GetQuotedAttributeValue(data, NS_LITERAL_STRING("href"), aHref); + nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::href, aHref); return NS_OK; } nsresult nsWebBrowserPersist::OnWalkDOMNode(nsIDOMNode *aNode) { // Fixup xml-stylesheet processing instructions nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNode);
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h +++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h @@ -147,18 +147,16 @@ private: URIData **aData = nsnull); nsresult StoreURIAttribute( nsIDOMNode *aNode, const char *aAttribute, bool aNeedsPersisting = true, URIData **aData = nsnull) { return StoreURIAttributeNS(aNode, "", aAttribute, aNeedsPersisting, aData); } - bool GetQuotedAttributeValue( - const nsAString &aSource, const nsAString &aAttribute, nsAString &aValue); bool DocumentEncoderExists(const PRUnichar *aContentType); nsresult GetNodeToFixup(nsIDOMNode *aNodeIn, nsIDOMNode **aNodeOut); nsresult FixupURI(nsAString &aURI); nsresult FixupNodeAttributeNS(nsIDOMNode *aNode, const char *aNamespaceURI, const char *aAttribute); nsresult FixupNodeAttribute(nsIDOMNode *aNode, const char *aAttribute) { return FixupNodeAttributeNS(aNode, "", aAttribute);
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp +++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp @@ -120,19 +120,19 @@ LayerManagerD3D10::~LayerManagerD3D10() delete attachments; } } Destroy(); } bool -LayerManagerD3D10::Initialize() +LayerManagerD3D10::Initialize(bool force) { - ScopedGfxFeatureReporter reporter("D3D10 Layers"); + ScopedGfxFeatureReporter reporter("D3D10 Layers", force); HRESULT hr; /* Create an Nv3DVUtils instance */ if (!mNv3DVUtils) { mNv3DVUtils = new Nv3DVUtils(); if (!mNv3DVUtils) { NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
--- a/gfx/layers/d3d10/LayerManagerD3D10.h +++ b/gfx/layers/d3d10/LayerManagerD3D10.h @@ -95,17 +95,17 @@ public: /* * Initializes the layer manager, this is when the layer manager will * actually access the device and attempt to create the swap chain used * to draw to the window. If this method fails the device cannot be used. * This function is not threadsafe. * * \return True is initialization was succesful, false when it was not. */ - bool Initialize(); + bool Initialize(bool force = false); /* * LayerManager implementation. */ virtual void Destroy(); virtual ShadowLayerForwarder* AsShadowForwarder() { return this; }
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp +++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp @@ -65,19 +65,19 @@ LayerManagerD3D9::LayerManagerD3D9(nsIWi } LayerManagerD3D9::~LayerManagerD3D9() { Destroy(); } bool -LayerManagerD3D9::Initialize() +LayerManagerD3D9::Initialize(bool force) { - ScopedGfxFeatureReporter reporter("D3D9 Layers"); + ScopedGfxFeatureReporter reporter("D3D9 Layers", force); /* XXX: this preference and blacklist code should move out of the layer manager */ bool forceAccelerate = Preferences::GetBool("layers.acceleration.force-enabled", false); nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); if (gfxInfo) { PRInt32 status;
--- a/gfx/layers/d3d9/LayerManagerD3D9.h +++ b/gfx/layers/d3d9/LayerManagerD3D9.h @@ -98,17 +98,17 @@ public: /* * Initializes the layer manager, this is when the layer manager will * actually access the device and attempt to create the swap chain used * to draw to the window. If this method fails the device cannot be used. * This function is not threadsafe. * * \return True is initialization was succesful, false when it was not. */ - bool Initialize(); + bool Initialize(bool force = false); /* * Sets the clipping region for this layer manager. This is important on * windows because using OGL we no longer have GDI's native clipping. Therefor * widget must tell us what part of the screen is being invalidated, * and we should clip to this. * * \param aClippingRegion Region to clip to. Setting an empty region
--- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -172,19 +172,19 @@ LayerManagerOGL::CreateContext() if (!context) { NS_WARNING("Failed to create LayerManagerOGL context"); } return context.forget(); } bool -LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext) +LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext, bool force) { - ScopedGfxFeatureReporter reporter("GL Layers"); + ScopedGfxFeatureReporter reporter("GL Layers", force); // Do not allow double intiailization NS_ABORT_IF_FALSE(mGLContext == nsnull, "Don't reiniailize layer managers"); if (!aContext) return false; mGLContext = aContext;
--- a/gfx/layers/opengl/LayerManagerOGL.h +++ b/gfx/layers/opengl/LayerManagerOGL.h @@ -101,21 +101,21 @@ public: /** * Initializes the layer manager with a given GLContext. If aContext is null * then the layer manager will try to create one for the associated widget. * * \param aContext an existing GL context to use. Can be created with CreateContext() * * \return True is initialization was succesful, false when it was not. */ - bool Initialize() { - return Initialize(CreateContext()); + bool Initialize(bool force = false) { + return Initialize(CreateContext(), force); } - bool Initialize(nsRefPtr<GLContext> aContext); + bool Initialize(nsRefPtr<GLContext> aContext, bool force = false); /** * Sets the clipping region for this layer manager. This is important on * windows because using OGL we no longer have GDI's native clipping. Therefor * widget must tell us what part of the screen is being invalidated, * and we should clip to this. * * \param aClippingRegion Region to clip to. Setting an empty region
--- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -98,20 +98,19 @@ ScopedGfxFeatureReporter::WriteAppNote(c if (NS_FAILED(rv)) { observer = nsnull; return; } gFeaturesAlreadyReported = new nsTArray<nsCString>; } nsCAutoString featureString; - featureString.AppendPrintf("%s%c%c", + featureString.AppendPrintf("%s%c ", mFeature, - statusChar, - statusChar == '?' ? ' ' : '\n'); + statusChar); if (!gFeaturesAlreadyReported->Contains(featureString)) { gFeaturesAlreadyReported->AppendElement(featureString); CrashReporter::AppendAppNotesToCrashReport(featureString); } } } // end namespace mozilla
--- a/gfx/src/gfxCrashReporterUtils.h +++ b/gfx/src/gfxCrashReporterUtils.h @@ -48,19 +48,20 @@ namespace mozilla { * * This ScopedGfxFeatureReporter class is designed to be fool-proof to use in functions that * have many exit points. We don't want to encourage having function with many exit points. * It just happens that our graphics features initialization functions are like that. */ class NS_GFX ScopedGfxFeatureReporter { public: - ScopedGfxFeatureReporter(const char *aFeature) : mFeature(aFeature), mStatusChar('-') + ScopedGfxFeatureReporter(const char *aFeature, bool force = false) + : mFeature(aFeature), mStatusChar('-') { - WriteAppNote('?'); + WriteAppNote(force ? '!' : '?'); } ~ScopedGfxFeatureReporter() { WriteAppNote(mStatusChar); } void SetSuccessful() { mStatusChar = '+'; } protected: const char *mFeature;
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -496,17 +496,17 @@ gfxWindowsPlatform::VerifyD2DDevice(bool ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice); if (SUCCEEDED(device->GetDeviceRemovedReason())) { return; } mD2DDevice = nsnull; } - mozilla::ScopedGfxFeatureReporter reporter("D2D"); + mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce); HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func) GetProcAddress(d3d10module, "D3D10CreateDevice1"); nsRefPtr<ID3D10Device1> device; if (createD3DDevice) { HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
--- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -123,16 +123,17 @@ struct RuntimeStats DestroyNameCallback destroyNameCb) : runtimeObject(0) , runtimeAtomsTable(0) , runtimeContexts(0) , runtimeNormal(0) , runtimeTemporary(0) , runtimeRegexpCode(0) , runtimeStackCommitted(0) + , runtimeGCMarker(0) , gcHeapChunkTotal(0) , gcHeapChunkCleanUnused(0) , gcHeapChunkDirtyUnused(0) , gcHeapChunkCleanDecommitted(0) , gcHeapChunkDirtyDecommitted(0) , gcHeapArenaUnused(0) , gcHeapChunkAdmin(0) , gcHeapUnusedPercentage(0) @@ -154,16 +155,17 @@ struct RuntimeStats size_t runtimeObject; size_t runtimeAtomsTable; size_t runtimeContexts; size_t runtimeNormal; size_t runtimeTemporary; size_t runtimeRegexpCode; size_t runtimeStackCommitted; + size_t runtimeGCMarker; size_t gcHeapChunkTotal; size_t gcHeapChunkCleanUnused; size_t gcHeapChunkDirtyUnused; size_t gcHeapChunkCleanDecommitted; size_t gcHeapChunkDirtyDecommitted; size_t gcHeapArenaUnused; size_t gcHeapChunkAdmin; size_t gcHeapUnusedPercentage;
--- a/js/public/Vector.h +++ b/js/public/Vector.h @@ -494,16 +494,27 @@ class Vector : private AllocPolicy */ bool insert(T *p, const T &val); /* * Removes the element |t|, which must fall in the bounds [begin, end), * shifting existing elements from |t + 1| onward one position lower. */ void erase(T *t); + + /* + * Measure the size of the Vector's heap-allocated storage. + */ + size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const; + + /* + * Like sizeOfExcludingThis, but also measures the size of the Vector + * object (which must be heap-allocated) itself. + */ + size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const; }; /* This does the re-entrancy check plus several other sanity checks. */ #define REENTRANCY_GUARD_ET_AL \ ReentrancyGuard g(*this); \ JS_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \ JS_ASSERT(reserved() <= mCapacity); \ JS_ASSERT(mLength <= reserved()); \ @@ -991,15 +1002,29 @@ Vector<T,N,AP>::replaceRawBuffer(T *p, s mLength = length; mCapacity = length; } #ifdef DEBUG mReserved = length; #endif } +template <class T, size_t N, class AP> +inline size_t +Vector<T,N,AP>::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const +{ + return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck()); +} + +template <class T, size_t N, class AP> +inline size_t +Vector<T,N,AP>::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const +{ + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); +} + } /* namespace js */ #ifdef _MSC_VER #pragma warning(pop) #endif #endif /* jsvector_h_ */
--- a/js/src/MemoryMetrics.cpp +++ b/js/src/MemoryMetrics.cpp @@ -206,20 +206,19 @@ CollectRuntimeStats(JSRuntime *rt, Runti IterateChunks(cx, rtStats, StatsChunkCallback); rtStats->runtimeObject = rtStats->mallocSizeOf(rt); rt->sizeOfExcludingThis(rtStats->mallocSizeOf, &rtStats->runtimeNormal, &rtStats->runtimeTemporary, &rtStats->runtimeRegexpCode, - &rtStats->runtimeStackCommitted); + &rtStats->runtimeStackCommitted, + &rtStats->runtimeGCMarker); - // Nb: we use sizeOfExcludingThis() because atomState.atoms is within - // JSRuntime, and so counted when JSRuntime is counted. rtStats->runtimeAtomsTable = rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf); JSContext *acx, *iter = NULL; while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf); } @@ -330,17 +329,18 @@ GetExplicitNonHeapForRuntime(JSRuntime * // explicit/runtime/regexp-code // explicit/runtime/stack-committed size_t regexpCode, stackCommitted; rt->sizeOfExcludingThis(mallocSizeOf, NULL, NULL, ®expCode, - &stackCommitted); + &stackCommitted, + NULL); *amount += regexpCode; *amount += stackCommitted; } JS_DestroyContextNoGC(cx); return true;
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -238,16 +238,18 @@ UpdateDecomposeLength(BytecodeEmitter *b uintN end = bce->offset(); JS_ASSERT(uintN(end - start) < 256); bce->code(start)[-1] = end - start; } ptrdiff_t frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op) { + JS_ASSERT_IF(op == JSOP_ARGUMENTS, !bce->mayOverwriteArguments()); + ptrdiff_t offset = EmitCheck(cx, bce, 1); if (offset >= 0) { *bce->current->next++ = (jsbytecode)op; UpdateDepth(cx, bce, offset); } return offset; } @@ -978,16 +980,24 @@ EmitSlotObjectOp(JSContext *cx, JSOp op, jsbytecode *pc = bce->code(off); SET_SLOTNO(pc, slot); pc += SLOTNO_LEN; SET_UINT32_INDEX(pc, index); return true; } +static bool +EmitArguments(JSContext *cx, BytecodeEmitter *bce) +{ + if (!bce->mayOverwriteArguments()) + return Emit1(cx, bce, JSOP_ARGUMENTS) >= 0; + return EmitAtomOp(cx, cx->runtime->atomState.argumentsAtom, JSOP_NAME, bce); +} + bool BytecodeEmitter::shouldNoteClosedName(ParseNode *pn) { return !callsEval() && pn->isDefn() && pn->isClosed(); } /* * Adjust the slot for a block local to account for the number of variables @@ -1828,17 +1838,20 @@ EmitNameOp(JSContext *cx, BytecodeEmitte op = JSOP_CALLFCSLOT; break; default: JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE); break; } } - if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) { + if (op == JSOP_ARGUMENTS) { + if (!EmitArguments(cx, bce)) + return JS_FALSE; + } else if (op == JSOP_CALLEE) { if (Emit1(cx, bce, op) < 0) return JS_FALSE; } else { if (!pn->pn_cookie.isFree()) { JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM); EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger()); } else { if (!EmitAtomOp(cx, pn, op, bce)) @@ -3584,17 +3597,17 @@ EmitVariables(JSContext *cx, BytecodeEmi (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 (Emit1(cx, bce, op) < 0) + if (!EmitArguments(cx, bce)) return JS_FALSE; } else if (!pn2->pn_cookie.isFree()) { EMIT_UINT16_IMM_OP(op, atomIndex); } else { if (!EmitIndexOp(cx, op, atomIndex, bce)) return false; } @@ -3695,17 +3708,17 @@ EmitAssignment(JSContext *cx, BytecodeEm if (op != JSOP_NOP) { JS_ASSERT(rhs); switch (lhs->getKind()) { case PNK_NAME: if (lhs->isConst()) { if (lhs->isOp(JSOP_CALLEE)) { if (Emit1(cx, bce, JSOP_CALLEE) < 0) return false; - } else if (lhs->isOp(JSOP_NAME)) { + } else if (lhs->isOp(JSOP_NAME) || lhs->isOp(JSOP_GETGNAME)) { if (!EmitIndex32(cx, lhs->getOp(), atomIndex, bce)) return false; } else { JS_ASSERT(JOF_OPTYPE(lhs->getOp()) != JOF_ATOM); EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex); } } else if (lhs->isOp(JSOP_SETNAME)) { if (Emit1(cx, bce, JSOP_DUP) < 0)
--- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -163,31 +163,30 @@ struct StmtInfo { #define TCF_COMPILING 0x01 /* TreeContext is BytecodeEmitter */ #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;' */ #define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */ #define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */ #define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */ -#define TCF_FUN_USES_ARGUMENTS 0x80 /* function uses arguments except as a +#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function has local named arguments */ +#define TCF_FUN_USES_ARGUMENTS 0x100 /* function uses arguments except as a parameter name */ -#define TCF_FUN_HEAVYWEIGHT 0x100 /* function needs Call object per call */ -#define TCF_FUN_IS_GENERATOR 0x200 /* parsed yield statement in function */ -#define TCF_FUN_USES_OWN_NAME 0x400 /* named function expression that uses its +#define TCF_FUN_HEAVYWEIGHT 0x200 /* function needs Call object per call */ +#define TCF_FUN_IS_GENERATOR 0x400 /* parsed yield statement in function */ +#define TCF_FUN_USES_OWN_NAME 0x800 /* named function expression that uses its own name */ -#define TCF_HAS_FUNCTION_STMT 0x800 /* block contains a function statement */ -#define TCF_GENEXP_LAMBDA 0x1000 /* flag lambda from generator expression */ -#define TCF_COMPILE_N_GO 0x2000 /* compile-and-go mode of script, can +#define TCF_HAS_FUNCTION_STMT 0x1000 /* block contains a function statement */ +#define TCF_GENEXP_LAMBDA 0x2000 /* flag lambda from generator expression */ +#define TCF_COMPILE_N_GO 0x4000 /* compile-and-go mode of script, can optimize name references based on scope chain */ -#define TCF_NO_SCRIPT_RVAL 0x4000 /* API caller does not want result value +#define TCF_NO_SCRIPT_RVAL 0x8000 /* API caller does not want result value from global script */ -/* bit 0x8000 is unused */ - /* * Set when parsing a declaration-like destructuring pattern. This * flag causes PrimaryExpr to create PN_NAME parse nodes for variable * references which are not hooked into any definition's use chain, * added to any tree context's AtomList, etc. etc. CheckDestructuring * will do that work later. * * The comments atop CheckDestructuring explain the distinction @@ -268,16 +267,17 @@ struct StmtInfo { #define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) /* * Sticky deoptimization flags to propagate from FunctionBody. */ #define TCF_FUN_FLAGS (TCF_FUN_SETS_OUTER_NAME | \ TCF_FUN_USES_ARGUMENTS | \ TCF_FUN_PARAM_ARGUMENTS | \ + TCF_FUN_LOCAL_ARGUMENTS | \ TCF_FUN_HEAVYWEIGHT | \ TCF_FUN_IS_GENERATOR | \ TCF_FUN_USES_OWN_NAME | \ TCF_FUN_CALLS_EVAL | \ TCF_FUN_MIGHT_ALIAS_LOCALS | \ TCF_FUN_MUTATES_PARAMETER | \ TCF_STRICT_MODE_CODE | \ TCF_FUN_EXTENSIBLE_SCOPE) @@ -429,16 +429,25 @@ struct TreeContext { /* t flags |= TCF_FUN_MUTATES_PARAMETER; } bool mutatesParameter() const { JS_ASSERT(inFunction()); return flags & TCF_FUN_MUTATES_PARAMETER; } + bool mayOverwriteArguments() const { + JS_ASSERT(inFunction()); + JS_ASSERT_IF(inStrictMode(), + !(flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS))); + return !inStrictMode() && + (callsEval() || + flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS)); + } + void noteArgumentsNameUse(ParseNode *node) { JS_ASSERT(inFunction()); JS_ASSERT(node->isKind(PNK_NAME)); JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom); countArgumentsUse(node); flags |= TCF_FUN_USES_ARGUMENTS; if (funbox) funbox->node->pn_dflags |= PND_FUNARG;
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2426,17 +2426,17 @@ NoteLValue(JSContext *cx, ParseNode *pn, * depending on code strictness. Assignment to arguments is a syntax error * in strict mode and thus cannot happen. Outside strict mode, we optimize * away assignment to the function name. For assignment to function name * to fail in strict mode, we must have a binding for it in the scope * chain; we ensure this happens by making such functions heavyweight. */ JSAtom *lname = pn->pn_atom; if (lname == cx->runtime->atomState.argumentsAtom) { - tc->flags |= TCF_FUN_HEAVYWEIGHT; + tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS); tc->countArgumentsUse(pn); } else if (tc->inFunction() && lname == tc->fun()->atom) { tc->flags |= TCF_FUN_HEAVYWEIGHT; } } #if JS_HAS_DESTRUCTURING @@ -2448,17 +2448,17 @@ BindDestructuringVar(JSContext *cx, Bind /* * Destructuring is a form of assignment, so just as for an initialized * simple variable, we must check for assignment to 'arguments' and flag * the enclosing function (if any) as heavyweight. */ JS_ASSERT(pn->isKind(PNK_NAME)); atom = pn->pn_atom; if (atom == cx->runtime->atomState.argumentsAtom) - tc->flags |= TCF_FUN_HEAVYWEIGHT; + tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS); data->pn = pn; if (!data->binder(cx, data, atom, tc)) return JS_FALSE; /* * Select the appropriate name-setting opcode, respecting eager selection * done by the data->binder function. @@ -4419,17 +4419,17 @@ Parser::variables(ParseNodeKind kind, St NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED); /* The declarator's position must include the initializer. */ pn2->pn_pos.end = init->pn_pos.end; if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) { tc->noteArgumentsNameUse(pn2); if (!blockObj) - tc->flags |= TCF_FUN_HEAVYWEIGHT; + tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS); } } } while (tokenStream.matchToken(TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; }
--- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -173,18 +173,18 @@ TokenStream::init(const jschar *base, si version = v; xml = VersionHasXML(v); userbuf.init(base, length); linebase = base; prevLinebase = NULL; sourceMap = NULL; - JSSourceHandler listener = cx->debugHooks->sourceHandler; - void *listenerData = cx->debugHooks->sourceHandlerData; + JSSourceHandler listener = cx->runtime->debugHooks.sourceHandler; + void *listenerData = cx->runtime->debugHooks.sourceHandlerData; if (listener) listener(fn, ln, base, length, &listenerTSData, listenerData); /* * This table holds all the token kinds that satisfy these properties: * - A single char long. * - Cannot be a prefix of any longer token (eg. '+' is excluded because @@ -516,18 +516,18 @@ TokenStream::reportCompileErrorNumberVA( * uncaught exception report. */ if (!js_ErrorToException(cx, message, &report, NULL, NULL)) { /* * If debugErrorHook is present then we give it a chance to veto * sending the error on to the regular error reporter. */ bool reportError = true; - if (JSDebugErrorHook hook = cx->debugHooks->debugErrorHook) - reportError = hook(cx, message, &report, cx->debugHooks->debugErrorHookData); + if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) + reportError = hook(cx, message, &report, cx->runtime->debugHooks.debugErrorHookData); /* Report the error */ if (reportError && cx->errorReporter) cx->errorReporter(cx, message, &report); } out: if (linebytes)
--- a/js/src/gc/Barrier-inl.h +++ b/js/src/gc/Barrier-inl.h @@ -41,58 +41,69 @@ #include "gc/Barrier.h" #ifndef jsgc_barrier_inl_h___ #define jsgc_barrier_inl_h___ namespace js { -static JS_ALWAYS_INLINE void -ClearValueRange(JSCompartment *comp, HeapValue *vec, uintN len, bool useHoles) +inline void +EncapsulatedValue::writeBarrierPre(const Value &value) { - if (useHoles) { - for (uintN i = 0; i < len; i++) - vec[i].set(comp, MagicValue(JS_ARRAY_HOLE)); - } else { - for (uintN i = 0; i < len; i++) - vec[i].set(comp, UndefinedValue()); +#ifdef JSGC_INCREMENTAL + if (value.isMarkable()) { + js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing(); + writeBarrierPre(cell->compartment(), value); } +#endif } -static JS_ALWAYS_INLINE void -InitValueRange(HeapValue *vec, uintN len, bool useHoles) +inline void +EncapsulatedValue::writeBarrierPre(JSCompartment *comp, const Value &value) { - if (useHoles) { - for (uintN i = 0; i < len; i++) - vec[i].init(MagicValue(JS_ARRAY_HOLE)); - } else { - for (uintN i = 0; i < len; i++) - vec[i].init(UndefinedValue()); +#ifdef JSGC_INCREMENTAL + if (comp->needsBarrier()) { + Value tmp(value); + js::gc::MarkValueUnbarriered(comp->barrierTracer(), &tmp, "write barrier"); + JS_ASSERT(tmp == value); } +#endif } -static JS_ALWAYS_INLINE void -DestroyValueRange(HeapValue *vec, uintN len) +inline void +EncapsulatedValue::pre() +{ + writeBarrierPre(value); +} + +inline void +EncapsulatedValue::pre(JSCompartment *comp) { - for (uintN i = 0; i < len; i++) - vec[i].~HeapValue(); + writeBarrierPre(comp, value); +} + +inline +HeapValue::HeapValue() + : EncapsulatedValue(UndefinedValue()) +{ + post(); } inline HeapValue::HeapValue(const Value &v) - : value(v) + : EncapsulatedValue(v) { JS_ASSERT(!IsPoisonedValue(v)); post(); } inline HeapValue::HeapValue(const HeapValue &v) - : value(v.value) + : EncapsulatedValue(v.value) { JS_ASSERT(!IsPoisonedValue(v.value)); post(); } inline HeapValue::~HeapValue() { @@ -109,71 +120,16 @@ HeapValue::init(const Value &v) inline void HeapValue::init(JSCompartment *comp, const Value &v) { value = v; post(comp); } -inline void -HeapValue::writeBarrierPre(const Value &value) -{ -#ifdef JSGC_INCREMENTAL - if (value.isMarkable()) { - js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing(); - writeBarrierPre(cell->compartment(), value); - } -#endif -} - -inline void -HeapValue::writeBarrierPost(const Value &value, void *addr) -{ -} - -inline void -HeapValue::writeBarrierPre(JSCompartment *comp, const Value &value) -{ -#ifdef JSGC_INCREMENTAL - if (comp->needsBarrier()) { - Value tmp(value); - js::gc::MarkValueUnbarriered(comp->barrierTracer(), &tmp, "write barrier"); - JS_ASSERT(tmp == value); - } -#endif -} - -inline void -HeapValue::writeBarrierPost(JSCompartment *comp, const Value &value, void *addr) -{ -} - -inline void -HeapValue::pre() -{ - writeBarrierPre(value); -} - -inline void -HeapValue::post() -{ -} - -inline void -HeapValue::pre(JSCompartment *comp) -{ - writeBarrierPre(comp, value); -} - -inline void -HeapValue::post(JSCompartment *comp) -{ -} - inline HeapValue & HeapValue::operator=(const Value &v) { pre(); JS_ASSERT(!IsPoisonedValue(v)); value = v; post(); return *this; @@ -201,16 +157,119 @@ HeapValue::set(JSCompartment *comp, cons #endif pre(comp); JS_ASSERT(!IsPoisonedValue(v)); value = v; post(comp); } +inline void +HeapValue::writeBarrierPost(const Value &value, void *addr) +{ +} + +inline void +HeapValue::writeBarrierPost(JSCompartment *comp, const Value &value, void *addr) +{ +} + +inline void +HeapValue::post() +{ +} + +inline void +HeapValue::post(JSCompartment *comp) +{ +} + +inline +HeapSlot::HeapSlot(JSObject *obj, uint32_t slot, const Value &v) + : EncapsulatedValue(v) +{ + JS_ASSERT(!IsPoisonedValue(v)); + post(obj, slot); +} + +inline +HeapSlot::HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &s) + : EncapsulatedValue(s.value) +{ + JS_ASSERT(!IsPoisonedValue(s.value)); + post(obj, slot); +} + +inline +HeapSlot::~HeapSlot() +{ + pre(); +} + +inline void +HeapSlot::init(JSObject *obj, uint32_t slot, const Value &v) +{ + value = v; + post(obj, slot); +} + +inline void +HeapSlot::init(JSCompartment *comp, JSObject *obj, uint32_t slot, const Value &v) +{ + value = v; + post(comp, obj, slot); +} + +inline void +HeapSlot::set(JSObject *obj, uint32_t slot, const Value &v) +{ + JS_ASSERT_IF(!obj->isArray(), &obj->getSlotRef(slot) == this); + JS_ASSERT_IF(obj->isDenseArray(), &obj->getDenseArrayElement(slot) == (const Value *)this); + + pre(); + JS_ASSERT(!IsPoisonedValue(v)); + value = v; + post(obj, slot); +} + +inline void +HeapSlot::set(JSCompartment *comp, JSObject *obj, uint32_t slot, const Value &v) +{ + JS_ASSERT_IF(!obj->isArray(), &const_cast<JSObject *>(obj)->getSlotRef(slot) == this); + JS_ASSERT_IF(obj->isDenseArray(), &obj->getDenseArrayElement(slot) == (const Value *)this); + JS_ASSERT(obj->compartment() == comp); + + pre(comp); + JS_ASSERT(!IsPoisonedValue(v)); + value = v; + post(comp, obj, slot); +} + +inline void +HeapSlot::writeBarrierPost(JSObject *obj, uint32_t slot) +{ +} + +inline void +HeapSlot::writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slotno) +{ +} + +inline void +HeapSlot::post(JSObject *owner, uint32_t slot) +{ + HeapSlot::writeBarrierPost(owner, slot); +} + +inline void +HeapSlot::post(JSCompartment *comp, JSObject *owner, uint32_t slot) +{ + HeapSlot::writeBarrierPost(comp, owner, slot); +} + inline HeapId::HeapId(jsid id) : value(id) { JS_ASSERT(!IsPoisonedId(id)); post(); }
--- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -294,41 +294,34 @@ struct HeapPtrHasher static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); } static bool match(const Key &k, Lookup l) { return k.get() == l; } }; /* Specialized hashing policy for HeapPtrs. */ template <class T> struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { }; -class HeapValue +class EncapsulatedValue { + protected: Value value; + /* + * Ensure that EncapsulatedValue is not constructable, except by our + * implementations. + */ + EncapsulatedValue() MOZ_DELETE; + EncapsulatedValue(const EncapsulatedValue &v) MOZ_DELETE; + EncapsulatedValue &operator=(const Value &v) MOZ_DELETE; + EncapsulatedValue &operator=(const EncapsulatedValue &v) MOZ_DELETE; + + EncapsulatedValue(const Value &v) : value(v) {} + ~EncapsulatedValue() {} + public: - explicit HeapValue() : value(UndefinedValue()) {} - explicit inline HeapValue(const Value &v); - explicit inline HeapValue(const HeapValue &v); - - inline ~HeapValue(); - - inline void init(const Value &v); - inline void init(JSCompartment *comp, const Value &v); - - inline HeapValue &operator=(const Value &v); - inline HeapValue &operator=(const HeapValue &v); - - /* - * This is a faster version of operator=. Normally, operator= has to - * determine the compartment of the value before it can decide whether to do - * the barrier. If you already know the compartment, it's faster to pass it - * in. - */ - inline void set(JSCompartment *comp, const Value &v); - const Value &get() const { return value; } Value *unsafeGet() { return &value; } operator const Value &() const { return value; } bool isUndefined() const { return value.isUndefined(); } bool isNull() const { return value.isNull(); } bool isBoolean() const { return value.isBoolean(); } bool isTrue() const { return value.isTrue(); } @@ -355,48 +348,103 @@ class HeapValue uint64_t asRawBits() const { return value.asRawBits(); } #ifdef DEBUG JSWhyMagic whyMagic() const { return value.whyMagic(); } #endif static inline void writeBarrierPre(const Value &v); - static inline void writeBarrierPost(const Value &v, void *addr); + static inline void writeBarrierPre(JSCompartment *comp, const Value &v); + + protected: + inline void pre(); + inline void pre(JSCompartment *comp); +}; + +class HeapValue : public EncapsulatedValue +{ + public: + explicit inline HeapValue(); + explicit inline HeapValue(const Value &v); + explicit inline HeapValue(const HeapValue &v); + inline ~HeapValue(); - static inline void writeBarrierPre(JSCompartment *comp, const Value &v); + inline void init(const Value &v); + inline void init(JSCompartment *comp, const Value &v); + + inline HeapValue &operator=(const Value &v); + inline HeapValue &operator=(const HeapValue &v); + + /* + * This is a faster version of operator=. Normally, operator= has to + * determine the compartment of the value before it can decide whether to do + * the barrier. If you already know the compartment, it's faster to pass it + * in. + */ + inline void set(JSCompartment *comp, const Value &v); + + static inline void writeBarrierPost(const Value &v, void *addr); static inline void writeBarrierPost(JSCompartment *comp, const Value &v, void *addr); private: - inline void pre(); inline void post(); + inline void post(JSCompartment *comp); +}; + +class HeapSlot : public EncapsulatedValue +{ + /* + * Operator= is not valid for HeapSlot because is must take the object and + * slot offset to provide to the post/generational barrier. + */ + inline HeapSlot &operator=(const Value &v) MOZ_DELETE; + inline HeapSlot &operator=(const HeapValue &v) MOZ_DELETE; + inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE; - inline void pre(JSCompartment *comp); - inline void post(JSCompartment *comp); + public: + explicit inline HeapSlot() MOZ_DELETE; + explicit inline HeapSlot(JSObject *obj, uint32_t slot, const Value &v); + explicit inline HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &v); + inline ~HeapSlot(); + + inline void init(JSObject *owner, uint32_t slot, const Value &v); + inline void init(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v); + + inline void set(JSObject *owner, uint32_t slot, const Value &v); + inline void set(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v); + + static inline void writeBarrierPost(JSObject *obj, uint32_t slot); + static inline void writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slotno); + + private: + inline void post(JSObject *owner, uint32_t slot); + inline void post(JSCompartment *comp, JSObject *owner, uint32_t slot); }; static inline const Value * -Valueify(const HeapValue *array) +Valueify(const EncapsulatedValue *array) { - JS_ASSERT(sizeof(HeapValue) == sizeof(Value)); + JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value)); + JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value)); return (const Value *)array; } -class HeapValueArray +class HeapSlotArray { - HeapValue *array; + HeapSlot *array; public: - HeapValueArray(HeapValue *array) : array(array) {} + HeapSlotArray(HeapSlot *array) : array(array) {} operator const Value *() const { return Valueify(array); } - operator HeapValue *() const { return array; } + operator HeapSlot *() const { return array; } - HeapValueArray operator +(int offset) const { return HeapValueArray(array + offset); } - HeapValueArray operator +(uint32_t offset) const { return HeapValueArray(array + offset); } + HeapSlotArray operator +(int offset) const { return HeapSlotArray(array + offset); } + HeapSlotArray operator +(uint32_t offset) const { return HeapSlotArray(array + offset); } }; class HeapId { jsid value; public: explicit HeapId() : value(JSID_VOID) {}
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/basic/testOverwrittenArgumentsWithUndefined.js @@ -0,0 +1,24 @@ +function f() { + var a = arguments; + eval("assertEq(arguments[0], 42)"); + eval("assertEq(arguments, a)"); + arguments = undefined; + eval("assertEq(arguments, undefined)"); + arguments = a; + eval("assertEq(arguments[0], 42)"); + eval("assertEq(arguments, a)"); +} +f(42); + +function f(z) { + var a = arguments; + eval("assertEq(arguments[0], 42)"); + eval("assertEq(arguments, a)"); + arguments = undefined; + eval("assertEq(arguments, undefined)"); + z = 17; + eval("assertEq(a[0], 17)"); + a[0] = 'ponies'; + eval("assertEq(z, 'ponies')"); +} +f(42);
--- a/js/src/jsapi-tests/testDebugger.cpp +++ b/js/src/jsapi-tests/testDebugger.cpp @@ -105,45 +105,43 @@ BEGIN_TEST(testDebugger_getThisStrict) } END_TEST(testDebugger_getThisStrict) bool called = false; static JSTrapStatus ThrowHook(JSContext *cx, JSScript *, jsbytecode *, jsval *rval, void *closure) { + JS_ASSERT(!closure); called = true; JSObject *global = JS_GetGlobalForScopeChain(cx); char text[] = "new Error()"; jsval _; JS_EvaluateScript(cx, global, text, strlen(text), "", 0, &_); return JSTRAP_CONTINUE; } BEGIN_TEST(testDebugger_throwHook) { uint32_t newopts = JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS; uint32_t oldopts = JS_SetOptions(cx, newopts); - JSDebugHooks hooks = { 0 }; - hooks.throwHook = ThrowHook; - JSDebugHooks *old = JS_SetContextDebugHooks(cx, &hooks); + CHECK(JS_SetThrowHook(rt, ThrowHook, NULL)); EXEC("function foo() { throw 3 };\n" "for (var i = 0; i < 10; ++i) { \n" " var x = <tag></tag>;\n" " try {\n" " foo(); \n" " } catch(e) {}\n" "}\n"); CHECK(called); - - JS_SetContextDebugHooks(cx, old); + CHECK(JS_SetThrowHook(rt, NULL, NULL)); JS_SetOptions(cx, oldopts); return true; } END_TEST(testDebugger_throwHook) BEGIN_TEST(testDebugger_debuggerObjectVsDebugMode) { CHECK(JS_DefineDebuggerObject(cx, global));
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -795,17 +795,17 @@ JSRuntime::JSRuntime() #endif inOOMReport(0), jitHardening(false) { /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&contextList); JS_INIT_CLIST(&debuggerList); - PodZero(&globalDebugHooks); + PodZero(&debugHooks); PodZero(&atomState); #if JS_STACK_GROWTH_DIRECTION > 0 nativeStackLimit = UINTPTR_MAX; #endif } bool
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1189,17 +1189,17 @@ array_deleteSpecial(JSContext *cx, JSObj } static void array_trace(JSTracer *trc, JSObject *obj) { JS_ASSERT(obj->isDenseArray()); uint32_t initLength = obj->getDenseArrayInitializedLength(); - MarkValueRange(trc, initLength, obj->getDenseArrayElements(), "element"); + MarkSlotRange(trc, initLength, obj->getDenseArrayElements(), "element"); } static JSBool array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props) { JS_ASSERT(obj->isDenseArray()); /* @@ -1372,29 +1372,30 @@ JSObject::makeDenseArraySlow(JSContext * gc::AllocKind kind = getAllocKind(); Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, getProto(), oldShape->getObjectParent(), kind); if (!shape) return false; this->shape_ = shape; /* Take ownership of the dense elements, reset to an empty dense array. */ - HeapValue *elems = elements; + HeapSlot *elems = elements; elements = emptyObjectElements; /* Root all values in the array during conversion. */ AutoValueArray autoArray(cx, (Value *) elems, arrayInitialized); /* * Begin with the length property to share more of the property tree. * The getter/setter here will directly access the object's private value. */ if (!AddLengthProperty(cx, this)) { this->shape_ = oldShape; - cx->free_(getElementsHeader()); + if (elements != emptyObjectElements) + cx->free_(getElementsHeader()); elements = elems; return false; } /* * Create new properties pointing to existing elements. Pack the array to * remove holes, so that shapes use successive slots (as for other objects). */
--- a/js/src/jsarrayinlines.h +++ b/js/src/jsarrayinlines.h @@ -59,17 +59,22 @@ JSObject::ensureDenseArrayInitializedLen * for a write. */ JS_ASSERT(index + extra <= getDenseArrayCapacity()); uint32_t &initlen = getElementsHeader()->initializedLength; if (initlen < index) markDenseArrayNotPacked(cx); if (initlen < index + extra) { - js::InitValueRange(elements + initlen, index + extra - initlen, true); + JSCompartment *comp = compartment(); + size_t offset = initlen; + for (js::HeapSlot *sp = elements + initlen; + sp != elements + (index + extra); + sp++, offset++) + sp->init(comp, this, offset, js::MagicValue(JS_ARRAY_HOLE)); initlen = index + extra; } } inline JSObject::EnsureDenseResult JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra) { JS_ASSERT(isDenseArray());
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -90,17 +90,17 @@ #include "jscompartment.h" #include "jsobjinlines.h" using namespace js; using namespace js::gc; void JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary, - size_t *regexpCode, size_t *stackCommitted) + size_t *regexpCode, size_t *stackCommitted, size_t *gcMarkerSize) { if (normal) *normal = mallocSizeOf(dtoaState); if (temporary) *temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf); if (regexpCode) { @@ -108,16 +108,19 @@ JSRuntime::sizeOfExcludingThis(JSMallocS if (execAlloc_) execAlloc_->sizeOfCode(&method, ®exp, &unused); JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */ *regexpCode = regexp + unused; } if (stackCommitted) *stackCommitted = stackSpace.sizeOfCommitted(); + + if (gcMarkerSize) + *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf); } JS_FRIEND_API(void) JSRuntime::triggerOperationCallback() { /* * Use JS_ATOMIC_SET in the hope that it ensures the write will become * immediately visible to other processors polling the flag. @@ -351,21 +354,19 @@ ReportError(JSContext *cx, const char *m * If an exception was raised, then we call the debugErrorHook * (if present) to give it a chance to see the error before it * propagates out of scope. This is needed for compatibility * with the old scheme. */ if (!JS_IsRunning(cx) || !js_ErrorToException(cx, message, reportp, callback, userRef)) { js_ReportErrorAgain(cx, message, reportp); - } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) { - JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; - /* test local in case debugErrorHook changed on another thread */ - if (hook) - hook(cx, message, reportp, cx->debugHooks->debugErrorHookData); + } else if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) { + if (cx->errorReporter) + hook(cx, message, reportp, cx->runtime->debugHooks.debugErrorHookData); } } /* * The given JSErrorReport object have been zeroed and must not outlive * cx->fp() (otherwise report->originPrincipals may become invalid). */ static void @@ -414,19 +415,19 @@ js_ReportOutOfMemory(JSContext *cx) /* * If debugErrorHook is present then we give it a chance to veto sending * the error on to the regular ErrorReporter. We also clear a pending * exception if any now so the hooks can replace the out-of-memory error * by a script-catchable exception. */ cx->clearPendingException(); if (onError) { - JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook; if (hook && - !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) { + !hook(cx, msg, &report, cx->runtime->debugHooks.debugErrorHookData)) { onError = NULL; } } if (onError) { AutoAtomicIncrement incr(&cx->runtime->inOOMReport); onError(cx, msg, &report); } @@ -746,22 +747,19 @@ js_ReportErrorAgain(JSContext *cx, const return; onError = cx->errorReporter; /* * If debugErrorHook is present then we give it a chance to veto * sending the error on to the regular ErrorReporter. */ if (onError) { - JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; - if (hook && - !hook(cx, cx->lastMessage, reportp, - cx->debugHooks->debugErrorHookData)) { + JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook; + if (hook && !hook(cx, cx->lastMessage, reportp, cx->runtime->debugHooks.debugErrorHookData)) onError = NULL; - } } if (onError) onError(cx, cx->lastMessage, reportp); } void js_ReportIsNotDefined(JSContext *cx, const char *name) { @@ -976,17 +974,16 @@ JSContext::JSContext(JSRuntime *rt) errorReporter(NULL), operationCallback(NULL), data(NULL), data2(NULL), #ifdef JS_THREADSAFE outstandingRequests(0), #endif autoGCRooters(NULL), - debugHooks(&rt->globalDebugHooks), securityCallbacks(NULL), resolveFlags(0), rngSeed(0), iterValue(MagicValue(JS_NO_ITER_VALUE)), #ifdef JS_METHODJIT methodJitEnabled(false), #endif inferenceEnabled(false),
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -470,17 +470,17 @@ struct JSRuntime : js::RuntimeFriendFiel /* List of active contexts sharing this runtime. */ JSCList contextList; bool hasContexts() const { return !JS_CLIST_IS_EMPTY(&contextList); } /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */ - JSDebugHooks globalDebugHooks; + JSDebugHooks debugHooks; /* If true, new compartments are initially in debug mode. */ bool debugMode; /* If true, new scripts must be created with PC counter information. */ bool profilingScripts; /* Had an out-of-memory error which did not populate an exception. */ @@ -684,17 +684,17 @@ struct JSRuntime : js::RuntimeFriendFiel JS_FRIEND_API(void) triggerOperationCallback(); void setJitHardening(bool enabled); bool getJitHardening() const { return jitHardening; } void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary, - size_t *regexpCode, size_t *stackCommitted); + size_t *regexpCode, size_t *stackCommitted, size_t *gcMarker); void purge(JSContext *cx); }; /* Common macros to access thread-local caches in JSRuntime. */ #define JS_PROPERTY_CACHE(cx) (cx->runtime->propertyCache) #define JS_KEEP_ATOMS(rt) (rt)->gcKeepAtoms++; @@ -709,18 +709,16 @@ struct JSRuntime : js::RuntimeFriendFiel struct JSArgumentFormatMap { const char *format; size_t length; JSArgumentFormatter formatter; JSArgumentFormatMap *next; }; #endif -extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ - namespace js { template <typename T> class Root; class CheckRoot; struct AutoResolving; static inline bool @@ -1010,19 +1008,16 @@ struct JSContext : js::ContextFriendFiel * location as holding a relocatable pointer, but have no other effect on * GC behavior. */ js::CheckRoot *checkGCRooters; #endif #endif /* JSGC_ROOT_ANALYSIS */ - /* Debug hooks associated with the current context. */ - const JSDebugHooks *debugHooks; - /* Security callbacks that override any defined on the runtime. */ JSSecurityCallbacks *securityCallbacks; /* Stored here to avoid passing it around as a parameter. */ uintN resolveFlags; /* Random number generator state, used by jsmath.cpp. */ int64_t rngSeed;
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -108,21 +108,21 @@ JS_SetRuntimeDebugMode(JSRuntime *rt, JS namespace js { JSTrapStatus ScriptDebugPrologue(JSContext *cx, StackFrame *fp) { JS_ASSERT(fp == cx->fp()); if (fp->isFramePushedByExecute()) { - if (JSInterpreterHook hook = cx->debugHooks->executeHook) - fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->executeHookData)); + if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook) + fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.executeHookData)); } else { - if (JSInterpreterHook hook = cx->debugHooks->callHook) - fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->callHookData)); + if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook) + fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.callHookData)); } Value rval; JSTrapStatus status = Debugger::onEnterFrame(cx, &rval); switch (status) { case JSTRAP_CONTINUE: break; case JSTRAP_THROW: @@ -143,20 +143,20 @@ ScriptDebugPrologue(JSContext *cx, Stack bool ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool okArg) { JS_ASSERT(fp == cx->fp()); JSBool ok = okArg; if (void *hookData = fp->maybeHookData()) { if (fp->isFramePushedByExecute()) { - if (JSInterpreterHook hook = cx->debugHooks->executeHook) + if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook) hook(cx, Jsvalify(fp), false, &ok, hookData); } else { - if (JSInterpreterHook hook = cx->debugHooks->callHook) + if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook) hook(cx, Jsvalify(fp), false, &ok, hookData); } } Debugger::onLeaveFrame(cx); return ok; } @@ -233,30 +233,30 @@ JS_PUBLIC_API(void) JS_ClearAllTrapsForCompartment(JSContext *cx) { cx->compartment->clearTraps(cx); } JS_PUBLIC_API(JSBool) JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure) { - rt->globalDebugHooks.interruptHook = hook; - rt->globalDebugHooks.interruptHookData = closure; + rt->debugHooks.interruptHook = hook; + rt->debugHooks.interruptHookData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep) { if (hoop) - *hoop = rt->globalDebugHooks.interruptHook; + *hoop = rt->debugHooks.interruptHook; if (closurep) - *closurep = rt->globalDebugHooks.interruptHookData; - rt->globalDebugHooks.interruptHook = 0; - rt->globalDebugHooks.interruptHookData = 0; + *closurep = rt->debugHooks.interruptHookData; + rt->debugHooks.interruptHook = 0; + rt->debugHooks.interruptHookData = 0; return JS_TRUE; } /************************************************************************/ JS_PUBLIC_API(JSBool) JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler handler, JSObject *closure) @@ -584,17 +584,17 @@ JS_GetFrameCallObject(JSContext *cx, JSS if (!ac.enter()) return NULL; /* * XXX ill-defined: null return here means error was reported, unlike a * null returned above or in the #else */ if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame()) - return CreateFunCallObject(cx, fp); + return CallObject::createForFunction(cx, fp); return &fp->callObj(); } JS_PUBLIC_API(JSBool) JS_GetFrameThis(JSContext *cx, JSStackFrame *fpArg, jsval *thisv) { StackFrame *fp = Valueify(fpArg); if (fp->isDummyFrame()) @@ -723,26 +723,26 @@ JS_GetScriptVersion(JSContext *cx, JSScr return VersionNumber(script->getVersion()); } /***************************************************************************/ JS_PUBLIC_API(void) JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) { - rt->globalDebugHooks.newScriptHook = hook; - rt->globalDebugHooks.newScriptHookData = callerdata; + rt->debugHooks.newScriptHook = hook; + rt->debugHooks.newScriptHookData = callerdata; } JS_PUBLIC_API(void) JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, void *callerdata) { - rt->globalDebugHooks.destroyScriptHook = hook; - rt->globalDebugHooks.destroyScriptHookData = callerdata; + rt->debugHooks.destroyScriptHook = hook; + rt->debugHooks.destroyScriptHookData = callerdata; } /***************************************************************************/ JS_PUBLIC_API(JSBool) JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg, const jschar *chars, uintN length, const char *filename, uintN lineno, @@ -839,20 +839,20 @@ JS_GetPropertyDesc(JSContext *cx, JSObje if (wasThrowing) cx->setPendingException(lastException); pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0) | (!shape->writable() ? JSPD_READONLY : 0) | (!shape->configurable() ? JSPD_PERMANENT : 0); pd->spare = 0; - if (shape->getter() == GetCallArg) { + if (shape->getter() == CallObject::getArgOp) { pd->slot = shape->shortid(); pd->flags |= JSPD_ARGUMENT; - } else if (shape->getter() == GetCallVar) { + } else if (shape->getter() == CallObject::getVarOp) { pd->slot = shape->shortid(); pd->flags |= JSPD_VARIABLE; } else { pd->slot = 0; } pd->alias = JSVAL_VOID; return JS_TRUE; @@ -923,58 +923,58 @@ JS_PutPropertyDescArray(JSContext *cx, J cx->free_(pd); } /************************************************************************/ JS_PUBLIC_API(JSBool) JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure) { - rt->globalDebugHooks.debuggerHandler = handler; - rt->globalDebugHooks.debuggerHandlerData = closure; + rt->debugHooks.debuggerHandler = handler; + rt->debugHooks.debuggerHandlerData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure) { - rt->globalDebugHooks.sourceHandler = handler; - rt->globalDebugHooks.sourceHandlerData = closure; + rt->debugHooks.sourceHandler = handler; + rt->debugHooks.sourceHandlerData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) { - rt->globalDebugHooks.executeHook = hook; - rt->globalDebugHooks.executeHookData = closure; + rt->debugHooks.executeHook = hook; + rt->debugHooks.executeHookData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) { - rt->globalDebugHooks.callHook = hook; - rt->globalDebugHooks.callHookData = closure; + rt->debugHooks.callHook = hook; + rt->debugHooks.callHookData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure) { - rt->globalDebugHooks.throwHook = hook; - rt->globalDebugHooks.throwHookData = closure; + rt->debugHooks.throwHook = hook; + rt->debugHooks.throwHookData = closure; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure) { - rt->globalDebugHooks.debugErrorHook = hook; - rt->globalDebugHooks.debugErrorHookData = closure; + rt->debugHooks.debugErrorHook = hook; + rt->debugHooks.debugErrorHookData = closure; return JS_TRUE; } /************************************************************************/ JS_PUBLIC_API(size_t) JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) { @@ -1081,35 +1081,17 @@ JS_FRIEND_API(void) js_RevertVersion(JSContext *cx) { cx->clearVersionOverride(); } JS_PUBLIC_API(const JSDebugHooks *) JS_GetGlobalDebugHooks(JSRuntime *rt) { - return &rt->globalDebugHooks; -} - -const JSDebugHooks js_NullDebugHooks = {}; - -JS_PUBLIC_API(JSDebugHooks *) -JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks) -{ - JS_ASSERT(hooks); - - JSDebugHooks *old = const_cast<JSDebugHooks *>(cx->debugHooks); - cx->debugHooks = hooks; - return old; -} - -JS_PUBLIC_API(JSDebugHooks *) -JS_ClearContextDebugHooks(JSContext *cx) -{ - return JS_SetContextDebugHooks(cx, &js_NullDebugHooks); + return &rt->debugHooks; } /************************************************************************/ /* Profiling-related API */ /* Thread-unsafe error management */
--- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -472,23 +472,16 @@ JS_MakeSystemObject(JSContext *cx, JSObj /************************************************************************/ extern JS_FRIEND_API(void) js_RevertVersion(JSContext *cx); extern JS_PUBLIC_API(const JSDebugHooks *) JS_GetGlobalDebugHooks(JSRuntime *rt); -extern JS_PUBLIC_API(JSDebugHooks *) -JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks); - -/* Disable debug hooks for this context. */ -extern JS_PUBLIC_API(JSDebugHooks *) -JS_ClearContextDebugHooks(JSContext *cx); - /** * Start any profilers that are available and have been configured on for this * platform. This is NOT thread safe. * * The profileName is used by some profilers to describe the current profiling * run. It may be used for part of the filename of the output, but the * specifics depend on the profiler. Many profilers will ignore it. Passing in * NULL is legal; some profilers may use it to output to stdout or similar.
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -586,27 +586,27 @@ VersionSetXML(JSVersion version, bool en { return enable ? JSVersion(uint32_t(version) | VersionFlags::HAS_XML) : JSVersion(uint32_t(version) & ~VersionFlags::HAS_XML); } JS_FRIEND_API(bool) CanCallContextDebugHandler(JSContext *cx) { - return cx->debugHooks && cx->debugHooks->debuggerHandler; + return !!cx->runtime->debugHooks.debuggerHandler; } JS_FRIEND_API(JSTrapStatus) CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval) { - if (!CanCallContextDebugHandler(cx)) + if (!cx->runtime->debugHooks.debuggerHandler) return JSTRAP_RETURN; - return cx->debugHooks->debuggerHandler(cx, script, bc, rval, - cx->debugHooks->debuggerHandlerData); + return cx->runtime->debugHooks.debuggerHandler(cx, script, bc, rval, + cx->runtime->debugHooks.debuggerHandlerData); } #ifdef JS_THREADSAFE void * GetOwnerThread(const JSContext *cx) { return cx->runtime->ownerThread(); }
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -96,31 +96,16 @@ #include "vm/ScopeObject-inl.h" #include "vm/Stack-inl.h" using namespace mozilla; using namespace js; using namespace js::gc; using namespace js::types; -JSBool -js_GetArgsValue(JSContext *cx, StackFrame *fp, Value *vp) -{ - JSObject *argsobj; - if (fp->hasOverriddenArgs()) { - JS_ASSERT(fp->hasCallObj()); - return fp->callObj().getProperty(cx, cx->runtime->atomState.argumentsAtom, vp); - } - argsobj = js_GetArgsObject(cx, fp); - if (!argsobj) - return JS_FALSE; - vp->setObject(*argsobj); - return JS_TRUE; -} - js::ArgumentsObject * ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee) { JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX); JSObject *proto = callee.global().getOrCreateObjectPrototype(cx); if (!proto) return NULL; @@ -143,17 +128,18 @@ ArgumentsObject::create(JSContext *cx, u return NULL; ArgumentsData *data = (ArgumentsData *) cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value)); if (!data) return NULL; data->callee.init(ObjectValue(callee)); - InitValueRange(data->slots, argc, false); + for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++) + vp->init(UndefinedValue()); /* We have everything needed to fill in the object, so make the object. */ JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL); if (!obj) return NULL; ArgumentsObject &argsobj = obj->asArguments(); @@ -177,17 +163,17 @@ struct STATIC_SKIP_INFERENCE PutArg JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined()); if (!dst->isMagic(JS_ARGS_HOLE)) dst->set(compartment, *src); ++dst; return true; } }; -JSObject * +ArgumentsObject * js_GetArgsObject(JSContext *cx, StackFrame *fp) { /* * Arguments and Call objects are owned by the enclosing non-eval function * frame, thus any eval frames must be skipped before testing hasArgsObj. */ JS_ASSERT(fp->isFunctionFrame()); while (fp->isEvalInFunction()) @@ -608,360 +594,16 @@ Class js::StrictArgumentsObjectClass = { NULL, /* outerObject */ NULL, /* innerObject */ JS_ElementIteratorStub, NULL, /* unused */ false, /* isWrappedNative */ } }; -namespace js { - -CallObject * -CreateFunCallObject(JSContext *cx, StackFrame *fp) -{ - JS_ASSERT(fp->isNonEvalFunctionFrame()); - JS_ASSERT(!fp->hasCallObj()); - - JSObject *scopeChain = &fp->scopeChain(); - JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(), - scopeChain->getPrivate() != fp); - - /* - * For a named function expression Call's parent points to an environment - * object holding function's name. - */ - if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) { - scopeChain = DeclEnvObject::create(cx, fp); - if (!scopeChain) - return NULL; - - if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName), - ObjectValue(fp->callee()), NULL, NULL, - JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) { - return NULL; - } - } - - CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee()); - if (!callobj) - return NULL; - - callobj->setStackFrame(fp); - fp->setScopeChainWithOwnCallObj(*callobj); - return callobj; -} - -CallObject * -CreateEvalCallObject(JSContext *cx, StackFrame *fp) -{ - CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL); - if (!callobj) - return NULL; - - callobj->setStackFrame(fp); - fp->setScopeChainWithOwnCallObj(*callobj); - return callobj; -} - -} // namespace js - -void -js_PutCallObject(StackFrame *fp) -{ - CallObject &callobj = fp->callObj().asCall(); - JS_ASSERT(callobj.maybeStackFrame() == fp); - JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame()); - JS_ASSERT(fp->isEvalFrame() == callobj.isForEval()); - - /* Get the arguments object to snapshot fp's actual argument values. */ - if (fp->hasArgsObj()) { - if (!fp->hasOverriddenArgs()) - callobj.initArguments(ObjectValue(fp->argsObj())); - js_PutArgsObject(fp); - } - - JSScript *script = fp->script(); - Bindings &bindings = script->bindings; - - if (callobj.isForEval()) { - JS_ASSERT(script->strictModeCode); - JS_ASSERT(bindings.countArgs() == 0); - - /* This could be optimized as below, but keep it simple for now. */ - callobj.copyValues(0, NULL, bindings.countVars(), fp->slots()); - } else { - JSFunction *fun = fp->fun(); - JS_ASSERT(script == callobj.getCalleeFunction()->script()); - JS_ASSERT(script == fun->script()); - - uintN n = bindings.countArgsAndVars(); - if (n > 0) { - uint32_t nvars = bindings.countVars(); - uint32_t nargs = bindings.countArgs(); - JS_ASSERT(fun->nargs == nargs); - JS_ASSERT(nvars + nargs == n); - - JSScript *script = fun->script(); - if (script->usesEval -#ifdef JS_METHODJIT - || script->debugMode -#endif - ) { - callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots()); - } else { - /* - * For each arg & var that is closed over, copy it from the stack - * into the call object. We use initArg/VarUnchecked because, - * when you call a getter on a call object, js_NativeGetInline - * caches the return value in the slot, so we can't assert that - * it's undefined. - */ - uint32_t nclosed = script->nClosedArgs; - for (uint32_t i = 0; i < nclosed; i++) { - uint32_t e = script->getClosedArg(i); -#ifdef JS_GC_ZEAL - callobj.setArg(e, fp->formalArg(e)); -#else - callobj.initArgUnchecked(e, fp->formalArg(e)); -#endif - } - - nclosed = script->nClosedVars; - for (uint32_t i = 0; i < nclosed; i++) { - uint32_t e = script->getClosedVar(i); -#ifdef JS_GC_ZEAL - callobj.setVar(e, fp->slots()[e]); -#else - callobj.initVarUnchecked(e, fp->slots()[e]); -#endif - } - } - - /* - * Update the args and vars for the active call if this is an outer - * function in a script nesting. - */ - types::TypeScriptNesting *nesting = script->nesting(); - if (nesting && script->isOuterFunction) { - nesting->argArray = callobj.argArray(); - nesting->varArray = callobj.varArray(); - } - } - - /* Clear private pointers to fp, which is about to go away. */ - if (js_IsNamedLambda(fun)) { - JSObject &env = callobj.enclosingScope(); - JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp); - env.setPrivate(NULL); - } - } - - callobj.setStackFrame(NULL); -} - -namespace js { - -static JSBool -GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - - StackFrame *fp = callobj.maybeStackFrame(); - if (fp && !fp->hasOverriddenArgs()) { - JSObject *argsobj = js_GetArgsObject(cx, fp); - if (!argsobj) - return false; - vp->setObject(*argsobj); - } else { - *vp = callobj.getArguments(); - } - return true; -} - -static JSBool -SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) -{ - CallObject &callobj = obj->asCall(); - - if (StackFrame *fp = callobj.maybeStackFrame()) - fp->setOverriddenArgs(); - callobj.setArguments(*vp); - return true; -} - -JSBool -GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - if (StackFrame *fp = callobj.maybeStackFrame()) - *vp = fp->formalArg(i); - else - *vp = callobj.arg(i); - return true; -} - -JSBool -SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) -{ - CallObject &callobj = obj->asCall(); - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - if (StackFrame *fp = callobj.maybeStackFrame()) - fp->formalArg(i) = *vp; - else - callobj.setArg(i, *vp); - - JSFunction *fun = callobj.getCalleeFunction(); - JSScript *script = fun->script(); - if (!script->ensureHasTypes(cx)) - return false; - - TypeScript::SetArgument(cx, script, i, *vp); - - return true; -} - -JSBool -GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - *vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i); - return true; -} - -JSBool -SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) -{ - CallObject &callobj = obj->asCall(); - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp); - return true; -} - -JSBool -GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp) -{ - CallObject &callobj = obj->asCall(); - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - if (StackFrame *fp = callobj.maybeStackFrame()) - *vp = fp->varSlot(i); - else - *vp = callobj.var(i); - return true; -} - -JSBool -SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) -{ - CallObject &callobj = obj->asCall(); - - JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); - uintN i = (uint16_t) JSID_TO_INT(id); - - if (StackFrame *fp = callobj.maybeStackFrame()) - fp->varSlot(i) = *vp; - else - callobj.setVar(i, *vp); - - JSFunction *fun = callobj.getCalleeFunction(); - JSScript *script = fun->script(); - if (!script->ensureHasTypes(cx)) - return false; - - TypeScript::SetLocal(cx, script, i, *vp); - - return true; -} - -} // namespace js - -static JSBool -call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) -{ - JS_ASSERT(!obj->getProto()); - - if (!JSID_IS_ATOM(id)) - return true; - - JSObject *callee = obj->asCall().getCallee(); -#ifdef DEBUG - if (callee) { - JSScript *script = callee->toFunction()->script(); - JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id))); - } -#endif - - /* - * Resolve arguments so that we never store a particular Call object's - * arguments object reference in a Call prototype's |arguments| slot. - * - * Include JSPROP_ENUMERATE for consistency with all other Call object - * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN - * rebinding-Call-property logic. - */ - if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) { - if (!DefineNativeProperty(cx, obj, id, UndefinedValue(), - GetCallArguments, SetCallArguments, - JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE, - 0, 0, DNP_DONT_PURGE)) { - return false; - } - *objp = obj; - return true; - } - - /* Control flow reaches here only if id was not resolved. */ - return true; -} - -static void -call_trace(JSTracer *trc, JSObject *obj) -{ - JS_ASSERT(obj->isCall()); - - /* Mark any generator frame, as for arguments objects. */ -#if JS_HAS_GENERATORS - StackFrame *fp = (StackFrame *) obj->getPrivate(); - if (fp && fp->isFloatingGenerator()) - MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object"); -#endif -} - -JS_PUBLIC_DATA(Class) js::CallClass = { - "Call", - JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | - JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) | - JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS, - JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - (JSResolveOp)call_resolve, - NULL, /* convert: Leave it NULL so we notice if calls ever escape */ - NULL, /* finalize */ - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* construct */ - NULL, /* hasInstance */ - call_trace -}; - bool StackFrame::getValidCalleeObject(JSContext *cx, Value *vp) { if (!isFunctionFrame()) { vp->setNull(); return true; }
--- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -357,40 +357,16 @@ js_ValueToCallableObject(JSContext *cx, extern void js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, uintN flags); extern void js_PutCallObject(js::StackFrame *fp); namespace js { -CallObject * -CreateFunCallObject(JSContext *cx, StackFrame *fp); - -CallObject * -CreateEvalCallObject(JSContext *cx, StackFrame *fp); - -extern JSBool -GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); - -extern JSBool -GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); - -extern JSBool -GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); - -extern JSBool -SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); - -extern JSBool -SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); - -extern JSBool -SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); - /* * Function extended with reserved slots for use by various kinds of functions. * Most functions do not have these extensions, but enough are that efficient * storage is required (no malloc'ed reserved slots). */ class FunctionExtended : public JSFunction { friend struct JSFunction; @@ -410,30 +386,27 @@ JSFunction::toExtended() inline const js::FunctionExtended * JSFunction::toExtended() const { JS_ASSERT(isExtended()); return static_cast<const js::FunctionExtended *>(this); } -extern JSBool -js_GetArgsValue(JSContext *cx, js::StackFrame *fp, js::Value *vp); - /* * Get the arguments object for the given frame. If the frame is strict mode * code, its current arguments will be copied into the arguments object. * * NB: Callers *must* get the arguments object before any parameters are * mutated when the frame is strict mode code! The emitter ensures this * occurs for strict mode functions containing syntax which might mutate a * named parameter by synthesizing an arguments access at the start of the * function. */ -extern JSObject * +extern js::ArgumentsObject * js_GetArgsObject(JSContext *cx, js::StackFrame *fp); extern void js_PutArgsObject(js::StackFrame *fp); inline bool js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2113,16 +2113,23 @@ GCMarker::appendGrayRoot(void *thing, JS void GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) { GCMarker *gcmarker = static_cast<GCMarker *>(trc); gcmarker->appendGrayRoot(*thingp, kind); } +size_t +GCMarker::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const +{ + return stack.sizeOfExcludingThis(mallocSizeOf) + + grayRoots.sizeOfExcludingThis(mallocSizeOf); +} + void SetMarkStackLimit(JSRuntime *rt, size_t limit) { JS_ASSERT(!rt->gcRunning); rt->gcMarker.setSizeLimit(limit); for (CompartmentsIter c(rt); !c.done(); c.next()) c->barrierMarker_.setSizeLimit(limit); } @@ -3073,37 +3080,45 @@ ValidateIncrementalMarking(JSContext *cx typedef HashMap<Chunk *, uintptr_t *, GCChunkHasher, SystemAllocPolicy> BitmapMap; BitmapMap map; if (!map.init()) return; JSRuntime *rt = cx->runtime; FullGCMarker *gcmarker = &rt->gcMarker; - /* Save existing mark bits */ + /* Save existing mark bits. */ for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { ChunkBitmap *bitmap = &r.front()->bitmap; uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap)); if (!entry) return; memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap)); if (!map.putNew(r.front(), entry)) return; } + /* Save the existing weakmaps. */ + WeakMapVector weakmaps; + if (!WeakMapBase::saveWeakMapList(rt, weakmaps)) + return; + /* * After this point, the function should run to completion, so we shouldn't * do anything fallible. */ /* Re-do all the marking, but non-incrementally. */ js::gc::State state = rt->gcIncrementalState; rt->gcIncrementalState = NO_INCREMENTAL; + /* As we're re-doing marking, we need to reset the weak map list. */ + WeakMapBase::resetWeakMapList(rt); + JS_ASSERT(gcmarker->isDrained()); gcmarker->reset(); for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); MarkRuntime(gcmarker, true); SliceBudget budget; @@ -3141,16 +3156,20 @@ ValidateIncrementalMarking(JSContext *cx JS_ASSERT_IF(bitmap->isMarked(cell, BLACK), incBitmap.isMarked(cell, BLACK)); thing += Arena::thingSize(kind); } } memcpy(bitmap->bitmap, incBitmap.bitmap, sizeof(incBitmap.bitmap)); } + /* Restore the weak map list. */ + WeakMapBase::resetWeakMapList(rt); + WeakMapBase::restoreWeakMapList(rt, weakmaps); + rt->gcIncrementalState = state; } #endif static void SweepPhase(JSContext *cx, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime;
--- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1685,16 +1685,24 @@ struct MarkStack { if (!newStack) return false; } stack = newStack; tos = stack + tosIndex; limit = newStack + newcap; return true; } + + size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const { + size_t n = 0; + if (stack != ballast) + n += mallocSizeOf(stack); + n += mallocSizeOf(ballast); + return n; + } }; /* * This class records how much work has been done in a given GC slice, so that * we can return before pausing for too long. Some slices are allowed to run for * unlimited time, and others are bounded. To reduce the number of gettimeofday * calls, we only check the time every 1000 operations. */ @@ -1822,16 +1830,18 @@ struct GCMarker : public JSTracer { */ bool hasBufferedGrayRoots() const; void startBufferingGrayRoots(); void endBufferingGrayRoots(); void markBufferedGrayRoots(); static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind); + size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const; + MarkStack<uintptr_t> stack; private: #ifdef DEBUG void checkCompartment(void *p); #else void checkCompartment(void *p) {} #endif
--- a/js/src/jsgcmark.cpp +++ b/js/src/jsgcmark.cpp @@ -351,16 +351,51 @@ MarkValueRootRange(JSTracer *trc, size_t { JS_ROOT_MARKING_ASSERT(trc); for (size_t i = 0; i < len; ++i) { JS_SET_TRACING_INDEX(trc, name, i); MarkValueInternal(trc, &vec[i]); } } +/*** Slot Marking ***/ + +void +MarkSlot(JSTracer *trc, HeapSlot *s, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkValueInternal(trc, s->unsafeGet()); +} + +void +MarkSlotRange(JSTracer *trc, size_t len, HeapSlot *vec, const char *name) +{ + for (size_t i = 0; i < len; ++i) { + JS_SET_TRACING_INDEX(trc, name, i); + MarkValueInternal(trc, vec[i].unsafeGet()); + } +} + +void +MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name) +{ + if (s->isMarkable()) { + Cell *cell = (Cell *)s->toGCThing(); + JSRuntime *rt = trc->runtime; + if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment) + return; + + /* In case we're called from a write barrier. */ + if (rt->gcIncrementalCompartment && cell->compartment() != rt->gcIncrementalCompartment) + return; + + MarkSlot(trc, s, name); + } +} + /*** Special Marking ***/ /* * The unioned HeapPtr stored in script->globalObj needs special treatment to * typecheck correctly. */ static void MarkObject(JSTracer *trc, const HeapPtr<GlobalObject, JSScript *> &thing, const char *name) @@ -371,33 +406,16 @@ MarkObject(JSTracer *trc, const HeapPtr< void MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name) { JS_SET_TRACING_NAME(trc, name); MarkValueInternal(trc, v); } -void -MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name) -{ - if (v->isMarkable()) { - Cell *cell = (Cell *)v->toGCThing(); - JSRuntime *rt = trc->runtime; - if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment) - return; - - /* In case we're called from a write barrier. */ - if (rt->gcIncrementalCompartment && cell->compartment() != rt->gcIncrementalCompartment) - return; - - MarkValue(trc, v, name); - } -} - /*** Push Mark Stack ***/ #define JS_COMPARTMENT_ASSERT(rt, thing) \ JS_ASSERT_IF((rt)->gcCurrentCompartment, \ (thing)->compartment() == (rt)->gcCurrentCompartment); #define JS_COMPARTMENT_ASSERT_STR(rt, thing) \ JS_ASSERT_IF((rt)->gcCurrentCompartment, \ @@ -891,31 +909,31 @@ PushArena(GCMarker *gcmarker, ArenaHeade #endif } } } /* namespace gc */ using namespace js::gc; -struct ValueArrayLayout +struct SlotArrayLayout { union { - HeapValue *end; + HeapSlot *end; js::Class *clasp; }; union { - HeapValue *start; + HeapSlot *start; uintptr_t index; }; JSObject *obj; static void staticAsserts() { /* This should have the same layout as three mark stack items. */ - JS_STATIC_ASSERT(sizeof(ValueArrayLayout) == 3 * sizeof(uintptr_t)); + JS_STATIC_ASSERT(sizeof(SlotArrayLayout) == 3 * sizeof(uintptr_t)); } }; /* * During incremental GC, we return from drainMarkStack without having processed * the entire stack. At that point, JS code can run and reallocate slot arrays * that are stored on the stack. To prevent this from happening, we replace all * ValueArrayTag stack items with SavedValueArrayTag. In the latter, slots @@ -928,26 +946,26 @@ struct ValueArrayLayout */ void GCMarker::saveValueRanges() { for (uintptr_t *p = stack.tos; p > stack.stack; ) { uintptr_t tag = *--p & StackTagMask; if (tag == ValueArrayTag) { p -= 2; - ValueArrayLayout *arr = reinterpret_cast<ValueArrayLayout *>(p); + SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p); JSObject *obj = arr->obj; if (obj->getClass() == &ArrayClass) { - HeapValue *vp = obj->getDenseArrayElements(); + HeapSlot *vp = obj->getDenseArrayElements(); JS_ASSERT(arr->start >= vp && arr->end == vp + obj->getDenseArrayInitializedLength()); arr->index = arr->start - vp; } else { - HeapValue *vp = obj->fixedSlots(); + HeapSlot *vp = obj->fixedSlots(); unsigned nfixed = obj->numFixedSlots(); if (arr->start >= vp && arr->start < vp + nfixed) { JS_ASSERT(arr->end == vp + Min(nfixed, obj->slotSpan())); arr->index = arr->start - vp; } else { JS_ASSERT(arr->start >= obj->slots && arr->end == obj->slots + obj->slotSpan() - nfixed); arr->index = (arr->start - obj->slots) + nfixed; @@ -970,26 +988,26 @@ GCMarker::restoreValueArray(JSObject *ob JS_ASSERT(obj->getClass() == clasp || (clasp == &ArrayClass && obj->getClass() == &SlowArrayClass)); if (clasp == &ArrayClass) { if (obj->getClass() != &ArrayClass) return false; uint32_t initlen = obj->getDenseArrayInitializedLength(); - HeapValue *vp = obj->getDenseArrayElements(); + HeapSlot *vp = obj->getDenseArrayElements(); if (start < initlen) { *vpp = vp + start; *endp = vp + initlen; } else { /* The object shrunk, in which case no scanning is needed. */ *vpp = *endp = vp; } } else { - HeapValue *vp = obj->fixedSlots(); + HeapSlot *vp = obj->fixedSlots(); unsigned nfixed = obj->numFixedSlots(); unsigned nslots = obj->slotSpan(); if (start < nfixed) { *vpp = vp + start; *endp = vp + Min(nfixed, nslots); } else if (start < nslots) { *vpp = obj->slots + start - nfixed; *endp = obj->slots + nslots - nfixed; @@ -1006,33 +1024,33 @@ GCMarker::restoreValueArray(JSObject *ob inline void GCMarker::processMarkStackTop(SliceBudget &budget) { /* * The function uses explicit goto and implements the scanning of the * object directly. It allows to eliminate the tail recursion and * significantly improve the marking performance, see bug 641025. */ - HeapValue *vp, *end; + HeapSlot *vp, *end; JSObject *obj; uintptr_t addr = stack.pop(); uintptr_t tag = addr & StackTagMask; addr &= ~StackTagMask; if (tag == ValueArrayTag) { JS_STATIC_ASSERT(ValueArrayTag == 0); JS_ASSERT(!(addr & Cell::CellMask)); obj = reinterpret_cast<JSObject *>(addr); uintptr_t addr2 = stack.pop(); uintptr_t addr3 = stack.pop(); JS_ASSERT(addr2 <= addr3); JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0); - vp = reinterpret_cast<HeapValue *>(addr2); - end = reinterpret_cast<HeapValue *>(addr3); + vp = reinterpret_cast<HeapSlot *>(addr2); + end = reinterpret_cast<HeapSlot *>(addr3); goto scan_value_array; } if (tag == ObjectTag) { obj = reinterpret_cast<JSObject *>(addr); JS_COMPARTMENT_ASSERT(runtime, obj); goto scan_obj; }
--- a/js/src/jsgcmark.h +++ b/js/src/jsgcmark.h @@ -109,28 +109,36 @@ void MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name); inline void MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name) { MarkValueRootRange(trc, end - begin, begin, name); } -/*** Special Cases ***/ +/*** Slot Marking ***/ -/* Direct value access used by the write barriers and the methodjit */ void -MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name); +MarkSlot(JSTracer *trc, HeapSlot *s, const char *name); + +void +MarkSlotRange(JSTracer *trc, size_t len, HeapSlot *vec, const char *name); /* * Mark a value that may be in a different compartment from the compartment * being GC'd. (Although it won't be marked if it's in the wrong compartment.) */ void -MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name); +MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name); + +/*** Special Cases ***/ + +/* Direct value access used by the write barriers and the methodjit. */ +void +MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name); /* * MarkChildren<JSObject> is exposed solely for preWriteBarrier on * JSObject::TradeGuts. It should not be considered external interface. */ void MarkChildren(JSTracer *trc, JSObject *obj);
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1683,20 +1683,18 @@ types::MarkArgumentsCreated(JSContext *c StackFrame *fp = iter.fp(); if (fp->isScriptFrame() && fp->script() == script) { /* * Check locals and stack slots, assignment to individual arguments * is treated as an escape on the arguments. */ Value *sp = fp->base() + analysis->getCode(iter.pc()).stackDepth; for (Value *vp = fp->slots(); vp < sp; vp++) { - if (vp->isParticularMagic(JS_LAZY_ARGUMENTS)) { - if (!js_GetArgsValue(cx, fp, vp)) - vp->setNull(); - } + if (vp->isParticularMagic(JS_LAZY_ARGUMENTS)) + *vp = ObjectOrNullValue(js_GetArgsObject(cx, fp)); } } } } static inline void ObjectStateChange(JSContext *cx, TypeObject *object, bool markingUnknown, bool force) { @@ -2407,16 +2405,21 @@ ScriptAnalysis::addTypeBarrier(JSContext InferSpew(ISpewOps, "typeBarrier: #%u:%05u: %sT%p%s %s", script->id(), pc - script->code, InferSpewColor(target), target, InferSpewColorReset(), TypeString(type)); barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, type, (JSObject *) NULL, JSID_VOID); + if (!barrier) { + cx->compartment->types.setPendingNukeTypes(cx); + return; + } + barrier->next = code.typeBarriers; code.typeBarriers = barrier; } void ScriptAnalysis::addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc, TypeSet *target, JSObject *singleton, jsid singletonId) { JS_ASSERT(singletonId == MakeTypeId(cx, singletonId) && !JSID_IS_VOID(singletonId)); @@ -2433,16 +2436,21 @@ ScriptAnalysis::addSingletonTypeBarrier( InferSpew(ISpewOps, "singletonTypeBarrier: #%u:%05u: %sT%p%s %p %s", script->id(), pc - script->code, InferSpewColor(target), target, InferSpewColorReset(), (void *) singleton, TypeIdString(singletonId)); TypeBarrier *barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(), singleton, singletonId); + if (!barrier) { + cx->compartment->types.setPendingNukeTypes(cx); + return; + } + barrier->next = code.typeBarriers; code.typeBarriers = barrier; } void TypeCompartment::print(JSContext *cx, bool force) { JSCompartment *compartment = this->compartment();
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -155,17 +155,17 @@ js::GetScopeChain(JSContext *cx, StackFr * make sure there's a call object at the current head of the scope chain, * if this frame is a call frame. * * Also, identify the innermost compiler-allocated block we needn't clone. */ JSObject *limitBlock, *limitClone; if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) { JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp); - if (!CreateFunCallObject(cx, fp)) + if (!CallObject::createForFunction(cx, fp)) return NULL; /* We know we must clone everything on blockChain. */ limitBlock = limitClone = NULL; } else { /* * scopeChain includes all blocks whose static scope we're within that * have already been cloned. Find the innermost such block. Its @@ -641,17 +641,17 @@ js::ExecuteKernel(JSContext *cx, JSScrip if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg)) return false; if (!script->ensureRanAnalysis(cx, &scopeChain)) return false; /* Give strict mode eval its own fresh lexical environment. */ StackFrame *fp = efg.fp(); - if (fp->isStrictEvalFrame() && !CreateEvalCallObject(cx, fp)) + if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp)) return false; Probes::startExecution(cx, script); TypeScript::SetThis(cx, script, fp->thisValue()); AutoPreserveEnumerators preserve(cx); JSBool ok = RunScript(cx, script, fp); @@ -1439,17 +1439,17 @@ js::Interpret(JSContext *cx, StackFrame if (script->pcCounters) \ ENABLE_INTERRUPTS(); \ JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, \ script->hasAnyBreakpointsOrStepMode()); \ JS_END_MACRO #define CHECK_INTERRUPT_HANDLER() \ JS_BEGIN_MACRO \ - if (cx->debugHooks->interruptHook) \ + if (cx->runtime->debugHooks.interruptHook) \ ENABLE_INTERRUPTS(); \ JS_END_MACRO /* Repoint cx->regs to a local variable for faster access. */ FrameRegs regs = cx->regs(); PreserveRegsGuard interpGuard(cx, regs); /* @@ -1586,22 +1586,22 @@ js::Interpret(JSContext *cx, StackFrame } if (script->pcCounters) { OpcodeCounts counts = script->getCounts(regs.pc); counts.get(OpcodeCounts::BASE_INTERP)++; moreInterrupts = true; } - JSInterruptHook hook = cx->debugHooks->interruptHook; + JSInterruptHook hook = cx->runtime->debugHooks.interruptHook; if (hook || script->stepModeEnabled()) { Value rval; JSTrapStatus status = JSTRAP_CONTINUE; if (hook) - status = hook(cx, script, regs.pc, &rval, cx->debugHooks->interruptHookData); + status = hook(cx, script, regs.pc, &rval, cx->runtime->debugHooks.interruptHookData); if (status == JSTRAP_CONTINUE && script->stepModeEnabled()) status = Debugger::onSingleStep(cx, &rval); switch (status) { case JSTRAP_ERROR: goto error; case JSTRAP_CONTINUE: break; case JSTRAP_RETURN: @@ -1962,17 +1962,17 @@ BEGIN_CASE(JSOP_IN) regs.sp[-1].setBoolean(cond); } END_CASE(JSOP_IN) BEGIN_CASE(JSOP_ITER) { JS_ASSERT(regs.sp > regs.fp()->base()); uint8_t flags = GET_UINT8(regs.pc); - if (!js_ValueToIterator(cx, flags, ®s.sp[-1])) + if (!ValueToIterator(cx, flags, ®s.sp[-1])) goto error; CHECK_INTERRUPT_HANDLER(); JS_ASSERT(!regs.sp[-1].isPrimitive()); } END_CASE(JSOP_ITER) BEGIN_CASE(JSOP_MOREITER) { @@ -1996,17 +1996,17 @@ BEGIN_CASE(JSOP_ITERNEXT) if (!IteratorNext(cx, &itervp->toObject(), ®s.sp[-1])) goto error; } END_CASE(JSOP_ITERNEXT) BEGIN_CASE(JSOP_ENDITER) { JS_ASSERT(regs.sp - 1 >= regs.fp()->base()); - bool ok = !!js_CloseIterator(cx, ®s.sp[-1].toObject()); + bool ok = CloseIterator(cx, ®s.sp[-1].toObject()); regs.sp--; if (!ok) goto error; } END_CASE(JSOP_ENDITER) BEGIN_CASE(JSOP_DUP) { @@ -2995,24 +2995,28 @@ END_VARLEN_CASE BEGIN_CASE(JSOP_ARGUMENTS) { Value rval; if (cx->typeInferenceEnabled() && !script->strictModeCode) { if (!script->ensureRanInference(cx)) goto error; if (script->createdArgs) { - if (!js_GetArgsValue(cx, regs.fp(), &rval)) + ArgumentsObject *arguments = js_GetArgsObject(cx, regs.fp()); + if (!arguments) goto error; + rval = ObjectValue(*arguments); } else { rval = MagicValue(JS_LAZY_ARGUMENTS); } } else { - if (!js_GetArgsValue(cx, regs.fp(), &rval)) + ArgumentsObject *arguments = js_GetArgsObject(cx, regs.fp()); + if (!arguments) goto error; + rval = ObjectValue(*arguments); } PUSH_COPY(rval); } END_CASE(JSOP_ARGUMENTS) BEGIN_CASE(JSOP_GETARG) BEGIN_CASE(JSOP_CALLARG) PUSH_COPY(regs.fp()->formalArg(GET_ARGNO(regs.pc))); @@ -3662,18 +3666,18 @@ BEGIN_CASE(JSOP_INSTANCEOF) regs.sp[-1].setBoolean(cond); } END_CASE(JSOP_INSTANCEOF) BEGIN_CASE(JSOP_DEBUGGER) { JSTrapStatus st = JSTRAP_CONTINUE; Value rval; - if (JSDebuggerHandler handler = cx->debugHooks->debuggerHandler) - st = handler(cx, script, regs.pc, &rval, cx->debugHooks->debuggerHandlerData); + if (JSDebuggerHandler handler = cx->runtime->debugHooks.debuggerHandler) + st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.debuggerHandlerData); if (st == JSTRAP_CONTINUE) st = Debugger::onDebuggerStatement(cx, &rval); switch (st) { case JSTRAP_ERROR: goto error; case JSTRAP_CONTINUE: break; case JSTRAP_RETURN: @@ -4222,23 +4226,23 @@ END_CASE(JSOP_ARRAYPUSH) JSThrowHook handler; JSTryNote *tn, *tnlimit; uint32_t offset; /* Restore atoms local in case we will resume. */ atoms = script->atoms; /* Call debugger throw hook if set. */ - if (cx->debugHooks->throwHook || !cx->compartment->getDebuggees().empty()) { + if (cx->runtime->debugHooks.throwHook || !cx->compartment->getDebuggees().empty()) { Value rval; JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval); if (st == JSTRAP_CONTINUE) { - handler = cx->debugHooks->throwHook; + handler = cx->runtime->debugHooks.throwHook; if (handler) - st = handler(cx, script, regs.pc, &rval, cx->debugHooks->throwHookData); + st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.throwHookData); } switch (st) { case JSTRAP_ERROR: cx->clearPendingException(); goto error; case JSTRAP_RETURN: cx->clearPendingException(); @@ -4325,23 +4329,20 @@ END_CASE(JSOP_ARRAYPUSH) PUSH_COPY(cx->getPendingException()); cx->clearPendingException(); len = 0; DO_NEXT_OP(len); case JSTRY_ITER: { /* This is similar to JSOP_ENDITER in the interpreter loop. */ JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER); - Value v = cx->getPendingException(); - cx->clearPendingException(); - bool ok = js_CloseIterator(cx, ®s.sp[-1].toObject()); + bool ok = UnwindIteratorForException(cx, ®s.sp[-1].toObject()); regs.sp -= 1; if (!ok) goto error; - cx->setPendingException(v); } } } while (++tn != tnlimit); no_catch: /* * Propagate the exception or error to the caller unless the exception * is an asynchronous return from a generator.
--- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -347,11 +347,27 @@ Debug_SetValueRangeToCrashOnTouch(Value static JS_ALWAYS_INLINE void Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len) { #ifdef DEBUG Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); #endif } +static JS_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin); +#endif +} + } /* namespace js */ #endif /* jsinterp_h___ */
--- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -824,17 +824,17 @@ iterator_iterator(JSContext *cx, JSObjec static JSBool Iterator(JSContext *cx, uintN argc, Value *vp) { Value *argv = JS_ARGV(cx, vp); bool keyonly = argc >= 2 ? js_ValueToBoolean(argv[1]) : false; uintN flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE)); *vp = argc >= 1 ? argv[0] : UndefinedValue(); - return js_ValueToIterator(cx, flags, vp); + return ValueToIterator(cx, flags, vp); } JSBool js_ThrowStopIteration(JSContext *cx) { Value v; JS_ASSERT(!JS_IsExceptionPending(cx)); @@ -866,22 +866,29 @@ iterator_next(JSContext *cx, uintN argc, #define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) static JSFunctionSpec iterator_methods[] = { JS_FN(js_next_str, iterator_next, 0,JSPROP_ROPERM), JS_FS_END }; +#if JS_HAS_GENERATORS +static JSBool +CloseGenerator(JSContext *cx, JSObject *genobj); +#endif + +namespace js { + /* * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists. * Otherwise construct the default iterator. */ -JS_FRIEND_API(JSBool) -js_ValueToIterator(JSContext *cx, uintN flags, Value *vp) +JSBool +ValueToIterator(JSContext *cx, uintN flags, Value *vp) { /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH); /* * Make sure the more/next state machine doesn't get stuck. A value might be * left in iterValue when a trace is left due to an operation time-out after * JSOP_MOREITER but before the value is picked up by FOR*. @@ -909,23 +916,18 @@ js_ValueToIterator(JSContext *cx, uintN if (!obj) return false; } } return GetIterator(cx, obj, flags, vp); } -#if JS_HAS_GENERATORS -static JSBool -CloseGenerator(JSContext *cx, JSObject *genobj); -#endif - -JS_FRIEND_API(JSBool) -js_CloseIterator(JSContext *cx, JSObject *obj) +bool +CloseIterator(JSContext *cx, JSObject *obj) { cx->iterValue.setMagic(JS_NO_ITER_VALUE); if (obj->isIterator()) { /* Remove enumerators from the active list, which is a stack. */ NativeIterator *ni = obj->getNativeIterator(); if (ni->flags & JSITER_ENUMERATE) { @@ -945,16 +947,29 @@ js_CloseIterator(JSContext *cx, JSObject #if JS_HAS_GENERATORS else if (obj->isGenerator()) { return CloseGenerator(cx, obj); } #endif return JS_TRUE; } +bool +UnwindIteratorForException(JSContext *cx, JSObject *obj) +{ + Value v = cx->getPendingException(); + cx->clearPendingException(); + if (!CloseIterator(cx, obj)) + return false; + cx->setPendingException(v); + return true; +} + +} // namespace js + /* * Suppress enumeration of deleted properties. This function must be called * when a property is deleted and there might be active enumerators. * * We maintain a list of active non-escaping for-in enumerators. To suppress * a property, we check whether each active enumerator contains the (obj, id) * pair and has not yet enumerated |id|. If so, and |id| is the next property, * we simply advance the cursor. Otherwise, we delete |id| from the list.
--- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -176,29 +176,32 @@ VectorToValueIterator(JSContext *cx, JSO /* * Creates either a key or value iterator, depending on flags. For a value * iterator, performs value-lookup to convert the given list of jsids. */ bool EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); -} - /* * Convert the value stored in *vp to its iteration object. The flags should * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating * for-in semantics are required, and when the caller can guarantee that the * iterator will never be exposed to scripts. */ -extern JS_FRIEND_API(JSBool) -js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp); +extern JSBool +ValueToIterator(JSContext *cx, uintN flags, js::Value *vp); -extern JS_FRIEND_API(JSBool) -js_CloseIterator(JSContext *cx, JSObject *iterObj); +extern bool +CloseIterator(JSContext *cx, JSObject *iterObj); + +extern bool +UnwindIteratorForException(JSContext *cx, JSObject *obj); + +} extern bool js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id); extern bool js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index); extern bool
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2748,17 +2748,17 @@ NewObject(JSContext *cx, Class *clasp, t RootTypeObject typeRoot(cx, &type); RootedVarShape shape(cx); shape = EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind); if (!shape) return NULL; - HeapValue *slots; + HeapSlot *slots; if (!PreallocateObjectDynamicSlots(cx, shape, &slots)) return NULL; JSObject *obj = JSObject::create(cx, kind, shape, typeRoot, slots); if (!obj) return NULL; /* @@ -3245,18 +3245,18 @@ JS_CloneObject(JSContext *cx, JSObject * struct JSObject::TradeGutsReserved { JSContext *cx; Vector<Value> avals; Vector<Value> bvals; int newafixed; int newbfixed; Shape *newashape; Shape *newbshape; - HeapValue *newaslots; - HeapValue *newbslots; + HeapSlot *newaslots; + HeapSlot *newbslots; TradeGutsReserved(JSContext *cx) : cx(cx), avals(cx), bvals(cx), newafixed(0), newbfixed(0), newashape(NULL), newbshape(NULL), newaslots(NULL), newbslots(NULL) {} @@ -3345,26 +3345,26 @@ JSObject::ReserveForTradeGuts(JSContext * if they do not have enough fixed slots to accomodate the slots in the * other object. */ unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan()); unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan()); if (adynamic) { - reserved.newaslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * adynamic); + reserved.newaslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * adynamic); if (!reserved.newaslots) return false; - Debug_SetValueRangeToCrashOnTouch(reserved.newaslots, adynamic); + Debug_SetSlotRangeToCrashOnTouch(reserved.newaslots, adynamic); } if (bdynamic) { - reserved.newbslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * bdynamic); + reserved.newbslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * bdynamic); if (!reserved.newbslots) return false; - Debug_SetValueRangeToCrashOnTouch(reserved.newbslots, bdynamic); + Debug_SetSlotRangeToCrashOnTouch(reserved.newbslots, bdynamic); } return true; } void JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved) { @@ -3416,21 +3416,20 @@ JSObject::TradeGuts(JSContext *cx, JSObj js_memcpy(a, b, size); js_memcpy(b, tmp, size); #ifdef JSGC_GENERATIONAL /* * Trigger post barriers for fixed slots. JSObject bits are barriered * below, in common with the other case. */ + JSCompartment *comp = cx->compartment; for (size_t i = 0; i < a->numFixedSlots(); ++i) { - HeapValue *slotA = &a->getFixedSlotRef(i); - HeapValue *slotB = &b->getFixedSlotRef(i); - HeapValue::writeBarrierPost(*slotA, slotA); - HeapValue::writeBarrierPost(*slotB, slotB); + HeapSlot::writeBarrierPost(comp, a, i); + HeapSlot::writeBarrierPost(comp, b, i); } #endif } else { /* * If the objects are of differing sizes, use the space we reserved * earlier to save the slots from each object and then copy them into * the new layout for the other object. */ @@ -3811,87 +3810,49 @@ js_InitClass(JSContext *cx, HandleObject return NULL; } return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs, ps, fs, static_ps, static_fs, ctorp, ctorKind); } void -JSObject::getSlotRange(size_t start, size_t length, - HeapValue **fixedStart, HeapValue **fixedEnd, - HeapValue **slotsStart, HeapValue **slotsEnd) -{ - JS_ASSERT(!isDenseArray()); - JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); - - size_t fixed = numFixedSlots(); - if (start < fixed) { - if (start + length < fixed) { - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + length]; - *slotsStart = *slotsEnd = NULL; - } else { - size_t localCopy = fixed - start; - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + localCopy]; - *slotsStart = &slots[0]; - *slotsEnd = &slots[length - localCopy]; - } - } else { - *fixedStart = *fixedEnd = NULL; - *slotsStart = &slots[start - fixed]; - *slotsEnd = &slots[start - fixed + length]; - } -} - -void JSObject::initSlotRange(size_t start, const Value *vector, size_t length) { JSCompartment *comp = compartment(); - HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); - for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++) - vp->init(comp, *vector++); - for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++) - vp->init(comp, *vector++); + for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++) + sp->init(comp, this, start++, *vector++); + for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++) + sp->init(comp, this, start++, *vector++); } void JSObject::copySlotRange(size_t start, const Value *vector, size_t length) { JSCompartment *comp = compartment(); - HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); - for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++) - vp->set(comp, *vector++); - for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++) - vp->set(comp, *vector++); + for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++) + sp->set(comp, this, start++, *vector++); + for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++) + sp->set(comp, this, start++, *vector++); } inline void JSObject::invalidateSlotRange(size_t start, size_t length) { #ifdef DEBUG JS_ASSERT(!isDenseArray()); - size_t fixed = numFixedSlots(); - - /* No bounds checks, allocated space has been updated but not the shape. */ - if (start < fixed) { - if (start + length < fixed) { - Debug_SetValueRangeToCrashOnTouch(fixedSlots() + start, length); - } else { - size_t localClear = fixed - start; - Debug_SetValueRangeToCrashOnTouch(fixedSlots() + start, localClear); - Debug_SetValueRangeToCrashOnTouch(slots, length - localClear); - } - } else { - Debug_SetValueRangeToCrashOnTouch(slots + start - fixed, length); - } + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); + Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd); + Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd); #endif /* DEBUG */ } inline bool JSObject::updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan) { JS_ASSERT(oldSpan != newSpan); @@ -4001,34 +3962,34 @@ JSObject::growSlots(JSContext *cx, uint3 type()->newScript->allocKind = kind; type()->newScript->shape = obj->lastProperty(); type()->markStateChange(cx); } } if (!oldCount) { - slots = (HeapValue *) cx->malloc_(newCount * sizeof(HeapValue)); + slots = (HeapSlot *) cx->malloc_(newCount * sizeof(HeapSlot)); if (!slots) return false; - Debug_SetValueRangeToCrashOnTouch(slots, newCount); + Debug_SetSlotRangeToCrashOnTouch(slots, newCount); if (Probes::objectResizeActive()) Probes::resizeObject(cx, this, oldSize, newSize); return true; } - HeapValue *newslots = (HeapValue*) cx->realloc_(slots, oldCount * sizeof(HeapValue), - newCount * sizeof(HeapValue)); + HeapSlot *newslots = (HeapSlot*) cx->realloc_(slots, oldCount * sizeof(HeapSlot), + newCount * sizeof(HeapSlot)); if (!newslots) return false; /* Leave slots at its old size. */ bool changed = slots != newslots; slots = newslots; - Debug_SetValueRangeToCrashOnTouch(slots + oldCount, newCount - oldCount); + Debug_SetSlotRangeToCrashOnTouch(slots + oldCount, newCount - oldCount); /* Changes in the slots of global objects can trigger recompilation. */ if (changed && isGlobal()) types::MarkObjectStateChange(cx, this); if (Probes::objectResizeActive()) Probes::resizeObject(cx, this, oldSize, newSize); @@ -4058,17 +4019,17 @@ JSObject::shrinkSlots(JSContext *cx, uin slots = NULL; if (Probes::objectResizeActive()) Probes::resizeObject(cx, this, oldSize, newSize); return; } JS_ASSERT(newCount >= SLOT_CAPACITY_MIN); - HeapValue *newslots = (HeapValue*) cx->realloc_(slots, newCount * sizeof(HeapValue)); + HeapSlot *newslots = (HeapSlot *) cx->realloc_(slots, newCount * sizeof(HeapSlot)); if (!newslots) return; /* Leave slots at its old size. */ bool changed = slots != newslots; slots = newslots; /* Watch for changes in global object slots, as for growSlots. */ if (changed && isGlobal()) @@ -4131,17 +4092,17 @@ JSObject::growElements(JSContext *cx, ui return false; /* Ditto. */ js_memcpy(newheader, getElementsHeader(), (ObjectElements::VALUES_PER_HEADER + initlen) * sizeof(Value)); } newheader->capacity = actualCapacity; elements = newheader->elements(); - Debug_SetValueRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen); + Debug_SetSlotRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen); if (Probes::objectResizeActive()) Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements()); return true; } void @@ -6533,18 +6494,16 @@ js_DumpStackFrame(JSContext *cx, StackFr } else { fprintf(stderr, "dummy frame"); } fputc('\n', stderr); fprintf(stderr, " flags:"); if (fp->isConstructing()) fprintf(stderr, " constructing"); - if (fp->hasOverriddenArgs()) - fprintf(stderr, " overridden_args"); if (fp->isDebuggerFrame()) fprintf(stderr, " debugger"); if (fp->isEvalFrame()) fprintf(stderr, " eval"); if (fp->isYielding()) fprintf(stderr, " yielding"); if (fp->isGeneratorFrame()) fprintf(stderr, " generator");
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -429,17 +429,17 @@ struct JSObject : public js::ObjectImpl /* As above, but does not change the slot span. */ inline void setLastPropertyInfallible(const js::Shape *shape); /* Make a non-array object with the specified initial state. */ static inline JSObject *create(JSContext *cx, js::gc::AllocKind kind, js::HandleShape shape, js::HandleTypeObject type, - js::HeapValue *slots); + js::HeapSlot *slots); /* Make a dense array object with the specified initial state. */ static inline JSObject *createDenseArray(JSContext *cx, js::gc::AllocKind kind, js::HandleShape shape, js::HandleTypeObject type, uint32_t length); @@ -541,31 +541,34 @@ struct JSObject : public js::ObjectImpl static const uint32_t MAX_FIXED_SLOTS = 16; private: /* * Get internal pointers to the range of values starting at start and * running for length. */ - void getSlotRange(size_t start, size_t length, - js::HeapValue **fixedStart, js::HeapValue **fixedEnd, - js::HeapValue **slotsStart, js::HeapValue **slotsEnd); + inline void getSlotRangeUnchecked(size_t start, size_t length, + js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd, + js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd); + inline void getSlotRange(size_t start, size_t length, + js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd, + js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd); public: /* Accessors for properties. */ /* Whether a slot is at a fixed offset from this object. */ inline bool isFixedSlot(size_t slot); /* Index into the dynamic slots array to use for a dynamic slot. */ inline size_t dynamicSlotIndex(size_t slot); /* Get a raw pointer to the object's properties. */ - inline const js::HeapValue *getRawSlots(); + inline const js::HeapSlot *getRawSlots(); /* * Grow or shrink slots immediately before changing the slot span. * The number of allocated slots is not stored explicitly, and changes to * the slots must track changes in the slot span. */ bool growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount); void shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount); @@ -615,39 +618,41 @@ struct JSObject : public js::ObjectImpl /* * Check that slot is in range for the object's allocated slots. * If sentinelAllowed then slot may equal the slot capacity. */ bool slotInRange(uintN slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const; #endif - js::HeapValue *getSlotAddressUnchecked(uintN slot) { + private: + js::HeapSlot *getSlotAddressUnchecked(uintN slot) { size_t fixed = numFixedSlots(); if (slot < fixed) return fixedSlots() + slot; return slots + (slot - fixed); } - js::HeapValue *getSlotAddress(uintN slot) { + public: + js::HeapSlot *getSlotAddress(uintN slot) { /* * This can be used to get the address of the end of the slots for the * object, which may be necessary when fetching zero-length arrays of * slots (e.g. for callObjVarArray). */ JS_ASSERT(slotInRange(slot, SENTINEL_ALLOWED)); return getSlotAddressUnchecked(slot); } - js::HeapValue &getSlotRef(uintN slot) { + js::HeapSlot &getSlotRef(uintN slot) { JS_ASSERT(slotInRange(slot)); return *getSlotAddress(slot); } - inline js::HeapValue &nativeGetSlotRef(uintN slot); + inline js::HeapSlot &nativeGetSlotRef(uintN slot); const js::Value &getSlot(uintN slot) const { JS_ASSERT(slotInRange(slot)); size_t fixed = numFixedSlots(); if (slot < fixed) return fixedSlots()[slot]; return slots[slot - fixed]; } @@ -658,22 +663,23 @@ struct JSObject : public js::ObjectImpl inline void setSlot(uintN slot, const js::Value &value); inline void initSlot(uintN slot, const js::Value &value); inline void initSlotUnchecked(uintN slot, const js::Value &value); inline void nativeSetSlot(uintN slot, const js::Value &value); inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value); inline const js::Value &getReservedSlot(uintN index) const; - inline js::HeapValue &getReservedSlotRef(uintN index); + inline js::HeapSlot &getReservedSlotRef(uintN index); + inline void initReservedSlot(uintN index, const js::Value &v); inline void setReservedSlot(uintN index, const js::Value &v); /* For slots which are known to always be fixed, due to the way they are allocated. */ - js::HeapValue &getFixedSlotRef(uintN slot) { + js::HeapSlot &getFixedSlotRef(uintN slot) { JS_ASSERT(slot < numFixedSlots()); return fixedSlots()[slot]; } const js::Value &getFixedSlot(uintN slot) const { JS_ASSERT(slot < numFixedSlots()); return fixedSlots()[slot]; } @@ -829,17 +835,17 @@ struct JSObject : public js::ObjectImpl inline uint32_t getArrayLength() const; inline void setArrayLength(JSContext *cx, uint32_t length); inline uint32_t getDenseArrayCapacity(); inline uint32_t getDenseArrayInitializedLength(); inline void setDenseArrayLength(uint32_t length); inline void setDenseArrayInitializedLength(uint32_t length); inline void ensureDenseArrayInitializedLength(JSContext *cx, uintN index, uintN extra); - inline js::HeapValueArray getDenseArrayElements(); + inline js::HeapSlotArray getDenseArrayElements(); inline const js::Value &getDenseArrayElement(uintN idx); inline void setDenseArrayElement(uintN idx, const js::Value &val); inline void initDenseArrayElement(uintN idx, const js::Value &val); inline void setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val); inline void initDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val); inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count); inline void initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count); inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
--- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -96,17 +96,17 @@ JSObject::privateRef(uint32_t nfixed) co { /* * The private pointer of an object can hold any word sized value. * Private pointers are stored immediately after the last fixed slot of * the object. */ JS_ASSERT(nfixed == numFixedSlots()); JS_ASSERT(hasPrivate()); - js::HeapValue *end = &fixedSlots()[nfixed]; + js::HeapSlot *end = &fixedSlots()[nfixed]; return *reinterpret_cast<void**>(end); } inline void * JSObject::getPrivate() const { return privateRef(numFixedSlots()); } inline void * JSObject::getPrivate(size_t nfixed) const { return privateRef(nfixed); } @@ -401,69 +401,76 @@ JSObject::canRemoveLastProperty() * converted to dictionary mode instead. See BaseShape comment in jsscope.h */ JS_ASSERT(!inDictionaryMode()); const js::Shape *previous = lastProperty()->previous(); return previous->getObjectParent() == lastProperty()->getObjectParent() && previous->getObjectFlags() == lastProperty()->getObjectFlags(); } -inline const js::HeapValue * +inline const js::HeapSlot * JSObject::getRawSlots() { JS_ASSERT(isGlobal()); return slots; } inline const js::Value & JSObject::getReservedSlot(uintN index) const { JS_ASSERT(index < JSSLOT_FREE(getClass())); return getSlot(index); } -inline js::HeapValue & +inline js::HeapSlot & JSObject::getReservedSlotRef(uintN index) { JS_ASSERT(index < JSSLOT_FREE(getClass())); return getSlotRef(index); } inline void JSObject::setReservedSlot(uintN index, const js::Value &v) { JS_ASSERT(index < JSSLOT_FREE(getClass())); setSlot(index, v); } +inline void +JSObject::initReservedSlot(uintN index, const js::Value &v) +{ + JS_ASSERT(index < JSSLOT_FREE(getClass())); + initSlot(index, v); +} + inline bool JSObject::hasContiguousSlots(size_t start, size_t count) const { /* * Check that the range [start, start+count) is either all inline or all * out of line. */ JS_ASSERT(slotInRange(start + count, SENTINEL_ALLOWED)); return (start + count <= numFixedSlots()) || (start >= numFixedSlots()); } inline void JSObject::prepareSlotRangeForOverwrite(size_t start, size_t end) { for (size_t i = start; i < end; i++) - getSlotAddressUnchecked(i)->js::HeapValue::~HeapValue(); + getSlotAddressUnchecked(i)->js::HeapSlot::~HeapSlot(); } inline void JSObject::prepareElementRangeForOverwrite(size_t start, size_t end) { JS_ASSERT(isDenseArray()); JS_ASSERT(end <= getDenseArrayInitializedLength()); for (size_t i = start; i < end; i++) - elements[i].js::HeapValue::~HeapValue(); + elements[i].js::HeapSlot::~HeapSlot(); } inline uint32_t JSObject::getArrayLength() const { JS_ASSERT(isArray()); return getElementsHeader()->length; } @@ -524,42 +531,42 @@ JSObject::getDenseArrayCapacity() inline bool JSObject::ensureElements(JSContext *cx, uint32_t capacity) { if (capacity > getDenseArrayCapacity()) return growElements(cx, capacity); return true; } -inline js::HeapValueArray +inline js::HeapSlotArray JSObject::getDenseArrayElements() { JS_ASSERT(isDenseArray()); - return js::HeapValueArray(elements); + return js::HeapSlotArray(elements); } inline const js::Value & JSObject::getDenseArrayElement(uintN idx) { JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength()); return elements[idx]; } inline void JSObject::setDenseArrayElement(uintN idx, const js::Value &val) { JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength()); - elements[idx] = val; + elements[idx].set(this, idx, val); } inline void JSObject::initDenseArrayElement(uintN idx, const js::Value &val) { JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength()); - elements[idx].init(val); + elements[idx].init(this, idx, val); } inline void JSObject::setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val) { js::types::AddTypePropertyId(cx, this, JSID_VOID, val); setDenseArrayElement(idx, val); } @@ -572,26 +579,26 @@ JSObject::initDenseArrayElementWithType( } inline void JSObject::copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count) { JS_ASSERT(dstStart + count <= getDenseArrayCapacity()); JSCompartment *comp = compartment(); for (unsigned i = 0; i < count; ++i) - elements[dstStart + i].set(comp, src[i]); + elements[dstStart + i].set(comp, this, dstStart + i, src[i]); } inline void JSObject::initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count) { JS_ASSERT(dstStart + count <= getDenseArrayCapacity()); JSCompartment *comp = compartment(); for (unsigned i = 0; i < count; ++i) - elements[dstStart + i].init(comp, src[i]); + elements[dstStart + i].init(comp, this, dstStart + i, src[i]); } inline void JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count) { JS_ASSERT(dstStart + count <= getDenseArrayCapacity()); JS_ASSERT(srcStart + count <= getDenseArrayInitializedLength()); @@ -602,30 +609,31 @@ JSObject::moveDenseArrayElements(uintN d * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code. * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C]. * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C). * * Since normal marking never happens on B, it is very important that the * write barrier is invoked here on B, despite the fact that it exists in * the array before and after the move. */ - if (compartment()->needsBarrier()) { + JSCompartment *comp = compartment(); + if (comp->needsBarrier()) { if (dstStart < srcStart) { - js::HeapValue *dst = elements + dstStart; - js::HeapValue *src = elements + srcStart; + js::HeapSlot *dst = elements + dstStart; + js::HeapSlot *src = elements + srcStart; for (unsigned i = 0; i < count; i++, dst++, src++) - *dst = *src; + dst->set(comp, this, dst - elements, *src); } else { - js::HeapValue *dst = elements + dstStart + count - 1; - js::HeapValue *src = elements + srcStart + count - 1; + js::HeapSlot *dst = elements + dstStart + count - 1; + js::HeapSlot *src = elements + srcStart + count - 1; for (unsigned i = 0; i < count; i++, dst--, src--) - *dst = *src; + dst->set(comp, this, dst - elements, *src); } } else { - memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value)); + memmove(elements + dstStart, elements + srcStart, count * sizeof(js::HeapSlot)); } } inline void JSObject::moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count) { JS_ASSERT(!compartment()->needsBarrier()); @@ -966,40 +974,72 @@ inline bool JSObject::isQName() const { return hasClass(&js::QNameClass) || hasClass(&js::AttributeNameClass) || hasClass(&js::AnyNameClass); } inline void +JSObject::getSlotRangeUnchecked(size_t start, size_t length, + js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd, + js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd) +{ + JS_ASSERT(!isDenseArray()); + + size_t fixed = numFixedSlots(); + if (start < fixed) { + if (start + length < fixed) { + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + length]; + *slotsStart = *slotsEnd = NULL; + } else { + size_t localCopy = fixed - start; + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + localCopy]; + *slotsStart = &slots[0]; + *slotsEnd = &slots[length - localCopy]; + } + } else { + *fixedStart = *fixedEnd = NULL; + *slotsStart = &slots[start - fixed]; + *slotsEnd = &slots[start - fixed + length]; + } +} + +inline void +JSObject::getSlotRange(size_t start, size_t length, + js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd, + js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd) +{ + JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); + getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd); +} + +inline void JSObject::initializeSlotRange(size_t start, size_t length) { /* * No bounds check, as this is used when the object's shape does not * reflect its allocated slots (updateSlotsForSpan). */ - JS_ASSERT(!isDenseArray()); - size_t fixed = numFixedSlots(); - if (start < fixed) { - if (start + length < fixed) { - js::InitValueRange(fixedSlots() + start, length, false); - } else { - size_t localClear = fixed - start; - js::InitValueRange(fixedSlots() + start, localClear, false); - js::InitValueRange(slots, length - localClear, false); - } - } else { - js::InitValueRange(slots + start - fixed, length, false); - } + js::HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); + + JSCompartment *comp = compartment(); + size_t offset = start; + for (js::HeapSlot *sp = fixedStart; sp != fixedEnd; sp++) + sp->init(comp, this, offset++, js::UndefinedValue()); + for (js::HeapSlot *sp = slotsStart; sp != slotsEnd; sp++) + sp->init(comp, this, offset++, js::UndefinedValue()); } /* static */ inline JSObject * JSObject::create(JSContext *cx, js::gc::AllocKind kind, - js::HandleShape shape, js::HandleTypeObject type, js::HeapValue *slots) + js::HandleShape shape, js::HandleTypeObject type, js::HeapSlot *slots) { /* * Callers must use dynamicSlotsCount to size the initial slot array of the * object. We can't check the allocated capacity of the dynamic slots, but * make sure their presence is consistent with the shape. */ JS_ASSERT(shape && type); JS_ASSERT(!!dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == !!slots); @@ -1097,17 +1137,17 @@ JSObject::principals(JSContext *cx) inline uint32_t JSObject::slotSpan() const { if (inDictionaryMode()) return lastProperty()->base()->slotSpan(); return lastProperty()->slotSpan(); } -inline js::HeapValue & +inline js::HeapSlot & JSObject::nativeGetSlotRef(uintN slot) { JS_ASSERT(isNative()); JS_ASSERT(slot < slotSpan()); return getSlotRef(slot); } inline const js::Value & @@ -1339,17 +1379,17 @@ JSObject::getSpecial(JSContext *cx, JSOb { return getGeneric(cx, receiver, 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); + 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); } @@ -1808,23 +1848,23 @@ NewObjectGCKind(JSContext *cx, js::Class return gc::FINALIZE_OBJECT4; } /* * Fill slots with the initial slot array to use for a newborn object which * may or may not need dynamic slots. */ inline bool -PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapValue **slots) +PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapSlot **slots) { if (size_t count = JSObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())) { - *slots = (HeapValue *) cx->malloc_(count * sizeof(HeapValue)); + *slots = (HeapSlot *) cx->malloc_(count * sizeof(HeapSlot)); if (!*slots) return false; - Debug_SetValueRangeToCrashOnTouch(*slots, count); + Debug_SetSlotRangeToCrashOnTouch(*slots, count); return true; } *slots = NULL; return true; } inline bool DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global, @@ -1964,40 +2004,40 @@ js_PurgeScopeChain(JSContext *cx, JSObje return js_PurgeScopeChainHelper(cx, obj, id); return true; } inline void JSObject::setSlot(uintN slot, const js::Value &value) { JS_ASSERT(slotInRange(slot)); - getSlotRef(slot).set(compartment(), value); + getSlotRef(slot).set(this, slot, value); } inline void JSObject::initSlot(uintN slot, const js::Value &value) { JS_ASSERT(getSlot(slot).isUndefined() || getSlot(slot).isMagic(JS_ARRAY_HOLE)); JS_ASSERT(slotInRange(slot)); initSlotUnchecked(slot, value); } inline void JSObject::initSlotUnchecked(uintN slot, const js::Value &value) { - getSlotAddressUnchecked(slot)->init(value); + getSlotAddressUnchecked(slot)->init(this, slot, value); } inline void JSObject::setFixedSlot(uintN slot, const js::Value &value) { JS_ASSERT(slot < numFixedSlots()); - fixedSlots()[slot] = value; + fixedSlots()[slot].set(this, slot, value); } inline void JSObject::initFixedSlot(uintN slot, const js::Value &value) { JS_ASSERT(slot < numFixedSlots()); - fixedSlots()[slot].init(value); + fixedSlots()[slot].init(this, slot, value); } #endif /* jsobjinlines_h___ */
--- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -54,32 +54,32 @@ #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h" using namespace js; using namespace js::gc; -static inline HeapValue & +static inline HeapSlot & GetCall(JSObject *proxy) { JS_ASSERT(IsFunctionProxy(proxy)); return proxy->getSlotRef(JSSLOT_PROXY_CALL); } static inline Value GetConstruct(JSObject *proxy) { if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT) return UndefinedValue(); return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT); } -static inline HeapValue & +static inline HeapSlot & GetFunctionProxyConstruct(JSObject *proxy) { JS_ASSERT(IsFunctionProxy(proxy)); JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT); return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT); } static bool @@ -1243,31 +1243,31 @@ proxy_DeleteSpecial(JSContext *cx, JSObj { return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict); } static void proxy_TraceObject(JSTracer *trc, JSObject *obj) { GetProxyHandler(obj)->trace(trc, obj); - MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private"); - MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0"); - MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1"); + MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private"); + MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0"); + MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1"); if (IsFunctionProxy(obj)) { - MarkCrossCompartmentValue(trc, &GetCall(obj), "call"); - MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct"); + MarkCrossCompartmentSlot(trc, &GetCall(obj), "call"); + MarkCrossCompartmentSlot(trc, &GetFunctionProxyConstruct(obj), "construct"); } } static void proxy_TraceFunction(JSTracer *trc, JSObject *obj) { proxy_TraceObject(trc, obj); - MarkCrossCompartmentValue(trc, &GetCall(obj), "call"); - MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct"); + MarkCrossCompartmentSlot(trc, &GetCall(obj), "call"); + MarkCrossCompartmentSlot(trc, &GetFunctionProxyConstruct(obj), "construct"); } static JSBool proxy_Convert(JSContext *cx, JSObject *proxy, JSType hint, Value *vp) { JS_ASSERT(proxy->isProxy()); return Proxy::defaultValue(cx, proxy, hint, vp); }
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -93,19 +93,19 @@ Bindings::lookup(JSContext *cx, JSAtom * Shape **spp; Shape *shape = Shape::search(cx, lastBinding, ATOM_TO_JSID(name), &spp); if (!shape) return NONE; if (indexp) *indexp = shape->shortid(); - if (shape->getter() == GetCallArg) + if (shape->getter() == CallObject::getArgOp) return ARGUMENT; - if (shape->getter() == GetCallUpvar) + if (shape->getter() == CallObject::getUpvarOp) return UPVAR; return shape->writable() ? VARIABLE : CONSTANT; } bool Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind) { @@ -123,32 +123,32 @@ Bindings::add(JSContext *cx, JSAtom *nam PropertyOp getter; StrictPropertyOp setter; uint32_t slot = CallObject::RESERVED_SLOTS; if (kind == ARGUMENT) { JS_ASSERT(nvars == 0); JS_ASSERT(nupvars == 0); indexp = &nargs; - getter = GetCallArg; - setter = SetCallArg; + getter = CallObject::getArgOp; + setter = CallObject::setArgOp; slot += nargs; } else if (kind == UPVAR) { indexp = &nupvars; - getter = GetCallUpvar; - setter = SetCallUpvar; + getter = CallObject::getUpvarOp; + setter = CallObject::setUpvarOp; slot = lastBinding->maybeSlot(); attrs |= JSPROP_SHARED; } else { JS_ASSERT(kind == VARIABLE || kind == CONSTANT); JS_ASSERT(nupvars == 0); indexp = &nvars; - getter = GetCallVar; - setter = SetCallVar; + getter = CallObject::getVarOp; + setter = CallObject::setVarOp; if (kind == CONSTANT) attrs |= JSPROP_READONLY; slot += nargs + nvars; } if (*indexp == BINDING_COUNT_LIMIT) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, (kind == ARGUMENT) @@ -243,31 +243,31 @@ Bindings::getLocalNameArray(JSContext *c for (uintN i = 0; i < n; i++) names[i] = POISON; #endif for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) { const Shape &shape = r.front(); uintN index = uint16_t(shape.shortid()); - if (shape.getter() == GetCallArg) { + if (shape.getter() == CallObject::getArgOp) { JS_ASSERT(index < nargs); - } else if (shape.getter() == GetCallUpvar) { + } else if (shape.getter() == CallObject::getUpvarOp) { JS_ASSERT(index < nupvars); index += nargs + nvars; } else { JS_ASSERT(index < nvars); index += nargs; } if (JSID_IS_ATOM(shape.propid())) { names[index] = JSID_TO_ATOM(shape.propid()); } else { JS_ASSERT(JSID_IS_INT(shape.propid())); - JS_ASSERT(shape.getter() == GetCallArg); + JS_ASSERT(shape.getter() == CallObject::getArgOp); names[index] = NULL; } } #ifdef DEBUG for (uintN i = 0; i < n; i++) JS_ASSERT(names[i] != POISON); #endif @@ -277,30 +277,30 @@ Bindings::getLocalNameArray(JSContext *c const Shape * Bindings::lastArgument() const { JS_ASSERT(lastBinding); const js::Shape *shape = lastVariable(); if (nvars > 0) { - while (shape->previous() && shape->getter() != GetCallArg) + while (shape->previous() && shape->getter() != CallObject::getArgOp) shape = shape->previous(); } return shape; } const Shape * Bindings::lastVariable() const { JS_ASSERT(lastBinding); const js::Shape *shape = lastUpvar(); if (nupvars > 0) { - while (shape->getter() == GetCallUpvar) + while (shape->getter() == CallObject::getUpvarOp) shape = shape->previous(); } return shape; } const Shape * Bindings::lastUpvar() const { @@ -1428,32 +1428,32 @@ JSScript::numNotes() continue; return sn - notes_ + 1; /* +1 for the terminator */ } JS_FRIEND_API(void) js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) { JS_ASSERT(!script->callDestroyHook); - if (JSNewScriptHook hook = cx->debugHooks->newScriptHook) { + if (JSNewScriptHook hook = cx->runtime->debugHooks.newScriptHook) { AutoKeepAtoms keep(cx->runtime); hook(cx, script->filename, script->lineno, script, fun, - cx->debugHooks->newScriptHookData); + cx->runtime->debugHooks.newScriptHookData); } script->callDestroyHook = true; } void js_CallDestroyScriptHook(JSContext *cx, JSScript *script) { if (!script->callDestroyHook) return; - if (JSDestroyScriptHook hook = cx->debugHooks->destroyScriptHook) - hook(cx, script, cx->debugHooks->destroyScriptHookData); + if (JSDestroyScriptHook hook = cx->runtime->debugHooks.destroyScriptHook) + hook(cx, script, cx->runtime->debugHooks.destroyScriptHookData); script->callDestroyHook = false; JS_ClearScriptTraps(cx, script); } void JSScript::finalize(JSContext *cx, bool background) { CheckScript(this, NULL);
--- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1094,17 +1094,17 @@ class TypedArrayTemplate static inline Class *fastClass() { return &TypedArray::fastClasses[ArrayTypeID()]; } static void obj_trace(JSTracer *trc, JSObject *obj) { - MarkValue(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer"); + MarkSlot(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer"); } static JSBool obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp) { JSObject *tarray = getTypedArray(obj);
--- a/js/src/jsval.h +++ b/js/src/jsval.h @@ -281,16 +281,17 @@ typedef enum JSWhyMagic * enumerated like a native object. */ JS_NO_ITER_VALUE, /* there is not a pending iterator value */ JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ JS_NO_CONSTANT, /* compiler sentinel value */ JS_THIS_POISON, /* used in debug builds to catch tracing errors */ JS_ARG_POISON, /* used in debug builds to catch tracing errors */ JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */ + JS_UNASSIGNED_ARGUMENTS, /* the initial value of callobj.arguments */ JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */ JS_GENERIC_MAGIC /* for local use */ } JSWhyMagic; #if defined(IS_LITTLE_ENDIAN) # if JS_BITS_PER_WORD == 32 typedef union jsval_layout {
--- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -97,16 +97,40 @@ WeakMapBase::resetWeakMapList(JSRuntime rt->gcWeakMapList = NULL; while (m) { WeakMapBase *n = m->next; m->next = WeakMapNotInList; m = n; } } +bool +WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector) +{ + WeakMapBase *m = rt->gcWeakMapList; + while (m) { + if (!vector.append(m)) + return false; + m = m->next; + } + return true; +} + +void +WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector) +{ + JS_ASSERT(!rt->gcWeakMapList); + for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) { + WeakMapBase *m = *p; + JS_ASSERT(m->next == WeakMapNotInList); + m->next = rt->gcWeakMapList; + rt->gcWeakMapList = m; + } +} + } /* namespace js */ typedef WeakMap<HeapPtr<JSObject>, HeapValue> ObjectValueMap; static ObjectValueMap * GetObjectMap(JSObject *obj) { JS_ASSERT(obj->isWeakMap());
--- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -104,16 +104,18 @@ template <class Type> class DefaultMarkP // A policy template holding default tracing algorithms for common type combinations. This // provides default types for WeakMap's TracePolicy template parameter. template <class Key, class Value> class DefaultTracePolicy; // The value for the next pointer for maps not in the map list. static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1); +typedef Vector<WeakMapBase *, 0, SystemAllocPolicy> WeakMapVector; + // Common base class for all WeakMap specializations. The collector uses this to call // their markIteratively and sweep methods. class WeakMapBase { public: WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { } virtual ~WeakMapBase() { } void trace(JSTracer *tracer) { @@ -156,16 +158,20 @@ class WeakMapBase { // Trace all delayed weak map bindings. Used by the cycle collector. static void traceAllMappings(WeakMapTracer *tracer); void check() { JS_ASSERT(next == WeakMapNotInList); } // Remove everything from the live weak map list. static void resetWeakMapList(JSRuntime *rt); + // Save and restore the live weak map list to a vector. + static bool saveWeakMapList(JSRuntime *rt, WeakMapVector &vector); + static void restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector); + protected: // Instance member functions called by the above. Instantiations of WeakMap override // these with definitions appropriate for their Key and Value types. virtual void nonMarkingTrace(JSTracer *tracer) = 0; virtual bool markIteratively(JSTracer *tracer) = 0; virtual void sweep(JSTracer *tracer) = 0; virtual void traceMappings(WeakMapTracer *tracer) = 0;
--- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -358,17 +358,17 @@ Wrapper::iteratorNext(JSContext *cx, JSO vp->setMagic(JS_NO_ITER_VALUE); } return true; } void Wrapper::trace(JSTracer *trc, JSObject *wrapper) { - MarkValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject"); + MarkSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject"); } JSObject * Wrapper::wrappedObject(const JSObject *wrapper) { return GetProxyPrivate(wrapper).toObjectOrNull(); } @@ -651,17 +651,17 @@ CanReify(Value *vp) (obj = &vp->toObject())->getClass() == &IteratorClass && (obj->getNativeIterator()->flags & JSITER_ENUMERATE); } struct AutoCloseIterator { AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {} - ~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); } + ~AutoCloseIterator() { if (obj) CloseIterator(cx, obj); } void clear() { obj = NULL; } private: JSContext *cx; JSObject *obj; }; @@ -696,17 +696,17 @@ Reify(JSContext *cx, JSCompartment *orig id = js_CheckForStringIndex(id); keys[i] = id; if (!origin->wrapId(cx, &keys[i])) return false; } } close.clear(); - if (!js_CloseIterator(cx, iterObj)) + if (!CloseIterator(cx, iterObj)) return false; if (isKeyIter) return VectorToKeyIterator(cx, obj, ni->flags, keys, vp); return VectorToValueIterator(cx, obj, ni->flags, keys, vp); } bool @@ -866,18 +866,18 @@ CrossCompartmentWrapper::iteratorNext(JS NOTHING, Wrapper::iteratorNext(cx, wrapper, vp), call.origin->wrap(cx, vp)); } void CrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper) { - MarkCrossCompartmentValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), - "wrappedObject"); + MarkCrossCompartmentSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), + "wrappedObject"); } CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u); /* Security wrappers. */ template <class Base> SecurityWrapper<Base>::SecurityWrapper(uintN flags)
--- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -7533,17 +7533,17 @@ js_InitXMLClasses(JSContext *cx, JSObjec return js_InitXMLClass(cx, obj); } namespace js { bool GlobalObject::getFunctionNamespace(JSContext *cx, Value *vp) { - HeapValue &v = getSlotRef(FUNCTION_NS); + HeapSlot &v = getSlotRef(FUNCTION_NS); if (v.isUndefined()) { JSRuntime *rt = cx->runtime; JSLinearString *prefix = rt->atomState.typeAtoms[JSTYPE_FUNCTION]; JSLinearString *uri = rt->atomState.functionNamespaceURIAtom; JSObject *obj = NewXMLNamespace(cx, prefix, uri, JS_FALSE); if (!obj) return false; @@ -7552,17 +7552,17 @@ GlobalObject::getFunctionNamespace(JSCon * Namespace.prototype is not detectable, as there is no way to * refer to this instance in scripts. When used to qualify method * names, its prefix and uri references are copied to the QName. * The parent remains set and links back to global. */ if (!obj->clearType(cx)) return false; - v.set(compartment(), ObjectValue(*obj)); + v.set(this, FUNCTION_NS, ObjectValue(*obj)); } *vp = v; return true; } } // namespace js
--- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -1150,18 +1150,17 @@ mjit::Compiler::generatePrologue() if (outerScript->usesArguments && !script->function()->isHeavyweight()) { /* * Make sure that fp->u.nactual is always coherent. This may be * inspected directly by JIT code, and is not guaranteed to be * correct if the UNDERFLOW and OVERF